WordPress.org

Make WordPress Core

Changeset 15731


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