[wp-trac] [WordPress Trac] #57303: wp_get_posts() for post_type="any" + post__in creates not optimized database query

WordPress Trac noreply at wordpress.org
Fri Dec 9 20:42:21 UTC 2022


#57303: wp_get_posts() for post_type="any" + post__in creates not optimized
database query
-------------------------------+-----------------------------
 Reporter:  madeinua           |      Owner:  (none)
     Type:  enhancement        |     Status:  new
 Priority:  normal             |  Milestone:  Awaiting Review
Component:  Posts, Post Types  |    Version:  trunk
 Severity:  normal             |   Keywords:  has-patch
  Focuses:  performance        |
-------------------------------+-----------------------------
 Hi all.

 I have a case where the database query is not very optimal and (probably)
 needs to be improved.

 Case: I have a list of post ids that belong to several different post
 types. Now I need to get the WP_Post objects for this list of posts. So I
 do the following:

 {{{#!php
 <?php
 get_posts([
   'post_type' => 'any',
   'post__in' => [10,20,30,40,50]
 ]);
 }}}

 This code works well, however I have a lot of different post types (15+)
 on my site and as a result the database query looks like this:

 {{{
 SELECT wp_posts.*
 FROM wp_posts
 WHERE 1=1
 AND ((wp_posts.post_type = ? AND (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)) OR (wp_posts.post_type = ? AND
 (wp_posts.post_status = ?
 OR wp_posts.post_status = ?)))
 WHERE wp_posts.ID IN (?)
 GROUP BY wp_posts.ID
 ORDER BY FIELD(wp_posts.ID,?,?)
 }}}

 As you can see, it checks post_type + post_status for every public post
 type on my site. But the wp_get_posts() attributes explicitly declare a
 list of ids and that the post type can simply be ignored in this case
 (because the post_type is set to "any").

 The relevant query should be like this (because it covers all
 requirements):

 {{{
 SELECT wp_posts.*
 FROM wp_posts
 WHERE 1=1
 AND (wp_posts.post_status = ?)
 WHERE wp_posts.ID IN (?)
 GROUP BY wp_posts.ID
 ORDER BY FIELD(wp_posts.ID,?,?)
 }}}

 I checked class-wp-query.php and didn't find a solution without making
 changes to the WordPress code. There may already be a workaround
 implemented - it would be nice to know it. But this can be easily
 implemented by adding something like post_type="all" (similar to "any").
 The implementation of the idea has been added to the patch file
 (attached).

 Thanks in advance!

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/57303>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list