Description
Most WooCommerce stores ship 80-150 KB of block CSS and JS that the store never actually renders. The WC BlockPatterns scanner is the one that bugs me most – it hits the filesystem on every request to scan a directory of pattern templates you don’t use. Then add core WP global-styles, wp-block-library and font-faces on top, and you’re loading a Gutenberg frontend you probably switched off a long time ago.
Zero Blocks Given turns it off at the source, through WooCommerce’s own dependency injection container. No CSS dequeue band-aid, no UI checkboxes, no PRO upsell. One constant in wp-config.php, pick a tier, done.
How it works
Here’s the thing – WC registers its block hooks as closures wrapping instance methods on container-managed objects. So you can’t remove_action() them by string. You have to fetch the same instance back from the DI container and pass it in as the callable. That’s what this does:
$bp = \Automattic\WooCommerce\Blocks\Package::container()->get( BlockPatterns::class );
remove_action( 'init', [ $bp, 'register_block_patterns' ] );
The DI-container path is the one that survives WC upgrades cleanly. String-callback matching and dequeue tricks tend to drift every release, so I went with the container.
Five modes. Three ways to set them.
Mode
What it turns off
When to use it
patterns
WC BlockPatterns directory scanner only
Block-based Cart/Checkout – keeps all blocks rendering, just skips the file-I/O scan
blocks
patterns + BlockTypesController + Notices styles + wc-blocks-style handle
Classic-shortcode WC stores
keep-styles
blocks + WC Product Filter pattern scan (ProductFilterAttribute)
Stores that don’t use WC blocks but keep Gutenberg styling – kills the expensive scans, leaves global-styles and core block rendering alone. Pixel-perfect.
all
keep-styles + WP global-styles pipeline + theme.json + font-faces + head <style> strip
Sites with no Gutenberg frontend at all
nuclear
all + unregister_block_type() for every core block
Page-builder sites – strips the editor inserter clean
Default is all. Set the mode you want with any of these:
- The
<dialog>settings – click the Settings link on the Plugins screen. Native HTML dialog, four radios, save. No menu items, nothing else added to your admin. - A constant in
wp-config.php–define( 'ZEROBLG_MODE', 'patterns' );. This wins over the dialog. Good devops escape hatch. - A filter in a theme or mu-plugin –
add_filter( 'zeroblg/mode', fn() => 'blocks' );. Used when neither the constant nor the dialog set a value.
Resolution order: constant, then settings, then filter, then all. An invalid value at any step just falls through to the next.
A few real cases
- Service-form site on WC. You sell consultations, not products – no cart, no checkout.
mode=allstrips every block stylesheet across the site. - Classic-shortcode WC store. You use
[woocommerce_cart]and[woocommerce_checkout], no block UI.mode=blocksturns off the block frontend without touching your classic flow. - Block-checkout store with bloated patterns. You run the new Cart/Checkout blocks but never the WC pattern library.
mode=patternsskips just the directory scanner – saves the disk hit, leaves your checkout alone. - Themed store with a layered-nav filter, pixel-perfect requirement. Woodmart or similar, WC layered nav, no Product Filter block in any post. The
ProductFilterAttributepattern scan can cost ~100ms a request on its own.mode=keep-styleskills that scan and the rest of the block registration, but leaves every inlineglobal-stylesrule in place – so the shop renders pixel-for-pixel the same.allwould shave the same milliseconds but stripstheme.jsonstyles too, which moves pixels. - FrankenPHP / worker mode. All hooks are idempotent, no
$GLOBALSwrites,\Throwablecatches around the DI lookups. Safe in a worker. - Elementor / Divi WC stores. The page builder renders its own checkout, so
mode=allclears the WC and WP block CSS your theme never uses anyway.
Why I built it this way
- Activate it and it works –
mode=allis the default, no setup needed. - No settings page to learn. One constant or one filter is the whole API.
- Pure PHP. No database rows, no admin scripts, no frontend JS.
- No external requests, no tracking, nothing phoning home. GDPR is a non-issue.
- It uses the same
Package::container()lookup as WC core, so it follows WC’s own object lifecycle instead of guessing. - Worker-safe – FrankenPHP, Roadrunner, Swoole. No
die, noexit, no session writes. - mu-plugin friendly. Drop the folder into
wp-content/mu-plugins/and it loads itself. - GPL, no upsells. No PRO tier, no Freemius, no admin notice nagging you for a review.
From the maker of WP Multitool
This plugin handles the frontend block bloat. If you also want the backend cleaned up, that’s what WP Multitool does – slow queries, autoload bloat, the database bottlenecks that caching plugins just hide instead of fixing. Most optimization plugins guess at the problem. WP Multitool runs EXPLAIN and shows you. 14 tools in there – slow-query analyzer, autoload optimizer, index suggestions, fatal-error recovery – and a free site scanner if you want to see what’s slow before paying for anything. If Zero Blocks Given earned a spot in your stack, that one probably will too.
Screenshots

define() line in wp-config.php.
BlockPatterns->register_block_patterns gone from init.
<dialog> settings on the Plugins screen – four radios, one save button, no menu item.Installation
- Install from the WordPress plugin directory, or upload the folder to
/wp-content/plugins/zero-blocks-given/. - Activate it. It runs on
mode=allout of the box. - To change the tier, add this to
wp-config.php: define( ‘ZEROBLG_MODE’, ‘patterns’ ); // or ‘blocks’ or ‘all’ - Or drop the folder into
wp-content/mu-plugins/instead – it works as a must-use plugin too.
FAQ
-
Which WooCommerce versions does it support?
-
WC 7.x through 10.x – anywhere the DI container (
Automattic\WooCommerce\Blocks\Package::container()) is stable. If a future WC release renames a method, the per-method\Throwablecatches mean Zero Blocks Given degrades quietly instead of throwing a fatal. -
Will it break my Block-based Cart/Checkout?
-
mode=patterns is safe – it only turns off the directory scanner, not the block UI.
mode=blocksandmode=allwill break Block-based Cart/Checkout, which is the whole point of those modes. Pick the one that matches your site. -
How do I switch tiers?
-
Add
define( 'ZEROBLG_MODE', 'patterns' );(or'blocks'or'all') towp-config.php. The constant wins over the filter. Invalid values fall back to'all'. -
Does it work as a must-use plugin?
-
Yes. Drop the whole
zero-blocks-given/folder intowp-content/mu-plugins/, then add a one-line loader likemu-plugins/zero-blocks-given-load.phpwithrequire WPMU_PLUGIN_DIR . '/zero-blocks-given/zero-blocks-given.php';in it. WordPress loads it on every request. -
Is it GDPR compliant?
-
Yes. It doesn’t collect, store, send or process any user data. No external requests, no cookies, no options written to your database.
-
Is it safe for FrankenPHP / worker mode?
-
Yes. No
die/exit, no$GLOBALSwrites, nosession_start, every hook is idempotent, every DI lookup is wrapped in a\Throwablecatch. Tested on FrankenPHP worker mode. -
How do I uninstall?
-
Deactivate and delete from the WordPress admin. It writes nothing to the database, so uninstall is a real no-op.
-
Does `keep-styles` need a specific version?
-
Yes –
keep-stylesshipped in 1.3.0. On 1.2.2 or older it’s an unknown value, so the resolver falls back to the defaultall– which DOES stripglobal-stylesand can move pixels. Setkeep-stylesonly on 1.3.0+. Watch the edge case where a forced reinstall or downgrade leaves you on an older build: the mode silently becomesalluntil you update, so your styles disappear without an error. Confirm the active version before relying onkeep-styles. -
I removed a hook but `wp profile` still lists it – did it work?
-
Probably yes.
wp profile hookcan still showregister_block_patternsas if it ran, because it wraps the callbacks it captured before the priority-0 removal fired. Don’t trust the profiler here – check the real request instead. Dump$wp_filter['wp_loaded'](or the relevant hook) on an actual front-end load; if the callback is gone from there, it’s gone. -
My pixel-diff shows changes I didn’t expect – is `keep-styles` moving pixels?
-
Check your screenshot widths first. Full-page screenshots taken at different viewport widths (say 2248px vs 2488px) produce a false diff that has nothing to do with the plugin. Re-shoot both the baseline and the test at identical dimensions before you trust the number. With matched dimensions,
keep-stylesleavesglobal-stylesintact and the diff against baseline stays in the noise. -
Why a constant first, settings UI second?
-
Keeping the tier in a
wp-config.phpconstant means it lives in version control with the rest of your devops config. The dialog is there for sites where editingwp-config.phpisn’t practical. Both end up in the same code path.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“Zero Blocks Given” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “Zero Blocks Given” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
1.3.0
- New
keep-stylestier, sitting betweenblocksandall. It kills the WC Product Filter pattern scanner (ProductFilterAttribute::register_block_patternsonwp_loaded) on top of theblocksremovals, but leaves the WPglobal-stylespipeline and core block rendering untouched. For stores that want the block/pattern registration cost gone without moving a single pixel – the scan can cost ~100ms a request on a layered-nav store that never uses the Product Filter block. Front-only; the editor’s pattern inserter is left alone. - The Product Filter scan removal runs for
keep-styles,allandnuclear. - Fixed:
nuclearnow also removesBlockTypesController::register_blocks(it was skipping it – max aggression should include it). - Dialog now lists five tiers.
1.2.2
- WP.org plugin review feedback – switched direct-file-access guards from
returntoexit(the WP coding-standards form). Applied tozero-blocks-given.php,uninstall.phpand allinc/*.phptier files. No behavior change.
1.2.1
- WP.org plugin review feedback – extended the internal prefix from
zbgtozeroblg(review wanted prefixes longer than 4 chars). Renamed constantZBG_MODEtoZEROBLG_MODE, filterzbg/modetozeroblg/mode, option keyzbg_modetozeroblg_mode, plus the matching function, CSS and DOM-id prefixes. No behavior change.
1.2.0
- First public release. Slug:
zero-blocks-given. Constant:ZEROBLG_MODE. Filter:zeroblg/mode. Option key:zeroblg_mode. - Settings dialog JavaScript loaded via
wp_enqueue_script()on the Plugins screen (inc/admin-settings.js).
1.1.0
- New
nucleartier – callsunregister_block_type()for every core block. Editor inserter goes empty, frontend block markup stops rendering. For sites that build content with page builders, shortcodes or the classic editor only. - New optional settings UI – a native
<dialog>modal off the Settings link on the Plugins screen. Four radios, one save button. No menu item, no admin notices. - The settings UI sits below the constant in the resolution chain –
ZEROBLG_MODEinwp-config.phpstill wins. When the constant is defined, the dialog shows the radios disabled with a “Locked by constant” notice. - Resolution order is now constant, option, filter,
all(was constant, filter,all). uninstall.phpnow deletes thezeroblg_modeoption on uninstall (was a no-op).
1.0.0
- Initial release. Three tiers:
patterns,blocks,all. Defaultall. - DI container unregister via
Package::container()->get( BlockPatterns::class ). - Per-method
\Throwablecatches for forward-compat with WC method renames. - Worker-safe (FrankenPHP / Roadrunner / Swoole).
- mu-plugin friendly.
