Custom Gutenberg Blocks: React or PHP?
Choose React when the block’s editing interface is the product, core PHP-only blocks when a few settings and server-rendered HTML are enough, and a PHP tool when you need richer fields or containers without a build step.
The WordPress block editor is written in React, and for years custom blocks had to be written in React too. Since WordPress 7.0, core can also register simple blocks from PHP alone. And most blocks on real websites don’t need a custom React interface: they need a few fields and some HTML. Here’s what each approach actually gives you.
What a block needs, technically
Every block has an editor side (how it appears and which settings it shows while editing) and a front end (the HTML visitors get). The front end can be saved as static HTML, or rendered by PHP on each request. So “React or PHP” really means: who writes the editor side, and who renders the front end?
A dynamic block is not a block without an editor. It is a block whose front-end HTML is generated by PHP at request time instead of being saved into the post.
The React approach
npx @wordpress/create-block gives you a plugin where edit.js defines the editor UI in React/JSX, and either save.js (static HTML) or render.php (dynamic) defines the output. You build it with webpack through @wordpress/scripts.
What you get:
- Full control over the editor: custom toolbars, drag handles, live-editable text (
RichText), media pickers wired exactly how you want. - Static blocks: output saved in the post, so it renders even without the plugin active.
- The same stack as core, with the most examples and documentation.
What it costs:
- Node.js and a build step for every change.
- Two templates to keep in sync: the React preview and the front-end output.
- A skill set many WordPress developers and agencies don’t use day to day.
- Markup changes don’t reach existing content. A static block’s HTML is saved in every post. Change the block and those posts keep the old HTML until each one is opened and re-saved, so visitors don’t see the change. The editor marks the old blocks as invalid unless you write a deprecation for each earlier version.
PHP-only blocks in WordPress core
Since WordPress 7.0, core registers a block from PHP alone: register_block_type() with autoRegister under supports and a render_callback. The editor generates the sidebar controls for string, number, integer and boolean attributes.
What you get:
- No JavaScript and no build step, with nothing to install.
- One PHP function renders the block in the editor and on the front end.
What it costs:
- Basic fields only. No image, color, link or date controls.
- No nested blocks, and no text typed directly in the canvas.
- The dev note says it “isn’t meant to replace the existing client-side paradigm”.
The code is in how to create a custom Gutenberg block without React.
The PHP approach with a tool
Here the front end is always a dynamic block rendered by PHP, and the editor shows a preview of that same PHP. Settings appear in the sidebar as native WordPress controls. A tool such as FanCoolo WP writes the registration for you and adds the parts core leaves out: more field types, nested blocks and SCSS.
What you get:
- One template. The editor preview and the front end come from the same PHP, so they can’t drift apart.
- No build step. Edit, save, refresh.
- Changes apply everywhere at once. Nothing is saved into the posts, so a template change shows on every page on its next load.
- Easy dynamic data. Query posts, read post meta or ACF fields, check the current user: it’s just PHP.
What it costs:
- Less inline editing. Content is edited in sidebar fields rather than typed directly into the block (unless you use nested blocks for the editable parts).
- Rendered per request. Dynamic blocks run PHP on every page view, like any PHP template. Page caching handles this well.
A middle path: nested blocks
The “no inline editing” limit is smaller than it sounds. A PHP block can be a container: you render the wrapper and layout in PHP, and let editors type headings, paragraphs and buttons with normal core blocks inside it (InnerBlocks). You get a fixed design with a comfortable editing experience, still without React. Core’s PHP-only blocks can’t do this; ACF Blocks and FanCoolo WP can.
How fast do the blocks render?
We measured the server time to render one small testimonial block (two text fields, the same HTML) built four ways:
| Block type | Time to render one block | Compared with a React static block |
|---|---|---|
| FanCoolo WP with Static output (coming in 1.4.1) | 10.0 µs | about 3× faster |
| React static block (HTML saved in the post) | 29.3 µs | baseline |
Core PHP block with a render_callback | 50.7 µs | 1.7× slower |
| FanCoolo WP, normal dynamic rendering | 427.3 µs | about 15× slower |
Static output is coming in FanCoolo WP 1.4.1; it is not in the current release. It stores a block’s rendered HTML and serves it without running the template, and re-renders the stored HTML when you change the template, so you get the speed of saved HTML without the stale-content problem.
Method: WordPress 7.1.2, PHP 8.3 with OPcache, a development build of FanCoolo WP 1.4.1, 2 October 2026. Each variant was rendered 3,000 times per run, and the table shows the median of 15 runs. No variant made a database query. These are microseconds per block on one server: with page caching, visitors won’t notice the difference between any of them.
How to decide
| Choose React when… | Choose core PHP-only blocks when… | Choose a PHP tool when… |
|---|---|---|
| The editing UI itself is the product (drag-and-drop builders, complex interactions) | The block needs a few text, number or on/off settings | The block needs image, color, link or post-picker fields |
| You want static HTML saved in the post | The output is server-rendered and has no nested blocks | The block is a container for other blocks |
| Your team already works in React | You want no dependency beyond WordPress 7.0+ | Your team works in PHP, or hands sites to clients |
| You’re building for the WordPress.org block directory | You’re fine writing the registration by hand | You want fields, SCSS and reusable parts managed in one place |
For the tool path, FanCoolo WP, which we build at DPlugins, does the wiring for you: you write the PHP render, add fields in a visual Attributes Manager (they appear as native sidebar controls), enable nested blocks in the block’s settings, and FanCoolo generates block.json and the editor registration.
FAQ
Can Gutenberg blocks be written entirely in PHP?
Yes, since WordPress 7.0, for simple server-rendered blocks. Richer editing still needs JavaScript or a tool.
What can’t a PHP-only block do?
No text typed directly in the canvas, no nested blocks, and sidebar controls only for string, number, integer and boolean attributes.
Do dynamic blocks hurt performance?
A dynamic block runs PHP on each page view, like any template. With page caching, visitors get the cached HTML either way. Our measurement above puts the difference in microseconds per block.
Sources
- PHP-only block registration, Miguel Fonseca, Make WordPress Core, 3 March 2026, including the author’s replies in the comments of 4 March 2026 (read 2 October 2026)
- Deprecation, Block Editor Handbook (read 2 October 2026)
- Attributes Manager and Inner Blocks, FanCoolo WP documentation (read 2 October 2026)
More comparisons
- Oxygen vs Gutenberg in 2026: Which Should You Build With?
- Bricks vs Gutenberg: Which Is Better for Your WordPress Site?
- Elementor vs Gutenberg: Which Should You Use in 2026?
- Page Builder or Block Theme for Client Sites?
- ACF Blocks vs Native Gutenberg Blocks: Which Should You Use?
- WordPress Code Snippet Plugins Compared (2026)
- Self-Hosted Plugin Updates vs WordPress.org: Which Is Right for Your Plugin?
