Make WordPress Core

Changeset 46188

Timestamp:
09/19/2019 03:02:20 PM (5 years ago)
Author:
boonebgorges
Message:

Query: Expand the list of operators available to compare_key in WP_Meta_Query.

compare_key, introduced in #42409, previously supported only = and LIKE
operators. This changeset introduces a number of other operators: !=, IN,
NOT IN, NOT LIKE, RLIKE, REGEXP, NOT REGEXP, EXISTS, and NOT EXISTS
(the latter two aliased to = and !=, respectively). To support case-sensitive
regular expression key comparisons, the new type_key parameter will force
a MySQL CAST when 'BINARY' is passed.

Props soulseekah.
Fixes #43346.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-meta-query.php

    r45603 r46188  
    101101     * @since 4.2.0 Introduced support for naming query clauses by associative array keys.
    102102     * @since 5.1.0 Introduced $compare_key clause parameter, which enables LIKE key matches.
     103
     104
    103105     *
    104106     * @param array $meta_query {
     
    112114     *
    113115     *         @type string $key         Meta key to filter by.
    114      *         @type string $compare_key MySQL operator used for comparing the $key. Accepts '=' and 'LIKE'.
    115      *                                   Default '='.
     116     *         @type string $compare_key MySQL operator used for comparing the $key. Accepts '=', '!='
     117     *                                   'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'REGEXP', 'NOT REGEXP', 'RLIKE',
     118     *                                   'EXISTS' (alias of '=') or 'NOT EXISTS' (alias of '!=').
     119     *                                   Default is 'IN' when `$key` is an array, '=' otherwise.
     120     *         @type string $type_key    MySQL data type that the meta_key column will be CAST to for
     121     *                                   comparisons. Accepts 'BINARY' for case-sensitive regular expression
     122     *                                   comparisons. Default is ''.
    116123     *         @type string $value       Meta value to filter by.
    117124     *         @type string $compare     MySQL operator used for comparing the $value. Accepts '=',
     
    240247         */
    241248        $primary_meta_query = array();
    242         foreach ( array( 'key', 'compare', 'type', 'compare_key' ) as $key ) {
     249        foreach ( array( 'key', 'compare', 'type', 'compare_key' ) as $key ) {
    243250            if ( ! empty( $qv[ "meta_$key" ] ) ) {
    244251                $primary_meta_query[ $key ] = $qv[ "meta_$key" ];
     
    499506        }
    500507
    501         if ( ! in_array(
    502             $clause['compare'],
    503             array(
    504                 '=',
    505                 '!=',
    506                 '>',
    507                 '>=',
    508                 '<',
    509                 '<=',
    510                 'LIKE',
    511                 'NOT LIKE',
    512                 'IN',
    513                 'NOT IN',
    514                 'BETWEEN',
    515                 'NOT BETWEEN',
    516                 'EXISTS',
    517                 'NOT EXISTS',
    518                 'REGEXP',
    519                 'NOT REGEXP',
    520                 'RLIKE',
    521             )
    522         ) ) {
     508        $non_numeric_operators = array(
     509            '=',
     510            '!=',
     511            'LIKE',
     512            'NOT LIKE',
     513            'IN',
     514            'NOT IN',
     515            'EXISTS',
     516            'NOT EXISTS',
     517            'RLIKE',
     518            'REGEXP',
     519            'NOT REGEXP',
     520        );
     521
     522        $numeric_operators = array(
     523            '>',
     524            '>=',
     525            '<',
     526            '<=',
     527            'BETWEEN',
     528            'NOT BETWEEN',
     529        );
     530
     531        if ( ! in_array( $clause['compare'], $non_numeric_operators, true ) && ! in_array( $clause['compare'], $numeric_operators, true ) ) {
    523532            $clause['compare'] = '=';
    524533        }
    525534
    526         if ( isset( $clause['compare_key'] ) && 'LIKE' === strtoupper( $clause['compare_key'] ) ) {
     535        if ( isset( $clause['compare_key'] ) ) {
    527536            $clause['compare_key'] = strtoupper( $clause['compare_key'] );
    528537        } else {
     538
     539
     540
     541
    529542            $clause['compare_key'] = '=';
    530543        }
     
    595608                $sql_chunks['where'][] = $alias . '.' . $this->meta_id_column . ' IS NULL';
    596609            } else {
    597                 if ( 'LIKE' === $meta_compare_key ) {
    598                     $sql_chunks['where'][] = $wpdb->prepare( "$alias.meta_key LIKE %s", '%' . $wpdb->esc_like( trim( $clause['key'] ) ) . '%' );
    599                 } else {
    600                     $sql_chunks['where'][] = $wpdb->prepare( "$alias.meta_key = %s", trim( $clause['key'] ) );
     610                /**
     611                 * In joined clauses negative operators have to be nested into a
     612                 * NOT EXISTS clause and flipped, to avoid returning records with
     613                 * matching post IDs but different meta keys. Here we prepare the
     614                 * nested clause.
     615                 */
     616                if ( in_array( $meta_compare_key, array( '!=', 'NOT IN', 'NOT LIKE', 'NOT EXISTS', 'NOT REGEXP' ), true ) ) {
     617                    // Negative clauses may be reused.
     618                    $i                     = count( $this->table_aliases );
     619                    $subquery_alias        = $i ? 'mt' . $i : $this->meta_table;
     620                    $this->table_aliases[] = $subquery_alias;
     621
     622                    $meta_compare_string_start  = 'NOT EXISTS (';
     623                    $meta_compare_string_start .= "SELECT 1 FROM $wpdb->postmeta $subquery_alias ";
     624                    $meta_compare_string_start .= "WHERE $subquery_alias.post_ID = $alias.post_ID ";
     625                    $meta_compare_string_end    = 'LIMIT 1';
     626                    $meta_compare_string_end   .= ')';
    601627                }
     628
     629
     630
     631
     632
     633
     634
     635
     636
     637
     638
     639
     640
     641
     642
     643
     644
     645
     646
     647
     648
     649
     650
     651
     652
     653
     654
     655
     656
     657
     658
     659
     660
     661
     662
     663
     664
     665
     666
     667
     668
     669
     670
     671
     672
     673
     674
     675
     676
     677
     678
     679
     680
     681
     682
    602683            }
    603684        }
  • trunk/src/wp-includes/class-wp-query.php

    r46144 r46188  
    615615     * @since 4.9.0 Introduced the `$comment_count` parameter.
    616616     * @since 5.1.0 Introduced the `$meta_compare_key` parameter.
     617
    617618     *
    618619     * @param string|array $query {
     
    656657     *     @type string       $meta_value              Custom field value.
    657658     *     @type int          $meta_value_num          Custom field value number.
     659
    658660     *     @type int          $menu_order              The menu order of the posts.
    659661     *     @type int          $monthnum                The two-digit month. Default empty. Accepts numbers 1-12.
  • trunk/tests/phpunit/tests/meta/query.php

    r42343 r46188  
    739739
    740740    /**
     741
     742
     743
     744
     745
     746
     747
     748
     749
     750
     751
     752
     753
     754
     755
     756
     757
     758
     759
     760
     761
     762
     763
     764
     765
     766
     767
     768
     769
     770
     771
     772
     773
     774
     775
     776
    741777     * This is the clause that ensures that empty arrays are not valid queries.
    742778     */
  • trunk/tests/phpunit/tests/query/metaQuery.php

    r43571 r46188  
    19231923
    19241924    }
     1925
     1926
     1927
     1928
     1929
     1930
     1931
     1932
     1933
     1934
     1935
     1936
     1937
     1938
     1939
     1940
     1941
     1942
     1943
     1944
     1945
     1946
     1947
     1948
     1949
     1950
     1951
     1952
     1953
     1954
     1955
     1956
     1957
     1958
     1959
     1960
     1961
     1962
     1963
     1964
     1965
     1966
     1967
     1968
     1969
     1970
     1971
     1972
     1973
     1974
     1975
     1976
     1977
     1978
     1979
     1980
     1981
     1982
     1983
     1984
     1985
     1986
     1987
     1988
     1989
     1990
     1991
     1992
     1993
     1994
     1995
     1996
     1997
     1998
     1999
     2000
     2001
     2002
     2003
     2004
     2005
     2006
     2007
     2008
     2009
     2010
     2011
     2012
     2013
     2014
     2015
     2016
     2017
     2018
     2019
     2020
     2021
     2022
     2023
     2024
     2025
     2026
     2027
     2028
     2029
     2030
     2031
     2032
     2033
     2034
     2035
     2036
     2037
     2038
     2039
     2040
     2041
     2042
     2043
     2044
     2045
     2046
     2047
     2048
     2049
     2050
     2051
     2052
     2053
     2054
     2055
     2056
     2057
     2058
     2059
     2060
     2061
     2062
     2063
     2064
     2065
     2066
     2067
     2068
     2069
     2070
     2071
     2072
     2073
     2074
     2075
     2076
     2077
     2078
     2079
     2080
     2081
     2082
     2083
     2084
     2085
     2086
     2087
     2088
     2089
     2090
     2091
     2092
     2093
     2094
     2095
     2096
     2097
     2098
     2099
     2100
     2101
     2102
     2103
     2104
     2105
     2106
     2107
     2108
     2109
     2110
     2111
     2112
     2113
     2114
     2115
     2116
     2117
     2118
     2119
     2120
     2121
     2122
     2123
     2124
     2125
     2126
     2127
     2128
     2129
     2130
     2131
     2132
     2133
     2134
     2135
     2136
     2137
     2138
     2139
     2140
     2141
     2142
     2143
     2144
     2145
     2146
     2147
     2148
     2149
     2150
     2151
     2152
     2153
     2154
     2155
     2156
     2157
     2158
     2159
     2160
     2161
     2162
     2163
     2164
     2165
     2166
     2167
    19252168}
Note: See TracChangeset for help on using the changeset viewer.