Bulk Move Content from One WordPress Post Type to Another (Given Some Relationship)

CAUTION! The following involves a ton of database manipulation. Even a small typo could destroy your entire WordPress’ install worth of content. ABSOLUTELY make a backup of your database before you proceed.

Maybe you’ve got a bunch of content in a specific post_type in WordPress. Maybe you’ve got a bunch of content in another post type with the exact same slugs. Or with some type of matching content (the same meta data, for example.)

Now, let’s say you want to move everything from Post Type 1 to Post Type 2. You can use the code to do so. This code will specifically move only the post_content, ie, what you type into the main content editor.

The code below could be manipulated to pull in any other data, not just the post content, or to associate the posts in a different way, say exact custom fields.

Why would I ever need this?

I recently had a project where a previous developer was creating a photo gallery site, where the photos could also be sold as Woocommerce products. The Photos’ content was in a post type by the name of photos and we needed to consolidate those into one: the Woocommerce product post type. So, I came up with the following:

<?php if (is_page('your-test-page-slug')) { // So that the code doesn't run on any page you load ?>

<?php $how_many = -1; // this will get ALL of the original post_type's post, if you have too many, you may time out your server
$offset = 0; // you could set this if your $how_many variable is set to a positive number instead of -1
$args = array(
'posts_per_page' => $how_many,
'post_type' => 'photos', // change this to whatever your original post type's name is
'offset' => $offset // you can remove this line if you're $how_many variable is set to -1
$the_query = new WP_Query( $args ); // here we do a WP Query for all of the original post_type posts.
if ($the_query->have_posts()) {
while ( $the_query->have_posts() ) :

// get the old POST_TYPE's content
$content_check = get_the_content();

// if not content CONTINUE
if (empty($content_check)) { continue; } // if the old one has no post_content, skip it

// check for a new POST_TYPE posts with the same slug
$this_photos_slug = get_post_field( 'post_name', get_post() ); // this will get the "slug" of the original post type, so we can match it later
$the_product_slug = $this_photos_slug;
$args2 = array( // now we check against the new post_type to see if there's a post with the same slug
'name' => $the_product_slug,
'post_type' => 'product', // change this to whatever your new post_type is
'numberposts' => 1 // leave this at 1!
$corresponding_product = get_posts($args2);
if( $corresponding_product ) :
$the_product_id = $corresponding_product[0]->ID;

$new_product_data = array(
'ID' => $the_product_id,
'post_content' => $content_check

// Update the new POST_TYPE's content with the old POST_TYPE's data
wp_update_post( $new_product_data, true );
if (is_wp_error($corresponding_product[0]->ID)) {
$errors = $post_id->get_error_messages();
foreach ($errors as $error) {
echo $error;
$clear_photo_content = array(
'ID' => get_the_ID(),
'post_content' => ''
// Remove the content from the old POST_TYPE (optional
wp_update_post( $clear_photo_content, true ); ?>

} ?>

Up Next: How to Clear HTML Lists Next to a Left-aligned Image