From ac86534c6228fa84698bccf6affddd160f88e079 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 10:35:55 +0000 Subject: [PATCH] Name the inherited query's search field `s` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An inherited query is the main query, and WordPress resolves that from its own `s`: a term only reaches the search results template because `s` is what routing reads. The field was named `query-s` there, so on arrival it rendered blank rather than showing the term being searched, and clearing it deleted a parameter the URL never carried — the "new" URL matched the current one, the router had nothing to fetch, and the results never changed. Name it `s` for the inherited case. `query-s` is still transposed onto the main query, so anything already linking to it keeps working. The test harness rewrites the theme's search template to put a search block inside the inheriting query loop, which is the one arrangement where these blocks see an inherited query and no bundled theme ships it. Fixes #50 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Lj871x28S1DXjoVm7AB4k5 --- inc/namespace.php | 8 ++++- tests/e2e/README.md | 4 ++- tests/e2e/inherited-search.spec.js | 41 ++++++++++++++++++++++ tests/mu-plugins/register-test-content.php | 37 +++++++++++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/inherited-search.spec.js diff --git a/inc/namespace.php b/inc/namespace.php index 8f53a69..15e9efb 100644 --- a/inc/namespace.php +++ b/inc/namespace.php @@ -302,9 +302,15 @@ function render_block_search( string $block_content, array $block, \WP_Block $in wp_enqueue_script_module( 'query-filter-taxonomy-view-script-module' ); + // 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 = empty( $instance->context['query']['inherit'] ) ? sprintf( 'query-%d-s', $instance->context['queryId'] ?? 0 ) - : 'query-s'; + : 's'; $action = str_replace( '/page/' . get_query_var( 'paged', 1 ), '', add_query_arg( [ $query_var => '' ] ) ); diff --git a/tests/e2e/README.md b/tests/e2e/README.md index 0a8ad6f..44d6f95 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -31,7 +31,9 @@ run and `npm run playground:start`: 3. Activates this plugin, mounted from the working tree. 4. Copies `tests/mu-plugins/register-test-content.php` into `mu-plugins`, which registers the post types and taxonomies the tests filter against — including - deliberately private ones. + deliberately private ones. It also rewrites the theme's search results + template to put a search block inside the inheriting query loop, the one + arrangement in which the blocks see an inherited query. 5. Runs `tests/seed.php`, which creates the fixture terms, posts and the demo pages the specs visit. diff --git a/tests/e2e/inherited-search.spec.js b/tests/e2e/inherited-search.spec.js new file mode 100644 index 0000000..371d0b9 --- /dev/null +++ b/tests/e2e/inherited-search.spec.js @@ -0,0 +1,41 @@ +const { test, expect, POSTS } = require( './fixtures' ); + +/** + * The search results template carries a query loop that inherits the main + * query, with a search block inside it — see tests/mu-plugins. A term reaches + * that page in WordPress' own `s`, because that is what routing reads, so the + * wired field has to be named `s` as well. + */ +test.describe( 'Search filter in an inherited query', () => { + test( 'the field is wired to the site search term', async ( { + page, + loop, + } ) => { + await page.goto( '/?s=Alpha' ); + + const input = page.locator( '.wp-block-query .wp-block-search__input' ); + await expect( input ).toHaveAttribute( 'name', 's' ); + await expect( input ).toHaveValue( 'Alpha' ); + + // The main query orders search results its own way, so compare as a set. + await expect + .poll( async () => ( await loop.titles() ).sort() ) + .toEqual( POSTS.alpha ); + } ); + + test( 'clearing the field clears the search', async ( { page, loop } ) => { + await page.goto( '/?s=Alpha' ); + await expect + .poll( async () => ( await loop.titles() ).sort() ) + .toEqual( POSTS.alpha ); + + await page + .locator( '.wp-block-query .wp-block-search__input' ) + .fill( '' ); + + await page.waitForURL( /\?s=$/ ); + + // An empty term is still a search to WordPress, and returns everything. + await expect.poll( () => loop.titles() ).toContain( POSTS.beta[ 0 ] ); + } ); +} ); diff --git a/tests/mu-plugins/register-test-content.php b/tests/mu-plugins/register-test-content.php index d2fc39b..02e9b48 100644 --- a/tests/mu-plugins/register-test-content.php +++ b/tests/mu-plugins/register-test-content.php @@ -12,6 +12,7 @@ namespace HM\Query_Loop_Filter\Tests; add_action( 'init', __NAMESPACE__ . '\\register_test_content' ); +add_filter( 'get_block_templates', __NAMESPACE__ . '\\replace_search_template', 10, 2 ); /** * Register the test post types and taxonomies. @@ -48,3 +49,39 @@ function register_test_content() : void { 'hierarchical' => false, ] ); } + +/** + * Put a searchable, inheriting query loop on the search results template. + * + * The bundled themes render search results through a query loop that inherits + * the main query, but none of them place a search block inside it. That is the + * arrangement a dedicated search page uses, and the only one where the filter + * blocks see an inherited query, so the tests need a template that has it. + * + * @param \WP_Block_Template[] $templates Templates matching the query. + * @param array $query Arguments the templates were queried with. + * @return \WP_Block_Template[] Templates, with the search template rewritten. + */ +function replace_search_template( array $templates, array $query ) : array { + if ( ! in_array( 'search', (array) ( $query['slug__in'] ?? [] ), true ) ) { + return $templates; + } + + foreach ( $templates as $template ) { + if ( $template->slug !== 'search' ) { + continue; + } + + $template->content = implode( '', [ + '', + '', + '
', + '', + '', + '
', + '', + ] ); + } + + return $templates; +}