WordPress.org

Make WordPress Core

Changeset 16849


Ignore:
Timestamp:
12/09/2010 07:29:21 PM (9 years ago)
Author:
scribu
Message:

Introduce WP_Tax_Query. Fix canonical redirects in the process. See #15752

Location:
trunk/wp-includes
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/canonical.php

    r16797 r16849  
    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
  • trunk/wp-includes/query.php

    r16844 r16849  
    715715     * @since 3.1.0
    716716     * @access public
    717      * @var array
    718      */
    719     var $tax_query = array();
     717     * @var object WP_Tax_Query
     718     */
     719    var $tax_query;
    720720
    721721    /**
     
    15851585        }
    15861586
    1587         _set_tax_query_defaults( $tax_query );
    1588 
    1589         foreach ( $tax_query as $query ) {
    1590             if ( ! is_array( $query ) )
    1591                 continue;
    1592 
     1587        $tax_query_obj = new WP_Tax_Query( $tax_query );
     1588
     1589        foreach ( $tax_query_obj->queries as $query ) {
    15931590            if ( 'IN' == $query['operator'] ) {
    15941591                switch ( $query['taxonomy'] ) {
     
    16051602        }
    16061603
    1607         return $tax_query;
     1604        return $tax_query_obj;
    16081605    }
    16091606
     
    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'];
     
    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'] ) ) {
     
    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 );
  • trunk/wp-includes/taxonomy.php

    r16845 r16849  
    528528 */
    529529function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) {
    530     global $wpdb;
    531 
    532     $join = '';
    533     $where = array();
    534     $i = 0;
    535 
    536     _set_tax_query_defaults( $tax_query );
    537 
    538     if ( strtoupper( $tax_query['relation'] ) == 'OR' ) {
    539         $relation = 'OR';
    540     } else {
    541         $relation = 'AND';
    542     }
    543 
    544     foreach ( $tax_query as $query ) {
    545         if ( ! is_array( $query ) )
    546             continue;
    547 
    548         extract( $query );
    549 
    550         if ( ! taxonomy_exists( $taxonomy ) )
    551             return array( 'join' => '', 'where' => ' AND 0 = 1');
    552 
    553         $terms = array_unique( (array) $terms );
    554 
    555         if ( empty( $terms ) )
    556             continue;
    557 
    558         if ( is_taxonomy_hierarchical( $taxonomy ) && $include_children ) {
    559             _transform_terms( $terms, $taxonomy, $field, 'term_id' );
    560 
    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;
    567 
    568             _transform_terms( $terms, $taxonomy, 'term_id', 'term_taxonomy_id' );
    569         }
    570         else {
    571             _transform_terms( $terms, $taxonomy, $field, 'term_taxonomy_id' );
    572         }
    573 
    574         if ( 'IN' == $operator ) {
    575 
    576             if ( empty( $terms ) ) {
    577                 if ( 'OR' == $relation )
    578                     continue;
    579                 else
    580                     return array( 'join' => '', 'where' => ' AND 0 = 1' );
    581             }
    582 
    583             $terms = implode( ',', $terms );
    584 
    585             $alias = $i ? 'tt' . $i : $wpdb->term_relationships;
    586 
    587             $join .= " INNER JOIN $wpdb->term_relationships";
    588             $join .= $i ? " AS $alias" : '';
    589             $join .= " ON ($primary_table.$primary_id_column = $alias.object_id)";
    590 
    591             $where[] = "$alias.term_taxonomy_id $operator ($terms)";
    592         }
    593         elseif ( 'NOT IN' == $operator ) {
     530    $tax_query_obj = new WP_Tax_Query( $tax_query );
     531    return $tax_query_obj->get_sql( $primary_table, $primary_id_column );
     532}
     533
     534class WP_Tax_Query {
     535    var $relation = '';
     536    var $queries = array();
     537
     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        }
     544
     545        $defaults = array(
     546            'taxonomy' => '',
     547            'terms' => array(),
     548            'include_children' => true,
     549            'field' => 'term_id',
     550            'operator' => 'IN',
     551        );
     552
     553        foreach ( $tax_query as $query ) {
     554            if ( ! is_array( $query ) )
     555                continue;
     556
     557            $query = array_merge( $defaults, $query );
     558
     559            $query['terms'] = (array) $query['terms'];
     560           
     561            $this->queries[] = $query;
     562        }
     563    }
     564
     565    function get_sql( $primary_table, $primary_id_column ) {
     566        global $wpdb;
     567
     568        $join = '';
     569        $where = array();
     570        $i = 0;
     571
     572        foreach ( $this->queries as $query ) {
     573            extract( $query );
     574
     575            if ( ! taxonomy_exists( $taxonomy ) )
     576                return array( 'join' => '', 'where' => ' AND 0 = 1');
     577
     578            $terms = array_unique( (array) $terms );
    594579
    595580            if ( empty( $terms ) )
    596581                continue;
    597582
    598             $terms = implode( ',', $terms );
    599 
    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         }
    606 
    607         $i++;
    608     }
    609 
    610     if ( !empty( $where ) )
    611         $where = ' AND ( ' . implode( " $relation ", $where ) . ' )';
    612     else
    613         $where = '';
    614 
    615     return compact( 'join', 'where' );
    616 }
    617 
    618 function _set_tax_query_defaults( &$tax_query ) {
    619     if ( ! isset( $tax_query['relation'] ) )
    620         $tax_query['relation'] = 'AND';
    621 
    622     $defaults = array(
    623         'taxonomy' => '',
    624         'terms' => array(),
    625         'include_children' => true,
    626         'field' => 'term_id',
    627         'operator' => 'IN',
    628     );
    629 
    630     foreach ( $tax_query as $i => $query ) {
    631         if ( ! is_array( $query ) )
    632             continue;
    633 
    634         $tax_query[$i] = array_merge( $defaults, $query );
    635 
    636         $tax_query[$i]['terms'] = (array) $tax_query[$i]['terms'];
    637     }
    638 }
    639 
    640 function _transform_terms( &$terms, $taxonomy, $field, $resulting_field ) {
    641     global $wpdb;
    642 
    643     if ( empty( $terms ) )
    644         return;
    645 
    646     if ( $field == $resulting_field )
    647         return;
    648 
    649     $resulting_field = esc_sql( $resulting_field );
    650 
    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;
    663 
    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             " );
     583            if ( is_taxonomy_hierarchical( $taxonomy ) && $include_children ) {
     584                $this->_transform_terms( $terms, $taxonomy, $field, 'term_id' );
     585
     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;
     592
     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            }
     598
     599            if ( 'IN' == $operator ) {
     600
     601                if ( empty( $terms ) ) {
     602                    if ( 'OR' == $relation )
     603                        continue;
     604                    else
     605                        return array( 'join' => '', 'where' => ' AND 0 = 1' );
     606                }
     607
     608                $terms = implode( ',', $terms );
     609
     610                $alias = $i ? 'tt' . $i : $wpdb->term_relationships;
     611
     612                $join .= " INNER JOIN $wpdb->term_relationships";
     613                $join .= $i ? " AS $alias" : '';
     614                $join .= " ON ($primary_table.$primary_id_column = $alias.object_id)";
     615
     616                $where[] = "$alias.term_taxonomy_id $operator ($terms)";
     617            }
     618            elseif ( 'NOT IN' == $operator ) {
     619
     620                if ( empty( $terms ) )
     621                    continue;
     622
     623                $terms = implode( ',', $terms );
     624
     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            }
     631
     632            $i++;
     633        }
     634
     635        if ( !empty( $where ) )
     636            $where = ' AND ( ' . implode( " $relation ", $where ) . ' )';
     637        else
     638            $where = '';
     639
     640        return compact( 'join', 'where' );
     641    }
     642
     643    function _transform_terms( &$terms, $taxonomy, $field, $resulting_field ) {
     644        global $wpdb;
     645
     646        if ( empty( $terms ) )
     647            return;
     648
     649        if ( $field == $resulting_field )
     650            return;
     651
     652        $resulting_field = esc_sql( $resulting_field );
     653
     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;
     666
     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}
Note: See TracChangeset for help on using the changeset viewer.