WordPress.org

Make WordPress Core

Ticket #15752: WP_Tax_Query.diff

File WP_Tax_Query.diff, 9.5 KB (added by scribu, 9 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();