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

Search and Query blocks: Add support for Default queries via pre_get_posts filter #67289

Open
wants to merge 13 commits into
base: feature/search-query-using-vars-filter
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 35 additions & 0 deletions lib/experimental/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,41 @@ function gutenberg_block_core_query_add_url_filtering( $query, $block ) {
}
add_filter( 'query_loop_block_query_vars', 'gutenberg_block_core_query_add_url_filtering', 10, 2 );

/**
* Adds the search query to Query blocks for the inherited queries if the instant search experiment is enabled.
*
* @param WP_Query $query The query object.
* @return void
*/
function gutenberg_block_core_query_add_search_query_filtering( $query ) {

// if the query is not the main query, return
if ( $query->is_admin() || ! $query->is_main_query() ) {
return;
}

// 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;
}

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

// Add the search parameter to the query
$query->set( 's', sanitize_text_field( $_GET[ $search_key ] ) );
}

add_action(
'pre_get_posts',
'gutenberg_block_core_query_add_search_query_filtering'
);

/**
* Additional data to expose to the view script module in the Form block.
*/
Expand Down
36 changes: 30 additions & 6 deletions packages/block-library/src/search/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ function render_block_core_search( $attributes, $content, $block ) {
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-bind--value', 'state.searchGetter' );
$input->set_attribute( 'data-wp-on-async--input', 'actions.updateSearch' );
}
}
Expand Down Expand Up @@ -214,21 +214,45 @@ function render_block_core_search( $attributes, $content, $block ) {

if ( $enhanced_pagination && $instant_search_enabled && isset( $block->context['queryId'] ) ) {

$search = '';
$form_directives .= ' data-wp-on--submit="actions.handleSearchSubmit"';

// Get the canonical URL without pagination
$canonical_url_no_pagination = get_pagenum_link( 1 );

// If we're on a singular post/page, use its permalink instead
if ( is_singular() ) {
$canonical_url_no_pagination = get_permalink();
}

wp_interactivity_config( 'core/search', array( 'canonicalURL' => $canonical_url_no_pagination ) );

$query_id = $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'] ] );
$is_inherited = isset( $block->context['query']['inherit'] ) && $block->context['query']['inherit'] && ! empty( $query_id );

// Inherited query: `instant-search=`
// Custom query: `instant-search-<query_id>=`
$search_key = $is_inherited ? 'instant-search' : 'instant-search-' . $query_id;

// If the query is defined in the URL, it overrides the block context value.
$search = empty( $_GET[ $search_key ] ) ? $search : sanitize_text_field( $_GET[ $search_key ] );

if ( $is_inherited ) {
wp_interactivity_state( 'core/search', array( 'search' => $search ) );
}

$form_context = array_merge(
$form_context,
array(
'search' => $search,
'queryId' => $block->context['queryId'],
'search' => $search,
'queryId' => $query_id,
'isInherited' => $is_inherited,
)
);
}
Expand Down
57 changes: 43 additions & 14 deletions packages/block-library/src/search/view.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/**
* WordPress dependencies
*/
import { store, getContext, getElement } from '@wordpress/interactivity';
import {
store,
getContext,
getElement,
getConfig,
} from '@wordpress/interactivity';

/** @type {( () => void ) | null} */
let supersedePreviousSearch = null;
Expand Down Expand Up @@ -43,6 +48,10 @@ const { state, actions } = store(
}
return ctx.isSearchInputVisible;
},
get searchGetter() {
const { isInherited, search } = getContext();
return isInherited ? state.search : search;
},
},
actions: {
openSearchInput( event ) {
Expand Down Expand Up @@ -80,17 +89,24 @@ const { state, actions } = store(
actions.closeSearchInput();
}
},
handleSearchSubmit( e ) {
e.preventDefault();
},
*updateSearch( e ) {
const { value } = e.target;

const ctx = getContext();

// Don't navigate if the search didn't really change.
if ( value === ctx.search ) {
if ( value === state.searchGetter ) {
return;
}

ctx.search = value;
const ctx = getContext();

if ( ctx.isInherited ) {
state.search = value;
} else {
ctx.search = value;
}

// Debounce the search by 300ms to prevent multiple navigations.
supersedePreviousSearch?.();
Expand All @@ -110,18 +126,31 @@ const { state, actions } = store(
return;
}

const url = new URL( window.location.href );
let url = new URL( window.location.href );

if ( value ) {
// Set the instant-search parameter using the query ID and search value
const queryId = ctx.queryId;
url.searchParams.set(
`instant-search-${ queryId }`,
value
);
if ( ctx.isInherited ) {
// Get the canonical URL from the config
const { canonicalURL } = getConfig( 'core/search' );

// Make sure we reset the pagination.
url = new URL( canonicalURL );
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
);

// Make sure we reset the pagination.
url.searchParams.set( `query-${ queryId }-page`, '1' );
// 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' );
} else {
// Reset specific search for non-inherited queries
url.searchParams.delete(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ import { listMedia, uploadMedia, deleteMedia, deleteAllMedia } from './media';
import { createUser, deleteAllUsers } from './users';
import { setupRest, rest, getMaxBatchSize, batchRest } from './rest';
import { getPluginsMap, activatePlugin, deactivatePlugin } from './plugins';
import { deleteAllTemplates, createTemplate } from './templates';
import {
deleteAllTemplates,
createTemplate,
updateOrCreateTemplate,
} from './templates';
import {
activateTheme,
getCurrentThemeGlobalStylesPostId,
Expand Down Expand Up @@ -175,6 +179,9 @@ class RequestUtils {
deleteAllTemplates.bind( this );
/** @borrows createTemplate as this.createTemplate */
createTemplate: typeof createTemplate = createTemplate.bind( this );
/** @borrows updateOrCreateTemplate as this.updateOrCreateTemplate */
updateOrCreateTemplate: typeof updateOrCreateTemplate =
updateOrCreateTemplate.bind( this );
/** @borrows resetPreferences as this.resetPreferences */
resetPreferences: typeof resetPreferences = resetPreferences.bind( this );
/** @borrows listMedia as this.listMedia */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ type TemplateType = 'wp_template' | 'wp_template_part';
interface Template {
wp_id: number;
id: string;
title: string;
slug: string;
}

interface CreateTemplatePayload {
Expand Down Expand Up @@ -80,4 +82,40 @@ async function createTemplate(
return template;
}

export { deleteAllTemplates, createTemplate };
/**
* Updates a template using the REST API.
*
* @param this
* @param type Template type.
* @param payload Template attributes.
*/
async function updateOrCreateTemplate(
this: RequestUtils,
type: TemplateType,
payload: CreateTemplatePayload
) {
const path = PATH_MAPPING[ type ];

if ( ! path ) {
throw new Error( `Unsupported template type: ${ type }.` );
}

const templates = await this.rest< Template[] >( { path } );

const template = templates.find( ( t ) => t.slug === payload.slug );

// If the template is not found, create it.
if ( ! template ) {
return createTemplate.bind( this )( type, payload );
}

const updatedTemplate = await this.rest< Template >( {
method: 'POST',
path: `${ PATH_MAPPING[ type ] }/${ template.id }`,
params: { ...payload, type, status: 'publish', is_wp_suggestion: true },
} );

return updatedTemplate;
}

export { deleteAllTemplates, createTemplate, updateOrCreateTemplate };
Loading
Loading