Skip to content
Open

#47642 #1762

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions src/wp-includes/class-wp-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -2331,6 +2331,41 @@ public function get_posts() {
} elseif ( 'none' === $q['orderby'] ) {
$orderby = '';
} else {
// https://core.trac.wordpress.org/ticket/47642
// Database engine fix to prevent strange (duplicate or missing) results in paginated resultsets
// Test for possible duplicate (non-unique, numeric or datetime) DB keys, add the unique ID
$force_ID = array(
'post_author',
'post_date',
'post_date_gmt',
'post_modified',
'post_modified',
'post_modified_gmt',
'post_parent',
'comment_count',
);
if ( is_array( $q['orderby'] ) ) {
$needs_ID = false;
$has_ID = false;
foreach ( $q['orderby'] as $_orderby => $order ) {
if ( in_array( $_orderby, $force_ID, true ) ) {
$needs_ID = true;
} else {
if ( 'ID' === $_orderby ) {
$has_ID = true;
break; // All done
}
}
}
if ( $needs_ID && ! $has_ID ) {
$q['orderby']['ID'] = 'ASC';
}
} else {
// Not an array, test as string
if ( in_array( $q['orderby'], $force_ID, true ) ) {
$q['orderby'] .= ' ID'; // Add ID here, note the space
}
}
$orderby_array = array();
if ( is_array( $q['orderby'] ) ) {
foreach ( $q['orderby'] as $_orderby => $order ) {
Expand Down Expand Up @@ -2371,21 +2406,23 @@ public function get_posts() {
// Order search results by relevance only when another "orderby" is not specified in the query.
if ( ! empty( $q['s'] ) ) {
$search_orderby = '';
if ( ! empty( $q['search_orderby_title'] ) && ( empty( $q['orderby'] ) && ! $this->is_feed ) || ( isset( $q['orderby'] ) && 'relevance' === $q['orderby'] ) ) {
if ( ( ! empty( $q['search_orderby_title'] ) && ( empty( $q['orderby'] ) && ! $this->is_feed ) ) || ( isset( $q['orderby'] ) && 'relevance' === $q['orderby'] ) ) {
$search_orderby = $this->parse_search_order( $q );
}

if ( ! $q['suppress_filters'] ) {
/**
* Filters the ORDER BY used when ordering search results.
*
*https://core.trac.wordpress.org/attachment/ticket/47642
* @since 3.7.0
*
* @param string $search_orderby The ORDER BY clause.
* @param WP_Query $query The current WP_Query instance.
*/
$search_orderby = apply_filters( 'posts_search_orderby', $search_orderby, $this );
}
//Add additional sort by order to break ties consistently for pagination https://core.trac.wordpress.org/ticket/47642
$orderby = $orderby ? $orderby . ', ID' : ' ID';

if ( $search_orderby ) {
$orderby = $orderby ? $search_orderby . ', ' . $orderby : $search_orderby;
Expand Down
59 changes: 59 additions & 0 deletions tests/phpunit/tests/query/orderby.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

/**
* Tests for query result ordering, specifically indeterminate ordering.
*
* @group query
*
* @covers WP_Query::posts
*/
class Tests_Query_Orderby extends WP_UnitTestCase {
function test_order_by_comment_count_does_not_cause_duplication_when_paginating() {
global $wpdb;

$posts = self::factory()->post->create_many( 5 );

$wpdb->update(
$wpdb->posts,
array(
'comment_count' => 50,
),
array(
'ID' => $posts[2],
)
);
$wpdb->update(
$wpdb->posts,
array(
'comment_count' => 100,
),
array(
'ID' => $posts[4],
)
);
$args = array(
'posts_per_page' => 1,
'paged' => 1,
'orderby' => 'comment_count',
'order' => 'desc',
);

$query = new WP_Query( $args );
$actual = array();
$expected = array(
$posts[4], // 100 comments
$posts[2], // 50 comments
$posts[3], // 0 comments
$posts[1], // 0 comments
$posts[0], // 0 comments
);

while ( $query->have_posts() ) {
$actual = array_merge( $actual, wp_list_pluck( $query->posts, 'ID' ) );
$args['paged']++;
$query = new WP_Query( $args );
}

$this->assertSame( $expected, $actual );
}
}