我有一个WP块<ServerSideRender />
后端中的组件。它可以很好地处理属性。但它不会返回$content
在前端的php回调中使用。
<ServerSideRender
block="mydomain/my-block"
attributes={ attributes }
/>
我在文档中找不到在使用$内容时是否有方法在后端动态呈现块。
这个$content
是嵌套块,因此save()
使用方式如下:
save() {
return <InnerBlocks.Content />;
},
有人知道如何共犯吗?
--编辑--我已添加当前edit()
密码请注意,并非所有内容都相关。重点在于:
使用InnerBlocks
预览按钮的使用。一种状态是编辑内容,另一种状态是使用php回调呈现预览使用ServerSideRender
/**
* 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 );
最合适的回答,由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\'];
*/
}
那么试试这些,告诉我进展如何?=)