Commerce Blocks
A modern, SSR-first, block-native WooCommerce product-grid plugin with live filtering, pagination, and AJAX add-to-cart.
by Anisur Rahman · github.com/anisur2805/commerce-blocks · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/anisur2805/commerce-blocks/archive/refs/heads/master.zipReadme
Commerce Blocks
A modern, SSR-first, block-native WooCommerce product-grid plugin with live filtering, pagination, and AJAX add-to-cart.

Why
WooCommerce's native product blocks are functional but plain, and the popular alternatives are large general-purpose suites with jQuery/admin-ajax frontends. Commerce Blocks is a focused, standards-first alternative:
- SSR first — the grid renders server-side, so it's SEO-indexable, fast on first paint, and works with JavaScript disabled.
- Interactivity API — filtering, pagination, view switching, and add-to-cart run on the WordPress Interactivity API (
data-wp-*directives). No jQuery. - REST-first — all dynamic data flows through a documented
commerce-blocks/v1endpoint that returns render-ready HTML partials, so card markup lives in one place (PHP). - Lean — the grid interactivity bundle is ~3 KB gzipped; assets load only where the block is present.
- Extensible — a module registry + documented hooks/filters let future features (Quick View, Wishlist, Compare) slot in without touching core.
Requirements
- WordPress 6.5+
- WooCommerce 8.0+
- PHP 7.4+
Installation
composer install
npm install
npm run build
Then activate the plugin in WordPress. Add the Product Grid block from the "Commerce Blocks" category in the inserter.
Features
- Grid and list layouts with a front-end view switcher
- Query builder: All / Recent / Featured / On Sale / Best Selling / Top Rated / Recently Viewed / Manual, with category/tag/ID filters, ordering, and stock/image exclusions
- Live AJAX filtering: category, tag, price range, on-sale, keyword search (debounced, in-flight requests cancelled)
- Pagination: numbered, load more, infinite scroll (with a keyboard/AT fallback)
- AJAX add-to-cart via the WooCommerce Store API, with graceful nonce/token recovery
- Sale/New badges with configurable text, position, and style
- Six card presets: Classic, Bordered, Minimal, Overlay, Spotlight, Split
- Curated style controls serialized to
--cb-*CSS custom properties - Per-element typography (title, price, description, button) with desktop/tablet/mobile sizes, resolved from the block's own width via container queries
- Starter block patterns (clean grid, sale grid, featured list)
- Theme-overridable templates (
yourtheme/commerce-blocks/{template}.php) - WCAG 2.1 AA target: ARIA live announcements,
aria-busy, keyboard-operable controls,prefers-reduced-motionsupport - RTL stylesheet, HPOS compatible
Architecture
commerce-blocks.php # header, requirement checks, bootstrap
src/
Plugin.php # orchestrator; registers hooks
Blocks/ProductGrid/
Block.php # register_block_type + render_callback wiring
Renderer.php # attributes → query → HTML (SSR + REST shared)
Patterns.php # starter block patterns
Query/ProductQuery.php # queryType → WP_Query args
Rest/ProductsController.php # GET /commerce-blocks/v1/products
Assets/Assets.php # localize runtime config
Support/
Templates.php # theme override resolver
StyleBuilder.php # style attributes → CSS custom properties
Admin/Settings.php # settings (delete-data-on-uninstall)
Modules/ModuleRegistry.php # freemium-ready module spine
Contracts/Module.php # module interface
templates/ # overridable card/pagination/state partials
src/product-grid/ # block source (edit.tsx, view.ts, block.json, SCSS)
Rendering model: save() returns null; PHP renders the initial grid. The front end hydrates via the Interactivity API and fetches page/filter updates from REST, swapping only the grid's inner list.
REST API
GET /wp-json/commerce-blocks/v1/products
| Param | Type | Notes |
|---|---|---|
queryType |
string | all recent featured on_sale best_selling top_rated recently_viewed manual |
page, perPage |
int | perPage clamped to 48 |
categories, tags |
int[] | term IDs |
orderby, order |
string | enum allow-list |
onSale, inStock |
bool | filters |
search |
string | keyword |
minPrice, maxPrice |
number | price range |
layout, display, badges, hover |
object | render matching card markup |
Response: { html, found, maxPages, page } plus X-WP-Total / X-WP-TotalPages headers.
Hooks
Filters: commerce-blocks/product_query_args, commerce-blocks/card_template, commerce-blocks/card_classes, commerce-blocks/rest/products_response.
Actions: commerce-blocks/before_card, commerce-blocks/after_card, commerce-blocks/card_actions, commerce-blocks/registered.
Development
npm start # watch + rebuild
npm run build # production build (Interactivity API module)
composer lint # PHPCS (WPCS)
composer phpstan # static analysis (level 5)
composer test # PHPUnit
npm run test:js # Jest
License
GPL-2.0-or-later.