Custom Gutenberg Blocks: React or PHP?
The WordPress block editor is written in React, so the official documentation assumes your custom blocks will be too. But 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 two sides:
- The editor side: how the block appears and which settings it shows while editing. This always runs in the browser, inside the React-based editor.
- The front end: the HTML visitors get. This can be saved as static HTML, or rendered by PHP on each request (a dynamic block).
So “React or PHP” really means: who writes the editor side, and who renders the front end?
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.
The PHP approach
Here the front end is always a dynamic block rendered by PHP, and the editor shows a server-rendered preview of that same PHP. Settings appear in the sidebar as native WordPress controls.
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.
- 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.
How to decide
| Choose React when… | Choose PHP when… |
|---|---|
| The editing UI itself is the product (drag-and-drop builders, complex interactions) | The block is mostly layout + a few settings |
| You want static HTML saved in the post | The block shows dynamic data (posts, meta, users) |
| Your team already works in React | Your team works in PHP, or hands sites to clients |
| You’re building for the WordPress.org block directory | You want to ship blocks quickly for one site |
For the PHP path, FanCoolo WP 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 with a toggle, and FanCoolo generates block.json and the editor registration. Step by step: create a custom Gutenberg block without React.
