Make WordPress Core

Changeset 55569


Ignore:
Timestamp:
03/21/2023 12:47:20 PM (20 months ago)
Author:
spacedmonkey
Message:

Posts, Post Types: Use WP_Query internally in get_pages.

Convert get_pages to use WP_Query internally. Using WP_Query means that a lot of code has been removed however existing parameters supported by get_pages are transformed in to query arguments. The custom caching solution found in the old version of this function is replaced with the caching found in WP_Query (added in [53941]). This change adds consistency to the codebase, as improvements and changes to WP_Query will filter down to the get_pages function.

Props mikeschinkel, spacedmonkey, nacin, scribu, filosofo, jane, garyc40, markoheijnen, grandslambert, kevinB, wlindley, dbernar1, atimmer, mdawaffe, helen, benjibee, johnbillion, peterwilsoncc, costdev, flixos90, joemcgill.
Fixes #12821.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/post.php

    r55526 r55569  
    58875887 * Retrieves an array of pages (or hierarchical post type items).
    58885888 *
    5889  * @global wpdb $wpdb WordPress database abstraction object.
    5890  *
    58915889 * @since 1.5.0
     5890 * @since 6.3.0 Use WP_Query internally.
    58925891 *
    58935892 * @param array|string $args {
     
    59295928 */
    59305929function get_pages( $args = array() ) {
    5931     global $wpdb;
    5932 
    59335930    $defaults = array(
    59345931        'child_of'     => 0,
     
    59795976    }
    59805977
    5981     // $args can be whatever, only use the args defined in defaults to compute the key.
    5982     $key          = md5( serialize( wp_array_slice_assoc( $parsed_args, array_keys( $defaults ) ) ) );
    5983     $last_changed = wp_cache_get_last_changed( 'posts' );
    5984 
    5985     $cache_key = "get_pages:$key:$last_changed";
    5986     $cache     = wp_cache_get( $cache_key, 'post-queries' );
    5987     if ( false !== $cache ) {
    5988         _prime_post_caches( $cache, false, false );
    5989 
    5990         // Convert to WP_Post instances.
    5991         $pages = array_map( 'get_post', $cache );
    5992         /** This filter is documented in wp-includes/post.php */
    5993         $pages = apply_filters( 'get_pages', $pages, $parsed_args );
    5994 
    5995         return $pages;
    5996     }
    5997 
    5998     $inclusions = '';
     5978    $query_args = array(
     5979        'orderby'                => 'post_title',
     5980        'order'                  => 'ASC',
     5981        'post__not_in'           => wp_parse_id_list( $exclude ),
     5982        'meta_key'               => $meta_key,
     5983        'meta_value'             => $meta_value,
     5984        'posts_per_page'         => -1,
     5985        'offset'                 => $offset,
     5986        'post_type'              => $parsed_args['post_type'],
     5987        'post_status'            => $post_status,
     5988        'update_post_term_cache' => false,
     5989        'update_post_meta_cache' => false,
     5990        'ignore_sticky_posts'    => true,
     5991        'no_found_rows'          => true,
     5992    );
     5993
    59995994    if ( ! empty( $parsed_args['include'] ) ) {
    6000         $child_of     = 0; // Ignore child_of, parent, exclude, meta_key, and meta_value params if using include.
    6001         $parent       = -1;
    6002         $exclude      = '';
    6003         $meta_key     = '';
    6004         $meta_value   = '';
    6005         $hierarchical = false;
    6006         $incpages     = wp_parse_id_list( $parsed_args['include'] );
    6007         if ( ! empty( $incpages ) ) {
    6008             $inclusions = ' AND ID IN (' . implode( ',', $incpages ) . ')';
    6009         }
    6010     }
    6011 
    6012     $exclusions = '';
    6013     if ( ! empty( $exclude ) ) {
    6014         $expages = wp_parse_id_list( $exclude );
    6015         if ( ! empty( $expages ) ) {
    6016             $exclusions = ' AND ID NOT IN (' . implode( ',', $expages ) . ')';
    6017         }
    6018     }
    6019 
    6020     $author_query = '';
     5995        $child_of = 0; // Ignore child_of, parent, exclude, meta_key, and meta_value params if using include.
     5996        $parent   = -1;
     5997        unset( $query_args['post__not_in'], $query_args['meta_key'], $query_args['meta_value'] );
     5998        $hierarchical           = false;
     5999        $query_args['post__in'] = wp_parse_id_list( $parsed_args['include'] );
     6000    }
     6001
    60216002    if ( ! empty( $parsed_args['authors'] ) ) {
    60226003        $post_authors = wp_parse_list( $parsed_args['authors'] );
    60236004
    60246005        if ( ! empty( $post_authors ) ) {
     6006            $query_args['author__in'] = array();
    60256007            foreach ( $post_authors as $post_author ) {
    60266008                // Do we have an author id or an author login?
     
    60356017                    $post_author = $post_author->ID;
    60366018                }
    6037 
    6038                 if ( '' === $author_query ) {
    6039                     $author_query = $wpdb->prepare( ' post_author = %d ', $post_author );
    6040                 } else {
    6041                     $author_query .= $wpdb->prepare( ' OR post_author = %d ', $post_author );
    6042                 }
     6019                $query_args['author__in'][] = $post_author;
    60436020            }
    6044             if ( '' !== $author_query ) {
    6045                 $author_query = " AND ($author_query)";
    6046             }
    6047         }
    6048     }
    6049 
    6050     $join  = '';
    6051     $where = "$exclusions $inclusions ";
    6052     if ( '' !== $meta_key || '' !== $meta_value ) {
    6053         $join = " LEFT JOIN $wpdb->postmeta ON ( $wpdb->posts.ID = $wpdb->postmeta.post_id )";
    6054 
    6055         // meta_key and meta_value might be slashed.
    6056         $meta_key   = wp_unslash( $meta_key );
    6057         $meta_value = wp_unslash( $meta_value );
    6058         if ( '' !== $meta_key ) {
    6059             $where .= $wpdb->prepare( " AND $wpdb->postmeta.meta_key = %s", $meta_key );
    6060         }
    6061         if ( '' !== $meta_value ) {
    6062             $where .= $wpdb->prepare( " AND $wpdb->postmeta.meta_value = %s", $meta_value );
    60636021        }
    60646022    }
    60656023
    60666024    if ( is_array( $parent ) ) {
    6067         $post_parent__in = implode( ',', array_map( 'absint', (array) $parent ) );
     6025        $post_parent__in = array_map( 'absint', (array) $parent );
    60686026        if ( ! empty( $post_parent__in ) ) {
    6069             $where .= " AND post_parent IN ($post_parent__in)";
     6027            $query_args['post_parent__in'] = $post_parent__in;
    60706028        }
    60716029    } elseif ( $parent >= 0 ) {
    6072         $where .= $wpdb->prepare( ' AND post_parent = %d ', $parent );
    6073     }
    6074 
    6075     if ( 1 === count( $post_status ) ) {
    6076         $where_post_type = $wpdb->prepare( 'post_type = %s AND post_status = %s', $parsed_args['post_type'], reset( $post_status ) );
    6077     } else {
    6078         $post_status     = implode( "', '", $post_status );
    6079         $where_post_type = $wpdb->prepare( "post_type = %s AND post_status IN ('$post_status')", $parsed_args['post_type'] );
    6080     }
    6081 
    6082     $orderby_array = array();
    6083     $allowed_keys  = array(
    6084         'author',
    6085         'post_author',
    6086         'date',
    6087         'post_date',
    6088         'title',
    6089         'post_title',
    6090         'name',
    6091         'post_name',
    6092         'modified',
    6093         'post_modified',
    6094         'modified_gmt',
    6095         'post_modified_gmt',
    6096         'menu_order',
    6097         'parent',
    6098         'post_parent',
    6099         'ID',
    6100         'rand',
    6101         'comment_count',
    6102     );
    6103 
    6104     foreach ( explode( ',', $parsed_args['sort_column'] ) as $orderby ) {
    6105         $orderby = trim( $orderby );
    6106         if ( ! in_array( $orderby, $allowed_keys, true ) ) {
    6107             continue;
    6108         }
    6109 
    6110         switch ( $orderby ) {
    6111             case 'menu_order':
    6112                 break;
    6113             case 'ID':
    6114                 $orderby = "$wpdb->posts.ID";
    6115                 break;
    6116             case 'rand':
    6117                 $orderby = 'RAND()';
    6118                 break;
    6119             case 'comment_count':
    6120                 $orderby = "$wpdb->posts.comment_count";
    6121                 break;
    6122             default:
    6123                 if ( 0 === strpos( $orderby, 'post_' ) ) {
    6124                     $orderby = "$wpdb->posts." . $orderby;
    6125                 } else {
    6126                     $orderby = "$wpdb->posts.post_" . $orderby;
    6127                 }
    6128         }
    6129 
    6130         $orderby_array[] = $orderby;
    6131 
    6132     }
    6133     $sort_column = ! empty( $orderby_array ) ? implode( ',', $orderby_array ) : "$wpdb->posts.post_title";
    6134 
    6135     $sort_order = strtoupper( $parsed_args['sort_order'] );
    6136     if ( '' !== $sort_order && ! in_array( $sort_order, array( 'ASC', 'DESC' ), true ) ) {
    6137         $sort_order = 'ASC';
    6138     }
    6139 
    6140     $query  = "SELECT * FROM $wpdb->posts $join WHERE ($where_post_type) $where ";
    6141     $query .= $author_query;
    6142     $query .= ' ORDER BY ' . $sort_column . ' ' . $sort_order;
     6030        $query_args['post_parent'] = $parent;
     6031    }
     6032
     6033    $orderby = wp_parse_list( $parsed_args['sort_column'] );
     6034    $orderby = array_map( 'trim', $orderby );
     6035    if ( $orderby ) {
     6036        $query_args['orderby'] = array_fill_keys( $orderby, $parsed_args['sort_order'] );
     6037    }
     6038
     6039    $order = $parsed_args['sort_order'];
     6040    if ( $order ) {
     6041        $query_args['order'] = $order;
     6042    }
    61436043
    61446044    if ( ! empty( $number ) ) {
    6145         $query .= ' LIMIT ' . $offset . ',' . $number;
    6146     }
    6147 
    6148     $pages = $wpdb->get_results( $query );
    6149 
    6150     if ( empty( $pages ) ) {
    6151         wp_cache_set( $cache_key, array(), 'post-queries' );
    6152 
    6153         /** This filter is documented in wp-includes/post.php */
    6154         $pages = apply_filters( 'get_pages', array(), $parsed_args );
    6155 
    6156         return $pages;
    6157     }
    6158 
    6159     // Sanitize before caching so it'll only get done once.
    6160     $num_pages = count( $pages );
    6161     for ( $i = 0; $i < $num_pages; $i++ ) {
    6162         $pages[ $i ] = sanitize_post( $pages[ $i ], 'raw' );
    6163     }
    6164 
    6165     // Update cache.
    6166     update_post_cache( $pages );
     6045        $query_args['posts_per_page'] = $number;
     6046    }
     6047
     6048    $query = new WP_Query( $query_args );
     6049    $pages = $query->get_posts();
    61676050
    61686051    if ( $child_of || $hierarchical ) {
     
    61866069        }
    61876070    }
    6188 
    6189     $page_structure = array();
    6190     foreach ( $pages as $page ) {
    6191         $page_structure[] = $page->ID;
    6192     }
    6193 
    6194     wp_cache_set( $cache_key, $page_structure, 'post-queries' );
    6195 
    6196     // Convert to WP_Post instances.
    6197     $pages = array_map( 'get_post', $pages );
    61986071
    61996072    /**
  • trunk/tests/phpunit/tests/post/getPages.php

    r54402 r55569  
    6767        clean_post_cache( $pages[0]->ID );
    6868        $this->assertNotEquals( $time1, $time2 = wp_cache_get( 'last_changed', 'posts' ) );
    69 
     69        get_post( $pages[0]->ID );
    7070        $num_queries = $wpdb->num_queries;
    7171
     
    171171        $found_ids = wp_list_pluck( $found, 'ID' );
    172172        $this->assertSameSets( array( $posts[0] ), $found_ids );
     173    }
     174
     175    /**
     176     * @ticket 12821
     177     * @covers ::get_pages
     178     */
     179    public function test_include_ignore_meta_key() {
     180        $posts = self::factory()->post->create_many(
     181            2,
     182            array(
     183                'post_type' => 'page',
     184            )
     185        );
     186
     187        $pages = get_pages(
     188            array(
     189                'include'    => $posts,
     190                'meta_key'   => 'foo',
     191                'meta_value' => 'bar',
     192            )
     193        );
     194
     195        $page_ids = wp_list_pluck( $pages, 'ID' );
     196        $this->assertSameSets( $posts, $page_ids );
     197    }
     198
     199    /**
     200     * @ticket 12821
     201     * @covers ::get_pages
     202     */
     203    public function test_include_ignore_exclude() {
     204        $includes = self::factory()->post->create_many(
     205            2,
     206            array(
     207                'post_type' => 'page',
     208            )
     209        );
     210
     211        $excludes = self::factory()->post->create_many(
     212            2,
     213            array(
     214                'post_type' => 'page',
     215            )
     216        );
     217
     218        $pages = get_pages(
     219            array(
     220                'include' => $includes,
     221                'exclude' => $excludes,
     222            )
     223        );
     224
     225        $page_ids = wp_list_pluck( $pages, 'ID' );
     226        $this->assertSameSets( $includes, $page_ids );
    173227    }
    174228
     
    720774        $this->assertSame( $num_queries, $wpdb->num_queries );
    721775    }
     776
     777    /**
     778     * @ticket 12821
     779     * @covers ::get_pages
     780     */
     781    public function test_get_pages_post_type() {
     782        register_post_type( 'wptests_pt', array( 'hierarchical' => true ) );
     783        $posts = self::factory()->post->create_many( 2, array( 'post_type' => 'wptests_pt' ) );
     784        $pages = get_pages(
     785            array(
     786                'post_type' => 'wptests_pt',
     787            )
     788        );
     789        $this->assertSameSets( $posts, wp_list_pluck( $pages, 'ID' ) );
     790    }
     791
     792
     793    /**
     794     * @ticket 12821
     795     * @covers ::get_pages
     796     */
     797    public function test_get_pages_author() {
     798        $author_1 = self::factory()->user->create(
     799            array(
     800                'user_login' => 'author1',
     801                'role'       => 'author',
     802            )
     803        );
     804        $posts    = self::factory()->post->create_many(
     805            2,
     806            array(
     807                'post_type'   => 'page',
     808                'post_author' => $author_1,
     809            )
     810        );
     811        $pages    = get_pages(
     812            array(
     813                'authors' => $author_1,
     814            )
     815        );
     816
     817        $this->assertSameSets( $posts, wp_list_pluck( $pages, 'ID' ) );
     818    }
     819
     820
     821    /**
     822     * @ticket 12821
     823     * @covers ::get_pages
     824     */
     825    public function test_get_pages_post_status() {
     826        register_post_status(
     827            'foo',
     828            array(
     829                'public' => true,
     830            )
     831        );
     832
     833        $posts = self::factory()->post->create_many(
     834            2,
     835            array(
     836                'post_type'   => 'page',
     837                'post_status' => 'foo',
     838            )
     839        );
     840        $pages = get_pages(
     841            array(
     842                'post_status' => 'foo',
     843            )
     844        );
     845
     846        $this->assertSameSets( $posts, wp_list_pluck( $pages, 'ID' ) );
     847    }
     848
     849    /**
     850     * @ticket 12821
     851     * @covers ::get_pages
     852     */
     853    public function test_get_pages_offset() {
     854        $posts = self::factory()->post->create_many( 4, array( 'post_type' => 'page' ) );
     855        $pages = get_pages(
     856            array(
     857                'offset' => 2,
     858                'number' => 2,
     859            )
     860        );
     861
     862        $this->assertSameSets( array( $posts[2], $posts[3] ), wp_list_pluck( $pages, 'ID' ) );
     863    }
     864
     865
     866    /**
     867     * @ticket 12821
     868     * @covers ::get_pages
     869     */
     870    public function test_get_pages_authors() {
     871        $author_1 = self::factory()->user->create(
     872            array(
     873                'user_login' => 'author1',
     874                'role'       => 'author',
     875            )
     876        );
     877        $post_1   = self::factory()->post->create(
     878            array(
     879                'post_title'  => 'Page 1',
     880                'post_type'   => 'page',
     881                'post_author' => $author_1,
     882                'post_date'   => '2007-01-01 00:00:00',
     883            )
     884        );
     885
     886        $author_2 = self::factory()->user->create(
     887            array(
     888                'user_login' => 'author2',
     889                'role'       => 'author',
     890            )
     891        );
     892        $post_2   = self::factory()->post->create(
     893            array(
     894                'post_title'  => 'Page 2',
     895                'post_type'   => 'page',
     896                'post_author' => $author_2,
     897                'post_date'   => '2007-01-01 00:00:00',
     898            )
     899        );
     900        $pages    = get_pages(
     901            array(
     902                'authors' => "{$author_1}, {$author_2}",
     903            )
     904        );
     905
     906        $this->assertSameSets( array( $post_1, $post_2 ), wp_list_pluck( $pages, 'ID' ) );
     907    }
     908
     909    /**
     910     * @ticket 12821
     911     * @covers ::get_pages
     912     */
     913    public function test_get_pages_authors_names() {
     914        $author_1 = self::factory()->user->create(
     915            array(
     916                'user_login' => 'author1',
     917                'role'       => 'author',
     918            )
     919        );
     920        $post_1   = self::factory()->post->create(
     921            array(
     922                'post_title'  => 'Page 1',
     923                'post_type'   => 'page',
     924                'post_author' => $author_1,
     925                'post_date'   => '2007-01-01 00:00:00',
     926            )
     927        );
     928
     929        $author_2 = self::factory()->user->create(
     930            array(
     931                'user_login' => 'author2',
     932                'role'       => 'author',
     933            )
     934        );
     935        $post_2   = self::factory()->post->create(
     936            array(
     937                'post_title'  => 'Page 2',
     938                'post_type'   => 'page',
     939                'post_author' => $author_2,
     940                'post_date'   => '2007-01-01 00:00:00',
     941            )
     942        );
     943        $pages    = get_pages(
     944            array(
     945                'authors' => 'author1, author2',
     946            )
     947        );
     948
     949        $this->assertSameSets( array( $post_1, $post_2 ), wp_list_pluck( $pages, 'ID' ) );
     950    }
     951
     952    /**
     953     * @ticket 12821
     954     * @covers ::get_pages
     955     */
     956    public function test_orderby() {
     957        global $wpdb;
     958        // 'rand' is a valid value.
     959        get_pages( array( 'sort_column' => 'rand' ) );
     960        $this->assertStringContainsString( 'ORDER BY RAND()', $wpdb->last_query, 'Check order is random' );
     961
     962        // This isn't allowed.
     963        get_pages( array( 'sort_order' => 'rand' ) );
     964        $this->assertStringContainsString( 'ORDER BY', $wpdb->last_query, 'Check orderby is present' );
     965        $this->assertStringNotContainsString( 'RAND()', $wpdb->last_query, 'Check order is random is not present' );
     966        $this->assertStringContainsString( 'DESC', $wpdb->last_query, 'Check DESC is random is not present' );
     967
     968        // 'none' is a valid value.
     969        get_pages( array( 'sort_column' => 'none' ) );
     970        $this->assertStringNotContainsString( 'ORDER BY', $wpdb->last_query, 'Check orderby is not present' );
     971        $this->assertStringNotContainsString( 'DESC', $wpdb->last_query, 'Check DESC is not present' );
     972        $this->assertStringNotContainsString( 'ASC', $wpdb->last_query, 'Check ASC is not present' );
     973
     974        // False is a valid value.
     975        get_pages( array( 'sort_column' => false ) );
     976        $this->assertStringContainsString( 'ORDER BY', $wpdb->last_query, 'Check orderby is present if sort_column equal false is passed.' );
     977
     978        // Empty array() is a valid value.
     979        get_pages( array( 'sort_column' => array() ) );
     980        $this->assertStringContainsString( 'ORDER BY', $wpdb->last_query, 'Check orderby is present  if sort_column equals an empty array is passed.' );
     981    }
     982
     983    /**
     984     * @ticket 12821
     985     * @covers ::get_pages
     986     */
     987    public function test_order() {
     988        global $wpdb;
     989
     990        get_pages(
     991            array(
     992                'sort_column' => 'post_type',
     993            )
     994        );
     995        $this->assertStringContainsString(
     996            "ORDER BY $wpdb->posts.post_type ASC",
     997            $wpdb->last_query,
     998            'Check order is post type'
     999        );
     1000
     1001        get_pages(
     1002            array(
     1003                'sort_column' => 'title',
     1004                'sort_order'  => 'foo',
     1005            )
     1006        );
     1007        $this->assertStringContainsString(
     1008            "ORDER BY $wpdb->posts.post_title DESC",
     1009            $wpdb->last_query,
     1010            'Check order is default'
     1011        );
     1012
     1013        get_pages(
     1014            array(
     1015                'sort_order'  => 'asc',
     1016                'sort_column' => 'date',
     1017            )
     1018        );
     1019        $this->assertStringContainsString(
     1020            "ORDER BY $wpdb->posts.post_date ASC",
     1021            $wpdb->last_query,
     1022            'Check order is post date'
     1023        );
     1024    }
    7221025}
Note: See TracChangeset for help on using the changeset viewer.