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 via query_loop_block_query_vars filter #67181

Open
wants to merge 25 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
def5f01
add the filter and test
michalczaplinski Nov 13, 2024
2886139
remove
michalczaplinski Nov 14, 2024
c8b390b
Create instant search using `render_block_context` filter.
michalczaplinski Nov 14, 2024
00d90f3
Remove handling of inheritd query from `search/index.php`
michalczaplinski Nov 14, 2024
6214a72
Handle case when query is defined in block context in DB.
michalczaplinski Nov 14, 2024
cbb469c
Guard against queryId being undefined in block context
michalczaplinski Nov 18, 2024
571d851
Fix the e2e test suite
michalczaplinski Nov 19, 2024
f922695
Move the filter to `/experimental` folder.
michalczaplinski Nov 20, 2024
c1eb9de
Add an e2e test case if query.search attribute is present
michalczaplinski Nov 20, 2024
970908f
Remove the search button when instant search is enabled
michalczaplinski Nov 20, 2024
98a0e23
Use the query_loop_block_query_vars filter
michalczaplinski Nov 21, 2024
64d68da
Do not delete pages and templates in e2e tests
michalczaplinski Nov 21, 2024
2a89b6a
Set the pageId for Multiple Queries tests
michalczaplinski Nov 21, 2024
7cad091
Fix the block name via metadata when Seach is instant.
michalczaplinski Nov 25, 2024
7e1e27b
Remove stuff related to Default queries from `view.js`
michalczaplinski Nov 26, 2024
b4d16f7
Add `attributes.metadata` to useEffect dependency array
michalczaplinski Nov 27, 2024
9095031
Remove `attributes.metadata` & label from dependency array
michalczaplinski Nov 29, 2024
ca253ef
Don't use `Promise.withResolvers()` in search block's view.js
michalczaplinski Dec 3, 2024
cf27754
Explain why we disable the react-hooks/exhaustive-deps lint
michalczaplinski Nov 29, 2024
a5c2b17
Undo formatting changes
michalczaplinski Nov 29, 2024
2fc61fd
Create instant search using `render_block_context` filter.
michalczaplinski Nov 14, 2024
5846998
Undo formatting changes
michalczaplinski Nov 29, 2024
4b2f66d
Remove the `render_block_context` filter from blocks.php
michalczaplinski Dec 5, 2024
1bf3f4b
Merge branch 'trunk' into feature/search-query-using-vars-filter
michalczaplinski Dec 9, 2024
ee2739d
Fix how directives are added to the form in the search block.
michalczaplinski Dec 11, 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
33 changes: 33 additions & 0 deletions lib/experimental/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,39 @@ function gutenberg_register_block_style( $block_name, $style_properties ) {
return $result;
}

/**
* Adds the search query to Query Loop blocks if the instant search experiment is enabled.
*
* @param array $query The query variables.
* @param WP_Block $block Block instance.
* @return array Modified query variables.
*/
function gutenberg_block_core_query_add_url_filtering( $query, $block ) {
// Check if the instant search gutenberg experiment is enabled
$gutenberg_experiments = get_option( 'gutenberg-experiments' );
$instant_search_enabled = $gutenberg_experiments && array_key_exists( 'gutenberg-search-query-block', $gutenberg_experiments );
if ( ! $instant_search_enabled ) {
return $query;
}

// Make sure block has a queryId
if ( empty( $block->context['queryId'] ) ) {
return $query;
}

// Get the search key from the URL
$search_key = 'instant-search-' . $block->context['queryId'];
if ( ! isset( $_GET[ $search_key ] ) ) {
return $query;
}

// Add the search parameter to the query
$query['s'] = sanitize_text_field( $_GET[ $search_key ] );

return $query;
}
add_filter( 'query_loop_block_query_vars', 'gutenberg_block_core_query_add_url_filtering', 10, 2 );

/**
* Additional data to expose to the view script module in the Form block.
*/
Expand Down
12 changes: 12 additions & 0 deletions lib/experiments-page.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,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'
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
77 changes: 61 additions & 16 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 All @@ -29,11 +29,16 @@
)
);

$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 = '';
Expand All @@ -48,6 +53,12 @@
// 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'];

// 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( '<label %1$s>%2$s</label>', $inline_styles['label'], $label_inner_html ) );
Expand Down Expand Up @@ -90,6 +101,16 @@
$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' );

if ( $instant_search_enabled ) {
$input->set_attribute( 'data-wp-bind--value', 'context.search' );
$input->set_attribute( 'data-wp-on-async--input', 'actions.updateSearch' );
}
}
}

if ( count( $query_params ) > 0 ) {
Expand Down Expand Up @@ -163,28 +184,52 @@
array( 'class' => $classnames )
);
$form_directives = '';
$form_context = array();

// If it's interactive, add the directives.
if ( $is_expandable_searchfield || ( $enhanced_pagination && $instant_search_enabled ) ) {
$form_directives = 'data-wp-interactive="core/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,
)
$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 .= '

Check warning on line 203 in packages/block-library/src/search/index.php

View workflow job for this annotation

GitHub Actions / PHP coding standards

Equals sign not aligned with surrounding assignments; expected 5 spaces but found 6 spaces
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 && $instant_search_enabled && isset( $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,
array(
'search' => $search,
'queryId' => $block->context['queryId'],
)
);
}

$form_directives .= wp_interactivity_data_wp_context( $form_context );

return sprintf(
'<form role="search" method="get" action="%1s" %2s %3s>%4s</form>',
esc_url( home_url( '/' ) ),
Expand Down
Loading
Loading