[wp-trac] [WordPress Trac] #25538: WP_Query: OR relation breaks orderby meta_value

WordPress Trac noreply at wordpress.org
Sun Feb 9 20:15:05 UTC 2014


#25538: WP_Query: OR relation breaks orderby meta_value
------------------------------------------+------------------
 Reporter:  darrengrant                   |       Owner:
     Type:  defect (bug)                  |      Status:  new
 Priority:  normal                        |   Milestone:  3.9
Component:  Query                         |     Version:
 Severity:  major                         |  Resolution:
 Keywords:  needs-patch needs-unit-tests  |     Focuses:
------------------------------------------+------------------

Comment (by jackreichert):

 I figured out the problem. I'm net yet fluent with the inner workings of
 the WP_Query class, yet, to find where to fix the problem. I'll dig into
 that next, but I wanted to post my findings first so someone else can jump
 in if they know where.

 If you spit out both queries the first is:
 {{{
 SELECT SQL_CALC_FOUND_ROWS wp_posts.*
 FROM wp_posts
         INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
 WHERE 1=1
         AND wp_posts.post_type = 'post'
         AND (wp_posts.post_status = 'publish' OR wp_posts.post_status =
 'private')
         AND ( (wp_postmeta.meta_key = 'order'
         AND CAST(wp_postmeta.meta_value AS CHAR) >= '1') )
 GROUP BY wp_posts.ID
 ORDER BY wp_postmeta.meta_value DESC
 LIMIT 0, 10
 }}}

 The second is:
 {{{
 SELECT SQL_CALC_FOUND_ROWS wp_posts.*
 FROM wp_posts
         INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
         INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
 WHERE 1=1
         AND wp_posts.post_type = 'post'
         AND (wp_posts.post_status = 'publish' OR wp_posts.post_status =
 'private')
         AND ( (wp_postmeta.meta_key = 'order'
                 AND CAST(wp_postmeta.meta_value AS CHAR) >= '1')
                 OR (mt1.meta_key = 'order'
                 AND CAST(mt1.meta_value AS CHAR) >= '1') )
 GROUP BY wp_posts.ID
 ORDER BY wp_postmeta.meta_value DESC
 LIMIT 0, 10
 }}}

 In order to see what's happening I changed the select from wp_posts.* to
 *.

 When you do this it becomes clear what is happening. For efficiency sake
 I'll only show wp_posts.ID, wp_postmeta.*,  mt1.*.

 Here are the results:
 [[Image(http://www.jackreichert.com/asset/d3dc35aa/8f2175db.png/)]]

 As you can see. The OR comes out in the wrong place, so when it running
 the condition, it finds mt1 where meta_key = 'order' and doesn't care what
 meta_key the first joined table joins on. So we get wp_postmeta.meta_key =
 '_edit_last' in this case.

 The solution is, instead of the query condition being:
 {{{
 AND ( (wp_postmeta.meta_key = 'order'
                 AND CAST(wp_postmeta.meta_value AS CHAR) >= '1')
                 OR (mt1.meta_key = 'order'
                 AND CAST(mt1.meta_value AS CHAR) >= '1') )
 }}}

 it should be:
 {{{
         AND wp_postmeta.meta_key = 'order'
         AND mt1.meta_key = 'order'
         AND (CAST(wp_postmeta.meta_value AS CHAR) >= '1'
                 OR CAST(mt1.meta_value AS CHAR) >= '1')
 }}}

 Pulling the meta_key comparison out of the OR, so the meta_key in both HAS
 to equal 'order'; the condition should ONLY be applied to the meta_value
 condition.

--
Ticket URL: <https://core.trac.wordpress.org/ticket/25538#comment:3>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list