search ]

Duplicate Posts & Pages Without a Plugin

The action of duplicating posts can be very useful when working with many similar posts. For example – products in a WooCommerce store. It can be said that the option to duplicate posts is especially useful when your posts have custom fields of various kinds but different titles and content. This option will save you the need to re-enter the content into the meta fields, categories, and tags each time you create a page or post.

While wanderings, I came across a guide explaining how to duplicate pages and posts without a plugin in the WordPress Dashboard.

Excuse me for not linking to the original post, I do not have the link for it.

You can use such a plugin or another of course for this functionality, but why use a plugin when you can add the option with simple copy/paste? Here is an example of the result we will get:

Duplicate Posts & Pages Without a Plugin

When you click on duplicate, the post will be duplicated. It will not be published of course but will be duplicated as a draft and an automatic redirection to the editing page of the duplicated post in the WordPress Dashboard will occur.

How to duplicate pages and posts without a plugin?

Let’s not waste words, here is the code that needs to be added to the functions.php file:

/*
 * Function creates post duplicate as a draft and redirects then to the edit post screen
 */
function sv_duplicate_post_as_draft() {
	global $wpdb;
	if ( ! ( isset( $_GET['post'] ) || isset( $_POST['post'] ) || ( isset( $_REQUEST['action'] ) && 'sv_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_sv_duplicate_post_as_draft', 'sv_duplicate_post_as_draft' );

Next, add the following code also to the functions.php file:

/*
 * Add the duplicate link to action list for post_row_actions
 */
function sv_duplicate_post_link( $actions, $post ) {
	if (current_user_can('edit_posts')) {
		$actions['duplicate'] = 'Duplicate';
	}
	return $actions;
}

add_filter( 'post_row_actions', 'sv_duplicate_post_link', 10, 2 );

However, this code will work only for posts (Posts) and not for pages and custom post types. If you want this feature to work on pages (Pages) as well, for example, add another filter in the following manner:

add_filter( 'post_row_actions', 'sv_duplicate_post_link', 10, 2 );

 

Roee Yossef
Roee Yossef

I develop custom WordPress themes by design. I love typography, colors & everything between, and aim to provide high performance, seo optimized websites with a clean & semantic code.

0 Comments...

Leave a Comment

Add code using the buttons below. For example, to add PHP click the PHP button & add the code inside the shortcode. Typo? Please let us know...