How to Duplicate Posts and Pages Without Plugins

It is very useful when you work with a lot of similar posts. So, when you copy a post, you don’t have to enter all metadata, taxonomies etc. each time manually.

#noplugins, #wp-admin  /   195

Duplicating posts is a very useful functionality when you work with a lot of similar posts (for example products in online shop). Especially if the posts have the same custom fields values, but the different post title and content.

It means that you do not have to re-enter custom fields, post tags and categories each time.

This is the example:

Duplicate post link in post row actions.

When you click the «Duplicate» link, the post will be cloned, but it won't be published, it will be saved as a draft and you will be redirected to the post edit admin page.

This is enough easy to do, so, look at the following code, insert it into your theme functions.php file (or into the another file if you know what to do).

/*
 * Function creates post duplicate as a draft and redirects then to the edit post screen
 */
function rd_duplicate_post_as_draft(){
	global $wpdb;
	if (! ( isset( $_GET['post']) || isset( $_POST['post'])  || ( isset($_REQUEST['action']) && 'rd_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__ ) ) )
		return;
 
	/*
	 * get the original post id
	 */
	$post_id = (isset($_GET['post']) ? absint( $_GET['post'] ) : absint( $_POST['post'] ) );
	/*
	 * and all the original post data then
	 */
	$post = get_post( $post_id );
 
	/*
	 * if you don't want current user to be the new post author,
	 * then change next couple of lines 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) {
 
		/*
		 * new post data array
		 */
		$args = array(
			'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
		);
 
		/*
		 * insert the post by wp_insert_post() function
		 */
		$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); // returns array of taxonomy names for post type, ex array("category", "post_tag");
		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 all post meta just in two SQL queries
		 */
		$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);
		}
 
 
		/*
		 * finally, 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 find original post: ' . $post_id);
	}
}
add_action( 'admin_action_rd_duplicate_post_as_draft', 'rd_duplicate_post_as_draft' );
 
/*
 * Add the duplicate link to action list for post_row_actions
 */
function rd_duplicate_post_link( $actions, $post ) {
	if (current_user_can('edit_posts')) {
		$actions['duplicate'] = '<a href="' . wp_nonce_url('admin.php?action=rd_duplicate_post_as_draft&post=' . $post->ID, basename(__FILE__), 'duplicate_nonce' ) . '" title="Duplicate this item" rel="permalink">Duplicate</a>';
	}
	return $actions;
}
 
add_filter( 'post_row_actions', 'rd_duplicate_post_link', 10, 2 );

But what if this code works only for posts, not for pages or any registered post types? Do not worry, all we need to do is to change the last filter to this:

add_filter('page_row_actions', 'rd_duplicate_post_link', 10, 2);

For custom post types view this example in comments.
You can use several filters at the same time, of course.

Only the best of WordPress

Subscribe to this weekly newsletter to receive the latest blog posts by email.Your email is safe with me. Unsubscribe anytime.

Comments 195

← Older
  • Hello

    Is there option to duplicate one post n times. For example if I create one “template” post and I wish to duplicate it 200x? Can I do that in one step, I do not wish yo click on “duplicate” 200 times?

    Thank you.

  • Thanks that really help me for my portfolio plugin. Did not need to change much of the code

  • For custom post types view this example in comments…where? ;-)

  • Doesn’t work with pages.
    And what does it mean:

    Do not worry, all we need to do is to change the last filter to this:
    add_filter(‘page_row_actions’, ‘rd_duplicate_post_link’, 10, 2);

    In original code there’s the same line:
    add_filter(‘page_row_actions’, ‘rd_duplicate_post_link’, 10, 2);

    What’s changed?

  • hi, you keep referring to a comment here that doesnt exist. I dont understand why you would do this.

    its bad enough trying to learn and do these things without being given the code, it would take 5 mins to update the post, instead you are misleading people.

    if you can take the time please let all of us know the solution for custom (or any/ all ) post type please.

    thanks

    J

  • It’s ok sorted it out thanks mate.

  • Good tutorial for copy page because sometime it need to clone same layout from one page to another and it will very helpful for it and also able to copy page layout via making it duplicate thanks for informative article

  • really your are awesome man.Thanks for save many developeers time.

  • Shawn Rebelo May 16, 2018 at 23:45

    This is great! Thanks!

Leave your question or feedback

phpjsHTMLCSSSQLCode
Please, enter a comment
Please, enter a name
Incorrect email