Support » Plugin: Gutenberg » create a custom editable block that really works

  • Resolved Jose

    (@giuse)


    Hello
    I’m really not able to add an editable custom block. I’ve read a lot of tutorials and used some boilerplate plug-ins. But no one is working.
    I would like to create a custom editable block, with the editable parameters on the right sidebar. I’m struggling a lot, but I’m not able to see the right sidebar working.
    If I look at the documentation at https://wordpress.org/gutenberg/handbook/blocks/block-controls-toolbars-and-inspector/ I see an example for Toolbars but no examples for the Inspector. Is it possible to have a working simple example including a couple of parameters editable on the right sidebar? Checking in the Gutenberg plug-in is too much, I’m sure it could be possible to provide a more simple example that works. Thank you in advance

Viewing 3 replies - 1 through 3 (of 3 total)
  • jhotadhari

    (@jhotadhari)

    Hi,

    The edit function returns a description of your block.
    – Everything wrapped in a InspectorControls component will appear on the right sidebar.
    – Everything wrapped in a BlockControls component will appear in the block-toolbar on top of the block. Well, components have to be ‘kind of special’ to fit in there.
    – Everything else will appear inside the block.

    An example block:

    /**
     * WordPress dependencies
     */
    const { __ } = wp.i18n;
    const { registerBlockType } = wp.blocks;
    const { ColorPalette, PanelBody } = wp.components;
    const { RichText, InspectorControls, BlockControls, AlignmentToolbar } = wp.editor;
    
    registerBlockType( 'tstg/my-block', {
    	title: __( 'My Block' ),
    	category: 'common',		// [ common | formatting | layout | widgets | embed ]
    
        attributes: {
            content: {
                type: 'array',
                source: 'children',
                selector: 'p',
            },
            color: {
                type: 'string',
                // default: '#000000',
            },
            alignment: {
                type: 'string',
            	// default: 'left',
            },
        },
    
        edit( { attributes, setAttributes } ) {
        	const { content, color, alignment } = attributes;
    
        	// let's return an array of components
            return ([
    
    			/*
    				RichText component as example
    				with style property
    			*/
    			<RichText
    				tagName='p'
    				placeholder={__('Example RichText Component ... is empty')}
    				value={ content }
    				style={{color, textAlign: alignment}}
    				onChange={ ( content ) => setAttributes({content}) }
    			/>,
    
    			/*
    				Everything wrapped in an InspectorControls component
    				will appear in the right sidebar and not within the block.
    			*/
    			<InspectorControls>
    				{/*
    					ColorPalette wrapped in a PanelBody.
    					onChange: set the color attribute
    				*/}
    				<PanelBody title={__('Font Color')}>
    					<ColorPalette
    						value={ color }
    						onChange={ (newHex) => setAttributes({color:newHex}) }
    					/>
    				</PanelBody>
    			</InspectorControls>,
    
    			/*
    				This is exactly same like above,
    				but not wrapped in an InspectorControls components.
    				So it will just appear inside the block.
    			*/
    			<PanelBody title={__('Font Color')}>
    				<ColorPalette
    					value={ color }
    					onChange={ (newHex) => setAttributes({color:newHex}) }
    				/>
    			</PanelBody>,
    
    			/*
    				Everything wrapped in an BlockControls component
    				will appear in the block-toolbar on top of the block
    			*/
                <BlockControls key="controls">
    				{/*
    					AlignmentToolbar component
    					see https://wordpress.org/gutenberg/handbook/blocks/block-controls-toolbars-and-inspector/#toolbar
    				*/}
                    <AlignmentToolbar
                        value={ alignment }
                        onChange={ (newAlignment) => setAttributes({alignment: newAlignment}) }
                    />
    
                    {/*
                    // Well, you could have the ColorPalette component in your toolbar as well
                    // it works, but breaks the style
    				<ColorPalette
    					value={ color }
    					onChange={ (newHex) => setAttributes({color:newHex}) }
    				/>
    				*/}
                </BlockControls>,
    
            ]);
        },
    
        save( { attributes } ) {
        	const { content, color, alignment } = attributes;
    
            return (
    			<RichText.Content
    				style={{color, textAlign: alignment}}
    				tagName='p'
    				value={ content }
    			/>
    		);
        }
    
    });

    Does that answer your question?

    Thread Starter Jose

    (@giuse)

    Really thanks for your answer!
    In the console I get this error: Uncaught SyntaxError: Unexpected token <
    It’s related to the line where you have <RichText
    The script where I’ve written the example you have provided, is enqueued after the following core scripts:
    ‘wp-blocks’, ‘wp-i18n’, ‘wp-element’,’wp-components’,’underscore’

    Should I enqueue additional core scripts? Or should I compile something?

    Thank you very much in advance

    jhotadhari

    (@jhotadhari)

    Hi,
    mmmmm, I don’t get that error.

    WordPress v4.9.7
    Gutenberg v3.3.0

    I enqueue the script with this dependencies: ‘wp-blocks’, ‘wp-i18n’, ‘wp-element’
    And hooked into: ‘enqueue_block_editor_assets’

    I use following class to register the ‘My Block’ and enqueue the scripts/styles.
    Looks little different to most examples, hope it’s not to confusing. But it’s same same, just wrapped in a class.
    The public function enqueue_editor_assets in line 122, enqueues assets for the editor.

    
    <?php
    
    // If this file is called directly, abort.
    if ( ! defined( 'WPINC' ) ) {
    	die;
    }
    
    class Tstg_Block_My_block {
    
    	protected static $instance = null;
    	protected $namspace = 'tstg/my-block';
    
    	protected $handles = array(
    		'editor' => 'tstg_block_my_block_editor',
    		'frontend' => 'tstg_block_my_block_frontend',
    	);
    
    	public static function get_instance() {
    		if ( null === self::$instance ) {
    			self::$instance = new self();
    			self::$instance->hooks();
    		}
    
    		return self::$instance;
    	}
    
    	protected function __construct() {
    		// ... silence
    	}
    
    	public function hooks() {
    		add_action( 'init', array( $this, 'register_block' ) );
    		add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_editor_assets' ) );
    		add_action( 'enqueue_block_assets', array( $this, 'enqueue_frontend_assets' ) );
    	}
    
    	public function register_block() {
    		if ( function_exists( 'register_block_type' ) ) {
    			register_block_type( $this->namspace, array(
    				'editor_script' => $this->get_handle( 'editor' ),
    				'editor_style' => $this->get_handle( 'editor' ),
    				// 'style' => 'tstg_block_my_block',		// dont set a style here. use hook instead and check if post_has_block
    				// 'script' => 'tstg_block_my_block',		// dont set a style here. use hook instead and check if post_has_block
    				'render_callback' => array( $this, 'render' ),
    			) );
    		}
    	}
    
    	protected function get_handle( $key ){
    		$handles = $this->handles;
    		if ( array_key_exists( $key, $handles ) ){
    			return $handles[$key];
    		}
    	}
    
    	protected function post_has_block(){
    		global $post;
    
    		if ( strlen( $post->post_content ) === 0 )
    			return false;
    
    		$block_pattern = (
    			'/<!--\s+wp:(' .
    			str_replace( '/', '\/',                 // Escape namespace, not handled by preg_quote.
    				preg_quote( $this->namspace )
    				) .
    			')(\s+(\{.*?\}))?\s+(\/)?-->/'
    			);
    		return preg_match( $block_pattern, $post->post_content, $block_matches ) === 1;
    	}
    
    	protected function get_localize_data(){
    		// global $post;
    		// $current_user = wp_get_current_user();
    		// return array(
    		// 	'pluginDirUrl' => Tstg_Testing::plugin_dir_url(),
    		// 	'user' => array(
    		// 		'id' => $current_user->ID,
    		// 	),
    		// 	'post' => array(
    		// 		'id' => $post->ID,
    		// 	)
    		// );
    		return array();
    	}
    
    	// hooked on enqueue_block_assets. So function will run in admin and frontend.
    	// But we will use it only on frontend if the post has this block
    	public function enqueue_frontend_assets() {
    
    		// check if we are on frontend and the post has a block
    		// ... Might be a bad way in future wp versions. Nowadays works well, Let's see.
    		if ( is_admin() || ! $this->post_has_block() )
    			return;
    
    		$handle = $this->get_handle( 'frontend' );
    
    		wp_enqueue_style(
    			$handle,
    			Tstg_Testing::plugin_dir_url() . '/css/' . $handle . '.min.css',
    			array( 'wp-blocks' ),
    			filemtime( Tstg_Testing::plugin_dir_path() . 'css/' . $handle . '.min.css' )
    		);
    
    		wp_register_script(
    			$handle,
    			Tstg_Testing::plugin_dir_url() . '/js/' . $handle . '.min.js',
    			array(
    				// 'wp-backbone',
    				// 'wp-api',
    				// 'utils',
    				),
    			filemtime( Tstg_Testing::plugin_dir_path() . 'js/' . $handle . '.min.js' )
    		);
    
    		wp_localize_script( $handle, 'tstgData', $this->get_localize_data() );
    
    		wp_enqueue_script( $handle );
    	}
    
    	// hooked on enqueue_block_editor_assets. So function will only run in admin
    	public function enqueue_editor_assets() {
    		$handle = $this->get_handle( 'editor' );
    
    		wp_register_script(
    			$handle,
    			Tstg_Testing::plugin_dir_url() . '/js/' . $handle . '.min.js',
    			array(
    				'wp-blocks',
    				'wp-i18n',
    				'wp-element',
    			),
    			filemtime( Tstg_Testing::plugin_dir_path() . 'js/' . $handle . '.min.js' )
    		);
    
    		wp_localize_script( $handle, 'tstgData', $this->get_localize_data() );
    
    		wp_enqueue_script( $handle );
    
    		wp_enqueue_style(
    			$handle,
    			Tstg_Testing::plugin_dir_url() . '/css/' . $handle . '.min.css',
    			array( 'wp-edit-blocks' ),
    			filemtime( Tstg_Testing::plugin_dir_path() . 'css/' . $handle . '.min.css' )
    		);
    	}
    
    }
    
    function tstg_block_my_block_init() {
    	return Tstg_Block_My_block::get_instance();
    }
    
    tstg_block_my_block_init();
    
    ?>
    
Viewing 3 replies - 1 through 3 (of 3 total)
  • The topic ‘create a custom editable block that really works’ is closed to new replies.