Site icon Hip-Hop Website Design and Development

Unable to edit server side rendered block

I have a problem with Gutenberg block. I created block which pulls recent custom post type posts and display them as carousel.

I struggled with saving that block but I found info that I should use ServerSideRender in js file.

Now I have a problem in backend editor. When I add my custom block I’m unable to select it or delete.

Below the code of 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>;
    }
}

and here is the code of render_callback function in php:


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' );

What should I do to make it selectable and removable on the backend editor?