Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query and Search blocks: support for Instant Search #63147

Closed
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
c3fd536
adding the necessary directives
Jul 4, 2024
793e330
add filter for query loop, rest necessarily things
Jul 5, 2024
0159a4a
Switch to isSearchInputInitiallyVisible so it works with navigation
luisherranz Jul 8, 2024
29b2399
Remove redundant await
michalczaplinski Oct 8, 2024
5952a03
Update the filter that adds the search param to query block
michalczaplinski Oct 8, 2024
f0944db
Refactor the view.js of search block
michalczaplinski Oct 8, 2024
5a85f98
Move changes from the `query_loop_block_query_vars` filter to inside …
michalczaplinski Oct 9, 2024
520629d
Add a comment in search/view.js
michalczaplinski Oct 9, 2024
b3331d5
Merge remote-tracking branch 'origin/trunk' into feature/instant-sear…
michalczaplinski Oct 9, 2024
f4776db
I messed up the merge commit earlier
michalczaplinski Oct 9, 2024
ce27856
First stab at making search work for "inherited" queries
michalczaplinski Oct 10, 2024
be75444
Forgot to check if $enhanced_pagination was on
michalczaplinski Oct 10, 2024
6fbf19c
remove the error_log()
michalczaplinski Oct 10, 2024
7627a35
reorder variables for easier review
michalczaplinski Oct 10, 2024
288603a
remove linebreak
michalczaplinski Oct 10, 2024
03d1be0
Add the missing space before parens
michalczaplinski Oct 10, 2024
1495a42
Add the experimental setting
michalczaplinski Oct 10, 2024
f249ed3
Add the experimental setting of for search and query block
michalczaplinski Oct 10, 2024
ca0e697
Fix the phpcs spaces
michalczaplinski Oct 10, 2024
d2fb6e6
Actually fix the phpcs lint 🤦‍♂️
michalczaplinski Oct 10, 2024
4624655
Merge branch 'trunk' into instant-search
Oct 13, 2024
e7d45bb
Merge branch 'trunk' into feature/query-and-search-blocks-support-for…
Oct 14, 2024
68d780e
Changes from #65950
Oct 14, 2024
ed9b908
Rename `search` to `instant-search`
michalczaplinski Oct 15, 2024
c63840a
remove the `name`
michalczaplinski Oct 16, 2024
a55194f
Add support for inherited queries
michalczaplinski Oct 16, 2024
73b525b
Merge remote-tracking branch 'origin/trunk' into feature/query-and-se…
michalczaplinski Oct 16, 2024
6583a43
Merge branch 'feature/instant-search-block' into feature/query-and-se…
michalczaplinski Oct 16, 2024
81ba04c
remove the unneeded changes to post-template/index.php
michalczaplinski Oct 16, 2024
fa14b25
debounce the search
michalczaplinski Oct 16, 2024
a699ce3
fix phpcs complaint
michalczaplinski Oct 16, 2024
9a4e78f
data-on-async--input
michalczaplinski Oct 16, 2024
aaeee09
use `window.location.href`
michalczaplinski Oct 16, 2024
818bc96
use the constructed URL
michalczaplinski Oct 16, 2024
289f583
Update packages/block-library/src/search/view.js
michalczaplinski Oct 17, 2024
c55cf31
Update packages/block-library/src/search/view.js
michalczaplinski Oct 17, 2024
9f2329b
Merge remote-tracking branch 'origin/trunk' into feature/query-and-se…
michalczaplinski Oct 17, 2024
87f5d00
get value from event.target
michalczaplinski Oct 17, 2024
15fe455
Merge remote-tracking branch 'origin/trunk' into feature/query-and-se…
michalczaplinski Oct 24, 2024
853083b
Add inherited context to search block
michalczaplinski Oct 24, 2024
3b5da50
Remove state and add the search to context in Search block
michalczaplinski Oct 24, 2024
1996b83
Use a proper debounce and take into account the multiple query blocks
michalczaplinski Oct 24, 2024
020c638
simplify how we enqueue search/view module
michalczaplinski Oct 24, 2024
853bed5
Update the query pagination numbers.
michalczaplinski Oct 28, 2024
51caf3e
Reset the pagination upon navigation
michalczaplinski Oct 28, 2024
f2e16be
Handle query-pagination-next correctly
michalczaplinski Oct 28, 2024
e89fd61
Rename $search_query_inherited to $search_query_global
michalczaplinski Oct 28, 2024
9a0e161
Ensure that the global instant search gets passed to the URL.
michalczaplinski Oct 28, 2024
5e00cdb
Don't remove the `paged` query param. Set it to `1` instead.
michalczaplinski Oct 28, 2024
786f7ba
Remove the pagination when clearing the search
michalczaplinski Oct 28, 2024
5a77f22
Reset pagination correctly on the frontent
michalczaplinski Oct 28, 2024
1c99346
Check if queryId exists in context before using it
michalczaplinski Oct 29, 2024
9883d0f
Appease the PHP formatter
michalczaplinski Oct 29, 2024
2029d4f
Add a @since tag to get_total_pages_from_query()
michalczaplinski Oct 29, 2024
00910e5
Reset the global `$wp_query` correctly
michalczaplinski Oct 29, 2024
370a0c5
Check if queryId is defined in context and rename search_query to query
michalczaplinski Oct 29, 2024
1be76e0
Use the query-no-results block
michalczaplinski Oct 29, 2024
4414176
Add a bunch of e2e tests
michalczaplinski Oct 30, 2024
42cdfb1
Add a bunch more e2e tests and a util to navigate to next page.
michalczaplinski Oct 30, 2024
df73c87
Format PHP again 🙄
michalczaplinski Oct 30, 2024
67175ea
Merge remote-tracking branch 'origin/trunk' into feature/query-and-se…
michalczaplinski Oct 31, 2024
60a15f4
Revert adding `page` to the interactivityUtils
michalczaplinski Oct 31, 2024
b4c3913
Extracted pagination logic into a reusable function `goToNextPage()`.
michalczaplinski Oct 31, 2024
2bb439e
Remove the inline script for search query block
michalczaplinski Oct 31, 2024
1edf044
Check BOTH if enhanced pagination AND instant search experiement are on.
michalczaplinski Oct 31, 2024
d070fe5
Guard against `queryId` being undefined
michalczaplinski Nov 8, 2024
d023c1d
Remove default query from src
michalczaplinski Nov 11, 2024
5e02671
Remove default query from tests
michalczaplinski Nov 11, 2024
6392614
Remove handling of inheritd query from `search/index.php`
michalczaplinski Nov 14, 2024
baa6188
Handle case when query is defined in block context in DB.
michalczaplinski Nov 14, 2024
a012780
appease the formatter
michalczaplinski Nov 18, 2024
4c0caee
Merge branch 'trunk' into feature/query-and-search-blocks-support-for…
michalczaplinski Nov 21, 2024
bd080db
Guard against queryId being undefined in block context
michalczaplinski Nov 18, 2024
ea01121
Fix the e2e test suite
michalczaplinski Nov 19, 2024
66c991a
Add an e2e test case if query.search attribute is present
michalczaplinski Nov 20, 2024
00a8a8b
Remove the search button when instant search is enabled
michalczaplinski Nov 20, 2024
dad41ca
Do not delete pages and templates in e2e tests
michalczaplinski Nov 21, 2024
68985af
Set the pageId for Multiple Queries tests
michalczaplinski Nov 21, 2024
dac2ec1
Fix the block name via metadata when Seach is instant.
michalczaplinski Nov 25, 2024
91863c0
Remove stuff related to Default queries from `view.js`
michalczaplinski Nov 26, 2024
1b7b4bf
Add `attributes.metadata` to useEffect dependency array
michalczaplinski Nov 27, 2024
3dcf20f
Remove `attributes.metadata` & label from dependency array
michalczaplinski Nov 29, 2024
ff1d50b
Merge remote-tracking branch 'origin/trunk' into feature/query-and-se…
michalczaplinski Nov 29, 2024
33fd080
Explain why we disable the react-hooks/exhaustive-deps lint
michalczaplinski Nov 29, 2024
db9ceee
Undo formatting changes
michalczaplinski Nov 29, 2024
7b326ce
Don't use `Promise.withResolvers()` in search block's view.js
michalczaplinski Dec 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/experimental/editor-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' );
}
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved
}

add_action( 'admin_init', 'gutenberg_enable_experiments' );
Expand Down
12 changes: 12 additions & 0 deletions lib/experiments-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,18 @@ function gutenberg_initialize_experiments_settings() {
)
);

add_settings_field(
'gutenberg-search-query-block',
__( 'Instant Search and Query Block', 'gutenberg' ),
gziolo marked this conversation as resolved.
Show resolved Hide resolved
'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'
Expand Down
25 changes: 24 additions & 1 deletion packages/block-library/src/post-template/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -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['instant-search'] ) ? '' : sanitize_text_field( $_GET['instant-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'] );
Expand All @@ -67,9 +72,27 @@ 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 ) && $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 );
$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() ) {
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/search/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"default": false
}
},
"usesContext": [ "enhancedPagination" ],
"supports": {
"align": [ "left", "center", "right" ],
"color": {
Expand Down
39 changes: 30 additions & 9 deletions packages/block-library/src/search/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<!--
// wp:search /-->`. Support these by defaulting an undefined label and
Expand Down Expand Up @@ -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'];
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved

$label_inner_html = empty( $attributes['label'] ) ? __( 'Search' ) : wp_kses_post( $attributes['label'] );
$label = new WP_HTML_Tag_Processor( sprintf( '<label %1$s>%2$s</label>', $inline_styles['label'], $label_inner_html ) );
Expand Down Expand Up @@ -79,9 +81,11 @@ 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 ) {
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' );

Expand All @@ -90,6 +94,11 @@ function render_block_core_search( $attributes ) {
$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' );
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved
}
}

if ( count( $query_params ) > 0 ) {
Expand Down Expand Up @@ -165,20 +174,32 @@ 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"';
}

// 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' );
$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 = '
data-wp-interactive="core/search"'
. $form_context .
$form_directives .= $form_context .
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved
'data-wp-class--wp-block-search__searchfield-hidden="!context.isSearchInputVisible"
data-wp-on-async--keydown="actions.handleSearchKeydown"
data-wp-on-async--focusout="actions.handleSearchFocusout"
Expand Down
58 changes: 54 additions & 4 deletions packages/block-library/src/search/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
*/
import { store, getContext, getElement } from '@wordpress/interactivity';

const { actions } = store(
const isEmpty = ( obj ) =>
[ Object, Array ].includes( ( obj || {} ).constructor ) &&
! Object.entries( obj || {} ).length;
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved

const { state, actions } = store(
'core/search',
{
state: {
Expand All @@ -29,14 +33,25 @@ const { actions } = store(
const { isSearchInputVisible } = getContext();
return isSearchInputVisible ? '0' : '-1';
},
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;
}
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();
}
},
Expand Down Expand Up @@ -66,6 +81,41 @@ const { actions } = store(
actions.closeSearchInput();
}
},
*updateSearch() {
const { ref } = getElement();
const { value } = ref;

// Don't navigate if the search didn't really change.
if ( value === state.search ) {
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved
return;
}

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 ) );
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved
if ( value !== state.search ) {
return;
}

const url = new URL( window.location );
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved
if ( ! isEmpty( value ) ) {
state.search = value;
url.searchParams.set( 'instant-search', value );
} else {
url.searchParams.delete( 'instant-search' );
}

const { actions: routerActions } = yield import(
'@wordpress/interactivity-router'
);

routerActions.navigate(
`${ window.location.pathname }${ url.search }`
);
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved
},
},
},
{ lock: true }
Expand Down
Loading