Skip to content

Commit

Permalink
Add: Number of templates using a template part and link to see them.
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta committed Dec 20, 2024
1 parent d9f18e5 commit 024ba52
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 8 deletions.
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;
}

0 comments on commit 024ba52

Please sign in to comment.