hardening 2.4: 2meet-data-optimizer 1.4.0 (index-ordered routed sorts, date copy route, count invalidation) #8
@@ -191,6 +191,25 @@ class TMDO_Post_Query_Router {
|
|||||||
$routed[ $pt ][] = $route;
|
$routed[ $pt ][] = $route;
|
||||||
$sort = self::sort_for( $pt, $route, $direction );
|
$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
|
||||||
|
&& '' === (string) $query->get( 'meta_value' ) && '' === (string) $query->get( 'meta_compare' )
|
||||||
|
&& ! in_array( $sort_name, array( 'meta_value', 'meta_value_num' ), true )
|
||||||
|
&& null !== self::field_for( array( 'key' => $meta_key ), $pt );
|
||||||
|
if ( $exists_key ) {
|
||||||
|
$route = self::route_clause(
|
||||||
|
array(
|
||||||
|
'key' => $meta_key,
|
||||||
|
'compare' => 'EXISTS',
|
||||||
|
),
|
||||||
|
self::field_for( array( 'key' => $meta_key ), $pt )
|
||||||
|
);
|
||||||
|
if ( ! $route ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$routed[ $pt ][] = $route;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ( $raw_meta_query as $k => $clause ) {
|
foreach ( $raw_meta_query as $k => $clause ) {
|
||||||
if ( 'relation' === $k || ! is_array( $clause ) ) {
|
if ( 'relation' === $k || ! is_array( $clause ) ) {
|
||||||
@@ -199,7 +218,10 @@ class TMDO_Post_Query_Router {
|
|||||||
}
|
}
|
||||||
if ( ! isset( $clause['key'] ) ) {
|
if ( ! isset( $clause['key'] ) ) {
|
||||||
// Sort shape: matches every post, only orders by the key.
|
// Sort shape: matches every post, only orders by the key.
|
||||||
$name = 'AND' === $relation ? self::sort_shape( $clause ) : '';
|
$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).
|
||||||
|
}
|
||||||
$field = '' !== $name && $name === $sort_name ? self::field_for( $clause[ $name ], $pt ) : null;
|
$field = '' !== $name && $name === $sort_name ? self::field_for( $clause[ $name ], $pt ) : null;
|
||||||
if ( $field ) {
|
if ( $field ) {
|
||||||
$route = self::route_clause( array( 'compare' => 'EXISTS' ) + $clause[ $name ], $field );
|
$route = self::route_clause( array( 'compare' => 'EXISTS' ) + $clause[ $name ], $field );
|
||||||
@@ -239,7 +261,7 @@ class TMDO_Post_Query_Router {
|
|||||||
if ( empty( $routed ) && empty( $sort ) ) {
|
if ( empty( $routed ) && empty( $sort ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( $take_key ) {
|
if ( $take_key || $exists_key ) {
|
||||||
$query->set( 'meta_key', '' );
|
$query->set( 'meta_key', '' );
|
||||||
}
|
}
|
||||||
if ( $sort ) {
|
if ( $sort ) {
|
||||||
|
|||||||
@@ -436,4 +436,47 @@ class PostQueryRouterTest extends TestCase {
|
|||||||
$this->assertEmpty( $query->get( 'meta_query' ), 'both clauses routed' );
|
$this->assertEmpty( $query->get( 'meta_query' ), 'both clauses routed' );
|
||||||
$this->assertStringContainsString( '`_stock` IS NOT NULL', $router->posts_where( '', $query ) );
|
$this->assertStringContainsString( '`_stock` IS NOT NULL', $router->posts_where( '', $query ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HivePress's featured-listing lookup (Attribute::set_search_query()): the
|
||||||
|
* search's meta query, including its sort group, plus meta_key hp_featured,
|
||||||
|
* ordered at random. The sort group (key NOT EXISTS OR key EXISTS) matches
|
||||||
|
* every post, so unused for ordering it is dropped; meta_key without a
|
||||||
|
* value or a meta_value sort tests that the key exists (2.4 PR-122).
|
||||||
|
*/
|
||||||
|
public function test_hivepress_featured_lookup_is_routed(): void {
|
||||||
|
$this->set_post_mode( 'aeav_only' );
|
||||||
|
$router = new WPDO_Post_Query_Router();
|
||||||
|
$query = $this->make_query(
|
||||||
|
array(
|
||||||
|
'post_type' => 'product',
|
||||||
|
'meta_key' => '_stock',
|
||||||
|
'orderby' => 'rand',
|
||||||
|
'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' => '_price', 'value' => array( 10, 20 ), 'compare' => 'BETWEEN', 'type' => 'NUMERIC' ),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$router->pre_get_posts( $query );
|
||||||
|
|
||||||
|
$this->assertSame( '', $query->get( 'meta_key' ), 'meta_key routed' );
|
||||||
|
$this->assertEmpty( array_filter( (array) $query->get( 'meta_query' ), 'is_array' ), 'sort group dropped, filter routed' );
|
||||||
|
$where = $router->posts_where( '', $query );
|
||||||
|
$this->assertStringContainsString( '`_stock` IS NOT NULL', $where );
|
||||||
|
$this->assertStringContainsString( 'BETWEEN', $where );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_meta_key_with_a_value_is_left_alone(): void {
|
||||||
|
$this->set_post_mode( 'aeav_only' );
|
||||||
|
$router = new WPDO_Post_Query_Router();
|
||||||
|
$query = $this->make_query( array( 'post_type' => 'product', 'meta_key' => '_stock', 'meta_value' => '5' ) );
|
||||||
|
$router->pre_get_posts( $query );
|
||||||
|
|
||||||
|
$this->assertSame( '_stock', $query->get( 'meta_key' ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user