-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Query and Search blocks: support for Instant Search via query_loop_block_query_vars
filter
#67181
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
base: trunk
Are you sure you want to change the base?
Conversation
Size Change: +532 B (+0.03%) Total Size: 1.86 MB
ℹ️ View Unchanged
|
query_loop_block_query_vars
filterquery_loop_block_query_vars
filter
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
…rch experiment are enabled.
…e logic to directly access the context.
…ng if enhancedPagination is enabled
Instead of updating the block's name in the metadata when the Search block becomes an Instant Search block, I'm considering adding help text (more discussion in #67181 (comment)): I opened a PR to add a SlotFill to support this so this PR is currently blocked until we decide on an approach. |
Is it essential to launch an experiment behind a flag? |
It's not essential 🙂. We can eliminate the indicator altogether for now and figure out a way to indicate that the block is enhanced before the block graduates from experimental status. Does that sound good? |
As an alternative approach to #68438, I imagine we could upe
a115a6d4b8a7ad18f18581f1790bc662.mp4Here are the changes I made to this PR to achieve this: Diffdiff --git a/packages/block-editor/src/components/block-title/use-block-display-title.js b/packages/block-editor/src/components/block-title/use-block-display-title.js
index a51b336554a..137c4ec1603 100644
--- a/packages/block-editor/src/components/block-title/use-block-display-title.js
+++ b/packages/block-editor/src/components/block-title/use-block-display-title.js
@@ -51,7 +51,12 @@ export default function useBlockDisplayTitle( {
}
const attributes = getBlockAttributes( clientId );
- const label = getBlockLabel( blockType, attributes, context );
+ const label = getBlockLabel(
+ blockType,
+ attributes,
+ context,
+ clientId
+ );
// If the label is defined we prioritize it over a possible block variation title match.
if ( label !== blockType.title ) {
return label;
diff --git a/packages/block-library/src/search/index.js b/packages/block-library/src/search/index.js
index 85770a23268..c81abebdf79 100644
--- a/packages/block-library/src/search/index.js
+++ b/packages/block-library/src/search/index.js
@@ -1,8 +1,10 @@
/**
* WordPress dependencies
*/
-import { __ } from '@wordpress/i18n';
+import { __, sprintf } from '@wordpress/i18n';
import { search as icon } from '@wordpress/icons';
+import { select } from '@wordpress/data';
+import { store as blockEditorStore } from '@wordpress/block-editor';
/**
* Internal dependencies
@@ -18,6 +20,41 @@ export { metadata, name };
export const settings = {
icon,
+ __experimentalLabel( attributes, { clientId } ) {
+ const { label } = attributes;
+ const customName = attributes?.metadata?.name;
+
+ // Check if the block is inside a Query Loop block.
+ const queryLoopBlockIds = select(
+ blockEditorStore
+ ).getBlockParentsByBlockName( clientId, 'core/query' );
+
+ // If the block is not inside a Query Loop block, return the block label.
+ if ( ! queryLoopBlockIds.length ) {
+ return customName || label;
+ }
+
+ const queryLoopBlock = select( blockEditorStore ).getBlock(
+ queryLoopBlockIds[ 0 ]
+ );
+
+ // Check if the Query Loop block has enhanced pagination enabled and
+ // if the `__experimentalEnableSearchQueryBlock` flag is enabled.
+ const hasInstantSearch = !! (
+ queryLoopBlock?.attributes?.enhancedPagination &&
+ window?.__experimentalEnableSearchQueryBlock
+ );
+
+ if ( ! hasInstantSearch ) {
+ return customName || label;
+ }
+
+ return sprintf(
+ /* translators: %s: The block label */
+ __( '%s (Instant search enabled)' ),
+ customName || label
+ );
+ },
example: {
attributes: { buttonText: __( 'Search' ), label: __( 'Search' ) },
viewportWidth: 400,
diff --git a/packages/blocks/src/api/utils.js b/packages/blocks/src/api/utils.js
index 1a215036496..2f77bf19937 100644
--- a/packages/blocks/src/api/utils.js
+++ b/packages/blocks/src/api/utils.js
@@ -153,13 +153,18 @@ export function normalizeBlockType( blockTypeOrName ) {
* @param {Object} blockType The block type.
* @param {Object} attributes The values of the block's attributes.
* @param {Object} context The intended use for the label.
- *
+ * @param clientId
* @return {string} The block label.
*/
-export function getBlockLabel( blockType, attributes, context = 'visual' ) {
+export function getBlockLabel(
+ blockType,
+ attributes,
+ context = 'visual',
+ clientId
+) {
const { __experimentalLabel: getLabel, title } = blockType;
- const label = getLabel && getLabel( attributes, { context } );
+ const label = getLabel && getLabel( attributes, { context, clientId } );
if ( ! label ) {
return title; One concern is that |
…n Search block is inside Query block with enhanced pagination. Removed checks for renaming Search block to "Instant Search" in List View and Inspector Controls, focusing on button visibility instead.
- Updated `getBlockLabel` to include `clientId` for improved label context. - Modified `useBlockDisplayTitle` to utilize the updated `getBlockLabel` function. - Introduced `__experimentalLabel` in the search settings to handle block labels based on query loop context and instant search status.
- Added a test to ensure the List View label updates correctly when the Search block is part of a Query block with enhanced pagination enabled. - Verified that the label reflects "Instant search enabled" when applicable and reverts to "Search" when enhanced pagination is disabled.
- It's not needed because we fall back to 'Search' as last resort in `_experimentalLabel()` (previous commit).
This works great @t-hamano, thank you! 👏 I'm not too worried about it not showing up in the Block Card for now. It's still better than not showing any updated label at all. I've implemented your suggestion in 2db363a and an e2e test for it in c20526f. I also had to add a fallback to default to
Otherwise, if the block had no label, depending on the circumstances it ended up showing up as Screen.Recording.2025-01-06.at.16.19.42.mov |
Sorry, I think the code I proposed was not complete. Originally in the List View, the display name and label attribute were not synchronized. That means the List View only shows either "Search" or the custom name. Additionally, the text So I think the logic should be like this: if ( context !== 'list-view' ) {
return;
}
const blockTitle = __( 'Search' );
if ( ! queryLoopBlockIds.length ) {
return customName || blockTitle;
}
if ( ! hasInstantSearch ) {
return customName || blockTitle;
}
return sprintf(
/* translators: %s: The block label */
__( '%s (Instant search enabled)' ),
customName || blockTitle
); |
…st view only. Adjusted fallback to use block title instead of label for better clarity.
@t-hamano I've updated it to use the logic you mentioned and re-tested 👍. Would you mind taking another look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michalczaplinski Sorry for the late reply!
I've resolved code conflicts and commented on things I've noticed throughout this PR to help move this PR forward. I'd be happy if you could take a look at them.
$enhanced_pagination = isset( $block->context['enhancedPagination'] ) && $block->context['enhancedPagination']; | ||
|
||
// Check if the block is using the instant search experiment, which requires the enhanced pagination. | ||
$gutenberg_experiments = get_option( 'gutenberg-experiments' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gutenberg-experiments
option is for the Gutenberg plugin, so I'm wondering if it's appropriate to write code like this in a file that is shipped to core. Of course, I think that once Instant Search is no longer experimental, this code can be removed.
@@ -71,6 +74,62 @@ const { actions } = store( | |||
actions.closeSearchInput(); | |||
} | |||
}, | |||
*updateSearch( e ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In CJK languages, an IME (Input Method Editor) is used to input complex characters. Therefore, for example, in a Japanese environment, the search results are updated even during IME composition. This is generally not desirable:
ae748c6d1de97106b860fcc0b6577c03.mp4
I guess we could address this in a follow-up, but ideally, we should ignore the event during composition and fire the updateSearch when the Enter key is pressed to commit the composition.
* | ||
* @param this | ||
*/ | ||
export async function openListView( this: Editor ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's a good idea to add a new utility for E2E testing in this PR. If we want to open a list view, we should be able to simply use code like this:
await page
.getByRole( 'region', { name: 'Editor top bar' } )
.getByRole( 'button', { name: 'Document Overview' } )
.click();
// Set the Blog pages show at most 2 posts | ||
await requestUtils.updateSiteSettings( { | ||
posts_per_page: 2, | ||
} ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to restore the default settings via afterAll
. Example:
gutenberg/test/e2e/specs/editor/plugins/post-type-templates.spec.js
Lines 84 to 92 in a513013
await requestUtils.updateSiteSettings( { | |
default_post_format: 'image', | |
} ); | |
} ); | |
test.afterAll( async ( { requestUtils } ) => { | |
await requestUtils.updateSiteSettings( { | |
default_post_format: STANDARD_FORMAT_VALUE, | |
} ); |
).toBeVisible(); | ||
|
||
// Type in search input and verify results update | ||
await page.locator( 'input[type="search"]' ).fill( 'Unique' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
await page.locator( 'input[type="search"]' ).fill( 'Unique' ); | |
await page.getByRole( 'searchbox' ).fill( 'Unique' ); |
Use accessible selectors whenever possible instead of page.locator
.
<!-- /wp:paragraph --> | ||
<!-- /wp:query-no-results --> | ||
</div> | ||
<!-- /wp:query -->`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If hard-coding HTML strings is not recommended, we can also use the following approach:
Details
await admin.createNewPost();
await editor.insertBlock( {
name: 'core/query',
attributes: {
enhancedPagination: true,
queryId,
query: {
inherit: false,
perPage: 2,
order: 'desc',
orderBy: 'date',
offset: 0,
search: 'Unique',
},
},
innerBlocks: [
{
name: 'core/search',
attributes: { label: '', buttonText: 'Search' },
},
{
name: 'core/post-template',
innerBlocks: [
{
name: 'core/post-title',
attributes: { level: 3 },
},
{ name: 'core/post-excerpt' },
],
},
{
name: 'core/query-pagination',
innerBlocks: [
{ name: 'core/query-pagination-previous' },
{ name: 'core/query-pagination-numbers' },
{ name: 'core/query-pagination-next' },
],
},
{
name: 'core/query-no-results',
innerBlocks: [
{
name: 'core/paragraph',
attributes: {
content: 'No results found.',
},
},
],
},
],
} );
const id = await editor.publishPost();
However, you need to remove this code so that the front-end page is not opened when the test starts.
This looks really nice. While testing, I noticed that there is an escaping bug for the search box when it contains quotes, they end up being escaped in the output If the instant search experiment is enabled, would it be possible to enable the feature on the search template with the option "Use instant search" for the search block? In that case it would be an inherited query so it's totally cool if the answer is no for the initial experiment. |
What?
Implementation of Instant Search using the Search and Query Loop blocks. Added as a new experiment on the Gutenberg Experiments page.
Related to #63053
output_62afd8.mp4
How does it work?
Testing
Instant Search and Query Block
Gutenberg experiment.Reload Full Page
checkbox in the Query block's Advanced Settings i.e. use "enhanced pagination" in that Query block.When the Search block is inside of the Query block using "enhanced pagination", it automatically gets "updated" to an Instant Search block.
Any search input in the Instant Search block gets passed as the
?instant-search-<queryId>=<search-term>
query search param in the URL.Multiple Query + Search blocks
It's possible to have multiple Instant Search blocks in a page/post/template. In such a case, ensuring their functionality is isolated is essential. For this to work, the
queryId
is part of the param syntax:instant-search-<queryId>=<search-term>
Search button
The search block can contain a search button (in some configurations). However, when using the Instant Search functionality, the button is redundant because the list of posts updates as you type. For this reason, in the editor, when the Search block is placed inside the Query Loop block with enhanced pagination ON, the Block Controls related to the Search button are removed. The displayed name of the block (via
label
) is changed toInstant Search (Search)
.On the frontend, the Search button is also always removed for each (Instant) Search block.
output_70b3a0.mp4
Pagination
The instant search functionality respects the pagination of the Query block, which uses the
query-<queryId>-page
syntax.Limitations
Custom
query types are supported in the current experiment. TheDefault
query types are currently not supported but will be in the future version. This is prototyped already in Search and Query blocks: Add support for Default queries viapre_get_posts
filter #67289.Alternatives
Alternative approaches have been explored:
render_block_context
filter #67013 - using therender_block_context
filter.Further work
This is an initial prototype and the following features is intentionally not yet implemented:
Default
queries, including multipleDefault
queries on a single page/post/template. Those have been prototyped already in Search and Query blocks: Add support for Default queries viapre_get_posts
filter #67289.