0

I need to query a lot of posts at once. A lot and performance is more than crucial here - things moving slow will net me bad reviews, a lot of them, but cutting a bit through WP's overhead could net me a way faster result, with a trade-off.

To cut a long story short, here's my final code that moves fast and I mean, boy it does, the memory footprint is also minimal, but there's no overhead on it, that means, there's no actions firing that would normally fire when calling wp_update_post:

$posts_to_hide = new \WP_Query([
    'post_type' => 'post',
    'fields' => 'ids',
    'posts_per_page' => '-1',
]);

global $wpdb;

while ( $next_posts = array_splice( $posts_to_hide->posts, 0, 10 ) ) {
    foreach( $next_posts as $index => $id ) {
        $wpdb->query( "UPDATE $wpdb->posts SET post_status='draft' WHERE ID=$id");
    }
}

Where I'm updating the post's status, you would normally do:

foreach( $next_posts as $index => $id ) {
    wp_update_post( ['ID' => $id, 'post_status' => 'draft' ] );
}

But this moves magnitudes slower, as it should be.

Thing is, my environment (even if it'll be deployed to thousands of sites) is quite special and highly controlled - these posts are created by me and these posts don't need outside forces to "prettify" them, but if it happens, that's completely ok, so they're ready to take a punch without ruining the experience.

**I will never query any other posts than what my plugin has put in (my WP_Query is more complex where it returns only posts that my plugin has created). Period. These posts, given the scope of my plugin don't need these modifications / improvements that other plugins give, for example, an SEO plugin might change my titles / structures, while that is not necessary, if it happens, this function from above will run right after my plugin inserts these posts into the system, as such, there's no race-condition -- posts get imported, this runs, no two ways around it. To add more, the posts are "mock posts" and the customer understands that perfectly.

As such, is it ok for me to skip all the hooks that WP provides given my situation?


I'm specifically talking about missing the actions provided by wp_insert_post which is used by wp_update_post. Any plugin / functionality that hooks into these will not see my posts being updated.

  • You could probably roll all of those queries into a single query – Tom J Nowell Dec 17 '18 at 2:15
  • @TomJNowell I did, but the question is: given my edge case, is it ok to skip the hooks provided by wp_update_post and so on? Remember that I use the WXR Importer, which uses these said functions. In 90/100 of the cases or even more, whoever uses this functionality of my plugin has a fresh website without any interferring plugins, still, I'd like to do a good job. – coolpasta Dec 17 '18 at 9:32
  • the only way to know for sure is to test it. This is one of those questions where you might say "is it a yes or a no", and the only answer is "it depends". Taken in isolation, "maybe"? Is this literally stock WP? Which plugins do you have installed? What hooks do they use? Is this a one time operation? Will you be able to inspect the result or is this an automation that happens at regular intervals? – Tom J Nowell Dec 17 '18 at 21:03
  • Additionally, you set posts_per_page to -1 which is never a good idea, you should use pagination combined with a do while loop. Additionally, by using $query->posts you're immediatley instantiating every single post object all at once, whereas if you did a standard post loop with the query object, it would instantiate them as it went along, which would be more efficient, and allow you to clean up memory as you looped. This is ignoring your question of course, but these are still genuine concerns, especially where scaling to larger numbers of posts is concerned – Tom J Nowell Dec 17 '18 at 21:05
  • Also, your code as described in the question could literally be a single query, UPDATE $wpdb->posts SET post_status='draft' WHERE post_type="post", which would be significantly faster than what you have, and reduce it to a single query – Tom J Nowell Dec 17 '18 at 21:07
1

The idea of directly modifying the database using $wpdb is not what you should worry about, it's what wp_update_post() does that you should be considering. This function internally uses the $wpdb to update the post, and if you know what you're doing, then do it.

But...

Many plugins can hook into the actions that are triggered once this function is used.

For example, cache plugins decide whether to clear the cache of the archive or not, once the post's status has been change to draft, which should no longer be shown in the archive.

So if you are sure there's nothing hooked into that function, and nothing ever will ( which is odd ), then you can use SQL to do so.

Other factors can be taken into consideration too, such as in case of rare changes being applied to database structures ( well, we just had the WYSIWYG editor replace with Gutenberg so quickly, so this might happen too ). In case of such event, the built-in functions will be updated automatically, while your code won't and will most likely cause issues.

  • Lucky for me, before I do these operations, WordPress' WXR Importer does a wp_insert_post for me. That's what I'm using. My plugin here, altough I worded it differently in my question only sees to look at these posts and update their status. There was an initial hook that plugins could've used to set internal datas and modify my posts (in case of SEO plugins or such), but now it's not needed anymore. While I acknowledge there could be conflicts with posts being displayed in lists as "open" while really they're drafted, the chances are slim. What do you think? – coolpasta Dec 17 '18 at 1:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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