From 5aa65bfb5be8230839aa4a3755356c0c9e3161fb Mon Sep 17 00:00:00 2001 From: goldenapples Date: Tue, 20 Oct 2026 11:50:04 -0400 Subject: [PATCH] Add a utility method for getting the query param of a query Makes it easier for blocks outside the query container to integrate with the query filters by providing the query string used to add filter links. --- README.md | 14 ++++++++++++++ inc/namespace.php | 36 ++++++++++++++++++++++++++++-------- src/post-type/render.php | 13 +++++-------- src/taxonomy/render.php | 15 ++++++--------- 4 files changed, 53 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 0153d76..386066e 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,20 @@ add_filter( 'query_filter_term_counts', function ( $counts, $query_vars, $taxono }, 10, 4 ); ``` +### Linking to filtered results + +Each filter is a URL parameter, so a link elsewhere on the page — outside the Query Loop, in a hero or a menu — can apply one. The parameter's name depends on the loop: `query-{taxonomy}` for a loop that inherits the main query, `query-{id}-{taxonomy}` for one with its own. Rather than build it by hand, ask for it with the loop's block context: + +```php +// "query-12-category", or "query-category" if the loop inherits its query. +$param = HM\Query_Loop_Filter\get_query_param( 'category', [ + 'query' => [ 'inherit' => false ], + 'queryId' => 12, +] ); +``` + +The key is a taxonomy name, `post_type`, `s` for the search or `page` for pagination. + ## Installation ### Using Composer diff --git a/inc/namespace.php b/inc/namespace.php index d48f781..55f8917 100644 --- a/inc/namespace.php +++ b/inc/namespace.php @@ -697,6 +697,32 @@ function filter_block_type_metadata( array $metadata ) : array { return $metadata; } +/** + * Name the URL parameter that sets a filter on a query. + * + * An inherited query is the main query, which reads `query-{key}`, with WordPress's own + * `s` and `page` for search and pagination. Any other query reads `query-{id}-{key}`, + * and its pagination is named as core's pagination block names it. + * + * Public so that controls outside a Query Loop, such as links built by a theme, can + * name the same parameters as the filter blocks inside it. + * + * @param string $key Taxonomy name, `post_type`, `s` or `page`. + * @param array $context Block context of the query: its `query` and `queryId`. + * @return string Parameter name. + */ +function get_query_param( string $key, array $context ) : string { + if ( ! empty( $context['query']['inherit'] ) ) { + return in_array( $key, [ 's', 'page' ], true ) ? $key : "query-{$key}"; + } + + if ( 'page' === $key ) { + return isset( $context['queryId'] ) ? "query-{$context['queryId']}-page" : 'query-page'; + } + + return sprintf( 'query-%d-%s', $context['queryId'] ?? 0, $key ); +} + /** * Sanitize a search query value. * @@ -749,26 +775,20 @@ function render_block_search( string $block_content, array $block, \WP_Block $in wp_enqueue_script_module( 'query-filter-taxonomy-view-script-module' ); - $inherit = ! empty( $instance->context['query']['inherit'] ); - // An inherited query is the main query, and WordPress resolves that from // its own `s`: a term only reaches the search template because `s` is what // routing reads. Naming the field anything else leaves the field blank on // arrival, and clearing it deletes a parameter the URL never carried, so // the results never change. `query-s` is still transposed onto the main // query for anything that already links to it. - $query_var = $inherit - ? 's' - : sprintf( 'query-%d-s', $instance->context['queryId'] ?? 0 ); + $query_var = get_query_param( 's', $instance->context ); // A search is a new set of results, so it belongs on the first page. Left // in place, the page the visitor happened to be on is carried into the // search and a term with fewer pages of matches than that renders empty. // Named as core names it, so the parameter the pagination block wrote is // the one that gets dropped. - $page_var = $inherit - ? 'page' - : ( isset( $instance->context['queryId'] ) ? 'query-' . $instance->context['queryId'] . '-page' : 'query-page' ); + $page_var = get_query_param( 'page', $instance->context ); $action = remove_query_arg( $page_var, add_query_arg( [ $query_var => '' ] ) ); $action = str_replace( '/page/' . get_query_var( 'paged', 1 ), '', $action ); diff --git a/src/post-type/render.php b/src/post-type/render.php index 2fb2b73..f264bfe 100644 --- a/src/post-type/render.php +++ b/src/post-type/render.php @@ -16,15 +16,12 @@ // rather than warning about an undefined index. $inherit = ! empty( $block->context['query']['inherit'] ); +$query_var = \HM\Query_Loop_Filter\get_query_param( 'post_type', $block->context ); +$page_var = \HM\Query_Loop_Filter\get_query_param( 'page', $block->context ); +$base_url = remove_query_arg( [ $query_var, $page_var ] ); + if ( $inherit ) { - $query_var = 'query-post_type'; - $page_var = 'page'; - $base_url = str_replace( '/page/' . get_query_var( 'paged' ), '', remove_query_arg( [ $query_var, $page_var ] ) ); -} else { - $query_id = $block->context['queryId'] ?? 0; - $query_var = sprintf( 'query-%d-post_type', $query_id ); - $page_var = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; - $base_url = remove_query_arg( [ $query_var, $page_var ] ); + $base_url = str_replace( '/page/' . get_query_var( 'paged' ), '', $base_url ); } $post_types = array_map( 'trim', explode( ',', $block->context['query']['postType'] ?? 'post' ) ); diff --git a/src/taxonomy/render.php b/src/taxonomy/render.php index fdb8643..195e710 100644 --- a/src/taxonomy/render.php +++ b/src/taxonomy/render.php @@ -22,15 +22,12 @@ $layout_direction = $attributes['layoutDirection'] ?? 'vertical'; $hierarchy = \HM\Query_Loop_Filter\get_hierarchy_mode( $attributes, $taxonomy->name ); -if ( empty( $block->context['query']['inherit'] ) ) { - $query_id = $block->context['queryId'] ?? 0; - $query_var = sprintf( 'query-%d-%s', $query_id, $attributes['taxonomy'] ); - $page_var = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; - $base_url = remove_query_arg( [ $query_var, $page_var ] ); -} else { - $query_var = sprintf( 'query-%s', $attributes['taxonomy'] ); - $page_var = 'page'; - $base_url = str_replace( '/page/' . get_query_var( 'paged' ), '', remove_query_arg( [ $query_var, $page_var ] ) ); +$query_var = \HM\Query_Loop_Filter\get_query_param( $attributes['taxonomy'], $block->context ); +$page_var = \HM\Query_Loop_Filter\get_query_param( 'page', $block->context ); +$base_url = remove_query_arg( [ $query_var, $page_var ] ); + +if ( ! empty( $block->context['query']['inherit'] ) ) { + $base_url = str_replace( '/page/' . get_query_var( 'paged' ), '', $base_url ); } // Non-ASCII term slugs are stored URL-encoded (e.g. "%e6%97%a5"), but arrive from $_GET