WordPress.org

Make WordPress Core

Opened 19 months ago

Last modified 19 months ago

#38442 new defect (bug)

Error when WP_Query parses orderby array in function parse_order

Reported by: oloynet Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 4.6.1
Component: Query Keywords: has-patch 2nd-opinion needs-unit-tests
Focuses: Cc:

Description

Example of query where I want to order by two custom fields in meta query start_date_order and is_sticky

<?php
$args = array(
    'no_found_rows'  => true ,
    'posts_per_page' => 4,
    'post_type'      => 'event',
    'post_status'    => 'publish',

    'meta_query' => array(
        'relation' => 'AND',
        array(
            'key'  => 'start_date_order',
            'type' => 'UNSIGNED',
        ),
        array(
            'key'  => 'is_sticky',
            'type' => 'UNSIGNED',
        ),
    ),
    'orderby' => array(
        'start_date_order' => 'DESC',
        'is_sticky'        => 'ASC',
    ),
);

$result_query = new WP_Query( $args );

echo $result_query->request;

The wrong SQL query generated is

SELECT wp_posts.ID
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_postmeta.meta_key = 'start_date_order'
    AND mt1.meta_key = 'is_sticky'
)
AND wp_posts.post_type = 'event'
AND ((wp_posts.post_status = 'publish'))
GROUP BY wp_posts.ID
ORDER BY CAST(wp_postmeta.meta_value AS UNSIGNED) DESC
LIMIT 0, 3

The '$primary_meta_query' var in method parse_order( $order ) is set forever with the first item of '$meta_clauses' array

see line 2336 /wp-includes/query.php

<?php
primary_meta_query = reset( $meta_clauses );

I quickly fix the problem with the following PHP code. Could use a native array function from PHP.

<?php
//$primary_meta_query = reset( $meta_clauses );

$primary_meta_query = array();
foreach( $meta_clauses as $meta_clause ) {
    if( $meta_clause['key'] == $orderby ) {
        $primary_meta_query = $meta_clause;
        break;
    }
}

Now the good SQL query is generated with two columns for ordering:

SELECT wp_posts.ID
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_postmeta.meta_key = 'start_date_order'
    AND mt1.meta_key = 'is_sticky'
)
AND wp_posts.post_type = 'event'
AND ((wp_posts.post_status = 'publish'))
GROUP BY wp_posts.ID
ORDER BY CAST(wp_postmeta.meta_value AS UNSIGNED) DESC, CAST(mt1.meta_value AS UNSIGNED) ASC
LIMIT 0, 3

Attachments (2)

patch-wp-query.txt (811 bytes) - added by oloynet 19 months ago.
38442.patch (913 bytes) - added by oloynet 19 months ago.
Patch for bur report 38442 with svn diff

Download all attachments as: .zip

Change History (7)

#1 @oloynet
19 months ago

The correct fix is

<?php
$primary_meta_query = false;
foreach( $meta_clauses as $meta_clause ) {
    if ( $meta_clause['key'] == $orderby ) {
        $primary_meta_query = $meta_clause;
        break;
    }
}
if( ! $primary_meta_query ) {
    $primary_meta_query = reset( $meta_clauses );
}

#2 @oloynet
19 months ago

  • Keywords has-patch 2nd-opinion added
  • Severity changed from normal to major

#3 @swissspidy
19 months ago

  • Component changed from Filesystem API to Query

#4 @swissspidy
19 months ago

  • Keywords needs-unit-tests added
  • Severity changed from major to normal

Hey there,

Thank you very much for your report and welcome to WordPress Trac! The change looks reasonable at first glance.

It would be nice to have unit tests showing this bug and how the patch resolves it. Also, the patch should ideally have a .patch or .diff extension and not contain any start patch and end patch comments.

Let me know if you're familiar with automated testing or not. I'm sure someone else might be able to step up here.

@oloynet
19 months ago

Patch for bur report 38442 with svn diff

#5 @oloynet
19 months ago

Hello,

I'm not a fluent user with unit tests on Wordpress. I've made a new patch with svn diff to do the job

Olivier

Note: See TracTickets for help on using tickets.