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.


Comments
One response to “Migrating from Post Meta to Custom Post Types”
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.