I need to change several hundred posts with custom post types to regular post type but only from one category within that custom post type.

So I have a custom post type 'films' and within that post type I have a couple dozen categories. What I would like to do is change all posts from custom post type 'films' that also have the category 'directors' to the standard post type without affecting other 'film' posts that do not have the category 'directors'.

I've searched around and have found a way to successfully change all posts within a post type using the query below but I need to be more specific.

UPDATE  `wp_posts` 
SET  `post_type` =  '<new post type name>' 
WHERE  `post_type` = '<old post type name>';

I've also tried using plugins such as 'Convert Post Types' but unfortunately they do not pull in categories from custom post types.

I've read a good deal of documentation on this but I'm totally new to this kind of work so I'm having a hard time wrapping my head around some of the syntax.

1 Answer 1


I would do it in php in two parts rather than one big raw sql statement, for safety reasons, eg in your "functions.php" put:

function wpse160706() {
    $old_post_type = 'films';
    $new_post_type = 'post';
    $category_slug = 'directors';
    $taxonomy = 'category';

    global $wpdb;
    $sql = $wpdb->prepare( 'SELECT p.ID FROM ' . $wpdb->posts . ' AS p'
        . ' JOIN ' . $wpdb->term_relationships . ' AS tr ON p.ID = tr.object_id'
        . ' JOIN ' . $wpdb->term_taxonomy . ' AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id'
        . ' JOIN ' . $wpdb->terms . ' AS t ON tt.term_id = t.term_id'
        . ' WHERE p.post_type = %s AND t.slug = %s AND tt.taxonomy = %s'
        , $old_post_type, $category_slug, $taxonomy );
    $post_ids = $wpdb->get_col( $sql );
    print("post_ids=" . implode( ',', $post_ids));
    foreach ( $post_ids as $post_id ) {
        $sql = $wpdb->prepare( 'UPDATE ' . $wpdb->posts
            . ' SET post_type = %s WHERE ID = %d AND post_type = %s'
            , $new_post_type, $post_id, $old_post_type );
        // Uncomment the following if happy that $post_ids correct.
        //$wpdb->query( $sql );

then call it and make sure you're only getting the posts you want, then backup your database etc and uncomment the update query, run once and then remove the wpse160706() call.

  • I gave this a shot but didn't see any results. I might not be calling it correctly. I just used <?php echo wpse160706(); ?> on one of my pages. The categories where not echoed but I could see them in my console. What was displayed in my console only included categories from my 'post' type and not my custom 'films' post type.
    – Kristopher
    Sep 9, 2014 at 23:56
  • Ok this was outputting to your php error.log which you may not have set up, I'll change it to output to the screen (error_log -> print) ... (not sure what you mean by "console" btw)
    – bonger
    Sep 10, 2014 at 4:58
  • I tried (error_log -> print) but it just gave me a white screen. I'm sorry you have to spell this out for me. By console I just meant console in my my web inspector.
    – Kristopher
    Sep 10, 2014 at 19:18
  • Ok the browser console will only show javascript messages. Did you check the updated line in the answer? I meant substitute the call to error_log("post_ids=" . implode( ',', $post_ids)) with print("post_ids=" . implode( ',', $post_ids)) instead so it just prints out all the ids to the screen rather than to the log file
    – bonger
    Sep 10, 2014 at 21:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.