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 0092745..83b3186 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` | | `/search-pagination/` | 5 | Core search block and pagination, two posts to a page | Posts: `Alpha One` and `Alpha Two` in the `alpha` category, `Beta One` in 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 8252022..7d88d7d 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' => << +