You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, registering blocks in core requires writing JavaScript code, even for blocks that are fully rendered in PHP using a render_callback. This adds unnecessary complexity for PHP-focused developers and prevents easier block adoption, especially in classic themes or server-driven workflows.
What is your proposed solution?
Allowing PHP-only block registration. This would:
Allow blocks to be registered and appear in the editor using only PHP and block metadata.
Enable WordPress sites and classic themes to adopt blocks more easily; these blocks could be wrappers for legacy PHP functions or shortcodes.
Open new opportunities for server-side features, custom integrations, and future-proof compatibility.
A pure-PHP registration model would simplify the minimum requirements for block development, making them accessible for a wider developer audience, and help grow the block ecosystem beyond advanced JavaScript usage.
I agree that we can use the block version if we need any kind of versioning. I'd be fine to ship this as-is and consider any additions as something for the future.
Does this PHP registration support <InnerBlocks> like ACF?
I wanted PHP registration of blocks with InnerBlocks support in a project recently so I researched how this is handled in ACF. Below is the custom JSX parsing approach that resulted.
With this approach instead of SSR we're transposing the PHP template into JSX thus from the editors perspective the block is identical to one written with React.
import { useState, useEffect } from '@wordpress/element';
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
import apiFetch from '@wordpress/api-fetch';
import parse from 'html-react-parser';
/**
* Component that parses PHP templates and renders them with InnerBlocks support
*/
export default function TemplateBlock({ blockName, attributes }) {
const [template, setTemplate] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const blockProps = useBlockProps();
useEffect(() => {
// Fetch the template content from the API
const fetchTemplate = async () => {
try {
setLoading(true);
const response = await apiFetch({
path: `/gateway/v1/blocks/${blockName}/template`,
});
setTemplate(response.template);
setLoading(false);
} catch (err) {
setError(err.message || 'Failed to load template');
setLoading(false);
}
};
fetchTemplate();
}, [blockName]);
if (loading) {
return <div {...blockProps}>Loading template...</div>;
}
if (error) {
return <div {...blockProps}>Error: {error}</div>;
}
if (!template) {
return <div {...blockProps}>No template found</div>;
}
// Parse the PHP template into renderable content
const parsedContent = parseTemplate(template);
return <div {...blockProps}>{parsedContent}</div>;
}
/**
* Parse PHP template string into React components
* Handles <InnerBlocks /> replacement and HTML parsing
*/
function parseTemplate(templateString) {
// Remove PHP opening tags and comments
let cleaned = templateString
.replace(/<\?php[\s\S]*?\?>/gi, '') // Remove PHP tags
.trim();
// Check if there's an InnerBlocks placeholder
if (!/<InnerBlocks\s*\/?>/i.test(cleaned)) {
// No InnerBlocks found, just parse as HTML
return parse(cleaned);
}
// Parse with custom replace function to handle InnerBlocks
return parse(cleaned, {
replace: (domNode) => {
// Check if this is an InnerBlocks element
if (domNode.type === 'tag' && domNode.name.toLowerCase() === 'innerblocks') {
return <InnerBlocks />;
}
}
});
}
One thing I just noticed when testing this in 7.0-beta2, any Additional CSS class(es) (from the Advanced panel in the editor )aren't passed in the $attributes param to the render_callback function for PHP-only blocks, like they are for JS-registered blocks.
Is this a known problem? Should I open a new issue for it?
One thing I just noticed when testing this in 7.0-beta2, any Additional CSS class(es) (from the Advanced panel in the editor )aren't passed in the $attributes param to the render_callback function for PHP-only blocks, like they are for JS-registered blocks.
Is this a known problem? Should I open a new issue for it?
D'oh...I had added the Additional classes to the wrong block. When added to the correct PHP-only Block the additional CSS classes are passed in the $attributes param.
This is fantastic. I was disappointed with the official Make blog post, which was very light on details.
I haven't tried and inspected the code yet, but my thought while skimming it all was that the interactivity api would be a good match and greatly simplify things. Most of the code just seemed to be for things like toggling css classes, and seemingly happening via server round trips. Perhaps the iAPI would let you do this with a few declarative attributes and signals?
(I have very limited knowledge of how blocks and the block editor work, so it's quite possible that there's various limitations that would prevent this. But surely it's something that could be supported at some point?)
@justintadlock wanted to flag the feedback above. I imagine you all are working on a developer blog post for this but it might be helpful to read through the current dev note feedback.
Activity
youknowriad commentedon Sep 21, 2025
Any thoughts on expanding this API to generate inspector controls based on DataForm and attribute types?
youknowriad commentedon Sep 21, 2025
cc @gziolo @mtias if you have any thoughts.
gziolo commentedon Sep 22, 2025
What are the code examples of the blocks developers could build this way?
There are Shortcode and Embed blocks.
priethor commentedon Sep 22, 2025
Yep, although this would provide higher reusability/distribution, with the code being part of the block instead of part of the content.
mtias commentedon Sep 22, 2025
I'm interested in seeing this also extend to improve pattern registration on the server side, including supporting latest features like bindings.
proweb commentedon Nov 22, 2025
nice feature
But got one question
9 remaining items
tyxla commentedon Feb 3, 2026
I agree that we can use the block version if we need any kind of versioning. I'd be fine to ship this as-is and consider any additions as something for the future.
t-hamano commentedon Feb 14, 2026
I'm now ready to stabilize this feature and would appreciate your feedback. #75543
caseyjmilne commentedon Feb 14, 2026
Does this PHP registration support
<InnerBlocks>like ACF?I wanted PHP registration of blocks with InnerBlocks support in a project recently so I researched how this is handled in ACF. Below is the custom JSX parsing approach that resulted.
With this approach instead of SSR we're transposing the PHP template into JSX thus from the editors perspective the block is identical to one written with React.
t-hamano commentedon Feb 15, 2026
Currently that is not supported.
JiveDig commentedon Feb 17, 2026
Is this a planned feature for a future update? Supporting inner blocks would be great for simple wrapper blocks like this.
t-hamano commentedon Feb 17, 2026
It's not supported in the initial version, but if you don't mind, could you submit a new issue and let us know what features you'd like to see?
wolffe commentedon Mar 4, 2026
This is an awesome improvement! 7 years too late, but it's awesome! Makes me want to go back to building proper server-side blocks.
I created 4 PHP-only blocks so far, in an experimental plugin, and I wrote about it here:
https://getbutterfly.com/php-only-block-registration-in-wordpress/
pbiron commentedon Mar 5, 2026
this is pretty cool for very simple blocks.
One thing I just noticed when testing this in 7.0-beta2, any
Additional CSS class(es)(from theAdvancedpanel in the editor )aren't passed in the$attributesparam to therender_callbackfunction for PHP-only blocks, like they are for JS-registered blocks.Is this a known problem? Should I open a new issue for it?
pbiron commentedon Mar 5, 2026
D'oh...I had added the Additional classes to the wrong block. When added to the correct PHP-only Block the additional CSS classes are passed in the
$attributesparam.Sorry for the false report ;-)
wolffe commentedon Mar 5, 2026
I built some really complex blocks using this functionality. I think simplicity or complexity depends on each developer's skills.
nickchomey commentedon Mar 5, 2026
This is fantastic. I was disappointed with the official Make blog post, which was very light on details.
I haven't tried and inspected the code yet, but my thought while skimming it all was that the interactivity api would be a good match and greatly simplify things. Most of the code just seemed to be for things like toggling css classes, and seemingly happening via server round trips. Perhaps the iAPI would let you do this with a few declarative attributes and signals?
(I have very limited knowledge of how blocks and the block editor work, so it's quite possible that there's various limitations that would prevent this. But surely it's something that could be supported at some point?)
annezazu commentedon Mar 5, 2026
@justintadlock wanted to flag the feedback above. I imagine you all are working on a developer blog post for this but it might be helpful to read through the current dev note feedback.