Commit 58363d022dd for woocommerce
commit 58363d022dd7a4cc13dd1d3401f4a41ea7777d5e
Author: Bhavik Tank <53536925+bhavz-10@users.noreply.github.com>
Date: Mon Apr 6 14:04:53 2026 +0530
Product Collection block: empty offset ("") triggers fatal 500 (TypeError: int + string) — frontend and editor become inaccessible (#64012)
diff --git a/plugins/woocommerce/changelog/fix-61447-product-collection-offset-per-page b/plugins/woocommerce/changelog/fix-61447-product-collection-offset-per-page
new file mode 100644
index 00000000000..bb5b6bf3ef2
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-61447-product-collection-offset-per-page
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Fix fatal TypeError when Product Collection block offset or perPage is an empty string.
diff --git a/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/QueryBuilder.php b/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/QueryBuilder.php
index af0a7982f65..ed8e3b91f08 100644
--- a/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/QueryBuilder.php
+++ b/plugins/woocommerce/src/Blocks/BlockTypes/ProductCollection/QueryBuilder.php
@@ -140,11 +140,13 @@ class QueryBuilder {
* @param bool $is_exclude_applied_filters Whether to exclude the applied filters or not.
*/
public function get_final_frontend_query( $collection_args, $query, $page = 1, $is_exclude_applied_filters = false ) {
- $product_ids = $query['post__in'] ?? array();
- $offset = $query['offset'] ?? 0;
- $per_page = $query['perPage'] ?? 9;
- $order = $query['order'] ?? 'asc';
- $search = $query['search'] ?? '';
+ $product_ids = $query['post__in'] ?? array();
+ $offset_raw = $query['offset'] ?? 0;
+ $per_page_raw = $query['perPage'] ?? null;
+ $offset = is_numeric( $offset_raw ) ? max( 0, (int) $offset_raw ) : 0;
+ $per_page = is_numeric( $per_page_raw ) ? max( 1, (int) $per_page_raw ) : 9;
+ $order = $query['order'] ?? 'asc';
+ $search = $query['search'] ?? '';
$common_query_values = array(
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
diff --git a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductCollection/QueryBuilder.php b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductCollection/QueryBuilder.php
index 5c370f5c5a0..1f22823b407 100644
--- a/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductCollection/QueryBuilder.php
+++ b/plugins/woocommerce/tests/php/src/Blocks/BlockTypes/ProductCollection/QueryBuilder.php
@@ -1231,4 +1231,20 @@ class QueryBuilder extends \WP_UnitTestCase {
return $clauses;
}
+
+ /**
+ * @testdox Empty string values for perPage and offset fall back to defaults.
+ */
+ public function test_per_page_and_offset_empty_string_handling() {
+ $parsed_block = Utils::get_base_parsed_block();
+
+ // Set values as empty strings.
+ $parsed_block['attrs']['query']['perPage'] = '';
+ $parsed_block['attrs']['query']['offset'] = '';
+
+ $merged_query = Utils::initialize_merged_query( $this->block_instance, $parsed_block );
+
+ $this->assertSame( 0, $merged_query['offset'] );
+ $this->assertSame( 9, $merged_query['posts_per_page'] );
+ }
}