From c3fd536976b5a717f2f09260ce65c6071f306001 Mon Sep 17 00:00:00 2001 From: rchrzan Date: Thu, 4 Jul 2024 22:47:10 +0200 Subject: [PATCH 01/76] adding the necessary directives --- packages/block-library/src/search/block.json | 1 + packages/block-library/src/search/index.php | 27 +++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/block-library/src/search/block.json b/packages/block-library/src/search/block.json index 8d5e208045068..f3d9780e9e834 100644 --- a/packages/block-library/src/search/block.json +++ b/packages/block-library/src/search/block.json @@ -48,6 +48,7 @@ "default": false } }, + "usesContext": [ "enhancedPagination" ], "supports": { "align": [ "left", "center", "right" ], "color": { diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index 39b8591c86600..129e153539bd9 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -16,7 +16,7 @@ * * @return string The search block markup. */ -function render_block_core_search( $attributes ) { +function render_block_core_search( $attributes, $content, $block ) { // Older versions of the Search block defaulted the label and buttonText // attributes to `__( 'Search' )` meaning that many posts contain ``. Support these by defaulting an undefined label and @@ -48,6 +48,8 @@ function render_block_core_search( $attributes ) { // This variable is a constant and its value is always false at this moment. // It is defined this way because some values depend on it, in case it changes in the future. $open_by_default = false; + // Check if the block is using the enhanced pagination. + $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; $label_inner_html = empty( $attributes['label'] ) ? __( 'Search' ) : wp_kses_post( $attributes['label'] ); $label = new WP_HTML_Tag_Processor( sprintf( '', $inline_styles['label'], $label_inner_html ) ); @@ -79,7 +81,8 @@ function render_block_core_search( $attributes ) { // If it's interactive, enqueue the script module and add the directives. $is_expandable_searchfield = 'button-only' === $button_position; - if ( $is_expandable_searchfield ) { + + if ( $is_expandable_searchfield || $enhanced_pagination ) { $suffix = wp_scripts_get_suffix(); if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { $module_url = gutenberg_url( '/build/interactivity/search.min.js' ); @@ -93,14 +96,20 @@ function render_block_core_search( $attributes ) { ); wp_enqueue_script_module( '@wordpress/block-library/search' ); + } + if ( $is_expandable_searchfield ) { $input->set_attribute( 'data-wp-bind--aria-hidden', '!context.isSearchInputVisible' ); $input->set_attribute( 'data-wp-bind--tabindex', 'state.tabindex' ); - // Adding these attributes manually is needed until the Interactivity API // SSR logic is added to core. $input->set_attribute( 'aria-hidden', 'true' ); $input->set_attribute( 'tabindex', '-1' ); } + // Instant search is only available when using the enhanced pagination. + if ( $enhanced_pagination ) { + $input->set_attribute( 'data-wp-bind--value', 'state.search' ); + $input->set_attribute( 'data-wp-on--input', 'actions.updateSearch' ); + } } if ( count( $query_params ) > 0 ) { @@ -176,6 +185,14 @@ function render_block_core_search( $attributes ) { $form_directives = ''; // If it's interactive, add the directives. + if ( $is_expandable_searchfield || $enhanced_pagination ) { + $form_directives = 'data-wp-interactive="core/search"'; + } + + if ( $enhanced_pagination ) { + // TODO: add wp_interactivity_state() + } + if ( $is_expandable_searchfield ) { $aria_label_expanded = __( 'Submit Search' ); $aria_label_collapsed = __( 'Expand search field' ); @@ -187,9 +204,7 @@ function render_block_core_search( $attributes ) { 'ariaLabelCollapsed' => $aria_label_collapsed, ) ); - $form_directives = ' - data-wp-interactive="core/search"' - . $form_context . + $form_directives .= $form_context . 'data-wp-class--wp-block-search__searchfield-hidden="!context.isSearchInputVisible" data-wp-on-async--keydown="actions.handleSearchKeydown" data-wp-on-async--focusout="actions.handleSearchFocusout" From 793e3308e020b1eed9d36944ea26dfa4238d4aed Mon Sep 17 00:00:00 2001 From: rchrzan Date: Fri, 5 Jul 2024 22:50:54 +0200 Subject: [PATCH 02/76] add filter for query loop, rest necessarily things --- packages/block-library/src/query/index.php | 32 ++++++++++++++++++ packages/block-library/src/search/index.php | 8 ++++- packages/block-library/src/search/view.js | 37 ++++++++++++++++++++- 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/query/index.php b/packages/block-library/src/query/index.php index 6cc57dc08388c..0c39044894847 100644 --- a/packages/block-library/src/query/index.php +++ b/packages/block-library/src/query/index.php @@ -170,3 +170,35 @@ function block_core_query_disable_enhanced_pagination( $parsed_block ) { } add_filter( 'render_block_data', 'block_core_query_disable_enhanced_pagination', 10, 1 ); + +/** + * Modifies the static `core/query` block on the server for instant search. + * + * @since 6.5.0 + * + * @param array $attributes Block attributes. + * @param string $content Block default content. + * @param WP_Block $block The block instance. + * + * @return string Returns the modified output of the query block. + */ + +function block_core_query_instant_search_filter( $pre_render, $parsed_block ) { + if ( 'core/query' === $parsed_block['blockName'] && array_key_exists( 'enhancedPagination', $parsed_block['attrs'] ) && true === $parsed_block['attrs']['enhancedPagination'] ) { + add_filter( + 'query_loop_block_query_vars', + function ( $query ) { + + if ( isset( $_GET['search'] ) && ! empty( $_GET['search'] ) ) { + $query['s'] = $_GET['search']; + } + + return $query; + } + ); + } + + return $pre_render; +} + +add_filter( 'pre_render_block', 'block_core_query_instant_search_filter', 10, 3 ); diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index 129e153539bd9..c514b0f1ff781 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -189,8 +189,14 @@ function render_block_core_search( $attributes, $content, $block ) { $form_directives = 'data-wp-interactive="core/search"'; } + // Adding wp_interactivity_state for the search block. if ( $enhanced_pagination ) { - // TODO: add wp_interactivity_state() + wp_interactivity_state( + 'core/search', + array( + 'search' => isset( $_GET['search'] ) ? $_GET['search'] : '', + ) + ); } if ( $is_expandable_searchfield ) { diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index 0e4c462a2e321..baba35f41d6f3 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -3,7 +3,26 @@ */ import { store, getContext, getElement } from '@wordpress/interactivity'; -const { actions } = store( +const isEmpty = ( obj ) => + [ Object, Array ].includes( ( obj || {} ).constructor ) && + ! Object.entries( obj || {} ).length; + +const updateURL = async ( value, name ) => { + const url = new URL( window.location ); + const { actions } = await import( '@wordpress/interactivity-router' ); + + if ( 's' === name ) { + if ( ! isEmpty( value ) ) { + url.searchParams.set( 'search', value ); + } else { + url.searchParams.delete( 'search' ); + } + } + + await actions.navigate( `${ window.location.pathname }${ url.search }` ); +}; + +const { state, actions } = store( 'core/search', { state: { @@ -66,6 +85,22 @@ const { actions } = store( actions.closeSearchInput(); } }, + *updateSearch() { + const { ref } = getElement(); + const { value, name } = ref; + + // Don't navigate if the search didn't really change. + if ( 's' === name && value === state.search ) { + return; + } + + if ( 's' === name ) { + state.search = value; + } + + // If not, navigate to the new URL. + yield updateURL( value, name ); + }, }, }, { lock: true } From 0159a4a7273e0b4c185e856ad461838583a398ac Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 8 Jul 2024 17:31:27 +0200 Subject: [PATCH 03/76] Switch to isSearchInputInitiallyVisible so it works with navigation --- packages/block-library/src/search/index.php | 8 ++++---- packages/block-library/src/search/view.js | 13 ++++++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index c514b0f1ff781..656fc7598802d 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -204,10 +204,10 @@ function render_block_core_search( $attributes, $content, $block ) { $aria_label_collapsed = __( 'Expand search field' ); $form_context = wp_interactivity_data_wp_context( array( - 'isSearchInputVisible' => $open_by_default, - 'inputId' => $input_id, - 'ariaLabelExpanded' => $aria_label_expanded, - 'ariaLabelCollapsed' => $aria_label_collapsed, + 'isSearchInputInitiallyVisible' => $open_by_default, + 'inputId' => $input_id, + 'ariaLabelExpanded' => $aria_label_expanded, + 'ariaLabelCollapsed' => $aria_label_collapsed, ) ); $form_directives .= $form_context . diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index baba35f41d6f3..c13f66cb99043 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -48,14 +48,21 @@ const { state, actions } = store( const { isSearchInputVisible } = getContext(); return isSearchInputVisible ? '0' : '-1'; }, + get isSearchInputVisible() { + const ctx = getContext(); + if ( typeof ctx.isSearchInputVisible === 'undefined' ) { + return ctx.isSearchInputInitiallyVisible; + } + return ctx.isSearchInputVisible; + }, }, actions: { openSearchInput( event ) { - const ctx = getContext(); - const { ref } = getElement(); - if ( ! ctx.isSearchInputVisible ) { + if ( ! state.isSearchInputVisible ) { event.preventDefault(); + const ctx = getContext(); ctx.isSearchInputVisible = true; + const { ref } = getElement(); ref.parentElement.querySelector( 'input' ).focus(); } }, From 29b239962a4f3d9411f089add9d8381d35da50db Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 8 Oct 2024 17:08:26 +0100 Subject: [PATCH 04/76] Remove redundant await --- packages/block-library/src/search/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index c13f66cb99043..a2929b9c719e8 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -19,7 +19,7 @@ const updateURL = async ( value, name ) => { } } - await actions.navigate( `${ window.location.pathname }${ url.search }` ); + actions.navigate( `${ window.location.pathname }${ url.search }` ); }; const { state, actions } = store( From 5952a03ee29ce8adfd8c930f64b61d9602d90e66 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 8 Oct 2024 17:14:19 +0100 Subject: [PATCH 05/76] Update the filter that adds the search param to query block --- packages/block-library/src/query/index.php | 39 +++++++++++----------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/packages/block-library/src/query/index.php b/packages/block-library/src/query/index.php index 0c39044894847..25846aff12ca4 100644 --- a/packages/block-library/src/query/index.php +++ b/packages/block-library/src/query/index.php @@ -172,33 +172,32 @@ function block_core_query_disable_enhanced_pagination( $parsed_block ) { add_filter( 'render_block_data', 'block_core_query_disable_enhanced_pagination', 10, 1 ); /** - * Modifies the static `core/query` block on the server for instant search. + * Filters the query arguments for the Query Loop block to support instant search functionality. * - * @since 6.5.0 + * This function modifies the query arguments if enhanced pagination is enabled and a search query + * parameter is present in the GET request. It adds the search term to the query, enabling + * instant search within the Query Loop block. * - * @param array $attributes Block attributes. - * @param string $content Block default content. - * @param WP_Block $block The block instance. + * @since 6.8.0 * - * @return string Returns the modified output of the query block. + * @param array $query The original query arguments. + * @param WP_Block $block The block instance. + * @return array The modified query arguments. */ +function block_core_query_instant_search_filter( $query, $block ) { -function block_core_query_instant_search_filter( $pre_render, $parsed_block ) { - if ( 'core/query' === $parsed_block['blockName'] && array_key_exists( 'enhancedPagination', $parsed_block['attrs'] ) && true === $parsed_block['attrs']['enhancedPagination'] ) { - add_filter( - 'query_loop_block_query_vars', - function ( $query ) { - - if ( isset( $_GET['search'] ) && ! empty( $_GET['search'] ) ) { - $query['s'] = $_GET['search']; - } + // if the enhancedPagination is false or not set, return the query as is + if ( empty( $block->context['enhancedPagination'] ) ) { + return $query; + } - return $query; - } - ); + // if the search query param is set, add it to the query + if ( isset( $_GET['search'] ) && ! empty( $_GET['search'] ) ) { + $query['s'] = $_GET['search']; } - return $pre_render; + return $query; } -add_filter( 'pre_render_block', 'block_core_query_instant_search_filter', 10, 3 ); + +add_filter( 'query_loop_block_query_vars', 'block_core_query_instant_search_filter', 10, 3 ); From f0944db3f7d2838bdffc2a9ca9e1b397253e4db6 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 8 Oct 2024 20:06:22 +0100 Subject: [PATCH 06/76] Refactor the view.js of search block --- packages/block-library/src/search/view.js | 31 ++++++++++------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index a2929b9c719e8..db0aa486e1f07 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -7,21 +7,6 @@ const isEmpty = ( obj ) => [ Object, Array ].includes( ( obj || {} ).constructor ) && ! Object.entries( obj || {} ).length; -const updateURL = async ( value, name ) => { - const url = new URL( window.location ); - const { actions } = await import( '@wordpress/interactivity-router' ); - - if ( 's' === name ) { - if ( ! isEmpty( value ) ) { - url.searchParams.set( 'search', value ); - } else { - url.searchParams.delete( 'search' ); - } - } - - actions.navigate( `${ window.location.pathname }${ url.search }` ); -}; - const { state, actions } = store( 'core/search', { @@ -101,12 +86,24 @@ const { state, actions } = store( return; } + const url = new URL( window.location ); + if ( 's' === name ) { state.search = value; + if ( ! isEmpty( value ) ) { + url.searchParams.set( 'search', value ); + } else { + url.searchParams.delete( 'search' ); + } } - // If not, navigate to the new URL. - yield updateURL( value, name ); + const { actions: routerActions } = yield import( + '@wordpress/interactivity-router' + ); + + routerActions.navigate( + `${ window.location.pathname }${ url.search }` + ); }, }, }, From 5a85f98d7e18f281a66bb32f9cd4d3ef5e983b0a Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 9 Oct 2024 13:41:09 +0100 Subject: [PATCH 07/76] Move changes from the `query_loop_block_query_vars` filter to inside of post-template/index.php --- .../block-library/src/post-template/index.php | 18 ++++++++++- packages/block-library/src/query/index.php | 31 ------------------- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 9126355c096a5..dfb79b7435dab 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -67,9 +67,25 @@ function render_block_core_post_template( $attributes, $content, $block ) { } else { $query = $wp_query; } + + // Add search parameter if enhanced pagination is on and search query exists + if ( $enhanced_pagination && isset( $_GET['search'] ) && ! empty( $_GET['search'] ) ) { + $query->set( 's', $_GET['search'] ); + } + + error_log( 'inherited query' ); } else { + $query_args = build_query_vars_from_query_block( $block, $page ); - $query = new WP_Query( $query_args ); + + // Add search parameter if enhanced pagination is on and search query exists + if ( $enhanced_pagination && isset( $_GET['search'] ) && ! empty( $_GET['search'] ) ) { + $query_args['s'] = $_GET['search']; + } + + error_log( 'regular query' ); + + $query = new WP_Query( $query_args ); } if ( ! $query->have_posts() ) { diff --git a/packages/block-library/src/query/index.php b/packages/block-library/src/query/index.php index 25846aff12ca4..6cc57dc08388c 100644 --- a/packages/block-library/src/query/index.php +++ b/packages/block-library/src/query/index.php @@ -170,34 +170,3 @@ function block_core_query_disable_enhanced_pagination( $parsed_block ) { } add_filter( 'render_block_data', 'block_core_query_disable_enhanced_pagination', 10, 1 ); - -/** - * Filters the query arguments for the Query Loop block to support instant search functionality. - * - * This function modifies the query arguments if enhanced pagination is enabled and a search query - * parameter is present in the GET request. It adds the search term to the query, enabling - * instant search within the Query Loop block. - * - * @since 6.8.0 - * - * @param array $query The original query arguments. - * @param WP_Block $block The block instance. - * @return array The modified query arguments. - */ -function block_core_query_instant_search_filter( $query, $block ) { - - // if the enhancedPagination is false or not set, return the query as is - if ( empty( $block->context['enhancedPagination'] ) ) { - return $query; - } - - // if the search query param is set, add it to the query - if ( isset( $_GET['search'] ) && ! empty( $_GET['search'] ) ) { - $query['s'] = $_GET['search']; - } - - return $query; -} - - -add_filter( 'query_loop_block_query_vars', 'block_core_query_instant_search_filter', 10, 3 ); From 520629df58bb94390df6f30151a6354def1e19fa Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 9 Oct 2024 13:41:39 +0100 Subject: [PATCH 08/76] Add a comment in search/view.js --- packages/block-library/src/search/view.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index db0aa486e1f07..dff0c5608a09f 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -35,6 +35,10 @@ const { state, actions } = store( }, get isSearchInputVisible() { const ctx = getContext(); + + // `ctx.isSearchInputVisible` is a client-side-only context value, so + // if it's not set, it means that it's an initial page load, so we need + // to return the value of `ctx.isSearchInputInitiallyVisible`. if ( typeof ctx.isSearchInputVisible === 'undefined' ) { return ctx.isSearchInputInitiallyVisible; } From f4776dbfbb1d30a9b212e0b4a32c357ec5119ca3 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 9 Oct 2024 17:12:12 +0100 Subject: [PATCH 09/76] I messed up the merge commit earlier --- packages/block-library/src/search/index.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index 6219ae629a7b8..39347a0a2ca95 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -81,13 +81,14 @@ function render_block_core_search( $attributes, $content, $block ) { // If it's interactive, enqueue the script module and add the directives. $is_expandable_searchfield = 'button-only' === $button_position; - if ( $is_expandable_searchfield ) { + if ( $is_expandable_searchfield || $enhanced_pagination) { wp_enqueue_script_module( '@wordpress/block-library/search/view' ); } - if ( $is_expandable_searchfield || $enhanced_pagination ) { + if ( $is_expandable_searchfield ) { $input->set_attribute( 'data-wp-bind--aria-hidden', '!context.isSearchInputVisible' ); $input->set_attribute( 'data-wp-bind--tabindex', 'state.tabindex' ); + // Adding these attributes manually is needed until the Interactivity API // SSR logic is added to core. $input->set_attribute( 'aria-hidden', 'true' ); From ce278566740aa84fdcaa442b5833173ee2634e88 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 10 Oct 2024 15:03:50 +0100 Subject: [PATCH 10/76] First stab at making search work for "inherited" queries --- .../block-library/src/post-template/index.php | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index dfb79b7435dab..c59d423d50bd6 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -50,6 +50,7 @@ function render_block_core_post_template( $attributes, $content, $block ) { $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; + $search_query = empty( $_GET['search'] ) ? '' : sanitize_text_field( $_GET['search'] ); // Use global query if needed. $use_global_query = ( isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] ); @@ -63,24 +64,29 @@ function render_block_core_post_template( $attributes, $content, $block ) { */ if ( in_the_loop() ) { $query = clone $wp_query; + $query_args = $wp_query->query_vars; $query->rewind_posts(); + + // Add search parameter if it exists. + if ( ! empty( $search_query ) ) { + $query_args['s'] = $search_query; + } + $query->query( $query_args ); + } else { + // The query has not been run yet, modify the global query. + if ( ! empty( $search_query ) ) { + $wp_query->set( 's', $search_query ); + } $query = $wp_query; } - - // Add search parameter if enhanced pagination is on and search query exists - if ( $enhanced_pagination && isset( $_GET['search'] ) && ! empty( $_GET['search'] ) ) { - $query->set( 's', $_GET['search'] ); - } - - error_log( 'inherited query' ); } else { $query_args = build_query_vars_from_query_block( $block, $page ); // Add search parameter if enhanced pagination is on and search query exists - if ( $enhanced_pagination && isset( $_GET['search'] ) && ! empty( $_GET['search'] ) ) { - $query_args['s'] = $_GET['search']; + if ( $enhanced_pagination && ! empty( $search_query ) ) { + $query_args['s'] = $search_query; } error_log( 'regular query' ); From be7544492837e71769e3399238efdbd41a43f314 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 10 Oct 2024 15:07:43 +0100 Subject: [PATCH 11/76] Forgot to check if $enhanced_pagination was on --- packages/block-library/src/post-template/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index c59d423d50bd6..d3bc478b3e160 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -68,14 +68,14 @@ function render_block_core_post_template( $attributes, $content, $block ) { $query->rewind_posts(); // Add search parameter if it exists. - if ( ! empty( $search_query ) ) { + if ( $enhanced_pagination && ! empty( $search_query ) ) { $query_args['s'] = $search_query; } $query->query( $query_args ); } else { // The query has not been run yet, modify the global query. - if ( ! empty( $search_query ) ) { + if ( $enhanced_pagination && ! empty( $search_query ) ) { $wp_query->set( 's', $search_query ); } $query = $wp_query; From 6fbf19c1bc00b9d7fe968be775c839788cef0376 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 10 Oct 2024 15:19:55 +0100 Subject: [PATCH 12/76] remove the error_log() --- packages/block-library/src/post-template/index.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index d3bc478b3e160..92be174f7e5ef 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -89,8 +89,6 @@ function render_block_core_post_template( $attributes, $content, $block ) { $query_args['s'] = $search_query; } - error_log( 'regular query' ); - $query = new WP_Query( $query_args ); } From 7627a350a88710051625aec1465c9f0183e36348 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 10 Oct 2024 15:20:32 +0100 Subject: [PATCH 13/76] reorder variables for easier review --- packages/block-library/src/post-template/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 92be174f7e5ef..e12ee3119c066 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -64,8 +64,8 @@ function render_block_core_post_template( $attributes, $content, $block ) { */ if ( in_the_loop() ) { $query = clone $wp_query; - $query_args = $wp_query->query_vars; $query->rewind_posts(); + $query_args = $wp_query->query_vars; // Add search parameter if it exists. if ( $enhanced_pagination && ! empty( $search_query ) ) { From 288603ad1f63eff600e4196d0415b77f5f627b39 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 10 Oct 2024 15:21:04 +0100 Subject: [PATCH 14/76] remove linebreak --- packages/block-library/src/post-template/index.php | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index e12ee3119c066..8a1dcab03502f 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -72,7 +72,6 @@ function render_block_core_post_template( $attributes, $content, $block ) { $query_args['s'] = $search_query; } $query->query( $query_args ); - } else { // The query has not been run yet, modify the global query. if ( $enhanced_pagination && ! empty( $search_query ) ) { From 03d1be096e57595ce5b21cb7549bc9fcca6d274f Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 10 Oct 2024 16:08:59 +0100 Subject: [PATCH 15/76] Add the missing space before parens --- packages/block-library/src/search/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index 39347a0a2ca95..e2e2444c2bd9a 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -81,7 +81,7 @@ function render_block_core_search( $attributes, $content, $block ) { // If it's interactive, enqueue the script module and add the directives. $is_expandable_searchfield = 'button-only' === $button_position; - if ( $is_expandable_searchfield || $enhanced_pagination) { + if ( $is_expandable_searchfield || $enhanced_pagination ) { wp_enqueue_script_module( '@wordpress/block-library/search/view' ); } From 1495a42baa8470d8ada4ac5d2450006a4d28af5c Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 10 Oct 2024 18:55:02 +0100 Subject: [PATCH 16/76] Add the experimental setting --- lib/experimental/editor-settings.php | 4 ++++ lib/experiments-page.php | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php index 126382f85a513..5b9764c837742 100644 --- a/lib/experimental/editor-settings.php +++ b/lib/experimental/editor-settings.php @@ -34,6 +34,10 @@ function gutenberg_enable_experiments() { if ( $gutenberg_experiments && array_key_exists( 'gutenberg-media-processing', $gutenberg_experiments ) ) { wp_add_inline_script( 'wp-block-editor', 'window.__experimentalMediaProcessing = true', 'before' ); } + + if ( $gutenberg_experiments && array_key_exists( 'gutenberg-search-query-block', $gutenberg_experiments ) ) { + wp_add_inline_script( 'wp-block-editor', 'window.__experimentalSearchQueryBlock = true', 'before' ); + } } add_action( 'admin_init', 'gutenberg_enable_experiments' ); diff --git a/lib/experiments-page.php b/lib/experiments-page.php index 27a54b920f4d5..9de707fb0d2db 100644 --- a/lib/experiments-page.php +++ b/lib/experiments-page.php @@ -175,6 +175,18 @@ function gutenberg_initialize_experiments_settings() { ) ); + add_settings_field( + 'gutenberg-search-query-block', + __( 'Instant Search and Query Block', 'gutenberg' ), + 'gutenberg_display_experiment_field', + 'gutenberg-experiments', + 'gutenberg_experiments_section', + array( + 'label' => __( 'Enable instant search functionality of the Search + Query blocks.', 'gutenberg' ), + 'id' => 'gutenberg-search-query-block', + ) + ); + register_setting( 'gutenberg-experiments', 'gutenberg-experiments' From f249ed317f42dfdc2287d8d36eab9905665761ed Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 10 Oct 2024 18:57:21 +0100 Subject: [PATCH 17/76] Add the experimental setting of for search and query block --- packages/block-library/src/post-template/index.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 8a1dcab03502f..49911bc4c1186 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -52,6 +52,9 @@ function render_block_core_post_template( $attributes, $content, $block ) { $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; $search_query = empty( $_GET['search'] ) ? '' : sanitize_text_field( $_GET['search'] ); + $gutenberg_experiments = get_option( 'gutenberg-experiments' ); + $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; + // Use global query if needed. $use_global_query = ( isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] ); if ( $use_global_query ) { @@ -68,13 +71,13 @@ function render_block_core_post_template( $attributes, $content, $block ) { $query_args = $wp_query->query_vars; // Add search parameter if it exists. - if ( $enhanced_pagination && ! empty( $search_query ) ) { + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) ) { $query_args['s'] = $search_query; } $query->query( $query_args ); } else { // The query has not been run yet, modify the global query. - if ( $enhanced_pagination && ! empty( $search_query ) ) { + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) ) { $wp_query->set( 's', $search_query ); } $query = $wp_query; @@ -84,7 +87,7 @@ function render_block_core_post_template( $attributes, $content, $block ) { $query_args = build_query_vars_from_query_block( $block, $page ); // Add search parameter if enhanced pagination is on and search query exists - if ( $enhanced_pagination && ! empty( $search_query ) ) { + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) ) { $query_args['s'] = $search_query; } From ca0e697036db0d0c61b5cb0536c14cc2ca962aec Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 10 Oct 2024 19:01:47 +0100 Subject: [PATCH 18/76] Fix the phpcs spaces --- packages/block-library/src/post-template/index.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 49911bc4c1186..0ae5c5d2741fd 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -52,7 +52,8 @@ function render_block_core_post_template( $attributes, $content, $block ) { $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; $search_query = empty( $_GET['search'] ) ? '' : sanitize_text_field( $_GET['search'] ); - $gutenberg_experiments = get_option( 'gutenberg-experiments' ); + // Check if the Instant Search experiment is enabled. + $gutenberg_experiments = get_option( 'gutenberg-experiments' ); $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; // Use global query if needed. From d2fb6e6a3d72f08acfcd131048943a2d06edc0d9 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 10 Oct 2024 19:03:48 +0100 Subject: [PATCH 19/76] =?UTF-8?q?Actually=20fix=20the=20phpcs=20lint=20?= =?UTF-8?q?=F0=9F=A4=A6=E2=80=8D=E2=99=82=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/block-library/src/post-template/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 0ae5c5d2741fd..b08722759f037 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -53,7 +53,7 @@ function render_block_core_post_template( $attributes, $content, $block ) { $search_query = empty( $_GET['search'] ) ? '' : sanitize_text_field( $_GET['search'] ); // Check if the Instant Search experiment is enabled. - $gutenberg_experiments = get_option( 'gutenberg-experiments' ); + $gutenberg_experiments = get_option( 'gutenberg-experiments' ); $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; // Use global query if needed. From 68d780e9a05f9076b649243cef5389504b6b8e48 Mon Sep 17 00:00:00 2001 From: rchrzan Date: Mon, 14 Oct 2024 17:07:53 +0200 Subject: [PATCH 20/76] Changes from #65950 --- lib/experimental/editor-settings.php | 3 ++ lib/experiments-page.php | 12 +++++++ .../block-library/src/post-template/index.php | 24 ++++++++++++- packages/block-library/src/search/view.js | 35 ++++++++++--------- 4 files changed, 56 insertions(+), 18 deletions(-) diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php index 126382f85a513..88611e77544be 100644 --- a/lib/experimental/editor-settings.php +++ b/lib/experimental/editor-settings.php @@ -34,6 +34,9 @@ function gutenberg_enable_experiments() { if ( $gutenberg_experiments && array_key_exists( 'gutenberg-media-processing', $gutenberg_experiments ) ) { wp_add_inline_script( 'wp-block-editor', 'window.__experimentalMediaProcessing = true', 'before' ); } + if ( $gutenberg_experiments && array_key_exists( 'gutenberg-search-query-block', $gutenberg_experiments ) ) { + wp_add_inline_script( 'wp-block-editor', 'window.__experimentalSearchQueryBlock = true', 'before' ); + } } add_action( 'admin_init', 'gutenberg_enable_experiments' ); diff --git a/lib/experiments-page.php b/lib/experiments-page.php index 27a54b920f4d5..9de707fb0d2db 100644 --- a/lib/experiments-page.php +++ b/lib/experiments-page.php @@ -175,6 +175,18 @@ function gutenberg_initialize_experiments_settings() { ) ); + add_settings_field( + 'gutenberg-search-query-block', + __( 'Instant Search and Query Block', 'gutenberg' ), + 'gutenberg_display_experiment_field', + 'gutenberg-experiments', + 'gutenberg_experiments_section', + array( + 'label' => __( 'Enable instant search functionality of the Search + Query blocks.', 'gutenberg' ), + 'id' => 'gutenberg-search-query-block', + ) + ); + register_setting( 'gutenberg-experiments', 'gutenberg-experiments' diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 9126355c096a5..691fa0ec90f1b 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -50,6 +50,11 @@ function render_block_core_post_template( $attributes, $content, $block ) { $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; + $search_query = empty( $_GET['search'] ) ? '' : sanitize_text_field( $_GET['search'] ); + + // Check if the Instant Search experiment is enabled. + $gutenberg_experiments = get_option( 'gutenberg-experiments' ); + $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; // Use global query if needed. $use_global_query = ( isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] ); @@ -64,12 +69,29 @@ function render_block_core_post_template( $attributes, $content, $block ) { if ( in_the_loop() ) { $query = clone $wp_query; $query->rewind_posts(); + $query_args = $wp_query->query_vars; + + // Add search parameter if it exists. + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) ) { + $query_args['s'] = $search_query; + } + $query->query( $query_args ); } else { + // The query has not been run yet, modify the global query. + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) ) { + $wp_query->set( 's', $search_query ); + } $query = $wp_query; } } else { $query_args = build_query_vars_from_query_block( $block, $page ); - $query = new WP_Query( $query_args ); + + // Add search parameter if enhanced pagination is on and search query exists + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) ) { + $query_args['s'] = $search_query; + } + + $query = new WP_Query( $query_args ); } if ( ! $query->have_posts() ) { diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index c13f66cb99043..dff0c5608a09f 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -7,21 +7,6 @@ const isEmpty = ( obj ) => [ Object, Array ].includes( ( obj || {} ).constructor ) && ! Object.entries( obj || {} ).length; -const updateURL = async ( value, name ) => { - const url = new URL( window.location ); - const { actions } = await import( '@wordpress/interactivity-router' ); - - if ( 's' === name ) { - if ( ! isEmpty( value ) ) { - url.searchParams.set( 'search', value ); - } else { - url.searchParams.delete( 'search' ); - } - } - - await actions.navigate( `${ window.location.pathname }${ url.search }` ); -}; - const { state, actions } = store( 'core/search', { @@ -50,6 +35,10 @@ const { state, actions } = store( }, get isSearchInputVisible() { const ctx = getContext(); + + // `ctx.isSearchInputVisible` is a client-side-only context value, so + // if it's not set, it means that it's an initial page load, so we need + // to return the value of `ctx.isSearchInputInitiallyVisible`. if ( typeof ctx.isSearchInputVisible === 'undefined' ) { return ctx.isSearchInputInitiallyVisible; } @@ -101,12 +90,24 @@ const { state, actions } = store( return; } + const url = new URL( window.location ); + if ( 's' === name ) { state.search = value; + if ( ! isEmpty( value ) ) { + url.searchParams.set( 'search', value ); + } else { + url.searchParams.delete( 'search' ); + } } - // If not, navigate to the new URL. - yield updateURL( value, name ); + const { actions: routerActions } = yield import( + '@wordpress/interactivity-router' + ); + + routerActions.navigate( + `${ window.location.pathname }${ url.search }` + ); }, }, }, From ed9b908d030fc6d3e390aa2ae8004bbedc19bfe5 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 15 Oct 2024 17:54:13 +0100 Subject: [PATCH 21/76] Rename `search` to `instant-search` --- packages/block-library/src/post-template/index.php | 2 +- packages/block-library/src/search/index.php | 2 +- packages/block-library/src/search/view.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index b08722759f037..b01eb0ba1f15d 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -50,7 +50,7 @@ function render_block_core_post_template( $attributes, $content, $block ) { $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; - $search_query = empty( $_GET['search'] ) ? '' : sanitize_text_field( $_GET['search'] ); + $search_query = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); // Check if the Instant Search experiment is enabled. $gutenberg_experiments = get_option( 'gutenberg-experiments' ); diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index e2e2444c2bd9a..b21e3632ceef9 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -183,7 +183,7 @@ function render_block_core_search( $attributes, $content, $block ) { wp_interactivity_state( 'core/search', array( - 'search' => isset( $_GET['search'] ) ? $_GET['search'] : '', + 'search' => isset( $_GET['instant-search'] ) ? $_GET['instant-search'] : '', ) ); } diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index dff0c5608a09f..559bf84b5b0f1 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -95,9 +95,9 @@ const { state, actions } = store( if ( 's' === name ) { state.search = value; if ( ! isEmpty( value ) ) { - url.searchParams.set( 'search', value ); + url.searchParams.set( 'instant-search', value ); } else { - url.searchParams.delete( 'search' ); + url.searchParams.delete( 'instant-search' ); } } From c63840a8e55d66c5370e622ea805ced6ee7f6fea Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 16 Oct 2024 12:22:25 +0100 Subject: [PATCH 22/76] remove the `name` --- packages/block-library/src/search/view.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index 559bf84b5b0f1..91b31e771e65a 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -83,22 +83,20 @@ const { state, actions } = store( }, *updateSearch() { const { ref } = getElement(); - const { value, name } = ref; + const { value } = ref; // Don't navigate if the search didn't really change. - if ( 's' === name && value === state.search ) { + if ( value === state.search ) { return; } const url = new URL( window.location ); - if ( 's' === name ) { + if ( ! isEmpty( value ) ) { state.search = value; - if ( ! isEmpty( value ) ) { - url.searchParams.set( 'instant-search', value ); - } else { - url.searchParams.delete( 'instant-search' ); - } + url.searchParams.set( 'instant-search', value ); + } else { + url.searchParams.delete( 'instant-search' ); } const { actions: routerActions } = yield import( From a55194fe44a0b1b241735345282113e282420177 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 16 Oct 2024 12:35:19 +0100 Subject: [PATCH 23/76] Add support for inherited queries --- .../block-library/src/post-template/index.php | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index b01eb0ba1f15d..feb8926118c94 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -69,22 +69,22 @@ function render_block_core_post_template( $attributes, $content, $block ) { if ( in_the_loop() ) { $query = clone $wp_query; $query->rewind_posts(); - $query_args = $wp_query->query_vars; - - // Add search parameter if it exists. - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) ) { - $query_args['s'] = $search_query; - } - $query->query( $query_args ); } else { - // The query has not been run yet, modify the global query. - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) ) { - $wp_query->set( 's', $search_query ); - } $query = $wp_query; } - } else { + /* + * If the following conditions are met, run a new query with the search query: + * 1. Enhanced pagination is on. + * 2. Instant search is enabled. + * 3. The search query is not empty. + * 4. The query already has posts. + */ + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) && $query->have_posts() ) { + $args = array_merge( $query->query_vars, array( 's' => $search_query ) ); + $query = new WP_Query( $args ); + } + } else { $query_args = build_query_vars_from_query_block( $block, $page ); // Add search parameter if enhanced pagination is on and search query exists From 81ba04c8a023293827296a137be08366f8eed736 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 16 Oct 2024 12:55:59 +0100 Subject: [PATCH 24/76] remove the unneeded changes to post-template/index.php --- packages/block-library/src/post-template/index.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index f3cabeb6a33a5..feb8926118c94 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -69,18 +69,7 @@ function render_block_core_post_template( $attributes, $content, $block ) { if ( in_the_loop() ) { $query = clone $wp_query; $query->rewind_posts(); - $query_args = $wp_query->query_vars; - - // Add search parameter if it exists. - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) ) { - $query_args['s'] = $search_query; - } - $query->query( $query_args ); } else { - // The query has not been run yet, modify the global query. - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) ) { - $wp_query->set( 's', $search_query ); - } $query = $wp_query; } From fa14b259c48159de50c314cd35896f7054ae6ee1 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 16 Oct 2024 13:00:21 +0100 Subject: [PATCH 25/76] debounce the search --- packages/block-library/src/search/view.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index 91b31e771e65a..66bd4191c0558 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -90,8 +90,17 @@ const { state, actions } = store( return; } - const url = new URL( window.location ); + state.search = value; + // Debounce the search by 300ms to prevent multiple navigations. + // We can do this by yielding a promise that resolves after 300ms and + // then bailing out if the search has changed. + yield new Promise( ( resolve ) => setTimeout( resolve, 300 ) ); + if ( value !== state.search ) { + return; + } + + const url = new URL( window.location ); if ( ! isEmpty( value ) ) { state.search = value; url.searchParams.set( 'instant-search', value ); From a699ce37193599223555f554a4ba8b35c44cc70e Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 16 Oct 2024 14:05:59 +0100 Subject: [PATCH 26/76] fix phpcs complaint --- packages/block-library/src/post-template/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index feb8926118c94..2899e07224294 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -81,7 +81,7 @@ function render_block_core_post_template( $attributes, $content, $block ) { * 4. The query already has posts. */ if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) && $query->have_posts() ) { - $args = array_merge( $query->query_vars, array( 's' => $search_query ) ); + $args = array_merge( $query->query_vars, array( 's' => $search_query ) ); $query = new WP_Query( $args ); } } else { From 9a4e78f48985973d79128119c626c06947a836b1 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 16 Oct 2024 16:11:35 +0100 Subject: [PATCH 27/76] data-on-async--input --- packages/block-library/src/search/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index b21e3632ceef9..633884f3929e2 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -97,7 +97,7 @@ function render_block_core_search( $attributes, $content, $block ) { // Instant search is only available when using the enhanced pagination. if ( $enhanced_pagination ) { $input->set_attribute( 'data-wp-bind--value', 'state.search' ); - $input->set_attribute( 'data-wp-on--input', 'actions.updateSearch' ); + $input->set_attribute( 'data-wp-on-async--input', 'actions.updateSearch' ); } } From aaeee09cbdaba188bd2c5aa926f0a883bc7dbe56 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 16 Oct 2024 16:38:08 +0100 Subject: [PATCH 28/76] use `window.location.href` --- packages/block-library/src/search/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index 66bd4191c0558..7b0a7f5278546 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -100,7 +100,7 @@ const { state, actions } = store( return; } - const url = new URL( window.location ); + const url = new URL( window.location.href ); if ( ! isEmpty( value ) ) { state.search = value; url.searchParams.set( 'instant-search', value ); From 818bc96a30ab3d944d0c6514032c6df9dbcaed6a Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 16 Oct 2024 16:43:38 +0100 Subject: [PATCH 29/76] use the constructed URL --- packages/block-library/src/search/view.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index 7b0a7f5278546..9bdc8275067f0 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -112,9 +112,7 @@ const { state, actions } = store( '@wordpress/interactivity-router' ); - routerActions.navigate( - `${ window.location.pathname }${ url.search }` - ); + routerActions.navigate( url.href ); }, }, }, From 289f583eede0e044b563ba5ca50cd77cff4a4e56 Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 17 Oct 2024 16:13:55 +0100 Subject: [PATCH 30/76] Update packages/block-library/src/search/view.js remove the isEmpty() function Co-authored-by: Jon Surrell --- packages/block-library/src/search/view.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index 9bdc8275067f0..e6da11563b2e7 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -3,9 +3,6 @@ */ import { store, getContext, getElement } from '@wordpress/interactivity'; -const isEmpty = ( obj ) => - [ Object, Array ].includes( ( obj || {} ).constructor ) && - ! Object.entries( obj || {} ).length; const { state, actions } = store( 'core/search', From c55cf31d8a24bb2040679f8508f77a0aa042627b Mon Sep 17 00:00:00 2001 From: Michal Date: Thu, 17 Oct 2024 16:14:35 +0100 Subject: [PATCH 31/76] Update packages/block-library/src/search/view.js clear the `paged` param and remove the `isEmpty(value)` check Co-authored-by: Jon Surrell --- packages/block-library/src/search/view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index e6da11563b2e7..cdad703789c8d 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -98,8 +98,8 @@ const { state, actions } = store( } const url = new URL( window.location.href ); - if ( ! isEmpty( value ) ) { - state.search = value; + url.searchParams.delete( 'paged' ); + if ( value ) { url.searchParams.set( 'instant-search', value ); } else { url.searchParams.delete( 'instant-search' ); From 87f5d005983982c848a6c58845289699fdf8c658 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 17 Oct 2024 17:31:23 +0100 Subject: [PATCH 32/76] get value from event.target --- packages/block-library/src/search/view.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index cdad703789c8d..84f3a35b594ce 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -3,7 +3,6 @@ */ import { store, getContext, getElement } from '@wordpress/interactivity'; - const { state, actions } = store( 'core/search', { @@ -78,9 +77,8 @@ const { state, actions } = store( actions.closeSearchInput(); } }, - *updateSearch() { - const { ref } = getElement(); - const { value } = ref; + *updateSearch( e ) { + const { value } = e.target; // Don't navigate if the search didn't really change. if ( value === state.search ) { From 853083b4b4e17736da6a343dfa5029bea446a64b Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 24 Oct 2024 18:00:42 +0100 Subject: [PATCH 33/76] Add inherited context to search block --- packages/block-library/src/search/block.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/search/block.json b/packages/block-library/src/search/block.json index d56c4b8809ccf..e7207498125d6 100644 --- a/packages/block-library/src/search/block.json +++ b/packages/block-library/src/search/block.json @@ -48,7 +48,7 @@ "default": false } }, - "usesContext": [ "enhancedPagination" ], + "usesContext": [ "enhancedPagination", "query", "queryId" ], "supports": { "align": [ "left", "center", "right" ], "color": { From 3b5da50e58b548e965ed79bb62708d1ee21b4991 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 24 Oct 2024 18:01:37 +0100 Subject: [PATCH 34/76] Remove state and add the search to context in Search block --- packages/block-library/src/search/index.php | 24 +++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index 633884f3929e2..12968bce63490 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -96,7 +96,7 @@ function render_block_core_search( $attributes, $content, $block ) { } // Instant search is only available when using the enhanced pagination. if ( $enhanced_pagination ) { - $input->set_attribute( 'data-wp-bind--value', 'state.search' ); + $input->set_attribute( 'data-wp-bind--value', 'context.search' ); $input->set_attribute( 'data-wp-on-async--input', 'actions.updateSearch' ); } } @@ -178,15 +178,6 @@ function render_block_core_search( $attributes, $content, $block ) { $form_directives = 'data-wp-interactive="core/search"'; } - // Adding wp_interactivity_state for the search block. - if ( $enhanced_pagination ) { - wp_interactivity_state( - 'core/search', - array( - 'search' => isset( $_GET['instant-search'] ) ? $_GET['instant-search'] : '', - ) - ); - } if ( $is_expandable_searchfield ) { $aria_label_expanded = __( 'Submit Search' ); @@ -197,12 +188,17 @@ function render_block_core_search( $attributes, $content, $block ) { 'inputId' => $input_id, 'ariaLabelExpanded' => $aria_label_expanded, 'ariaLabelCollapsed' => $aria_label_collapsed, + 'search' => empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ), + 'isInherited' => isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'], + 'queryId' => $block->context['queryId'], ) ); - $form_directives .= $form_context . - 'data-wp-class--wp-block-search__searchfield-hidden="!context.isSearchInputVisible" - data-wp-on-async--keydown="actions.handleSearchKeydown" - data-wp-on-async--focusout="actions.handleSearchFocusout" + $form_directives = ' + data-wp-interactive="core/search"' + . $form_context . + 'data-wp-class--wp-block-search__searchfield-hidden="!context.isSearchInputVisible" + data-wp-on-async--keydown="actions.handleSearchKeydown" + data-wp-on-async--focusout="actions.handleSearchFocusout" '; } From 1996b8336416603c08a774847b6f81435945950d Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 24 Oct 2024 21:46:11 +0100 Subject: [PATCH 35/76] Use a proper debounce and take into account the multiple query blocks --- .../block-library/src/post-template/index.php | 17 +++++---- packages/block-library/src/search/index.php | 33 +++++++++------- packages/block-library/src/search/view.js | 38 +++++++++++++++---- 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 2899e07224294..7f671ca8b26ea 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -47,10 +47,11 @@ function block_core_post_template_uses_featured_image( $inner_blocks ) { * @return string Returns the output of the query, structured using the layout defined by the block's inner blocks. */ function render_block_core_post_template( $attributes, $content, $block ) { - $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; - $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; - $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; - $search_query = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; + $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; + $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; + $search_query_inherited = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + $search_query_direct = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); // Check if the Instant Search experiment is enabled. $gutenberg_experiments = get_option( 'gutenberg-experiments' ); @@ -80,16 +81,16 @@ function render_block_core_post_template( $attributes, $content, $block ) { * 3. The search query is not empty. * 4. The query already has posts. */ - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) && $query->have_posts() ) { - $args = array_merge( $query->query_vars, array( 's' => $search_query ) ); + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_inherited ) && $query->have_posts() ) { + $args = array_merge( $query->query_vars, array( 's' => $search_query_inherited ) ); $query = new WP_Query( $args ); } } else { $query_args = build_query_vars_from_query_block( $block, $page ); // Add search parameter if enhanced pagination is on and search query exists - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query ) ) { - $query_args['s'] = $search_query; + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_direct ) ) { + $query_args['s'] = $search_query_direct; } $query = new WP_Query( $query_args ); diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index 12968bce63490..feec02102a58a 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -172,6 +172,7 @@ function render_block_core_search( $attributes, $content, $block ) { array( 'class' => $classnames ) ); $form_directives = ''; + $form_context = array(); // If it's interactive, add the directives. if ( $is_expandable_searchfield || $enhanced_pagination ) { @@ -182,26 +183,32 @@ function render_block_core_search( $attributes, $content, $block ) { if ( $is_expandable_searchfield ) { $aria_label_expanded = __( 'Submit Search' ); $aria_label_collapsed = __( 'Expand search field' ); - $form_context = wp_interactivity_data_wp_context( - array( - 'isSearchInputInitiallyVisible' => $open_by_default, - 'inputId' => $input_id, - 'ariaLabelExpanded' => $aria_label_expanded, - 'ariaLabelCollapsed' => $aria_label_collapsed, - 'search' => empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ), - 'isInherited' => isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'], - 'queryId' => $block->context['queryId'], - ) + $form_context = array( + 'isSearchInputInitiallyVisible' => $open_by_default, + 'inputId' => $input_id, + 'ariaLabelExpanded' => $aria_label_expanded, + 'ariaLabelCollapsed' => $aria_label_collapsed, ); - $form_directives = ' - data-wp-interactive="core/search"' - . $form_context . + $form_directives .= 'data-wp-class--wp-block-search__searchfield-hidden="!context.isSearchInputVisible" data-wp-on-async--keydown="actions.handleSearchKeydown" data-wp-on-async--focusout="actions.handleSearchFocusout" '; } + if ( $enhanced_pagination ) { + $form_context = array_merge( + $form_context, + array( + 'search' => empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ), + 'isInherited' => isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'], + 'queryId' => $block->context['queryId'], + ) + ); + } + + $form_directives .= wp_interactivity_data_wp_context( $form_context ); + return sprintf( '
%4s
', esc_url( home_url( '/' ) ), diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index 84f3a35b594ce..e87c83baff8dd 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -3,6 +3,9 @@ */ import { store, getContext, getElement } from '@wordpress/interactivity'; +/** @type {( () => void ) | null} */ +let supersedePreviousSearch = null; + const { state, actions } = store( 'core/search', { @@ -80,27 +83,48 @@ const { state, actions } = store( *updateSearch( e ) { const { value } = e.target; + const ctx = getContext(); + // Don't navigate if the search didn't really change. - if ( value === state.search ) { + if ( value === ctx.search ) { return; } - state.search = value; + ctx.search = value; // Debounce the search by 300ms to prevent multiple navigations. - // We can do this by yielding a promise that resolves after 300ms and - // then bailing out if the search has changed. - yield new Promise( ( resolve ) => setTimeout( resolve, 300 ) ); - if ( value !== state.search ) { + supersedePreviousSearch?.(); + const { promise, resolve, reject } = Promise.withResolvers(); + const timeout = setTimeout( resolve, 300 ); + supersedePreviousSearch = () => { + clearTimeout( timeout ); + reject(); + }; + try { + yield promise; + } catch { return; } const url = new URL( window.location.href ); url.searchParams.delete( 'paged' ); + if ( value ) { - url.searchParams.set( 'instant-search', value ); + if ( ctx.isInherited ) { + url.searchParams.set( 'instant-search', value ); + } else { + // Set the instant-search parameter using the query ID and search value + const queryId = ctx.queryId; + url.searchParams.set( + `instant-search-${ queryId }`, + value + ); + } } else { url.searchParams.delete( 'instant-search' ); + url.searchParams.delete( + `instant-search-${ ctx.queryId }` + ); } const { actions: routerActions } = yield import( From 020c638d3058527b4381efde56293c0809487951 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 24 Oct 2024 21:50:39 +0100 Subject: [PATCH 36/76] simplify how we enqueue search/view module --- packages/block-library/src/search/index.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index feec02102a58a..4247dca3b9616 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -81,11 +81,9 @@ function render_block_core_search( $attributes, $content, $block ) { // If it's interactive, enqueue the script module and add the directives. $is_expandable_searchfield = 'button-only' === $button_position; - if ( $is_expandable_searchfield || $enhanced_pagination ) { + if ( $is_expandable_searchfield ) { wp_enqueue_script_module( '@wordpress/block-library/search/view' ); - } - if ( $is_expandable_searchfield ) { $input->set_attribute( 'data-wp-bind--aria-hidden', '!context.isSearchInputVisible' ); $input->set_attribute( 'data-wp-bind--tabindex', 'state.tabindex' ); @@ -94,8 +92,10 @@ function render_block_core_search( $attributes, $content, $block ) { $input->set_attribute( 'aria-hidden', 'true' ); $input->set_attribute( 'tabindex', '-1' ); } + // Instant search is only available when using the enhanced pagination. if ( $enhanced_pagination ) { + wp_enqueue_script_module( '@wordpress/block-library/search/view' ); $input->set_attribute( 'data-wp-bind--value', 'context.search' ); $input->set_attribute( 'data-wp-on-async--input', 'actions.updateSearch' ); } From 853bed502e9ac1b12c1fe8a46feb8debef4c1d7f Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 28 Oct 2024 17:38:19 +0000 Subject: [PATCH 37/76] Update the query pagination numbers. --- .../src/query-pagination-numbers/index.php | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/query-pagination-numbers/index.php b/packages/block-library/src/query-pagination-numbers/index.php index fddf28660fe4f..3ea63d4892f01 100644 --- a/packages/block-library/src/query-pagination-numbers/index.php +++ b/packages/block-library/src/query-pagination-numbers/index.php @@ -5,6 +5,18 @@ * @package WordPress */ + +/** + * Get the total number of pages from the query. + * + * @param WP_Query $query The query object. + * @param int $max_page The maximum number of pages, usually set in the block context. + * @return int The total number of pages. + */ +function block_core_query_pagination_numbers_get_total_pages_from_query( $query, $max_page ) { + return ! $max_page || $max_page > $query->max_num_pages ? $query->max_num_pages : $max_page; +} + /** * Renders the `core/query-pagination-numbers` block on the server. * @@ -24,14 +36,33 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; $max_page = isset( $block->context['query']['pages'] ) ? (int) $block->context['query']['pages'] : 0; + // Add check for instant search experiment and search query + $gutenberg_experiments = get_option( 'gutenberg-experiments' ); + $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; + $search_query_inherited = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + $search_query_direct = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); + + $wrapper_attributes = get_block_wrapper_attributes(); $content = ''; global $wp_query; $mid_size = isset( $block->attributes['midSize'] ) ? (int) $block->attributes['midSize'] : null; + if ( isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] ) { // Take into account if we have set a bigger `max page` // than what the query has. - $total = ! $max_page || $max_page > $wp_query->max_num_pages ? $wp_query->max_num_pages : $max_page; + $total = block_core_query_pagination_numbers_get_total_pages_from_query( $wp_query, $max_page ); + + // If instant search is enabled and we have a search query, run a new query + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_inherited ) ) { + $args = array_merge( + $wp_query->query_vars, + array( 's' => $search_query_inherited ) + ); + $search_query = new WP_Query( $args ); + $total = block_core_query_pagination_numbers_get_total_pages_from_query( $search_query, $max_page ); + } + $paginate_args = array( 'prev_next' => false, 'total' => $total, @@ -41,12 +72,21 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo } $content = paginate_links( $paginate_args ); } else { - $block_query = new WP_Query( build_query_vars_from_query_block( $block, $page ) ); + // Add check for instant search experiment and search query + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_direct ) ) { + $args = array_merge( + build_query_vars_from_query_block( $block, $page ), + array( 's' => $search_query_direct ) + ); + $block_query = new WP_Query( $args ); + } else { + $block_query = new WP_Query( build_query_vars_from_query_block( $block, $page ) ); + } // `paginate_links` works with the global $wp_query, so we have to // temporarily switch it with our custom query. $prev_wp_query = $wp_query; $wp_query = $block_query; - $total = ! $max_page || $max_page > $wp_query->max_num_pages ? $wp_query->max_num_pages : $max_page; + $total = block_core_query_pagination_numbers_get_total_pages_from_query( $wp_query, $max_page ); $paginate_args = array( 'base' => '%_%', 'format' => "?$page_key=%#%", From 51caf3e12255c5a9674606eeec10bf044b10e8d7 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 28 Oct 2024 18:56:14 +0000 Subject: [PATCH 38/76] Reset the pagination upon navigation --- packages/block-library/src/search/view.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index e87c83baff8dd..9657b917da921 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -107,6 +107,8 @@ const { state, actions } = store( } const url = new URL( window.location.href ); + + // Make sure we reset the pagination. url.searchParams.delete( 'paged' ); if ( value ) { @@ -119,6 +121,9 @@ const { state, actions } = store( `instant-search-${ queryId }`, value ); + + // Make sure we reset the pagination. + url.searchParams.set( `query-${ queryId }-page`, '1' ); } } else { url.searchParams.delete( 'instant-search' ); From f2e16be60417d04b4fdb3a326c74e704b40ca657 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 28 Oct 2024 19:25:14 +0000 Subject: [PATCH 39/76] Handle query-pagination-next correctly --- .../src/query-pagination-next/index.php | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/query-pagination-next/index.php b/packages/block-library/src/query-pagination-next/index.php index 3b5be47fbed37..219d3851947d4 100644 --- a/packages/block-library/src/query-pagination-next/index.php +++ b/packages/block-library/src/query-pagination-next/index.php @@ -24,6 +24,12 @@ function render_block_core_query_pagination_next( $attributes, $content, $block $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; $max_page = isset( $block->context['query']['pages'] ) ? (int) $block->context['query']['pages'] : 0; + // Add check for instant search experiment and search query + $gutenberg_experiments = get_option( 'gutenberg-experiments' ); + $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; + $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + $search_query_direct = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); + $wrapper_attributes = get_block_wrapper_attributes(); $show_label = isset( $block->context['showLabel'] ) ? (bool) $block->context['showLabel'] : true; $default_label = __( 'Next Page' ); @@ -51,10 +57,32 @@ function render_block_core_query_pagination_next( $attributes, $content, $block if ( $max_page > $wp_query->max_num_pages ) { $max_page = $wp_query->max_num_pages; } + + // If instant search is enabled and we have a search query, run a new query + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) ) { + $args = array_merge( + $wp_query->query_vars, + array( 's' => $search_query_global ) + ); + $search_query = new WP_Query( $args ); + $max_page = $search_query->max_num_pages; + } + $content = get_next_posts_link( $label, $max_page ); remove_filter( 'next_posts_link_attributes', $filter_link_attributes ); } elseif ( ! $max_page || $max_page > $page ) { - $custom_query = new WP_Query( build_query_vars_from_query_block( $block, $page ) ); + // Add check for instant search experiment and search query + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_direct ) ) { + $args = array_merge( + build_query_vars_from_query_block( $block, $page ), + array( 's' => $search_query_direct ) + ); + $custom_query = new WP_Query( $args ); + } else { + $custom_query = new WP_Query( build_query_vars_from_query_block( $block, $page ) ); + } + + $custom_query_max_pages = (int) $custom_query->max_num_pages; if ( $custom_query_max_pages && $custom_query_max_pages !== $page ) { $content = sprintf( From e89fd61ecc5a6d44f20471c2896575979da2f001 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 28 Oct 2024 19:28:16 +0000 Subject: [PATCH 40/76] Rename $search_query_inherited to $search_query_global --- packages/block-library/src/post-template/index.php | 6 +++--- .../block-library/src/query-pagination-numbers/index.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 7f671ca8b26ea..7734f22c31f80 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -50,7 +50,7 @@ function render_block_core_post_template( $attributes, $content, $block ) { $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; - $search_query_inherited = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); $search_query_direct = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); // Check if the Instant Search experiment is enabled. @@ -81,8 +81,8 @@ function render_block_core_post_template( $attributes, $content, $block ) { * 3. The search query is not empty. * 4. The query already has posts. */ - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_inherited ) && $query->have_posts() ) { - $args = array_merge( $query->query_vars, array( 's' => $search_query_inherited ) ); + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) && $query->have_posts() ) { + $args = array_merge( $query->query_vars, array( 's' => $search_query_global ) ); $query = new WP_Query( $args ); } } else { diff --git a/packages/block-library/src/query-pagination-numbers/index.php b/packages/block-library/src/query-pagination-numbers/index.php index 3ea63d4892f01..447439299e90b 100644 --- a/packages/block-library/src/query-pagination-numbers/index.php +++ b/packages/block-library/src/query-pagination-numbers/index.php @@ -39,7 +39,7 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo // Add check for instant search experiment and search query $gutenberg_experiments = get_option( 'gutenberg-experiments' ); $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; - $search_query_inherited = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); $search_query_direct = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); @@ -54,10 +54,10 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo $total = block_core_query_pagination_numbers_get_total_pages_from_query( $wp_query, $max_page ); // If instant search is enabled and we have a search query, run a new query - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_inherited ) ) { + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) ) { $args = array_merge( $wp_query->query_vars, - array( 's' => $search_query_inherited ) + array( 's' => $search_query_global ) ); $search_query = new WP_Query( $args ); $total = block_core_query_pagination_numbers_get_total_pages_from_query( $search_query, $max_page ); From 9a0e1610b7cbe98c64cd37ca97bad559ac53ac17 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 28 Oct 2024 19:29:07 +0000 Subject: [PATCH 41/76] Ensure that the global instant search gets passed to the URL. --- packages/block-library/src/search/index.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index 4247dca3b9616..fee25eacd6970 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -197,11 +197,20 @@ function render_block_core_search( $attributes, $content, $block ) { } if ( $enhanced_pagination ) { + $is_inherited = isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit']; + $search = ''; + + if ( $is_inherited ) { + $search = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + } else { + $search = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); + } + $form_context = array_merge( $form_context, array( - 'search' => empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ), - 'isInherited' => isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'], + 'search' => $search, + 'isInherited' => $is_inherited, 'queryId' => $block->context['queryId'], ) ); From 5e00cdbfec7f5a51dc8b11200357b429a2e1ff45 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 28 Oct 2024 19:29:47 +0000 Subject: [PATCH 42/76] Don't remove the `paged` query param. Set it to `1` instead. --- packages/block-library/src/search/view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index 9657b917da921..f1dcf457b2b3b 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -109,7 +109,7 @@ const { state, actions } = store( const url = new URL( window.location.href ); // Make sure we reset the pagination. - url.searchParams.delete( 'paged' ); + url.searchParams.set( 'paged', '1' ); if ( value ) { if ( ctx.isInherited ) { From 786f7ba0b4ee96ad117a6fa2848ded45d38a8302 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 28 Oct 2024 19:32:47 +0000 Subject: [PATCH 43/76] Remove the pagination when clearing the search --- packages/block-library/src/search/view.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index f1dcf457b2b3b..92d6188ab0c25 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -126,10 +126,14 @@ const { state, actions } = store( url.searchParams.set( `query-${ queryId }-page`, '1' ); } } else { + // This means that we are clearing the search. url.searchParams.delete( 'instant-search' ); url.searchParams.delete( `instant-search-${ ctx.queryId }` ); + // Since we are clearing the search, we need to get back to the first + // page of results. + url.searchParams.delete( `query-${ ctx.queryId }-page` ); } const { actions: routerActions } = yield import( From 5a77f22c9215dd08f40e9ca42cff7eb445e4f45f Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 28 Oct 2024 20:43:24 +0000 Subject: [PATCH 44/76] Reset pagination correctly on the frontent --- packages/block-library/src/search/view.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index 92d6188ab0c25..c953a7dd55792 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -108,12 +108,11 @@ const { state, actions } = store( const url = new URL( window.location.href ); - // Make sure we reset the pagination. - url.searchParams.set( 'paged', '1' ); - if ( value ) { if ( ctx.isInherited ) { url.searchParams.set( 'instant-search', value ); + // Make sure we reset the pagination. + url.searchParams.set( 'paged', '1' ); } else { // Set the instant-search parameter using the query ID and search value const queryId = ctx.queryId; @@ -125,14 +124,15 @@ const { state, actions } = store( // Make sure we reset the pagination. url.searchParams.set( `query-${ queryId }-page`, '1' ); } - } else { - // This means that we are clearing the search. + } else if ( ctx.isInherited ) { + // Reset global search for inherited queries url.searchParams.delete( 'instant-search' ); + url.searchParams.delete( 'paged' ); + } else { + // Reset specific search for non-inherited queries url.searchParams.delete( `instant-search-${ ctx.queryId }` ); - // Since we are clearing the search, we need to get back to the first - // page of results. url.searchParams.delete( `query-${ ctx.queryId }-page` ); } From 1c99346fe91d4e5084e32c4a42ac89f1ac7c3f26 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 29 Oct 2024 11:30:35 +0000 Subject: [PATCH 45/76] Check if queryId exists in context before using it --- packages/block-library/src/post-template/index.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 7734f22c31f80..39784a2da6182 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -51,7 +51,15 @@ function render_block_core_post_template( $attributes, $content, $block ) { $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); - $search_query_direct = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); + $search_query_direct = ''; + + // Get the search query parameter for the specific query if it exists. + if ( isset( $block->context['queryId'] ) ) { + $search_param = 'instant-search-' . $block->context['queryId']; + if ( ! empty( $_GET[ $search_param ] ) ) { + $search_query_direct = sanitize_text_field( $_GET[ $search_param ] ); + } + } // Check if the Instant Search experiment is enabled. $gutenberg_experiments = get_option( 'gutenberg-experiments' ); From 9883d0f85d0baf5e62614f1b206c824a237b179e Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 29 Oct 2024 11:31:32 +0000 Subject: [PATCH 46/76] Appease the PHP formatter --- packages/block-library/src/post-template/index.php | 8 ++++---- .../block-library/src/query-pagination-next/index.php | 9 ++++----- .../src/query-pagination-numbers/index.php | 11 +++++------ packages/block-library/src/search/index.php | 5 ++--- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 39784a2da6182..2aa56b93409a6 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -47,10 +47,10 @@ function block_core_post_template_uses_featured_image( $inner_blocks ) { * @return string Returns the output of the query, structured using the layout defined by the block's inner blocks. */ function render_block_core_post_template( $attributes, $content, $block ) { - $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; - $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; - $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; - $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; + $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; + $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; + $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); $search_query_direct = ''; // Get the search query parameter for the specific query if it exists. diff --git a/packages/block-library/src/query-pagination-next/index.php b/packages/block-library/src/query-pagination-next/index.php index 219d3851947d4..c02ceb61470f5 100644 --- a/packages/block-library/src/query-pagination-next/index.php +++ b/packages/block-library/src/query-pagination-next/index.php @@ -27,7 +27,7 @@ function render_block_core_query_pagination_next( $attributes, $content, $block // Add check for instant search experiment and search query $gutenberg_experiments = get_option( 'gutenberg-experiments' ); $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; - $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); $search_query_direct = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); $wrapper_attributes = get_block_wrapper_attributes(); @@ -60,12 +60,12 @@ function render_block_core_query_pagination_next( $attributes, $content, $block // If instant search is enabled and we have a search query, run a new query if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) ) { - $args = array_merge( + $args = array_merge( $wp_query->query_vars, array( 's' => $search_query_global ) ); $search_query = new WP_Query( $args ); - $max_page = $search_query->max_num_pages; + $max_page = $search_query->max_num_pages; } $content = get_next_posts_link( $label, $max_page ); @@ -73,7 +73,7 @@ function render_block_core_query_pagination_next( $attributes, $content, $block } elseif ( ! $max_page || $max_page > $page ) { // Add check for instant search experiment and search query if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_direct ) ) { - $args = array_merge( + $args = array_merge( build_query_vars_from_query_block( $block, $page ), array( 's' => $search_query_direct ) ); @@ -82,7 +82,6 @@ function render_block_core_query_pagination_next( $attributes, $content, $block $custom_query = new WP_Query( build_query_vars_from_query_block( $block, $page ) ); } - $custom_query_max_pages = (int) $custom_query->max_num_pages; if ( $custom_query_max_pages && $custom_query_max_pages !== $page ) { $content = sprintf( diff --git a/packages/block-library/src/query-pagination-numbers/index.php b/packages/block-library/src/query-pagination-numbers/index.php index 447439299e90b..2581d6b060f22 100644 --- a/packages/block-library/src/query-pagination-numbers/index.php +++ b/packages/block-library/src/query-pagination-numbers/index.php @@ -39,10 +39,9 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo // Add check for instant search experiment and search query $gutenberg_experiments = get_option( 'gutenberg-experiments' ); $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; - $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); $search_query_direct = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); - $wrapper_attributes = get_block_wrapper_attributes(); $content = ''; global $wp_query; @@ -51,16 +50,16 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo if ( isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] ) { // Take into account if we have set a bigger `max page` // than what the query has. - $total = block_core_query_pagination_numbers_get_total_pages_from_query( $wp_query, $max_page ); + $total = block_core_query_pagination_numbers_get_total_pages_from_query( $wp_query, $max_page ); // If instant search is enabled and we have a search query, run a new query if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) ) { - $args = array_merge( + $args = array_merge( $wp_query->query_vars, array( 's' => $search_query_global ) ); $search_query = new WP_Query( $args ); - $total = block_core_query_pagination_numbers_get_total_pages_from_query( $search_query, $max_page ); + $total = block_core_query_pagination_numbers_get_total_pages_from_query( $search_query, $max_page ); } $paginate_args = array( @@ -74,7 +73,7 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo } else { // Add check for instant search experiment and search query if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_direct ) ) { - $args = array_merge( + $args = array_merge( build_query_vars_from_query_block( $block, $page ), array( 's' => $search_query_direct ) ); diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index fee25eacd6970..3e65fffa45f2f 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -179,7 +179,6 @@ function render_block_core_search( $attributes, $content, $block ) { $form_directives = 'data-wp-interactive="core/search"'; } - if ( $is_expandable_searchfield ) { $aria_label_expanded = __( 'Submit Search' ); $aria_label_collapsed = __( 'Expand search field' ); @@ -189,7 +188,7 @@ function render_block_core_search( $attributes, $content, $block ) { 'ariaLabelExpanded' => $aria_label_expanded, 'ariaLabelCollapsed' => $aria_label_collapsed, ); - $form_directives .= + $form_directives .= 'data-wp-class--wp-block-search__searchfield-hidden="!context.isSearchInputVisible" data-wp-on-async--keydown="actions.handleSearchKeydown" data-wp-on-async--focusout="actions.handleSearchFocusout" @@ -198,7 +197,7 @@ function render_block_core_search( $attributes, $content, $block ) { if ( $enhanced_pagination ) { $is_inherited = isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit']; - $search = ''; + $search = ''; if ( $is_inherited ) { $search = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); From 2029d4f3fcc9674e304fe2a86e27119aeb489db8 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 29 Oct 2024 11:35:39 +0000 Subject: [PATCH 47/76] Add a @since tag to get_total_pages_from_query() --- packages/block-library/src/query-pagination-numbers/index.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/block-library/src/query-pagination-numbers/index.php b/packages/block-library/src/query-pagination-numbers/index.php index 2581d6b060f22..83d2188b30871 100644 --- a/packages/block-library/src/query-pagination-numbers/index.php +++ b/packages/block-library/src/query-pagination-numbers/index.php @@ -9,6 +9,8 @@ /** * Get the total number of pages from the query. * + * @since 6.8.0 + * * @param WP_Query $query The query object. * @param int $max_page The maximum number of pages, usually set in the block context. * @return int The total number of pages. From 00910e5f9dfec846f74e9b30c7f3ac09ce82af04 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 29 Oct 2024 13:34:30 +0000 Subject: [PATCH 48/76] Reset the global `$wp_query` correctly --- .../src/query-pagination-next/index.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/block-library/src/query-pagination-next/index.php b/packages/block-library/src/query-pagination-next/index.php index c02ceb61470f5..4f158c00fb903 100644 --- a/packages/block-library/src/query-pagination-next/index.php +++ b/packages/block-library/src/query-pagination-next/index.php @@ -60,15 +60,24 @@ function render_block_core_query_pagination_next( $attributes, $content, $block // If instant search is enabled and we have a search query, run a new query if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) ) { - $args = array_merge( + $args = array_merge( $wp_query->query_vars, array( 's' => $search_query_global ) ); - $search_query = new WP_Query( $args ); - $max_page = $search_query->max_num_pages; - } - $content = get_next_posts_link( $label, $max_page ); + // Store the original global $wp_query + $temp_query = $wp_query; + + // Temporarily replace global $wp_query with a new query that includes the + // search query because get_next_posts_link() uses global $wp_query. + $wp_query = new WP_Query( $args ); + $content = get_next_posts_link( $label ); + + // Restore the original global $wp_query + $wp_query = $temp_query; + } else { + $content = get_next_posts_link( $label, $max_page ); + } remove_filter( 'next_posts_link_attributes', $filter_link_attributes ); } elseif ( ! $max_page || $max_page > $page ) { // Add check for instant search experiment and search query From 370a0c52c44e0f3b2f6a7b03f08ee20caf1abc8a Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 29 Oct 2024 13:37:28 +0000 Subject: [PATCH 49/76] Check if queryId is defined in context and rename search_query to query --- .../src/query-pagination-numbers/index.php | 20 +++++++++++++------ packages/block-library/src/search/view.js | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/block-library/src/query-pagination-numbers/index.php b/packages/block-library/src/query-pagination-numbers/index.php index 83d2188b30871..a2c4aaf15b985 100644 --- a/packages/block-library/src/query-pagination-numbers/index.php +++ b/packages/block-library/src/query-pagination-numbers/index.php @@ -12,8 +12,8 @@ * @since 6.8.0 * * @param WP_Query $query The query object. - * @param int $max_page The maximum number of pages, usually set in the block context. - * @return int The total number of pages. + * @param int|null $max_page Optional. The maximum number of pages, usually set in the block context. + * @return int The total number of pages. */ function block_core_query_pagination_numbers_get_total_pages_from_query( $query, $max_page ) { return ! $max_page || $max_page > $query->max_num_pages ? $query->max_num_pages : $max_page; @@ -42,13 +42,20 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo $gutenberg_experiments = get_option( 'gutenberg-experiments' ); $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); - $search_query_direct = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); + $search_query_direct = ''; + + // Get the search query parameter for the specific query if it exists. + if ( isset( $block->context['queryId'] ) ) { + $search_param = 'instant-search-' . $block->context['queryId']; + if ( ! empty( $_GET[ $search_param ] ) ) { + $search_query_direct = sanitize_text_field( $_GET[ $search_param ] ); + } + } $wrapper_attributes = get_block_wrapper_attributes(); $content = ''; global $wp_query; $mid_size = isset( $block->attributes['midSize'] ) ? (int) $block->attributes['midSize'] : null; - if ( isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] ) { // Take into account if we have set a bigger `max page` // than what the query has. @@ -60,8 +67,8 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo $wp_query->query_vars, array( 's' => $search_query_global ) ); - $search_query = new WP_Query( $args ); - $total = block_core_query_pagination_numbers_get_total_pages_from_query( $search_query, $max_page ); + $query = new WP_Query( $args ); + $total = block_core_query_pagination_numbers_get_total_pages_from_query( $query, $max_page ); } $paginate_args = array( @@ -74,6 +81,7 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo $content = paginate_links( $paginate_args ); } else { // Add check for instant search experiment and search query + // If instant search is enabled and we have a search query, run a new query if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_direct ) ) { $args = array_merge( build_query_vars_from_query_block( $block, $page ), diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index c953a7dd55792..b3494c6f1a836 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -111,6 +111,7 @@ const { state, actions } = store( if ( value ) { if ( ctx.isInherited ) { url.searchParams.set( 'instant-search', value ); + // Make sure we reset the pagination. url.searchParams.set( 'paged', '1' ); } else { From 1be76e060ba9e5fbf6d841929572bb7465161a51 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 29 Oct 2024 15:11:43 +0000 Subject: [PATCH 50/76] Use the query-no-results block --- .../src/query-no-results/block.json | 2 +- .../src/query-no-results/index.php | 33 +++++++++++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/query-no-results/block.json b/packages/block-library/src/query-no-results/block.json index 2f656594afa30..edc268243ecc0 100644 --- a/packages/block-library/src/query-no-results/block.json +++ b/packages/block-library/src/query-no-results/block.json @@ -7,7 +7,7 @@ "description": "Contains the block elements used to render content when no query results are found.", "parent": [ "core/query" ], "textdomain": "default", - "usesContext": [ "queryId", "query" ], + "usesContext": [ "queryId", "query", "enhancedPagination" ], "example": { "innerBlocks": [ { diff --git a/packages/block-library/src/query-no-results/index.php b/packages/block-library/src/query-no-results/index.php index 34d6b321cbd6b..39df6cbf0a802 100644 --- a/packages/block-library/src/query-no-results/index.php +++ b/packages/block-library/src/query-no-results/index.php @@ -23,17 +23,44 @@ function render_block_core_query_no_results( $attributes, $content, $block ) { return ''; } - $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; - $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; + $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; + $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; + $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; + + // Add check for instant search experiment and search query + $gutenberg_experiments = get_option( 'gutenberg-experiments' ); + $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; + $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + $search_query_direct = ''; + + // Get the search query parameter for the specific query if it exists + if ( isset( $block->context['queryId'] ) ) { + $search_param = 'instant-search-' . $block->context['queryId']; + if ( ! empty( $_GET[ $search_param ] ) ) { + $search_query_direct = sanitize_text_field( $_GET[ $search_param ] ); + } + } // Override the custom query with the global query if needed. $use_global_query = ( isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] ); if ( $use_global_query ) { global $wp_query; $query = $wp_query; + + // If instant search is enabled and we have a search query, run a new query + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) ) { + $args = array_merge( $wp_query->query_vars, array( 's' => $search_query_global ) ); + $query = new WP_Query( $args ); + } } else { $query_args = build_query_vars_from_query_block( $block, $page ); - $query = new WP_Query( $query_args ); + + // Add search parameter if instant search is enabled and search query exists + if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_direct ) ) { + $query_args['s'] = $search_query_direct; + } + + $query = new WP_Query( $query_args ); } if ( $query->post_count > 0 ) { From 441417608aa82b363baa0aa15b566164a1f2d75b Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 30 Oct 2024 18:13:19 +0000 Subject: [PATCH 51/76] Add a bunch of e2e tests --- .../interactivity/instant-search.spec.ts | 436 ++++++++++++++++++ 1 file changed, 436 insertions(+) create mode 100644 test/e2e/specs/interactivity/instant-search.spec.ts diff --git a/test/e2e/specs/interactivity/instant-search.spec.ts b/test/e2e/specs/interactivity/instant-search.spec.ts new file mode 100644 index 0000000000000..031d0c414df61 --- /dev/null +++ b/test/e2e/specs/interactivity/instant-search.spec.ts @@ -0,0 +1,436 @@ +/** + * Internal dependencies + */ +import { test, expect } from './fixtures'; + +test.describe( 'Instant Search', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activateTheme( 'emptytheme' ); + await requestUtils.setGutenbergExperiments( [ + 'gutenberg-search-query-block', + ] ); + await requestUtils.deleteAllPosts(); + + // Create test posts + // Make sure to create them last-to-first to avoid flakiness + await requestUtils.createPost( { + title: 'Unique Post', + content: 'This post has unique content.', + status: 'publish', + date_gmt: new Date( + new Date().getTime() - 1000 * 60 * 60 * 24 * 5 + ).toISOString(), + } ); + await requestUtils.createPost( { + title: 'Fourth Test Post', + content: 'This is the fourth test post content.', + status: 'publish', + date_gmt: new Date( + new Date().getTime() - 1000 * 60 * 60 * 24 * 4 + ).toISOString(), + } ); + await requestUtils.createPost( { + title: 'Third Test Post', + content: 'This is the third test post content.', + status: 'publish', + date_gmt: new Date( + new Date().getTime() - 1000 * 60 * 60 * 24 * 3 + ).toISOString(), + } ); + await requestUtils.createPost( { + title: 'Second Test Post', + content: 'This is the second test post content.', + status: 'publish', + date_gmt: new Date( + new Date().getTime() - 1000 * 60 * 60 * 24 * 2 + ).toISOString(), + } ); + await requestUtils.createPost( { + title: 'First Test Post', + content: 'This is the first test post content.', + status: 'publish', + date_gmt: new Date( + new Date().getTime() - 1000 * 60 * 60 * 24 * 1 + ).toISOString(), + } ); + + // Set the Blog pages show at most 2 posts + await requestUtils.updateSiteSettings( { + posts_per_page: 2, + } ); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.deleteAllPosts(); + await requestUtils.deleteAllPages(); + await requestUtils.deleteAllTemplates( 'wp_template' ); + + // Reset the Blog pages show at most 10 posts + await requestUtils.updateSiteSettings( { + posts_per_page: 10, + } ); + } ); + + test.describe( 'Inherited (Default) Query', () => { + test.beforeEach( async ( { page } ) => { + // Navigate to the home page + await page.goto( '/' ); + } ); + + test.beforeAll( async ( { requestUtils } ) => { + // Edit the Home template instead of creating a new page + await requestUtils.createTemplate( 'wp_template', { + slug: 'home', + title: 'Home', + content: ` + +
+ + + + + + + + + + + + +

No results found.

+ + +
+`, + } ); + } ); + + test( 'should update search results without page reload', async ( { + page, + } ) => { + // Check that the first post is shown initially + await expect( + page.getByText( 'First Test Post', { exact: true } ) + ).toBeVisible(); + + // Type in search input and verify results update + await page.locator( 'input[type="search"]' ).fill( 'Unique' ); + await page.waitForResponse( ( response ) => + response.url().includes( 'instant-search=Unique' ) + ); + + // Verify only the unique post is shown + await expect( + page.getByText( 'Unique Post', { exact: true } ) + ).toBeVisible(); + await expect( + page.getByText( 'First Test Post', { exact: true } ) + ).toBeHidden(); + } ); + + test( 'should update URL with search parameter', async ( { page } ) => { + // Test global query search parameter + await page.locator( 'input[type="search"]' ).fill( 'Test' ); + await expect( page ).toHaveURL( /instant-search=Test/ ); + + // Clear search and verify parameter is removed + await page.locator( 'input[type="search"]' ).fill( '' ); + await expect( page ).not.toHaveURL( /instant-search=/ ); + } ); + + test( 'should handle search debouncing', async ( { page } ) => { + let responseCount = 0; + + // Monitor the number of requests + page.on( 'response', ( response ) => { + if ( response.url().includes( 'instant-search=' ) ) { + responseCount++; + } + } ); + + // Type quickly and wait for the response + let responsePromise = page.waitForResponse( ( response ) => { + return ( + response.url().includes( 'instant-search=Test' ) && + response.status() === 200 + ); + } ); + await page + .locator( 'input[type="search"]' ) + .pressSequentially( 'Test', { delay: 100 } ); + await responsePromise; + + // Check that only one request was made + expect( responseCount ).toBe( 1 ); + + // Verify URL is updated after debounce + await expect( page ).toHaveURL( /instant-search=Test/ ); + + responsePromise = page.waitForResponse( ( response ) => { + return response.url().includes( 'instant-search=Test1234' ); + } ); + // Type again with a large delay and verify that a request is made + // for each character + await page + .locator( 'input[type="search"]' ) + .pressSequentially( '1234', { delay: 500 } ); + await responsePromise; + + // Check that five requests were made (Test, Test1, Test12, Test123, Test1234) + expect( responseCount ).toBe( 5 ); + } ); + + test( 'should reset pagination when searching', async ( { page } ) => { + // Navigate to second page + await page.click( 'a.wp-block-query-pagination-next' ); + + // Check that the url contains either `?paged=2` or `/page/2/`. If the + // site has the `pretty` permalink structure, the url will contain + // `/page/2/` instead of `?paged=2`. + await expect( page ).toHaveURL( /(?:paged=2|\/page\/2\/)/ ); + + // Search and verify we're back to first page + await page.locator( 'input[type="search"]' ).fill( 'Test' ); + await expect( page ).not.toHaveURL( /paged=2/ ); + + // The url should now contain `?paged=1` because we're on the first page + // We cannot remove the `paged` param completely because the pathname + // might contain the `/page/2` suffix so we need to set `paged` to `1` to + // override it. + await expect( page ).toHaveURL( /paged=1/ ); + } ); + + test( 'should show no-results block when search has no matches', async ( { + page, + } ) => { + await page + .locator( 'input[type="search"]' ) + .fill( 'NonexistentContent' ); + await page.waitForResponse( ( response ) => + response.url().includes( 'instant-search=NonexistentContent' ) + ); + + // Verify no-results block is shown + await expect( page.getByText( 'No results found.' ) ).toBeVisible(); + } ); + + test( 'should update pagination numbers based on search results', async ( { + page, + } ) => { + // Initially should show pagination numbers for 3 pages + await expect( + page.locator( '.wp-block-query-pagination-numbers' ) + ).toBeVisible(); + await expect( + page.getByRole( 'link', { name: '2' } ) + ).toBeVisible(); + await expect( + page.getByRole( 'link', { name: '3' } ) + ).toBeVisible(); + + // Search for unique post + await page.locator( 'input[type="search"]' ).fill( 'Unique' ); + await page.waitForResponse( ( response ) => + response.url().includes( 'instant-search=Unique' ) + ); + + // Pagination numbers should not be visible with single result + await expect( + page.locator( '.wp-block-query-pagination-numbers' ) + ).toBeHidden(); + } ); + } ); + + test.describe( 'Custom Query', () => { + let pageId: number; + + const queryId = 123; + + test.beforeAll( async ( { requestUtils } ) => { + // Create page with custom query + const { id } = await requestUtils.createPage( { + status: 'publish', + date_gmt: new Date().toISOString(), + title: 'Custom Query', + content: ` + +
+ + + + + + + + + + + + +

No results found.

+ + +
+`, + } ); + + pageId = id; + } ); + + test.beforeEach( async ( { page } ) => { + await page.goto( `/?p=${ pageId }` ); + } ); + + test( 'should update search results without page reload', async ( { + page, + } ) => { + // Check that the first post is shown initially + await expect( + page.getByText( 'First Test Post', { exact: true } ) + ).toBeVisible(); + + // Type in search input and verify results update + await page.locator( 'input[type="search"]' ).fill( 'Unique' ); + await page.waitForResponse( ( response ) => + response.url().includes( `instant-search-${ queryId }=Unique` ) + ); + + // Verify only the unique post is shown + await expect( + page.getByText( 'Unique Post', { exact: true } ) + ).toBeVisible(); + await expect( + page.getByText( 'First Test Post', { exact: true } ) + ).toBeHidden(); + } ); + + test( 'should update URL with search parameter', async ( { page } ) => { + // Test global query search parameter + await page.locator( 'input[type="search"]' ).fill( 'Test' ); + await expect( page ).toHaveURL( + new RegExp( `instant-search-${ queryId }=Test` ) + ); + + // Clear search and verify parameter is removed + await page.locator( 'input[type="search"]' ).fill( '' ); + await expect( page ).not.toHaveURL( + new RegExp( `instant-search-${ queryId }=` ) + ); + } ); + + test( 'should handle search debouncing', async ( { page } ) => { + let responseCount = 0; + + // Monitor the number of requests + page.on( 'response', ( res ) => { + if ( res.url().includes( `instant-search-${ queryId }=` ) ) { + responseCount++; + } + } ); + + // Type quickly and wait for the response + let responsePromise = page.waitForResponse( ( response ) => { + return ( + response + .url() + .includes( `instant-search-${ queryId }=Test` ) && + response.status() === 200 + ); + } ); + await page + .locator( 'input[type="search"]' ) + .pressSequentially( 'Test', { delay: 100 } ); + await responsePromise; + + // Check that only one request was made + expect( responseCount ).toBe( 1 ); + + // Verify URL is updated after debounce + await expect( page ).toHaveURL( + new RegExp( `instant-search-${ queryId }=Test` ) + ); + + responsePromise = page.waitForResponse( ( response ) => { + return response + .url() + .includes( `instant-search-${ queryId }=Test1234` ); + } ); + // Type again with a large delay and verify that a request is made + // for each character + await page + .locator( 'input[type="search"]' ) + .pressSequentially( '1234', { delay: 500 } ); + await responsePromise; + + // Check that five requests were made (Test, Test1, Test12, Test123, Test1234) + expect( responseCount ).toBe( 5 ); + } ); + + test( 'should reset pagination when searching', async ( { page } ) => { + // Navigate to second page + await page.click( 'a.wp-block-query-pagination-next' ); + + await expect( page ).toHaveURL( + new RegExp( `query-${ queryId }-page=2` ) + ); + + // Search and verify we're back to first page + await page.locator( 'input[type="search"]' ).fill( 'Test' ); + await expect( page ).not.toHaveURL( + new RegExp( `query-${ queryId }-page=2` ) + ); + + // The url should now contain `?paged=1` because we're on the first page + // We cannot remove the `paged` param completely because the pathname + // might contain the `/page/2` suffix so we need to set `paged` to `1` to + // override it. + await expect( page ).toHaveURL( + new RegExp( `query-${ queryId }-page=1` ) + ); + } ); + + test( 'should show no-results block when search has no matches', async ( { + page, + } ) => { + await page + .locator( 'input[type="search"]' ) + .fill( 'NonexistentContent' ); + await page.waitForResponse( ( response ) => + response + .url() + .includes( + `instant-search-${ queryId }=NonexistentContent` + ) + ); + + // Verify no-results block is shown + await expect( page.getByText( 'No results found.' ) ).toBeVisible(); + } ); + + test( 'should update pagination numbers based on search results', async ( { + page, + } ) => { + // Initially should show pagination numbers for 3 pages + await expect( + page.locator( '.wp-block-query-pagination-numbers' ) + ).toBeVisible(); + await expect( + page.getByRole( 'link', { name: '2' } ) + ).toBeVisible(); + await expect( + page.getByRole( 'link', { name: '3' } ) + ).toBeVisible(); + + // Search for unique post + await page.locator( 'input[type="search"]' ).fill( 'Unique' ); + await page.waitForResponse( ( response ) => + response.url().includes( `instant-search-${ queryId }=Unique` ) + ); + + // Pagination numbers should not be visible with single result + await expect( + page.locator( '.wp-block-query-pagination-numbers' ) + ).toBeHidden(); + } ); + } ); +} ); From 42cdfb1116bdf044956f46854aa89be3efa674ad Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 30 Oct 2024 21:27:20 +0000 Subject: [PATCH 52/76] Add a bunch more e2e tests and a util to navigate to next page. --- .../e2e/specs/interactivity/fixtures/index.ts | 8 +- .../fixtures/interactivity-utils.ts | 37 +++- .../interactivity/instant-search.spec.ts | 192 +++++++++++++++++- 3 files changed, 226 insertions(+), 11 deletions(-) diff --git a/test/e2e/specs/interactivity/fixtures/index.ts b/test/e2e/specs/interactivity/fixtures/index.ts index 607221ffb1ec4..8d531fc8882d6 100644 --- a/test/e2e/specs/interactivity/fixtures/index.ts +++ b/test/e2e/specs/interactivity/fixtures/index.ts @@ -15,11 +15,9 @@ type Fixtures = { export const test = base.extend< Fixtures >( { interactivityUtils: [ - async ( { requestUtils }, use ) => { - await use( new InteractivityUtils( { requestUtils } ) ); + async ( { requestUtils, page }, use ) => { + await use( new InteractivityUtils( { requestUtils, page } ) ); }, - // @ts-ignore: The required type is 'test', but can be 'worker' too. See - // https://playwright.dev/docs/test-fixtures#worker-scoped-fixtures - { scope: 'worker' }, + { scope: 'test' }, ], } ); diff --git a/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts b/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts index fd850a6e39fae..abaf07f7846ed 100644 --- a/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts +++ b/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts @@ -2,6 +2,10 @@ * WordPress dependencies */ import type { RequestUtils } from '@wordpress/e2e-test-utils-playwright'; +/** + * External dependencies + */ +import type { Page } from '@playwright/test'; type AddPostWithBlockOptions = { alias?: string; @@ -11,10 +15,18 @@ type AddPostWithBlockOptions = { export default class InteractivityUtils { links: Map< string, string >; requestUtils: RequestUtils; + page: Page; - constructor( { requestUtils }: { requestUtils: RequestUtils } ) { + constructor( { + requestUtils, + page, + }: { + requestUtils: RequestUtils; + page: Page; + } ) { this.links = new Map(); this.requestUtils = requestUtils; + this.page = page; } getLink( blockName: string ) { @@ -67,6 +79,29 @@ export default class InteractivityUtils { this.links.clear(); } + async goToNextPage( + pageNumber: number, + ...args: [ 'default' ] | [ 'custom', number ] + ) { + const [ queryType, queryId ] = args; + await this.page + .getByTestId( `${ queryType }-query` ) + .getByRole( 'link', { name: 'Next Page' } ) + .click(); + + // Wait for the response + return this.page.waitForResponse( ( response ) => + // if the query type is default, the url should include `paged=2` or `/page/2/` + // if the query type is custom, the url should include `query-${ queryId }-page=2` + queryType === 'default' + ? response.url().includes( `paged=${ pageNumber }` ) || + response.url().includes( `/page/${ pageNumber }/` ) + : response + .url() + .includes( `query-${ queryId }-page=${ pageNumber }` ) + ); + } + async activatePlugins() { await this.requestUtils.activateTheme( 'emptytheme' ); await this.requestUtils.activatePlugin( diff --git a/test/e2e/specs/interactivity/instant-search.spec.ts b/test/e2e/specs/interactivity/instant-search.spec.ts index 031d0c414df61..36e25328ed248 100644 --- a/test/e2e/specs/interactivity/instant-search.spec.ts +++ b/test/e2e/specs/interactivity/instant-search.spec.ts @@ -84,10 +84,10 @@ test.describe( 'Instant Search', () => { title: 'Home', content: ` -
+
- + @@ -119,10 +119,18 @@ test.describe( 'Instant Search', () => { response.url().includes( 'instant-search=Unique' ) ); - // Verify only the unique post is shown + // Verify the unique post is shown await expect( page.getByText( 'Unique Post', { exact: true } ) ).toBeVisible(); + + // Check that there is only one post + const posts = page + .getByTestId( 'default-query' ) + .getByRole( 'heading', { level: 3 } ); + await expect( posts ).toHaveCount( 1 ); + + // Verify that the other posts are hidden await expect( page.getByText( 'First Test Post', { exact: true } ) ).toBeHidden(); @@ -254,10 +262,10 @@ test.describe( 'Instant Search', () => { title: 'Custom Query', content: ` -
+
- + @@ -299,6 +307,14 @@ test.describe( 'Instant Search', () => { await expect( page.getByText( 'Unique Post', { exact: true } ) ).toBeVisible(); + + // Check that there is only one post + const posts = page + .getByTestId( 'custom-query' ) + .getByRole( 'heading', { level: 3 } ); + await expect( posts ).toHaveCount( 1 ); + + // Verify that the other posts are hidden await expect( page.getByText( 'First Test Post', { exact: true } ) ).toBeHidden(); @@ -433,4 +449,170 @@ test.describe( 'Instant Search', () => { ).toBeHidden(); } ); } ); + + test.describe( 'Multiple Queries', () => { + const customQueryId = 1234; + + test.beforeAll( async ( { requestUtils } ) => { + // Edit the Home template to include both query types + await requestUtils.deleteAllTemplates( 'wp_template' ); + await requestUtils.createTemplate( 'wp_template', { + slug: 'home', + title: 'Home', + content: ` + +
+ +

Default Query

+ + + + + + + + + + + + + +

No results found.

+ + +
+ + + +
+ +

Custom Query

+ + + + + + + + + + + + + +

No results found.

+ + +
+`, + } ); + } ); + + test.beforeEach( async ( { page } ) => { + await page.goto( '/' ); + } ); + + test( 'should handle searches independently', async ( { page } ) => { + // Get search inputs + const defaultQuerySearch = page.getByLabel( + 'default-instant-search' + ); + + const customQuerySearch = page.getByLabel( + 'custom-instant-search' + ); + + // Search in default query + await defaultQuerySearch.fill( 'Unique' ); + await page.waitForResponse( ( response ) => + response.url().includes( 'instant-search=Unique' ) + ); + + // Verify only default query ONLY shows the unique post + await expect( + page + .getByTestId( 'default-query' ) + .getByText( 'Unique Post', { exact: true } ) + ).toBeVisible(); + + // Verify that the custom query shows exactly 2 posts: First Test Post and Second Test Post + const customQuery = page.getByTestId( 'custom-query' ); + const posts = customQuery.getByRole( 'heading', { level: 3 } ); + await expect( posts ).toHaveCount( 2 ); + await expect( posts ).toContainText( [ + 'First Test Post', + 'Second Test Post', + ] ); + + // Search in custom query + await customQuerySearch.fill( 'Third' ); + await page.waitForResponse( ( response ) => + response + .url() + .includes( `instant-search-${ customQueryId }=Third` ) + ); + + // Verify URL contains both search parameters + await expect( page ).toHaveURL( /instant-search=Unique/ ); + await expect( page ).toHaveURL( + new RegExp( `instant-search-${ customQueryId }=Third` ) + ); + + // Clear default query search + await defaultQuerySearch.fill( '' ); + await expect( page ).not.toHaveURL( /instant-search=/ ); + await expect( page ).toHaveURL( + new RegExp( `instant-search-${ customQueryId }=Third` ) + ); + + // Clear custom query search + await customQuerySearch.fill( '' ); + await expect( page ).not.toHaveURL( + new RegExp( `instant-search-${ customQueryId }=` ) + ); + } ); + + test( 'should handle pagination independently', async ( { + page, + interactivityUtils: utils, + } ) => { + const defaultQuerySearch = page.getByLabel( + 'default-instant-search' + ); + const customQuerySearch = page.getByLabel( + 'custom-instant-search' + ); + + // Navigate to second page in default query + await utils.goToNextPage( 2, 'default' ); + + // Navigate to second page in custom query + await utils.goToNextPage( 2, 'custom', customQueryId ); + + // Navigate to third page in custom query + await utils.goToNextPage( 3, 'custom', customQueryId ); + + // Verify URL contains both pagination parameters + await expect( page ).toHaveURL( /(?:paged=2|\/page\/2\/)/ ); + await expect( page ).toHaveURL( + new RegExp( `query-${ customQueryId }-page=3` ) + ); + + // Search in default query and verify only its pagination resets + await defaultQuerySearch.fill( 'Test' ); + await expect( page ).toHaveURL( /paged=1/ ); + await expect( page ).toHaveURL( + new RegExp( `query-${ customQueryId }-page=3` ) + ); + + // Verify that the + + // Search in custom query and verify only its pagination resets + await customQuerySearch.fill( 'Test' ); + await expect( page ).toHaveURL( /paged=1/ ); + await expect( page ).toHaveURL( + new RegExp( `query-${ customQueryId }-page=1` ) + ); + } ); + } ); } ); From df73c87614b1e14062f8e67e936c46aac1b12268 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 30 Oct 2024 21:59:35 +0000 Subject: [PATCH 53/76] =?UTF-8?q?Format=20PHP=20again=20=F0=9F=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/block-library/src/query-pagination-numbers/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/query-pagination-numbers/index.php b/packages/block-library/src/query-pagination-numbers/index.php index a2c4aaf15b985..90a5ce47d9392 100644 --- a/packages/block-library/src/query-pagination-numbers/index.php +++ b/packages/block-library/src/query-pagination-numbers/index.php @@ -63,12 +63,12 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo // If instant search is enabled and we have a search query, run a new query if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) ) { - $args = array_merge( + $args = array_merge( $wp_query->query_vars, array( 's' => $search_query_global ) ); $query = new WP_Query( $args ); - $total = block_core_query_pagination_numbers_get_total_pages_from_query( $query, $max_page ); + $total = block_core_query_pagination_numbers_get_total_pages_from_query( $query, $max_page ); } $paginate_args = array( From 60a15f40c75078fe7da8b8ca927614a2bd331897 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 31 Oct 2024 13:00:30 +0000 Subject: [PATCH 54/76] Revert adding `page` to the interactivityUtils --- .../e2e/specs/interactivity/fixtures/index.ts | 8 ++-- .../fixtures/interactivity-utils.ts | 37 +------------------ 2 files changed, 6 insertions(+), 39 deletions(-) diff --git a/test/e2e/specs/interactivity/fixtures/index.ts b/test/e2e/specs/interactivity/fixtures/index.ts index 8d531fc8882d6..607221ffb1ec4 100644 --- a/test/e2e/specs/interactivity/fixtures/index.ts +++ b/test/e2e/specs/interactivity/fixtures/index.ts @@ -15,9 +15,11 @@ type Fixtures = { export const test = base.extend< Fixtures >( { interactivityUtils: [ - async ( { requestUtils, page }, use ) => { - await use( new InteractivityUtils( { requestUtils, page } ) ); + async ( { requestUtils }, use ) => { + await use( new InteractivityUtils( { requestUtils } ) ); }, - { scope: 'test' }, + // @ts-ignore: The required type is 'test', but can be 'worker' too. See + // https://playwright.dev/docs/test-fixtures#worker-scoped-fixtures + { scope: 'worker' }, ], } ); diff --git a/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts b/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts index abaf07f7846ed..fd850a6e39fae 100644 --- a/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts +++ b/test/e2e/specs/interactivity/fixtures/interactivity-utils.ts @@ -2,10 +2,6 @@ * WordPress dependencies */ import type { RequestUtils } from '@wordpress/e2e-test-utils-playwright'; -/** - * External dependencies - */ -import type { Page } from '@playwright/test'; type AddPostWithBlockOptions = { alias?: string; @@ -15,18 +11,10 @@ type AddPostWithBlockOptions = { export default class InteractivityUtils { links: Map< string, string >; requestUtils: RequestUtils; - page: Page; - constructor( { - requestUtils, - page, - }: { - requestUtils: RequestUtils; - page: Page; - } ) { + constructor( { requestUtils }: { requestUtils: RequestUtils } ) { this.links = new Map(); this.requestUtils = requestUtils; - this.page = page; } getLink( blockName: string ) { @@ -79,29 +67,6 @@ export default class InteractivityUtils { this.links.clear(); } - async goToNextPage( - pageNumber: number, - ...args: [ 'default' ] | [ 'custom', number ] - ) { - const [ queryType, queryId ] = args; - await this.page - .getByTestId( `${ queryType }-query` ) - .getByRole( 'link', { name: 'Next Page' } ) - .click(); - - // Wait for the response - return this.page.waitForResponse( ( response ) => - // if the query type is default, the url should include `paged=2` or `/page/2/` - // if the query type is custom, the url should include `query-${ queryId }-page=2` - queryType === 'default' - ? response.url().includes( `paged=${ pageNumber }` ) || - response.url().includes( `/page/${ pageNumber }/` ) - : response - .url() - .includes( `query-${ queryId }-page=${ pageNumber }` ) - ); - } - async activatePlugins() { await this.requestUtils.activateTheme( 'emptytheme' ); await this.requestUtils.activatePlugin( From b4c391301da443c9a0b287c15d5a8dcf0bfb51a4 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 31 Oct 2024 13:09:27 +0000 Subject: [PATCH 55/76] Extracted pagination logic into a reusable function `goToNextPage()`. --- .../interactivity/instant-search.spec.ts | 43 ++++++++++++++++--- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/test/e2e/specs/interactivity/instant-search.spec.ts b/test/e2e/specs/interactivity/instant-search.spec.ts index 36e25328ed248..a3a2498383ff2 100644 --- a/test/e2e/specs/interactivity/instant-search.spec.ts +++ b/test/e2e/specs/interactivity/instant-search.spec.ts @@ -2,6 +2,38 @@ * Internal dependencies */ import { test, expect } from './fixtures'; +/** + * External dependencies + */ +import type { Page } from '@playwright/test'; + +/** + * Go to the next page of the query. + * @param page - The page object. + * @param pageNumber - The page number to navigate to. + * @param args - Query arguments: ['default'] or ['custom', number] + */ +async function goToNextPage( + page: Page, + pageNumber: number, + ...args: [ 'default' ] | [ 'custom', number ] +) { + const [ queryType, queryId ] = args; + await page + .getByTestId( `${ queryType }-query` ) + .getByRole( 'link', { name: 'Next Page' } ) + .click(); + + // Wait for the response + return page.waitForResponse( ( response ) => + queryType === 'default' + ? response.url().includes( `paged=${ pageNumber }` ) || + response.url().includes( `/page/${ pageNumber }/` ) + : response + .url() + .includes( `query-${ queryId }-page=${ pageNumber }` ) + ); +} test.describe( 'Instant Search', () => { test.beforeAll( async ( { requestUtils } ) => { @@ -572,10 +604,7 @@ test.describe( 'Instant Search', () => { ); } ); - test( 'should handle pagination independently', async ( { - page, - interactivityUtils: utils, - } ) => { + test( 'should handle pagination independently', async ( { page } ) => { const defaultQuerySearch = page.getByLabel( 'default-instant-search' ); @@ -584,13 +613,13 @@ test.describe( 'Instant Search', () => { ); // Navigate to second page in default query - await utils.goToNextPage( 2, 'default' ); + await goToNextPage( page, 2, 'default' ); // Navigate to second page in custom query - await utils.goToNextPage( 2, 'custom', customQueryId ); + await goToNextPage( page, 2, 'custom', customQueryId ); // Navigate to third page in custom query - await utils.goToNextPage( 3, 'custom', customQueryId ); + await goToNextPage( page, 3, 'custom', customQueryId ); // Verify URL contains both pagination parameters await expect( page ).toHaveURL( /(?:paged=2|\/page\/2\/)/ ); From 2bb439e5e145fe81e954f0ca072db6d285067790 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 31 Oct 2024 15:01:56 +0000 Subject: [PATCH 56/76] Remove the inline script for search query block --- lib/experimental/editor-settings.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php index 208bcc530169d..afc6d7e220f67 100644 --- a/lib/experimental/editor-settings.php +++ b/lib/experimental/editor-settings.php @@ -37,10 +37,6 @@ function gutenberg_enable_experiments() { if ( $gutenberg_experiments && array_key_exists( 'gutenberg-media-processing', $gutenberg_experiments ) ) { wp_add_inline_script( 'wp-block-editor', 'window.__experimentalMediaProcessing = true', 'before' ); } - - if ( $gutenberg_experiments && array_key_exists( 'gutenberg-search-query-block', $gutenberg_experiments ) ) { - wp_add_inline_script( 'wp-block-editor', 'window.__experimentalSearchQueryBlock = true', 'before' ); - } } add_action( 'admin_init', 'gutenberg_enable_experiments' ); From 1edf04482a631616d6ed630139ee66beb365334d Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 31 Oct 2024 15:32:13 +0000 Subject: [PATCH 57/76] Check BOTH if enhanced pagination AND instant search experiement are on. --- packages/block-library/src/search/index.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index 3e65fffa45f2f..0970f09c6ec7e 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -51,6 +51,10 @@ function render_block_core_search( $attributes, $content, $block ) { // Check if the block is using the enhanced pagination. $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; + // Check if the block is using the instant search experiment. + $gutenberg_experiments = get_option( 'gutenberg-experiments' ); + $instant_search_enabled = $gutenberg_experiments && array_key_exists( 'gutenberg-search-query-block', $gutenberg_experiments ); + $label_inner_html = empty( $attributes['label'] ) ? __( 'Search' ) : wp_kses_post( $attributes['label'] ); $label = new WP_HTML_Tag_Processor( sprintf( '', $inline_styles['label'], $label_inner_html ) ); if ( $label->next_tag() ) { @@ -96,8 +100,11 @@ function render_block_core_search( $attributes, $content, $block ) { // Instant search is only available when using the enhanced pagination. if ( $enhanced_pagination ) { wp_enqueue_script_module( '@wordpress/block-library/search/view' ); - $input->set_attribute( 'data-wp-bind--value', 'context.search' ); - $input->set_attribute( 'data-wp-on-async--input', 'actions.updateSearch' ); + + if ( $instant_search_enabled ) { + $input->set_attribute( 'data-wp-bind--value', 'context.search' ); + $input->set_attribute( 'data-wp-on-async--input', 'actions.updateSearch' ); + } } } @@ -175,7 +182,7 @@ function render_block_core_search( $attributes, $content, $block ) { $form_context = array(); // If it's interactive, add the directives. - if ( $is_expandable_searchfield || $enhanced_pagination ) { + if ( $is_expandable_searchfield || ( $enhanced_pagination && $instant_search_enabled ) ) { $form_directives = 'data-wp-interactive="core/search"'; } @@ -195,7 +202,7 @@ function render_block_core_search( $attributes, $content, $block ) { '; } - if ( $enhanced_pagination ) { + if ( $enhanced_pagination && $instant_search_enabled ) { $is_inherited = isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit']; $search = ''; From d070fe5d7af6d908ef12ebdfa6286125b71672ed Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Fri, 8 Nov 2024 14:33:34 +0000 Subject: [PATCH 58/76] Guard against `queryId` being undefined --- packages/block-library/src/query-pagination-next/index.php | 6 +++++- packages/block-library/src/search/index.php | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/query-pagination-next/index.php b/packages/block-library/src/query-pagination-next/index.php index 4f158c00fb903..4c2c6ed2c304d 100644 --- a/packages/block-library/src/query-pagination-next/index.php +++ b/packages/block-library/src/query-pagination-next/index.php @@ -28,7 +28,11 @@ function render_block_core_query_pagination_next( $attributes, $content, $block $gutenberg_experiments = get_option( 'gutenberg-experiments' ); $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); - $search_query_direct = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); + $search_query_direct = ''; + if ( isset( $block->context['queryId'] ) ) { + $search_param = 'instant-search-' . $block->context['queryId']; + $search_query_direct = empty( $_GET[ $search_param ] ) ? '' : sanitize_text_field( $_GET[ $search_param ] ); + } $wrapper_attributes = get_block_wrapper_attributes(); $show_label = isset( $block->context['showLabel'] ) ? (bool) $block->context['showLabel'] : true; diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index 0970f09c6ec7e..d0046c2963c89 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -203,7 +203,7 @@ function render_block_core_search( $attributes, $content, $block ) { } if ( $enhanced_pagination && $instant_search_enabled ) { - $is_inherited = isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit']; + $is_inherited = isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] && ! empty( $block->context['queryId'] ); $search = ''; if ( $is_inherited ) { From d023c1dc1ff4fefcf2738a4ee433dcd04d38c2c8 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 11 Nov 2024 19:59:50 +0000 Subject: [PATCH 59/76] Remove default query from src --- .../block-library/src/post-template/index.php | 13 -------- .../src/query-no-results/index.php | 7 ---- .../src/query-pagination-next/index.php | 24 ++------------ .../src/query-pagination-numbers/index.php | 32 ++----------------- 4 files changed, 5 insertions(+), 71 deletions(-) diff --git a/packages/block-library/src/post-template/index.php b/packages/block-library/src/post-template/index.php index 2aa56b93409a6..0168290dcbdaf 100644 --- a/packages/block-library/src/post-template/index.php +++ b/packages/block-library/src/post-template/index.php @@ -50,7 +50,6 @@ function render_block_core_post_template( $attributes, $content, $block ) { $page_key = isset( $block->context['queryId'] ) ? 'query-' . $block->context['queryId'] . '-page' : 'query-page'; $enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; $page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; - $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); $search_query_direct = ''; // Get the search query parameter for the specific query if it exists. @@ -81,18 +80,6 @@ function render_block_core_post_template( $attributes, $content, $block ) { } else { $query = $wp_query; } - - /* - * If the following conditions are met, run a new query with the search query: - * 1. Enhanced pagination is on. - * 2. Instant search is enabled. - * 3. The search query is not empty. - * 4. The query already has posts. - */ - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) && $query->have_posts() ) { - $args = array_merge( $query->query_vars, array( 's' => $search_query_global ) ); - $query = new WP_Query( $args ); - } } else { $query_args = build_query_vars_from_query_block( $block, $page ); diff --git a/packages/block-library/src/query-no-results/index.php b/packages/block-library/src/query-no-results/index.php index 39df6cbf0a802..fcd2655f25770 100644 --- a/packages/block-library/src/query-no-results/index.php +++ b/packages/block-library/src/query-no-results/index.php @@ -30,7 +30,6 @@ function render_block_core_query_no_results( $attributes, $content, $block ) { // Add check for instant search experiment and search query $gutenberg_experiments = get_option( 'gutenberg-experiments' ); $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; - $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); $search_query_direct = ''; // Get the search query parameter for the specific query if it exists @@ -46,12 +45,6 @@ function render_block_core_query_no_results( $attributes, $content, $block ) { if ( $use_global_query ) { global $wp_query; $query = $wp_query; - - // If instant search is enabled and we have a search query, run a new query - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) ) { - $args = array_merge( $wp_query->query_vars, array( 's' => $search_query_global ) ); - $query = new WP_Query( $args ); - } } else { $query_args = build_query_vars_from_query_block( $block, $page ); diff --git a/packages/block-library/src/query-pagination-next/index.php b/packages/block-library/src/query-pagination-next/index.php index 4c2c6ed2c304d..e324fe0f597e1 100644 --- a/packages/block-library/src/query-pagination-next/index.php +++ b/packages/block-library/src/query-pagination-next/index.php @@ -27,7 +27,7 @@ function render_block_core_query_pagination_next( $attributes, $content, $block // Add check for instant search experiment and search query $gutenberg_experiments = get_option( 'gutenberg-experiments' ); $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; - $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); + $search_query_direct = ''; if ( isset( $block->context['queryId'] ) ) { $search_param = 'instant-search-' . $block->context['queryId']; @@ -61,27 +61,7 @@ function render_block_core_query_pagination_next( $attributes, $content, $block if ( $max_page > $wp_query->max_num_pages ) { $max_page = $wp_query->max_num_pages; } - - // If instant search is enabled and we have a search query, run a new query - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) ) { - $args = array_merge( - $wp_query->query_vars, - array( 's' => $search_query_global ) - ); - - // Store the original global $wp_query - $temp_query = $wp_query; - - // Temporarily replace global $wp_query with a new query that includes the - // search query because get_next_posts_link() uses global $wp_query. - $wp_query = new WP_Query( $args ); - $content = get_next_posts_link( $label ); - - // Restore the original global $wp_query - $wp_query = $temp_query; - } else { - $content = get_next_posts_link( $label, $max_page ); - } + $content = get_next_posts_link( $label, $max_page ); remove_filter( 'next_posts_link_attributes', $filter_link_attributes ); } elseif ( ! $max_page || $max_page > $page ) { // Add check for instant search experiment and search query diff --git a/packages/block-library/src/query-pagination-numbers/index.php b/packages/block-library/src/query-pagination-numbers/index.php index 90a5ce47d9392..00d5e5191dbb3 100644 --- a/packages/block-library/src/query-pagination-numbers/index.php +++ b/packages/block-library/src/query-pagination-numbers/index.php @@ -5,20 +5,6 @@ * @package WordPress */ - -/** - * Get the total number of pages from the query. - * - * @since 6.8.0 - * - * @param WP_Query $query The query object. - * @param int|null $max_page Optional. The maximum number of pages, usually set in the block context. - * @return int The total number of pages. - */ -function block_core_query_pagination_numbers_get_total_pages_from_query( $query, $max_page ) { - return ! $max_page || $max_page > $query->max_num_pages ? $query->max_num_pages : $max_page; -} - /** * Renders the `core/query-pagination-numbers` block on the server. * @@ -41,10 +27,9 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo // Add check for instant search experiment and search query $gutenberg_experiments = get_option( 'gutenberg-experiments' ); $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; - $search_query_global = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); - $search_query_direct = ''; // Get the search query parameter for the specific query if it exists. + $search_query_direct = ''; if ( isset( $block->context['queryId'] ) ) { $search_param = 'instant-search-' . $block->context['queryId']; if ( ! empty( $_GET[ $search_param ] ) ) { @@ -59,18 +44,7 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo if ( isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] ) { // Take into account if we have set a bigger `max page` // than what the query has. - $total = block_core_query_pagination_numbers_get_total_pages_from_query( $wp_query, $max_page ); - - // If instant search is enabled and we have a search query, run a new query - if ( $enhanced_pagination && $instant_search_enabled && ! empty( $search_query_global ) ) { - $args = array_merge( - $wp_query->query_vars, - array( 's' => $search_query_global ) - ); - $query = new WP_Query( $args ); - $total = block_core_query_pagination_numbers_get_total_pages_from_query( $query, $max_page ); - } - + $total = ! $max_page || $max_page > $wp_query->max_num_pages ? $wp_query->max_num_pages : $max_page; $paginate_args = array( 'prev_next' => false, 'total' => $total, @@ -95,7 +69,7 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo // temporarily switch it with our custom query. $prev_wp_query = $wp_query; $wp_query = $block_query; - $total = block_core_query_pagination_numbers_get_total_pages_from_query( $wp_query, $max_page ); + $total = ! $max_page || $max_page > $wp_query->max_num_pages ? $wp_query->max_num_pages : $max_page; $paginate_args = array( 'base' => '%_%', 'format' => "?$page_key=%#%", From 5e026714fedd589b835c457f35311b0957da73c3 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 11 Nov 2024 19:59:56 +0000 Subject: [PATCH 60/76] Remove default query from tests --- .../interactivity/instant-search.spec.ts | 178 ------------------ 1 file changed, 178 deletions(-) diff --git a/test/e2e/specs/interactivity/instant-search.spec.ts b/test/e2e/specs/interactivity/instant-search.spec.ts index a3a2498383ff2..9a1f6cba317b1 100644 --- a/test/e2e/specs/interactivity/instant-search.spec.ts +++ b/test/e2e/specs/interactivity/instant-search.spec.ts @@ -103,184 +103,6 @@ test.describe( 'Instant Search', () => { } ); } ); - test.describe( 'Inherited (Default) Query', () => { - test.beforeEach( async ( { page } ) => { - // Navigate to the home page - await page.goto( '/' ); - } ); - - test.beforeAll( async ( { requestUtils } ) => { - // Edit the Home template instead of creating a new page - await requestUtils.createTemplate( 'wp_template', { - slug: 'home', - title: 'Home', - content: ` - -
- - - - - - - - - - - - -

No results found.

- - -
-`, - } ); - } ); - - test( 'should update search results without page reload', async ( { - page, - } ) => { - // Check that the first post is shown initially - await expect( - page.getByText( 'First Test Post', { exact: true } ) - ).toBeVisible(); - - // Type in search input and verify results update - await page.locator( 'input[type="search"]' ).fill( 'Unique' ); - await page.waitForResponse( ( response ) => - response.url().includes( 'instant-search=Unique' ) - ); - - // Verify the unique post is shown - await expect( - page.getByText( 'Unique Post', { exact: true } ) - ).toBeVisible(); - - // Check that there is only one post - const posts = page - .getByTestId( 'default-query' ) - .getByRole( 'heading', { level: 3 } ); - await expect( posts ).toHaveCount( 1 ); - - // Verify that the other posts are hidden - await expect( - page.getByText( 'First Test Post', { exact: true } ) - ).toBeHidden(); - } ); - - test( 'should update URL with search parameter', async ( { page } ) => { - // Test global query search parameter - await page.locator( 'input[type="search"]' ).fill( 'Test' ); - await expect( page ).toHaveURL( /instant-search=Test/ ); - - // Clear search and verify parameter is removed - await page.locator( 'input[type="search"]' ).fill( '' ); - await expect( page ).not.toHaveURL( /instant-search=/ ); - } ); - - test( 'should handle search debouncing', async ( { page } ) => { - let responseCount = 0; - - // Monitor the number of requests - page.on( 'response', ( response ) => { - if ( response.url().includes( 'instant-search=' ) ) { - responseCount++; - } - } ); - - // Type quickly and wait for the response - let responsePromise = page.waitForResponse( ( response ) => { - return ( - response.url().includes( 'instant-search=Test' ) && - response.status() === 200 - ); - } ); - await page - .locator( 'input[type="search"]' ) - .pressSequentially( 'Test', { delay: 100 } ); - await responsePromise; - - // Check that only one request was made - expect( responseCount ).toBe( 1 ); - - // Verify URL is updated after debounce - await expect( page ).toHaveURL( /instant-search=Test/ ); - - responsePromise = page.waitForResponse( ( response ) => { - return response.url().includes( 'instant-search=Test1234' ); - } ); - // Type again with a large delay and verify that a request is made - // for each character - await page - .locator( 'input[type="search"]' ) - .pressSequentially( '1234', { delay: 500 } ); - await responsePromise; - - // Check that five requests were made (Test, Test1, Test12, Test123, Test1234) - expect( responseCount ).toBe( 5 ); - } ); - - test( 'should reset pagination when searching', async ( { page } ) => { - // Navigate to second page - await page.click( 'a.wp-block-query-pagination-next' ); - - // Check that the url contains either `?paged=2` or `/page/2/`. If the - // site has the `pretty` permalink structure, the url will contain - // `/page/2/` instead of `?paged=2`. - await expect( page ).toHaveURL( /(?:paged=2|\/page\/2\/)/ ); - - // Search and verify we're back to first page - await page.locator( 'input[type="search"]' ).fill( 'Test' ); - await expect( page ).not.toHaveURL( /paged=2/ ); - - // The url should now contain `?paged=1` because we're on the first page - // We cannot remove the `paged` param completely because the pathname - // might contain the `/page/2` suffix so we need to set `paged` to `1` to - // override it. - await expect( page ).toHaveURL( /paged=1/ ); - } ); - - test( 'should show no-results block when search has no matches', async ( { - page, - } ) => { - await page - .locator( 'input[type="search"]' ) - .fill( 'NonexistentContent' ); - await page.waitForResponse( ( response ) => - response.url().includes( 'instant-search=NonexistentContent' ) - ); - - // Verify no-results block is shown - await expect( page.getByText( 'No results found.' ) ).toBeVisible(); - } ); - - test( 'should update pagination numbers based on search results', async ( { - page, - } ) => { - // Initially should show pagination numbers for 3 pages - await expect( - page.locator( '.wp-block-query-pagination-numbers' ) - ).toBeVisible(); - await expect( - page.getByRole( 'link', { name: '2' } ) - ).toBeVisible(); - await expect( - page.getByRole( 'link', { name: '3' } ) - ).toBeVisible(); - - // Search for unique post - await page.locator( 'input[type="search"]' ).fill( 'Unique' ); - await page.waitForResponse( ( response ) => - response.url().includes( 'instant-search=Unique' ) - ); - - // Pagination numbers should not be visible with single result - await expect( - page.locator( '.wp-block-query-pagination-numbers' ) - ).toBeHidden(); - } ); - } ); - test.describe( 'Custom Query', () => { let pageId: number; From 639261466c66d01be67da331788ea85eedf03004 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 14 Nov 2024 18:02:29 -0500 Subject: [PATCH 61/76] Remove handling of inheritd query from `search/index.php` --- packages/block-library/src/search/index.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index d0046c2963c89..d13b62f51a8e0 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -203,21 +203,14 @@ function render_block_core_search( $attributes, $content, $block ) { } if ( $enhanced_pagination && $instant_search_enabled ) { - $is_inherited = isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] && ! empty( $block->context['queryId'] ); - $search = ''; - if ( $is_inherited ) { - $search = empty( $_GET['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-search'] ); - } else { - $search = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); - } + $search = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); $form_context = array_merge( $form_context, array( - 'search' => $search, - 'isInherited' => $is_inherited, - 'queryId' => $block->context['queryId'], + 'search' => $search, + 'queryId' => $block->context['queryId'], ) ); } From baa61883d349b01fcce68a1026374c40df747654 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 14 Nov 2024 18:49:21 -0500 Subject: [PATCH 62/76] Handle case when query is defined in block context in DB. --- packages/block-library/src/search/index.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index d13b62f51a8e0..a3e1d1ba39b77 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -204,7 +204,15 @@ function render_block_core_search( $attributes, $content, $block ) { if ( $enhanced_pagination && $instant_search_enabled ) { - $search = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? '' : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); + $search = ''; + + // If the query is defined in the block context, use it + if ( isset( $block->context['query']['search'] ) && '' !== $block->context['query']['search'] ) { + $search = $block->context['query']['search']; + } + + // If the query is defined in the URL, it overrides the block context value if defined + $search = empty( $_GET[ 'instant-search-' . $block->context['queryId'] ] ) ? $search : sanitize_text_field( $_GET[ 'instant-search-' . $block->context['queryId'] ] ); $form_context = array_merge( $form_context, From a012780ff7a95ad4050395921164e77ffde30e3d Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 18 Nov 2024 17:49:58 -0500 Subject: [PATCH 63/76] appease the formatter --- packages/block-library/src/query-pagination-next/index.php | 2 +- packages/block-library/src/query-pagination-numbers/index.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/query-pagination-next/index.php b/packages/block-library/src/query-pagination-next/index.php index e324fe0f597e1..bdc1dec04a9db 100644 --- a/packages/block-library/src/query-pagination-next/index.php +++ b/packages/block-library/src/query-pagination-next/index.php @@ -28,7 +28,7 @@ function render_block_core_query_pagination_next( $attributes, $content, $block $gutenberg_experiments = get_option( 'gutenberg-experiments' ); $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; - $search_query_direct = ''; + $search_query_direct = ''; if ( isset( $block->context['queryId'] ) ) { $search_param = 'instant-search-' . $block->context['queryId']; $search_query_direct = empty( $_GET[ $search_param ] ) ? '' : sanitize_text_field( $_GET[ $search_param ] ); diff --git a/packages/block-library/src/query-pagination-numbers/index.php b/packages/block-library/src/query-pagination-numbers/index.php index 00d5e5191dbb3..beb204cae6c9c 100644 --- a/packages/block-library/src/query-pagination-numbers/index.php +++ b/packages/block-library/src/query-pagination-numbers/index.php @@ -29,7 +29,7 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo $instant_search_enabled = isset( $gutenberg_experiments['gutenberg-search-query-block'] ) && $gutenberg_experiments['gutenberg-search-query-block']; // Get the search query parameter for the specific query if it exists. - $search_query_direct = ''; + $search_query_direct = ''; if ( isset( $block->context['queryId'] ) ) { $search_param = 'instant-search-' . $block->context['queryId']; if ( ! empty( $_GET[ $search_param ] ) ) { From bd080db2edf014c3138e2aa56678796833686375 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 18 Nov 2024 17:58:47 -0500 Subject: [PATCH 64/76] Guard against queryId being undefined in block context --- packages/block-library/src/search/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index 10ad45fe1a13e..e6bf8cb0fc643 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -202,7 +202,7 @@ function render_block_core_search( $attributes, $content, $block ) { '; } - if ( $enhanced_pagination && $instant_search_enabled ) { + if ( $enhanced_pagination && $instant_search_enabled && isset( $block->context['queryId'] ) ) { $search = ''; From ea011217c500a305fcf7688882966e26cc24a261 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 19 Nov 2024 18:28:20 -0500 Subject: [PATCH 65/76] Fix the e2e test suite --- .../interactivity/instant-search.spec.ts | 154 ++++++++++-------- 1 file changed, 83 insertions(+), 71 deletions(-) diff --git a/test/e2e/specs/interactivity/instant-search.spec.ts b/test/e2e/specs/interactivity/instant-search.spec.ts index 9a1f6cba317b1..b766dae1b576e 100644 --- a/test/e2e/specs/interactivity/instant-search.spec.ts +++ b/test/e2e/specs/interactivity/instant-search.spec.ts @@ -11,27 +11,23 @@ import type { Page } from '@playwright/test'; * Go to the next page of the query. * @param page - The page object. * @param pageNumber - The page number to navigate to. - * @param args - Query arguments: ['default'] or ['custom', number] + * @param testId - The test ID of the query. + * @param queryId - The query ID. */ async function goToNextPage( page: Page, pageNumber: number, - ...args: [ 'default' ] | [ 'custom', number ] + testId: string, + queryId: number ) { - const [ queryType, queryId ] = args; await page - .getByTestId( `${ queryType }-query` ) + .getByTestId( testId ) .getByRole( 'link', { name: 'Next Page' } ) .click(); // Wait for the response return page.waitForResponse( ( response ) => - queryType === 'default' - ? response.url().includes( `paged=${ pageNumber }` ) || - response.url().includes( `/page/${ pageNumber }/` ) - : response - .url() - .includes( `query-${ queryId }-page=${ pageNumber }` ) + response.url().includes( `query-${ queryId }-page=${ pageNumber }` ) ); } @@ -305,21 +301,22 @@ test.describe( 'Instant Search', () => { } ); test.describe( 'Multiple Queries', () => { - const customQueryId = 1234; + const firstQueryId = 1234; + const secondQueryId = 5678; test.beforeAll( async ( { requestUtils } ) => { - // Edit the Home template to include both query types + // Edit the Home template to include two custom queries await requestUtils.deleteAllTemplates( 'wp_template' ); await requestUtils.createTemplate( 'wp_template', { slug: 'home', title: 'Home', content: ` - -
+ +
-

Default Query

+

First Query

- + @@ -337,12 +334,12 @@ test.describe( 'Instant Search', () => {
- -
+ +
-

Custom Query

+

Second Query

- + @@ -368,101 +365,116 @@ test.describe( 'Instant Search', () => { test( 'should handle searches independently', async ( { page } ) => { // Get search inputs - const defaultQuerySearch = page.getByLabel( - 'default-instant-search' - ); - - const customQuerySearch = page.getByLabel( - 'custom-instant-search' - ); + const firstQuerySearch = page.getByLabel( '1st-instant-search' ); + const secondQuerySearch = page.getByLabel( '2nd-instant-search' ); - // Search in default query - await defaultQuerySearch.fill( 'Unique' ); + // Search in first query + await firstQuerySearch.fill( 'Unique' ); await page.waitForResponse( ( response ) => - response.url().includes( 'instant-search=Unique' ) + response + .url() + .includes( `instant-search-${ firstQueryId }=Unique` ) ); - // Verify only default query ONLY shows the unique post + // Verify first query ONLY shows the unique post await expect( page - .getByTestId( 'default-query' ) + .getByTestId( 'first-query' ) .getByText( 'Unique Post', { exact: true } ) ).toBeVisible(); - // Verify that the custom query shows exactly 2 posts: First Test Post and Second Test Post - const customQuery = page.getByTestId( 'custom-query' ); - const posts = customQuery.getByRole( 'heading', { level: 3 } ); + // Verify that the second query shows exactly 2 posts: First Test Post and Second Test Post + const secondQuery = page.getByTestId( 'second-query' ); + const posts = secondQuery.getByRole( 'heading', { level: 3 } ); await expect( posts ).toHaveCount( 2 ); await expect( posts ).toContainText( [ 'First Test Post', 'Second Test Post', ] ); - // Search in custom query - await customQuerySearch.fill( 'Third' ); + // Search in second query + await secondQuerySearch.fill( 'Third' ); await page.waitForResponse( ( response ) => response .url() - .includes( `instant-search-${ customQueryId }=Third` ) + .includes( `instant-search-${ secondQueryId }=Third` ) ); // Verify URL contains both search parameters - await expect( page ).toHaveURL( /instant-search=Unique/ ); await expect( page ).toHaveURL( - new RegExp( `instant-search-${ customQueryId }=Third` ) + new RegExp( `instant-search-${ firstQueryId }=Unique` ) ); + await expect( page ).toHaveURL( + new RegExp( `instant-search-${ secondQueryId }=Third` ) + ); + + // Verify that the first query has only one post which is the "Unique" post + const firstQueryPosts = page + .getByTestId( 'first-query' ) + .getByRole( 'heading', { level: 3 } ); + await expect( firstQueryPosts ).toHaveCount( 1 ); + await expect( firstQueryPosts ).toContainText( 'Unique Post' ); + + // Verify that the second query has only one post which is the "Third Test Post" + const secondQueryPosts = page + .getByTestId( 'second-query' ) + .getByRole( 'heading', { level: 3 } ); + await expect( secondQueryPosts ).toHaveCount( 1 ); + await expect( secondQueryPosts ).toContainText( 'Third Test Post' ); - // Clear default query search - await defaultQuerySearch.fill( '' ); - await expect( page ).not.toHaveURL( /instant-search=/ ); + // Clear first query search + await firstQuerySearch.fill( '' ); + await expect( page ).not.toHaveURL( + new RegExp( `instant-search-${ firstQueryId }=` ) + ); await expect( page ).toHaveURL( - new RegExp( `instant-search-${ customQueryId }=Third` ) + new RegExp( `instant-search-${ secondQueryId }=Third` ) ); - // Clear custom query search - await customQuerySearch.fill( '' ); + // Clear second query search + await secondQuerySearch.fill( '' ); await expect( page ).not.toHaveURL( - new RegExp( `instant-search-${ customQueryId }=` ) + new RegExp( `instant-search-${ secondQueryId }=` ) ); } ); test( 'should handle pagination independently', async ( { page } ) => { - const defaultQuerySearch = page.getByLabel( - 'default-instant-search' - ); - const customQuerySearch = page.getByLabel( - 'custom-instant-search' - ); + const firstQuerySearch = page.getByLabel( '1st-instant-search' ); + const secondQuerySearch = page.getByLabel( '2nd-instant-search' ); - // Navigate to second page in default query - await goToNextPage( page, 2, 'default' ); + // Navigate to second page in first query + await goToNextPage( page, 2, 'first-query', firstQueryId ); - // Navigate to second page in custom query - await goToNextPage( page, 2, 'custom', customQueryId ); + // Navigate to second page in second query + await goToNextPage( page, 2, 'second-query', secondQueryId ); - // Navigate to third page in custom query - await goToNextPage( page, 3, 'custom', customQueryId ); + // Navigate to third page in second query + await goToNextPage( page, 3, 'second-query', secondQueryId ); // Verify URL contains both pagination parameters - await expect( page ).toHaveURL( /(?:paged=2|\/page\/2\/)/ ); await expect( page ).toHaveURL( - new RegExp( `query-${ customQueryId }-page=3` ) + new RegExp( `query-${ firstQueryId }-page=2` ) ); - - // Search in default query and verify only its pagination resets - await defaultQuerySearch.fill( 'Test' ); - await expect( page ).toHaveURL( /paged=1/ ); await expect( page ).toHaveURL( - new RegExp( `query-${ customQueryId }-page=3` ) + new RegExp( `query-${ secondQueryId }-page=3` ) ); - // Verify that the + // Search in first query and verify only its pagination resets + await firstQuerySearch.fill( 'Test' ); + await expect( page ).toHaveURL( + new RegExp( `query-${ firstQueryId }-page=1` ) + ); + await expect( page ).toHaveURL( + new RegExp( `query-${ secondQueryId }-page=3` ) + ); - // Search in custom query and verify only its pagination resets - await customQuerySearch.fill( 'Test' ); - await expect( page ).toHaveURL( /paged=1/ ); + // Search in second query and verify only its pagination resets + await secondQuerySearch.fill( 'Test' ); + await expect( page ).toHaveURL( + new RegExp( `query-${ firstQueryId }-page=1` ) + ); await expect( page ).toHaveURL( - new RegExp( `query-${ customQueryId }-page=1` ) + new RegExp( `query-${ secondQueryId }-page=1` ) ); } ); } ); From 66c991a7681a20d03f3d8bc9e3a25055289955b1 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 20 Nov 2024 16:30:56 -0500 Subject: [PATCH 66/76] Add an e2e test case if query.search attribute is present --- .../interactivity/instant-search.spec.ts | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/test/e2e/specs/interactivity/instant-search.spec.ts b/test/e2e/specs/interactivity/instant-search.spec.ts index b766dae1b576e..8b83d4ca0c869 100644 --- a/test/e2e/specs/interactivity/instant-search.spec.ts +++ b/test/e2e/specs/interactivity/instant-search.spec.ts @@ -298,6 +298,75 @@ test.describe( 'Instant Search', () => { page.locator( '.wp-block-query-pagination-numbers' ) ).toBeHidden(); } ); + + test( 'should handle pre-defined search from query attributes', async ( { + requestUtils, + page, + } ) => { + // Create page with custom query that includes a search parameter + const { id } = await requestUtils.createPage( { + status: 'publish', + title: 'Query with Search', + content: ` + +
+ + + + + + + + + + + + +

No results found.

+ + +
+`, + } ); + + // Navigate to the page + await page.goto( `/?p=${ id }` ); + + // Verify the search input has the initial value + await expect( page.locator( 'input[type="search"]' ) ).toHaveValue( + 'Unique' + ); + + // Verify only the unique post is shown + await expect( + page.getByText( 'Unique Post', { exact: true } ) + ).toBeVisible(); + const posts = page + .getByTestId( 'query-with-search' ) + .getByRole( 'heading', { level: 3 } ); + await expect( posts ).toHaveCount( 1 ); + + // Verify URL does not contain the instant-search parameter + await expect( page ).not.toHaveURL( + new RegExp( `instant-search-${ queryId }=` ) + ); + + // Type new search term and verify normal instant search behavior + await page.locator( 'input[type="search"]' ).fill( 'Test' ); + await page.waitForResponse( ( response ) => + response.url().includes( `instant-search-${ queryId }=Test` ) + ); + + // Verify URL now contains the instant-search parameter + await expect( page ).toHaveURL( + new RegExp( `instant-search-${ queryId }=Test` ) + ); + + // Verify search results update + await expect( + page.getByText( 'First Test Post', { exact: true } ) + ).toBeVisible(); + } ); } ); test.describe( 'Multiple Queries', () => { From 00a8a8ba076b461ebb660f96a28eb6ee8f564c93 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 20 Nov 2024 17:44:31 -0500 Subject: [PATCH 67/76] Remove the search button when instant search is enabled --- packages/block-library/src/search/edit.js | 71 +++++++++++++-------- packages/block-library/src/search/index.php | 15 +++-- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js index f193c04e2493a..fd039a4212b2d 100644 --- a/packages/block-library/src/search/edit.js +++ b/packages/block-library/src/search/edit.js @@ -67,6 +67,7 @@ export default function SearchEdit( { toggleSelection, isSelected, clientId, + context, } ) { const { label, @@ -82,6 +83,16 @@ export default function SearchEdit( { style, } = attributes; + const isEnhancedPagination = context?.enhancedPagination; + + useEffect( () => { + if ( isEnhancedPagination ) { + setAttributes( { metadata: { name: 'Instant Search' } } ); + } else { + setAttributes( { metadata: { name: label } } ); + } + }, [ isEnhancedPagination, setAttributes, label ] ); + const wasJustInsertedIntoNavigationBlock = useSelect( ( select ) => { const { getBlockParentsByBlockName, wasBlockJustInserted } = @@ -385,24 +396,28 @@ export default function SearchEdit( { } } className={ showLabel ? 'is-pressed' : undefined } /> - - { ! hasNoButton && ( - { - setAttributes( { - buttonUseIcon: ! buttonUseIcon, - } ); - } } - className={ - buttonUseIcon ? 'is-pressed' : undefined - } - /> + { ! isEnhancedPagination && ( + <> + + { ! hasNoButton && ( + { + setAttributes( { + buttonUseIcon: ! buttonUseIcon, + } ); + } } + className={ + buttonUseIcon ? 'is-pressed' : undefined + } + /> + ) } + ) } @@ -596,16 +611,22 @@ export default function SearchEdit( { } } showHandle={ isSelected } > - { ( isButtonPositionInside || - isButtonPositionOutside || - hasOnlyButton ) && ( + { isEnhancedPagination ? ( + renderTextField() + ) : ( <> - { renderTextField() } - { renderButton() } + { ( isButtonPositionInside || + isButtonPositionOutside || + hasOnlyButton ) && ( + <> + { renderTextField() } + { renderButton() } + + ) } + + { hasNoButton && renderTextField() } ) } - - { hasNoButton && renderTextField() }
); diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index e6bf8cb0fc643..c0eb88a528d5d 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -29,11 +29,16 @@ function render_block_core_search( $attributes, $content, $block ) { ) ); - $input_id = wp_unique_id( 'wp-block-search__input-' ); - $classnames = classnames_for_block_core_search( $attributes ); - $show_label = ! empty( $attributes['showLabel'] ); - $use_icon_button = ! empty( $attributes['buttonUseIcon'] ); - $show_button = ( ! empty( $attributes['buttonPosition'] ) && 'no-button' === $attributes['buttonPosition'] ) ? false : true; + $input_id = wp_unique_id( 'wp-block-search__input-' ); + $classnames = classnames_for_block_core_search( $attributes ); + $show_label = ( ! empty( $attributes['showLabel'] ) ) ? true : false; + $use_icon_button = ( ! empty( $attributes['buttonUseIcon'] ) ) ? true : false; + $show_button = true; + if ( isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination'] ) { + $show_button = false; + } elseif ( ! empty( $attributes['buttonPosition'] ) && 'no-button' === $attributes['buttonPosition'] ) { + $show_button = false; + } $button_position = $show_button ? $attributes['buttonPosition'] : null; $query_params = ( ! empty( $attributes['query'] ) ) ? $attributes['query'] : array(); $button = ''; From dad41ca67422f28e9bbee9269bb3a5a591dc60e7 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 21 Nov 2024 15:42:36 -0500 Subject: [PATCH 68/76] Do not delete pages and templates in e2e tests --- test/e2e/specs/interactivity/instant-search.spec.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/test/e2e/specs/interactivity/instant-search.spec.ts b/test/e2e/specs/interactivity/instant-search.spec.ts index 8b83d4ca0c869..e1eaafd2eeb28 100644 --- a/test/e2e/specs/interactivity/instant-search.spec.ts +++ b/test/e2e/specs/interactivity/instant-search.spec.ts @@ -90,13 +90,7 @@ test.describe( 'Instant Search', () => { test.afterAll( async ( { requestUtils } ) => { await requestUtils.deleteAllPosts(); - await requestUtils.deleteAllPages(); - await requestUtils.deleteAllTemplates( 'wp_template' ); - - // Reset the Blog pages show at most 10 posts - await requestUtils.updateSiteSettings( { - posts_per_page: 10, - } ); + await requestUtils.activateTheme( 'twentytwentyone' ); } ); test.describe( 'Custom Query', () => { @@ -375,9 +369,8 @@ test.describe( 'Instant Search', () => { test.beforeAll( async ( { requestUtils } ) => { // Edit the Home template to include two custom queries - await requestUtils.deleteAllTemplates( 'wp_template' ); - await requestUtils.createTemplate( 'wp_template', { - slug: 'home', + await requestUtils.createPage( { + status: 'publish', title: 'Home', content: ` From 68985af122f0c26b19fefe137b4a01a812fbce45 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 21 Nov 2024 15:45:36 -0500 Subject: [PATCH 69/76] Set the pageId for Multiple Queries tests --- test/e2e/specs/interactivity/instant-search.spec.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/e2e/specs/interactivity/instant-search.spec.ts b/test/e2e/specs/interactivity/instant-search.spec.ts index e1eaafd2eeb28..19362ad27d41b 100644 --- a/test/e2e/specs/interactivity/instant-search.spec.ts +++ b/test/e2e/specs/interactivity/instant-search.spec.ts @@ -364,12 +364,14 @@ test.describe( 'Instant Search', () => { } ); test.describe( 'Multiple Queries', () => { + let pageId: number; + const firstQueryId = 1234; const secondQueryId = 5678; test.beforeAll( async ( { requestUtils } ) => { // Edit the Home template to include two custom queries - await requestUtils.createPage( { + const { id } = await requestUtils.createPage( { status: 'publish', title: 'Home', content: ` @@ -419,10 +421,12 @@ test.describe( 'Instant Search', () => {
`, } ); + + pageId = id; } ); test.beforeEach( async ( { page } ) => { - await page.goto( '/' ); + await page.goto( `/?p=${ pageId }` ); } ); test( 'should handle searches independently', async ( { page } ) => { From dac2ec1ffbbe38cba5e95945e36a2cec164648bf Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 25 Nov 2024 12:56:42 -0500 Subject: [PATCH 70/76] Fix the block name via metadata when Seach is instant. --- packages/block-library/src/search/edit.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js index fd039a4212b2d..69aba4416b7a9 100644 --- a/packages/block-library/src/search/edit.js +++ b/packages/block-library/src/search/edit.js @@ -87,9 +87,12 @@ export default function SearchEdit( { useEffect( () => { if ( isEnhancedPagination ) { + // Add the name to the metadata setAttributes( { metadata: { name: 'Instant Search' } } ); } else { - setAttributes( { metadata: { name: label } } ); + // Remove the name from the metadata + const { name, ...metadata } = attributes.metadata || {}; + setAttributes( { metadata } ); } }, [ isEnhancedPagination, setAttributes, label ] ); From 91863c0d3874863573540925533e10e52d71a752 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 26 Nov 2024 12:44:46 -0500 Subject: [PATCH 71/76] Remove stuff related to Default queries from `view.js` --- packages/block-library/src/search/view.js | 27 +++++++---------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index b3494c6f1a836..763cabbf714ef 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -109,26 +109,15 @@ const { state, actions } = store( const url = new URL( window.location.href ); if ( value ) { - if ( ctx.isInherited ) { - url.searchParams.set( 'instant-search', value ); - - // Make sure we reset the pagination. - url.searchParams.set( 'paged', '1' ); - } else { - // Set the instant-search parameter using the query ID and search value - const queryId = ctx.queryId; - url.searchParams.set( - `instant-search-${ queryId }`, - value - ); + // Set the instant-search parameter using the query ID and search value + const queryId = ctx.queryId; + url.searchParams.set( + `instant-search-${ queryId }`, + value + ); - // Make sure we reset the pagination. - url.searchParams.set( `query-${ queryId }-page`, '1' ); - } - } else if ( ctx.isInherited ) { - // Reset global search for inherited queries - url.searchParams.delete( 'instant-search' ); - url.searchParams.delete( 'paged' ); + // Make sure we reset the pagination. + url.searchParams.set( `query-${ queryId }-page`, '1' ); } else { // Reset specific search for non-inherited queries url.searchParams.delete( From 1b7b4bff8f1c528180652cf5d4eef8efd169fd4b Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 26 Nov 2024 20:12:25 -0500 Subject: [PATCH 72/76] Add `attributes.metadata` to useEffect dependency array --- packages/block-library/src/search/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js index 69aba4416b7a9..cb9bcf2709484 100644 --- a/packages/block-library/src/search/edit.js +++ b/packages/block-library/src/search/edit.js @@ -94,7 +94,7 @@ export default function SearchEdit( { const { name, ...metadata } = attributes.metadata || {}; setAttributes( { metadata } ); } - }, [ isEnhancedPagination, setAttributes, label ] ); + }, [ isEnhancedPagination, setAttributes, label, attributes.metadata ] ); const wasJustInsertedIntoNavigationBlock = useSelect( ( select ) => { From 3dcf20ff0d95f547d7e22e68f4c2000fb5a7ccb0 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Fri, 29 Nov 2024 18:36:48 +0000 Subject: [PATCH 73/76] Remove `attributes.metadata` & label from dependency array --- packages/block-library/src/search/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js index cb9bcf2709484..9da028f338fab 100644 --- a/packages/block-library/src/search/edit.js +++ b/packages/block-library/src/search/edit.js @@ -94,7 +94,7 @@ export default function SearchEdit( { const { name, ...metadata } = attributes.metadata || {}; setAttributes( { metadata } ); } - }, [ isEnhancedPagination, setAttributes, label, attributes.metadata ] ); + }, [ isEnhancedPagination, setAttributes ] ); const wasJustInsertedIntoNavigationBlock = useSelect( ( select ) => { From 33fd0807871d9e1cd367878434f955fb30ae9633 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Fri, 29 Nov 2024 19:56:34 +0000 Subject: [PATCH 74/76] Explain why we disable the react-hooks/exhaustive-deps lint --- packages/block-library/src/search/edit.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js index 9da028f338fab..7165f818c61a4 100644 --- a/packages/block-library/src/search/edit.js +++ b/packages/block-library/src/search/edit.js @@ -94,6 +94,13 @@ export default function SearchEdit( { const { name, ...metadata } = attributes.metadata || {}; setAttributes( { metadata } ); } + + // We disable the exhaustive-deps warning because the effect should not depend + // on the attributes.metadata value. We only want to re-run the effect when the + // isEnhancedPagination value changes. + + // eslint-disable-next-line react-compiler/react-compiler + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ isEnhancedPagination, setAttributes ] ); const wasJustInsertedIntoNavigationBlock = useSelect( From db9ceeefc5e45cc82bdf30501319852e168ed885 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Fri, 29 Nov 2024 20:14:13 +0000 Subject: [PATCH 75/76] Undo formatting changes --- packages/block-library/src/image/block.json | 9 +-------- packages/block-library/src/post-content/block.json | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 26835df9e856c..16e3121747602 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -4,14 +4,7 @@ "name": "core/image", "title": "Image", "category": "media", - "usesContext": [ - "allowResize", - "imageCrop", - "fixedHeight", - "postId", - "postType", - "queryId" - ], + "usesContext": [ "allowResize", "imageCrop", "fixedHeight", "postId", "postType", "queryId" ], "description": "Insert an image to make a visual statement.", "keywords": [ "img", "photo", "picture" ], "textdomain": "default", diff --git a/packages/block-library/src/post-content/block.json b/packages/block-library/src/post-content/block.json index e5d455b97a8a3..ed9c47154b2f8 100644 --- a/packages/block-library/src/post-content/block.json +++ b/packages/block-library/src/post-content/block.json @@ -69,4 +69,4 @@ }, "style": "wp-block-post-content", "editorStyle": "wp-block-post-content-editor" -} +} \ No newline at end of file From 7b326cee38c577db3c6123895d6ddb8f25089c26 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 3 Dec 2024 17:39:50 +0000 Subject: [PATCH 76/76] Don't use `Promise.withResolvers()` in search block's view.js --- packages/block-library/src/search/view.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/search/view.js b/packages/block-library/src/search/view.js index 763cabbf714ef..d280d355322af 100644 --- a/packages/block-library/src/search/view.js +++ b/packages/block-library/src/search/view.js @@ -94,7 +94,11 @@ const { state, actions } = store( // Debounce the search by 300ms to prevent multiple navigations. supersedePreviousSearch?.(); - const { promise, resolve, reject } = Promise.withResolvers(); + let resolve, reject; + const promise = new Promise( ( res, rej ) => { + resolve = res; + reject = rej; + } ); const timeout = setTimeout( resolve, 300 ); supersedePreviousSearch = () => { clearTimeout( timeout );