Skip to content

Allow PHP-Only Block Registration #71792

Closed

Description

@priethor

What problem does this address?

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.

Tasks

Activity

  1. self-assigned this
    on Sep 21, 2025
  2. added
    [Type] New APINew API to be used by plugin developers or package users.
    and removed
    [Type] New APINew API to be used by plugin developers or package users.
    on Sep 21, 2025
  3. youknowriad commented on Sep 21, 2025

    @youknowriad
    Contributor

    Any thoughts on expanding this API to generate inspector controls based on DataForm and attribute types?

  4. youknowriad commented on Sep 21, 2025

    @youknowriad
    Contributor

    cc @gziolo @mtias if you have any thoughts.

  5. gziolo commented on Sep 22, 2025

    @gziolo
    Member

    What are the code examples of the blocks developers could build this way?

    Enable WordPress sites and classic themes to adopt blocks more easily; blocks could be powerful wrappers for legacy PHP functions or shortcodes.

    There are Shortcode and Embed blocks.

  6. priethor commented on Sep 22, 2025

    @priethor
    ContributorAuthor

    There are Shortcode and Embed blocks.

    Yep, although this would provide higher reusability/distribution, with the code being part of the block instead of part of the content.

  7. mtias commented on Sep 22, 2025

    @mtias
    Member

    I'm interested in seeing this also extend to improve pattern registration on the server side, including supporting latest features like bindings.

  8. proweb commented on Nov 22, 2025

    @proweb

    nice feature
    But got one question

  9. 9 remaining items

  10. tyxla commented on Feb 3, 2026

    @tyxla
    Member

    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.

  11. t-hamano commented on Feb 14, 2026

    @t-hamano
    Contributor

    I'm now ready to stabilize this feature and would appreciate your feedback. #75543

  12. moved this from 📥 Todo to 🏗️ In Progress in WordPress 7.0 Editor Taskson Feb 14, 2026
  13. caseyjmilne commented on Feb 14, 2026

    @caseyjmilne

    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 />;
                }
            }
        });
    }
    
  14. t-hamano commented on Feb 15, 2026

    @t-hamano
    Contributor

    Does this PHP registration support <InnerBlocks> like ACF?

    Currently that is not supported.

  15. moved this from 🏗️ In Progress to ✅ Done in WordPress 7.0 Editor Taskson Feb 17, 2026
  16. JiveDig commented on Feb 17, 2026

    @JiveDig

    Does this PHP registration support <InnerBlocks> like ACF?

    Is this a planned feature for a future update? Supporting inner blocks would be great for simple wrapper blocks like this.

  17. t-hamano commented on Feb 17, 2026

    @t-hamano
    Contributor

    Is this a planned feature for a future update? Supporting inner blocks would be great for simple wrapper blocks like this.

    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?

  18. wolffe commented on Mar 4, 2026

    @wolffe

    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/

  19. pbiron commented on Mar 5, 2026

    @pbiron

    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 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?

  20. pbiron commented on Mar 5, 2026

    @pbiron

    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.

    Sorry for the false report ;-)

  21. wolffe commented on Mar 5, 2026

    @wolffe

    this is pretty cool for very simple blocks.

    I built some really complex blocks using this functionality. I think simplicity or complexity depends on each developer's skills.

  22. nickchomey commented on Mar 5, 2026

    @nickchomey
    Contributor

    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/

    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?)

  23. annezazu commented on Mar 5, 2026

    @annezazu
    Contributor

    @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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions