From 502965d6b73492ceea2ffb00b55b90d9330cd1ba Mon Sep 17 00:00:00 2001 From: Imants Date: Wed, 22 Oct 2025 13:18:37 +0300 Subject: [PATCH 1/7] test: add REST API pagination test for snippets --- tests/phpunit/test-rest-api.php | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/phpunit/test-rest-api.php diff --git a/tests/phpunit/test-rest-api.php b/tests/phpunit/test-rest-api.php new file mode 100644 index 00000000..80f11300 --- /dev/null +++ b/tests/phpunit/test-rest-api.php @@ -0,0 +1,46 @@ +name = "Snippet $i"; + $snippet->code = "// code $i"; + $result = \Code_Snippets\save_snippet( $snippet ); + $this->assertNotNull( $result ); + $created_ids[] = $result->id; + } + + // Request page 1 with per_page=10 + $request1 = new WP_REST_Request( 'GET', '/code-snippets/v1/snippets' ); + $request1->set_param( 'per_page', 10 ); + $request1->set_param( 'page', 1 ); + $response1 = rest_get_server()->dispatch( $request1 ); + $this->assertEquals( 200, $response1->get_status() ); + $data1 = $response1->get_data(); + $this->assertCount( 10, $data1 ); + + // Request page 2 with per_page=10 + $request2 = new WP_REST_Request( 'GET', '/code-snippets/v1/snippets' ); + $request2->set_param( 'per_page', 10 ); + $request2->set_param( 'page', 2 ); + $response2 = rest_get_server()->dispatch( $request2 ); + $this->assertEquals( 200, $response2->get_status() ); + $data2 = $response2->get_data(); + + // Ensure page 2 has the remaining items and is different from page 1 + $this->assertGreaterThanOrEqual( 1, count( $data2 ) ); + $this->assertNotEquals( $data1, $data2 ); + + // Check pagination headers + $this->assertEquals( '15', $response1->get_headers()['X-WP-Total'] ); + $this->assertEquals( '2', $response1->get_headers()['X-WP-TotalPages'] ); + } +} From fb9de70d656176be7717d4b5e8a69635850f8cc9 Mon Sep 17 00:00:00 2001 From: Imants Date: Wed, 22 Oct 2025 13:18:51 +0300 Subject: [PATCH 2/7] fix: pagination support to snippets REST API endpoint --- .../class-snippets-rest-controller.php | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/php/rest-api/class-snippets-rest-controller.php b/src/php/rest-api/class-snippets-rest-controller.php index 18a1f827..49fbe59d 100644 --- a/src/php/rest-api/class-snippets-rest-controller.php +++ b/src/php/rest-api/class-snippets-rest-controller.php @@ -80,6 +80,9 @@ public function register_routes() { [ 'network' ] ); + // Allow standard collection parameters (page, per_page, etc.) on the collection route. + $collection_args = array_merge( $network_args, $this->get_collection_params() ); + register_rest_route( $this->namespace, $route, @@ -88,7 +91,7 @@ public function register_routes() { 'methods' => WP_REST_Server::READABLE, 'callback' => [ $this, 'get_items' ], 'permission_callback' => [ $this, 'get_items_permissions_check' ], - 'args' => $network_args, + 'args' => $collection_args, ], [ 'methods' => WP_REST_Server::CREATABLE, @@ -193,15 +196,44 @@ public function register_routes() { * @return WP_REST_Response Response object on success. */ public function get_items( $request ): WP_REST_Response { - $snippets = get_snippets(); - $snippets_data = []; + // Respect the optional 'network' param when fetching snippets. + $network = $request->get_param( 'network' ); + $all_snippets = get_snippets( [], $network ); + + // Collection params (page, per_page) are provided via route args. Use defaults + // from get_collection_params() when not present on the request. + $collection_params = $this->get_collection_params(); + $per_page = (int) $request->get_param( 'per_page' ); + if ( ! $per_page ) { + $per_page = isset( $collection_params['per_page']['default'] ) ? (int) $collection_params['per_page']['default'] : 10; + } + $per_page = max( 1, $per_page ); + + $page = (int) $request->get_param( 'page' ); + if ( ! $page ) { + $page = isset( $collection_params['page']['default'] ) ? (int) $collection_params['page']['default'] : 1; + } + $page = max( 1, $page ); + + $total_items = count( $all_snippets ); + $total_pages = (int) ceil( $total_items / $per_page ); + + // Slice the full list to the requested page. + $offset = ( $page - 1 ) * $per_page; + $snippets = array_slice( $all_snippets, $offset, $per_page ); + $snippets_data = []; foreach ( $snippets as $snippet ) { $snippet_data = $this->prepare_item_for_response( $snippet, $request ); $snippets_data[] = $this->prepare_response_for_collection( $snippet_data ); } - return rest_ensure_response( $snippets_data ); + $response = rest_ensure_response( $snippets_data ); + // Provide total counts in the response headers like WP core REST responses do. + $response->header( 'X-WP-Total', (string) $total_items ); + $response->header( 'X-WP-TotalPages', (string) $total_pages ); + + return $response; } /** From 811be0bea73d4274fe8ac717bb87a3015ebd6b24 Mon Sep 17 00:00:00 2001 From: Imants Date: Wed, 22 Oct 2025 13:24:52 +0300 Subject: [PATCH 3/7] fix: stylelint --- src/css/settings.scss | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/css/settings.scss b/src/css/settings.scss index 2ff6dc76..e2a040ae 100644 --- a/src/css/settings.scss +++ b/src/css/settings.scss @@ -142,7 +142,7 @@ body.js { } #target_version { - min-width: 200px; + min-inline-size: 200px; margin-inline-start: 8px; } @@ -158,9 +158,9 @@ body.js { // Warning box styling #version-switch-warning { - margin-top: 20px !important; + margin-block-start: 20px !important; padding: 12px 16px; - border-left: 4px solid #dba617; + border-inline-start: 4px solid #dba617; background: #fff8e5; border-radius: 4px; @@ -183,31 +183,31 @@ body.js { } } - .notice { - &.notice { - &-success { - border-left-color: #00a32a; - } + .notice { + &.notice { + &-success { + border-inline-start-color: #00a32a; + } - &-error { - border-left-color: #d63638; - } + &-error { + border-inline-start-color: #d63638; + } - &-warning { - border-left-color: #dba617; - } + &-warning { + border-inline-start-color: #dba617; + } - &-info { - border-left-color: #72aee6; - } - } - } + &-info { + border-inline-start-color: #72aee6; + } + } + } } .version-switch-settings { .form-table { th { - width: 180px; + inline-size: 180px; } } } From df8af7b3ad9fd678c0a57a342e86ac3aab2d99cf Mon Sep 17 00:00:00 2001 From: Imants Date: Wed, 22 Oct 2025 15:10:14 +0300 Subject: [PATCH 4/7] fix: get_items method to support pagination --- src/php/rest-api/class-snippets-rest-controller.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/php/rest-api/class-snippets-rest-controller.php b/src/php/rest-api/class-snippets-rest-controller.php index 49fbe59d..25b6ccdc 100644 --- a/src/php/rest-api/class-snippets-rest-controller.php +++ b/src/php/rest-api/class-snippets-rest-controller.php @@ -189,19 +189,17 @@ public function register_routes() { } /** - * Retrieves a collection of snippets. + * Retrieves a collection of snippets, with pagination. * * @param WP_REST_Request $request Full details about the request. * * @return WP_REST_Response Response object on success. */ public function get_items( $request ): WP_REST_Response { - // Respect the optional 'network' param when fetching snippets. $network = $request->get_param( 'network' ); $all_snippets = get_snippets( [], $network ); - // Collection params (page, per_page) are provided via route args. Use defaults - // from get_collection_params() when not present on the request. + // Collection params (page, per_page) $collection_params = $this->get_collection_params(); $per_page = (int) $request->get_param( 'per_page' ); if ( ! $per_page ) { @@ -229,7 +227,6 @@ public function get_items( $request ): WP_REST_Response { } $response = rest_ensure_response( $snippets_data ); - // Provide total counts in the response headers like WP core REST responses do. $response->header( 'X-WP-Total', (string) $total_items ); $response->header( 'X-WP-TotalPages', (string) $total_pages ); From 93c700a1df02a077103035a007ad881c675688a6 Mon Sep 17 00:00:00 2001 From: Imants Date: Wed, 22 Oct 2025 15:20:30 +0300 Subject: [PATCH 5/7] fix: remove unused file --- tests/phpunit/test-rest-api.php | 46 --------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 tests/phpunit/test-rest-api.php diff --git a/tests/phpunit/test-rest-api.php b/tests/phpunit/test-rest-api.php deleted file mode 100644 index 80f11300..00000000 --- a/tests/phpunit/test-rest-api.php +++ /dev/null @@ -1,46 +0,0 @@ -name = "Snippet $i"; - $snippet->code = "// code $i"; - $result = \Code_Snippets\save_snippet( $snippet ); - $this->assertNotNull( $result ); - $created_ids[] = $result->id; - } - - // Request page 1 with per_page=10 - $request1 = new WP_REST_Request( 'GET', '/code-snippets/v1/snippets' ); - $request1->set_param( 'per_page', 10 ); - $request1->set_param( 'page', 1 ); - $response1 = rest_get_server()->dispatch( $request1 ); - $this->assertEquals( 200, $response1->get_status() ); - $data1 = $response1->get_data(); - $this->assertCount( 10, $data1 ); - - // Request page 2 with per_page=10 - $request2 = new WP_REST_Request( 'GET', '/code-snippets/v1/snippets' ); - $request2->set_param( 'per_page', 10 ); - $request2->set_param( 'page', 2 ); - $response2 = rest_get_server()->dispatch( $request2 ); - $this->assertEquals( 200, $response2->get_status() ); - $data2 = $response2->get_data(); - - // Ensure page 2 has the remaining items and is different from page 1 - $this->assertGreaterThanOrEqual( 1, count( $data2 ) ); - $this->assertNotEquals( $data1, $data2 ); - - // Check pagination headers - $this->assertEquals( '15', $response1->get_headers()['X-WP-Total'] ); - $this->assertEquals( '2', $response1->get_headers()['X-WP-TotalPages'] ); - } -} From c0aa1a72ee843d9de02027aa2089077bba77066c Mon Sep 17 00:00:00 2001 From: Imants Date: Wed, 22 Oct 2025 15:24:12 +0300 Subject: [PATCH 6/7] fix(copilot): comment style Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/php/rest-api/class-snippets-rest-controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/php/rest-api/class-snippets-rest-controller.php b/src/php/rest-api/class-snippets-rest-controller.php index 25b6ccdc..d6a904f9 100644 --- a/src/php/rest-api/class-snippets-rest-controller.php +++ b/src/php/rest-api/class-snippets-rest-controller.php @@ -199,7 +199,7 @@ public function get_items( $request ): WP_REST_Response { $network = $request->get_param( 'network' ); $all_snippets = get_snippets( [], $network ); - // Collection params (page, per_page) + // Collection params (page, per_page). $collection_params = $this->get_collection_params(); $per_page = (int) $request->get_param( 'per_page' ); if ( ! $per_page ) { From ff728863e39e54ad1838bc7679dec860fc7dd657 Mon Sep 17 00:00:00 2001 From: Imants Date: Wed, 22 Oct 2025 15:39:22 +0300 Subject: [PATCH 7/7] fix: improve pagination --- .../class-snippets-rest-controller.php | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/php/rest-api/class-snippets-rest-controller.php b/src/php/rest-api/class-snippets-rest-controller.php index d6a904f9..6fe58ba9 100644 --- a/src/php/rest-api/class-snippets-rest-controller.php +++ b/src/php/rest-api/class-snippets-rest-controller.php @@ -199,20 +199,15 @@ public function get_items( $request ): WP_REST_Response { $network = $request->get_param( 'network' ); $all_snippets = get_snippets( [], $network ); - // Collection params (page, per_page). + // Get collection params (page, per_page). $collection_params = $this->get_collection_params(); - $per_page = (int) $request->get_param( 'per_page' ); - if ( ! $per_page ) { - $per_page = isset( $collection_params['per_page']['default'] ) ? (int) $collection_params['per_page']['default'] : 10; - } - $per_page = max( 1, $per_page ); + $per_page_request = (int) $request->get_param( 'per_page' ); + $per_page = max( 1, $per_page_request ? $per_page_request : (int) $collection_params['per_page']['default'] ); - $page = (int) $request->get_param( 'page' ); - if ( ! $page ) { - $page = isset( $collection_params['page']['default'] ) ? (int) $collection_params['page']['default'] : 1; - } - $page = max( 1, $page ); + $page_request = (int) $request->get_param( 'page' ); + $page = max( 1, $page_request ? $page_request : (int) $collection_params['page']['default'] ); + // Count total items $total_items = count( $all_snippets ); $total_pages = (int) ceil( $total_items / $per_page ); @@ -221,6 +216,7 @@ public function get_items( $request ): WP_REST_Response { $snippets = array_slice( $all_snippets, $offset, $per_page ); $snippets_data = []; + foreach ( $snippets as $snippet ) { $snippet_data = $this->prepare_item_for_response( $snippet, $request ); $snippets_data[] = $this->prepare_response_for_collection( $snippet_data );