html = $html; $this->plugin = $plugin; } public abstract function replacePostUpdatedMessage(array $messages): array; protected function cloneItemMeta(int $fromPostId, int $toPostId) { global $wpdb; $metaFields = get_post_custom($fromPostId); foreach ($metaFields as $metaKey => $metaValues) { if (! is_array($metaValues) || ! $metaValues) { continue; } foreach ($metaValues as $i => $metaValue) { $wpdb->insert($wpdb->prefix . 'postmeta', [ 'post_id' => $toPostId, 'meta_key' => sanitize_text_field($metaKey), 'meta_value' => $metaValue, ], [ '%d', '%s', '%s', ]); } } } protected function getActionClone(): string { return static::NAME . '_clone'; } protected function getActionCloned(): string { return static::NAME . '_cloned'; } /** * @param int|string $postId Can be string, e.g. 'options' * * @return bool */ protected function isMyPost($postId): bool { // for 'site-settings' and similar if (! is_numeric($postId)) { return false; } $post = get_post($postId); if (static::NAME !== $post->post_type || wp_is_post_revision($postId) || 'publish' !== $post->post_status) { return false; } return true; } public function setHooks(): void { add_action('admin_init', [$this, 'cloneItemAction']); add_action('admin_notices', [$this, 'showItemClonedMessage']); add_action('add_meta_boxes', [$this, 'addMetaboxes']); add_action('admin_enqueue_scripts', [$this, 'addCodemirrorToCPTEditScreens']); add_action('post_edit_form_tag', [$this, 'disableAutocompleteForPostEdit']); add_filter('views_edit-' . static::NAME, [$this, 'printPostTypeDescription',]); add_filter('post_row_actions', [$this, 'getRowActions',], 10, 2); add_filter('post_updated_messages', [$this, 'replacePostUpdatedMessage']); } public function cloneItemAction(): void { if (! isset($_GET[$this->getActionClone()])) { return; } $viewId = (int)$_GET[$this->getActionClone()]; $viewPost = get_post($viewId); if (! $viewPost || static::NAME !== $viewPost->post_type) { return; } check_admin_referer('bulk-posts'); $args = [ 'post_type' => $viewPost->post_type, 'post_status' => 'draft', 'post_name' => $viewPost->post_name, 'post_title' => $viewPost->post_title . ' Clone', 'post_author' => $viewPost->post_author, ]; $newPostId = wp_insert_post($args); // something went wrong if (is_wp_error($newPostId)) { return; } $this->cloneItemMeta($viewPost->ID, $newPostId); $targetUrl = get_admin_url(null, '/edit.php?post_type=' . static::NAME); $targetUrl .= '&' . $this->getActionCloned() . '=1'; wp_redirect($targetUrl); exit; } public function showItemClonedMessage(): void { if (! isset($_GET[$this->getActionCloned()])) { return; } echo '
Item success cloned.
' . '%s
', esc_html($postType->description)); } return $views; // return original input unchanged } /** * Otherwise in case editing fields (without saving) and reloading a page, * then the fields have these unsaved values, it's wrong and breaks logic (e.g. of group-field selects) */ public function disableAutocompleteForPostEdit(WP_Post $post): void { if (static::NAME !== $post->post_type) { return; } echo ' autocomplete="off"'; } }