Make WordPress Core

Changeset 15731


Ignore:
Timestamp:
10/06/2010 10:40:30 AM (14 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.