diff --git a/wp-includes/taxonomy.php b/wp-includes/taxonomy.php index eab8d19703..3ed69bfdbb 100644 --- a/wp-includes/taxonomy.php +++ b/wp-includes/taxonomy.php @@ -539,7 +539,7 @@ class WP_Tax_Query { * Possible values: 'term_id', 'slug' or 'name' * Default: 'term_id' * - 'operator' string (optional) - * Possible values: 'IN' and 'NOT IN'. + * Possible values: 'AND', 'IN' or 'NOT IN'. * Default: 'IN' * - 'include_children' bool (optional) Whether to include child terms. * Default: true @@ -548,7 +548,7 @@ class WP_Tax_Query { * @access public * @var array */ - var $queries = array(); + public $queries = array(); /** * The relation between the queries. Can be one of 'AND' or 'OR'. @@ -557,10 +557,19 @@ class WP_Tax_Query { * @access public * @var string */ - var $relation; + public $relation; /** - * PHP4 type constructor. + * Standard response when the query should not return any rows. + * + * @since 3.2.0 + * @access private + * @var string + */ + private static $no_results = array( 'join' => '', 'where' => ' AND 0 = 1' ); + + /** + * Constructor. * * Parses a compact tax query and sets defaults. * @@ -581,10 +590,8 @@ class WP_Tax_Query { * 'field' => 'slug', * ), * ) - * - * @return WP_Tax_Query */ - function WP_Tax_Query( $tax_query ) { + public function __construct( $tax_query ) { if ( isset( $tax_query['relation'] ) && strtoupper( $tax_query['relation'] ) == 'OR' ) { $this->relation = 'OR'; } else { @@ -621,7 +628,7 @@ class WP_Tax_Query { * @param string $primary_id_column * @return array */ - function get_sql( $primary_table, $primary_id_column ) { + public function get_sql( $primary_table, $primary_id_column ) { global $wpdb; $join = ''; @@ -629,39 +636,21 @@ class WP_Tax_Query { $i = 0; foreach ( $this->queries as $query ) { + $this->clean_query( $query ); + + if ( is_wp_error( $query ) ) { + return self::$no_results; + } + extract( $query ); - if ( ! taxonomy_exists( $taxonomy ) ) - return array( 'join' => '', 'where' => ' AND 0 = 1'); - - $terms = array_unique( (array) $terms ); - - if ( empty( $terms ) ) - continue; - - if ( is_taxonomy_hierarchical( $taxonomy ) && $include_children ) { - $this->_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; - - $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' == $this->relation ) continue; else - return array( 'join' => '', 'where' => ' AND 0 = 1' ); + return self::$no_results; } $terms = implode( ',', $terms ); @@ -714,49 +703,88 @@ class WP_Tax_Query { } /** - * Transforms a list of terms, from one field to another. + * Validates a single query. * - * @since 3.1.0 + * @since 3.2.0 * @access private * - * @param array &$terms The list of terms - * @param string $taxonomy The taxonomy of the terms - * @param string $field The initial field + * @param array &$query The single query + */ + private function clean_query( &$query ) { + if ( ! taxonomy_exists( $query['taxonomy'] ) ) { + $query = new WP_Error( 'Invalid taxonomy' ); + return; + } + + $query['terms'] = array_unique( (array) $query['terms'] ); + + if ( is_taxonomy_hierarchical( $query['taxonomy'] ) && $query['include_children'] ) { + $this->transform_query( $query, 'term_id' ); + + if ( is_wp_error( $query ) ) + return; + + $children = array(); + foreach ( $query['terms'] as $term ) { + $children = array_merge( $children, get_term_children( $term, $query['taxonomy'] ) ); + $children[] = $term; + } + $query['terms'] = $children; + } + + $this->transform_query( $query, 'term_taxonomy_id' ); + } + + /** + * Transforms a single query, from one field to another. + * + * @since 3.2.0 + * @access private + * + * @param array &$query The single query * @param string $resulting_field The resulting field */ - function _transform_terms( &$terms, $taxonomy, $field, $resulting_field ) { + private function transform_query( &$query, $resulting_field ) { global $wpdb; - if ( empty( $terms ) ) + if ( empty( $query['terms'] ) ) return; - if ( $field == $resulting_field ) + if ( $query['field'] == $resulting_field ) return; $resulting_field = esc_sql( $resulting_field ); - switch ( $field ) { + switch ( $query['field'] ) { case 'slug': case 'name': - $terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $terms ) ) . "'"; + $terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $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) + WHERE taxonomy = '{$query['taxonomy']}' + AND $wpdb->terms.{$query['field']} IN ($terms) " ); break; default: - $terms = implode( ',', array_map( 'intval', $terms ) ); + $terms = implode( ',', array_map( 'intval', $query['terms'] ) ); $terms = $wpdb->get_col( " SELECT $resulting_field FROM $wpdb->term_taxonomy - WHERE taxonomy = '$taxonomy' + WHERE taxonomy = '{$query['taxonomy']}' AND term_id IN ($terms) " ); } + + if ( 'AND' == $query['operator'] && count( $terms ) < count( $query['terms'] ) ) { + $query = new WP_Error( 'Inexistent terms' ); + return; + } + + $query['terms'] = $terms; + $query['field'] = $resulting_field; } }