WordPress.org

Make WordPress Core

Ticket #15752: WP_Tax_Query.diff

File WP_Tax_Query.diff, 9.5 KB (added by scribu, 3 years ago)
  • wp-includes/taxonomy.php

     
    527527 * @return array 
    528528 */ 
    529529function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) { 
    530         global $wpdb; 
     530        $tax_query_obj = new WP_Tax_Query( $tax_query ); 
     531        return $tax_query_obj->get_sql( $primary_table, $primary_id_column ); 
     532} 
    531533 
    532         $join = ''; 
    533         $where = array(); 
    534         $i = 0; 
     534class WP_Tax_Query { 
     535        var $relation = ''; 
     536        var $queries = array(); 
    535537 
    536         _set_tax_query_defaults( $tax_query ); 
     538        function __construct( &$tax_query ) { 
     539                if ( isset( $tax_query['relation'] ) && strtoupper( $tax_query['relation'] ) == 'OR' ) { 
     540                        $this->relation = 'OR'; 
     541                } else { 
     542                        $this->relation = 'AND'; 
     543                } 
    537544 
    538         if ( strtoupper( $tax_query['relation'] ) == 'OR' ) { 
    539                 $relation = 'OR'; 
    540         } else { 
    541                 $relation = 'AND'; 
    542         } 
     545                $defaults = array( 
     546                        'taxonomy' => '', 
     547                        'terms' => array(), 
     548                        'include_children' => true, 
     549                        'field' => 'term_id', 
     550                        'operator' => 'IN', 
     551                ); 
    543552 
    544         foreach ( $tax_query as $query ) { 
    545                 if ( ! is_array( $query ) ) 
    546                         continue; 
     553                foreach ( $tax_query as $query ) { 
     554                        if ( ! is_array( $query ) ) 
     555                                continue; 
    547556 
    548                 extract( $query ); 
     557                        $query = array_merge( $defaults, $query ); 
    549558 
    550                 if ( ! taxonomy_exists( $taxonomy ) ) 
    551                         return array( 'join' => '', 'where' => ' AND 0 = 1'); 
     559                        $query['terms'] = (array) $query['terms']; 
     560                         
     561                        $this->queries[] = $query; 
     562                } 
     563        } 
    552564 
    553                 $terms = array_unique( (array) $terms ); 
     565        function get_sql( $primary_table, $primary_id_column ) { 
     566                global $wpdb; 
    554567 
    555                 if ( empty( $terms ) ) 
    556                         continue; 
     568                $join = ''; 
     569                $where = array(); 
     570                $i = 0; 
    557571 
    558                 if ( is_taxonomy_hierarchical( $taxonomy ) && $include_children ) { 
    559                         _transform_terms( $terms, $taxonomy, $field, 'term_id' ); 
     572                foreach ( $this->queries as $query ) { 
     573                        extract( $query ); 
    560574 
    561                         $children = array(); 
    562                         foreach ( $terms as $term ) { 
    563                                 $children = array_merge( $children, get_term_children( $term, $taxonomy ) ); 
    564                                 $children[] = $term; 
    565                         } 
    566                         $terms = $children; 
     575                        if ( ! taxonomy_exists( $taxonomy ) ) 
     576                                return array( 'join' => '', 'where' => ' AND 0 = 1'); 
    567577 
    568                         _transform_terms( $terms, $taxonomy, 'term_id', 'term_taxonomy_id' ); 
    569                 } 
    570                 else { 
    571                         _transform_terms( $terms, $taxonomy, $field, 'term_taxonomy_id' ); 
    572                 } 
     578                        $terms = array_unique( (array) $terms ); 
    573579 
    574                 if ( 'IN' == $operator ) { 
     580                        if ( empty( $terms ) ) 
     581                                continue; 
    575582 
    576                         if ( empty( $terms ) ) { 
    577                                 if ( 'OR' == $relation ) 
    578                                         continue; 
    579                                 else 
    580                                         return array( 'join' => '', 'where' => ' AND 0 = 1' ); 
    581                         } 
     583                        if ( is_taxonomy_hierarchical( $taxonomy ) && $include_children ) { 
     584                                $this->_transform_terms( $terms, $taxonomy, $field, 'term_id' ); 
    582585 
    583                         $terms = implode( ',', $terms ); 
     586                                $children = array(); 
     587                                foreach ( $terms as $term ) { 
     588                                        $children = array_merge( $children, get_term_children( $term, $taxonomy ) ); 
     589                                        $children[] = $term; 
     590                                } 
     591                                $terms = $children; 
    584592 
    585                         $alias = $i ? 'tt' . $i : $wpdb->term_relationships; 
     593                                $this->_transform_terms( $terms, $taxonomy, 'term_id', 'term_taxonomy_id' ); 
     594                        } 
     595                        else { 
     596                                $this->_transform_terms( $terms, $taxonomy, $field, 'term_taxonomy_id' ); 
     597                        } 
    586598 
    587                         $join .= " INNER JOIN $wpdb->term_relationships"; 
    588                         $join .= $i ? " AS $alias" : ''; 
    589                         $join .= " ON ($primary_table.$primary_id_column = $alias.object_id)"; 
     599                        if ( 'IN' == $operator ) { 
    590600 
    591                         $where[] = "$alias.term_taxonomy_id $operator ($terms)"; 
    592                 } 
    593                 elseif ( 'NOT IN' == $operator ) { 
     601                                if ( empty( $terms ) ) { 
     602                                        if ( 'OR' == $relation ) 
     603                                                continue; 
     604                                        else 
     605                                                return array( 'join' => '', 'where' => ' AND 0 = 1' ); 
     606                                } 
    594607 
    595                         if ( empty( $terms ) ) 
    596                                 continue; 
     608                                $terms = implode( ',', $terms ); 
    597609 
    598                         $terms = implode( ',', $terms ); 
     610                                $alias = $i ? 'tt' . $i : $wpdb->term_relationships; 
    599611 
    600                         $where[] = "$primary_table.$primary_id_column NOT IN ( 
    601                                 SELECT object_id 
    602                                 FROM $wpdb->term_relationships 
    603                                 WHERE term_taxonomy_id IN ($terms) 
    604                         )"; 
    605                 } 
     612                                $join .= " INNER JOIN $wpdb->term_relationships"; 
     613                                $join .= $i ? " AS $alias" : ''; 
     614                                $join .= " ON ($primary_table.$primary_id_column = $alias.object_id)"; 
    606615 
    607                 $i++; 
    608         } 
     616                                $where[] = "$alias.term_taxonomy_id $operator ($terms)"; 
     617                        } 
     618                        elseif ( 'NOT IN' == $operator ) { 
    609619 
    610         if ( !empty( $where ) ) 
    611                 $where = ' AND ( ' . implode( " $relation ", $where ) . ' )'; 
    612         else 
    613                 $where = ''; 
     620                                if ( empty( $terms ) ) 
     621                                        continue; 
    614622 
    615         return compact( 'join', 'where' ); 
    616 } 
     623                                $terms = implode( ',', $terms ); 
    617624 
    618 function _set_tax_query_defaults( &$tax_query ) { 
    619         if ( ! isset( $tax_query['relation'] ) ) 
    620                 $tax_query['relation'] = 'AND'; 
     625                                $where[] = "$primary_table.$primary_id_column NOT IN ( 
     626                                        SELECT object_id 
     627                                        FROM $wpdb->term_relationships 
     628                                        WHERE term_taxonomy_id IN ($terms) 
     629                                )"; 
     630                        } 
    621631 
    622         $defaults = array( 
    623                 'taxonomy' => '', 
    624                 'terms' => array(), 
    625                 'include_children' => true, 
    626                 'field' => 'term_id', 
    627                 'operator' => 'IN', 
    628         ); 
     632                        $i++; 
     633                } 
    629634 
    630         foreach ( $tax_query as $i => $query ) { 
    631                 if ( ! is_array( $query ) ) 
    632                         continue; 
     635                if ( !empty( $where ) ) 
     636                        $where = ' AND ( ' . implode( " $relation ", $where ) . ' )'; 
     637                else 
     638                        $where = ''; 
    633639 
    634                 $tax_query[$i] = array_merge( $defaults, $query ); 
    635  
    636                 $tax_query[$i]['terms'] = (array) $tax_query[$i]['terms']; 
     640                return compact( 'join', 'where' ); 
    637641        } 
    638 } 
    639642 
    640 function _transform_terms( &$terms, $taxonomy, $field, $resulting_field ) { 
    641         global $wpdb; 
     643        function _transform_terms( &$terms, $taxonomy, $field, $resulting_field ) { 
     644                global $wpdb; 
    642645 
    643         if ( empty( $terms ) ) 
    644                 return; 
     646                if ( empty( $terms ) ) 
     647                        return; 
    645648 
    646         if ( $field == $resulting_field ) 
    647                 return; 
     649                if ( $field == $resulting_field ) 
     650                        return; 
    648651 
    649         $resulting_field = esc_sql( $resulting_field ); 
     652                $resulting_field = esc_sql( $resulting_field ); 
    650653 
    651         switch ( $field ) { 
    652                 case 'slug': 
    653                 case 'name': 
    654                         $terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $terms ) ) . "'"; 
    655                         $terms = $wpdb->get_col( " 
    656                                 SELECT $wpdb->term_taxonomy.$resulting_field 
    657                                 FROM $wpdb->term_taxonomy 
    658                                 INNER JOIN $wpdb->terms USING (term_id) 
    659                                 WHERE taxonomy = '$taxonomy' 
    660                                 AND $wpdb->terms.$field IN ($terms) 
    661                         " ); 
    662                         break; 
     654                switch ( $field ) { 
     655                        case 'slug': 
     656                        case 'name': 
     657                                $terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $terms ) ) . "'"; 
     658                                $terms = $wpdb->get_col( " 
     659                                        SELECT $wpdb->term_taxonomy.$resulting_field 
     660                                        FROM $wpdb->term_taxonomy 
     661                                        INNER JOIN $wpdb->terms USING (term_id) 
     662                                        WHERE taxonomy = '$taxonomy' 
     663                                        AND $wpdb->terms.$field IN ($terms) 
     664                                " ); 
     665                                break; 
    663666 
    664                 default: 
    665                         $terms = implode( ',', array_map( 'intval', $terms ) ); 
    666                         $terms = $wpdb->get_col( " 
    667                                 SELECT $resulting_field 
    668                                 FROM $wpdb->term_taxonomy 
    669                                 WHERE taxonomy = '$taxonomy' 
    670                                 AND term_id IN ($terms) 
    671                         " ); 
     667                        default: 
     668                                $terms = implode( ',', array_map( 'intval', $terms ) ); 
     669                                $terms = $wpdb->get_col( " 
     670                                        SELECT $resulting_field 
     671                                        FROM $wpdb->term_taxonomy 
     672                                        WHERE taxonomy = '$taxonomy' 
     673                                        AND term_id IN ($terms) 
     674                                " ); 
     675                } 
    672676        } 
    673677} 
    674678 
  • wp-includes/query.php

     
    714714         * 
    715715         * @since 3.1.0 
    716716         * @access public 
    717          * @var array 
     717         * @var object WP_Tax_Query 
    718718         */ 
    719         var $tax_query = array(); 
     719        var $tax_query; 
    720720 
    721721        /** 
    722722         * Holds the data for a single object that is queried. 
     
    15841584                        ); 
    15851585                } 
    15861586 
    1587                 _set_tax_query_defaults( $tax_query ); 
     1587                $tax_query_obj = new WP_Tax_Query( $tax_query ); 
    15881588 
    1589                 foreach ( $tax_query as $query ) { 
    1590                         if ( ! is_array( $query ) ) 
    1591                                 continue; 
    1592  
     1589                foreach ( $tax_query_obj->queries as $query ) { 
    15931590                        if ( 'IN' == $query['operator'] ) { 
    15941591                                switch ( $query['taxonomy'] ) { 
    15951592                                        case 'category': 
     
    16041601                        } 
    16051602                } 
    16061603 
    1607                 return $tax_query; 
     1604                return $tax_query_obj; 
    16081605        } 
    16091606 
    16101607        /** 
     
    19421939                if ( $this->is_category || $this->is_tag || $this->is_tax ) { 
    19431940                        $this->tax_query = $this->parse_tax_query( $q ); 
    19441941 
    1945                         $clauses = call_user_func_array( 'get_tax_sql', array( $this->tax_query, $wpdb->posts, 'ID', &$this) ); 
     1942                        $clauses = $this->tax_query->get_sql( $wpdb->posts, 'ID' ); 
    19461943 
    19471944                        $join .= $clauses['join']; 
    19481945                        $where .= $clauses['where']; 
     
    19571954                        } 
    19581955 
    19591956                        // Back-compat 
    1960                         $tax_query_in = wp_list_filter( $this->tax_query, array( 'operator' => 'IN' ) ); 
     1957                        $tax_query_in = wp_list_filter( $this->tax_query->queries, array( 'operator' => 'IN' ) ); 
    19611958                        if ( !empty( $tax_query_in ) ) { 
    19621959                                if ( !isset( $q['taxonomy'] ) ) { 
    19631960                                        foreach ( $tax_query_in as $a_tax_query ) { 
     
    26572654                $this->queried_object = NULL; 
    26582655                $this->queried_object_id = 0; 
    26592656 
    2660                 $tax_query_in = wp_list_filter( $this->tax_query, array( 'operator' => 'IN' ) ); 
     2657                $tax_query_in = wp_list_filter( $this->tax_query->queries, array( 'operator' => 'IN' ) ); 
    26612658                if ( !empty( $tax_query_in ) ) { 
    26622659                        $query = reset( $tax_query_in ); 
    26632660 
  • wp-includes/canonical.php

     
    146146                } elseif ( is_category() || is_tag() || is_tax() ) { // Terms (Tags/categories) 
    147147 
    148148                        $term_count = 0; 
    149                         foreach ( $wp_query->tax_query as $tax_query ) 
     149                        foreach ( $wp_query->tax_query->queries as $tax_query ) 
    150150                                $term_count += count( $tax_query['terms'] ); 
    151151 
    152152                        $obj = $wp_query->get_queried_object();