fix(2meet-data-optimizer): keep meta_key native when the query still orders by it
- meta_key is routed as EXISTS only when no orderby entry names meta_value, meta_value_num or the key (several orderings or an array included); clearing it made WordPress drop the price ordering - A sort group is dropped as unused only when orderby names neither it, meta_value(_num) nor its key (it is then the primary clause) - meta_compare_key other than '=' keeps meta_key native (LIKE matches other keys) - Found in the 2.4 correctness review (regressions from PR-122) - Verify: PostQueryRouterTest (3 new), router suites 67 OK - PR: PR-130
This commit is contained in:
@@ -172,8 +172,11 @@ class TMDO_Post_Query_Router {
|
||||
|
||||
// meta_key + orderby meta_value(_num): native INNER JOINs the key
|
||||
// (EXISTS) and orders by meta_value+0 (NUMERIC) or meta_value.
|
||||
$meta_key = $query->get( 'meta_key' );
|
||||
$take_key = is_string( $meta_key ) && in_array( $sort_name, array( 'meta_value', 'meta_value_num' ), true )
|
||||
// A key comparison other than equality (meta_compare_key LIKE …) matches
|
||||
// other keys too: not a test on one flat column.
|
||||
$meta_key = $query->get( 'meta_key' );
|
||||
$key_exact = in_array( (string) $query->get( 'meta_compare_key' ), array( '', '=' ), true );
|
||||
$take_key = $key_exact && is_string( $meta_key ) && in_array( $sort_name, array( 'meta_value', 'meta_value_num' ), true )
|
||||
&& null !== self::field_for( array( 'key' => $meta_key ), $pt );
|
||||
if ( $take_key ) {
|
||||
$field = self::field_for( array( 'key' => $meta_key ), $pt );
|
||||
@@ -192,11 +195,13 @@ class TMDO_Post_Query_Router {
|
||||
$routed[ $pt ][] = $route;
|
||||
$sort = self::sort_for( $pt, $route, $direction );
|
||||
}
|
||||
// meta_key alone (no meta_value, not a meta_value sort): WP_Query adds a
|
||||
// clause that tests the key exists — HivePress's featured-listing lookup.
|
||||
$exists_key = ! $take_key && is_string( $meta_key ) && '' !== $meta_key
|
||||
// meta_key alone (no meta_value, not ordered by): WP_Query adds a clause
|
||||
// that tests the key exists — HivePress's featured-listing lookup. Any
|
||||
// orderby naming meta_value, meta_value_num or the key sorts by that
|
||||
// clause, which clearing meta_key would drop.
|
||||
$exists_key = ! $take_key && $key_exact && is_string( $meta_key ) && '' !== $meta_key
|
||||
&& '' === (string) $query->get( 'meta_value' ) && '' === (string) $query->get( 'meta_compare' )
|
||||
&& ! in_array( $sort_name, array( 'meta_value', 'meta_value_num' ), true )
|
||||
&& ! array_intersect( $named, array( 'meta_value', 'meta_value_num', $meta_key ) )
|
||||
&& null !== self::field_for( array( 'key' => $meta_key ), $pt );
|
||||
if ( $exists_key ) {
|
||||
$route = self::route_clause(
|
||||
@@ -220,8 +225,12 @@ class TMDO_Post_Query_Router {
|
||||
if ( ! isset( $clause['key'] ) ) {
|
||||
// Sort shape: matches every post, only orders by the key.
|
||||
$name = 'AND' === $relation ? self::sort_shape( $clause ) : '';
|
||||
if ( '' !== $name && ! in_array( $name, $named, true ) && self::field_for( $clause[ $name ], $pt ) ) {
|
||||
continue; // Matches every post and orders nothing here (a copy of a search's meta query).
|
||||
// Matches every post and orders nothing here (a copy of a search's meta
|
||||
// query) — unless orderby names it, or meta_value(_num) / its key, which
|
||||
// sort by it when it is WordPress's primary (first) clause.
|
||||
if ( '' !== $name && ! array_intersect( $named, array( $name, 'meta_value', 'meta_value_num', (string) ( $clause[ $name ]['key'] ?? '' ) ) )
|
||||
&& self::field_for( $clause[ $name ], $pt ) ) {
|
||||
continue;
|
||||
}
|
||||
$field = '' !== $name && $name === $sort_name ? self::field_for( $clause[ $name ], $pt ) : null;
|
||||
if ( $field ) {
|
||||
|
||||
@@ -471,6 +471,61 @@ class PostQueryRouterTest extends TestCase {
|
||||
$this->assertStringContainsString( 'BETWEEN', $where );
|
||||
}
|
||||
|
||||
/**
|
||||
* WordPress orders by the primary meta clause (meta_key) for meta_value,
|
||||
* meta_value_num or the key's name anywhere in orderby; routing the key and
|
||||
* clearing meta_key would drop that ordering (2.4 correctness review).
|
||||
*/
|
||||
public function test_meta_key_ordered_by_among_several_orderings_stays_native(): void {
|
||||
foreach ( array(
|
||||
array( 'meta_value_num' => 'ASC', 'title' => 'ASC' ),
|
||||
'meta_value date',
|
||||
'_stock',
|
||||
) as $orderby ) {
|
||||
$this->set_post_mode( 'aeav_only' );
|
||||
$query = $this->make_query( array( 'post_type' => 'product', 'meta_key' => '_stock', 'orderby' => $orderby ) );
|
||||
( new WPDO_Post_Query_Router() )->pre_get_posts( $query );
|
||||
|
||||
$label = is_array( $orderby ) ? implode( ',', array_keys( $orderby ) ) : $orderby;
|
||||
$this->assertSame( '_stock', $query->get( 'meta_key' ), $label );
|
||||
$this->assertSame( '', $query->get( 'wpdo_post_clauses' ), $label );
|
||||
}
|
||||
}
|
||||
|
||||
/** meta_compare_key LIKE matches other keys too: not a test on one flat column. */
|
||||
public function test_meta_key_with_a_key_comparison_stays_native(): void {
|
||||
foreach ( array( 'rand', 'meta_value_num' ) as $orderby ) {
|
||||
$this->set_post_mode( 'aeav_only' );
|
||||
$query = $this->make_query( array( 'post_type' => 'product', 'meta_key' => '_stock', 'meta_compare_key' => 'LIKE', 'orderby' => $orderby ) );
|
||||
( new WPDO_Post_Query_Router() )->pre_get_posts( $query );
|
||||
|
||||
$this->assertSame( '_stock', $query->get( 'meta_key' ), $orderby );
|
||||
$this->assertSame( '', $query->get( 'wpdo_post_clauses' ), $orderby );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Without meta_key the first clause is WordPress's primary one: orderby
|
||||
* meta_value_num sorts by the sort group's key, so the group stays.
|
||||
*/
|
||||
public function test_sort_group_ordered_as_the_primary_clause_is_not_dropped(): void {
|
||||
$this->assert_not_routed(
|
||||
array(
|
||||
'post_type' => 'product',
|
||||
'orderby' => 'meta_value_num',
|
||||
'meta_query' => array(
|
||||
array(
|
||||
'relation' => 'OR',
|
||||
'price__order' => array( 'key' => '_price', 'compare' => 'NOT EXISTS', 'type' => 'DECIMAL' ),
|
||||
array( 'key' => '_price', 'compare' => 'EXISTS', 'type' => 'DECIMAL' ),
|
||||
),
|
||||
array( 'key' => '_stock', 'value' => 1, 'compare' => '>=', 'type' => 'NUMERIC' ),
|
||||
),
|
||||
),
|
||||
'primary sort group'
|
||||
);
|
||||
}
|
||||
|
||||
public function test_meta_key_with_a_value_is_left_alone(): void {
|
||||
$this->set_post_mode( 'aeav_only' );
|
||||
$router = new WPDO_Post_Query_Router();
|
||||
|
||||
Reference in New Issue
Block a user