无法编辑服务器端呈现的块

时间:2021-12-01 作者:bgolemba

我对古腾堡街区有意见。我创建了一个块,用于提取最近的自定义帖子类型帖子,并将其显示为旋转木马。

我很难保存那个块,但我在js文件中找到了应该使用ServerSideRender的信息。

现在,我在后端编辑器中遇到了一个问题。添加自定义块时,我无法选择或删除它。

js代码如下:

const { serverSideRender: ServerSideRender } = wp;

wp.blocks.registerBlockType(\'wp-portfolio-manager/wppm-block\', {
    title: \'Portfolio Block\', 
    description: \'Block containing portfolio projects\',
    category: \'common\',
    icon: \'screenoptions\',
    keywords: [
         \'portfolio\',
         \'project\', 
         \'wppm\'
    ],
    supports: {
        html: true, 
        align: true
    },
    attributes: {
        projects_count: {
            type: \'integer\' 
        }
    },
    edit: ( props ) => {
        return <ServerSideRender block="wp-portfolio-manager/wppm-block"></ServerSideRender>;
    },
    save: (props) => {
        return null;
    }
});
export class Portfolio extends React.Component{
    constructor(props){
        super(props);
        this.props = props;
        this.state = {
            error: null,
            postsFetched: false,
            mediaFetched: false,
            posts: []
        };
    }

    componentDidMount(){
        let postes = [];
        fetch("/foobar/wp-json/wp/v2/foobar_post?per_page=5&_embed")
         .then(res => res.json())
         .then(
             (result) => {
                 result.forEach(function(item){
                    postes.push({ 
                        id: item[\'id\'],
                        title: item.title[\'rendered\'],
                        featured_image: item[\'_embedded\'][\'wp:featuredmedia\'][0][\'source_url\'],
                        url: item.link,
                    });
                });
                this.setState({
                    postsFetched: true,
                    mediaFetched:  true,
                    posts: postes
                    }
                );
             },
             (error) => {
                 this.setState({
                    postsFetched: true,
                    mediaFetched: true,
                    error: error
                 });
             }
         );
    }

    render(){
        const {postsFetched, mediaFetched, posts, error} = this.state;

        if(postsFetched && mediaFetched){
            let items = [];
            for(let i = 0; i < this.state.posts.length; i++){
                items.push(
                    <Project post={posts[i]}></Project>
                );
            }
            return <div className="wppm-portfolio">
                {items}
            </div>;
            
        }
        else if(error){
            return <div className="wppm-portfolio error">{error.message}</div>;
        }
        else{
            return <div className="wppm-portfolio loading dashicons dashicons-update"></div>;
        }
    }

}

class Project extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            media: []
        };
    }

    componentDidMount(){
        let medias = [];
        fetch("/foobar/wp-json/wp/v2/media?media_type=image&parent=" + this.props.post.id)
        .then(res => res.json())
        .then(
            (result) => {
                result.forEach(function(item){
                    medias.push(
                        {
                            url: item.source_url,
                            title: item.title[\'rendered\'],
                            alt: item.alt_text
                        }
                        
                    );
                });
                this.setState(
                    { media: medias }
                );
            }
        );
    }

    render(){
        const { post } = this.props;
        const { media } = this.state;
        if(media === null || media == \'undefined\' || media.length < 1)
            return <div className="portfolio-project loading">Loading</div>;

        let gallery = [];
        for(let i = 0; i < media.length; i++){
            gallery.push(
                <ProjectImage url={media[i].url} title={media[i].title} alt={media[i].alt}></ProjectImage>
            );
        }
        return <div className="portfolio-project">
            <div className="project-container">
                <div className="project-actions">
                    <span className="dashicons dashicons-search"></span>
                    <span className="dashicons dashicons-format-gallery"></span>                
                </div>
                <img src={post.featured_image} className="img-fluid"/>
                <div className="project-title">{post.title}</div>
            </div>
            <div className="project-gallery hidden">
                {gallery}
            </div>
        </div>;

    }
}

class ProjectImage extends React.Component{
    constructor(props){
        super(props);
    }

    render(){
        const {url, alt, title} = this.props;
        return <div className="image-container">
            <img src={url} alt={alt} title={title}/>
        </div>;
    }
}
下面是php中render\\u回调函数的代码:


function wppm_portfolio_block_render_callback($block_attributes, $content){
    if ( !defined( \'REST_REQUEST\' ) || !REST_REQUEST ) {
        $projects = wp_get_recent_posts( array(
            \'numberposts\' => 5, //ToDo: Ilość z bloku (w bloku obsłużyć attributes)
            \'post_status\' => \'publish\',
            \'post_type\'   => \'wppm_portfolio\'
        ) );
        if ( count( $projects ) === 0 ) {
            return \'No posts\';
        }
        $elements = \'\';
        foreach($projects as $post){
            $featured_image = get_the_post_thumbnail( $post[\'ID\'] ) == \'\' ? \'<img src="\' . __WPPM_IMG__ . \'/placeholder.jpg\' . \'">\' : get_the_post_thumbnail( $post[\'ID\'] );
            $post_media = get_attached_media( \'image\', $post[\'ID\'] );
            $gallery = \'\';
            if(isset($post_media) && is_array($post_media) && count($post_media) > 1){
                $images = \'\';
                foreach($post_media as $image){
                    $image_tag = wp_get_attachment_image($image->ID, \'full\');
                    $image_element = sprintf(\'
                        <div class="image-container">
                            %1$s
                            <div class="image-title">
                                %2$s
                            </div>
                        </div>\', 
                        $image_tag, 
                        $image->title
                    );
                    $images .= $image_element;
                }
                $gallery = sprintf(
                    \'<div class="project-gallery hidden">
                        %s
                    </div>\',
                    $images
                );
            }
            $element = sprintf(\'<div class="portfolio-project">
                            <div class="project-container">
                                <div class="project-actions">
                                    <span class="dashicons dashicons-search"></span>
                                    <span class="dashicons dashicons-format-gallery"></span>
                                </div>
                                %1$s
                                <div class="project-title">%2$s</div>
                            </div>
                            %3$s
                        </div>\', $featured_image, $post[\'post_title\'], $gallery);
            $elements .= $element;
        }
        $result = sprintf(\'<div class="wppm-portfolio">%s</div>\', $elements);
        return $result;
}
function wppm_portfolio_block(){
    wp_register_script( \'wppm_block\', __WPPM_ADMIN_JS__ . \'/block.js\', array(\'wp-block-editor\', \'wp-blocks\', \'wp-element\', \'wp-i18n\', \'wp-polyfill\', \'wp-server-side-render\'), null);
    register_block_type(\'wp-portfolio-manager/wppm-block\', array(
        \'api_version\' => 2,
        \'editor_script\' => \'wppm_block\',
        \'render_callback\' => \'wppm_portfolio_block_render_callback\'
    ));
}
add_action( \'init\', \'wppm_portfolio_block\' );

我应该怎么做才能使它在后端编辑器上可选择和可删除?

1 个回复
SO网友:Tom J Nowell

您已经使用了基于类的组件,这个问题的正常解决方案是you forgot to use useBlockProps.

编辑组件和保存组件不使用useBlockProps:

    edit: ( props ) => {
        return <ServerSideRender block="wp-portfolio-manager/wppm-block"></ServerSideRender>;
    },
    save: (props) => {
        return null;
    }

Wrap your server side render component in a div and apply useBlockProps to that div and the problem should go away.

类似于此:

<div { ...useBlockProps() }>
    ... etc
</div>
useBlockProps 为块编辑器提供了注入事件处理程序和额外CSS类的机会。这就是它如何设置选定块的样式和处理选择过程,以及设置块移动器动画等。

此外,要警惕基于类的组件。WP挂钩API,如useBlockProps 不要使用基于类的组件。你在这里做的一切都可以用useStateuseEffect, 尽管看起来没有任何基于类的组件在实际使用中。