-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Categories Block: Add iAPI directive for client-side routing #64907
Conversation
@@ -54,6 +54,12 @@ function render_block_core_categories( $attributes ) { | |||
$wrapper_markup = '<ul %1$s>%2$s</ul>'; | |||
$items_markup = wp_list_categories( $args ); | |||
$type = 'list'; | |||
|
|||
$p = new WP_HTML_Tag_Processor( $items_markup ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be the responsibility of the Query Loop block to intercept all clicks to links instead when the proper setting is enabled? Otherwise, the same change would have to be applied to every possible block that contains link.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. We should add the data-wp-on-click
directives in the Query block's render callback.
However, in order to find where to add them, we should also add some "markers" here (in the Categories block).
One solution could be something like adding data-wp-navigation-link
attributes (which were removed in #57853):
// Categories block
while ( $p->next_tag( 'a' ) ) {
$p->set_attribute( 'data-wp-navigation-link', );
}
// Query block
while ( $p->next_tag( 'a' ) ) {
if ( $p->get_attribute('data-wp-navigation-link') ) {
$p->set_attribute( 'data-wp-on--click', 'core/query::actions.navigate' );
}
}
$items_markup = $p->get_updated_html();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, folks, that's exactly the kind of feedback I was looking for!
@gziolo wrote:
Wouldn't it be the responsibility of the Query Loop block to intercept all clicks to links instead when the proper setting is enabled? Otherwise, the same change would have to be applied to every possible block that contains link.
@michalczaplinski wrote:
Indeed. We should add the
data-wp-on-click
directives in the Query Loop block's render callback.
However, in order to find where to add them, we should also add some "markers" here (in the Categories block).
I like the idea of adding the directives from within the Query block's render callback, as that gives us access to the information whether enhanced pagination is on or off.
However, we need to decide on an overall strategy:
- Doing it wholesale for all links found inside of the Query Loop block, as @gziolo suggested, or
- Applying it only to individual blocks that have opted in, e.g. via some sort of marker (another
data-wp-
attribute), as suggested by @michalczaplinski.
I think both approaches have their tradeoffs:
- Doing it wholesale might erroneously apply to links that point other parts of the site (that use a different template and would thus break region-based client-side navigation), or even external links. OTOH.
- Requiring opt-in adds some overhead. Furthermore, in terms of how blocks opt into this behavior, I don't really love the idea of using another
data-wp
attribute just to tell WP to replace it withdata-wp-on--click='core/query::actions.navigate'
. (To me, it raises the question what we're gaining from that, vs. having the block set thedata-wp-on--click
attribute itself.)
We might be able to tweak both strategies a bit:
- Wholesale: We could make sure to only add the
data-wp-on--click
handler to links that point to routes that are handled by the same template. (This could be a bit tricky in practice due to WP's template hierarchy; the system would need to know a lot about routes and templates.) - Opt-in: Instead of setting a marker on each instance of a given block; can we just opt the entire block type in, i.e. set a block attribute or something of the sort?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that the Query Loop block provides
enhancedPagination
context, which is used by the Post Template block. This looks promising to me, as it might allow us to minimize the extra information we introduce and/or communicate. It would still leave the responsibility of setting data-wp-on--click='core/query::actions.navigate'
attribute with individual blocks, but based on the above, that might be reasonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Note that not all blocks will require the HTML API to inject the attribute; we need it for the core/categories
block as that block gets its HTML from wp_list_categories()
and wp_dropdown_categories
, respectively. That HTML is opaque to us, so we have to resort to the HTML API in order to modify it; but in other cases, we'll be able to simply include the data-wp-on--click
attribute in the HTML string we return from the block.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried it in d9dc1b7. I kinda like this 😬
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have much to add here.
- It's true that click handlers cannot be added to all the clicks within the Query loop because there are links that may point to other parts of the site.
- I don't have a strong opinion on how to include those click handlers, but in my opinion, the way we are currently doing it, passing whether the enhanced pagination is active through block context and injecting the click handlers into each block, seems simple and appropriate for now.
- Sometimes, there will be more complex cases where a click-handler is not enough, and more logic needs to be added, such as with the Search block, so it's important to leave room for custom implementations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for weighing in, @luisherranz!
I'll go ahead and open this for review then 😊
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left more thoughts related to that topic #64907 (comment) in response to the #64907 (review) from @dmsnell.
Flaky tests detected in d9dc1b7. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/10621473315
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit confused on this and that's probably because I don't understand the issues involved, but why is this being done on the server? it doesn't appear to impact the rendered page at all other than by adding a flag that client-side JS code is going to have to find and deal with anyway.
could we not identify the category-containing HTML on page load/DOM ready and then apply the associated click handler there? the benefit to that approach is that it's much easier to detect whether a link is local or external, since the .href
property of each A
element will be normalized and complete.
if it still requires JS to work anyway, could we leave it all in JS? or possibly use this code to add some class to the containing element like this?
if ( ! empty( $block->context['enhancePagination'] ) ) {
$processor = new WP_HTML_Tag_Processor( $content );
if ( $processor->next_tag() ) {
$processor->add_class( 'uses-enhanced-pagination' );
}
}
In the client:
document
.querySeletorAll( '.uses-enhanced-pagination a' )
.forEach( node => {
const linkHost = (new URL(node.href)).domain;
if ( document.location.host !== linkHost ) {
return;
}
node.dataset['wpOn-Click'] = 'core/query::actions.navigate';
} );
I had the same thoughts when commenting here. I didn't elaborate as much as @dmsnell, but I agree on principle that it isn't the most efficient to run 3 steps of processing to properly handle links in the block embeded in the Query loop. In the currently proposed approach the following things happen:
Plus, for every possible block, it's up to the author to ensure that links are correctly integrated. I would also like to point out that the full-page client-side nagivation experiment automatically applies the proper events by detecting all applicable links: gutenberg/packages/interactivity-router/src/index.ts Lines 366 to 395 in 9d4f918
In effect, all necessary logic is in place to replicate that for region-based client-side navigation within the Query Loop. The only difference in this case would be that there should be some way to configure how to detect which URL should be handled without the page reload, as that should be narrowed down to the pattern used by the Query loop block. If necessary, there could be a way to opt out of the block or individual link from the default behavior, for example, through |
Thanks @dmsnell and @gziolo! I'll answer Dennis' comment first, and will reply to Grzegorz's separately.
Primarily because that's how it's done by some existing blocks (Query Pagination Previous/Numbers/Next) -- so it seemed to be the agreed-upon way of using the iAPI. However, I understand your concerns!
But that distinction (local vs external) isn't quite enough, is it? If a link is local but points to a different part of the site that requires additional styling or scripts, client-side navigation would yield a visually broken result, no? (For the iAPI, folks are tackling this problem under the umbrella term of full-page -- vs region-based -- client-side navigation.) Being limited to region-based client-side navigation (for the time being) is one of the main reasons I was opting to do it on a per-block basis (also see this discussion). LMK if that makes sense, and/or if I'm missing something! |
Yeah, that's fair enough. I guess it becomes more apparent if one looks at how the same problem would be solved with vanilla JS -- where we'd only require a simple (Aside: I'm wondering if that raises some questions around using the iAPI in Core. On the one hand, I thought it would be a good way to provide developers with some example code to look at; plus given the fact that it's already used in Query Pagination blocks, I thought that it'd make sense to use it somewhat consistently. OTOH, I hear your and Dennis' performance and complexity concerns.)
Right, I was unaware. Thank you for pointing that out!
Yeah, and that's the part that looked fairly tricky to me: As long as we're confined by region-based client-side navigation, the criterion is basically if a link's target URL would be rendered by the same template that's currently being displayed. The way that WP's routing and querying works, I'm not sure it's easily possible to find that out without actually rendering that route 😕 |
I wasn’t aware of that implementation detail. Thank you for sharing this context. I see it’s hardcoded to In case you want to iterate quickly and add the missing functionality then the approach taken in this PR is reasonable as it follows the well-established pattern. I raised all my concerns with the intent to spark the discussion to improve the entire design over time. In particular to align closer two types of client-side navigation that should morph into one solution in the long run. |
Thank you @gziolo! I hope I didn't win your approval through my verbosity 😅 |
This is the part that's beyond my familiarity, though it still seems like something worth double- or triple-checking. Is there not some way to classify at the group level which links should be activated? For example, how does the server know if a link is set to the same "region"? I'm guessing it's not path-related. Just caught my eye since we're doing stuff that only works when JavaScript runs, but we're doing that processing on render in the server. |
Hey @ockham 👋 Would you be able to help write a dev note for this for the 6.7 release? We are planning to have this as part of a larger Miscellaneous Editor Updates note. We are hoping to get all drafts in by October 13th to leave some time for reviews before the RC1. All Dev Notes get tracked in #65784 so feel free to leave a note there or ping me directly :) Please let us know if you can assist with that. Thanks in advance :) |
@fabiankaegy Hmm, I'm not sure that this is a change that needs a Dev Note, as it's more user-facing? Essentially, it enables client-side navigation for the links in the Categories Block, provided that it's a descendent of a Query Loop block that has opted into client-side navigation by disabling the "Reload full page" toggle (previously labeled "Force page reload", see #65081). |
@ockham okay in that case let me remove it from the board :) Question though, how would developers / users find out about the new capabilities? There is no UI for any of this so I think it is really hard to discover. That is in part why I thought it would be good to call out. As it it something that developers no longer need to custom build but rather can use the core block for now. |
Fair question :) I was thinking it would bubble up via a different path, e.g. via GB release notes (that are used to compile user-facing updates for a WP release)? But TBH that's speculation on my part; I don't really know what's the established process for changes like that. Can you enlighten me? (FWIW, there's also this -- somewhat major -- change that would be nice to have documented in 6.7) In any case, if we'd like to document the changes from the present PR somehow, maybe something like the following would do: Categories Block: Conditionally enable client-side routingIf a Categories block is used inside a Query Loop block whose "Reload full page" toggle is disabled, the Categories block's links will now use client-side routing. (This is achieved by adding the Interactivity API's |
@ockham Yeah I don't really know the answer either. I don't think there is an established process... Kind of because I don't know I was thinking to just include a few more of these types of things in the Field Guide. Just to have a space where we can talk about them |
What?
Enable client-side navigation for the Categories block, when used with the Query Loop block.
Why?
For a better user experience when using the Categories block.
How?
By adding the Interactivity API's
data-wp-on--click
directive and setting it to thecore/query::actions.navigate
action. (The latter is provided by the Query Loop block.)Testing Instructions
Screenshots or screencast