admin管理员组文章数量:1296310
Let's have a block that creates a Carousel using <InnerBlocks />
:
edit.js
of the parent component returns something like:
return(
<div className="carousel">
<div className="carousel__track">
<ul {...innerBlocksProps} className="carousel__list" />
</div>
</div>
)
edit.js
of the child returns something like:
return(
<li class="slide">
<figure>
<img src={url} data-id={id} alt={title} />
<figcaption>
<h5>{caption}</h5>
</figcaption>
</figure>
</li>
)
In the parent edit.js
I would create a state like; const [isPreview, setIsPreview] = useState(false)
and when I click a "edit" button the state is set to false
, when I click a "preview" button the state is set to true
.
I thought that when the parent state isPreview
is true
I could render the Carousel via <ServerSideRender />
, so I've created a server-side rendered block, let's call it "myblocks/carousel-preview" and I've changed the edit.js
parent like that:
return(
{
!isPreview
?
<div className="carousel">
<div className="carousel__track">
<ul {...innerBlocksProps} className="carousel__list" />
</div>
</div>
)
:
<>
<ServerSideRender
block="myblocks/carousel-preview"
attributes={{ /* pass children here?!? */ }}
/>
</>
My main problem is: how can I pass to my <ServerSideRender />
block the children of my block?
In fact, I thought that the markup of the <ServerSideRender />
could be something like:
<?php
function RenderCarouselServerSide($attributes, $content) {
ob_start();
?>
<div class="carousel">
<div class="carousel__track">
<ul class="carousel__list" />
<?php foreach($attributes['children'] as $child) :
$url = $child['url'];
$id = $child['id'];
$caption = $child['caption'];
?>
<li class="slide">
<figure>
<img src="<?php echo $url; ?>" data-id="<?php echo $id; ?>" />
<figcaption>
<h5>"<?php echo $caption; ?>"</h5>
</figcaption>
</figure>
</li>
</ul>
<?php endforeach; ?>
</div>
</div>
<?php
return ob_get_clean();
}
But how to pass the children as $attributes
?
Let's have a block that creates a Carousel using <InnerBlocks />
:
edit.js
of the parent component returns something like:
return(
<div className="carousel">
<div className="carousel__track">
<ul {...innerBlocksProps} className="carousel__list" />
</div>
</div>
)
edit.js
of the child returns something like:
return(
<li class="slide">
<figure>
<img src={url} data-id={id} alt={title} />
<figcaption>
<h5>{caption}</h5>
</figcaption>
</figure>
</li>
)
In the parent edit.js
I would create a state like; const [isPreview, setIsPreview] = useState(false)
and when I click a "edit" button the state is set to false
, when I click a "preview" button the state is set to true
.
I thought that when the parent state isPreview
is true
I could render the Carousel via <ServerSideRender />
, so I've created a server-side rendered block, let's call it "myblocks/carousel-preview" and I've changed the edit.js
parent like that:
return(
{
!isPreview
?
<div className="carousel">
<div className="carousel__track">
<ul {...innerBlocksProps} className="carousel__list" />
</div>
</div>
)
:
<>
<ServerSideRender
block="myblocks/carousel-preview"
attributes={{ /* pass children here?!? */ }}
/>
</>
My main problem is: how can I pass to my <ServerSideRender />
block the children of my block?
In fact, I thought that the markup of the <ServerSideRender />
could be something like:
<?php
function RenderCarouselServerSide($attributes, $content) {
ob_start();
?>
<div class="carousel">
<div class="carousel__track">
<ul class="carousel__list" />
<?php foreach($attributes['children'] as $child) :
$url = $child['url'];
$id = $child['id'];
$caption = $child['caption'];
?>
<li class="slide">
<figure>
<img src="<?php echo $url; ?>" data-id="<?php echo $id; ?>" />
<figcaption>
<h5>"<?php echo $caption; ?>"</h5>
</figcaption>
</figure>
</li>
</ul>
<?php endforeach; ?>
</div>
</div>
<?php
return ob_get_clean();
}
But how to pass the children as $attributes
?
1 Answer
Reset to default 5 +50My 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 } = wpponents; // 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;
withconst 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.
本文标签:
版权声明:本文标题:Is it possible to use <ServerSideRender > to create a "switchable" preview of a Carousel Gutenbe 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741632829a2389465.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论