Migrating from Post Meta to Custom Post Types

There are, as it happens, a lot of ways to do this. This is a way that I tested and it works, but it’s not the final way I did things. That said, this does work and, if you’re not on a shared server, is just fine.

The Concept

I have (roughly) 2200 posts in a custom post type (post_type_characters). Each of those posts has a post meta field for actors (lezchars_actor). The content of the post meta is an array of text fields, that looks something like this:

Array(
    [0] => "Caity Lotz",
    [1] => " Jacqueline MacInnes Wood (Arrow 1x01 only)"
)

I wanted to take the post meta and split it into a post for each actor, however I wanted to remove any comments in parenthesis. I also wanted to change the content of lezchars_actor to be the IDs of the new actors pages.

Did I mention I had 2200 posts? And some actors were there multiple times? And I didn’t want to make a lot of duplicate posts.

The Code

If you want to do this with PHP, it’ll look something like this:

<?php
/*
Plugin Name: Post Bulk Update
Description: Change all the actors to Taxonomy
*/

add_action('wp','post_bulk_update_queers');

function post_bulk_update_queers(){
	$char_queery = new WP_Query( array(
		'post_type'              => 'post_type_characters',
		'posts_per_page'         => '3000',
	) );

	if ( $char_queery->have_posts() ) {
		while ( $char_queery->have_posts() ) {
			$char_queery->the_post();
			$the_ID = get_the_ID();

			// Get the post meta for actor:
			$postmeta_actors = get_post_meta( $the_ID, 'lezchars_actor', true );
			if ( !is_array ( $postmeta_actors ) ) {
				$postmeta_actors = array( get_post_meta( $the_ID, 'lezchars_actor', true ) );
			}
			
			if ( !empty( $postmeta_actors ) ) {

				$posts_actors = array();
				// Create posts if needed:
				foreach ( $postmeta_actors as $actor ) {
					// Make sure the ID isn't numeric as that means we did this...
					if ( !is_numeric( $actor ) ) {

						// Remove content in parens...
						$actor = preg_replace( '/\([^)]+\)/', '', $actor );

						$already_post = get_page_by_path( sanitize_title( $actor ), OBJECT, 'post_type_actors' );
						if ( !( $already_post ) ) {
							// Create post object
							$my_post_args = array(
								'post_title'    => wp_strip_all_tags( $actor ),
								'post_status'   => 'publish',
								'post_author'   => 1,
								'post_type'     => 'post_type_actors',
							);
	
							// Insert the post into the database
							$my_post = wp_insert_post( $my_post_args );
							
							// add post to array
							array_push( $posts_actors, $my_post );
						} else {
							array_push( $posts_actors, $already_post->ID );
						}
					}
				}
				
				// Change the post meta to be numbers
				update_post_meta( $the_ID, 'lezchars_actor', $posts_actors );
			}
		}
	}
}

Notes

The reason this really works is this:

$already_post = get_page_by_path( sanitize_title( $actor ), OBJECT, 'post_type_actors' );

That actually checks if the page with the slug already exists and if so, uses it to edit the post meta.

If you don’t have robust hosting, or you have a lot of posts, you’ll need to edit the $char_queery like this:

	$char_queery = new WP_Query( array(
		'post_type'              => 'post_type_characters',
		'posts_per_page'         => '300',
		'offset'                 => '0',
	) );

Run it once, bump the offset from 0 to 300, and repeat until you get through all your posts.

One response to “Migrating from Post Meta to Custom Post Types”

  1. Richard Buff Avatar

    Great, simple solution. I wished I’d seen more articles like this, involving migrating data and working with large sets of posts and such, years ago.