How to Duplicate a WordPress Page or Post with a single click?

In this short post I’m going to show you how to duplicate a WordPress page or post with a single click. Not only is the method really simple, but it will copy all the meta date your post may have (custom fields, featured image etc.)

Video: How to Duplicate a WordPress Page or Post without a plugin?

Where to add the code?

Add a snippet shown here below to your child theme’s functions.php file or better yet, use a snippet manager like Code Snippets or WpCodeBox (my favorite).

WpCodeBox is my favorite code snippets manager for WordPress. This is a premium plugin and if you’re interested, then grab WPCodeBox with a nice 20% discount here (SAVE 20% Coupon WPSH20).

How to Duplicate a WordPress Page or Post with a single click?

Next, just grab the code here below and it will add a “Duplicate” link inside your quick links. See the screenshot.

How to Duplicate a WordPress Page or Post with a single click

If you click this link then:

  • Duplicate of the post will be created
  • Status of the post is “Draft”
  • You will be redirected to the post editing page

So, in order to make it work, just use this code here below.

<span role="button" tabindex="0" data-code="// Duplicate a WordPress Page or Post with a Single Click

add_filter("post_row_actions", "wpsh_add_duplicate_link", 10, 2);
add_filter("page_row_actions", "wpsh_add_duplicate_link", 10, 2); // add the link to pages too

function wpsh_duplicate_post_as_draft()
{
if (!current_user_can("edit_posts")) {
return;
}
if (
!isset($_GET["duplicate_nonce"]) ||
!wp_verify_nonce($_GET["duplicate_nonce"], basename(__FILE__))
) {
return;
}
global $wpdb;
if (
!(
isset($_GET["post"]) ||
isset($_POST["post"]) ||
(isset($_REQUEST["action"]) &&
"wpsh_duplicate_post_as_draft" == $_REQUEST["action"])
)
) {
wp_die("No post to duplicate has been supplied!");
}
// This on here gets the original post id and post all the original post data
$post_id = isset($_GET["post"])
? absint($_GET["post"])
: absint($_POST["post"]);
$post = get_post($post_id);

// In case you don't want current user to be the new post author, then change this line to this: $new_post_author = $post->post_author;
$current_user = wp_get_current_user();
$new_post_author = $current_user->ID;

// If post data exists, create the post duplicate

if (isset($post) && $post != null) {

$args = [
"comment_status" => $post->comment_status,
"ping_status" => $post->ping_status,
"post_author" => $new_post_author,
"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,
];

$new_post_id = wp_insert_post($args);

// Get all current post terms ad set them to the new post draft

$taxonomies = get_object_taxonomies($post->post_type);
foreach ($taxonomies as $taxonomy) {
$post_terms = wp_get_object_terms($post_id, $taxonomy, [
"fields" => "slugs",
]);
wp_set_object_terms($new_post_id, $post_terms, $taxonomy, false);
}

// Duplicate all post meta

$post_meta_infos = $wpdb->get_results(
"SELECT meta_key, meta_value FROM $wpdb->postmeta WHERE post_id=$post_id"
);
if (count($post_meta_infos) != 0) {
$sql_query = "INSERT INTO $wpdb->postmeta (post_id, meta_key, meta_value) ";
foreach ($post_meta_infos as $meta_info) {
$meta_key = $meta_info->meta_key;
if ($meta_key == "_wp_old_slug") {
continue;
}
$meta_value = addslashes($meta_info->meta_value);
$sql_query_sel[] = "SELECT $new_post_id, '$meta_key', '$meta_value'";
}
$sql_query .= implode(" UNION ALL ", $sql_query_sel);
$wpdb->query($sql_query);
}

// Redirect to the edit post screen for the new draft
wp_safe_redirect(
admin_url("post.php?action=edit&post=" . $new_post_id)
);
exit();
} else {
wp_die(
"Post creation failed, could not find original post: " . $post_id
);
}
}
add_action(
"admin_action_wpsh_duplicate_post_as_draft",
"wpsh_duplicate_post_as_draft"
);

// Add the "Duplicate" link to action list for post_row_actions

function wpsh_add_duplicate_link($actions, $post)
{
if (current_user_can("edit_posts")) {
$actions["duplicate"] =
'<a href="' .
wp_nonce_url(
"admin.php?action=wpsh_duplicate_post_as_draft&post=" . $post->ID,
basename(__FILE__),
"duplicate_nonce"
) .
'" title="Duplicate this item" rel="permalink">Duplicate

// Duplicate a WordPress Page or Post with a Single Click

add_filter("post_row_actions", "wpsh_add_duplicate_link", 10, 2);
add_filter("page_row_actions", "wpsh_add_duplicate_link", 10, 2); // add the link to pages too

function wpsh_duplicate_post_as_draft()
{
    if (!current_user_can("edit_posts")) {
        return;
    }
    if (
        !isset($_GET["duplicate_nonce"]) ||
        !wp_verify_nonce($_GET["duplicate_nonce"], basename(__FILE__))
    ) {
        return;
    }
    global $wpdb; 
    if (
        !(
            isset($_GET["post"]) ||
            isset($_POST["post"]) ||
            (isset($_REQUEST["action"]) &&
                "wpsh_duplicate_post_as_draft" == $_REQUEST["action"])
        )
    ) {
        wp_die("No post to duplicate has been supplied!");
    }
    // This on here gets the original post id and post all the original post data
    $post_id = isset($_GET["post"])
        ? absint($_GET["post"])
        : absint($_POST["post"]);
   		 $post = get_post($post_id);
  
  // In case you don't want current user to be the new post author, then change this line to this: $new_post_author = $post->post_author;
    $current_user = wp_get_current_user();
    $new_post_author = $current_user->ID; 

    // If post data exists, create the post duplicate

    if (isset($post) && $post != null) {

        $args = [
            "comment_status" => $post->comment_status,
            "ping_status" => $post->ping_status,
            "post_author" => $new_post_author,
            "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,
        ];

        $new_post_id = wp_insert_post($args);

        // Get all current post terms ad set them to the new post draft

        $taxonomies = get_object_taxonomies($post->post_type); 
        foreach ($taxonomies as $taxonomy) {
            $post_terms = wp_get_object_terms($post_id, $taxonomy, [
                "fields" => "slugs",
            ]);
            wp_set_object_terms($new_post_id, $post_terms, $taxonomy, false);
        }

        // Duplicate all post meta
        
        $post_meta_infos = $wpdb->get_results(
            "SELECT meta_key, meta_value FROM $wpdb->postmeta WHERE post_id=$post_id"
        );
        if (count($post_meta_infos) != 0) {
            $sql_query = "INSERT INTO $wpdb->postmeta (post_id, meta_key, meta_value) ";
            foreach ($post_meta_infos as $meta_info) {
                $meta_key = $meta_info->meta_key;
                if ($meta_key == "_wp_old_slug") {
                    continue;
                }
                $meta_value = addslashes($meta_info->meta_value);
                $sql_query_sel[] = "SELECT $new_post_id, '$meta_key', '$meta_value'";
            }
            $sql_query .= implode(" UNION ALL ", $sql_query_sel);
            $wpdb->query($sql_query);
        }

        // Redirect to the edit post screen for the new draft
        wp_safe_redirect(
            admin_url("post.php?action=edit&post=" . $new_post_id)
        ); 
        exit();
    } else {
        wp_die(
            "Post creation failed, could not find original post: " . $post_id
        );
    }
}
add_action(
    "admin_action_wpsh_duplicate_post_as_draft",
    "wpsh_duplicate_post_as_draft"
);

// Add the "Duplicate" link to action list for post_row_actions

function wpsh_add_duplicate_link($actions, $post)
{
    if (current_user_can("edit_posts")) {
        $actions["duplicate"] =
            '<a href="' .
            wp_nonce_url(
                "admin.php?action=wpsh_duplicate_post_as_draft&post=" . $post->ID,
                basename(__FILE__),
                "duplicate_nonce"
            ) .
            '" title="Duplicate this item" rel="permalink">Duplicate</a>';
    }
    return $actions;
}

After adding the code just go tou your post, pager or custom post types and press on a “Duplicate” link and you have a nice clone of your site with the status “Draft”.

How to Duplicate a WordPress Page or Post with a plugin?

In case the previous method seems difficult for you, then you also have another option. That is, you can duplicate a WordPress page or post with the help of a plugin.

  1. Install a plugin called “Yoast Duplicate post”.
  2. Next go to Settings >> Duplicate post and take a look at the settings (screenshot below)
  3. When everything is set up just go to the pages or posts and use “Clone” link

Related WordPress hacks

  • How to Hide WordPress Admin Notifications

  • How to create custom fields in WordPress without a plugin?

  • How to Display Woocommerce Payment Methods Conditionally? (14 hacks)

  • How to Customize Woocommerce Stock Status? (17 hacks)

  • How to Add Custom Endpoints in WooCommerce?

  • How to add and clone user roles in WordPress?

  • How to restore WordPress classic widgets?

  • How to Add Custom Admin Menu Items in WordPress?

  • How to Remove WordPress Admin Menu Items for Specific User Roles?

  • How to Clean & Remove Divi Shortcodes When Changing Your Theme?

  • How to Create Custom WordPress Admin Dashboard for your customers?

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top