diff --git a/wp-includes/canonical.php b/wp-includes/canonical.php index 978d988ba5..66859b9aad 100644 --- a/wp-includes/canonical.php +++ b/wp-includes/canonical.php @@ -146,7 +146,7 @@ function redirect_canonical( $requested_url = null, $do_redirect = true ) { } elseif ( is_category() || is_tag() || is_tax() ) { // Terms (Tags/categories) $term_count = 0; - foreach ( $wp_query->tax_query as $tax_query ) + foreach ( $wp_query->tax_query->queries as $tax_query ) $term_count += count( $tax_query['terms'] ); $obj = $wp_query->get_queried_object(); diff --git a/wp-includes/query.php b/wp-includes/query.php index f1cebd7ad8..9fac164cb4 100644 --- a/wp-includes/query.php +++ b/wp-includes/query.php @@ -714,9 +714,9 @@ class WP_Query { * * @since 3.1.0 * @access public - * @var array + * @var object WP_Tax_Query */ - var $tax_query = array(); + var $tax_query; /** * Holds the data for a single object that is queried. @@ -1584,12 +1584,9 @@ class WP_Query { ); } - _set_tax_query_defaults( $tax_query ); - - foreach ( $tax_query as $query ) { - if ( ! is_array( $query ) ) - continue; + $tax_query_obj = new WP_Tax_Query( $tax_query ); + foreach ( $tax_query_obj->queries as $query ) { if ( 'IN' == $query['operator'] ) { switch ( $query['taxonomy'] ) { case 'category': @@ -1604,7 +1601,7 @@ class WP_Query { } } - return $tax_query; + return $tax_query_obj; } /** @@ -1942,7 +1939,7 @@ class WP_Query { if ( $this->is_category || $this->is_tag || $this->is_tax ) { $this->tax_query = $this->parse_tax_query( $q ); - $clauses = call_user_func_array( 'get_tax_sql', array( $this->tax_query, $wpdb->posts, 'ID', &$this) ); + $clauses = $this->tax_query->get_sql( $wpdb->posts, 'ID' ); $join .= $clauses['join']; $where .= $clauses['where']; @@ -1957,7 +1954,7 @@ class WP_Query { } // Back-compat - $tax_query_in = wp_list_filter( $this->tax_query, array( 'operator' => 'IN' ) ); + $tax_query_in = wp_list_filter( $this->tax_query->queries, array( 'operator' => 'IN' ) ); if ( !empty( $tax_query_in ) ) { if ( !isset( $q['taxonomy'] ) ) { foreach ( $tax_query_in as $a_tax_query ) { @@ -2657,7 +2654,7 @@ class WP_Query { $this->queried_object = NULL; $this->queried_object_id = 0; - $tax_query_in = wp_list_filter( $this->tax_query, array( 'operator' => 'IN' ) ); + $tax_query_in = wp_list_filter( $this->tax_query->queries, array( 'operator' => 'IN' ) ); if ( !empty( $tax_query_in ) ) { $query = reset( $tax_query_in ); diff --git a/wp-includes/taxonomy.php b/wp-includes/taxonomy.php index 7b67c1ca37..4f3ffbbfe3 100644 --- a/wp-includes/taxonomy.php +++ b/wp-includes/taxonomy.php @@ -527,148 +527,152 @@ function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) { * @return array */ function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) { - global $wpdb; + $tax_query_obj = new WP_Tax_Query( $tax_query ); + return $tax_query_obj->get_sql( $primary_table, $primary_id_column ); +} - $join = ''; - $where = array(); - $i = 0; +class WP_Tax_Query { + var $relation = ''; + var $queries = array(); - _set_tax_query_defaults( $tax_query ); + function __construct( &$tax_query ) { + if ( isset( $tax_query['relation'] ) && strtoupper( $tax_query['relation'] ) == 'OR' ) { + $this->relation = 'OR'; + } else { + $this->relation = 'AND'; + } - if ( strtoupper( $tax_query['relation'] ) == 'OR' ) { - $relation = 'OR'; - } else { - $relation = 'AND'; + $defaults = array( + 'taxonomy' => '', + 'terms' => array(), + 'include_children' => true, + 'field' => 'term_id', + 'operator' => 'IN', + ); + + foreach ( $tax_query as $query ) { + if ( ! is_array( $query ) ) + continue; + + $query = array_merge( $defaults, $query ); + + $query['terms'] = (array) $query['terms']; + + $this->queries[] = $query; + } } - foreach ( $tax_query as $query ) { - if ( ! is_array( $query ) ) - continue; + function get_sql( $primary_table, $primary_id_column ) { + global $wpdb; - extract( $query ); + $join = ''; + $where = array(); + $i = 0; - if ( ! taxonomy_exists( $taxonomy ) ) - return array( 'join' => '', 'where' => ' AND 0 = 1'); + foreach ( $this->queries as $query ) { + extract( $query ); - $terms = array_unique( (array) $terms ); + if ( ! taxonomy_exists( $taxonomy ) ) + return array( 'join' => '', 'where' => ' AND 0 = 1'); - if ( empty( $terms ) ) - continue; - - if ( is_taxonomy_hierarchical( $taxonomy ) && $include_children ) { - _transform_terms( $terms, $taxonomy, $field, 'term_id' ); - - $children = array(); - foreach ( $terms as $term ) { - $children = array_merge( $children, get_term_children( $term, $taxonomy ) ); - $children[] = $term; - } - $terms = $children; - - _transform_terms( $terms, $taxonomy, 'term_id', 'term_taxonomy_id' ); - } - else { - _transform_terms( $terms, $taxonomy, $field, 'term_taxonomy_id' ); - } - - if ( 'IN' == $operator ) { - - if ( empty( $terms ) ) { - if ( 'OR' == $relation ) - continue; - else - return array( 'join' => '', 'where' => ' AND 0 = 1' ); - } - - $terms = implode( ',', $terms ); - - $alias = $i ? 'tt' . $i : $wpdb->term_relationships; - - $join .= " INNER JOIN $wpdb->term_relationships"; - $join .= $i ? " AS $alias" : ''; - $join .= " ON ($primary_table.$primary_id_column = $alias.object_id)"; - - $where[] = "$alias.term_taxonomy_id $operator ($terms)"; - } - elseif ( 'NOT IN' == $operator ) { + $terms = array_unique( (array) $terms ); if ( empty( $terms ) ) continue; - $terms = implode( ',', $terms ); + if ( is_taxonomy_hierarchical( $taxonomy ) && $include_children ) { + $this->_transform_terms( $terms, $taxonomy, $field, 'term_id' ); - $where[] = "$primary_table.$primary_id_column NOT IN ( - SELECT object_id - FROM $wpdb->term_relationships - WHERE term_taxonomy_id IN ($terms) - )"; + $children = array(); + foreach ( $terms as $term ) { + $children = array_merge( $children, get_term_children( $term, $taxonomy ) ); + $children[] = $term; + } + $terms = $children; + + $this->_transform_terms( $terms, $taxonomy, 'term_id', 'term_taxonomy_id' ); + } + else { + $this->_transform_terms( $terms, $taxonomy, $field, 'term_taxonomy_id' ); + } + + if ( 'IN' == $operator ) { + + if ( empty( $terms ) ) { + if ( 'OR' == $relation ) + continue; + else + return array( 'join' => '', 'where' => ' AND 0 = 1' ); + } + + $terms = implode( ',', $terms ); + + $alias = $i ? 'tt' . $i : $wpdb->term_relationships; + + $join .= " INNER JOIN $wpdb->term_relationships"; + $join .= $i ? " AS $alias" : ''; + $join .= " ON ($primary_table.$primary_id_column = $alias.object_id)"; + + $where[] = "$alias.term_taxonomy_id $operator ($terms)"; + } + elseif ( 'NOT IN' == $operator ) { + + if ( empty( $terms ) ) + continue; + + $terms = implode( ',', $terms ); + + $where[] = "$primary_table.$primary_id_column NOT IN ( + SELECT object_id + FROM $wpdb->term_relationships + WHERE term_taxonomy_id IN ($terms) + )"; + } + + $i++; } - $i++; + if ( !empty( $where ) ) + $where = ' AND ( ' . implode( " $relation ", $where ) . ' )'; + else + $where = ''; + + return compact( 'join', 'where' ); } - if ( !empty( $where ) ) - $where = ' AND ( ' . implode( " $relation ", $where ) . ' )'; - else - $where = ''; + function _transform_terms( &$terms, $taxonomy, $field, $resulting_field ) { + global $wpdb; - return compact( 'join', 'where' ); -} + if ( empty( $terms ) ) + return; -function _set_tax_query_defaults( &$tax_query ) { - if ( ! isset( $tax_query['relation'] ) ) - $tax_query['relation'] = 'AND'; + if ( $field == $resulting_field ) + return; - $defaults = array( - 'taxonomy' => '', - 'terms' => array(), - 'include_children' => true, - 'field' => 'term_id', - 'operator' => 'IN', - ); + $resulting_field = esc_sql( $resulting_field ); - foreach ( $tax_query as $i => $query ) { - if ( ! is_array( $query ) ) - continue; + switch ( $field ) { + case 'slug': + case 'name': + $terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $terms ) ) . "'"; + $terms = $wpdb->get_col( " + SELECT $wpdb->term_taxonomy.$resulting_field + FROM $wpdb->term_taxonomy + INNER JOIN $wpdb->terms USING (term_id) + WHERE taxonomy = '$taxonomy' + AND $wpdb->terms.$field IN ($terms) + " ); + break; - $tax_query[$i] = array_merge( $defaults, $query ); - - $tax_query[$i]['terms'] = (array) $tax_query[$i]['terms']; - } -} - -function _transform_terms( &$terms, $taxonomy, $field, $resulting_field ) { - global $wpdb; - - if ( empty( $terms ) ) - return; - - if ( $field == $resulting_field ) - return; - - $resulting_field = esc_sql( $resulting_field ); - - switch ( $field ) { - case 'slug': - case 'name': - $terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $terms ) ) . "'"; - $terms = $wpdb->get_col( " - SELECT $wpdb->term_taxonomy.$resulting_field - FROM $wpdb->term_taxonomy - INNER JOIN $wpdb->terms USING (term_id) - WHERE taxonomy = '$taxonomy' - AND $wpdb->terms.$field IN ($terms) - " ); - break; - - default: - $terms = implode( ',', array_map( 'intval', $terms ) ); - $terms = $wpdb->get_col( " - SELECT $resulting_field - FROM $wpdb->term_taxonomy - WHERE taxonomy = '$taxonomy' - AND term_id IN ($terms) - " ); + default: + $terms = implode( ',', array_map( 'intval', $terms ) ); + $terms = $wpdb->get_col( " + SELECT $resulting_field + FROM $wpdb->term_taxonomy + WHERE taxonomy = '$taxonomy' + AND term_id IN ($terms) + " ); + } } }