Slow and laggy post creation time on WordPress

Pasan Gamage
3 min readJun 7, 2021

--

Today I received a ticket to look into an issue on a WP website where the post creation has become progressively slow. The wp_insert_post() is triggered as a response to an API request and what started as a 1 sec response ended up becoming 20sec.

Eliminating the obvious

I started to debug by eliminating each line on that particular API endpoint till I found that it waswp_insert_post() that's taking a longer execution time.

Therefore, I tried simplifying the argument list passed into the wp_insert_post function and kept on validating the response time. I kept on trimming down the arg list until it was no more than post_title, post_status, post_type. But still there was no change in response time.

Using Query Monitor plugin is highly recommended as it helped to trace the issue with slow response and any other PHP warning.

Debugger to the rescue

I finally decided to step in to the wp_insert_post() on wordpress/wp-includes/post.php and traverse line by line to determine the code which consume a lot of time. And there it was;

Culprit

It turned out the code segment which tries to determine a unique slug takes the most of the time.

The reason being, I was setting a generic post_title value to the posts that were getting created via the API and at the moment when the slow response got worse there were 1 million posts in the database.

If you have a look on wordpress/wp-includes/post.php line 4737–4757, WP loops through all the posts in the db to determine the suffix that could be added to the new post. And it just keeps on looping through all the posts only to find that there are so many posts with the same titles as “Created through API” while the user sits and waits to hear back from the API.

// line 4737–4757
$is_bad_hierarchical_slug = apply_filters( 'wp_unique_post_slug_is_bad_hierarchical_slug', false, $slug, $post_type, $post_parent );

if ( $post_name_check
|| in_array( $slug, $feeds, true ) || 'embed' === $slug
|| preg_match( "@^($wp_rewrite->pagination_base)?\d+$@", $slug )
|| $is_bad_hierarchical_slug
) {
$suffix = 2;
do {
$alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_ID, $post_parent ) );
$suffix++;
} while ( $post_name_check );
$slug = $alt_post_name;
}
} else {
// Post slugs must be unique across all posts.
$check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d LIMIT 1";
$post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID ) );

The Fix

In order to fix the issue I used uniqid() PHP function where it generates a prefixed unique identifier based on the current time in microseconds.

The solution is simple as

'post_title' => 'Created through API' . uniqid(' ', TRUE),

This code helped to bring down the response time by 19400 milliseconds

Conclusion

If you are dealing with large content based WP sites, be aware when using matching titles. Maybe there are plugins that helps to generate unique slugs. But on my scenario where everything is API based I went with the above solution.

Let me know if you have run in to any weird WP issues.

--

--

Pasan Gamage
Pasan Gamage

Written by Pasan Gamage

Backend Developer | Motorbike enthusiast

No responses yet