Hacking, Programming

WordPress Post Inserts Are Super Slow

Logging another one of my “weird wordpress problems” here.

We use a plugin called Buddypress Private Checklist to offer wedding to-do lists to our members on the Offbeat Bride Tribe. It was written many years ago by our old developer, and I’ve been vaguely maintaining it in our open source plugin repo on git. But it was a hack when it was written (old dev’s words, not mine!) and we’ve grown a lot over the years. It’s in need of a major upgrade, and the first item on my docket was the fact that it takes forever to load the initial default tasks into a to-do list.

The initial task loader takes a CSV full of default tasks and inserts them as posts into the Worpdress database. We have 124 tasks and it was taking five minutes. I expect a loop of 124 inserts to be a little slow, but five minutes is insane.

The posts, which are a custom post type, also use custom taxonomies to organize them. When I disabled the taxonomy inserts, done with wp_set_object_terms(), everything ran quickly. When I tried the plugin on a fresh install it ran quickly even with the taxonomy information. Disabling all plugins and going to the default theme didn’t change anything. I finally put together a test page that just looped through a bunch of post and taxonomy inserts, and watched it with Query Monitor.

After every new taxonomy term is inserted, wordpress runs wp_update_term_count(). On something the size of a personal blog this is not a big deal. On a community with 40,000 posts and 900 tags, this takes maybe half a second. Doing that 124 times takes forever. Thankfully there is a way to disable this excessive recounting, wp_defer_term_counting().

function insert_many_posts(){
  wp_defer_term_counting(true);
  $tasks = get_default_tasks(); 
  for ($tasks as $task){
     $post = array(
       'post_title' => $task[content],
       'post_author' => $current_user->ID,
       'post_content' => '',
       'post_type' => 'bpc_default_task',
       'post_status' => 'publish'
     );
     $task_id = wp_insert_post( $post );

     if ( $task[category] )
        //Make sure we're passing an int as the term so it isn't mistaken for a slug
        wp_set_object_terms( $task_id, array( intval( $category ) ), 'bpc_category' );
  }
}

Now the whole loop takes about 10 seconds. Hooray!

Leave a Reply

Your email address will not be published. Required fields are marked *