Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Interactivity API: Update interactive regions during client-side navigation #10200

Merged
merged 12 commits into from
Aug 3, 2023
50 changes: 36 additions & 14 deletions assets/js/interactivity/router.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { hydrate, render } from 'preact';
import { toVdom, hydratedIslands } from './vdom';
import { createRootFragment } from './utils';
import { csnMetaTagItemprop, directivePrefix } from './constants';

// The root to render the vdom (document.body).
let rootFragment;
import { directivePrefix } from './constants';

// The cache of visited and prefetched pages.
const pages = new Map();

// Keep the same root fragment for each interactive region node.
const regionRootFragments = new WeakMap();
const getRegionRootFragment = ( region ) => {
if ( ! regionRootFragments.has( region ) ) {
regionRootFragments.set(
region,
createRootFragment( region.parentElement, region )
);
}
return regionRootFragments.get( region );
};

// Helper to remove domain and hash from the URL. We are only interesting in
// caching the path and the query.
const cleanUrl = ( url ) => {
Expand All @@ -27,9 +36,17 @@ const fetchPage = async ( url ) => {
} catch ( e ) {
return false;
}

return regionsToVdom( dom );
};

// Return an object with VDOM trees of those HTML regions marked with a
// `navigation-id` directive.
const regionsToVdom = ( dom ) => {
const regions = {};
dom.querySelectorAll( '[data-wc-navigation-id]' ).forEach( ( region ) => {
const id = region.attributes[ 'data-wc-navigation-id' ];
const attrName = `data-${ directivePrefix }-navigation-id`;
dom.querySelectorAll( `[${ attrName }]` ).forEach( ( region ) => {
const id = region.attributes[ attrName ];
regions[ id ] = toVdom( region );
} );

Expand All @@ -47,13 +64,12 @@ export const prefetch = ( url ) => {

// Render all interactive regions contained in the given page.
const renderRegions = ( page ) => {
document
.querySelectorAll( '[data-wc-navigation-id]' )
.forEach( ( region ) => {
const id = region.attributes[ 'data-wc-navigation-id' ];
const fragment = createRootFragment( region.parentElement, region );
render( page.regions[ id ], fragment );
} );
const attrName = `data-${ directivePrefix }-navigation-id`;
document.querySelectorAll( `[${ attrName }]` ).forEach( ( region ) => {
const id = region.attributes[ attrName ];
const fragment = getRegionRootFragment( region );
render( page.regions[ id ], fragment );
} );
};

// Navigate to a new page.
Expand Down Expand Up @@ -91,9 +107,15 @@ export const init = async () => {
.querySelectorAll( `[data-${ directivePrefix }-interactive]` )
.forEach( ( node ) => {
if ( ! hydratedIslands.has( node ) ) {
const fragment = createRootFragment( node.parentNode, node );
const fragment = getRegionRootFragment( node );
const vdom = toVdom( node );
hydrate( vdom, fragment );
}
} );

// Cache the current regions.
pages.set(
cleanUrl( window.location ),
Promise.resolve( regionsToVdom( document ) )
);
};
26 changes: 24 additions & 2 deletions src/BlockTypes/ProductQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,11 @@ public function add_navigation_id_directive( $block_content, $block, $instance )

// Add `data-wc-navigation-id to the query block.
if ( $p->next_tag( array( 'class_name' => 'wp-block-query' ) ) ) {
$p->set_attribute(
'data-wc-navigation-id',
'woo-products-' . $block['attrs']['queryId']
);
$p->set_attribute( 'data-wc-interactive', true );
luisherranz marked this conversation as resolved.
Show resolved Hide resolved
$p->set_attribute( 'data-wc-navigation-id', $block['attrs']['queryId'] );
$block_content = $p->get_updated_html();
}
}
Expand All @@ -122,12 +125,31 @@ public function add_navigation_link_directives( $block_content, $block, $instanc
$instance->context['queryId'] === $this->parsed_block['attrs']['queryId']
) {
$p = new \WP_HTML_Tag_Processor( $block_content );
$p->next_tag( array( 'class_name' => 'wp-block-query-pagination' ) );

while ( $p->next_tag( 'a' ) ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking into account that this is not an experiment anymore, maybe we could start with a prefetch strategy of only prefetching the previous/next links, and skipping the page number links?

cc: @gigitux, @Aljullu, any thoughts on the prefetching strategy for the pagination?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I don't have a strong opinion, but prefetching the next and previous ones and skip the others makes sense to me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll make that change.

$class_attr = $p->get_attribute( 'class' );
$class_list = preg_split( '/\s+/', $class_attr );

$is_previous = in_array( 'wp-block-query-pagination-previous', $class_list, true );
$is_next = in_array( 'wp-block-query-pagination-next', $class_list, true );
$is_previous_or_next = $is_previous || $is_next;

$navigation_link_payload = array(
'prefetch' => $is_previous_or_next,
'scroll' => true,
);

$p->set_attribute(
'data-wc-navigation-link',
'{"prefetch":true,"scroll":false}'
wp_json_encode( $navigation_link_payload )
);

if ( $is_previous ) {
$p->set_attribute( 'key', 'pagination-previous' );
} elseif ( $is_next ) {
$p->set_attribute( 'key', 'pagination-next' );
}
Comment on lines +148 to +152
Copy link
Collaborator

@luisherranz luisherranz Jul 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. Time to add support for data-wc-key to avoid adding invalid HTML?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DAreRodz I've added data-wc-key in #10604 so we should use it here as well.

}
$block_content = $p->get_updated_html();
}
Expand Down
Loading