Here is a small thing that catches almost everyone the first time, and it is not really their fault, because the advice that ranks sets them up for it.
You want a copy of a post or page. Maybe a template for the next one, maybe an A/B variant of a landing page, maybe a backup before a big edit. WordPress has no duplicate button, so the standard advice is: open the editor, select all blocks, copy, paste into a new page.
You do that, and the copy arrives hollow. No featured image. No categories or tags. No SEO title or description. And if the page was built with Elementor, no page. The paste is blank.
Every tutorial that recommends copy-paste admits this in a footnote, "you will need to re-add the featured image and SEO settings manually." None of them explain why. Let me explain why, because once you see it you will never be confused by it again.
What a WordPress post actually is
A post is three kinds of database records working together.
- The posts-table row. Title, content, excerpt, status, type. This is the only part the editor shows you and the only part a paste moves.
-
Postmeta rows. One row per setting, keyed to the post ID. See
get_post_meta()for how WordPress reads them. - Taxonomy relationships. Categories, tags and custom taxonomies are term records linked to the post. They are not stored in the post at all.
Where the "lost" data lives
Everything the paste dropped is record type 2 or 3:
_thumbnail_id = 42 // the featured image is postmeta
_yoast_wpseo_title = "..." // SEO title: postmeta
_yoast_wpseo_metadesc = "..." // meta description: postmeta
_elementor_data = "[{...}]" // the ENTIRE Elementor layout, JSON in postmeta
The _elementor_data one is the fact worth keeping. On an Elementor page, post_content is nearly empty, a fallback render at best. The real design is serialized JSON in postmeta. So when you copy "the content" of an Elementor page, you are copying the one field that does not contain the page. That is why the paste lands blank.
Categories are the same story from the other side. They are relationships between the post and term records, so a brand-new pasted post has no relationships until you rebuild them by hand.
This is the core of it: duplicating a post is not copying text, it is copying a row, a stack of meta, and a set of term links. Copy-paste does the first part only.
Doing it correctly in code
If you script it, the shape is three passes, one per record type:
$src = get_post($post_id);
// Pass 1: the row
$new_id = wp_insert_post([
'post_title' => $src->post_title . ' (Copy)',
'post_content' => $src->post_content,
'post_type' => $src->post_type,
'post_status' => 'draft', // draft on purpose, see below
]);
// Pass 2: every meta, the part paste never does
foreach (get_post_meta($post_id) as $key => $values) {
foreach ($values as $value) {
add_post_meta($new_id, $key, maybe_unserialize($value));
}
}
// Pass 3: the term links
foreach (get_object_taxonomies($src->post_type) as $tax) {
$terms = wp_get_object_terms($post_id, $tax, ['fields' => 'ids']);
wp_set_object_terms($new_id, $terms, $tax);
}
See wp_insert_post() for the first pass. And a warning on pass 2: serialized builder meta like _elementor_data is where hand-rolled duplicators break, the JSON needs correct unserializing and slashing or the clone's layout corrupts. It is the fiddliest part of the whole job, which is exactly why a maintained one-click tool beats a snippet here.
Gotcha one: the clone is an SEO twin until you edit it
A correct clone copies the SEO meta too, slug base, title, description. Which means until you change those, you have two pages targeting one query. Publish both and you have built keyword cannibalization by hand. This is why the clone should be created as a draft and stay one while you rewrite the slug, title and meta.
Gotcha two: WooCommerce already has this, for one post type
WooCommerce ships a Duplicate action for products, because stores clone configured products constantly. But it is products only. Posts, pages and custom post types are on their own.
The settings-panel version
I did this run with WP Adminify's Productivity module, which covers every post type from one place. 30 second demo below.
What changed after enabling Post Duplicator in Adminify > Productivity:
- An Adminify Clone action appeared in the row actions of Posts, Pages and custom post types, next to Edit and Quick Edit, no code to add it
- One click produced a
(Copy)with the content, featured image, categories and settings intact, which is the exact part copy-paste drops - It works on custom post types too, which is where the free single-purpose plugins tend to get fussy
- It sits alongside the rest of the same module, including the one-click menu duplication feature, same idea applied to navigation menus, and the wider Productivity toolset
- Pair it with the Admin Columns Editor if you clone a lot, a custom column showing modified dates keeps originals and copies easy to tell apart, and Activity Logs records who cloned what on multi-author sites
The caveat I will not skip: a clone is a snapshot, not a live mirror, and it inherits everything, including stale meta you forgot was on the original. Clone posts you trust, keep the copy draft, fix the slug and meta, then publish.
Feature page: Duplicate any WordPress post type with WP Adminify
So: do you duplicate with a tool, script the three-pass copy yourself, or copy-paste and rebuild the settings every time?
Top comments (0)