What is the Block Hooks API
The Block Hooks API allows a block to automatically insert itself relative to instances of other block types. For example, a “Like” button block can ask to be inserted before the Post Content block, or a Mini Cart block can ask to be inserted after the Navigation block. Think of it as WordPress’s answer to the classic theme hooks and filters system to extend site UIs, but specifically designed for the block editor era.
As the name suggests, you can only insert blocks with the Block Hooks API. The API works holistically with site editing. While insertion happens automatically when a block is hooked, the user has the ultimate control. In the Site Editor, they can keep, remove, customise, or move the block, and those changes will be reflected on the front end.
The beauty lies in its simplicity: instead of users manually adding blocks everywhere, plugins can automatically insert their blocks where they make sense, while still giving users complete control to customize or remove them.
How I got involved
I was selected from the WooCommerce team to work directly with some incredibly talented individuals on the WordPress.org team, particularly Bernie Reiter, who led much of the technical vision for this project. The reason for my involvement was pretty straightforward – WooCommerce was going to be a primary consumer of this API, and we represented a perfect real-world use case.
Our immediate use-case: we wanted to automatically insert things like the Mini Cart block and My Account block into store headers without forcing users to manually add them. Every WooCommerce store owner shouldn’t have to waste time editing areas like their header to get this basic ecommerce functionality, they should come out the box automatically. That’s exactly the kind of problem Block Hooks was designed to solve.
The weight of building an API for WordPress core
Working on a new API for WordPress core meant we had to be incredibly careful about how we approached every decision. Unlike a typical project where you can iterate and change things as you learn, the API signature and behavior patterns we established had to be maintained going forward due to WordPress’s commitment to backwards compatibility.
Every function name, every parameter, every return value, once it shipped, it was essentially set in stone. That’s both terrifying and exciting when you’re helping to design something that could potentially be used by thousands of plugins and themes across millions of websites.
The frontend and editor challenge
This API had two distinct problems to solve at the heart of it: how to insert blocks on the server-side rendered frontend versus the client-side React editor. It was decided to focus on templates and template parts as the initial use case since WooCommerce headers are typically built as template parts. Diving into the core WordPress template system, two key functions: _build_block_template_result_from_file and _build_block_template_result_from_post in the block template utilities. These functions were perfect because they’re used to build template markup for both the editor REST API responses and the frontend rendering – giving a unified approach needed to solve both challenges with a single implementation.
The algorithm at the heart of it all
At these template function entry points, we ran an algorithm through a function called apply_block_hooks_to_content (which you can find in here). This function does the heavy lifting:
- It iterates through the block structure of the template content
- Parses the block markup into a workable format
- Identifies where hooked blocks should be inserted based on their anchor blocks
- Inserts the new blocks if they’re eligible
- Re-serializes everything back into the block markup format
The elegance of hooking into these template functions was that they served both our frontend and editor needs with a single implementation.
This is an oversimplification, but it’s the core concept that made the whole system work. For other use cases like specific blocks (navigation blocks, post content blocks), block patterns, and more, we approached them using similar patterns.
One area identified for future improvement is that this approach loads the entire template markup into memory for parsing and re-serialization. For very large templates, this could become a memory constraint. A streaming approach that processes the markup incrementally would be more efficient.
Respecting user choice
After inserting a newly hooked block, we added a reference to its anchor block in the form of ignoredHookedBlocks – essentially a list of hooked blocks associated with an anchor block that the API has explicitly inserted at one time or another. This was crucial because it meant when users removed a hooked block in the editor, the next time our algorithm ran against that markup, it would see the ignoredHookedBlocks list and respect the user’s decision not to re-insert it. Meaning if the hooked block was already there it wouldn’t be duplicated, and if removed it wouldn’t be re-inserted.
The navigation block challenge
One particularly tricky case was blocks like the navigation block, where the inner blocks aren’t stored in the template markup but in the database as their own posts. Since the inner blocks didn’t have its parent blocks data to access the ignoredHookedBlocks data at the time the algorithm ran against the parent block, we had to find a different storage solution.
We ended up storing this data in the wp_postmeta table against the post that stores the navigation’s inner blocks. It was a bit more complex, but it preserved the user choice principle that was so important to the overall design.
I wrote a more detailed post about implementing Block Hooks for the Navigation block that covers the specific challenges we faced, the entry points we chose, and how we solved the ignoredHookedBlocks tracking problem without access to the anchor block. It was one of the most requested features for the API and made it into WordPress 6.5.
My experience
Collaborating with talented people like Bernie was absolutely one of the highlights of this project. I learned an incredible amount working alongside him and the other core contributors. The pace was much more deliberate and considered – and for good reason.
We needed to ensure everything was right the first time. So we approached problems with multiple potential solutions, prototyped different approaches, and carefully evaluated the trade-offs before committing to an implementation. It was slower, but the thoroughness was necessary.
Testing was naturally an incredibly important aspect of this project. Every behaviour of the API was covered with comprehensive unit and integration tests. When you’re building something that will be used across the entire WordPress ecosystem, you can’t afford to have edge cases slip through.
The ultimate validation came when WooCommerce started using this API for some of its out-of-the-box behaviors which was one of the original goals of the project. Seeing it work in production across thousands of WooCommerce stores was satisfying.
Looking back
Being part of building a brand new API for WordPress was both challenging and rewarding. It’s one thing to work on an your typical project, but it’s entirely different to design something that needs to work for the entire ecosystem while maintaining WordPress’s commitment to backwards compatibility and user control.
The Block Hooks API shipped in WordPress 6.4 and has continued to evolve ever since. It’s amazing to see something you helped build continuing to grow and serve the community.
Leave a Reply to Building the Block Hooks API: My WordPress core experience Cancel reply