WP块-古腾堡-<ServerSideRender/>不呈现$Content

时间:2021-03-30 作者:Tim

我有一个WP块<ServerSideRender /> 后端中的组件。它可以很好地处理属性。但它不会返回$content 在前端的php回调中使用。

<ServerSideRender
    block="mydomain/my-block"
    attributes={ attributes }
/>
我在文档中找不到在使用$内容时是否有方法在后端动态呈现块。

这个$content 是嵌套块,因此save() 使用方式如下:

    save() {
        return <InnerBlocks.Content />;
    },
有人知道如何共犯吗?

--编辑--我已添加当前edit() 密码请注意,并非所有内容都相关。重点在于:

使用InnerBlocksServerSideRender

/**
 * WordPress dependencies
 */

const { __ } = wp.i18n;
const {
    InnerBlocks,
    InspectorControls,
    MediaUpload,
    MediaUploadCheck,
    BlockControls,
} = wp.blockEditor || wp.editor; // Fallback to \'wp.editor\' for backwards compatibility
const {
    PanelBody,
    RangeControl,
    Button,
    SelectControl,
    ToolbarGroup,
    ToolbarButton,
    ServerSideRender,
} = wp.components;

const { Component, Fragment } = wp.element;
const { withSelect, select } = wp.data;
const { compose } = wp.compose;

class BlockImageOverlayEdit extends Component {
    render() {

        const {
            clientId,
            attributes,
            className,
            setAttributes,
            hasChildBlocks,
        } = this.props;
        const {
            id,
            preview,
            editorSize,
            bgColor,
            mediaId,
            mediaUrl,
            centerContent,
            mediaSpanCols,
            mediaSpanOffset,
            overlaySpanCols,
            overlaySpanOffset,
            alignX,
            alignY,
        } = attributes;

        if ( id !== clientId ) {
            setAttributes( { id: clientId } );
        }
        const colMaxAmount = 12;
        const sizes = [ \'xs\', \'sm\', \'md\', \'lg\', \'xl\', \'xxl\' ];

        const removeMedia = () => {
            this.props.setAttributes( {
                mediaId: 0,
                mediaUrl: \'\',
            } );
        };

        const onSelectMedia = ( media ) => {
            setAttributes( {
                mediaId: media.id,
                mediaUrl: media.url,
            } );
        };

        const onChangeColumns = ( value ) => {
            const newMediaSpanOffset = (value + mediaSpanOffset) > colMaxAmount ? colMaxAmount - value : mediaSpanOffset;
            setAttributes(
                {
                    mediaSpanCols: value,
                    mediaSpanOffset: newMediaSpanOffset,
                } );
        };
        
        const onChangeColumnsOverlay = ( value ) => {
            const newOverlaySpanOffset = (value + overlaySpanOffset) > colMaxAmount ? colMaxAmount - value : overlaySpanOffset;
            setAttributes(
                {
                    overlaySpanCols: value,
                    overlaySpanOffset: newOverlaySpanOffset,
                } );
        };


        const MyServerSideRender = () => {
// thought. maybe I can fetch, and prerender the inner blocks here, serialize them and set them as an attribute. Right before this return. (and at save() set it back to null)
            return (
                <ServerSideRender
                    block="mydomain/block-wp-block-image-overlay-01"
                    attributes={ attributes }
                />
            );
        };

        const PreviewButton = () => (
            <BlockControls>
                <ToolbarGroup>
                    <ToolbarButton
                        icon={ preview ? \'hidden\' : \'visibility\' }
                        label="Preview"
                        onClick={ () => setAttributes( { preview: ! preview } ) }
                    />
                </ToolbarGroup>
            </BlockControls>
        );

        const BreakpointButtons = () => (
            <ToolbarGroup>
                { sizes.map( ( size, index ) => {
                    return (
                        <ToolbarButton
                            key={ index }
                            style={ { padding: 0.5 + \'em\' } } //TODO: fix spacing
                            isPrimary={ editorSize === size }
                            isSecondary={ editorSize !== size }

                            // icon={ edit }
                            label="Edit"
                            onClick={ () => setAttributes( { editorSize: size } ) }
                        >{ size }</ToolbarButton>
                    );
                } ) }
            </ToolbarGroup>
        );
        const AlignPanel = () => (
            <PanelBody
                title={ __( \'Column size\', \'mydomain\' ) }
                initialOpen={ false }
            >
                <SelectControl
                    label={ __( \'Horizontal align\', \'mydomain\' ) }
                    value={ alignX }
                    options={ [
                        { value: \'start\', label: __( \'Image on the right\', \'mydomain\' ) },
                        { value: \'end\', label: __( \'Image on the left\', \'mydomain\' ) },
                    ] }
                    onChange={ ( value ) => setAttributes( { alignX: value } ) }
                />
                <SelectControl
                    label={ __( \'Vertical align\', \'mydomain\' ) }
                    value={ alignY }
                    options={ [
                        { value: \'start\', label: __( \'Image on the top\', \'mydomain\' ) },
                        { value: \'end\', label: __( \'Image on the bottom\', \'mydomain\' ) },
                    ] }
                    onChange={ ( value ) => setAttributes( { alignY: value } ) }
                />
            </PanelBody>
        );
        const ColumnPanel = () => (
            <PanelBody
                title={ __( \'Column size\', \'mydomain\' ) }
                initialOpen={ false }
            >
                <BreakpointButtons/>

                <RangeControl
                    label={ __( \'Image columns\', \'mydomain\' ) }
                    value={ mediaSpanCols }
                    onChange={ onChangeColumns }
                    min={ 1 }
                    max={ colMaxAmount }
                />

                <RangeControl
                    label={ __( \'Overlay columns\', \'mydomain\' ) }
                    value={ overlaySpanCols }
                    onChange={ onChangeColumnsOverlay }
                    min={ 1 }
                    max={ colMaxAmount }
                />

            </PanelBody>
        );

        const Media = () => (
            <Fragment>
                <MediaUploadCheck>
                    <MediaUpload
                        onSelect={ onSelectMedia }
                        value={ mediaId }
                        allowedTypes={ [ \'image\' ] }
                        render={ ( { open } ) => (
                            <Button
                                className={ mediaId === 0 ? \'editor-post-featured-image__toggle\' : \'editor-post-featured-image__preview\' }
                                onClick={ open }
                            >
                                { mediaId === 0 && __( \'Choose an image\', \'mydomain\' ) }
                                { mediaUrl !== undefined &&

                                <img alt={ \'\' } src={ mediaUrl }/>
                                }
                            </Button>
                        ) }
                    />
                </MediaUploadCheck>
                {
                    mediaId !== 0 &&
                    <MediaUploadCheck>
                        <MediaUpload
                            title={ __( \'Replace image\', \'mydomain\' ) }
                            value={ mediaId }
                            onSelect={ onSelectMedia }
                            allowedTypes={ [ \'image\' ] }
                            render={ ( { open } ) => (
                                <Button
                                    onClick={ open }
                                    isDefault
                                    isLarge>{ __( \'Replace image\', \'mydomain\' ) }
                                </Button>
                            ) }
                        />
                    </MediaUploadCheck>
                }
                {
                    mediaId !== 0 &&
                    <MediaUploadCheck>
                        <Button
                            onClick={ removeMedia }
                            isLink
                            isDestructive>{ __( \'Remove image\', \'mydomain\' ) }
                        </Button>
                    </MediaUploadCheck>
                }
            </Fragment>
        );

        const Overlay = () => (
            <InnerBlocks
                templateLock={ false }
                renderAppender={
                    hasChildBlocks ?
                        undefined :
                        () => <InnerBlocks.ButtonBlockAppender/>
                }
            />
        )
        
        return (
            <Fragment>

                <InspectorControls>
                    <AlignPanel/>
                    <ColumnPanel/>
                </InspectorControls>

                <PreviewButton/>

                { ! preview &&
                <div className={ `${ className }` } style={ { display: \'flex\' } }>
                    <div style={ { width: 50 + \'%\' } }>
                        <Media />
                    </div>

                    <div style={ { width: 50 + \'%\' } }>
                        <Overlay />
                    </div>

                </div> }

                { preview &&
                <MyServerSideRender /> }

            </Fragment>
        );
    }
}

export default compose(
    withSelect

    ( (
        select
        ,
        ownProps
    ) => {
        const {
            clientId
        }
            = ownProps;
        const { getBlockOrder } =
        select( \'core/block-editor\' ) || select( \'core/editor\' ); // Fallback to \'core/editor\' for backwards compatibility

        return {
            hasChildBlocks: getBlockOrder( clientId ).length > 0,
        };
    } )
)
( BlockImageOverlayEdit );

1 个回复
最合适的回答,由SO网友:Sally CJ 整理而成

ServerSideRender uses the Block Renderer API endpoint (/wp/v2/block-renderer/<name>) 它不解析内部块,因此$content 在块中,渲染回调自然为空。

然而,检索内部块非常容易,正如您所想,您可以将块(或其内容)设置为要传递给的属性ServerSideRender.

但不需要保存属性(使用setAttributes()), 因此,它将作为一个;“虚拟”;将与一起使用的属性ServerSideRender 以便块渲染回调将接收内部块。

工作示例,因此我使用innerContent 作为虚拟属性的名称,但只需使用您喜欢的任何名称,并确保在PHP中注册属性。例如。

register_block_type( \'mydomain/block-wp-block-image-overlay-01\', array(
    \'render_callback\' => \'my_block_render_callback\',
    \'attributes\'      => array(
        // the dummy attribute
        \'innerContent\' => array(
            \'type\'    => \'string\',
            \'default\' => \'\',
        ),

        // your other attributes
        \'editorSize\'   => array(
            \'type\'    => \'string\',
            \'default\' => \'md\',
        ),
        // ...
    ),
    // ...
) );
但是在JS中,实际上不需要在attributes 块类型的属性(使用registerBlockType()).

然后在MyServerSideRender, 检索内部块的内容并将内容包括在attributes 的属性ServerSideRender 要素:

Note: 我使用POST作为httpMethod 因为该方法将允许更大的attributes对象。

// ... your code here.
const { compose } = wp.compose;
// 1. After the above line, add the following:

// These are used to retrieve the inner block content.
const { getBlock } = select( \'core/block-editor\' );
const { getBlockContent } = wp.blocks;

// 2. Then define MyServerSideRender like so:
const MyServerSideRender = () => {
    // Retrieve the inner block content.
    const innerContent = getBlockContent( getBlock( clientId ) );

    // Then append the innerContent to the attributes object below.
    return (
        <ServerSideRender
            block="mydomain/block-wp-block-image-overlay-01"
            attributes={ { ...attributes, innerContent } }
            httpMethod="POST"
        />
    );
};
innerContent) 类似这样的属性:

function my_block_render_callback( $attributes, $content ) {
    // On the front-end (or non REST API requests), we use $content.

    if ( defined( \'REST_REQUEST\' ) && REST_REQUEST ) {
        return \'<h3>MyServerSideRender output</h3>\' . $attributes[\'innerContent\'];
    }
    return $content;

    /* Or you could instead just do:
    return $content ? $content : $attributes[\'innerContent\'];
    */
}
那么试试这些,告诉我进展如何?=)

相关推荐