diff --git a/public_html/wp-content/plugins/pattern-directory/includes/notifications.php b/public_html/wp-content/plugins/pattern-directory/includes/notifications.php
index e61fac045..ebd5c862e 100644
--- a/public_html/wp-content/plugins/pattern-directory/includes/notifications.php
+++ b/public_html/wp-content/plugins/pattern-directory/includes/notifications.php
@@ -8,11 +8,44 @@
defined( 'WPINC' ) || die();
+/**
+ * The post meta key holding the moderator's message to the author, which is
+ * included in the "pattern unlisted" email.
+ */
+const UNLISTED_DETAIL_META = '_wporg_unlist_reason_detail';
+
/**
* Actions and filters.
*/
add_action( 'wp_after_insert_post', __NAMESPACE__ . '\trigger_notifications', 20, 4 );
add_action( 'wporg_unlist_pattern', __NAMESPACE__ . '\notify_pattern_flagged' );
+add_action( 'init', __NAMESPACE__ . '\register_unlisted_meta' );
+
+/**
+ * Register the post meta used to store the moderator's message to the author.
+ *
+ * Editable by anyone who can edit the pattern (i.e. moderators), so it can be
+ * set from the Unlist modal in the block editor and read back when sending the
+ * "pattern unlisted" email.
+ *
+ * @return void
+ */
+function register_unlisted_meta() {
+ register_post_meta(
+ PATTERN,
+ UNLISTED_DETAIL_META,
+ array(
+ 'type' => 'string',
+ 'description' => 'A message from the moderator, included in the email sent to the author when a pattern is unlisted.',
+ 'single' => true,
+ 'show_in_rest' => true,
+ 'sanitize_callback' => 'sanitize_textarea_field',
+ 'auth_callback' => function( $allowed, $meta_key, $object_id ) {
+ return current_user_can( 'edit_post', $object_id );
+ },
+ )
+ );
+}
/**
* Fire off relevant notification when a post is finished updating.
@@ -211,6 +244,12 @@ function notify_pattern_unlisted( $post ) {
$reason = get_default_reason_description();
}
+ // Append the moderator's message to the author, if one was provided.
+ $detail = get_post_meta( $post->ID, UNLISTED_DETAIL_META, true );
+ if ( $detail ) {
+ $reason .= "\n\n" . $detail;
+ }
+
$subject = esc_html__( 'Pattern unlisted', 'wporg-patterns' );
$message = sprintf(
diff --git a/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/details.js b/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/details.js
index 7c9a923f4..333a7f4e6 100644
--- a/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/details.js
+++ b/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/details.js
@@ -2,10 +2,17 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
-import { PluginDocumentSettingPanel } from '@wordpress/edit-post';
import { ComboboxControl, FormTokenField, TextControl, TextareaControl } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
-import { store as editorStore } from '@wordpress/editor';
+// `PluginDocumentSettingPanel` moved from `@wordpress/edit-post` to `@wordpress/editor`.
+// Import from both and use whichever the running WordPress version provides.
+import {
+ PluginDocumentSettingPanel as PluginDocumentSettingPanelFromEditor,
+ store as editorStore,
+} from '@wordpress/editor';
+import { PluginDocumentSettingPanel as PluginDocumentSettingPanelFromEditPost } from '@wordpress/edit-post';
+
+const PluginDocumentSettingPanel = PluginDocumentSettingPanelFromEditor || PluginDocumentSettingPanelFromEditPost;
const KEYWORD_SLUG = 'wpop_keywords';
const DESCRIPTION_SLUG = 'wpop_description';
diff --git a/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/unlist-button/index.js b/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/unlist-button/index.js
index 5ab72c2a1..087476063 100644
--- a/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/unlist-button/index.js
+++ b/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/unlist-button/index.js
@@ -2,9 +2,11 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
-import { PluginPostStatusInfo } from '@wordpress/edit-post';
import { Button } from '@wordpress/components';
-import { store as editorStore } from '@wordpress/editor';
+// `PluginPostStatusInfo` moved from `@wordpress/edit-post` to `@wordpress/editor`.
+// Import from both and use whichever the running WordPress version provides.
+import { PluginPostStatusInfo as PluginPostStatusInfoFromEditor, store as editorStore } from '@wordpress/editor';
+import { PluginPostStatusInfo as PluginPostStatusInfoFromEditPost } from '@wordpress/edit-post';
import { useDispatch, useSelect } from '@wordpress/data';
import { useState } from '@wordpress/element';
@@ -15,6 +17,8 @@ import { UNLISTED_STATUS } from '../settings';
import UnlistModal from './modal';
import './unlist.scss';
+const PluginPostStatusInfo = PluginPostStatusInfoFromEditor || PluginPostStatusInfoFromEditPost;
+
export const UnlistButton = () => {
const status = useSelect( ( select ) => {
const _post = select( editorStore ).getCurrentPost();
@@ -23,10 +27,11 @@ export const UnlistButton = () => {
const { editPost, savePost } = useDispatch( editorStore );
const [ showModal, setShowModal ] = useState( false );
- const onSubmit = ( reasonId ) => {
+ const onSubmit = ( reasonId, details = '' ) => {
editPost( {
status: UNLISTED_STATUS,
'wporg-pattern-flag-reason': [ reasonId ],
+ meta: { _wporg_unlist_reason_detail: details },
} );
savePost();
};
diff --git a/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/unlist-button/modal.js b/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/unlist-button/modal.js
index e3838641c..80b34b8ec 100644
--- a/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/unlist-button/modal.js
+++ b/public_html/wp-content/plugins/pattern-directory/src/pattern-post-type/unlist-button/modal.js
@@ -74,7 +74,7 @@ const UnlistModal = ( { onClose, onSubmit } ) => {
}, [] );
const submittedText = __(
- 'The pattern has been unlisted, and your internal note has been saved.',
+ 'The pattern has been unlisted, and the author has been notified by email.',
'wporg-patterns'
);
@@ -101,7 +101,7 @@ const UnlistModal = ( { onClose, onSubmit } ) => {
note: details ? `UNLISTED: ${ reason.label } — ${ details }` : `UNLISTED: ${ reason.label }`,
onSuccess: () => {
if ( 'function' === typeof onSubmit ) {
- onSubmit( selectedOption );
+ onSubmit( selectedOption, details );
}
dispatch( { status: 'NOTE_RECIEVED' } );
speak( submittedText );
@@ -155,9 +155,9 @@ const UnlistModal = ( { onClose, onSubmit } ) => {
) }