Skip to main content
Login Join
Snippet · PHP

Clone Any Post/Page as Draft

Shared by Darshit Rajyaguru · May 8, 2026 · @admin_action_*

37 views
1 upvote
Back to Snippets

Add a “Clone” action to posts and pages that instantly duplicates content, custom fields, taxonomies, and settings into a new draft. Perfect for developers, agencies, and content teams who frequently reuse layouts or landing pages.

add_filter( 'post_row_actions', 'wpf_duplicate_post_link', 10, 2 );
add_filter( 'page_row_actions', 'wpf_duplicate_post_link', 10, 2 );

function wp_duplicate_post_link( $actions, $post ) {
	if ( current_user_can( 'edit_posts' ) ) {
		$url = wp_nonce_url(
			admin_url( 'admin.php?action=wpfolks_duplicate_post&post=' . $post->ID ),
			'wpfolks_duplicate_post_' . $post->ID
		);
		$actions['duplicate'] = '<a href="' . esc_url( $url ) . '">Clone</a>';
	}
	return $actions;
}

add_action( 'admin_action_wpf_duplicate_post', 'wpfolks_duplicate_post' );
function wpf_duplicate_post() {
	if ( empty( $_GET['post'] ) ) {
		wp_die( 'No post to duplicate.' );
	}
	$post_id = absint( $_GET['post'] );
	check_admin_referer( 'wpfolks_duplicate_post_' . $post_id );
	$post = get_post( $post_id );
	if ( ! $post ) {
		wp_die( 'Post not found.' );
	}
	$new_post_id = wp_insert_post( array(
		'post_title'   => $post->post_title . ' (Copy)',
		'post_content' => $post->post_content,
		'post_status'  => 'draft',
		'post_type'    => $post->post_type,
		'post_excerpt' => $post->post_excerpt,
	) );
	$taxonomies = get_object_taxonomies( $post->post_type );
	foreach ( $taxonomies as $taxonomy ) {
		$terms = wp_get_object_terms( $post_id, $taxonomy, array(
			'fields' => 'ids',
		) );
		wp_set_object_terms( $new_post_id, $terms, $taxonomy );
	}
	$meta = get_post_meta( $post_id );
	foreach ( $meta as $key => $values ) {
		if ( '_wp_old_slug' === $key ) {
			continue;
		}
		foreach ( $values as $value ) {
			add_post_meta( $new_post_id, $key, maybe_unserialize( $value ) );
		}
	}
	wp_safe_redirect(
		admin_url( 'post.php?action=edit&post=' . $new_post_id )
	);
	exit;
}
Know a different way to do this? Add your approach as a variation so folks can compare them side by side.
Submit a variation

0 comments