Make WordPress Core

Changeset 15731


Ignore:
Timestamp:
10/06/2010 10:40:30 AM (16 years ago)
Author:
scribu
Message:

Generalize taxonomy queries:

  • transform wp_tax_query() into WP_Object_Query::get_tax_sql()
  • create parse_tax_query() method in WP_Query
  • add doc-block for $tax_query and $meta_query

See #15032. See #12891.

Location:
trunk/wp-includes
Files:
3 edited

Legend:

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

    r15730 r15731  
    536536
    537537        /**
    538          * Metadata query
     538         * List of metadata queries
     539         *
     540         * A query is an associative array:
     541         * - 'key' string The meta key
     542         * - 'value' string|array The meta value
     543         * - 'compare' (optional) string How to compare the key to the value.
     544         *              Possible values: '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'IN', 'BETWEEN'.
     545         *              Default: '='
     546         * - 'type' string (optional) The type of the value.
     547         *              Possible values: 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'.
     548         *              Default: 'CHAR'
    539549         *
    540550         * @since 3.1.0
    … …  
    543553         */
    544554        var $meta_query = array();
     555
     556        /*
     557         * List of taxonomy queries
     558         *
     559         * A query is an associative array:
     560         * - 'taxonomy' string|array The taxonomy being queried
     561         * - 'terms' string|array The list of terms
     562         * - 'field' string (optional) Which term field is being used.
     563         *              Possible values: 'term_id', 'slug' or 'name'
     564         *              Default: 'slug'
     565         * - 'operator' string (optional)
     566         *              Possible values: 'IN' and 'NOT IN'.
     567         *              Default: 'IN'
     568         * - 'include_children' bool (optional) Wether to include child terms.
     569         *              Default: true
     570         *
     571         * @since 3.1.0
     572         * @access public
     573         * @var array
     574         */
     575        var $tax_query = array();
    545576
    546577        /*
    … …  
    573604         * @access protected
    574605         * @since 3.1.0
     606         *
     607         * @uses $this->meta_query
    575608         *
    576609         * @param string $primary_table
    … …  
    644677
    645678                return array( $join, $where );
     679        }
     680
     681        /*
     682         * Used internally to generate an SQL string for searching across multiple taxonomies
     683         *
     684         * @access protected
     685         * @since 3.1.0
     686         *
     687         * @uses $this->tax_query
     688         *
     689         * @param string $object_id_column
     690         * @return string
     691         */
     692        function get_tax_sql( $object_id_column ) {
     693                global $wpdb;
     694
     695                $sql = array();
     696                foreach ( $this->tax_query as $query ) {
     697                        if ( !isset( $query['include_children'] ) )
     698                                $query['include_children'] = true;
     699                        $query['do_query'] = false;
     700                        $sql[] = get_objects_in_term( $query['terms'], $query['taxonomy'], $query );
     701                }
     702
     703                if ( 1 == count( $sql ) ) {
     704                        $ids = $wpdb->get_col( $sql[0] );
     705                } else {
     706                        $r = "SELECT object_id FROM $wpdb->term_relationships WHERE 1=1";
     707                        foreach ( $sql as $query )
     708                                $r .= " AND object_id IN ($query)";
     709
     710                        $ids = $wpdb->get_col( $r );
     711                }
     712
     713                if ( !empty( $ids ) )
     714                        return " AND $object_id_column IN(" . implode( ', ', $ids ) . ")";
     715                else
     716                        return ' AND 0 = 1';
    646717        }
    647718
  • trunk/wp-includes/query.php

    r15729 r15731  
    661661         */
    662662        var $query_vars = array();
    663 
    664         /**
    665          * Taxonomy query, after parsing
    666          *
    667          * @since 3.1.0
    668          * @access public
    669          * @var array
    670          */
    671         var $tax_query = array();
    672663
    673664        /**
    … …  
    13831374                        }
    13841375
     1376                        $this->parse_tax_query( $qv );
     1377
    13851378                        $this->parse_meta_query( $qv );
    13861379
    … …  
    14911484        }
    14921485
    1493         /**
    1494          * Sets the 404 property and saves whether query is feed.
    1495          *
    1496          * @since 2.0.0
    1497          * @access public
    1498          */
    1499         function set_404() {
    1500                 $is_feed = $this->is_feed;
    1501 
    1502                 $this->init_query_flags();
    1503                 $this->is_404 = true;
    1504 
    1505                 $this->is_feed = $is_feed;
    1506         }
    1507 
    1508         /**
    1509          * Retrieve query variable.
    1510          *
    1511          * @since 1.5.0
    1512          * @access public
    1513          *
    1514          * @param string $query_var Query variable key.
    1515          * @return mixed
    1516          */
    1517         function get($query_var) {
    1518                 if ( isset($this->query_vars[$query_var]) )
    1519                         return $this->query_vars[$query_var];
    1520 
    1521                 return '';
    1522         }
    1523 
    1524         /**
    1525          * Set query variable.
    1526          *
    1527          * @since 1.5.0
    1528          * @access public
    1529          *
    1530          * @param string $query_var Query variable key.
    1531          * @param mixed $value Query variable value.
    1532          */
    1533         function set($query_var, $value) {
    1534                 $this->query_vars[$query_var] = $value;
    1535         }
    1536 
    1537         /**
    1538          * Retrieve the posts based on query variables.
    1539          *
    1540          * There are a few filters and actions that can be used to modify the post
    1541          * database query.
    1542          *
    1543          * @since 1.5.0
    1544          * @access public
    1545          * @uses do_action_ref_array() Calls 'pre_get_posts' hook before retrieving posts.
    1546          *
    1547          * @return array List of posts.
    1548          */
    1549         function &get_posts() {
    1550                 global $wpdb, $user_ID, $_wp_using_ext_object_cache;
    1551 
    1552                 do_action_ref_array('pre_get_posts', array(&$this));
    1553 
    1554                 // Shorthand.
    1555                 $q = &$this->query_vars;
    1556 
    1557                 $q = $this->fill_query_vars($q);
    1558 
    1559                 // First let's clear some variables
    1560                 $distinct = '';
    1561                 $whichauthor = '';
    1562                 $whichmimetype = '';
    1563                 $where = '';
    1564                 $limits = '';
    1565                 $join = '';
    1566                 $search = '';
    1567                 $groupby = '';
    1568                 $fields = "$wpdb->posts.*";
    1569                 $post_status_join = false;
    1570                 $page = 1;
    1571 
    1572                 if ( isset( $q['caller_get_posts'] ) ) {
    1573                         _deprecated_argument( 'WP_Query', '3.1', __( '"caller_get_posts" is deprecated. Use "ignore_sticky_posts" instead.' ) );
    1574                         if ( !isset( $q['ignore_sticky_posts'] ) )
    1575                                 $q['ignore_sticky_posts'] = $q['caller_get_posts'];
    1576                 }
    1577 
    1578                 if ( !isset( $q['ignore_sticky_posts'] ) )
    1579                         $q['ignore_sticky_posts'] = false;
    1580 
    1581                 if ( !isset($q['suppress_filters']) )
    1582                         $q['suppress_filters'] = false;
    1583 
    1584                 if ( !isset($q['cache_results']) ) {
    1585                         if ( $_wp_using_ext_object_cache )
    1586                                 $q['cache_results'] = false;
    1587                         else
    1588                                 $q['cache_results'] = true;
    1589                 }
    1590 
    1591                 if ( !isset($q['update_post_term_cache']) )
    1592                         $q['update_post_term_cache'] = true;
    1593 
    1594                 if ( !isset($q['update_post_meta_cache']) )
    1595                         $q['update_post_meta_cache'] = true;
    1596 
    1597                 if ( !isset($q['post_type']) ) {
    1598                         if ( $this->is_search )
    1599                                 $q['post_type'] = 'any';
    1600                         else
    1601                                 $q['post_type'] = '';
    1602                 }
    1603                 $post_type = $q['post_type'];
    1604                 if ( !isset($q['posts_per_page']) || $q['posts_per_page'] == 0 )
    1605                         $q['posts_per_page'] = get_option('posts_per_page');
    1606                 if ( isset($q['showposts']) && $q['showposts'] ) {
    1607                         $q['showposts'] = (int) $q['showposts'];
    1608                         $q['posts_per_page'] = $q['showposts'];
    1609                 }
    1610                 if ( (isset($q['posts_per_archive_page']) && $q['posts_per_archive_page'] != 0) && ($this->is_archive || $this->is_search) )
    1611                         $q['posts_per_page'] = $q['posts_per_archive_page'];
    1612                 if ( !isset($q['nopaging']) ) {
    1613                         if ( $q['posts_per_page'] == -1 ) {
    1614                                 $q['nopaging'] = true;
    1615                         } else {
    1616                                 $q['nopaging'] = false;
    1617                         }
    1618                 }
    1619                 if ( $this->is_feed ) {
    1620                         $q['posts_per_page'] = get_option('posts_per_rss');
    1621                         $q['nopaging'] = false;
    1622                 }
    1623                 $q['posts_per_page'] = (int) $q['posts_per_page'];
    1624                 if ( $q['posts_per_page'] < -1 )
    1625                         $q['posts_per_page'] = abs($q['posts_per_page']);
    1626                 else if ( $q['posts_per_page'] == 0 )
    1627                         $q['posts_per_page'] = 1;
    1628 
    1629                 if ( !isset($q['comments_per_page']) || $q['comments_per_page'] == 0 )
    1630                         $q['comments_per_page'] = get_option('comments_per_page');
    1631 
    1632                 if ( $this->is_home && (empty($this->query) || $q['preview'] == 'true') && ( 'page' == get_option('show_on_front') ) && get_option('page_on_front') ) {
    1633                         $this->is_page = true;
    1634                         $this->is_home = false;
    1635                         $q['page_id'] = get_option('page_on_front');
    1636                 }
    1637 
    1638                 if ( isset($q['page']) ) {
    1639                         $q['page'] = trim($q['page'], '/');
    1640                         $q['page'] = absint($q['page']);
    1641                 }
    1642 
    1643                 // If true, forcibly turns off SQL_CALC_FOUND_ROWS even when limits are present.
    1644                 if ( isset($q['no_found_rows']) )
    1645                         $q['no_found_rows'] = (bool) $q['no_found_rows'];
    1646                 else
    1647                         $q['no_found_rows'] = false;
    1648 
    1649                 // If a month is specified in the querystring, load that month
    1650                 if ( $q['m'] ) {
    1651                         $q['m'] = '' . preg_replace('|[^0-9]|', '', $q['m']);
    1652                         $where .= " AND YEAR($wpdb->posts.post_date)=" . substr($q['m'], 0, 4);
    1653                         if ( strlen($q['m']) > 5 )
    1654                                 $where .= " AND MONTH($wpdb->posts.post_date)=" . substr($q['m'], 4, 2);
    1655                         if ( strlen($q['m']) > 7 )
    1656                                 $where .= " AND DAYOFMONTH($wpdb->posts.post_date)=" . substr($q['m'], 6, 2);
    1657                         if ( strlen($q['m']) > 9 )
    1658                                 $where .= " AND HOUR($wpdb->posts.post_date)=" . substr($q['m'], 8, 2);
    1659                         if ( strlen($q['m']) > 11 )
    1660                                 $where .= " AND MINUTE($wpdb->posts.post_date)=" . substr($q['m'], 10, 2);
    1661                         if ( strlen($q['m']) > 13 )
    1662                                 $where .= " AND SECOND($wpdb->posts.post_date)=" . substr($q['m'], 12, 2);
    1663                 }
    1664 
    1665                 if ( '' !== $q['hour'] )
    1666                         $where .= " AND HOUR($wpdb->posts.post_date)='" . $q['hour'] . "'";
    1667 
    1668                 if ( '' !== $q['minute'] )
    1669                         $where .= " AND MINUTE($wpdb->posts.post_date)='" . $q['minute'] . "'";
    1670 
    1671                 if ( '' !== $q['second'] )
    1672                         $where .= " AND SECOND($wpdb->posts.post_date)='" . $q['second'] . "'";
    1673 
    1674                 if ( $q['year'] )
    1675                         $where .= " AND YEAR($wpdb->posts.post_date)='" . $q['year'] . "'";
    1676 
    1677                 if ( $q['monthnum'] )
    1678                         $where .= " AND MONTH($wpdb->posts.post_date)='" . $q['monthnum'] . "'";
    1679 
    1680                 if ( $q['day'] )
    1681                         $where .= " AND DAYOFMONTH($wpdb->posts.post_date)='" . $q['day'] . "'";
    1682 
    1683                 // If we've got a post_type AND its not "any" post_type.
    1684                 if ( !empty($q['post_type']) && 'any' != $q['post_type'] ) {
    1685                         foreach ( (array)$q['post_type'] as $_post_type ) {
    1686                                 $ptype_obj = get_post_type_object($_post_type);
    1687                                 if ( !$ptype_obj || !$ptype_obj->query_var || empty($q[ $ptype_obj->query_var ]) )
    1688                                         continue;
    1689 
    1690                                 if ( ! $ptype_obj->hierarchical || strpos($q[ $ptype_obj->query_var ], '/') === false ) {
    1691                                         // Non-hierarchical post_types & parent-level-hierarchical post_types can directly use 'name'
    1692                                         $q['name'] = $q[ $ptype_obj->query_var ];
    1693                                 } else {
    1694                                         // Hierarchical post_types will operate through the
    1695                                         $q['pagename'] = $q[ $ptype_obj->query_var ];
    1696                                         $q['name'] = '';
    1697                                 }
    1698 
    1699                                 // Only one request for a slug is possible, this is why name & pagename are overwritten above.
    1700                                 break;
    1701                         } //end foreach
    1702                         unset($ptype_obj);
    1703                 }
    1704 
    1705                 if ( '' != $q['name'] ) {
    1706                         $q['name'] = sanitize_title($q['name']);
    1707                         $where .= " AND $wpdb->posts.post_name = '" . $q['name'] . "'";
    1708                 } elseif ( '' != $q['pagename'] ) {
    1709                         if ( isset($this->queried_object_id) ) {
    1710                                 $reqpage = $this->queried_object_id;
    1711                         } else {
    1712                                 if ( 'page' != $q['post_type'] ) {
    1713                                         foreach ( (array)$q['post_type'] as $_post_type ) {
    1714                                                 $ptype_obj = get_post_type_object($_post_type);
    1715                                                 if ( !$ptype_obj || !$ptype_obj->hierarchical )
    1716                                                         continue;
    1717 
    1718                                                 $reqpage = get_page_by_path($q['pagename'], OBJECT, $_post_type);
    1719                                                 if ( $reqpage )
    1720                                                         break;
    1721                                         }
    1722                                         unset($ptype_obj);
    1723                                 } else {
    1724                                         $reqpage = get_page_by_path($q['pagename']);
    1725                                 }
    1726                                 if ( !empty($reqpage) )
    1727                                         $reqpage = $reqpage->ID;
    1728                                 else
    1729                                         $reqpage = 0;
    1730                         }
    1731 
    1732                         $page_for_posts = get_option('page_for_posts');
    1733                         if  ( ('page' != get_option('show_on_front') ) || empty($page_for_posts) || ( $reqpage != $page_for_posts ) ) {
    1734                                 $q['pagename'] = str_replace('%2F', '/', urlencode(urldecode($q['pagename'])));
    1735                                 $page_paths = '/' . trim($q['pagename'], '/');
    1736                                 $q['pagename'] = sanitize_title(basename($page_paths));
    1737                                 $q['name'] = $q['pagename'];
    1738                                 $where .= " AND ($wpdb->posts.ID = '$reqpage')";
    1739                                 $reqpage_obj = get_page($reqpage);
    1740                                 if ( is_object($reqpage_obj) && 'attachment' == $reqpage_obj->post_type ) {
    1741                                         $this->is_attachment = true;
    1742                                         $post_type = $q['post_type'] = 'attachment';
    1743                                         $this->is_page = true;
    1744                                         $q['attachment_id'] = $reqpage;
    1745                                 }
    1746                         }
    1747                 } elseif ( '' != $q['attachment'] ) {
    1748                         $q['attachment'] = str_replace('%2F', '/', urlencode(urldecode($q['attachment'])));
    1749                         $attach_paths = '/' . trim($q['attachment'], '/');
    1750                         $q['attachment'] = sanitize_title(basename($attach_paths));
    1751                         $q['name'] = $q['attachment'];
    1752                         $where .= " AND $wpdb->posts.post_name = '" . $q['attachment'] . "'";
    1753                 }
    1754 
    1755                 if ( $q['w'] )
    1756                         $where .= ' AND ' . _wp_mysql_week( "`$wpdb->posts`.`post_date`" ) . " = '" . $q['w'] . "'";
    1757 
    1758                 if ( intval($q['comments_popup']) )
    1759                         $q['p'] = absint($q['comments_popup']);
    1760 
    1761                 // If an attachment is requested by number, let it supercede any post number.
    1762                 if ( $q['attachment_id'] )
    1763                         $q['p'] = absint($q['attachment_id']);
    1764 
    1765                 // If a post number is specified, load that post
    1766                 if ( $q['p'] ) {
    1767                         $where .= " AND {$wpdb->posts}.ID = " . $q['p'];
    1768                 } elseif ( $q['post__in'] ) {
    1769                         $post__in = implode(',', array_map( 'absint', $q['post__in'] ));
    1770                         $where .= " AND {$wpdb->posts}.ID IN ($post__in)";
    1771                 } elseif ( $q['post__not_in'] ) {
    1772                         $post__not_in = implode(',',  array_map( 'absint', $q['post__not_in'] ));
    1773                         $where .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)";
    1774                 }
    1775 
    1776                 if ( is_numeric($q['post_parent']) )
    1777                         $where .= $wpdb->prepare( " AND $wpdb->posts.post_parent = %d ", $q['post_parent'] );
    1778 
    1779                 if ( $q['page_id'] ) {
    1780                         if  ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) {
    1781                                 $q['p'] = $q['page_id'];
    1782                                 $where = " AND {$wpdb->posts}.ID = " . $q['page_id'];
    1783                         }
    1784                 }
    1785 
    1786                 // If a search pattern is specified, load the posts that match
    1787                 if ( !empty($q['s']) ) {
    1788                         // added slashes screw with quote grouping when done early, so done later
    1789                         $q['s'] = stripslashes($q['s']);
    1790                         if ( !empty($q['sentence']) ) {
    1791                                 $q['search_terms'] = array($q['s']);
    1792                         } else {
    1793                                 preg_match_all('/".*?("|$)|((?<=[\\s",+])|^)[^\\s",+]+/', $q['s'], $matches);
    1794                                 $q['search_terms'] = array_map('_search_terms_tidy', $matches[0]);
    1795                         }
    1796                         $n = !empty($q['exact']) ? '' : '%';
    1797                         $searchand = '';
    1798                         foreach( (array) $q['search_terms'] as $term ) {
    1799                                 $term = addslashes_gpc($term);
    1800                                 $search .= "{$searchand}(($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}'))";
    1801                                 $searchand = ' AND ';
    1802                         }
    1803                         $term = esc_sql($q['s']);
    1804                         if ( empty($q['sentence']) && count($q['search_terms']) > 1 && $q['search_terms'][0] != $q['s'] )
    1805                                 $search .= " OR ($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}')";
    1806 
    1807                         if ( !empty($search) ) {
    1808                                 $search = " AND ({$search}) ";
    1809                                 if ( !is_user_logged_in() )
    1810                                         $search .= " AND ($wpdb->posts.post_password = '') ";
    1811                         }
    1812                 }
    1813 
    1814                 // Allow plugins to contextually add/remove/modify the search section of the database query
    1815                 $search = apply_filters_ref_array('posts_search', array( $search, &$this ) );
    1816 
    1817                 // Taxonomies
     1486        function parse_tax_query( $q ) {
    18181487                $tax_query = array();
    18191488
    … …  
    19251594                }
    19261595
    1927                 if ( !empty( $tax_query ) ) {
    1928                         $this->tax_query = $tax_query;
    1929 
     1596                $this->tax_query = $tax_query;
     1597        }
     1598
     1599        /**
     1600         * Sets the 404 property and saves whether query is feed.
     1601         *
     1602         * @since 2.0.0
     1603         * @access public
     1604         */
     1605        function set_404() {
     1606                $is_feed = $this->is_feed;
     1607
     1608                $this->init_query_flags();
     1609                $this->is_404 = true;
     1610
     1611                $this->is_feed = $is_feed;
     1612        }
     1613
     1614        /**
     1615         * Retrieve query variable.
     1616         *
     1617         * @since 1.5.0
     1618         * @access public
     1619         *
     1620         * @param string $query_var Query variable key.
     1621         * @return mixed
     1622         */
     1623        function get($query_var) {
     1624                if ( isset($this->query_vars[$query_var]) )
     1625                        return $this->query_vars[$query_var];
     1626
     1627                return '';
     1628        }
     1629
     1630        /**
     1631         * Set query variable.
     1632         *
     1633         * @since 1.5.0
     1634         * @access public
     1635         *
     1636         * @param string $query_var Query variable key.
     1637         * @param mixed $value Query variable value.
     1638         */
     1639        function set($query_var, $value) {
     1640                $this->query_vars[$query_var] = $value;
     1641        }
     1642
     1643        /**
     1644         * Retrieve the posts based on query variables.
     1645         *
     1646         * There are a few filters and actions that can be used to modify the post
     1647         * database query.
     1648         *
     1649         * @since 1.5.0
     1650         * @access public
     1651         * @uses do_action_ref_array() Calls 'pre_get_posts' hook before retrieving posts.
     1652         *
     1653         * @return array List of posts.
     1654         */
     1655        function &get_posts() {
     1656                global $wpdb, $user_ID, $_wp_using_ext_object_cache;
     1657
     1658                do_action_ref_array('pre_get_posts', array(&$this));
     1659
     1660                // Shorthand.
     1661                $q = &$this->query_vars;
     1662
     1663                $q = $this->fill_query_vars($q);
     1664
     1665                // First let's clear some variables
     1666                $distinct = '';
     1667                $whichauthor = '';
     1668                $whichmimetype = '';
     1669                $where = '';
     1670                $limits = '';
     1671                $join = '';
     1672                $search = '';
     1673                $groupby = '';
     1674                $fields = "$wpdb->posts.*";
     1675                $post_status_join = false;
     1676                $page = 1;
     1677
     1678                if ( isset( $q['caller_get_posts'] ) ) {
     1679                        _deprecated_argument( 'WP_Query', '3.1', __( '"caller_get_posts" is deprecated. Use "ignore_sticky_posts" instead.' ) );
     1680                        if ( !isset( $q['ignore_sticky_posts'] ) )
     1681                                $q['ignore_sticky_posts'] = $q['caller_get_posts'];
     1682                }
     1683
     1684                if ( !isset( $q['ignore_sticky_posts'] ) )
     1685                        $q['ignore_sticky_posts'] = false;
     1686
     1687                if ( !isset($q['suppress_filters']) )
     1688                        $q['suppress_filters'] = false;
     1689
     1690                if ( !isset($q['cache_results']) ) {
     1691                        if ( $_wp_using_ext_object_cache )
     1692                                $q['cache_results'] = false;
     1693                        else
     1694                                $q['cache_results'] = true;
     1695                }
     1696
     1697                if ( !isset($q['update_post_term_cache']) )
     1698                        $q['update_post_term_cache'] = true;
     1699
     1700                if ( !isset($q['update_post_meta_cache']) )
     1701                        $q['update_post_meta_cache'] = true;
     1702
     1703                if ( !isset($q['post_type']) ) {
     1704                        if ( $this->is_search )
     1705                                $q['post_type'] = 'any';
     1706                        else
     1707                                $q['post_type'] = '';
     1708                }
     1709                $post_type = $q['post_type'];
     1710                if ( !isset($q['posts_per_page']) || $q['posts_per_page'] == 0 )
     1711                        $q['posts_per_page'] = get_option('posts_per_page');
     1712                if ( isset($q['showposts']) && $q['showposts'] ) {
     1713                        $q['showposts'] = (int) $q['showposts'];
     1714                        $q['posts_per_page'] = $q['showposts'];
     1715                }
     1716                if ( (isset($q['posts_per_archive_page']) && $q['posts_per_archive_page'] != 0) && ($this->is_archive || $this->is_search) )
     1717                        $q['posts_per_page'] = $q['posts_per_archive_page'];
     1718                if ( !isset($q['nopaging']) ) {
     1719                        if ( $q['posts_per_page'] == -1 ) {
     1720                                $q['nopaging'] = true;
     1721                        } else {
     1722                                $q['nopaging'] = false;
     1723                        }
     1724                }
     1725                if ( $this->is_feed ) {
     1726                        $q['posts_per_page'] = get_option('posts_per_rss');
     1727                        $q['nopaging'] = false;
     1728                }
     1729                $q['posts_per_page'] = (int) $q['posts_per_page'];
     1730                if ( $q['posts_per_page'] < -1 )
     1731                        $q['posts_per_page'] = abs($q['posts_per_page']);
     1732                else if ( $q['posts_per_page'] == 0 )
     1733                        $q['posts_per_page'] = 1;
     1734
     1735                if ( !isset($q['comments_per_page']) || $q['comments_per_page'] == 0 )
     1736                        $q['comments_per_page'] = get_option('comments_per_page');
     1737
     1738                if ( $this->is_home && (empty($this->query) || $q['preview'] == 'true') && ( 'page' == get_option('show_on_front') ) && get_option('page_on_front') ) {
     1739                        $this->is_page = true;
     1740                        $this->is_home = false;
     1741                        $q['page_id'] = get_option('page_on_front');
     1742                }
     1743
     1744                if ( isset($q['page']) ) {
     1745                        $q['page'] = trim($q['page'], '/');
     1746                        $q['page'] = absint($q['page']);
     1747                }
     1748
     1749                // If true, forcibly turns off SQL_CALC_FOUND_ROWS even when limits are present.
     1750                if ( isset($q['no_found_rows']) )
     1751                        $q['no_found_rows'] = (bool) $q['no_found_rows'];
     1752                else
     1753                        $q['no_found_rows'] = false;
     1754
     1755                // If a month is specified in the querystring, load that month
     1756                if ( $q['m'] ) {
     1757                        $q['m'] = '' . preg_replace('|[^0-9]|', '', $q['m']);
     1758                        $where .= " AND YEAR($wpdb->posts.post_date)=" . substr($q['m'], 0, 4);
     1759                        if ( strlen($q['m']) > 5 )
     1760                                $where .= " AND MONTH($wpdb->posts.post_date)=" . substr($q['m'], 4, 2);
     1761                        if ( strlen($q['m']) > 7 )
     1762                                $where .= " AND DAYOFMONTH($wpdb->posts.post_date)=" . substr($q['m'], 6, 2);
     1763                        if ( strlen($q['m']) > 9 )
     1764                                $where .= " AND HOUR($wpdb->posts.post_date)=" . substr($q['m'], 8, 2);
     1765                        if ( strlen($q['m']) > 11 )
     1766                                $where .= " AND MINUTE($wpdb->posts.post_date)=" . substr($q['m'], 10, 2);
     1767                        if ( strlen($q['m']) > 13 )
     1768                                $where .= " AND SECOND($wpdb->posts.post_date)=" . substr($q['m'], 12, 2);
     1769                }
     1770
     1771                if ( '' !== $q['hour'] )
     1772                        $where .= " AND HOUR($wpdb->posts.post_date)='" . $q['hour'] . "'";
     1773
     1774                if ( '' !== $q['minute'] )
     1775                        $where .= " AND MINUTE($wpdb->posts.post_date)='" . $q['minute'] . "'";
     1776
     1777                if ( '' !== $q['second'] )
     1778                        $where .= " AND SECOND($wpdb->posts.post_date)='" . $q['second'] . "'";
     1779
     1780                if ( $q['year'] )
     1781                        $where .= " AND YEAR($wpdb->posts.post_date)='" . $q['year'] . "'";
     1782
     1783                if ( $q['monthnum'] )
     1784                        $where .= " AND MONTH($wpdb->posts.post_date)='" . $q['monthnum'] . "'";
     1785
     1786                if ( $q['day'] )
     1787                        $where .= " AND DAYOFMONTH($wpdb->posts.post_date)='" . $q['day'] . "'";
     1788
     1789                // If we've got a post_type AND its not "any" post_type.
     1790                if ( !empty($q['post_type']) && 'any' != $q['post_type'] ) {
     1791                        foreach ( (array)$q['post_type'] as $_post_type ) {
     1792                                $ptype_obj = get_post_type_object($_post_type);
     1793                                if ( !$ptype_obj || !$ptype_obj->query_var || empty($q[ $ptype_obj->query_var ]) )
     1794                                        continue;
     1795
     1796                                if ( ! $ptype_obj->hierarchical || strpos($q[ $ptype_obj->query_var ], '/') === false ) {
     1797                                        // Non-hierarchical post_types & parent-level-hierarchical post_types can directly use 'name'
     1798                                        $q['name'] = $q[ $ptype_obj->query_var ];
     1799                                } else {
     1800                                        // Hierarchical post_types will operate through the
     1801                                        $q['pagename'] = $q[ $ptype_obj->query_var ];
     1802                                        $q['name'] = '';
     1803                                }
     1804
     1805                                // Only one request for a slug is possible, this is why name & pagename are overwritten above.
     1806                                break;
     1807                        } //end foreach
     1808                        unset($ptype_obj);
     1809                }
     1810
     1811                if ( '' != $q['name'] ) {
     1812                        $q['name'] = sanitize_title($q['name']);
     1813                        $where .= " AND $wpdb->posts.post_name = '" . $q['name'] . "'";
     1814                } elseif ( '' != $q['pagename'] ) {
     1815                        if ( isset($this->queried_object_id) ) {
     1816                                $reqpage = $this->queried_object_id;
     1817                        } else {
     1818                                if ( 'page' != $q['post_type'] ) {
     1819                                        foreach ( (array)$q['post_type'] as $_post_type ) {
     1820                                                $ptype_obj = get_post_type_object($_post_type);
     1821                                                if ( !$ptype_obj || !$ptype_obj->hierarchical )
     1822                                                        continue;
     1823
     1824                                                $reqpage = get_page_by_path($q['pagename'], OBJECT, $_post_type);
     1825                                                if ( $reqpage )
     1826                                                        break;
     1827                                        }
     1828                                        unset($ptype_obj);
     1829                                } else {
     1830                                        $reqpage = get_page_by_path($q['pagename']);
     1831                                }
     1832                                if ( !empty($reqpage) )
     1833                                        $reqpage = $reqpage->ID;
     1834                                else
     1835                                        $reqpage = 0;
     1836                        }
     1837
     1838                        $page_for_posts = get_option('page_for_posts');
     1839                        if  ( ('page' != get_option('show_on_front') ) || empty($page_for_posts) || ( $reqpage != $page_for_posts ) ) {
     1840                                $q['pagename'] = str_replace('%2F', '/', urlencode(urldecode($q['pagename'])));
     1841                                $page_paths = '/' . trim($q['pagename'], '/');
     1842                                $q['pagename'] = sanitize_title(basename($page_paths));
     1843                                $q['name'] = $q['pagename'];
     1844                                $where .= " AND ($wpdb->posts.ID = '$reqpage')";
     1845                                $reqpage_obj = get_page($reqpage);
     1846                                if ( is_object($reqpage_obj) && 'attachment' == $reqpage_obj->post_type ) {
     1847                                        $this->is_attachment = true;
     1848                                        $post_type = $q['post_type'] = 'attachment';
     1849                                        $this->is_page = true;
     1850                                        $q['attachment_id'] = $reqpage;
     1851                                }
     1852                        }
     1853                } elseif ( '' != $q['attachment'] ) {
     1854                        $q['attachment'] = str_replace('%2F', '/', urlencode(urldecode($q['attachment'])));
     1855                        $attach_paths = '/' . trim($q['attachment'], '/');
     1856                        $q['attachment'] = sanitize_title(basename($attach_paths));
     1857                        $q['name'] = $q['attachment'];
     1858                        $where .= " AND $wpdb->posts.post_name = '" . $q['attachment'] . "'";
     1859                }
     1860
     1861                if ( $q['w'] )
     1862                        $where .= ' AND ' . _wp_mysql_week( "`$wpdb->posts`.`post_date`" ) . " = '" . $q['w'] . "'";
     1863
     1864                if ( intval($q['comments_popup']) )
     1865                        $q['p'] = absint($q['comments_popup']);
     1866
     1867                // If an attachment is requested by number, let it supercede any post number.
     1868                if ( $q['attachment_id'] )
     1869                        $q['p'] = absint($q['attachment_id']);
     1870
     1871                // If a post number is specified, load that post
     1872                if ( $q['p'] ) {
     1873                        $where .= " AND {$wpdb->posts}.ID = " . $q['p'];
     1874                } elseif ( $q['post__in'] ) {
     1875                        $post__in = implode(',', array_map( 'absint', $q['post__in'] ));
     1876                        $where .= " AND {$wpdb->posts}.ID IN ($post__in)";
     1877                } elseif ( $q['post__not_in'] ) {
     1878                        $post__not_in = implode(',',  array_map( 'absint', $q['post__not_in'] ));
     1879                        $where .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)";
     1880                }
     1881
     1882                if ( is_numeric($q['post_parent']) )
     1883                        $where .= $wpdb->prepare( " AND $wpdb->posts.post_parent = %d ", $q['post_parent'] );
     1884
     1885                if ( $q['page_id'] ) {
     1886                        if  ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) {
     1887                                $q['p'] = $q['page_id'];
     1888                                $where = " AND {$wpdb->posts}.ID = " . $q['page_id'];
     1889                        }
     1890                }
     1891
     1892                // If a search pattern is specified, load the posts that match
     1893                if ( !empty($q['s']) ) {
     1894                        // added slashes screw with quote grouping when done early, so done later
     1895                        $q['s'] = stripslashes($q['s']);
     1896                        if ( !empty($q['sentence']) ) {
     1897                                $q['search_terms'] = array($q['s']);
     1898                        } else {
     1899                                preg_match_all('/".*?("|$)|((?<=[\\s",+])|^)[^\\s",+]+/', $q['s'], $matches);
     1900                                $q['search_terms'] = array_map('_search_terms_tidy', $matches[0]);
     1901                        }
     1902                        $n = !empty($q['exact']) ? '' : '%';
     1903                        $searchand = '';
     1904                        foreach( (array) $q['search_terms'] as $term ) {
     1905                                $term = addslashes_gpc($term);
     1906                                $search .= "{$searchand}(($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}'))";
     1907                                $searchand = ' AND ';
     1908                        }
     1909                        $term = esc_sql($q['s']);
     1910                        if ( empty($q['sentence']) && count($q['search_terms']) > 1 && $q['search_terms'][0] != $q['s'] )
     1911                                $search .= " OR ($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}')";
     1912
     1913                        if ( !empty($search) ) {
     1914                                $search = " AND ({$search}) ";
     1915                                if ( !is_user_logged_in() )
     1916                                        $search .= " AND ($wpdb->posts.post_password = '') ";
     1917                        }
     1918                }
     1919
     1920                // Allow plugins to contextually add/remove/modify the search section of the database query
     1921                $search = apply_filters_ref_array('posts_search', array( $search, &$this ) );
     1922
     1923                // Taxonomies
     1924                if ( !empty( $this->tax_query ) ) {
    19301925                        if ( empty($post_type) ) {
    19311926                                $post_type = 'any';
    … …  
    19351930                        }
    19361931
    1937                         $ids = wp_tax_query( $tax_query );
    1938                         if ( !empty($ids) )
    1939                                 $where .= " AND $wpdb->posts.ID IN(" . implode( ', ', $ids ) . ")";
    1940                         else
    1941                                 $where .= ' AND 0 = 1';
     1932                        $where .= $this->get_tax_sql( "$wpdb->posts.ID" );
    19421933
    19431934                        // Back-compat
    19441935                        if ( !empty( $ids ) ) {
    1945                                 $cat_query = wp_list_filter( $tax_query, array( 'taxonomy' => 'category' ) );
     1936                                $cat_query = wp_list_filter( $this->tax_query, array( 'taxonomy' => 'category' ) );
    19461937                                if ( !empty( $cat_query ) ) {
    19471938                                        $cat_query = reset( $cat_query );
  • trunk/wp-includes/taxonomy.php

    r15712 r15731  
    531531
    532532        return $wpdb->get_col( $sql ); 
    533 }
    534 
    535 /*
    536  * Retrieve object_ids matching one or more taxonomy queries
    537  *
    538  * @since 3.1.0
    539  *
    540  * @param array $queries A list of taxonomy queries. A query is an associative array:
    541  *   'taxonomy' string|array The taxonomy being queried
    542  *   'terms' string|array The list of terms
    543  *   'field' string Which term field is being used. Can be 'term_id', 'slug' or 'name'
    544  *   'operator' string Can be 'IN' and 'NOT IN'
    545  *
    546  * @return array|WP_Error List of matching object_ids; WP_Error on failure.
    547  */
    548 function wp_tax_query( $queries ) {
    549         global $wpdb;
    550 
    551         $sql = array();
    552         foreach ( $queries as $query ) {
    553                 if ( !isset( $query['include_children'] ) )
    554                         $query['include_children'] = true;
    555                 $query['do_query'] = false;
    556                 $sql[] = get_objects_in_term( $query['terms'], $query['taxonomy'], $query );
    557         }
    558 
    559         if ( 1 == count( $sql ) )
    560                 return $wpdb->get_col( $sql[0] );
    561 
    562         $r = "SELECT object_id FROM $wpdb->term_relationships WHERE 1=1";
    563         foreach ( $sql as $query )
    564                 $r .= " AND object_id IN ($query)";
    565 
    566         return $wpdb->get_col( $r );
    567533}
    568534
Note: See TracChangeset for help on using the changeset viewer.