Skip to content

Commit

Permalink
Navigation: use same default implementation of __experimentalFetchLin…
Browse files Browse the repository at this point in the history
…kSuggestions in post, site, navigation, widget editor (#29993)
  • Loading branch information
gwwar authored Apr 1, 2021
1 parent 7b22e5f commit dc22fab
Show file tree
Hide file tree
Showing 11 changed files with 394 additions and 231 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/core-data/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@wordpress/data": "file:../data",
"@wordpress/data-controls": "file:../data-controls",
"@wordpress/element": "file:../element",
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",
"@wordpress/is-shallow-equal": "file:../is-shallow-equal",
"@wordpress/url": "file:../url",
Expand Down
155 changes: 155 additions & 0 deletions packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/**
* WordPress dependencies
*/
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';
import { decodeEntities } from '@wordpress/html-entities';
import { __ } from '@wordpress/i18n';

/**
* Filters the search by type
*
* @typedef { 'post' | 'term' | 'post-format' } WPLinkSearchType
*/

/**
* @typedef WPLinkSearchOptions
*
* @property {boolean} [isInitialSuggestions] Displays initial search suggestions, when true.
* @property {WPLinkSearchType} [type] Filters by search type.
* @property {string} [subtype] Slug of the post-type or taxonomy.
* @property {number} [page] Which page of results to return.
* @property {number} [perPage] Search results per page.
*/

/**
* @typedef WPLinkSearchResult
*
* @property {number} id Post or term id.
* @property {string} url Link url.
* @property {string} title Title of the link.
* @property {string} type The taxonomy or post type slug or type URL.
*/

/**
* @typedef WPEditorSettings
*
* @property {boolean} [ disablePostFormats ] Disables post formats, when true.
*/

/**
* Fetches link suggestions from the API.
*
* @async
* @param {string} search
* @param {WPLinkSearchOptions} [searchOptions]
* @param {WPEditorSettings} [settings]
*
* @example
* ```js
* import { __experimentalFetchLinkSuggestions as fetchLinkSuggestions } from '@wordpress/core-data';
*
* //...
*
* export function initialize( id, settings ) {
*
* settings.__experimentalFetchLinkSuggestions = (
* search,
* searchOptions
* ) => fetchLinkSuggestions( search, searchOptions, settings );
* ```
* @return {Promise< WPLinkSearchResult[] >} List of search suggestions
*/
const fetchLinkSuggestions = async (
search,
searchOptions = {},
settings = {}
) => {
const {
isInitialSuggestions = false,
type = undefined,
subtype = undefined,
page = undefined,
perPage = isInitialSuggestions ? 3 : 20,
} = searchOptions;

const { disablePostFormats = false } = settings;

const queries = [];

if ( ! type || type === 'post' ) {
queries.push(
apiFetch( {
path: addQueryArgs( '/wp/v2/search', {
search,
page,
per_page: perPage,
type: 'post',
subtype,
} ),
} ).catch( () => [] ) // fail by returning no results
);
}

if ( ! type || type === 'term' ) {
queries.push(
apiFetch( {
path: addQueryArgs( '/wp/v2/search', {
search,
page,
per_page: perPage,
type: 'term',
subtype,
} ),
} ).catch( () => [] )
);
}

if ( ! disablePostFormats && ( ! type || type === 'post-format' ) ) {
queries.push(
apiFetch( {
path: addQueryArgs( '/wp/v2/search', {
search,
page,
per_page: perPage,
type: 'post-format',
subtype,
} ),
} ).catch( () => [] )
);
}

return Promise.all( queries ).then( ( results ) => {
return results
.reduce(
( accumulator, current ) => accumulator.concat( current ), //flatten list
[]
)
.filter(
/**
* @param {{ id: number }} result
*/
( result ) => {
return !! result.id;
}
)
.slice( 0, perPage )
.map(
/**
* @param {{ id: number, url:string, title?:string, subtype?: string, type?: string }} result
*/
( result ) => {
return {
id: result.id,
url: result.url,
title:
decodeEntities( result.title || '' ) ||
__( '(no title)' ),
type: result.subtype || result.type,
};
}
);
} );
};

export default fetchLinkSuggestions;
1 change: 1 addition & 0 deletions packages/core-data/src/fetch/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as __experimentalFetchLinkSuggestions } from './__experimental-fetch-link-suggestions';
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/**
* Internal dependencies
*/
import fetchLinkSuggestions from '../__experimental-fetch-link-suggestions';

jest.mock( '@wordpress/api-fetch', () =>
jest.fn( ( { path } ) => {
switch ( path ) {
case '/wp/v2/search?search=&per_page=20&type=post':
case '/wp/v2/search?search=Contact&per_page=20&type=post&subtype=page':
return Promise.resolve( [
{
id: 37,
title: 'Contact Page',
url: 'http://wordpress.local/contact-page/',
type: 'post',
subtype: 'page',
},
] );
case '/wp/v2/search?search=&per_page=20&type=term':
case '/wp/v2/search?search=cat&per_page=20&type=term&subtype=category':
return Promise.resolve( [
{
id: 9,
title: 'Cats',
url: 'http://wordpress.local/category/cats/',
type: 'category',
},
{
id: 1,
title: 'Uncategorized',
url: 'http://wordpress.local/category/uncategorized/',
type: 'category',
},
] );
case '/wp/v2/search?search=&per_page=20&type=post-format':
return Promise.resolve( [
{
id: 'gallery',
title: 'Gallery',
url: 'http://wordpress.local/type/gallery/',
type: 'post-format',
},
{
id: 'quote',
title: 'Quote',
url: 'http://wordpress.local/type/quote/',
type: 'post-format',
},
] );
case '/wp/v2/search?search=&per_page=3&type=post&subtype=page':
return Promise.resolve( [
{
id: 11,
title: 'Limit Case',
url: 'http://wordpress.local/limit-case/',
type: 'post',
subtype: 'page',
},
] );
case '/wp/v2/search?search=&page=11&per_page=20&type=post&subtype=page':
return Promise.resolve( [
{
id: 22,
title: 'Page Case',
url: 'http://wordpress.local/page-case/',
type: 'post',
subtype: 'page',
},
] );
default:
return Promise.resolve( [
{
id: -1,
title: 'missing case or failed',
url: path,
type: 'missing case or failed',
},
] );
}
} )
);

describe( 'fetchLinkSuggestions', () => {
it( 'filters suggestions by post-type', () => {
return fetchLinkSuggestions( 'Contact', {
type: 'post',
subtype: 'page',
} ).then( ( suggestions ) =>
expect( suggestions ).toEqual( [
{
id: 37,
title: 'Contact Page',
type: 'page',
url: 'http://wordpress.local/contact-page/',
},
] )
);
} );
it( 'filters suggestions by term', () => {
return fetchLinkSuggestions( 'cat', {
type: 'term',
subtype: 'category',
} ).then( ( suggestions ) =>
expect( suggestions ).toEqual( [
{
id: 9,
title: 'Cats',
url: 'http://wordpress.local/category/cats/',
type: 'category',
},
{
id: 1,
title: 'Uncategorized',
url: 'http://wordpress.local/category/uncategorized/',
type: 'category',
},
] )
);
} );
it( 'filters suggestions by post-format', () => {
return fetchLinkSuggestions( '', {
type: 'post-format',
} ).then( ( suggestions ) =>
expect( suggestions ).toEqual( [
{
id: 'gallery',
title: 'Gallery',
url: 'http://wordpress.local/type/gallery/',
type: 'post-format',
},
{
id: 'quote',
title: 'Quote',
url: 'http://wordpress.local/type/quote/',
type: 'post-format',
},
] )
);
} );
it( 'filters does not return post-format suggestions when formats are not supported', () => {
return fetchLinkSuggestions(
'',
{
type: 'post-format',
},
{ disablePostFormats: true }
).then( ( suggestions ) => expect( suggestions ).toEqual( [] ) );
} );
it( 'returns suggestions from post, term, and post-format', () => {
return fetchLinkSuggestions( '', {} ).then( ( suggestions ) =>
expect( suggestions ).toEqual( [
{
id: 37,
title: 'Contact Page',
url: 'http://wordpress.local/contact-page/',
type: 'page',
},
{
id: 9,
title: 'Cats',
url: 'http://wordpress.local/category/cats/',
type: 'category',
},
{
id: 1,
title: 'Uncategorized',
url: 'http://wordpress.local/category/uncategorized/',
type: 'category',
},
{
id: 'gallery',
title: 'Gallery',
url: 'http://wordpress.local/type/gallery/',
type: 'post-format',
},
{
id: 'quote',
title: 'Quote',
url: 'http://wordpress.local/type/quote/',
type: 'post-format',
},
] )
);
} );
it( 'initial search suggestions limits results', () => {
return fetchLinkSuggestions( '', {
type: 'post',
subtype: 'page',
isInitialSuggestions: true,
} ).then( ( suggestions ) =>
expect( suggestions ).toEqual( [
{
id: 11,
title: 'Limit Case',
url: 'http://wordpress.local/limit-case/',
type: 'page',
},
] )
);
} );
it( 'allows searching from a page', () => {
return fetchLinkSuggestions( '', {
type: 'post',
subtype: 'page',
page: 11,
} ).then( ( suggestions ) =>
expect( suggestions ).toEqual( [
{
id: 22,
title: 'Page Case',
url: 'http://wordpress.local/page-case/',
type: 'page',
},
] )
);
} );
} );
1 change: 1 addition & 0 deletions packages/core-data/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,4 @@ register( store );

export { default as EntityProvider } from './entity-provider';
export * from './entity-provider';
export * from './fetch';
Loading

0 comments on commit dc22fab

Please sign in to comment.