diff --git a/packages/edit-site/src/components/dataviews-actions/index.js b/packages/edit-site/src/components/dataviews-actions/index.js
index ed6522995d3b7b..09b7597c6cb341 100644
--- a/packages/edit-site/src/components/dataviews-actions/index.js
+++ b/packages/edit-site/src/components/dataviews-actions/index.js
@@ -9,6 +9,7 @@ import { privateApis as routerPrivateApis } from '@wordpress/router';
/**
* Internal dependencies
*/
+import { PATTERN_TYPES } from '../../utils/constants';
import { unlock } from '../../lock-unlock';
const { useHistory } = unlock( routerPrivateApis );
@@ -21,8 +22,12 @@ export const useEditPostAction = () => {
label: __( 'Edit' ),
isPrimary: true,
icon: edit,
- isEligible( { status } ) {
- return status !== 'trash';
+ isEligible( post ) {
+ if ( post.status === 'trash' ) {
+ return false;
+ }
+ // It's eligible for all post types except theme patterns.
+ return post.type !== PATTERN_TYPES.theme;
},
callback( items ) {
const post = items[ 0 ];
diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js
index ba4d751de5ae08..b7fc350c3eabb9 100644
--- a/packages/edit-site/src/components/editor/index.js
+++ b/packages/edit-site/src/components/editor/index.js
@@ -213,6 +213,7 @@ export default function Editor( { isLoading } ) {
( actionId, items ) => {
switch ( actionId ) {
case 'move-to-trash':
+ case 'delete-post':
{
history.push( {
postType: items[ 0 ].type,
diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js
index bd7552b642fad7..1d05a22c52209a 100644
--- a/packages/editor/src/components/post-actions/actions.js
+++ b/packages/editor/src/components/post-actions/actions.js
@@ -9,7 +9,6 @@ import { store as coreStore } from '@wordpress/core-data';
import { __, _n, sprintf, _x } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
import { useMemo, useState } from '@wordpress/element';
-import { store as reusableBlocksStore } from '@wordpress/reusable-blocks';
import { privateApis as patternsPrivateApis } from '@wordpress/patterns';
import {
@@ -37,6 +36,33 @@ import { exportPatternAsJSONAction } from './export-pattern-action';
// Patterns.
const { PATTERN_TYPES } = unlock( patternsPrivateApis );
+/**
+ * Check if a template is removable.
+ *
+ * @param {Object} template The template entity to check.
+ * @return {boolean} Whether the template is removable.
+ */
+function isTemplateRemovable( template ) {
+ if ( ! template ) {
+ return false;
+ }
+ // In patterns list page we map the templates parts to a different object
+ // than the one returned from the endpoint. This is why we need to check for
+ // two props whether is custom or has a theme file.
+ return (
+ [ template.source, template.templatePart?.source ].includes(
+ TEMPLATE_ORIGINS.custom
+ ) &&
+ ! template.has_theme_file &&
+ ! template.templatePart?.has_theme_file
+ );
+}
+const canDeleteOrReset = ( item ) => {
+ const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE;
+ const isUserPattern = item.type === PATTERN_TYPES.user;
+ return isUserPattern || ( isTemplatePart && item.isCustom );
+};
+
function getItemTitle( item ) {
if ( typeof item.title === 'string' ) {
return decodeEntities( item.title );
@@ -44,6 +70,89 @@ function getItemTitle( item ) {
return decodeEntities( item.title?.rendered || '' );
}
+// This action is used for templates, patterns and template parts.
+// Every other post type uses the similar `trashPostAction` which
+// moves the post to trash.
+const deletePostAction = {
+ id: 'delete-post',
+ label: __( 'Delete' ),
+ isPrimary: true,
+ icon: trash,
+ isEligible( post ) {
+ if (
+ [ TEMPLATE_POST_TYPE, TEMPLATE_PART_POST_TYPE ].includes(
+ post.type
+ )
+ ) {
+ return isTemplateRemovable( post );
+ }
+ // We can only remove user patterns.
+ return post.type === PATTERN_TYPES.user;
+ },
+ supportsBulk: true,
+ hideModalHeader: true,
+ RenderModal: ( {
+ items,
+ closeModal,
+ onActionStart,
+ onActionPerformed,
+ } ) => {
+ const [ isBusy, setIsBusy ] = useState( false );
+ const { removeTemplates } = unlock( useDispatch( editorStore ) );
+ return (
+
+
+ { items.length > 1
+ ? sprintf(
+ // translators: %d: number of items to delete.
+ _n(
+ 'Delete %d item?',
+ 'Delete %d items?',
+ items.length
+ ),
+ items.length
+ )
+ : sprintf(
+ // translators: %s: The template or template part's titles
+ __( 'Delete "%s"?' ),
+ getItemTitle( items[ 0 ] )
+ ) }
+
+
+
+
+
+
+ );
+ },
+};
+
const trashPostAction = {
id: 'move-to-trash',
label: __( 'Move to Trash' ),
@@ -55,7 +164,7 @@ const trashPostAction = {
supportsBulk: true,
hideModalHeader: true,
RenderModal: ( {
- items: posts,
+ items,
closeModal,
onActionStart,
onActionPerformed,
@@ -67,20 +176,22 @@ const trashPostAction = {
return (
- { posts.length === 1
+ { items.length === 1
? sprintf(
- // translators: %s: The page's title.
- __( 'Are you sure you want to delete "%s"?' ),
- getItemTitle( posts[ 0 ] )
+ // translators: %s: The item's title.
+ __(
+ 'Are you sure you want to move to trash "%s"?'
+ ),
+ getItemTitle( items[ 0 ] )
)
: sprintf(
- // translators: %d: The number of pages (2 or more).
+ // translators: %d: The number of items (2 or more).
_n(
- 'Are you sure you want to delete %d page?',
- 'Are you sure you want to delete %d pages?',
- posts.length
+ 'Are you sure you want to move to trash %d item?',
+ 'Are you sure you want to move to trash %d items?',
+ items.length
),
- posts.length
+ items.length
) }
@@ -97,18 +208,18 @@ const trashPostAction = {
onClick={ async () => {
setIsBusy( true );
if ( onActionStart ) {
- onActionStart( posts );
+ onActionStart( items );
}
const promiseResult = await Promise.allSettled(
- posts.map( ( post ) => {
- return deleteEntityRecord(
+ items.map( ( item ) =>
+ deleteEntityRecord(
'postType',
- post.type,
- post.id,
+ item.type,
+ item.id,
{},
{ throwOnError: true }
- );
- } )
+ )
+ )
);
// If all the promises were fulfilled with success.
if (
@@ -119,41 +230,41 @@ const trashPostAction = {
let successMessage;
if ( promiseResult.length === 1 ) {
successMessage = sprintf(
- /* translators: The posts's title. */
- __( '"%s" moved to the Trash.' ),
- getItemTitle( posts[ 0 ] )
+ /* translators: The item's title. */
+ __( '"%s" moved to trash.' ),
+ getItemTitle( items[ 0 ] )
);
- } else if ( posts[ 0 ].type === 'page' ) {
+ } else if ( items[ 0 ].type === 'page' ) {
successMessage = sprintf(
- /* translators: The number of pages. */
- __( '%s pages moved to the Trash.' ),
- posts.length
+ /* translators: The number of items. */
+ __( '%s items moved to trash.' ),
+ items.length
);
} else {
successMessage = sprintf(
/* translators: The number of posts. */
- __( '%s posts moved to the Trash.' ),
- posts.length
+ __( '%s items move to trash.' ),
+ items.length
);
}
createSuccessNotice( successMessage, {
type: 'snackbar',
- id: 'trash-post-action',
+ id: 'move-to-trash-action',
} );
} else {
- // If there was at lease one failure.
+ // If there was at least one failure.
let errorMessage;
- // If we were trying to move a single post to the trash.
+ // If we were trying to delete a single item.
if ( promiseResult.length === 1 ) {
if ( promiseResult[ 0 ].reason?.message ) {
errorMessage =
promiseResult[ 0 ].reason.message;
} else {
errorMessage = __(
- 'An error occurred while moving the post to the trash.'
+ 'An error occurred while moving to trash the item.'
);
}
- // If we were trying to move multiple posts to the trash
+ // If we were trying to delete multiple items.
} else {
const errorMessages = new Set();
const failedPromises = promiseResult.filter(
@@ -168,13 +279,13 @@ const trashPostAction = {
}
if ( errorMessages.size === 0 ) {
errorMessage = __(
- 'An error occurred while moving the posts to the trash.'
+ 'An error occurred while moving to trash the items.'
);
} else if ( errorMessages.size === 1 ) {
errorMessage = sprintf(
/* translators: %s: an error message */
__(
- 'An error occurred while moving the posts to the trash: %s'
+ 'An error occurred while moving to trash the item: %s'
),
[ ...errorMessages ][ 0 ]
);
@@ -182,7 +293,7 @@ const trashPostAction = {
errorMessage = sprintf(
/* translators: %s: a list of comma separated error messages */
__(
- 'Some errors occurred while moving the pages to the trash: %s'
+ 'Some errors occurred while moving to trash the items: %s'
),
[ ...errorMessages ].join( ',' )
);
@@ -193,7 +304,7 @@ const trashPostAction = {
} );
}
if ( onActionPerformed ) {
- onActionPerformed( posts );
+ onActionPerformed( items );
}
setIsBusy( false );
closeModal();
@@ -202,7 +313,7 @@ const trashPostAction = {
disabled={ isBusy }
__experimentalIsFocusable
>
- { __( 'Delete' ) }
+ { __( 'Trash' ) }
@@ -511,7 +622,7 @@ const renamePostAction = {
) {
return true;
}
- // In the case of templates, we can only remove custom templates.
+ // In the case of templates, we can only rename custom templates.
if ( post.type === TEMPLATE_POST_TYPE ) {
return isTemplateRemovable( post ) && post.is_custom;
}
@@ -850,245 +961,6 @@ const resetTemplateAction = {
},
};
-/**
- * Check if a template is removable.
- * Copy from packages/edit-site/src/utils/is-template-removable.js.
- *
- * @param {Object} template The template entity to check.
- * @return {boolean} Whether the template is revertable.
- */
-function isTemplateRemovable( template ) {
- if ( ! template ) {
- return false;
- }
-
- return (
- template.source === TEMPLATE_ORIGINS.custom && ! template.has_theme_file
- );
-}
-
-const deleteTemplateAction = {
- id: 'delete-template',
- label: __( 'Delete' ),
- isEligible: isTemplateRemovable,
- icon: trash,
- supportsBulk: true,
- hideModalHeader: true,
- RenderModal: ( {
- items: templates,
- closeModal,
- onActionStart,
- onActionPerformed,
- } ) => {
- const [ isBusy, setIsBusy ] = useState( false );
- const { removeTemplates } = unlock( useDispatch( editorStore ) );
- return (
-
-
- { templates.length > 1
- ? sprintf(
- // translators: %d: number of items to delete.
- _n(
- 'Delete %d item?',
- 'Delete %d items?',
- templates.length
- ),
- templates.length
- )
- : sprintf(
- // translators: %s: The template or template part's titles
- __( 'Delete "%s"?' ),
- decodeEntities(
- templates?.[ 0 ]?.title?.rendered
- )
- ) }
-
-
-
-
-
-
- );
- },
-};
-
-const canDeleteOrReset = ( item ) => {
- const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE;
- const isUserPattern = item.type === PATTERN_TYPES.user;
- return isUserPattern || ( isTemplatePart && item.isCustom );
-};
-
-export const deletePatternAction = {
- id: 'delete-pattern',
- label: __( 'Delete' ),
- isEligible: ( item ) => {
- if ( ! item ) {
- return false;
- }
- const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE;
- const hasThemeFile =
- isTemplatePart && item.templatePart?.has_theme_file;
- return canDeleteOrReset( item ) && ! hasThemeFile;
- },
- hideModalHeader: true,
- supportsBulk: true,
- RenderModal: ( { items, closeModal, onActionPerformed } ) => {
- const { __experimentalDeleteReusableBlock } =
- useDispatch( reusableBlocksStore );
- const { createErrorNotice, createSuccessNotice } =
- useDispatch( noticesStore );
- const { removeTemplates } = unlock( useDispatch( editorStore ) );
-
- const deletePattern = async () => {
- const promiseResult = await Promise.allSettled(
- items.map( ( item ) => {
- return __experimentalDeleteReusableBlock( item.id );
- } )
- );
- // If all the promises were fulfilled with success.
- if (
- promiseResult.every( ( { status } ) => status === 'fulfilled' )
- ) {
- let successMessage;
- if ( promiseResult.length === 1 ) {
- successMessage = sprintf(
- /* translators: The posts's title. */
- __( '"%s" deleted.' ),
- items[ 0 ].title
- );
- } else {
- successMessage = __( 'The patterns were deleted.' );
- }
- createSuccessNotice( successMessage, {
- type: 'snackbar',
- id: 'edit-site-page-trashed',
- } );
- } else {
- // If there was at lease one failure.
- let errorMessage;
- // If we were trying to delete a single pattern.
- if ( promiseResult.length === 1 ) {
- if ( promiseResult[ 0 ].reason?.message ) {
- errorMessage = promiseResult[ 0 ].reason.message;
- } else {
- errorMessage = __(
- 'An error occurred while deleting the pattern.'
- );
- }
- // If we were trying to delete multiple patterns.
- } else {
- const errorMessages = new Set();
- const failedPromises = promiseResult.filter(
- ( { status } ) => status === 'rejected'
- );
- for ( const failedPromise of failedPromises ) {
- if ( failedPromise.reason?.message ) {
- errorMessages.add( failedPromise.reason.message );
- }
- }
- if ( errorMessages.size === 0 ) {
- errorMessage = __(
- 'An error occurred while deleting the patterns.'
- );
- } else if ( errorMessages.size === 1 ) {
- errorMessage = sprintf(
- /* translators: %s: an error message */
- __(
- 'An error occurred while deleting the patterns: %s'
- ),
- [ ...errorMessages ][ 0 ]
- );
- } else {
- errorMessage = sprintf(
- /* translators: %s: a list of comma separated error messages */
- __(
- 'Some errors occurred while deleting the patterns: %s'
- ),
- [ ...errorMessages ].join( ',' )
- );
- }
- createErrorNotice( errorMessage, {
- type: 'snackbar',
- } );
- }
- }
- };
- const deleteItem = () => {
- if ( items[ 0 ].type === TEMPLATE_PART_POST_TYPE ) {
- removeTemplates( items );
- } else {
- deletePattern();
- }
- if ( onActionPerformed ) {
- onActionPerformed();
- }
- closeModal();
- };
- let questionMessage;
- if ( items.length === 1 ) {
- questionMessage = sprintf(
- // translators: %s: The page's title.
- __( 'Are you sure you want to delete "%s"?' ),
- decodeEntities( items[ 0 ].title || items[ 0 ].name )
- );
- } else if (
- items.length > 1 &&
- items[ 0 ].type === TEMPLATE_PART_POST_TYPE
- ) {
- questionMessage = sprintf(
- // translators: %d: The number of template parts (2 or more).
- __( 'Are you sure you want to delete %d template parts?' ),
- items.length
- );
- } else {
- questionMessage = sprintf(
- // translators: %d: The number of patterns (2 or more).
- __( 'Are you sure you want to delete %d patterns?' ),
- items.length
- );
- }
- return (
-
- { questionMessage }
-
-
-
-
-
- );
- },
-};
-
export function usePostActions( postType, onActionPerformed ) {
const { postTypeObject } = useSelect(
( select ) => {
@@ -1125,11 +997,10 @@ export function usePostActions( postType, onActionPerformed ) {
renamePostAction,
isPattern && exportPatternAsJSONAction,
isTemplateOrTemplatePart ? resetTemplateAction : restorePostAction,
- isTemplateOrTemplatePart
- ? deleteTemplateAction
- : permanentlyDeletePostAction,
- isPattern && deletePatternAction,
- ! isTemplateOrTemplatePart && trashPostAction,
+ isTemplateOrTemplatePart || isPattern
+ ? deletePostAction
+ : trashPostAction,
+ ! isTemplateOrTemplatePart && permanentlyDeletePostAction,
].filter( Boolean );
if ( onActionPerformed ) {
diff --git a/packages/editor/src/store/private-actions.js b/packages/editor/src/store/private-actions.js
index c3fca0798e8b70..9304a2fe2c0579 100644
--- a/packages/editor/src/store/private-actions.js
+++ b/packages/editor/src/store/private-actions.js
@@ -15,7 +15,6 @@ import { decodeEntities } from '@wordpress/html-entities';
* Internal dependencies
*/
import isTemplateRevertable from './utils/is-template-revertable';
-import { TEMPLATE_POST_TYPE } from './constants';
/**
* Returns an action object used to set which template is currently being used/edited.
@@ -363,14 +362,13 @@ export const revertTemplate =
};
/**
- * Action that removes an array of templates.
+ * Action that removes an array of templates, template parts or patterns.
*
- * @param {Array} items An array of template or template part objects to remove.
+ * @param {Array} items An array of template,template part or pattern objects to remove.
*/
export const removeTemplates =
( items ) =>
async ( { registry } ) => {
- const isTemplate = items[ 0 ].type === TEMPLATE_POST_TYPE;
const promiseResult = await Promise.allSettled(
items.map( ( item ) => {
return registry
@@ -402,16 +400,14 @@ export const removeTemplates =
decodeEntities( title )
);
} else {
- successMessage = isTemplate
- ? __( 'Templates deleted.' )
- : __( 'Template parts deleted.' );
+ successMessage = __( 'Items deleted.' );
}
registry
.dispatch( noticesStore )
.createSuccessNotice( successMessage, {
type: 'snackbar',
- id: 'site-editor-template-deleted-success',
+ id: 'editor-template-deleted-success',
} );
} else {
// If there was at lease one failure.
@@ -421,11 +417,9 @@ export const removeTemplates =
if ( promiseResult[ 0 ].reason?.message ) {
errorMessage = promiseResult[ 0 ].reason.message;
} else {
- errorMessage = isTemplate
- ? __( 'An error occurred while deleting the template.' )
- : __(
- 'An error occurred while deleting the template part.'
- );
+ errorMessage = __(
+ 'An error occurred while deleting the item.'
+ );
}
// If we were trying to delete a multiple templates
} else {
@@ -439,45 +433,23 @@ export const removeTemplates =
}
}
if ( errorMessages.size === 0 ) {
- errorMessage = isTemplate
- ? __(
- 'An error occurred while deleting the templates.'
- )
- : __(
- 'An error occurred while deleting the template parts.'
- );
+ errorMessage = __(
+ 'An error occurred while deleting the items.'
+ );
} else if ( errorMessages.size === 1 ) {
- errorMessage = isTemplate
- ? sprintf(
- /* translators: %s: an error message */
- __(
- 'An error occurred while deleting the templates: %s'
- ),
- [ ...errorMessages ][ 0 ]
- )
- : sprintf(
- /* translators: %s: an error message */
- __(
- 'An error occurred while deleting the template parts: %s'
- ),
- [ ...errorMessages ][ 0 ]
- );
+ errorMessage = sprintf(
+ /* translators: %s: an error message */
+ __( 'An error occurred while deleting the items: %s' ),
+ [ ...errorMessages ][ 0 ]
+ );
} else {
- errorMessage = isTemplate
- ? sprintf(
- /* translators: %s: a list of comma separated error messages */
- __(
- 'Some errors occurred while deleting the templates: %s'
- ),
- [ ...errorMessages ].join( ',' )
- )
- : sprintf(
- /* translators: %s: a list of comma separated error messages */
- __(
- 'Some errors occurred while deleting the template parts: %s'
- ),
- [ ...errorMessages ].join( ',' )
- );
+ sprintf(
+ /* translators: %s: a list of comma separated error messages */
+ __(
+ 'Some errors occurred while deleting the items: %s'
+ ),
+ [ ...errorMessages ].join( ',' )
+ );
}
}
registry
diff --git a/test/e2e/specs/editor/various/change-detection.spec.js b/test/e2e/specs/editor/various/change-detection.spec.js
index a737e4eb94a5fc..4ac262f4c1348d 100644
--- a/test/e2e/specs/editor/various/change-detection.spec.js
+++ b/test/e2e/specs/editor/various/change-detection.spec.js
@@ -420,7 +420,7 @@ test.describe( 'Change detection', () => {
.click();
await page
.getByRole( 'dialog' )
- .getByRole( 'button', { name: 'Delete' } )
+ .getByRole( 'button', { name: 'Trash' } )
.click();
await expect( page ).toHaveURL( '/wp-admin/edit.php?post_type=post' );