How to create a custom Gutenberg block in WordPress

WordPress recently introduced @wordpress/scripts npm package. It is a collection of reusable scripts for WordPress Development. We will learn about how to create a Custom Gutenberg block using ES6 , JSX and @wordpress/scripts package.
Since most browsers cannot support or run ES6 and JSX, we need to use tools Babel to transform these syntaxes, to the code that browsers can understand. Also by using a build tool like Webpack, we can organize our code into smaller modules and then bundle them together into a single download.

The @wordpress/scripts package abstracts these libraries away to standardize and simplify development, so you won’t need to handle the details for configuring those libraries.

Before Starting Development

  • We need WordPress development environment
  • JavaScript build tools (node/npm) if using React/JSX

Create directory for Gutenberg Block in plugins directory

Create a new directory in wordpress/wp-content/plugins with name myFirst-block and install @wordpress/scripts package using npm inside of it. The — save-exact installs the exact version of the @wordpress/scripts package

cd wordpress/wp-content/plugins
mkdir myFirst-block
cd myFirst-block

npm init
npm i --save-dev --save-exact @wordpress/scripts

This will install all required packages and dependencies inside a node_modules directory. Please note that src/index.js will be its entry point and output build file will be in build/index.js

So also create two directories in myFirst-block directory as src and build

This is a CLI and exposes a binary called wp-scripts so we can call it directly. So we will add these script in the package.json

"scripts": {
  "start": "wp-scripts start",
  "build": "wp-scripts build"
},

When we run

npm run start then wp-scripts will run in watch mode So if we make changes in src/index.js then it will automatically create build file for it real time

Create plugin file to Register Block in plugin

We need to register our block server-side to ensure that the script is enqueued when the editor loads, Now we create a plugin file to enquee styles and scripts build/index.js to our block

<?php
/*
Plugin Name: myFirst-block
Author: webkul
*/
function myFirst-block() {

	$styleURI = plugin_dir_url( __FILE__  ).'/src/style.css';
	//Enquee style
	wp_enqueue_style( 
		'myFirst-block-style', 
		$styleURI, 
	 );

	// Register JavasScript File build/index.js
	wp_register_script(
		'myFirstblock',
		plugins_url( 'build/index.js', __FILE__ ),
		array( 'wp-blocks', 'wp-element', 'wp-editor' ),
	);

	// Register editor style src/editor.css
	wp_register_style(
		'myFirst-block-editor-style',
		plugins_url( 'src/editor.css', __FILE__ ),
	);

	// Register block
	register_block_type( 'gutenreact/myFirst-block', array(
		'editor_script' => 'myFirstblock',
		'editor_style' => 'myFirst-block-editor-style',
	) );

}

add_action( 'init', 'myFirst-block' );

Now we need to create index.js file in src directory, this will be our entry point.

In index.js we can register a block with registerBlockType() function, registerBlockType will take two arguments.

  1. Block name : This is a unique identify string for our Block.
  2. Object(Array) : This is a configuration object of our Block. Object [ { key: value } ]
// Registering my first block with a unique name
registerBlockType( 'myCustomBlock/my-first-block', {} );

namespace is the name of our theme or plugin.
This name is used on the comment delimiters as <!-- wp:namespace/block-name --> when the post is saved into the database.

Now we are going to register our first block using registerBlockType() function. Here myFirst-block is my plugin directory my-first-block is my block name. Now we need to put the title, description, icon, and category, Here myCustomBlock is my namespace of plugin.

The edit function is use for editor.

The save function is for frontend and define how the attributes will combine and render a final markup.

Lets bundle it

Create css and js file in myFirst-block/src for styles and scripts.

//src/editor.css
.wp-block-myCustomBlock-my-first-block {
    color: cornflowerblue;
}
//src/style.css
.wp-block-myCustomBlock-my-first-block {
    color: tomato;
}

Our block will shown in gutenberg modules

guten-block

Create advance block for card component

We are going to use useBlockProps React hook on the block wrapper element, useInnerBlocksProps for adding default components of gutenbrg into our custom block like heading, paragraph, buttons etc and MediaUpload for card Image.

Here we will use useInnerBlocksProps for giving support of adding other Blocks inside our custom Block ex: Button, Text, Heading, etc.

// src/index.js
import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps, RichText, MediaUpload,  InnerBlocks } from '@wordpress/block-editor';

registerBlockType('gutenreact/webkul-cards', {
    title: 'Webkul Card Section',
    icon: 'columns',
    category: 'widgets',
    attributes: {
        content: {
            type: 'string',
            source: 'html',
            selector: 'p',
        },
        description: {
            type: 'string',
            source: 'html',
            selector: 'p',
        },
        imgUrl: {
            type: 'string',
        },
    },
    edit: (props) => {
        const {
            attributes: { content, description, imgUrl },
            setAttributes,
        } = props;
        const blockProps = useBlockProps();
        const onChangeContent = (newContent) => {
            setAttributes({ content: newContent });
        };
        const onChangeDescription = (newDescription) => {
            setAttributes({ description: newDescription });
        };
        const onImageSelect = (newImgUrl) => {
            setAttributes({ imgUrl: newImgUrl.sizes.full.url });
        };
        const ALLOWED_BLOCKS = [ 'core/buttons' ];
        return (
            <div className='webkul-card'>
                <MediaUpload onSelect={onImageSelect}
                    render={
                        ({ open }) => {
                            return imgUrl ? <img onClick={open} src={imgUrl} /> : <button onClick={open}> Upload Image </button>
                        }
                    }
                    title="Insert Image"
                />
                <RichText {...blockProps}
                    tagName='h3'
                    onChange={onChangeContent}
                    placeholder='title'
                    value={content} />
                <RichText {...blockProps}
                    tagName='p'
                    onChange={onChangeDescription}
                    placeholder='Short description'
                    value={description} />
                <InnerBlocks allowedBlocks={ ALLOWED_BLOCKS } />
            </div>
        )

    },
    save: (props) => {
        const blockProps = useBlockProps.save();
        return (
            <div className='webkul-card'>
                <img src={props.attributes.imgUrl} />
                <RichText.Content {...blockProps}
                    tagName='h3'
                    value={props.attributes.content} />
                    <RichText.Content {...blockProps}
                    tagName='p'
                    value={props.attributes.description} />
                 <InnerBlocks.Content />
            </div>
        )
    }
});

We can also have a validator function ALLOWED_BLOCKS in which we can allow only selected innerBlocks to add in our custom Block

const ALLOWED_BLOCKS = [ 'core/image', 'core/paragraph' ];
//...
<InnerBlocks allowedBlocks={ ALLOWED_BLOCKS } />;

Here we give support of Image and Paragraph to our custom Block, you can give more Blocks. you can check core blocks here.

Lets bundle it

npm run start

Now our card block is appear in gutenberg editor

Now we write some css for frontend and editor

// src/editor.css

.webkul-card {
    text-align: center;
    background: #d5d5d5;
    padding: 40px 20px;
    border: 1px solid #000000;
}
//  src/style.css

.webkul-card {
    text-align: center;
    background: #d5d5d5;
    padding: 40px 20px;
}
guttenberg-custom-block-development

If you need custom WordPress Development services then feel free to reach us.

!!Have a Great Day Ahead!!


Source link