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

Navigation: Add Post, Page, Category and Tag variations to Link #24670

Merged
merged 7 commits into from
Aug 26, 2020
3 changes: 3 additions & 0 deletions packages/block-editor/src/components/link-control/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import { ViewerFill } from './viewer-slot';
* @property {boolean=} showSuggestions Whether to present suggestions when typing the URL.
* @property {boolean=} showInitialSuggestions Whether to present initial suggestions immediately.
* @property {boolean=} withCreateSuggestion Whether to allow creation of link value from suggestion.
* @property {Object=} suggestionsQuery Query parameters to pass along to wp.blockEditor.__experimentalFetchLinkSuggestions.
*/

/**
Expand All @@ -109,6 +110,7 @@ function LinkControl( {
createSuggestion,
withCreateSuggestion,
inputValue: propInputValue = '',
suggestionsQuery = {},
noisysocks marked this conversation as resolved.
Show resolved Hide resolved
} ) {
if ( withCreateSuggestion === undefined && createSuggestion ) {
withCreateSuggestion = true;
Expand Down Expand Up @@ -209,6 +211,7 @@ function LinkControl( {
showInitialSuggestions={ showInitialSuggestions }
allowDirectEntry={ ! noDirectEntry }
showSuggestions={ showSuggestions }
suggestionsQuery={ suggestionsQuery }
>
<div className="block-editor-link-control__search-actions">
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ const LinkControlSearchInput = forwardRef(
fetchSuggestions = null,
allowDirectEntry = true,
showInitialSuggestions = false,
suggestionsQuery = {},
},
ref
) => {
const genericSearchHandler = useSearchHandler(
suggestionsQuery,
allowDirectEntry,
withCreateSuggestion
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,15 @@ export const handleDirectEntry = ( val ) => {
] );
};

export const handleEntitySearch = async (
const handleEntitySearch = async (
val,
args,
suggestionsQuery,
fetchSearchSuggestions,
directEntryHandler,
withCreateSuggestion
) => {
let results = await Promise.all( [
fetchSearchSuggestions( val, {
...( args.isInitialSuggestions ? { perPage: 3 } : {} ),
} ),
fetchSearchSuggestions( val, suggestionsQuery ),
directEntryHandler( val ),
] );

Expand All @@ -65,12 +63,12 @@ export const handleEntitySearch = async (
// just for good measure. That way once the actual results run out we always
// have a URL option to fallback on.
results =
couldBeURL && ! args.isInitialSuggestions
couldBeURL && ! suggestionsQuery.isInitialSuggestions
? results[ 0 ].concat( results[ 1 ] )
: results[ 0 ];

// If displaying initial suggestions just return plain results.
if ( args.isInitialSuggestions ) {
if ( suggestionsQuery.isInitialSuggestions ) {
return results;
}

Expand Down Expand Up @@ -101,6 +99,7 @@ export const handleEntitySearch = async (
};

export default function useSearchHandler(
suggestionsQuery,
allowDirectEntry,
withCreateSuggestion
) {
Expand All @@ -117,12 +116,12 @@ export default function useSearchHandler(
: handleNoop;

return useCallback(
( val, args ) => {
( val, { isInitialSuggestions } ) => {
return isURLLike( val )
? directEntryHandler( val, args )
? directEntryHandler( val, { isInitialSuggestions } )
: handleEntitySearch(
val,
args,
{ ...suggestionsQuery, isInitialSuggestions },
fetchSearchSuggestions,
directEntryHandler,
withCreateSuggestion
Expand Down
27 changes: 24 additions & 3 deletions packages/block-library/src/navigation-link/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,27 @@ const useIsDraggingWithin = ( elementRef ) => {
return isDraggingWithin;
};

/**
* Given the Link block's type attribute, return the query params to give to
* /wp/v2/search.
*
* @param {string} type Link block's type attribute.
* @return {{ type?: string, subtype?: string }} Search query params.
*/
function getSuggestionsQuery( type ) {
switch ( type ) {
case 'post':
case 'page':
return { type: 'post', subtype: type };
case 'category':
return { type: 'term', subtype: 'category' };
case 'tag':
return { type: 'term', subtype: 'post_tag' };
default:
return {};
}
}

function NavigationLinkEdit( {
attributes,
hasDescendants,
Expand All @@ -111,7 +132,7 @@ function NavigationLinkEdit( {
mergeBlocks,
onReplace,
} ) {
const { label, opensInNewTab, url, description, rel } = attributes;
const { label, type, opensInNewTab, url, description, rel } = attributes;
const link = {
url,
opensInNewTab,
Expand Down Expand Up @@ -179,8 +200,7 @@ function NavigationLinkEdit( {
}

async function handleCreatePage( pageTitle ) {
const type = 'page';
const page = await saveEntityRecord( 'postType', type, {
const page = await saveEntityRecord( 'postType', 'page', {
title: pageTitle,
status: 'publish',
} );
Expand Down Expand Up @@ -300,6 +320,7 @@ function NavigationLinkEdit( {
showInitialSuggestions={ true }
withCreateSuggestion={ userCanCreatePages }
createSuggestion={ handleCreatePage }
suggestionsQuery={ getSuggestionsQuery( type ) }
onChange={ ( {
title: newTitle = '',
url: newURL = '',
Expand Down
40 changes: 40 additions & 0 deletions packages/block-library/src/navigation-link/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,56 @@ export { metadata, name };

export const settings = {
title: __( 'Link' ),

icon,

description: __( 'Add a page, link, or another item to your navigation.' ),

variations: [
{
name: 'link',
isDefault: true,
title: __( 'Link' ),
description: __( 'A link to a URL.' ),
attributes: {},
},
{
name: 'post',
title: __( 'Post' ),
description: __( 'A link to a post.' ),
attributes: { type: 'post' },
},
{
name: 'page',
title: __( 'Page' ),
description: __( 'A link to a page.' ),
attributes: { type: 'page' },
},
{
name: 'category',
title: __( 'Category' ),
description: __( 'A link to a category.' ),
attributes: { type: 'category' },
},
{
name: 'tag',
title: __( 'Tag' ),
description: __( 'A link to a tag.' ),
attributes: { type: 'tag' },
},
],

__experimentalLabel: ( { label } ) => label,

merge( leftAttributes, { label: rightLabel = '' } ) {
return {
...leftAttributes,
label: leftAttributes.label + rightLabel,
};
},

edit,

save,

deprecated: [
Expand Down
17 changes: 13 additions & 4 deletions packages/block-library/src/navigation/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { useRef } from '@wordpress/element';
import { useRef, useState } from '@wordpress/element';
import {
InnerBlocks,
InspectorControls,
Expand Down Expand Up @@ -48,7 +48,13 @@ function Navigation( {
// HOOKS
//
const ref = useRef();

const [ isPlaceholderShown, setIsPlaceholderShown ] = useState(
! hasExistingNavItems
);

const { selectBlock } = useDispatch( 'core/block-editor' );

const { TextColor, BackgroundColor, ColorPanel } = __experimentalUseColors(
[
{ name: 'textColor', property: 'color' },
Expand Down Expand Up @@ -85,13 +91,17 @@ function Navigation( {
};
}

// If we don't have existing items then show the Placeholder
if ( ! hasExistingNavItems ) {
//
// RENDER
//

if ( isPlaceholderShown ) {
return (
<Block.div>
<NavigationPlaceholder
ref={ ref }
onCreate={ ( blocks, selectNavigationBlock ) => {
setIsPlaceholderShown( false );
updateInnerBlocks( blocks );
if ( selectNavigationBlock ) {
selectBlock( clientId );
Expand All @@ -107,7 +117,6 @@ function Navigation( {
'is-vertical': attributes.orientation === 'vertical',
} );

// UI State: rendered Block UI
return (
<>
<BlockControls>
Expand Down
5 changes: 5 additions & 0 deletions packages/block-library/src/navigation/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ $navigation-item-height: 46px;
padding: $grid-unit-20;
}

// Ensure that an empty block has space around the appender.
.wp-block-navigation__container {
min-height: $navigation-item-height;
}

// Ensure sub-menus stay open and visible when a nested block is selected.
.wp-block-navigation__container.is-parent-of-selected-block {
visibility: visible;
Expand Down
6 changes: 2 additions & 4 deletions packages/block-library/src/navigation/placeholder.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,7 @@ function NavigationPlaceholder( { onCreate }, ref ) {
const createFromMenu = useCallback( () => {
// If an empty menu was selected, create an empty block.
if ( ! menuItems.length ) {
const blocks = [ createBlock( 'core/navigation-link' ) ];
onCreate( blocks );
onCreate( [] );
return;
}

Expand All @@ -263,8 +262,7 @@ function NavigationPlaceholder( { onCreate }, ref ) {
const { key } = selectedCreateOption;
switch ( key ) {
case CREATE_EMPTY_OPTION_VALUE: {
const blocks = [ createBlock( 'core/navigation-link' ) ];
onCreate( blocks );
onCreate( [] );
return;
}

Expand Down
74 changes: 45 additions & 29 deletions packages/edit-navigation/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,53 +34,69 @@ function disableInsertingNonNavigationBlocks( settings, name ) {
/**
* Fetches link suggestions from the API. This function is an exact copy of a function found at:
*
* wordpress/editor/src/components/provider/index.js
* packages/editor/src/components/provider/index.js
*
* It seems like there is no suitable package to import this from. Ideally it would be either part of core-data.
* Until we refactor it, just copying the code is the simplest solution.
*
* @param {string} search
* @param {Object} [searchArguments]
* @param {number} [searchArguments.perPage=20]
* @param {number} [searchArguments.isInitialSuggestions]
* @param {number} [searchArguments.type]
* @param {number} [searchArguments.subtype]
* @param {Object} [editorSettings]
* @param {boolean} [editorSettings.disablePostFormats=false]
* @return {Promise<Object[]>} List of suggestions
*/
const fetchLinkSuggestions = (
search,
{ perPage = 20 } = {},
{ isInitialSuggestions, type, subtype } = {},
{ disablePostFormats = false } = {}
) => {
const posts = apiFetch( {
path: addQueryArgs( '/wp/v2/search', {
search,
per_page: perPage,
type: 'post',
} ),
} );
const perPage = isInitialSuggestions ? 3 : 20;

const terms = apiFetch( {
path: addQueryArgs( '/wp/v2/search', {
search,
per_page: perPage,
type: 'term',
} ),
} );
const queries = [];

if ( ! type || type === 'post' ) {
queries.push(
apiFetch( {
path: addQueryArgs( '/wp/v2/search', {
search,
per_page: perPage,
type: 'post',
subtype,
} ),
} )
);
}

let formats;
if ( disablePostFormats ) {
formats = Promise.resolve( [] );
} else {
formats = apiFetch( {
path: addQueryArgs( '/wp/v2/search', {
search,
per_page: perPage,
type: 'post-format',
} ),
} );
if ( ! type || type === 'term' ) {
queries.push(
apiFetch( {
path: addQueryArgs( '/wp/v2/search', {
search,
per_page: perPage,
type: 'term',
subtype,
} ),
} )
);
}

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

return Promise.all( [ posts, terms, formats ] ).then( ( results ) => {
return Promise.all( queries ).then( ( results ) => {
return map( flatten( results ).slice( 0, perPage ), ( result ) => ( {
id: result.id,
url: result.url,
Expand Down
Loading