<!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'   =&gt; _x('&amp;raquo;', 'feed link'),
</span><span class="lines">@@ -1614,16 +1616,15 @@
</span><span class="cx">                         $href = get_post_comments_feed_link( $post-&gt;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-&gt;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-&gt;name ));
+                $href = get_category_feed_link( $term-&gt;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-&gt;get_queried_object();
</ins><span class="cx"> 
</span><del>-                $title = esc_attr(sprintf( $args['tagtitle'], get_bloginfo('name'), $args['separator'], $tag-&gt;name ));
-                $href = get_tag_feed_link( $tag_id );
</del><ins>+                $title = esc_attr(sprintf( $args['tagtitle'], get_bloginfo('name'), $args['separator'], $term-&gt;name ));
+                $href = get_tag_feed_link( $term-&gt;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, &amp;$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-&gt;is_singular ) {
-                        $whichcat = '';
-                } else {
</del><ins>+                if ( $this-&gt;is_tax ) {
+                        foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy =&gt; $t ) {
+                                if ( $t-&gt;query_var &amp;&amp; !empty( $q[$t-&gt;query_var] ) ) {
+                                        $tax_query_defaults = array(
+                                                'taxonomy' =&gt; $taxonomy,
+                                                'field' =&gt; 'slug',
+                                                'operator' =&gt; 'IN'
+                                        );
+
+                                        $term = str_replace( ' ', '+', $q[$t-&gt;query_var] );
+
+                                        if ( strpos($term, '+') !== false ) {
+                                                $terms = preg_split( '/[+\s]+/', $term );
+                                                foreach ( $terms as $term ) {
+                                                        $tax_query[] = array_merge( $tax_query_defaults, array(
+                                                                'terms' =&gt; array( $term )
+                                                        ) );
+                                                }
+                                        } else {
+                                                $tax_query[] = array_merge( $tax_query_defaults, array(
+                                                        'terms' =&gt; preg_split('/[,\s]+/', $term)
+                                                ) );
+                                        }
+                                }
+                        }
+                }
+
+                // Category stuff
+                if ( !empty($q['cat']) &amp;&amp; '0' != $q['cat'] &amp;&amp; !$this-&gt;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 = &quot; INNER JOIN $wpdb-&gt;term_relationships ON ($wpdb-&gt;posts.ID = $wpdb-&gt;term_relationships.object_id) INNER JOIN $wpdb-&gt;term_taxonomy ON ($wpdb-&gt;term_relationships.term_taxonomy_id = $wpdb-&gt;term_taxonomy.term_taxonomy_id) &quot;;
-                        $whichcat .= &quot; AND $wpdb-&gt;term_taxonomy.taxonomy = 'category' &quot;;
-                        $include_cats = &quot;'&quot; . implode(&quot;', '&quot;, $q['category__in']) . &quot;'&quot;;
-                        $whichcat .= &quot; AND $wpdb-&gt;term_taxonomy.term_id IN ($include_cats) &quot;;
</del><ins>+                        $tax_query[] = array(
+                                'taxonomy' =&gt; 'category',
+                                'terms' =&gt; $q['category__in'],
+                                'operator' =&gt; 'IN',
+                                'field' =&gt; 'term_id'
+                        );
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 if ( !empty($q['category__not_in']) ) {
</span><del>-                        $cat_string = &quot;'&quot; . implode(&quot;', '&quot;, $q['category__not_in']) . &quot;'&quot;;
-                        $whichcat .= &quot; AND $wpdb-&gt;posts.ID NOT IN ( SELECT tr.object_id FROM $wpdb-&gt;term_relationships AS tr INNER JOIN $wpdb-&gt;term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy = 'category' AND tt.term_id IN ($cat_string) )&quot;;
</del><ins>+                        $tax_query[] = array(
+                                'taxonomy' =&gt; 'category',
+                                'terms' =&gt; $q['category__not_in'],
+                                'operator' =&gt; 'NOT IN',
+                                'field' =&gt; '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 = &quot; INNER JOIN $wpdb-&gt;term_relationships ON ($wpdb-&gt;posts.ID = $wpdb-&gt;term_relationships.object_id) INNER JOIN $wpdb-&gt;term_taxonomy ON ($wpdb-&gt;term_relationships.term_taxonomy_id = $wpdb-&gt;term_taxonomy.term_taxonomy_id) &quot;;
-                        $whichcat = &quot; AND $wpdb-&gt;term_taxonomy.taxonomy = 'category' &quot;;
-                        $in_cats = array($q['cat']);
-                        $in_cats = array_merge($in_cats, get_term_children($q['cat'], 'category'));
-                        $in_cats = &quot;'&quot; . implode(&quot;', '&quot;, $in_cats) . &quot;'&quot;;
-                        $whichcat .= &quot;AND $wpdb-&gt;term_taxonomy.term_id IN ($in_cats)&quot;;
-                        $groupby = &quot;{$wpdb-&gt;posts}.ID&quot;;
</del><ins>+                        $tax_query[] = array(
+                                'taxonomy' =&gt; 'category',
+                                'terms' =&gt; array( $q['cat'] ),
+                                'operator' =&gt; 'IN',
+                                'field' =&gt; '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' =&gt; 'post_tag',
+                                'terms' =&gt; $qv['tag_id'],
+                                'operator' =&gt; 'IN',
+                                'field' =&gt; '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 = &quot;{$wpdb-&gt;posts}.ID&quot;;
</del><ins>+                if ( !empty($q['tag__in']) ) {
+                        $tax_query[] = array(
+                                'taxonomy' =&gt; 'post_tag',
+                                'terms' =&gt; $q['tag__in'],
+                                'operator' =&gt; 'IN',
+                                'field' =&gt; 'term_id'
+                        );
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                if ( !empty($q['tag__in']) &amp;&amp; empty($q['cat']) ) {
-                        $join = &quot; INNER JOIN $wpdb-&gt;term_relationships ON ($wpdb-&gt;posts.ID = $wpdb-&gt;term_relationships.object_id) INNER JOIN $wpdb-&gt;term_taxonomy ON ($wpdb-&gt;term_relationships.term_taxonomy_id = $wpdb-&gt;term_taxonomy.term_taxonomy_id) &quot;;
-                        $whichcat .= &quot; AND $wpdb-&gt;term_taxonomy.taxonomy = 'post_tag' &quot;;
-                        $include_tags = &quot;'&quot; . implode(&quot;', '&quot;, $q['tag__in']) . &quot;'&quot;;
-                        $whichcat .= &quot; AND $wpdb-&gt;term_taxonomy.term_id IN ($include_tags) &quot;;
-                        $reqtag = term_exists( $q['tag__in'][0], 'post_tag' );
-                        if ( !empty($reqtag) )
-                                $q['tag_id'] = $reqtag['term_id'];
-                }
-
-                if ( !empty($q['tag_slug__in']) &amp;&amp; empty($q['cat']) ) {
-                        $join = &quot; INNER JOIN $wpdb-&gt;term_relationships ON ($wpdb-&gt;posts.ID = $wpdb-&gt;term_relationships.object_id) INNER JOIN $wpdb-&gt;term_taxonomy ON ($wpdb-&gt;term_relationships.term_taxonomy_id = $wpdb-&gt;term_taxonomy.term_taxonomy_id) INNER JOIN $wpdb-&gt;terms ON ($wpdb-&gt;term_taxonomy.term_id = $wpdb-&gt;terms.term_id) &quot;;
-                        $whichcat .= &quot; AND $wpdb-&gt;term_taxonomy.taxonomy = 'post_tag' &quot;;
-                        $include_tags = &quot;'&quot; . implode(&quot;', '&quot;, $q['tag_slug__in']) . &quot;'&quot;;
-                        $whichcat .= &quot; AND $wpdb-&gt;terms.slug IN ($include_tags) &quot;;
-                        $reqtag = get_term_by( 'slug', $q['tag_slug__in'][0], 'post_tag' );
-                        if ( !empty($reqtag) )
-                                $q['tag_id'] = $reqtag-&gt;term_id;
-                }
-
</del><span class="cx">                 if ( !empty($q['tag__not_in']) ) {
</span><del>-                        $tag_string = &quot;'&quot; . implode(&quot;', '&quot;, $q['tag__not_in']) . &quot;'&quot;;
-                        $whichcat .= &quot; AND $wpdb-&gt;posts.ID NOT IN ( SELECT tr.object_id FROM $wpdb-&gt;term_relationships AS tr INNER JOIN $wpdb-&gt;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) )&quot;;
</del><ins>+                        $tax_query[] = array(
+                                'taxonomy' =&gt; 'post_tag',
+                                'terms' =&gt; $q['tag__not_in'],
+                                'operator' =&gt; 'NOT IN',
+                                'field' =&gt; 'term_id'
+                        );
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                // Tag and slug intersections.
-                $intersections = array('category__and' =&gt; 'category', 'tag__and' =&gt; 'post_tag', 'tag_slug__and' =&gt; 'post_tag', 'tag__in' =&gt; 'post_tag', 'tag_slug__in' =&gt; 'post_tag');
-                $tagin = array('tag__in', 'tag_slug__in'); // These are used to make some exceptions below
-                foreach ( $intersections as $item =&gt; $taxonomy ) {
-                        if ( empty($q[$item]) ) continue;
-                        if ( in_array($item, $tagin) &amp;&amp; empty($q['cat']) ) continue; // We should already have what we need if categories aren't being used
</del><ins>+                if ( !empty( $tax_query ) ) {
+                        $this-&gt;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 = &quot;SELECT p.ID FROM $wpdb-&gt;posts p INNER JOIN $wpdb-&gt;term_relationships tr ON (p.ID = tr.object_id) INNER JOIN $wpdb-&gt;term_taxonomy tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id) INNER JOIN $wpdb-&gt;terms t ON (tt.term_id = t.term_id)&quot;;
-                        $tsql .= &quot; WHERE tt.taxonomy = '$taxonomy' AND t.$taxonomy_field IN ('&quot; . implode(&quot;', '&quot;, $q[$item]) . &quot;')&quot;;
-                        if ( !in_array($item, $tagin) ) { // This next line is only helpful if we are doing an and relationship
-                                $tsql .= &quot; GROUP BY p.ID HAVING count(p.ID) = &quot; . count($q[$item]);
-                        }
-                        $post_ids = $wpdb-&gt;get_col($tsql);
-
-                        if ( count($post_ids) )
-                                $whichcat .= &quot; AND $wpdb-&gt;posts.ID IN (&quot; . implode(', ', $post_ids) . &quot;) &quot;;
-                        else {
-                                $whichcat = &quot; AND 0 = 1&quot;;
-                                break;
-                        }
</del><ins>+                        $where .= &quot; AND $wpdb-&gt;posts.ID IN( &quot; . implode( ', ', wp_tax_query( $tax_query ) ) . &quot;)&quot;;
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                // Taxonomies
-                if ( $this-&gt;is_tax ) {
-                        if ( '' != $q['taxonomy'] ) {
-                                $taxonomy = $q['taxonomy'];
-                                $tt[$taxonomy] = $q['term'];
-                        } else {
-                                foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy =&gt; $t ) {
-                                        if ( $t-&gt;query_var &amp;&amp; '' != $q[$t-&gt;query_var] ) {
-                                                $tt[$taxonomy] = $q[$t-&gt;query_var];
-                                                break;
-                                        }
-                                }
-                        }
-
-                        $terms = get_terms($taxonomy, array('slug' =&gt; $tt[$taxonomy], 'hide_empty' =&gt; !is_taxonomy_hierarchical($taxonomy)));
-
-                        if ( is_wp_error($terms) || empty($terms) ) {
-                                $whichcat = &quot; AND 0 &quot;;
-                        } else {
-                                foreach ( $terms as $term ) {
-                                        $term_ids[] = $term-&gt;term_id;
-                                        if ( is_taxonomy_hierarchical($taxonomy) ) {
-                                                $children = get_term_children($term-&gt;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) &amp;&amp; !empty($post_ids) ) {
-                                        $whichcat .= &quot; AND $wpdb-&gt;posts.ID IN (&quot; . implode(', ', $post_ids) . &quot;) &quot;;
-                                        if ( empty($post_type) ) {
-                                                $post_type = 'any';
-                                                $post_status_join = true;
-                                        } elseif ( in_array('attachment', (array)$post_type) ) {
-                                                $post_status_join = true;
-                                        }
-                                } else {
-                                        $whichcat = &quot; AND 0 &quot;;
-                                }
-                        }
</del><ins>+                if ( !empty($q['meta_key']) ) {
+                        $groupby = &quot;{$wpdb-&gt;posts}.ID&quot;;
</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') &amp;&amp; (strtoupper($q['order']) != 'DESC')) )
</span><span class="cx">                         $q['order'] = 'DESC';
</span><span class="lines">@@ -2625,27 +2575,13 @@
</span><span class="cx">                 $this-&gt;queried_object = NULL;
</span><span class="cx">                 $this-&gt;queried_object_id = 0;
</span><span class="cx"> 
</span><del>-                if ( $this-&gt;is_category ) {
-                        $cat = $this-&gt;get('cat');
-                        $category = &amp;get_category($cat);
-                        if ( is_wp_error( $category ) )
-                                return NULL;
-                        $this-&gt;queried_object = &amp;$category;
-                        $this-&gt;queried_object_id = (int) $cat;
-                } elseif ( $this-&gt;is_tag ) {
-                        $tag_id = $this-&gt;get('tag_id');
-                        $tag = &amp;get_term($tag_id, 'post_tag');
-                        if ( is_wp_error( $tag ) )
-                                return NULL;
-                        $this-&gt;queried_object = &amp;$tag;
-                        $this-&gt;queried_object_id = (int) $tag_id;
-                } elseif ( $this-&gt;is_tax ) {
-                        $tax = $this-&gt;get('taxonomy');
-                        $slug = $this-&gt;get('term');
-                        $term = &amp;get_terms($tax, array( 'slug' =&gt; $slug, 'hide_empty' =&gt; false ) );
-                        if ( is_wp_error($term) || empty($term) )
-                                return NULL;
-                        $term = $term[0];
</del><ins>+                if ( $this-&gt;tax_query ) {
+                        $query = reset( $this-&gt;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-&gt;queried_object = $term;
</span><span class="cx">                         $this-&gt;queried_object_id = $term-&gt;term_id;
</span><span class="cx">                 } elseif ( $this-&gt;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' =&gt; true,
</span><span class="cx">                 'show_ui' =&gt; true,
</span><span class="cx">                 '_builtin' =&gt; true,
</span><del>-        ) ) ;
</del><ins>+        ) );
</ins><span class="cx"> 
</span><span class="cx">         register_taxonomy( 'post_tag', 'post', array(
</span><span class="cx">                  'hierarchical' =&gt; false,
</span><span class="cx">                 'update_count_callback' =&gt; '_update_post_term_count',
</span><del>-                'query_var' =&gt; false,
</del><ins>+                'query_var' =&gt; 'tag',
</ins><span class="cx">                 'rewrite' =&gt; false,
</span><span class="cx">                 'public' =&gt; true,
</span><span class="cx">                 'show_ui' =&gt; 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' =&gt; false,
+                'field' =&gt; 'term_id',
+                'operator' =&gt; 'IN',
+                'do_query' =&gt; 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' =&gt; '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 = &quot;'&quot; . implode( &quot;', '&quot;, $taxonomies ) . &quot;'&quot;;
</span><del>-        $term_ids = &quot;'&quot; . implode( &quot;', '&quot;, $term_ids ) . &quot;'&quot;;
</del><span class="cx"> 
</span><del>-        $object_ids = $wpdb-&gt;get_col(&quot;SELECT tr.object_id FROM $wpdb-&gt;term_relationships AS tr INNER JOIN $wpdb-&gt;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&quot;);
</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 ) &amp;&amp; $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 = &quot;
+                                SELECT object_id
+                                FROM $wpdb-&gt;term_relationships
+                                INNER JOIN $wpdb-&gt;term_taxonomy USING (term_taxonomy_id)
+                                WHERE taxonomy IN ($taxonomies)
+                                AND term_id $operator ($terms)
+                        &quot;;
+                break;
+
+                case 'slug':
+                case 'name':
+                        foreach ( $terms as $i =&gt; $term ) {
+                                $terms[$i] = sanitize_term_field('slug', $term, 0, $taxonomy, 'db');
+                        }
+                        $terms = array_filter($terms);
+
+                        $terms = &quot;'&quot; . implode( &quot;','&quot;, $terms ) . &quot;'&quot;;
+                        $sql = &quot;
+                                SELECT object_id
+                                FROM $wpdb-&gt;term_relationships
+                                INNER JOIN $wpdb-&gt;term_taxonomy USING (term_taxonomy_id)
+                                INNER JOIN $wpdb-&gt;terms USING (term_id)
+                                WHERE taxonomy IN ($taxonomies)
+                                AND $field $operator ($terms)
+                        &quot;;
+                break;
+        }
+
+        if ( !$do_query )
+                return $sql;
+
+        return $wpdb-&gt;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-&gt;get_col( $sql[0] );
+
+        $r = &quot;SELECT object_id FROM $wpdb-&gt;term_relationships WHERE 1=1&quot;;
+        foreach ( $sql as $query )
+                $r .= &quot; AND object_id IN ($query)&quot;;
+
+        return $wpdb-&gt;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-&gt;get_queried_object();
+        $tag_name = $tag-&gt;slug;
+        $tag_id = $tag-&gt;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>