Make WordPress Core

Ticket #53450: 53450.patch

File 53450.patch, 6.0 KB (added by janthiel, 3 years ago)
  • src/wp-includes/class-wp-meta-query.php

    From 4d5175f395ec404bd0dbc99978705b9a5b9170a1 Mon Sep 17 00:00:00 2001
    From: Jan Thiel <jan@hive-it.de>
    Date: Fri, 18 Jun 2021 17:48:04 +0200
    Subject: [PATCH] Adds the new LIKE based compare operators STARTSWITH,
     ENDSWITH, NOT STARTSWITH, NOT ENDSWITH to the meta query value compares. They
     allow more performant regular query cases than REGEXP which would be the
     alternative.
    
    ---
     src/wp-includes/class-wp-meta-query.php |  20 +++++
     tests/phpunit/tests/query/metaQuery.php | 104 ++++++++++++++++++++++++
     2 files changed, 124 insertions(+)
    
    diff --git a/src/wp-includes/class-wp-meta-query.php b/src/wp-includes/class-wp-meta-query.php
    index 5a1b0c41479..a2339b79248 100644
    a b class WP_Meta_Query { 
    102102         * @since 5.1.0 Introduced $compare_key clause parameter, which enables LIKE key matches.
    103103         * @since 5.3.0 Increased the number of operators available to $compare_key. Introduced $type_key,
    104104         *              which enables the $key to be cast to a new data type for comparisons.
     105         * @since 5.9.0 Adds LIKE based STARTSWITH and ENDSWITH operators for value compares
    105106         *
    106107         * @param array $meta_query {
    107108         *     Array of meta query clauses. When first-order clauses or sub-clauses use strings as
    class WP_Meta_Query { 
    123124         *         @type string $value       Meta value to filter by.
    124125         *         @type string $compare     MySQL operator used for comparing the $value. Accepts '=',
    125126         *                                   '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE',
     127         *                                   'STARTSWITH', 'NOT STARTSWITH', 'ENDSWITH', 'NOT ENDSWITH',
    126128         *                                   'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'REGEXP',
    127129         *                                   'NOT REGEXP', 'RLIKE', 'EXISTS' or 'NOT EXISTS'.
    128130         *                                   Default is 'IN' when `$value` is an array, '=' otherwise.
    public function get_sql_for_clause( &$clause, $parent_query, $clause_key = '' ) 
    509511                        '=',
    510512                        '!=',
    511513                        'LIKE',
     514                        'STARTSWITH',
     515                        'ENDSWITH',
    512516                        'NOT LIKE',
     517                        'NOT STARTSWITH',
     518                        'NOT ENDSWITH',
    513519                        'IN',
    514520                        'NOT IN',
    515521                        'EXISTS',
    public function get_sql_for_clause( &$clause, $parent_query, $clause_key = '' ) 
    713719                                        $where      = $wpdb->prepare( '%s', $meta_value );
    714720                                        break;
    715721
     722                                case 'STARTSWITH':
     723                                case 'NOT STARTSWITH':
     724                                        $meta_compare = $meta_compare === 'STARTSWITH' ? 'LIKE' : 'NOT LIKE';
     725                                        $meta_value   = $wpdb->esc_like( $meta_value ) . '%';
     726                                        $where        = $wpdb->prepare( '%s', $meta_value );
     727                                        break;
     728
     729                                case 'ENDSSWITH':
     730                                case 'NOT ENDSWITH':
     731                                        $meta_compare = $meta_compare === 'ENDSSWITH' ? 'LIKE' : 'NOT LIKE';
     732                                        $meta_value   = '%' . $wpdb->esc_like( $meta_value );
     733                                        $where        = $wpdb->prepare( '%s', $meta_value );
     734                                        break;
     735
    716736                                // EXISTS with a value is interpreted as '='.
    717737                                case 'EXISTS':
    718738                                        $meta_compare = '=';
  • tests/phpunit/tests/query/metaQuery.php

    diff --git a/tests/phpunit/tests/query/metaQuery.php b/tests/phpunit/tests/query/metaQuery.php
    index 5acec55d3f9..239173893e1 100644
    a b public function test_meta_query_single_query_compare_not_like() { 
    271271                $this->assertSameSets( $expected, $query->posts );
    272272        }
    273273
     274        public function test_meta_query_single_query_compare_startswith() {
     275                $p1 = self::factory()->post->create();
     276                $p2 = self::factory()->post->create();
     277
     278                add_post_meta( $p1, 'foo', 'bar' );
     279
     280                $query = new WP_Query(
     281                        array(
     282                                'update_post_meta_cache' => false,
     283                                'update_post_term_cache' => false,
     284                                'fields'                 => 'ids',
     285                                'meta_query'             => array(
     286                                        array(
     287                                                'key'     => 'foo',
     288                                                'value'   => 'ba',
     289                                                'compare' => 'STARTSWITH',
     290                                        ),
     291                                ),
     292                        )
     293                );
     294
     295                $expected = array( $p1 );
     296                $this->assertSameSets( $expected, $query->posts );
     297        }
     298
     299        public function test_meta_query_single_query_compare_not_startswith() {
     300                $p1 = self::factory()->post->create();
     301                $p2 = self::factory()->post->create();
     302                $p3 = self::factory()->post->create();
     303
     304                add_post_meta( $p1, 'foo', 'bar' );
     305                add_post_meta( $p2, 'foo', 'rab' );
     306
     307                $query = new WP_Query(
     308                        array(
     309                                'update_post_meta_cache' => false,
     310                                'update_post_term_cache' => false,
     311                                'fields'                 => 'ids',
     312                                'meta_query'             => array(
     313                                        array(
     314                                                'key'     => 'foo',
     315                                                'value'   => 'ba',
     316                                                'compare' => 'NOT STARTSWITH',
     317                                        ),
     318                                ),
     319                        )
     320                );
     321
     322                $expected = array( $p2 );
     323                $this->assertSameSets( $expected, $query->posts );
     324        }
     325
     326        public function test_meta_query_single_query_compare_endswith() {
     327                $p1 = self::factory()->post->create();
     328                $p2 = self::factory()->post->create();
     329
     330                add_post_meta( $p1, 'foo', 'bar' );
     331
     332                $query = new WP_Query(
     333                        array(
     334                                'update_post_meta_cache' => false,
     335                                'update_post_term_cache' => false,
     336                                'fields'                 => 'ids',
     337                                'meta_query'             => array(
     338                                        array(
     339                                                'key'     => 'foo',
     340                                                'value'   => 'ar',
     341                                                'compare' => 'ENDSWITH',
     342                                        ),
     343                                ),
     344                        )
     345                );
     346
     347                $expected = array( $p1 );
     348                $this->assertSameSets( $expected, $query->posts );
     349        }
     350
     351        public function test_meta_query_single_query_compare_not_endswith() {
     352                $p1 = self::factory()->post->create();
     353                $p2 = self::factory()->post->create();
     354                $p3 = self::factory()->post->create();
     355
     356                add_post_meta( $p1, 'foo', 'bar' );
     357                add_post_meta( $p2, 'foo', 'rab' );
     358
     359                $query = new WP_Query(
     360                        array(
     361                                'update_post_meta_cache' => false,
     362                                'update_post_term_cache' => false,
     363                                'fields'                 => 'ids',
     364                                'meta_query'             => array(
     365                                        array(
     366                                                'key'     => 'foo',
     367                                                'value'   => 'ar',
     368                                                'compare' => 'NOT ENDSWITH',
     369                                        ),
     370                                ),
     371                        )
     372                );
     373
     374                $expected = array( $p2 );
     375                $this->assertSameSets( $expected, $query->posts );
     376        }
     377
    274378        public function test_meta_query_single_query_compare_between_not_between() {
    275379                $p1 = self::factory()->post->create();
    276380                $p2 = self::factory()->post->create();