Is it possible to use to create a “switchable” preview of a Carousel Gutenberg block?

My main problem is: how can I pass to my <ServerSideRender /> block
the children of my block?

Well actually, you might not need to use ServerSideRender..

If you just wanted to see a preview of the block output coming from the save() function, then you could simply use getSaveElement() to get that output, or the element returned by the save function.

Here’s an example where I’m using the useBlockProps hook introduced in block API version 2: (these are all for the main/parent block)

  • Variables I used:

    // Used in the 'edit' and 'save' functions.
    const { useBlockProps, InnerBlocks } = wp.blockEditor;
    
    // Used in the 'edit' function.
    const { useState } = wp.element;
    const { Button } = wp.components;
    
    // Used in the preview function.
    const { select } = wp.data;
    const { getSaveElement } = wp.blocks;
    
  • My edit function:

    const edit = ( { clientId } ) => {
        const blockProps = useBlockProps();
    
        const [ isPreview, setIsPreview ] = useState( false );
        const setPreviewMode = () => setIsPreview( ! isPreview );
    
        const innerBlocksProps = { /* your code */ };
    
        return (
            <div { ...blockProps }>
                { isPreview ? (
                    <PreviewBlock
                        clientId={ clientId }
                    />
                ) : (
                    <div className="carousel">
                        <div className="carousel__track">
                            <ul { ...innerBlocksProps } className="carousel__list">
                                <InnerBlocks allowedBlocks={ [ 'myblocks/carousel-child' ] } />
                            </ul>
                        </div>
                    </div>
                ) }
                <Button onClick={ setPreviewMode }>{ isPreview ? 'Close Preview' : 'Preview' }</Button>
            </div>
        );
    };
    
  • My save function:

    const save = () => {
        const blockProps = useBlockProps.save( { className: 'carousel' } );
    
        const innerBlocksProps = { /* your code */ };
    
        return (
            <div { ...blockProps }>
                <div className="carousel__track">
                    <ul { ...innerBlocksProps } className="carousel__list">
                        <InnerBlocks.Content />
                    </ul>
                </div>
            </div>
        );
    };
    
  • And my preview function/component:

    function PreviewBlock( { clientId } ) {
        const { getBlock } = select( 'core/block-editor' );
    
        const block = getBlock( clientId );
    
        return getSaveElement( 'myblocks/carousel', block.attributes, block.innerBlocks );
    }
    

If you would rather use ServerSideRender, though:

Or if you just need to, then you can use getBlocks() to retrieve the inner/child blocks, then get the attributes of each of the child block, and include the attributes in the attributes property of the ServerSideRender element.

So based on my code above, I would only need to make these two changes:

  • In the Variables I used part, replace the const { getSaveElement } = wp.blocks; with const ServerSideRender = wp.serverSideRender;.

  • Then change the preview function to:

    function PreviewBlock( { clientId } ) {
        const { getBlocks } = select( 'core/block-editor' );
    
        // Get the attributes of the inner/child blocks.
        const blocks = getBlocks( clientId ).map( block => block.attributes );
    
        return (
            <ServerSideRender
                block="myblocks/carousel-preview"
                attributes={ { children: blocks } }
                httpMethod="POST"
            />
        );
    }
    

    Note that the httpMethod (HTTP request method) doesn’t have to be set to POST, but POST will allow a bigger attributes object.

And remember, you must register the above children attribute in PHP (via register_block_type()). E.g.

Note: The attribute name doesn’t have to be children. You can use any other name you like. But be sure the name matches the one used in the preview function above.

register_block_type( 'myblocks/carousel-preview', array(
    'apiVersion'      => 2,
    'render_callback' => 'RenderCarouselServerSide',
    'attributes'      => array(
        'children' => array(
            'type'    => 'array',
            'default' => array(),
        ),
    ),
) );

So I hope that helps and you might want to check my answer here which sends the block content instead of the inner blocks atrributes, to the server-side renderer.