<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><style type="text/css"><!--
#msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; }
#msg ul, pre { overflow: auto; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<title>[15613] trunk/wp-includes: Clean up taxonomy queries in WP_Query.</title>
</head>
<body>
<div id="msg">
<dl>
<dt>Revision</dt> <dd><a href="http://trac.wordpress.org/changeset/15613">15613</a></dd>
<dt>Author</dt> <dd>scribu</dd>
<dt>Date</dt> <dd>2010-09-13 16:44:14 +0000 (Mon, 13 Sep 2010)</dd>
</dl>
<h3>Log Message</h3>
<pre>Clean up taxonomy queries in WP_Query. See <a href="http://trac.wordpress.org/ticket/12891">#12891</a></pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkwpincludesgeneraltemplatephp">trunk/wp-includes/general-template.php</a></li>
<li><a href="#trunkwpincludesqueryphp">trunk/wp-includes/query.php</a></li>
<li><a href="#trunkwpincludestaxonomyphp">trunk/wp-includes/taxonomy.php</a></li>
<li><a href="#trunkwpincludesthemephp">trunk/wp-includes/theme.php</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkwpincludesgeneraltemplatephp"></a>
<div class="modfile"><h4>Modified: trunk/wp-includes/general-template.php (15612 => 15613)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/general-template.php        2010-09-13 16:36:08 UTC (rev 15612)
+++ trunk/wp-includes/general-template.php        2010-09-13 16:44:14 UTC (rev 15613)
</span><span class="lines">@@ -1589,6 +1589,8 @@
</span><span class="cx"> * @param array $args Optional arguments.
</span><span class="cx"> */
</span><span class="cx"> function feed_links_extra( $args = array() ) {
</span><ins>+        global $wp_query;
+
</ins><span class="cx">         $defaults = array(
</span><span class="cx">                 /* translators: Separator between blog name and feed type in feed links */
</span><span class="cx">                 'separator' => _x('&raquo;', 'feed link'),
</span><span class="lines">@@ -1614,16 +1616,15 @@
</span><span class="cx">                         $href = get_post_comments_feed_link( $post->ID );
</span><span class="cx">                 }
</span><span class="cx">         } elseif ( is_category() ) {
</span><del>-                $cat_id = intval( get_query_var('cat') );
</del><ins>+                $term = $wp_query->get_queried_object();
</ins><span class="cx">
</span><del>-                $title = esc_attr(sprintf( $args['cattitle'], get_bloginfo('name'), $args['separator'], get_cat_name( $cat_id ) ));
-                $href = get_category_feed_link( $cat_id );
</del><ins>+                $title = esc_attr(sprintf( $args['cattitle'], get_bloginfo('name'), $args['separator'], $term->name ));
+                $href = get_category_feed_link( $term->term_id );
</ins><span class="cx">         } elseif ( is_tag() ) {
</span><del>-                $tag_id = intval( get_query_var('tag_id') );
-                $tag = get_tag( $tag_id );
</del><ins>+                $term = $wp_query->get_queried_object();
</ins><span class="cx">
</span><del>-                $title = esc_attr(sprintf( $args['tagtitle'], get_bloginfo('name'), $args['separator'], $tag->name ));
-                $href = get_tag_feed_link( $tag_id );
</del><ins>+                $title = esc_attr(sprintf( $args['tagtitle'], get_bloginfo('name'), $args['separator'], $term->name ));
+                $href = get_tag_feed_link( $term->term_id );
</ins><span class="cx">         } elseif ( is_author() ) {
</span><span class="cx">                 $author_id = intval( get_query_var('author') );
</span><span class="cx">
</span></span></pre></div>
<a id="trunkwpincludesqueryphp"></a>
<div class="modfile"><h4>Modified: trunk/wp-includes/query.php (15612 => 15613)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/query.php        2010-09-13 16:36:08 UTC (rev 15612)
+++ trunk/wp-includes/query.php        2010-09-13 16:44:14 UTC (rev 15613)
</span><span class="lines">@@ -662,6 +662,15 @@
</span><span class="cx">         var $query_vars = array();
</span><span class="cx">
</span><span class="cx">         /**
</span><ins>+         * Taxonomy query, after parsing
+         *
+         * @since 3.1.0
+         * @access public
+         * @var array
+         */
+        var $tax_query = array();
+
+        /**
</ins><span class="cx">          * Holds the data for a single object that is queried.
</span><span class="cx">          *
</span><span class="cx">          * Holds the contents of a post, page, category, attachment.
</span><span class="lines">@@ -1528,7 +1537,6 @@
</span><span class="cx">
</span><span class="cx">                 // First let's clear some variables
</span><span class="cx">                 $distinct = '';
</span><del>-                $whichcat = '';
</del><span class="cx">                 $whichauthor = '';
</span><span class="cx">                 $whichmimetype = '';
</span><span class="cx">                 $where = '';
</span><span class="lines">@@ -1785,13 +1793,38 @@
</span><span class="cx">                 // Allow plugins to contextually add/remove/modify the search section of the database query
</span><span class="cx">                 $search = apply_filters_ref_array('posts_search', array( $search, &$this ) );
</span><span class="cx">
</span><del>-                // Category stuff
</del><ins>+                // Taxonomies
+                $tax_query = array();
</ins><span class="cx">
</span><del>-                if ( empty($q['cat']) || ($q['cat'] == '0') ||
-                                // Bypass cat checks if fetching specific posts
-                                $this->is_singular ) {
-                        $whichcat = '';
-                } else {
</del><ins>+                if ( $this->is_tax ) {
+                        foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t ) {
+                                if ( $t->query_var && !empty( $q[$t->query_var] ) ) {
+                                        $tax_query_defaults = array(
+                                                'taxonomy' => $taxonomy,
+                                                'field' => 'slug',
+                                                'operator' => 'IN'
+                                        );
+
+                                        $term = str_replace( ' ', '+', $q[$t->query_var] );
+
+                                        if ( strpos($term, '+') !== false ) {
+                                                $terms = preg_split( '/[+\s]+/', $term );
+                                                foreach ( $terms as $term ) {
+                                                        $tax_query[] = array_merge( $tax_query_defaults, array(
+                                                                'terms' => array( $term )
+                                                        ) );
+                                                }
+                                        } else {
+                                                $tax_query[] = array_merge( $tax_query_defaults, array(
+                                                        'terms' => preg_split('/[,\s]+/', $term)
+                                                ) );
+                                        }
+                                }
+                        }
+                }
+
+                // Category stuff
+                if ( !empty($q['cat']) && '0' != $q['cat'] && !$this->is_singular ) {
</ins><span class="cx">                         $q['cat'] = ''.urldecode($q['cat']).'';
</span><span class="cx">                         $q['cat'] = addslashes_gpc($q['cat']);
</span><span class="cx">                         $cat_array = preg_split('/[,\s]+/', $q['cat']);
</span><span class="lines">@@ -1804,25 +1837,29 @@
</span><span class="cx">                                 $cat = abs($cat);
</span><span class="cx">                                 if ( $in ) {
</span><span class="cx">                                         $q['category__in'][] = $cat;
</span><del>-                                        $q['category__in'] = array_merge($q['category__in'], get_term_children($cat, 'category'));
</del><span class="cx">                                 } else {
</span><span class="cx">                                         $q['category__not_in'][] = $cat;
</span><del>-                                        $q['category__not_in'] = array_merge($q['category__not_in'], get_term_children($cat, 'category'));
</del><span class="cx">                                 }
</span><span class="cx">                         }
</span><span class="cx">                         $q['cat'] = implode(',', $req_cats);
</span><span class="cx">                 }
</span><span class="cx">
</span><span class="cx">                 if ( !empty($q['category__in']) ) {
</span><del>-                        $join = " INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id) INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id) ";
-                        $whichcat .= " AND $wpdb->term_taxonomy.taxonomy = 'category' ";
-                        $include_cats = "'" . implode("', '", $q['category__in']) . "'";
-                        $whichcat .= " AND $wpdb->term_taxonomy.term_id IN ($include_cats) ";
</del><ins>+                        $tax_query[] = array(
+                                'taxonomy' => 'category',
+                                'terms' => $q['category__in'],
+                                'operator' => 'IN',
+                                'field' => 'term_id'
+                        );
</ins><span class="cx">                 }
</span><span class="cx">
</span><span class="cx">                 if ( !empty($q['category__not_in']) ) {
</span><del>-                        $cat_string = "'" . implode("', '", $q['category__not_in']) . "'";
-                        $whichcat .= " AND $wpdb->posts.ID NOT IN ( SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy = 'category' AND tt.term_id IN ($cat_string) )";
</del><ins>+                        $tax_query[] = array(
+                                'taxonomy' => 'category',
+                                'terms' => $q['category__not_in'],
+                                'operator' => 'NOT IN',
+                                'field' => 'term_id'
+                        );
</ins><span class="cx">                 }
</span><span class="cx">
</span><span class="cx">                 // Category stuff for nice URLs
</span><span class="lines">@@ -1851,137 +1888,50 @@
</span><span class="cx">
</span><span class="cx">                         $q['cat'] = $reqcat;
</span><span class="cx">
</span><del>-                        $join = " INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id) INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id) ";
-                        $whichcat = " AND $wpdb->term_taxonomy.taxonomy = 'category' ";
-                        $in_cats = array($q['cat']);
-                        $in_cats = array_merge($in_cats, get_term_children($q['cat'], 'category'));
-                        $in_cats = "'" . implode("', '", $in_cats) . "'";
-                        $whichcat .= "AND $wpdb->term_taxonomy.term_id IN ($in_cats)";
-                        $groupby = "{$wpdb->posts}.ID";
</del><ins>+                        $tax_query[] = array(
+                                'taxonomy' => 'category',
+                                'terms' => array( $q['cat'] ),
+                                'operator' => 'IN',
+                                'field' => 'term_id'
+                        );
</ins><span class="cx">                 }
</span><span class="cx">
</span><del>-                // Tags
-                if ( '' != $q['tag'] ) {
-                        if ( strpos($q['tag'], ',') !== false ) {
-                                $tags = preg_split('/[,\s]+/', $q['tag']);
-                                foreach ( (array) $tags as $tag ) {
-                                        $tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
-                                        $q['tag_slug__in'][] = $tag;
-                                }
-                        } else if ( preg_match('/[+\s]+/', $q['tag']) || !empty($q['cat']) ) {
-                                $tags = preg_split('/[+\s]+/', $q['tag']);
-                                foreach ( (array) $tags as $tag ) {
-                                        $tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
-                                        $q['tag_slug__and'][] = $tag;
-                                }
-                        } else {
-                                $q['tag'] = sanitize_term_field('slug', $q['tag'], 0, 'post_tag', 'db');
-                                $q['tag_slug__in'][] = $q['tag'];
-                        }
</del><ins>+                // Tag stuff
+                if ( !empty($qv['tag_id']) ) {
+                        $tax_query[] = array(
+                                'taxonomy' => 'post_tag',
+                                'terms' => $qv['tag_id'],
+                                'operator' => 'IN',
+                                'field' => 'term_id'
+                        );
</ins><span class="cx">                 }
</span><span class="cx">
</span><del>-                if ( !empty($q['category__in']) || !empty($q['meta_key']) || !empty($q['tag__in']) || !empty($q['tag_slug__in']) ) {
-                        $groupby = "{$wpdb->posts}.ID";
</del><ins>+                if ( !empty($q['tag__in']) ) {
+                        $tax_query[] = array(
+                                'taxonomy' => 'post_tag',
+                                'terms' => $q['tag__in'],
+                                'operator' => 'IN',
+                                'field' => 'term_id'
+                        );
</ins><span class="cx">                 }
</span><span class="cx">
</span><del>-                if ( !empty($q['tag__in']) && empty($q['cat']) ) {
-                        $join = " INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id) INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id) ";
-                        $whichcat .= " AND $wpdb->term_taxonomy.taxonomy = 'post_tag' ";
-                        $include_tags = "'" . implode("', '", $q['tag__in']) . "'";
-                        $whichcat .= " AND $wpdb->term_taxonomy.term_id IN ($include_tags) ";
-                        $reqtag = term_exists( $q['tag__in'][0], 'post_tag' );
-                        if ( !empty($reqtag) )
-                                $q['tag_id'] = $reqtag['term_id'];
-                }
-
-                if ( !empty($q['tag_slug__in']) && empty($q['cat']) ) {
-                        $join = " INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id) INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id) INNER JOIN $wpdb->terms ON ($wpdb->term_taxonomy.term_id = $wpdb->terms.term_id) ";
-                        $whichcat .= " AND $wpdb->term_taxonomy.taxonomy = 'post_tag' ";
-                        $include_tags = "'" . implode("', '", $q['tag_slug__in']) . "'";
-                        $whichcat .= " AND $wpdb->terms.slug IN ($include_tags) ";
-                        $reqtag = get_term_by( 'slug', $q['tag_slug__in'][0], 'post_tag' );
-                        if ( !empty($reqtag) )
-                                $q['tag_id'] = $reqtag->term_id;
-                }
-
</del><span class="cx">                 if ( !empty($q['tag__not_in']) ) {
</span><del>-                        $tag_string = "'" . implode("', '", $q['tag__not_in']) . "'";
-                        $whichcat .= " AND $wpdb->posts.ID NOT IN ( SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy = 'post_tag' AND tt.term_id IN ($tag_string) )";
</del><ins>+                        $tax_query[] = array(
+                                'taxonomy' => 'post_tag',
+                                'terms' => $q['tag__not_in'],
+                                'operator' => 'NOT IN',
+                                'field' => 'term_id'
+                        );
</ins><span class="cx">                 }
</span><span class="cx">
</span><del>-                // Tag and slug intersections.
-                $intersections = array('category__and' => 'category', 'tag__and' => 'post_tag', 'tag_slug__and' => 'post_tag', 'tag__in' => 'post_tag', 'tag_slug__in' => 'post_tag');
-                $tagin = array('tag__in', 'tag_slug__in'); // These are used to make some exceptions below
-                foreach ( $intersections as $item => $taxonomy ) {
-                        if ( empty($q[$item]) ) continue;
-                        if ( in_array($item, $tagin) && empty($q['cat']) ) continue; // We should already have what we need if categories aren't being used
</del><ins>+                if ( !empty( $tax_query ) ) {
+                        $this->tax_query = $tax_query;
</ins><span class="cx">
</span><del>-                        if ( $item != 'category__and' ) {
-                                $reqtag = term_exists( $q[$item][0], 'post_tag' );
-                                if ( !empty($reqtag) )
-                                        $q['tag_id'] = $reqtag['term_id'];
-                        }
-
-                        if ( in_array( $item, array('tag_slug__and', 'tag_slug__in' ) ) )
-                                $taxonomy_field = 'slug';
-                        else
-                                $taxonomy_field = 'term_id';
-
-                        $q[$item] = array_unique($q[$item]);
-                        $tsql = "SELECT p.ID FROM $wpdb->posts p INNER JOIN $wpdb->term_relationships tr ON (p.ID = tr.object_id) INNER JOIN $wpdb->term_taxonomy tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id) INNER JOIN $wpdb->terms t ON (tt.term_id = t.term_id)";
-                        $tsql .= " WHERE tt.taxonomy = '$taxonomy' AND t.$taxonomy_field IN ('" . implode("', '", $q[$item]) . "')";
-                        if ( !in_array($item, $tagin) ) { // This next line is only helpful if we are doing an and relationship
-                                $tsql .= " GROUP BY p.ID HAVING count(p.ID) = " . count($q[$item]);
-                        }
-                        $post_ids = $wpdb->get_col($tsql);
-
-                        if ( count($post_ids) )
-                                $whichcat .= " AND $wpdb->posts.ID IN (" . implode(', ', $post_ids) . ") ";
-                        else {
-                                $whichcat = " AND 0 = 1";
-                                break;
-                        }
</del><ins>+                        $where .= " AND $wpdb->posts.ID IN( " . implode( ', ', wp_tax_query( $tax_query ) ) . ")";
</ins><span class="cx">                 }
</span><span class="cx">
</span><del>-                // Taxonomies
-                if ( $this->is_tax ) {
-                        if ( '' != $q['taxonomy'] ) {
-                                $taxonomy = $q['taxonomy'];
-                                $tt[$taxonomy] = $q['term'];
-                        } else {
-                                foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t ) {
-                                        if ( $t->query_var && '' != $q[$t->query_var] ) {
-                                                $tt[$taxonomy] = $q[$t->query_var];
-                                                break;
-                                        }
-                                }
-                        }
-
-                        $terms = get_terms($taxonomy, array('slug' => $tt[$taxonomy], 'hide_empty' => !is_taxonomy_hierarchical($taxonomy)));
-
-                        if ( is_wp_error($terms) || empty($terms) ) {
-                                $whichcat = " AND 0 ";
-                        } else {
-                                foreach ( $terms as $term ) {
-                                        $term_ids[] = $term->term_id;
-                                        if ( is_taxonomy_hierarchical($taxonomy) ) {
-                                                $children = get_term_children($term->term_id, $taxonomy);
-                                                $term_ids = array_merge($term_ids, $children);
-                                        }
-                                }
-                                $post_ids = get_objects_in_term($term_ids, $taxonomy);
-                                if ( !is_wp_error($post_ids) && !empty($post_ids) ) {
-                                        $whichcat .= " AND $wpdb->posts.ID IN (" . implode(', ', $post_ids) . ") ";
-                                        if ( empty($post_type) ) {
-                                                $post_type = 'any';
-                                                $post_status_join = true;
-                                        } elseif ( in_array('attachment', (array)$post_type) ) {
-                                                $post_status_join = true;
-                                        }
-                                } else {
-                                        $whichcat = " AND 0 ";
-                                }
-                        }
</del><ins>+                if ( !empty($q['meta_key']) ) {
+                        $groupby = "{$wpdb->posts}.ID";
</ins><span class="cx">                 }
</span><span class="cx">
</span><span class="cx">                 // Author/user stuff
</span><span class="lines">@@ -2033,7 +1983,7 @@
</span><span class="cx">                         $whichmimetype = wp_post_mime_type_where($q['post_mime_type'], $table_alias);
</span><span class="cx">                 }
</span><span class="cx">
</span><del>-                $where .= $search . $whichcat . $whichauthor . $whichmimetype;
</del><ins>+                $where .= $search . $whichauthor . $whichmimetype;
</ins><span class="cx">
</span><span class="cx">                 if ( empty($q['order']) || ((strtoupper($q['order']) != 'ASC') && (strtoupper($q['order']) != 'DESC')) )
</span><span class="cx">                         $q['order'] = 'DESC';
</span><span class="lines">@@ -2625,27 +2575,13 @@
</span><span class="cx">                 $this->queried_object = NULL;
</span><span class="cx">                 $this->queried_object_id = 0;
</span><span class="cx">
</span><del>-                if ( $this->is_category ) {
-                        $cat = $this->get('cat');
-                        $category = &get_category($cat);
-                        if ( is_wp_error( $category ) )
-                                return NULL;
-                        $this->queried_object = &$category;
-                        $this->queried_object_id = (int) $cat;
-                } elseif ( $this->is_tag ) {
-                        $tag_id = $this->get('tag_id');
-                        $tag = &get_term($tag_id, 'post_tag');
-                        if ( is_wp_error( $tag ) )
-                                return NULL;
-                        $this->queried_object = &$tag;
-                        $this->queried_object_id = (int) $tag_id;
-                } elseif ( $this->is_tax ) {
-                        $tax = $this->get('taxonomy');
-                        $slug = $this->get('term');
-                        $term = &get_terms($tax, array( 'slug' => $slug, 'hide_empty' => false ) );
-                        if ( is_wp_error($term) || empty($term) )
-                                return NULL;
-                        $term = $term[0];
</del><ins>+                if ( $this->tax_query ) {
+                        $query = reset( $this->tax_query );
+                        if ( 'term_id' == $query['field'] )
+                                $term = get_term( reset( $query['terms'] ), $query['taxonomy'] );
+                        else
+                                $term = get_term_by( $query['field'], reset( $query['terms'] ), $query['taxonomy'] );
+
</ins><span class="cx">                         $this->queried_object = $term;
</span><span class="cx">                         $this->queried_object_id = $term->term_id;
</span><span class="cx">                 } elseif ( $this->is_posts_page ) {
</span></span></pre></div>
<a id="trunkwpincludestaxonomyphp"></a>
<div class="modfile"><h4>Modified: trunk/wp-includes/taxonomy.php (15612 => 15613)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/taxonomy.php        2010-09-13 16:36:08 UTC (rev 15612)
+++ trunk/wp-includes/taxonomy.php        2010-09-13 16:44:14 UTC (rev 15613)
</span><span class="lines">@@ -23,12 +23,12 @@
</span><span class="cx">                 'public' => true,
</span><span class="cx">                 'show_ui' => true,
</span><span class="cx">                 '_builtin' => true,
</span><del>-        ) ) ;
</del><ins>+        ) );
</ins><span class="cx">
</span><span class="cx">         register_taxonomy( 'post_tag', 'post', array(
</span><span class="cx">                  'hierarchical' => false,
</span><span class="cx">                 'update_count_callback' => '_update_post_term_count',
</span><del>-                'query_var' => false,
</del><ins>+                'query_var' => 'tag',
</ins><span class="cx">                 'rewrite' => false,
</span><span class="cx">                 'public' => true,
</span><span class="cx">                 'show_ui' => true,
</span><span class="lines">@@ -432,45 +432,127 @@
</span><span class="cx"> * @uses $wpdb
</span><span class="cx"> * @uses wp_parse_args() Creates an array from string $args.
</span><span class="cx"> *
</span><del>- * @param int|array $term_ids Term id or array of term ids of terms that will be used
</del><ins>+ * @param mixed $terms Term id/slug/name or array of such to match against
</ins><span class="cx"> * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names
</span><del>- * @param array|string $args Change the order of the object_ids, either ASC or DESC
- * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success
- *        the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
</del><ins>+ * @param array|string $args
+ * 'include_children' bool Wether to include term children (hierarchical taxonomies only)
+ * 'field' string Which term field is being used. Can be 'term_id', 'slug' or 'name'
+ * 'operator' string Can be 'IN' and 'NOT IN'
+ * 'do_query' bool Wether to execute the query or return the SQL string
+ *
+ * @return WP_Error If the taxonomy does not exist
+ * @return array The list of found object_ids
+ * @return string The SQL string, if do_query is set to false
</ins><span class="cx"> */
</span><del>-function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
</del><ins>+function get_objects_in_term( $terms, $taxonomies, $args = array() ) {
</ins><span class="cx">         global $wpdb;
</span><span class="cx">
</span><del>-        if ( ! is_array( $term_ids ) )
-                $term_ids = array( $term_ids );
</del><ins>+        extract( wp_parse_args( $args, array(
+                'include_children' => false,
+                'field' => 'term_id',
+                'operator' => 'IN',
+                'do_query' => true,
+        ) ), EXTR_SKIP );
</ins><span class="cx">
</span><del>-        if ( ! is_array( $taxonomies ) )
-                $taxonomies = array( $taxonomies );
</del><ins>+        $taxonomies = (array) $taxonomies;
</ins><span class="cx">
</span><del>-        foreach ( (array) $taxonomies as $taxonomy ) {
</del><ins>+        foreach ( $taxonomies as $taxonomy ) {
</ins><span class="cx">                 if ( ! taxonomy_exists( $taxonomy ) )
</span><del>-                        return new WP_Error( 'invalid_taxonomy', __( 'Invalid Taxonomy' ) );
</del><ins>+                        return new WP_Error( 'invalid_taxonomy', sprintf( __( 'Invalid Taxonomy: %s' ), $taxonomy ) );
</ins><span class="cx">         }
</span><span class="cx">
</span><del>-        $defaults = array( 'order' => 'ASC' );
-        $args = wp_parse_args( $args, $defaults );
-        extract( $args, EXTR_SKIP );
</del><ins>+        $terms = array_unique( (array) $terms );
+        if ( empty($terms) )
+                continue;
</ins><span class="cx">
</span><del>-        $order = ( 'desc' == strtolower( $order ) ) ? 'DESC' : 'ASC';
</del><ins>+        if ( !in_array( $field, array( 'term_id', 'slug', 'name' ) ) )
+                $field = 'term_id';
</ins><span class="cx">
</span><del>-        $term_ids = array_map('intval', $term_ids );
</del><ins>+        if ( !in_array( $operator, array( 'IN', 'NOT IN' ) ) )
+                $operator = 'IN';
</ins><span class="cx">
</span><span class="cx">         $taxonomies = "'" . implode( "', '", $taxonomies ) . "'";
</span><del>-        $term_ids = "'" . implode( "', '", $term_ids ) . "'";
</del><span class="cx">
</span><del>-        $object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order");
</del><ins>+        switch ( $field ) {
+                case 'term_id':
+                        $terms = array_map( 'intval', $terms );
</ins><span class="cx">
</span><del>-        if ( ! $object_ids )
-                return array();
</del><ins>+                        if ( is_taxonomy_hierarchical( $taxonomy ) && $include_children ) {
+                                $children = $terms;
+                                foreach ( $terms as $term )
+                                        $children = array_merge( $children, get_term_children( $term, $taxonomy ) );
+                                $terms = $children;
+                        }
</ins><span class="cx">
</span><del>-        return $object_ids;
</del><ins>+                        $terms = implode( ',', $terms );
+                        $sql = "
+                                SELECT object_id
+                                FROM $wpdb->term_relationships
+                                INNER JOIN $wpdb->term_taxonomy USING (term_taxonomy_id)
+                                WHERE taxonomy IN ($taxonomies)
+                                AND term_id $operator ($terms)
+                        ";
+                break;
+
+                case 'slug':
+                case 'name':
+                        foreach ( $terms as $i => $term ) {
+                                $terms[$i] = sanitize_term_field('slug', $term, 0, $taxonomy, 'db');
+                        }
+                        $terms = array_filter($terms);
+
+                        $terms = "'" . implode( "','", $terms ) . "'";
+                        $sql = "
+                                SELECT object_id
+                                FROM $wpdb->term_relationships
+                                INNER JOIN $wpdb->term_taxonomy USING (term_taxonomy_id)
+                                INNER JOIN $wpdb->terms USING (term_id)
+                                WHERE taxonomy IN ($taxonomies)
+                                AND $field $operator ($terms)
+                        ";
+                break;
+        }
+
+        if ( !$do_query )
+                return $sql;
+
+        return $wpdb->get_col( $sql );        
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+/*
+ * Retrieve object_ids matching one or more taxonomy queries
+ *
+ * @since 3.1.0
+ *
+ * @param array $queries A list of taxonomy queries. A query is an associative array:
+ * 'taxonomy' string|array The taxonomy being queried
+ * 'terms' string|array The list of terms
+ * 'field' string Which term field is being used. Can be 'term_id', 'slug' or 'name'
+ * 'operator' string Can be 'IN' and 'NOT IN'
+ *
+ * @return array|WP_Error List of matching object_ids; WP_Error on failure.
+ */
+function wp_tax_query( $queries ) {
+        global $wpdb;
+
+        $sql = array();
+        foreach ( $queries as $query ) {
+                if ( !isset( $query['include_children'] ) )
+                        $query['include_children'] = true;
+                $query['do_query'] = false;
+                $sql[] = get_objects_in_term( $query['terms'], $query['taxonomy'], $query );
+        }
+
+        if ( 1 == count( $sql ) )
+                return $wpdb->get_col( $sql[0] );
+
+        $r = "SELECT object_id FROM $wpdb->term_relationships WHERE 1=1";
+        foreach ( $sql as $query )
+                $r .= " AND object_id IN ($query)";
+
+        return $wpdb->get_col( $r );
+}
+
</ins><span class="cx"> /**
</span><span class="cx"> * Get all Term data from database by Term ID.
</span><span class="cx"> *
</span></span></pre></div>
<a id="trunkwpincludesthemephp"></a>
<div class="modfile"><h4>Modified: trunk/wp-includes/theme.php (15612 => 15613)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/theme.php        2010-09-13 16:36:08 UTC (rev 15612)
+++ trunk/wp-includes/theme.php        2010-09-13 16:44:14 UTC (rev 15613)
</span><span class="lines">@@ -807,9 +807,12 @@
</span><span class="cx"> * @return string
</span><span class="cx"> */
</span><span class="cx"> function get_tag_template() {
</span><del>-        $tag_id = absint( get_query_var('tag_id') );
-        $tag_name = get_query_var('tag');
</del><ins>+        global $wp_query;
</ins><span class="cx">
</span><ins>+        $tag = $wp_query->get_queried_object();
+        $tag_name = $tag->slug;
+        $tag_id = $tag->term_id;
+
</ins><span class="cx">         $templates = array();
</span><span class="cx">
</span><span class="cx">         if ( $tag_name )
</span></span></pre>
</div>
</div>
</body>
</html>