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

Add: Number of templates using a template part and link to see them. #68211

Open
wants to merge 1 commit into
base: trunk
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
28 changes: 28 additions & 0 deletions packages/edit-site/src/components/page-templates/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,31 @@ export function useAddedBy( postType, postId ) {
[ postType, postId ]
);
}

/**
* Returns the template part title.
*
* @param {?string} slug The template part slug.
* @return {?string} The template part title.
*/
export function useTemplatePartTitle( slug ) {
return useSelect(
( select ) => {
const { getEntityRecord, getCurrentTheme } = select( coreStore );
const theme = getCurrentTheme()?.stylesheet;
if ( ! theme ) {
return;
}
const templatePart = getEntityRecord(
'postType',
'wp_template_part',
`${ theme }//${ slug }`
);
if ( ! templatePart ) {
return;
}
return templatePart.title?.rendered;
},
[ slug ]
);
}
31 changes: 24 additions & 7 deletions packages/edit-site/src/components/page-templates/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import { useState, useMemo, useCallback, useEffect } from '@wordpress/element';
import { privateApis as corePrivateApis } from '@wordpress/core-data';
import { DataViews, filterSortAndPaginate } from '@wordpress/dataviews';
Expand All @@ -27,7 +27,10 @@ import { useEditPostAction } from '../dataviews-actions';
import { authorField, descriptionField, previewField } from './fields';
import { useEvent } from '@wordpress/compose';

const { usePostActions } = unlock( editorPrivateApis );
import { useTemplatePartTitle } from './hooks';

const { usePostActions, useTemplatesFilteredByTemplatePart } =
unlock( editorPrivateApis );
const { useHistory, useLocation } = unlock( routerPrivateApis );
const { useEntityRecordsWithPermissions } = unlock( corePrivateApis );

Expand Down Expand Up @@ -71,7 +74,7 @@ const DEFAULT_VIEW = {

export default function PageTemplates() {
const { path, query } = useLocation();
const { activeView = 'all', layout, postId } = query;
const { activeView = 'all', layout, postId, usingTemplatePart } = query;
const [ selection, setSelection ] = useState( [ postId ] );

const defaultView = useMemo( () => {
Expand Down Expand Up @@ -119,10 +122,17 @@ export default function PageTemplates() {
} ) );
}, [ setView, activeView ] );

const { records, isResolving: isLoadingData } =
const { records: unfilteredRecords, isResolving: isLoadingData } =
useEntityRecordsWithPermissions( 'postType', TEMPLATE_POST_TYPE, {
per_page: -1,
} );
const records = useTemplatesFilteredByTemplatePart(
usingTemplatePart,
unfilteredRecords
);

const templatePartTitle = useTemplatePartTitle( usingTemplatePart );

const history = useHistory();
const onChangeSelection = useCallback(
( items ) => {
Expand Down Expand Up @@ -189,12 +199,19 @@ export default function PageTemplates() {
);
}
} );

let title = __( 'Templates' );
if ( usingTemplatePart && templatePartTitle ) {
/* translators: %s: template part title */
title = sprintf(
'Templates using %s template part.',
templatePartTitle
);
}
return (
<Page
className="edit-site-page-templates"
title={ __( 'Templates' ) }
actions={ <AddNewTemplate /> }
title={ title }
actions={ usingTemplatePart ? undefined : <AddNewTemplate /> }
>
<DataViews
key={ activeView }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.editor-post-last-edited-panel {
.editor-post-last-edited-panel,
.editor-post-used-by-panel {
color: $gray-700;
& .components-text {
color: inherit;
Expand Down
82 changes: 82 additions & 0 deletions packages/editor/src/components/post-used-by-panel/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* WordPress dependencies
*/
import {
__experimentalText as Text,
ExternalLink,
} from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useEntityRecords } from '@wordpress/core-data';
import { _n, sprintf } from '@wordpress/i18n';
import { createInterpolateElement } from '@wordpress/element';
import { addQueryArgs } from '@wordpress/url';

/**
* Internal dependencies
*/
import { store as editorStore } from '../../store';
import {
TEMPLATE_PART_POST_TYPE,
TEMPLATE_POST_TYPE,
} from '../../store/constants';
import useTemplatesFilteredByTemplatePart from '../../utils/use-templates-filtered-by-template-part';

function PostUsedByTemplatePartPanel( { templatePartSlug } ) {
const { records: templates } = useEntityRecords(
'postType',
TEMPLATE_POST_TYPE,
{
per_page: -1,
}
);
const filteredTemplates = useTemplatesFilteredByTemplatePart(
templatePartSlug,
templates
);
if ( ! filteredTemplates?.length ) {
return null;
}
return (
<Text>
{ createInterpolateElement(
sprintf(
/* translators: 1: number of templates. */
_n(
'Used by <Link>%1$s template</Link>.',
'Used by <Link>%1$s templates</Link>.',
filteredTemplates.length
),
filteredTemplates.length
),
{
Link: (
<ExternalLink
href={ addQueryArgs( 'site-editor.php', {
p: '/template',
usingTemplatePart: templatePartSlug,
} ) }
/>
),
}
) }
</Text>
);
}

export default function PostUsedByPanel() {
const { postType, slug } = useSelect( ( select ) => {
select( editorStore ).getCurrentPostType();
return {
postType: select( editorStore ).getCurrentPostType(),
slug: select( editorStore ).getCurrentPostAttribute( 'slug' ),
};
}, [] );
if ( postType !== TEMPLATE_PART_POST_TYPE ) {
return null;
}
return (
<div className="editor-post-used-by-panel">
<PostUsedByTemplatePartPanel templatePartSlug={ slug } />
</div>
);
}
2 changes: 2 additions & 0 deletions packages/editor/src/components/sidebar/post-summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import SiteDiscussion from '../site-discussion';
import { store as editorStore } from '../../store';
import { PrivatePostLastRevision } from '../post-last-revision';
import PostTrash from '../post-trash';
import PostUsedByPanel from '../post-used-by-panel';

/**
* Module Constants
Expand Down Expand Up @@ -70,6 +71,7 @@ export default function PostSummary( { onActionPerformed } ) {
<VStack spacing={ 1 }>
<PostContentInformation />
<PostLastEditedPanel />
<PostUsedByPanel />
</VStack>
{ ! isRemovedPostStatusPanel && (
<VStack spacing={ 4 }>
Expand Down
2 changes: 2 additions & 0 deletions packages/editor/src/private-apis.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
import { CreateTemplatePartModal } from '@wordpress/fields';
import { registerCoreBlockBindingsSources } from './bindings/api';
import { getTemplateInfo } from './utils/get-template-info';
import useTemplatesFilteredByTemplatePart from './utils/use-templates-filtered-by-template-part';

const { store: interfaceStore, ...remainingInterfaceApis } = interfaceApis;

Expand All @@ -51,4 +52,5 @@ lock( privateApis, {
// This is a temporary private API while we're updating the site editor to use EditorProvider.
interfaceStore,
...remainingInterfaceApis,
useTemplatesFilteredByTemplatePart,
} );
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* WordPress dependencies
*/
import { useEffect, useState } from '@wordpress/element';
import { parse } from '@wordpress/blocks';

function findBlock( blocks, isMatch ) {
if ( ! Array.isArray( blocks ) ) {
return;
}
for ( const block of blocks ) {
if ( isMatch( block ) ) {
return block;
}
const childResult = findBlock( block.innerBlocks, isMatch );
if ( childResult ) {
return childResult;
}
}
}

export default function useTemplatesFilteredByTemplatePart(
templatePartSlug,
templates
) {
const [ result, setResult ] = useState( [] );
// We are using a timeout and an effect just to make sure
// the parsing of templates is done asynchronously and does not blocks
// the rendering of the page.
useEffect( () => {
if ( ! templatePartSlug || ! templates ) {
return;
}
const timeoutId = setTimeout( () => {
setResult(
templates.filter( ( template ) => {
if ( template?.content?.raw ) {
const blocks = parse( template.content.raw );
return !! findBlock( blocks, ( block ) => {
return (
block.name === 'core/template-part' &&
block.attributes.slug === templatePartSlug
);
} );
}
return false;
} )
);
}, 0 );
return () => {
if ( timeoutId ) {
clearTimeout( timeoutId );
}
};
} );
if ( ! templatePartSlug || ! templates ) {
return templates;
}
return result;
}
Loading