From 767719c329423d2c06ecb6a808d1bbf9728ea673 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Wed, 19 Jun 2019 15:35:05 +0100 Subject: [PATCH] Improve pagination header generation --- ...-product-attribute-terms-v1-controller.php | 3 +- .../Version4/AbstractObjectsController.php | 38 +-------- .../Version4/AbstractTermsContoller.php | 28 ++----- src/Controllers/Version4/Customers.php | 23 +----- src/Controllers/Version4/ProductReviews.php | 24 +----- src/Controllers/Version4/Taxes.php | 24 ++---- .../Version4/Utilities/Pagination.php | 81 +++++++++++++++++++ src/Controllers/Version4/Webhooks.php | 26 ++---- 8 files changed, 108 insertions(+), 139 deletions(-) create mode 100644 src/Controllers/Version4/Utilities/Pagination.php diff --git a/src/Controllers/Version1/class-wc-rest-product-attribute-terms-v1-controller.php b/src/Controllers/Version1/class-wc-rest-product-attribute-terms-v1-controller.php index 76d43c5cd90..6142998d003 100644 --- a/src/Controllers/Version1/class-wc-rest-product-attribute-terms-v1-controller.php +++ b/src/Controllers/Version1/class-wc-rest-product-attribute-terms-v1-controller.php @@ -40,7 +40,8 @@ class WC_REST_Product_Attribute_Terms_V1_Controller extends WC_REST_Terms_Contro * Register the routes for terms. */ public function register_routes() { - register_rest_route( $this->namespace, '/' . $this->rest_base, array( + register_rest_route( $this->namespace, '/' . $this->rest_base, + array( 'args' => array( 'attribute_id' => array( 'description' => __( 'Unique identifier for the attribute of the terms.', 'woocommerce' ), diff --git a/src/Controllers/Version4/AbstractObjectsController.php b/src/Controllers/Version4/AbstractObjectsController.php index fb0c1ec10b2..21cec24457d 100644 --- a/src/Controllers/Version4/AbstractObjectsController.php +++ b/src/Controllers/Version4/AbstractObjectsController.php @@ -9,7 +9,8 @@ namespace WooCommerce\RestApi\Controllers\Version4; defined( 'ABSPATH' ) || exit; -use \WooCommerce\RestApi\Controllers\Version4\Utilities\Permissions; +use WooCommerce\RestApi\Controllers\Version4\Utilities\Permissions; +use WooCommerce\RestApi\Controllers\Version4\Utilities\Pagination; /** * CRUD Object Controller. @@ -296,42 +297,11 @@ abstract class AbstractObjectsController extends AbstractController { $objects[] = $this->prepare_response_for_collection( $data ); } - $page = (int) $query_args['paged']; + $total = $query_results['total']; $max_pages = $query_results['pages']; $response = rest_ensure_response( $objects ); - $response->header( 'X-WP-Total', $query_results['total'] ); - $response->header( 'X-WP-TotalPages', (int) $max_pages ); - - $base = $this->rest_base; - $attrib_prefix = '(?P<'; - if ( strpos( $base, $attrib_prefix ) !== false ) { - $attrib_names = array(); - preg_match( '/\(\?P<[^>]+>.*\)/', $base, $attrib_names, PREG_OFFSET_CAPTURE ); - foreach ( $attrib_names as $attrib_name_match ) { - $beginning_offset = strlen( $attrib_prefix ); - $attrib_name_end = strpos( $attrib_name_match[0], '>', $attrib_name_match[1] ); - $attrib_name = substr( $attrib_name_match[0], $beginning_offset, $attrib_name_end - $beginning_offset ); - if ( isset( $request[ $attrib_name ] ) ) { - $base = str_replace( "(?P<$attrib_name>[\d]+)", $request[ $attrib_name ], $base ); - } - } - } - $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ) ); - - if ( $page > 1 ) { - $prev_page = $page - 1; - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - if ( $max_pages > $page ) { - $next_page = $page + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - $response->link_header( 'next', $next_link ); - } + $response = Pagination::add_pagination_headers( $response, $request, $total, $max_pages ); return $response; } diff --git a/src/Controllers/Version4/AbstractTermsContoller.php b/src/Controllers/Version4/AbstractTermsContoller.php index ffcf6870ba4..f86b7886eae 100644 --- a/src/Controllers/Version4/AbstractTermsContoller.php +++ b/src/Controllers/Version4/AbstractTermsContoller.php @@ -9,7 +9,8 @@ namespace WooCommerce\RestApi\Controllers\Version4; defined( 'ABSPATH' ) || exit; -use \WooCommerce\RestApi\Controllers\Version4\Utilities\Permissions; +use WooCommerce\RestApi\Controllers\Version4\Utilities\Permissions; +use WooCommerce\RestApi\Controllers\Version4\Utilities\Pagination; /** * Terms controller class. @@ -203,31 +204,12 @@ abstract class AbstractTermsContoller extends AbstractController { $response[] = $this->prepare_response_for_collection( $data ); } - $response = rest_ensure_response( $response ); - // Store pagination values for headers then unset for count query. - $per_page = (int) $prepared_args['number']; - $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); - - $response->header( 'X-WP-Total', (int) $total_terms ); + $per_page = (int) $prepared_args['number']; $max_pages = ceil( $total_terms / $per_page ); - $response->header( 'X-WP-TotalPages', (int) $max_pages ); - $base = str_replace( '(?P[\d]+)', $request['attribute_id'], $this->rest_base ); - $base = add_query_arg( $request->get_query_params(), rest_url( '/' . $this->namespace . '/' . $base ) ); - if ( $page > 1 ) { - $prev_page = $page - 1; - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - if ( $max_pages > $page ) { - $next_page = $page + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - $response->link_header( 'next', $next_link ); - } + $response = rest_ensure_response( $response ); + $response = Pagination::add_pagination_headers( $response, $request, $total_terms, $max_pages ); return $response; } diff --git a/src/Controllers/Version4/Customers.php b/src/Controllers/Version4/Customers.php index 091bfd4e61f..fc7c8af0cd5 100644 --- a/src/Controllers/Version4/Customers.php +++ b/src/Controllers/Version4/Customers.php @@ -14,6 +14,7 @@ defined( 'ABSPATH' ) || exit; use \WP_REST_Server; use WooCommerce\RestApi\Controllers\Version4\Requests\CustomerRequest; use WooCommerce\RestApi\Controllers\Version4\Responses\CustomerResponse; +use WooCommerce\RestApi\Controllers\Version4\Utilities\Pagination; /** * REST API Customers controller class. @@ -190,8 +191,6 @@ class Customers extends AbstractController { $users[] = $this->prepare_response_for_collection( $data ); } - $response = rest_ensure_response( $users ); - // Store pagination values for headers then unset for count query. $per_page = (int) $prepared_args['number']; $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); @@ -199,6 +198,7 @@ class Customers extends AbstractController { $prepared_args['fields'] = 'ID'; $total_users = $query->get_total(); + if ( $total_users < 1 ) { // Out-of-bounds, run the query again without LIMIT for total count. unset( $prepared_args['number'] ); @@ -206,24 +206,9 @@ class Customers extends AbstractController { $count_query = new \ WP_User_Query( $prepared_args ); $total_users = $count_query->get_total(); } - $response->header( 'X-WP-Total', (int) $total_users ); - $max_pages = ceil( $total_users / $per_page ); - $response->header( 'X-WP-TotalPages', (int) $max_pages ); - $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) ); - if ( $page > 1 ) { - $prev_page = $page - 1; - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - if ( $max_pages > $page ) { - $next_page = $page + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - $response->link_header( 'next', $next_link ); - } + $response = rest_ensure_response( $users ); + $response = Pagination::add_pagination_headers( $response, $request, $total_users, ceil( $total_users / $per_page ) ); return $response; } diff --git a/src/Controllers/Version4/ProductReviews.php b/src/Controllers/Version4/ProductReviews.php index 35c1d5b27ba..2b6922f330d 100644 --- a/src/Controllers/Version4/ProductReviews.php +++ b/src/Controllers/Version4/ProductReviews.php @@ -13,6 +13,7 @@ defined( 'ABSPATH' ) || exit; use WooCommerce\RestApi\Controllers\Version4\Responses\ProductReviewResponse; use WooCommerce\RestApi\Controllers\Version4\Utilities\Permissions; +use WooCommerce\RestApi\Controllers\Version4\Utilities\Pagination; /** * REST API Product Reviews controller class. @@ -242,28 +243,7 @@ class ProductReviews extends AbstractController { } $response = rest_ensure_response( $reviews ); - $response->header( 'X-WP-Total', $total_reviews ); - $response->header( 'X-WP-TotalPages', $max_pages ); - - $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) ); - - if ( $request['page'] > 1 ) { - $prev_page = $request['page'] - 1; - - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - - if ( $max_pages > $request['page'] ) { - $next_page = $request['page'] + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - - $response->link_header( 'next', $next_link ); - } + $response = Pagination::add_pagination_headers( $response, $request, $total_reviews, $max_pages ); return $response; } diff --git a/src/Controllers/Version4/Taxes.php b/src/Controllers/Version4/Taxes.php index 4cddea1b2a4..2fb84276569 100644 --- a/src/Controllers/Version4/Taxes.php +++ b/src/Controllers/Version4/Taxes.php @@ -11,6 +11,8 @@ namespace WooCommerce\RestApi\Controllers\Version4; defined( 'ABSPATH' ) || exit; +use WooCommerce\RestApi\Controllers\Version4\Utilities\Pagination; + /** * REST API Taxes controller class. */ @@ -175,8 +177,6 @@ class Taxes extends AbstractController { $taxes[] = $this->prepare_response_for_collection( $data ); } - $response = rest_ensure_response( $taxes ); - // Store pagination values for headers then unset for count query. $per_page = (int) $prepared_args['number']; $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); @@ -186,24 +186,10 @@ class Taxes extends AbstractController { // Calculate totals. $total_taxes = (int) $wpdb->num_rows; - $response->header( 'X-WP-Total', (int) $total_taxes ); - $max_pages = ceil( $total_taxes / $per_page ); - $response->header( 'X-WP-TotalPages', (int) $max_pages ); + $max_pages = ceil( $total_taxes / $per_page ); - $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) ); - if ( $page > 1 ) { - $prev_page = $page - 1; - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - if ( $max_pages > $page ) { - $next_page = $page + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - $response->link_header( 'next', $next_link ); - } + $response = rest_ensure_response( $taxes ); + $response = Pagination::add_pagination_headers( $response, $request, $total_taxes, $max_pages ); return $response; } diff --git a/src/Controllers/Version4/Utilities/Pagination.php b/src/Controllers/Version4/Utilities/Pagination.php new file mode 100644 index 00000000000..71b31eb19f1 --- /dev/null +++ b/src/Controllers/Version4/Utilities/Pagination.php @@ -0,0 +1,81 @@ +header( 'X-WP-Total', $total_items ); + $response->header( 'X-WP-TotalPages', $total_pages ); + + $current_page = self::get_current_page( $request ); + $link_base = self::get_link_base( $request ); + + if ( $current_page > 1 ) { + $previous_page = $current_page - 1; + if ( $previous_page > $total_pages ) { + $previous_page = $total_pages; + } + self::add_page_link( $response, 'prev', $previous_page, $link_base ); + } + + if ( $total_pages > $current_page ) { + self::add_page_link( $response, 'next', ( $current_page + 1 ), $link_base ); + } + + return $response; + } + + /** + * Get current page. + * + * @param \WP_REST_Request $request The request object. + * @return int Get the page from the request object. + */ + protected static function get_current_page( $request ) { + return (int) $request->get_param( 'page' ); + } + + /** + * Get base for links from the request object. + * + * @param \WP_REST_Request $request The request object. + * @return string + */ + protected static function get_link_base( $request ) { + return add_query_arg( $request->get_query_params(), rest_url( $request->get_route() ) ); + } + + /** + * Add a page link. + * + * @param \WP_REST_Response $response Reference to the response object. + * @param string $name Page link name. e.g. prev. + * @param int $page Page number. + * @param string $link_base Base URL. + */ + protected static function add_page_link( &$response, $name, $page, $link_base ) { + $response->link_header( $name, add_query_arg( 'page', $page, $link_base ) ); + } +} diff --git a/src/Controllers/Version4/Webhooks.php b/src/Controllers/Version4/Webhooks.php index 49bb01d6c1d..58cc4374dbd 100644 --- a/src/Controllers/Version4/Webhooks.php +++ b/src/Controllers/Version4/Webhooks.php @@ -11,6 +11,8 @@ namespace WooCommerce\RestApi\Controllers\Version4; defined( 'ABSPATH' ) || exit; +use WooCommerce\RestApi\Controllers\Version4\Utilities\Pagination; + /** * REST API Webhooks controller class. */ @@ -179,29 +181,11 @@ class Webhooks extends AbstractController { $webhooks[] = $this->prepare_response_for_collection( $data ); } - $response = rest_ensure_response( $webhooks ); - $per_page = (int) $prepared_args['limit']; - $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); + $total_webhooks = $results->total; $max_pages = $results->max_num_pages; - $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) ); - - $response->header( 'X-WP-Total', $total_webhooks ); - $response->header( 'X-WP-TotalPages', $max_pages ); - - if ( $page > 1 ) { - $prev_page = $page - 1; - if ( $prev_page > $max_pages ) { - $prev_page = $max_pages; - } - $prev_link = add_query_arg( 'page', $prev_page, $base ); - $response->link_header( 'prev', $prev_link ); - } - if ( $max_pages > $page ) { - $next_page = $page + 1; - $next_link = add_query_arg( 'page', $next_page, $base ); - $response->link_header( 'next', $next_link ); - } + $response = rest_ensure_response( $webhooks ); + $response = Pagination::add_pagination_headers( $response, $request, $total_webhooks, $max_pages ); return $response; }