From 64c379e42165f5f431dd104cb12da6886a9627df Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 10:30:28 +0000 Subject: [PATCH] Read a missing query `inherit` key as not inherited MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The post type filter reads `$block->context['query']['inherit']` directly. The query block's own attribute default carries the key, but markup that names a `query` object without it — hand written patterns, third party query blocks — reaches render with the key absent, and every render of the filter raises "Undefined array key \"inherit\"" twice. Read it through empty(), as the taxonomy filter already does, and reuse the result for the inherited post type fill-in below. The test mu-plugin now records notices raised from this plugin's own files and prints them into the page, so a spec can assert a page rendered cleanly without depending on how the environment displays errors. Fixture page 4 carries a query loop whose context omits `inherit`. Fixes #15 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Lj871x28S1DXjoVm7AB4k5 --- src/post-type/render.php | 10 ++++- tests/e2e/README.md | 6 ++- tests/e2e/query-context.spec.js | 30 +++++++++++++ tests/mu-plugins/register-test-content.php | 52 ++++++++++++++++++++++ tests/seed.php | 18 ++++++++ 5 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 tests/e2e/query-context.spec.js diff --git a/src/post-type/render.php b/src/post-type/render.php index 95cc5d1..2fb2b73 100644 --- a/src/post-type/render.php +++ b/src/post-type/render.php @@ -10,7 +10,13 @@ $display_type = $attributes['displayType'] ?? 'select'; $layout_direction = $attributes['layoutDirection'] ?? 'vertical'; -if ( $block->context['query']['inherit'] ) { +// The query block's own attribute default carries `inherit`, but markup that +// names a `query` object without it (hand written patterns, third party query +// blocks) reaches render with the key absent. Read it as "not inherited" +// rather than warning about an undefined index. +$inherit = ! empty( $block->context['query']['inherit'] ); + +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 ] ) ); @@ -29,7 +35,7 @@ } // Fill in inherited query types. -if ( $block->context['query']['inherit'] ) { +if ( $inherit ) { $inherited_post_types = $wp_query->get( 'query-filter-post_type' ) === 'any' ? get_post_types( [ 'public' => true, 'exclude_from_search' => false ] ) : (array) $wp_query->get( 'query-filter-post_type' ); diff --git a/tests/e2e/README.md b/tests/e2e/README.md index 0a8ad6f..0cd787e 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -31,7 +31,10 @@ 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 records any PHP notice raised from this + plugin's files and prints it into the page as a `qf-php-error:` comment, + followed by a `qf-php-errors-checked` marker, so a spec can assert a page + rendered cleanly without depending on `display_errors`. 5. Runs `tests/seed.php`, which creates the fixture terms, posts and the demo pages the specs visit. @@ -44,6 +47,7 @@ Seeding is idempotent, guarded by the `query_filter_e2e_seeded` option. | `/taxonomy-filter/` | 1 | Taxonomy filter (select) | | `/taxonomy-checkboxes/` | 2 | Taxonomy filter (checkboxes) | | `/post-type-filter/` | 3 | Post type filter and core search block | +| `/no-inherit-context/` | 4 | Both filters, in a query loop whose `query` context omits `inherit` | Posts: `Alpha One` and `Alpha Two` in the `alpha` category, `Beta One` in `beta`, and `Unfiled Post` in neither — so an active filter is always diff --git a/tests/e2e/query-context.spec.js b/tests/e2e/query-context.spec.js new file mode 100644 index 0000000..c8c8348 --- /dev/null +++ b/tests/e2e/query-context.spec.js @@ -0,0 +1,30 @@ +const { test, expect, POSTS } = require( './fixtures' ); + +test.describe( 'Query context without inherit', () => { + test( 'the filters render without a PHP notice', async ( { + page, + loop, + } ) => { + await page.goto( '/no-inherit-context/' ); + await loop.expectTitles( POSTS.all ); + + await expect( loop.postTypeSelect() ).toBeVisible(); + await expect( loop.taxonomySelect() ).toBeVisible(); + + // The test mu-plugin collects anything this plugin's files raise and + // prints it as an HTML comment, so the assertion does not depend on + // how the environment is configured to display errors. + const html = await page.content(); + expect( html ).toContain( 'qf-php-errors-checked' ); + expect( html ).not.toContain( 'qf-php-error:' ); + } ); + + test( 'the filters still narrow the loop', async ( { page, loop } ) => { + await page.goto( '/no-inherit-context/' ); + + await loop.taxonomySelect().selectOption( { label: 'Alpha' } ); + + await page.waitForURL( /query-4-category=alpha/ ); + await loop.expectTitles( POSTS.alpha ); + } ); +} ); diff --git a/tests/mu-plugins/register-test-content.php b/tests/mu-plugins/register-test-content.php index d2fc39b..caa8015 100644 --- a/tests/mu-plugins/register-test-content.php +++ b/tests/mu-plugins/register-test-content.php @@ -48,3 +48,55 @@ function register_test_content() : void { 'hierarchical' => false, ] ); } + +/** + * PHP notices raised from inside this plugin during the current request. + * + * @var string[] + */ +$GLOBALS['query_filter_php_errors'] = []; + +set_error_handler( __NAMESPACE__ . '\\record_plugin_php_error', E_ALL ); +add_action( 'wp_footer', __NAMESPACE__ . '\\print_plugin_php_errors', 1000 ); + +/** + * Record diagnostics raised from this plugin's own files. + * + * A PHP warning only reaches the response when the server is configured to + * display errors, which is not something a test can rely on. Collecting them + * here instead means a spec can assert that a page rendered cleanly whatever + * the environment does with `display_errors`. + * + * Returns false so PHP's own handler still runs and the debug log is unchanged. + * + * @param int $errno Level of the error raised. + * @param string $errstr Error message. + * @param string $errfile File the error was raised in. + * @param int $errline Line the error was raised on. + * @return bool False, so the standard error handler also runs. + */ +function record_plugin_php_error( int $errno, string $errstr, string $errfile = '', int $errline = 0 ) : bool { + if ( strpos( $errfile, '/query-filter/' ) !== false ) { + $GLOBALS['query_filter_php_errors'][] = sprintf( + '%s in %s:%d', + $errstr, + basename( dirname( $errfile ) ) . '/' . basename( $errfile ), + $errline + ); + } + + return false; +} + +/** + * Print the recorded notices, and a marker proving the handler was installed. + * + * @return void + */ +function print_plugin_php_errors() : void { + foreach ( array_unique( $GLOBALS['query_filter_php_errors'] ) as $error ) { + printf( "\n", esc_html( $error ) ); + } + + echo "\n"; +} diff --git a/tests/seed.php b/tests/seed.php index db7f31f..d0ea22d 100644 --- a/tests/seed.php +++ b/tests/seed.php @@ -146,6 +146,24 @@ function query_loop_markup( int $query_id, string $filters ) : string { ), ] ); +// Page 4: a query loop whose `query` context omits `inherit` altogether, as +// hand written pattern markup and third party query blocks do. The filters +// must render without warning about the missing key. +seed_post( 'No Inherit Context', 'page', [ + 'post_name' => 'no-inherit-context', + 'post_content' => << +
+ + + + + +
+ +HTML, +] ); + update_option( 'query_filter_e2e_seeded', 1 ); echo "Seeded query filter e2e fixtures.\n";