Duplicate Posts & Pages without a Plugin! The Simple Post Duplicator!

Duplicate posts pages without a plugin the simple post duplicator

Duplicating posts or pages in WordPress used to be simple. Yea, you can install a plugin, and there are some good ones. Years ago I used to use a great free one until it got bought by a bigger company and became bloated and tried to upsell me on other plugins. So, I wrote this code. And now… everything is simple again!

Duplicate posts pages without a plugin the simple post duplicator

What it does…

This is a WordPress code snippet that allows users to duplicate posts and pages seamlessly. It enables the creation of duplicate drafts, ensuring that the original content remains untouched (including taxonomy terms and post meta). This straightforward solution avoids the complexities of plugins while providing an efficient post duplication feature.

Why it does it…

This code was created as an alternative to bloated plugins that compromise simplicity and attempt to sell additional features. This Simple Post Duplicator code snippet aims to bring back the ease of duplicating posts and pages in WordPress without unnecessary complexities or upsells. It offers a lightweight and reliable solution for users who prefer a straightforward approach.

How it does it…

Orig: This code snippet gives you a PHP class (which means you can use the Code Snippets Pro ❤️ plugin or just copy/paste the code into your theme’s functions.php file) and will only run the code if the class doesn’t already exist.

This works on posts, pages and even custom post types (CPTs). It consists of two main methods:

  1. duplicatePostAsDraft(): This method handles the post duplication process. It verifies the user’s permission, checks for the presence of a post to duplicate, performs nonce verification for security, creates a duplicate draft post with identical content, taxonomy terms, and post meta information, and redirects the user to the new draft’s edit screen.
  2. addDuplicatePostLink(): This method adds a “Duplicate” link to the action list of individual posts in the WordPress admin panel. It ensures that only users with the appropriate permissions can see and use the link. Upon clicking the “Duplicate” link, the user is directed to the duplicate post’s edit screen.

Ahhh… concise and well-structured code to ensure a hassle-free post duplication experience! You’re welcome.

See the code…

<?php

if (!class_exists('SimplePostDuplicator')) {
    class SimplePostDuplicator {
        public function __construct() {
            add_action('admin_action_simple_post_duplicator_duplicate_post_as_draft', array($this, 'duplicatePostAsDraft'));
            add_filter('post_row_actions', array($this, 'addDuplicatePostLink'), 10, 2);
            add_filter('page_row_actions', array($this, 'addDuplicatePostLink'), 10, 2);
        }

        /**
         * Function for post duplication. Duplicates appear as drafts. Users are redirected to the edit screen.
         */
        public function duplicatePostAsDraft() {
            if (!(isset($_GET['post']) || isset($_POST['post']) || (isset($_REQUEST['action']) && 'simple_post_duplicator_duplicate_post_as_draft' === $_REQUEST['action']))) {
                wp_die('No post to duplicate has been supplied!');
            }

            // Nonce verification
            if (!isset($_GET['duplicate_nonce']) || !wp_verify_nonce($_GET['duplicate_nonce'], basename(__FILE__))) {
                wp_die('Invalid security token.');
            }

            // Get the original post ID
            $post_id = (isset($_GET['post'])) ? absint($_GET['post']) : absint($_POST['post']);

            // Get the original post data
            $post = get_post($post_id);

            // Check if the user has permission to duplicate posts
            if (!current_user_can('edit_posts') || !$post) {
                wp_die('You do not have permission to duplicate posts.');
            }

            // Prepare the new post data
            $args = array(
                'comment_status' => $post->comment_status,
                'ping_status' => $post->ping_status,
                'post_author' => get_current_user_id(),
                'post_content' => $post->post_content,
                'post_excerpt' => $post->post_excerpt,
                'post_name' => $post->post_name,
                'post_parent' => $post->post_parent,
                'post_password' => $post->post_password,
                'post_status' => 'draft',
                'post_title' => $post->post_title,
                'post_type' => $post->post_type,
                'to_ping' => $post->to_ping,
                'menu_order' => $post->menu_order
            );

            // Insert the new post
            $new_post_id = wp_insert_post($args);

            if ($new_post_id) {
                // Duplicate the taxonomy terms
                $taxonomies = get_object_taxonomies($post->post_type);
                foreach ($taxonomies as $taxonomy) {
                    $post_terms = wp_get_object_terms($post_id, $taxonomy, array('fields' => 'slugs'));
                    wp_set_object_terms($new_post_id, $post_terms, $taxonomy, false);
                }

                // Duplicate the post meta
                global $wpdb;
                $post_meta_infos = $wpdb->get_results($wpdb->prepare("SELECT meta_key, meta_value FROM $wpdb->postmeta WHERE post_id = %d", $post_id));
                foreach ($post_meta_infos as $meta_info) {
                    $meta_key = $meta_info->meta_key;
                    if ($meta_key === '_wp_old_slug') {
                        continue;
                    }
                    $meta_value = $meta_info->meta_value;
                    update_post_meta($new_post_id, $meta_key, $meta_value);
                }

                // Redirect to the edit post screen for the new draft
                wp_redirect(admin_url('post.php?action=edit&post=' . $new_post_id));
                exit;
            } else {
                wp_die('Post creation failed, could not duplicate the original post.');
            }
        }

        /**
         * Add the duplicate link to the action list for post_row_actions
         */
        public function addDuplicatePostLink($actions, $post) {
            if (current_user_can('edit_posts')) {
                $duplicate_url = wp_nonce_url(admin_url('admin.php?action=simple_post_duplicator_duplicate_post_as_draft&post=' . $post->ID), basename(__FILE__), 'duplicate_nonce');
                $actions['duplicate'] = '<a href="' . esc_url($duplicate_url) . '" title="Duplicate this item" rel="permalink">Duplicate</a>';
            }
            return $actions;
        }
    }

    // Instantiate the class
    new SimplePostDuplicator();
}

See the code on github…