Skip to content

[Blocks] Basics

picasso edited this page Nov 7, 2021 · 14 revisions

Custom Blocks Basics

If you plan to support custom blocks for WordPress Block Editor in a plugin/theme, then the framework has some functionality, which makes it easier to create such blocks.

Basically, all the functionality of custom blocks is implemented in JavaScript and it takes little effort and a little PHP code to register and activate them in WordPress. And precisely because these actions are quite the same and are repeated from project to project - all this was moved into a separate block of functionality, which is implemented in this framework as an add-on.

In order to use this functionality, you need to specify a list of blocks in your configuration.

Blocks Names and Namespace

The minimum you should do is specify the names of the block/blocks you are going to support. This is done through the blocks key in the blocks section of the configuration. You can specify one name or an array of names if you want to register multiple blocks. The names can be specified together with the namespace in the form myplugin/block-one or you can specify the namespace separately and list only the block names (in this case, the namespace you specified will be added to the block name automatically). You can also change which blocks are available on your front-end (by default, all are assumed to be available).

protected function config() {
    return  [
        // other config options...         

        // custom blocks
        'blocks'          => [
            'namespace'         => 'myplugin',
            'blocks'            => ['block-one', 'block-two'],
            'frontend_blocks'   => 'block-one',
        ],
    ];
}

Scripts & Styles

The main functionality of the blocks is implemented in JavaScript. That is why the script for your blocks will be loaded automatically when requested by WordPress. The name for the script and its location will be generated based on Naming Conventions. You can change this by overriding the handle key in the config. If you do not need to load CSS styles for the WordPress Block Editor, then you need to set the load_css key to false (here we are talking about the styles that are required by your blocks in the Block Editor, but not those that are needed for the block to display correctly on front-end - they will be discussed below).

It's actually easy to get confused about when and what scripts/styles should be loaded. For custom blocks, the number of loaded elements reaches four (for one block) and the number of their combinations is even greater.

The JS script that implements the block support in the WordPress Block Editor is the main one. This script is always loaded. There is also a stylesheet that supports your block presentation in the Block Editor. It may or may not be required if your block is fairly simple and does not require additional CSS rules. If you do not need styles for your block in the Block Editor, then their loading can be disabled using load_css (see above). In addition, there are styles that are responsible for the correct display of your block on the front-end. And, most likely, they will be needed inside the Block Editor as well, since it works in WYSIWYG mode. Of course, these styles can be simply duplicated into the stylesheet mentioned above, but it's much easier to load the file with the front-end styles. This can be controlled using the load_frontend_css key. By default it is set to true and if you don't want your front-end styles to load in the Block Editor then set it to false. The same goes for the front-end JS script with the only difference that by default the load_frontend_js key is set to false.

protected function config() {
    return  [
        // other config options...         

        // custom blocks
        'blocks'          => [
            'namespace'         => 'myplugin',
            'blocks'            => 'super-block',

            // scripts and styles to be loaded for the WordPress Block Editor (Gutenberg)
            'load_zukit'        => true,
            'load_css'          => false,
            'load_frontend_css' => true,
            'load_frontend_js'  => true,
            'handle'            => 'myplugin-super-block',
        ],
    ];
}

Please note that front-end styles and scripts will only be loaded if you have specified this in the main plugin/theme using the should_load_css and should_load_js methods. If you need additional styles and scripts, then you need to override the blocks_enqueue_more method. The first argument to this method is $is_frontend, which will allow you to detect in which environment you are loading additional scripts/styles.

If your block is present on the front-end page, then its main script and style will be loaded automatically (it depends on whether this block is in the frontend_blocks list and on the values ​​returned by the overridden methods should_load_css and should_load_js).

If, in addition to the main scripts, you need to load additional scripts/styles on the front-end (for example, Google reCAPTCHA), then this is achieved by overriding the blocks_enqueue_more method. Unlike the Block Editor, for the front-end this method will be called with three arguments: $is_frontend,$block_name and $attributes. The second and third arguments will help you decide whether to load additional scripts if their presence is associated with some attributes of your block. On the page there may be several blocks, so $attributes is an array of attributes for all blocks on the page.

❗ And don't forget to add the block to the frontend_blocks list otherwise the blocks_enqueue_more method will not be called for your block.

❗ Please note that not all the attributes of your block will be included in the argument of this method, but only those for which the source has not been defined in their description (that is, only those attributes that remained inside the special comments for the block description).

// enqueue Google reCaptcha script if block 'my/form' with needed attributes found on page
public function blocks_enqueue_more($is_frontend, $block_name, $attributes) {
    if($is_frontend && $block_name === 'my/form') {
        // '$attributes' is an array of attributes for all blocks on the page
        foreach($attributes as $block_attr) {
            $recaptcha_enabled = $block_attr['useRecaptcha'] ?? false;
            if($recaptcha_enabled) {
                $absolute_path = 'https://www.google.com/recaptcha/api.js?hl=' . get_locale();
                $this->enqueue_script($absolute_path, [
                    'handle'        => $this->prefix_it('recaptcha2'),
                    'bottom'        => false,
                    'absolute'      => true,
                    'async'         => true,
                    'defer'         => true,
                ]);
                // we should enqueue reCaptcha only once, therefore, we interrupt the loop
                break;
            }
        }
    }
}

Instance

By default, the framework creates an instance of the zukit_Blocks class if the list of blocks in the configuration is not empty. Usually the basic functionality of this class is sufficient for most cases. But there is an option when you can use your class inheriting the class zukit_Blocks. This will allow you to override many methods and more flexible control over the process of registering blocks and loading scripts / styles. In order for the framework to use the instance of your class, it must be passed in the configuration using the instance key.

class my_Blocks extends zukit_Blocks {

    protected function get_block_args($block) {
        if($block === 'myplugin/my-block') {
            $args = [
                'editor_script'  => 'my-block-script',
                'style'          => 'my-block',
            ];
            return $args;
        } else {
            return parent::get_block_args($block);
        }
    }

    // 'block_assets' will be called in the Block Editor as well as on front-end
    // here you can load front-end theme/plugin scripts for the Block Editor
    public function block_assets() {
        if(is_admin()) {
            $recaptcha_path = 'https://www.google.com/recaptcha/api.js?hl='.get_locale();
            $this->enqueue_script($recaptcha_path, [
                'handle'      => 'recaptcha2',
                'bottom'      => false,
                'absolute'    => true,
                'async'       => true,
                'defer'       => true,
            ]);
        }
    }
}
protected function config() {

    $my_blocks = new my_Blocks;
    return  [
        // other config options...         

        // custom blocks
        'blocks'          => [
            'namespace'         => 'myplugin',
            'blocks'            => 'my-block',

            'instance'          => $my_blocks,
        ],
    ];
}

Clone this wiki locally