WordPress.org

Make WordPress Core

Ticket #12891: scale.12891.4.diff

File scale.12891.4.diff, 8.7 KB (added by scribu, 8 years ago)

Use JOINs

  • wp-includes/taxonomy.php

     
    460460 * @uses $wpdb
    461461 * @uses wp_parse_args() Creates an array from string $args.
    462462 *
    463  * @param mixed $terms Term id/slug/name or array of such to match against
     463 * @param int|array $term_ids Term id or array of term ids of terms that will be used
    464464 * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names
    465  * @param array|string $args
    466  *   'include_children' bool Whether to include term children (hierarchical taxonomies only)
    467  *   'field' string Which term field is being used. Can be 'term_id', 'slug' or 'name'
    468  *   'operator' string Can be 'IN' and 'NOT IN'
    469  *   'do_query' bool Whether to execute the query or return the SQL string
    470  *
    471  * @return WP_Error If the taxonomy does not exist
    472  * @return array The list of found object_ids
    473  * @return string The SQL string, if do_query is set to false
     465 * @param array|string $args Change the order of the object_ids, either ASC or DESC
     466 * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success
     467 *      the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
    474468 */
    475 function get_objects_in_term( $terms, $taxonomies, $args = array() ) {
     469function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
    476470        global $wpdb;
    477471
    478         extract( wp_parse_args( $args, array(
    479                 'include_children' => false,
    480                 'field' => 'term_id',
    481                 'operator' => 'IN',
    482                 'do_query' => true,
    483         ) ), EXTR_SKIP );
     472        if ( ! is_array( $term_ids ) )
     473                $term_ids = array( $term_ids );
    484474
    485         $taxonomies = (array) $taxonomies;
     475        if ( ! is_array( $taxonomies ) )
     476                $taxonomies = array( $taxonomies );
    486477
    487         foreach ( $taxonomies as $taxonomy ) {
     478        foreach ( (array) $taxonomies as $taxonomy ) {
    488479                if ( ! taxonomy_exists( $taxonomy ) )
    489                         return new WP_Error( 'invalid_taxonomy', sprintf( __( 'Invalid Taxonomy: %s' ), $taxonomy ) );
     480                        return new WP_Error( 'invalid_taxonomy', __( 'Invalid Taxonomy' ) );
    490481        }
    491482
    492         if ( !in_array( $field, array( 'term_id', 'slug', 'name' ) ) )
    493                 $field = 'term_id';
     483        $defaults = array( 'order' => 'ASC' );
     484        $args = wp_parse_args( $args, $defaults );
     485        extract( $args, EXTR_SKIP );
    494486
    495         if ( !in_array( $operator, array( 'IN', 'NOT IN' ) ) )
    496                 $operator = 'IN';
     487        $order = ( 'desc' == strtolower( $order ) ) ? 'DESC' : 'ASC';
    497488
    498         $terms = array_unique( (array) $terms );
     489        $term_ids = array_map('intval', $term_ids );
    499490
    500         if ( is_taxonomy_hierarchical( $taxonomy ) && $include_children ) {
    501                 $children = array();
    502                 foreach ( $terms as $term ) {
    503                         if ( 'term_id' != $field ) {
    504                                 if ( $term = get_term_by( $field, $term, $taxonomy ) )
    505                                         $term = $term->term_id;
    506                                 else
    507                                         continue;
    508                         }
    509                         $children = array_merge( $children, get_term_children( $term, $taxonomy ) );
    510                         $children[] = $term;
    511                 }
    512                 $terms = $children;
    513                 $field = 'term_id';
    514         }
    515 
    516         if ( empty( $terms ) )
    517                 return $do_query ? array() : '';
    518 
    519491        $taxonomies = "'" . implode( "', '", $taxonomies ) . "'";
     492        $term_ids = "'" . implode( "', '", $term_ids ) . "'";
    520493
    521         switch ( $field ) {
    522                 case 'term_id':
    523                         $terms = array_map( 'intval', $terms );
     494        $object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order");
    524495
    525                         $terms = implode( ',', $terms );
    526                         $sql = "
    527                                 SELECT object_id
    528                                 FROM $wpdb->term_relationships
    529                                 INNER JOIN $wpdb->term_taxonomy USING (term_taxonomy_id)
    530                                 WHERE taxonomy IN ($taxonomies)
    531                                 AND term_id $operator ($terms)
    532                         ";
    533                 break;
     496        if ( ! $object_ids )
     497                return array();
    534498
    535                 case 'slug':
    536                 case 'name':
    537                         foreach ( $terms as $i => $term ) {
    538                                 $terms[$i] = sanitize_title_for_query( $term );
    539                         }
    540                         $terms = array_filter($terms);
    541 
    542                         $terms = "'" . implode( "','", $terms ) . "'";
    543                         $sql = "
    544                                 SELECT object_id
    545                                 FROM $wpdb->term_relationships
    546                                 INNER JOIN $wpdb->term_taxonomy USING (term_taxonomy_id)
    547                                 INNER JOIN $wpdb->terms USING (term_id)
    548                                 WHERE taxonomy IN ($taxonomies)
    549                                 AND $field $operator ($terms)
    550                         ";
    551                 break;
    552         }
    553 
    554         return $do_query ? $wpdb->get_col( $sql ) : $sql;
     499        return $object_ids;
    555500}
    556501
    557502/*
     
    571516 * - 'include_children' bool (optional) Whether to include child terms.
    572517 *              Default: true
    573518 *
    574  * @param string $object_id_column
     519 * @param string $primary_table
     520 * @param string $primary_id_column
    575521 * @return string
    576522 */
    577 function get_tax_sql( $tax_query, $object_id_column ) {
     523function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) {
    578524        global $wpdb;
    579525
    580         $sql = array();
     526        $join = '';
     527        $where = '';
     528        $i = 0;
    581529        foreach ( $tax_query as $query ) {
    582                 if ( !isset( $query['include_children'] ) )
    583                         $query['include_children'] = true;
     530                extract( wp_parse_args( $query, array(
     531                        'taxonomy' => array(),
     532                        'terms' => array(),
     533                        'include_children' => true,
     534                        'field' => 'term_id',
     535                        'operator' => 'IN',
     536                ) ) );
    584537
    585                 $query['do_query'] = false;
     538                $taxonomies = (array) $taxonomy;
    586539
    587                 $sql_single = get_objects_in_term( $query['terms'], $query['taxonomy'], $query );
     540                foreach ( $taxonomies as $taxonomy ) {
     541                        if ( ! taxonomy_exists( $taxonomy ) )
     542                                return ' AND 0 = 1';
     543                }
    588544
    589                 if ( empty( $sql_single ) || is_wp_error( $sql_single ) )
    590                         return ' AND 0 = 1';
     545                if ( !in_array( $operator, array( 'IN', 'NOT IN' ) ) )
     546                        $operator = 'IN';
    591547
    592                 $sql[] = $sql_single;
    593         }
     548                $taxonomies = "'" . implode( "', '", $taxonomies ) . "'";
    594549
    595         if ( 1 == count( $sql ) ) {
    596                 $ids = $wpdb->get_col( $sql[0] );
    597         } else {
    598                 $r = "SELECT object_id FROM $wpdb->term_relationships WHERE 1=1";
    599                 foreach ( $sql as $query )
    600                         $r .= " AND object_id IN ($query)";
     550                $terms = array_unique( (array) $terms );
    601551
    602                 $ids = $wpdb->get_col( $r );
     552                if ( empty( $terms ) )
     553                        continue;
     554
     555                if ( is_taxonomy_hierarchical( $taxonomy ) && $include_children ) {
     556                        $terms = _get_existing_terms( $field, $terms, $taxonomies, 'term_id' );
     557
     558                        if ( empty( $terms ) )
     559                                continue;
     560
     561                        $children = array();
     562                        foreach ( $terms as $term ) {
     563                                $children = array_merge( $children, get_term_children( $term, $taxonomy ) );
     564                                $children[] = $term;
     565                        }
     566                        $terms = _get_existing_terms( 'term_id', $children, $taxonomies, 'term_taxonomy_id' );
     567                }
     568                else {
     569                        $terms = _get_existing_terms( $field, $terms, $taxonomies, 'term_taxonomy_id' );
     570                }
     571
     572                if ( empty( $terms ) )
     573                        continue;
     574
     575                $alias = $i ? 'tt' . $i : $wpdb->term_relationships;
     576
     577                $join .= "\nINNER JOIN $wpdb->term_relationships";
     578                $join .= $i ? " AS $alias" : '';
     579                $join .= " ON ($primary_table.$primary_id_column = $alias.object_id)";
     580
     581                $terms = implode( ',', $terms );
     582
     583                $where .= " AND $alias.term_taxonomy_id $operator ($terms)";
     584
     585                $i++;
    603586        }
    604587
    605         if ( !empty( $ids ) )
    606                 return " AND $object_id_column IN(" . implode( ', ', $ids ) . ")";
    607         else
    608                 return ' AND 0 = 1';
     588        return compact( 'join', 'where' );
    609589}
    610590
     591function _get_existing_terms( $field, &$terms, $taxonomies, $resulting_field ) {
     592        global $wpdb;
    611593
     594        $resulting_field = esc_sql( $resulting_field );
     595
     596        switch ( $field ) {
     597                case 'slug':
     598                case 'name':
     599                        $terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $terms ) ) . "'";
     600                        return $wpdb->get_col( "
     601                                SELECT $resulting_field
     602                                FROM $wpdb->term_taxonomy
     603                                INNER JOIN $wpdb->terms USING (term_id)
     604                                WHERE taxonomy IN ($taxonomies)
     605                                AND $field IN ($terms)
     606                        " );
     607                        break;
     608
     609                default:
     610                        $terms = implode( ',', array_map( 'intval', $terms ) );
     611                        return $wpdb->get_col( "
     612                                SELECT $resulting_field
     613                                FROM $wpdb->term_taxonomy
     614                                WHERE taxonomy IN ($taxonomies)
     615                                AND term_id IN ($terms)
     616                        " );
     617        }
     618}
     619
    612620/**
    613621 * Get all Term data from database by Term ID.
    614622 *
  • wp-includes/query.php

     
    19331933                // Taxonomies
    19341934                $q['tax_query'] = $this->parse_tax_query( $q );
    19351935                if ( !empty( $q['tax_query'] ) ) {
     1936                        $clauses = call_user_func_array( 'get_tax_sql', array( $q['tax_query'], $wpdb->posts, 'ID', &$this) );
     1937
     1938                        $join .= $clauses['join'];
     1939                        $where .= $clauses['where'];
     1940
    19361941                        if ( empty($post_type) ) {
    19371942                                $post_type = 'any';
    19381943                                $post_status_join = true;
     
    19401945                                $post_status_join = true;
    19411946                        }
    19421947
    1943                         $where .= get_tax_sql( $q['tax_query'], "$wpdb->posts.ID" );
    1944 
    19451948                        // Back-compat
    19461949                        $tax_query_in = wp_list_filter( $q['tax_query'], array( 'operator' => 'IN' ) );
    19471950                        if ( !empty( $tax_query_in ) ) {