1

Is there any possibility to detect, either in React or PHP, whether or not a block uses server-side rendering?

The only thing I could came up with is checking whether the save function of the block returns null, but that’s not reliable.

Example of this try:

const checkServersideRender = ( settings ) => {
    // if a block returns null on save, it's server-side rendered
    // which is not supported
    try {
        const saveCall = settings.save.call( this, settings );
        
        if ( saveCall === null ) {
            // server-side render, I guess
        }
    }
    catch ( e ) {}
    
    return settings;
}

addFilter( 'blocks.registerBlockType', 'my/attributes', checkServersideRender, 5 );

Is there any reliable possibility to check that?

Background: adding custom attributes for server-side rendered blocks may break them.

1
  • what do you custom attributes do?
    – Tom J Nowell
    Commented Jul 3, 2023 at 14:55

2 Answers 2

3

In PHP, it's certainly possible to check if a block type is dynamic or whether the block uses server-side rendering. For example for already registered block types, just get the block type object and call its is_dynamic method.

$block_registry = WP_Block_Type_Registry::get_instance();

$block_name        = 'core/latest-posts';
$block_type_object = $block_registry->get_registered( $block_name );

if ( $block_type_object ) {
    // Note: render_callback is not included in the REST API response.
    var_dump(
        $block_name,
        $block_type_object->is_dynamic(),
        $block_type_object->render_callback
    );
}

In Gutenberg though, for now you would need to fetch the block type object/data from the Block Types API endpoints, and just check whether the block type's is_dynamic property is true.

But you could combine PHP and JS: Add a constant/variable which stores the names of the dynamic block types, and in checkServersideRender(), just check whether settings.name is in the list.

Example using get_dynamic_block_names() and wp_add_inline_script():

  • PHP:

    add_action( 'enqueue_block_editor_assets', 'my_enqueue_block_editor_assets' );
    function my_enqueue_block_editor_assets() {
        wp_add_inline_script(
            'wp-blocks',
            sprintf(
                'const DYNAMIC_BLOCKS = %s;',
                wp_json_encode( get_dynamic_block_names() )
            )
        );
    }
    
  • JS:

    const checkServersideRender = ( settings ) => {
        if ( DYNAMIC_BLOCKS.indexOf( settings.name ) >= 0 ) {
            // it's a dynamic block type; add your attributes
        }
    
        return settings;
    };
    

But then, for what you're trying to do, it's probably better/easier to just add your custom attributes using the register_block_type_args hook. That way, you wouldn't need to worry about breaking server-side rendered blocks, or that you would be free from the rest_invalid_param error as stated in the previous revision.

add_filter( 'register_block_type_args', 'my_register_block_type_args' );
function my_register_block_type_args( $args ) {
    $args['attributes']['your_attribute'] = array(
        'type'    => 'boolean',
        'default' => false,
    }

    return $args;
}
1

Is there any reliable possibility to check that?

Not in JS, and only somewhat in PHP, because even a block that you hand crafted yourself to not be server rendered can still be modified/edited/added to/edited out by the block rendering filters and callbacks on the server side.

The problem here is that what you're doing is fundamentally brittle. For example if your code changes, or is disabled, every single block it ever touched will fail block validation.

Instead some notes:

  • adding extra attributes to a block doesn't mean you have to store those attributes in the HTML, WP will quite happily save them in the block comment HTML in the JSON attributes section
  • modifying the HTML to add your customizations server side is more reliable, especially if done on render
    • even the official docs use this method, e.g.
  • doing this at all is usually avoidable, be it via block styles, block variants, HTML classes, etc
    • the vast majority of people trying to insert brand new attributes on to core blocks are doing it because they're unaware of block styles. E.g. people trying to modify gallery blocks to add new options such as tiling, when Jetpack does it with a tiled gallery block style that lets them do it with a HTML class and full compatibility avoiidng all of those problems

In your situation I'd make these 2 changes at a minimum:

  • re-implement the JS filter that adds the block attributes as a PHP filter on the register_block_type_args filter. This means that PHP is aware of your attributes, and they show in the REST API and get preloaded by the block editor
  • a lot of the attributes are being used in a save filter to modify the HTML classes attribute, instead directly modify the classes attribute and skip the save filter/dedicated attributes. This simplifies those parts greatly, and has a lot of precedent as it's how WordPress detects and identifies block styles. Core itself will make the effort to ensure the class names persist as it's a foundational part of block styles and global styles
8
  • I’m actually trying to exclude server-side rendered blocks because they have problems with custom attributes. I need these attributes for my plugin "Block Control" to control the visibility of a block. I don’t think that is possible with block styles, variations and such (the block is then completely removed in PHP, not hidden via CSS).
    – KittMedia
    Commented Jul 3, 2023 at 16:15
  • I don't see why this would be a problem then or why you would ever need to touch the save component at all, set a block attribute on the block and it'll get saved in the JSON, then you can use a block rendering filter to return an empty string based on that attributes value. That way of doing it works 100% with server rendered blocks, and always will. The reason it breaks for server rendered blocks is because the chosen implementation is incorrect
    – Tom J Nowell
    Commented Jul 3, 2023 at 16:56
  • I would also note that another method that involves no attributes at all exists, wrapping the chosen blocks in a containing block that you built. This is how HTML and React would do it via composition. Eitherway what you seek is not possible to implement using a javascript hook in the editor, particularly since you can't know the condition until after the post is saved and the editor no longer exists. Modifying what gets saved will also interfere with post content in a way that could lead to data loss
    – Tom J Nowell
    Commented Jul 3, 2023 at 16:59
  • take a look at developer.wordpress.org/reference/hooks/render_block, you can check your attribute by looking at the parsed block it gives you, and return "" if the block needs to be hidden/removed. Doing this won't destroy data in the backend/database, and is fully compatible with all forms of block rendering
    – Tom J Nowell
    Commented Jul 3, 2023 at 17:01
  • 1
    also I see there's JS code that adds attributes on block registration via filtering, but the PHP side is unaware of these, so they don't show in the REST API. A PHP first approach may allow that JS code to be eliminated while ensuring that PHP rendered blocks are aware of those attributes. It's still not as simple as checking the class names which would simplify things greatly, but it would mean your attributes show up in the REST API and preloaded registrations automatically without JS, and can be filtered in PHP. register_block_type_args looks like the filter you would use for that
    – Tom J Nowell
    Commented Jul 5, 2023 at 11:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.