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:
2026-09-28 00:27:56 +08:00
parent 7ad65eab95
commit bed3f906da
2 changed files with 72 additions and 8 deletions
@@ -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 ) {