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 all 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
12 changes: 12 additions & 0 deletions lib/experiments-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,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',
)
);

add_settings_field(
'gutenberg-editor-write-mode',
__( 'Editor write mode', 'gutenberg' ),
Expand Down
21 changes: 20 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,19 @@ 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_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' );
$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 @@ -69,7 +82,13 @@ function render_block_core_post_template( $attributes, $content, $block ) {
}
} 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_direct ) ) {
$query_args['s'] = $search_query_direct;
}

$query = new WP_Query( $query_args );
}

if ( ! $query->have_posts() ) {
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/query-no-results/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
{
Expand Down
26 changes: 23 additions & 3 deletions packages/block-library/src/query-no-results/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,22 @@ 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_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'] );
Expand All @@ -33,7 +47,13 @@ function render_block_core_query_no_results( $attributes, $content, $block ) {
$query = $wp_query;
} 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 );
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved
}

if ( $query->post_count > 0 ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can include the contents of this block but hide them when there are no posts. That way, the CSS and JS of the inner blocks will be correctly loaded and the blocks will work when the user navigates to a "no results" page in the client.

We can remove this workaround if we finally improve how client-side navigation works before WP 6.8.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, nice. That's a good idea 👍

Can we add this in a follow-up PR though? I feel that it's not essential for the first version of the experimental block.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

Expand Down
22 changes: 21 additions & 1 deletion packages/block-library/src/query-pagination-next/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ 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_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;
$default_label = __( 'Next Page' );
Expand Down Expand Up @@ -54,7 +64,17 @@ function render_block_core_query_pagination_next( $attributes, $content, $block
$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 ) );
}
Comment on lines +68 to +76
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the Pagination Next block needs this change, I understand that the Pagination Previous block will also need it, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I had had thought initially as well but actually it won't 🙂

The Query Pagination, Next block has to create a new query to determine if it's on the last page of the results (if it is, then the block shouldn't show anything). We have to pass the search parameter to this new query.

In Query Pagination Previous, no such new query is created, so it just works out of the box!

Copy link
Contributor

@michalczaplinski michalczaplinski Nov 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed an edge case:

If you navigate to a page with ?instant-search param AND a pagination parameter like http://gutenberg.local/?instant-search-18=qwponbfv&query-18-page=2, then the Pagination Previous block shows up although it should not.

I'll hold on with fixing this for now though until we make a decision on whether we should go ahead with this PR or the approach in #67181 or #67013.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be a general issue with the Query Loop block as discussed with @ntsekouras. I've opened an issue in #67748


$custom_query_max_pages = (int) $custom_query->max_num_pages;
if ( $custom_query_max_pages && $custom_query_max_pages !== $page ) {
$content = sprintf(
Expand Down
25 changes: 24 additions & 1 deletion packages/block-library/src/query-pagination-numbers/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ 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'];

// 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 ] ) ) {
$search_query_direct = sanitize_text_field( $_GET[ $search_param ] );
}
}

$wrapper_attributes = get_block_wrapper_attributes();
$content = '';
global $wp_query;
Expand All @@ -41,7 +54,17 @@ 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 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 ),
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;
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", "query", "queryId" ],
"supports": {
"align": [ "left", "center", "right" ],
"color": {
Expand Down
81 changes: 56 additions & 25 deletions packages/block-library/src/search/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export default function SearchEdit( {
toggleSelection,
isSelected,
clientId,
context,
} ) {
const {
label,
Expand All @@ -82,6 +83,26 @@ export default function SearchEdit( {
style,
} = attributes;

const isEnhancedPagination = context?.enhancedPagination;

useEffect( () => {
if ( isEnhancedPagination ) {
// Add the name to the metadata
setAttributes( { metadata: { name: 'Instant Search' } } );
} else {
// Remove the name from the metadata
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(
( select ) => {
const { getBlockParentsByBlockName, wasBlockJustInserted } =
Expand Down Expand Up @@ -385,24 +406,28 @@ export default function SearchEdit( {
} }
className={ showLabel ? 'is-pressed' : undefined }
/>
<ToolbarDropdownMenu
icon={ getButtonPositionIcon() }
label={ __( 'Change button position' ) }
controls={ buttonPositionControls }
/>
{ ! hasNoButton && (
<ToolbarButton
title={ __( 'Use button with icon' ) }
icon={ buttonWithIcon }
onClick={ () => {
setAttributes( {
buttonUseIcon: ! buttonUseIcon,
} );
} }
className={
buttonUseIcon ? 'is-pressed' : undefined
}
/>
{ ! isEnhancedPagination && (
<>
<ToolbarDropdownMenu
icon={ getButtonPositionIcon() }
label={ __( 'Change button position' ) }
controls={ buttonPositionControls }
/>
{ ! hasNoButton && (
<ToolbarButton
title={ __( 'Use button with icon' ) }
icon={ buttonWithIcon }
onClick={ () => {
setAttributes( {
buttonUseIcon: ! buttonUseIcon,
} );
} }
className={
buttonUseIcon ? 'is-pressed' : undefined
}
/>
) }
</>
) }
</ToolbarGroup>
</BlockControls>
Expand Down Expand Up @@ -596,16 +621,22 @@ export default function SearchEdit( {
} }
showHandle={ isSelected }
>
{ ( isButtonPositionInside ||
isButtonPositionOutside ||
hasOnlyButton ) && (
{ isEnhancedPagination ? (
renderTextField()
) : (
<>
{ renderTextField() }
{ renderButton() }
{ ( isButtonPositionInside ||
isButtonPositionOutside ||
hasOnlyButton ) && (
<>
{ renderTextField() }
{ renderButton() }
</>
) }

{ hasNoButton && renderTextField() }
</>
) }

{ hasNoButton && renderTextField() }
</ResizableBox>
</div>
);
Expand Down
Loading
Loading