Skip to content

Commit

Permalink
[Site Editor - Page Inspector]: Add ability to switch templates (#51477)
Browse files Browse the repository at this point in the history
* [Site Editor - Page Inspector]: Add ability to switch templates

* try setting the page/template from edited entity record

* Update label

* Truncate

* update z-index of templates swap modal

* fix typo

* add + update tests

* fix suggestions per template's `postTypes` and test

* change order of calling in `onTemplateSelect`

---------

Co-authored-by: James Koster <james@jameskoster.co.uk>
  • Loading branch information
ntsekouras and jameskoster committed Sep 12, 2023
1 parent 7d054a2 commit bba4bbf
Show file tree
Hide file tree
Showing 14 changed files with 460 additions and 83 deletions.
2 changes: 1 addition & 1 deletion docs/reference-guides/data/data-core-edit-site.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ _Parameters_

_Returns_

- `number`: The resolved template ID for the page route.
- `Object`: Action object.

### setHasPageContentFocus

Expand Down
1 change: 1 addition & 0 deletions packages/base-styles/_z-index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ $z-layers: (
".block-editor-template-part__selection-modal": 1000001,
".block-editor-block-rename-modal": 1000001,
".edit-site-list__rename-modal": 1000001,
".edit-site-swap-template-modal": 1000001,

// Note: The ConfirmDialog component's z-index is being set to 1000001 in packages/components/src/confirm-dialog/styles.ts
// because it uses emotion and not sass. We need it to render on top its parent popover.
Expand Down
4 changes: 2 additions & 2 deletions packages/core-data/src/hooks/use-entity-record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ export default function useEntityRecord< RecordType >(

const mutations = useMemo(
() => ( {
edit: ( record ) =>
editEntityRecord( kind, name, recordId, record ),
edit: ( record, editOptions: any = {} ) =>
editEntityRecord( kind, name, recordId, record, editOptions ),
save: ( saveOptions: any = {} ) =>
saveEditedEntityRecord( kind, name, recordId, {
throwOnError: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,31 @@
* WordPress dependencies
*/
import { useSelect, useDispatch } from '@wordpress/data';
import { useMemo } from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';
import { BlockContextProvider, BlockPreview } from '@wordpress/block-editor';
import { Button, __experimentalVStack as VStack } from '@wordpress/components';
import {
DropdownMenu,
MenuGroup,
MenuItem,
__experimentalHStack as HStack,
__experimentalText as Text,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { store as coreStore } from '@wordpress/core-data';
import { parse } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import { store as editSiteStore } from '../../../store';
import SwapTemplateButton from './swap-template-button';
import ResetDefaultTemplate from './reset-default-template';

const POPOVER_PROPS = {
className: 'edit-site-page-panels-edit-template__dropdown',
placement: 'bottom-start',
};

export default function EditTemplate() {
const { context, hasResolved, template } = useSelect( ( select ) => {
const { hasResolved, template } = useSelect( ( select ) => {
const { getEditedPostContext, getEditedPostType, getEditedPostId } =
select( editSiteStore );
const { getEditedEntityRecord, hasFinishedResolution } =
Expand All @@ -39,39 +49,43 @@ export default function EditTemplate() {

const { setHasPageContentFocus } = useDispatch( editSiteStore );

const blockContext = useMemo(
() => ( { ...context, postType: null, postId: null } ),
[ context ]
);

const blocks = useMemo(
() =>
template.blocks ??
( template.content && typeof template.content !== 'function'
? parse( template.content )
: [] ),
[ template.blocks, template.content ]
);

if ( ! hasResolved ) {
return null;
}

return (
<VStack>
<div>{ decodeEntities( template.title ) }</div>
<div className="edit-site-page-panels__edit-template-preview">
<BlockContextProvider value={ blockContext }>
<BlockPreview viewportWidth={ 1024 } blocks={ blocks } />
</BlockContextProvider>
</div>
<Button
className="edit-site-page-panels__edit-template-button"
variant="secondary"
onClick={ () => setHasPageContentFocus( false ) }
<HStack className="edit-site-summary-field">
<Text className="edit-site-summary-field__label">
{ __( 'Template' ) }
</Text>
<DropdownMenu
popoverProps={ POPOVER_PROPS }
focusOnMount
toggleProps={ {
variant: 'tertiary',
className: 'edit-site-summary-field__trigger',
} }
label={ __( 'Template options' ) }
text={ decodeEntities( template.title ) }
icon={ null }
>
{ __( 'Edit template' ) }
</Button>
</VStack>
{ ( { onClose } ) => (
<>
<MenuGroup>
<MenuItem
onClick={ () => {
setHasPageContentFocus( false );
onClose();
} }
>
{ __( 'Edit template' ) }
</MenuItem>
<SwapTemplateButton onClick={ onClose } />
</MenuGroup>
<ResetDefaultTemplate onClick={ onClose } />
</>
) }
</DropdownMenu>
</HStack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { useMemo } from '@wordpress/element';
import { store as coreStore } from '@wordpress/core-data';

/**
* Internal dependencies
*/
import { store as editSiteStore } from '../../../store';

export function useEditedPostContext() {
return useSelect(
( select ) => select( editSiteStore ).getEditedPostContext(),
[]
);
}

export function useIsPostsPage() {
const { postId } = useEditedPostContext();
return useSelect(
( select ) =>
+postId ===
select( coreStore ).getEntityRecord( 'root', 'site' )
?.page_for_posts,
[ postId ]
);
}

function useTemplates() {
return useSelect(
( select ) =>
select( coreStore ).getEntityRecords( 'postType', 'wp_template', {
per_page: -1,
post_type: 'page',
} ),
[]
);
}

export function useAvailableTemplates() {
const currentTemplateSlug = useCurrentTemplateSlug();
const isPostsPage = useIsPostsPage();
const templates = useTemplates();
return useMemo(
() =>
// The posts page template cannot be changed.
! isPostsPage &&
templates?.filter(
( template ) =>
template.is_custom &&
template.slug !== currentTemplateSlug &&
!! template.content.raw // Skip empty templates.
),
[ templates, currentTemplateSlug, isPostsPage ]
);
}

export function useCurrentTemplateSlug() {
const { postType, postId } = useEditedPostContext();
const templates = useTemplates();
const entityTemplate = useSelect(
( select ) => {
const post = select( coreStore ).getEditedEntityRecord(
'postType',
postType,
postId
);
return post?.template;
},
[ postType, postId ]
);

if ( ! entityTemplate ) {
return;
}
// If a page has a `template` set and is not included in the list
// of the theme's templates, do not return it, in order to resolve
// to the current theme's default template.
return templates?.find( ( template ) => template.slug === entityTemplate )
?.slug;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { store as editSiteStore } from '../../../store';
import SidebarCard from '../sidebar-card';
import PageContent from './page-content';
import PageSummary from './page-summary';
import EditTemplate from './edit-template';

export default function PagePanels() {
const { id, type, hasResolved, status, date, password, title, modified } =
Expand Down Expand Up @@ -81,9 +80,6 @@ export default function PagePanels() {
<PanelBody title={ __( 'Content' ) }>
<PageContent />
</PanelBody>
<PanelBody title={ __( 'Template' ) }>
<EditTemplate />
</PanelBody>
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { __experimentalVStack as VStack } from '@wordpress/components';
*/
import PageStatus from './page-status';
import PublishDate from './publish-date';
import EditTemplate from './edit-template';

export default function PageSummary( {
status,
Expand All @@ -30,6 +31,7 @@ export default function PageSummary( {
postId={ postId }
postType={ postType }
/>
<EditTemplate />
</VStack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* WordPress dependencies
*/
import { useDispatch } from '@wordpress/data';
import { MenuGroup, MenuItem } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useEntityRecord } from '@wordpress/core-data';

/**
* Internal dependencies
*/
import {
useCurrentTemplateSlug,
useEditedPostContext,
useIsPostsPage,
} from './hooks';
import { store as editSiteStore } from '../../../store';

export default function ResetDefaultTemplate( { onClick } ) {
const currentTemplateSlug = useCurrentTemplateSlug();
const isPostsPage = useIsPostsPage();
const { postType, postId } = useEditedPostContext();
const entity = useEntityRecord( 'postType', postType, postId );
const { setPage } = useDispatch( editSiteStore );
// The default template in a post is indicated by an empty string.
if ( ! currentTemplateSlug || isPostsPage ) {
return null;
}
return (
<MenuGroup>
<MenuItem
onClick={ async () => {
entity.edit( { template: '' }, { undoIgnore: true } );
onClick();
await setPage( {
context: { postType, postId },
} );
} }
>
{ __( 'Reset' ) }
</MenuItem>
</MenuGroup>
);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
.edit-site-page-panels__edit-template-preview {
border: 1px solid $gray-200;
height: 200px;
max-height: 200px;
overflow: hidden;
.edit-site-swap-template-modal {
z-index: z-index(".edit-site-swap-template-modal");
}

.edit-site-page-panels__edit-template-button {
justify-content: center;
.edit-site-page-panels__swap-template__confirm-modal__actions {
margin-top: $grid-unit-30;
}

.edit-site-page-panels__swap-template__modal-content .block-editor-block-patterns-list {
column-count: 2;
column-gap: $grid-unit-30;

// Small top padding required to avoid cutting off the visible outline when hovering items
padding-top: $border-width-focus-fallback;

@include break-medium() {
column-count: 3;
}

@include break-wide() {
column-count: 4;
}

.block-editor-block-patterns-list__list-item {
break-inside: avoid-column;
}

.block-editor-block-patterns-list__item {
// Avoid to override the BlockPatternList component
// default hover and focus styles.
&:not(:focus):not(:hover) .block-editor-block-preview__container {
box-shadow: 0 0 0 1px $gray-300;
}
}
}

.edit-site-change-status__content {
Expand Down Expand Up @@ -36,15 +61,21 @@

.edit-site-summary-field {
.components-dropdown {
flex-grow: 1;
width: 70%;
}

.edit-site-summary-field__trigger {
width: 100%;
max-width: 100%;

// Truncate
display: block;
text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.edit-site-summary-field__label {
width: 30%;
}
}

Loading

0 comments on commit bba4bbf

Please sign in to comment.