Make WordPress Core

Opened 7 years ago

Closed 7 years ago

Last modified 2 years ago

#41866 closed defect (bug) (invalid)

REST API throws error when displaying an unlimited number of posts in a request

Reported by: dpsjfveloso1's profile dpsjfveloso1 Owned by:
Milestone: Priority: normal
Severity: normal Version: 4.9
Component: REST API Keywords:
Focuses: rest-api Cc:

Description

Hi there,

The REST API posts/pages endpoints fails when using a filter to set the posts_per_page as -1, it throws a WP_Error, rest_post_invalid_page_number, as the number of max pages, $max_pages, is negative as the posts_per_page has a negative value (-1).

The error can be reproduced by applying a filter for the rest_page_query filter, setting the posts_per_page argument as -1:

<?php
function remove_posts_limits( array $arguments = array(), \WP_REST_Request $restApiRequest ) {
    // Let's suppose that we want to remove the number of posts per page as unlimited under certain conditions, and this is the reason why we use this filter
    $arguments[ 'posts_per_page' ] = -1;

    return $arguments;
}

add_filter( 'rest_page_query', 'remove_posts_limits', 10, 2);

The issue is caused due to the way that $max_pages is set (file /wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php, starts at line 326):

<?php
/*
.
.
.
*/
$max_pages = ceil( $total_posts / (int) $posts_query->query_vars['posts_per_page'] );

                if ( $page > $max_pages && $total_posts > 0 ) {
                        return new WP_Error( 'rest_post_invalid_page_number', __( 'The page number requested is larger than the number of pages available.' ), array( 'status' => 400 ) );
                }

/*
.
.
.
*/

The simplest solution here would be to use the abs() after casting posts_per_page value:

<?php
/*
.
.
.
*/

$max_pages = ceil( $total_posts / abs( (int) $posts_query->query_vars['posts_per_page'] ) );

/*
.
.
.
*/

But the $max_pages could also be set inside of an if clause, as the value of $max_pages should be one in all cases (this would be a better solution):

<?php
/*
.
.
.
*/

$posts_per_page = (int) $posts_query->query_vars['posts_per_page'];

$max_pages = ceil( $total_posts / $posts_per_page );

if ($posts_per_page < 0) {
    // It's an unlimited number of posts per page, which means that $max_pages must be 1
    $max_pages = 1;
}

/*
.
.
.
*/

Thanks,
Jorge

Change History (4)

#1 @JPry
7 years ago

  • Keywords close added
  • Resolution set to invalid
  • Status changed from new to closed

Hi @dpsjfveloso1,

Thanks for taking the time to make this report, and welcome to Trac! This particular behavior is by design. As described in this comment from the WP-API GitHub repo, querying for all posts should be done via iteration, rather than a single massive query.

#2 @SergeyBiryukov
7 years ago

  • Keywords close removed
  • Milestone Awaiting Review deleted

#3 @SergeyBiryukov
7 years ago

  • Focuses administration template multisite performance removed

#4 @onetarek
2 years ago

I am getting the same problem on WP version 6.1.1.

Using the REST URL '/wp-json/wp/v2/events/' I am fetching all events posts. My code is modifying the wp-query object to set posts_per_page = -1 via pre_get_posts hook.

<?php
add_action( 'pre_get_posts', array($this, 'qw_pre_get_posts') );

function qw_pre_get_posts( $query ){

        if( !is_admin() && !is_home() && !is_page()){

                $meta_query = array(
      'relation' => 'OR',
      array(
        'key' => 'sticky',
        'value' => array(1, '1', true, 0, '0', false, 'on')
      ),
      array(
        'key' => '_qw_events_date',
      )
    );

    $query->set( 'meta_query', $meta_query );
    $query->set( 'orderby', 'meta_value' );
    $query->set('meta_key', '_qw_events_date');
    $query->set('order', 'ASC');
    $query->set('posts_per_page', -1);

   }
}

REST RESPONSE:

[{"id":1468,"date":"2022-07-29T13:14:37","date_gmt":"2022-07-29T17:14:37","guid":{"rendered":"http:\/\/example.com\/?post_type=events&#038;p=1468"},"modified":"2022-11-14T09:58:50","modified_gmt":"2022-11-14T13:58:50","slug":"greensboro-symphony-with-michael-feinstein","type":"events","link":"https:\/\/example.com\/events......

My code was working perfectly on WP version 4.6.25. After updating to version 6.1.1 I am getting the following response from REST API.

REST RESPONSE:
'

{"code":"rest_post_invalid_page_number","message":"The page number requested is larger than the number of pages available.","data":{"status":400}}

'

If I disable the line '$query->set('posts_per_page', -1);' REST API returns event post data.

Note: See TracTickets for help on using tickets.