Gutenberg: Jak vytvořím vlastní blok?

// obsah 6
  1. 01 1) Vytvořit plugin
  2. 02 2) Instalace @wordpress/scripts
  3. 03 3) Samotný blok
  4. 04 4) Kompilace JavaScriptu
  5. 05 5) Aktivace pluginu
  6. 06 6) Použití

Gutenberg je nový editor obsahu pro WordPress. Momentálně pracuji na projektu, kde pro něj vytvářím i vlastní editační bloky, tak se chci podělit o nějaký mustr, kde lze editovat text a obrázek.  Jednotlivé kroky popíšu. Celý kód jsem dal na Github: github.com/MichalKatuscak/gutenberg-blocks/

1) Vytvořit plugin

V první kroku si vytvořím plugin, který do Gutenberga bude bloky „přidávat“. Slouží de facto jen k registraci JavaScriptu a CSS stylu pro blok v editoru a CSS pro vykreslení bloku.

/wp-content/plugins/katuscak-gutenberg/katuscak-gutenberg.php

<?php
/*
Plugin Name: Katuscak Gutenberg Blocks
Description: Gutenberg plugin with awesome blocks
Author: Michal Katuščák
Version: 0.1
Author URI: https://www.katuscak.cz/
*/

function katuscak_gutenberg_block_editor_assets() {
    wp_enqueue_script(
        'katuscak-gutenberg/blockquote-with-image-editor',
        plugins_url("/build/index.js",__FILE__),
        ['wp-blocks', 'wp-editor', 'wp-element']
    );

    wp_enqueue_style(
        'katuscak-gutenberg/blockquote-with-image-editor',
        plugins_url("/gutenberg/blocks/blockquote-with-image/editor.css",__FILE__),
        ['wp-edit-blocks']
    );
}

add_action('enqueue_block_editor_assets', 'katuscak_gutenberg_block_editor_assets');

function katuscak_gutenberg_block_assets() {
    if (!is_admin()) {
        wp_enqueue_style(
            'katuscak-gutenberg/blockquote-with-image',
            plugins_url('/gutenberg/blocks/blockquote-with-image/view.css', __FILE__)
        );
    }
}

add_action('enqueue_block_assets', 'katuscak_gutenberg_block_assets');

2) Instalace @wordpress/scripts

Ve složce s pluginem s nainstaluji npm balík @wordpress/scripts, který má vše potřebné pro kompilaci JavaScriptu. Celý Gutenberg je především JavaScript, takže i blok jako takový bude napsaný v něm.

$ npm init
$ npm install --save-dev --save-exact @wordpress/scripts

Poté si do package.json přidám sekci skriptů, takže celý package.json bude vypadat následovně:

{
  "name": "katuscak-gutenberg",
  "version": "1.0.0",
  "description": "",
  "main": "block.js",
  "dependencies": {},
  "devDependencies": {
    "@wordpress/scripts": "^3.1.0"
  },
  "scripts": {
    "start": "wp-scripts start",
    "build": "wp-scripts build"
  },
  "author": "",
  "license": "ISC"
}

Existuje i jednodušší cesta, kdy žádný JavaScript nekompilujete, ale osobně takový JavaScript psát nechci a raději si dám jednou práci s nastavení npm, abych ji měl následně více jednodušší.

3) Samotný blok

Blok jako takový se skládá ze 3 částí:

  1. Hlavní JavaScript,
  2. CSS k editoru,
  3. CSS k zobrazení bloku (myšleno na frontendu).

Hlavní JavaScript

Blok, který vytvářím bude citace s obrázkem na pozadí.

V bloku definuji 2 RichText elementy, jeden pro citaci samotnou a druhý pro autora. Pro zvolení obrázku na pozadí jsem použil <InspectorControls>, abych přidal tlačítko do pravého bloku s nástroji. Výborným zdrojem toho, co vše je možné je dokumentace.

/wp-content/plugins/katuscak-gutenberg/gutenberg/blocks/blockquote-with-image/view.css

const {registerBlockType} = wp.blocks;
const {RichText, MediaUpload, InspectorControls} = wp.editor;

const block = registerBlockType('katuscak-gutenberg/blockquote-with-image', {
    title: 'Citace s obrázkem na pozadí',
    icon: 'format-image',
    category: 'layout',

    attributes: {
        textString: {
            type: 'array',
            source: 'children',
            selector: 'p'
        },
        authorString: {
            type: 'array',
            source: 'children',
            selector: 'footer'
        },
        backgroundImage: {
            type: 'string',
            default: null
        }
    },

    edit(props) {
        const {setAttributes, attributes, className} = props;
        const {backgroundImage} = props.attributes;

        function onTextChange(changes) {
            setAttributes({
                textString: changes
            });
        }

        function onAuthorChange(changes) {
            setAttributes({
                authorString: changes
            });
        }

        function onImageSelect(imageObject) {
            setAttributes({
                backgroundImage: imageObject.sizes.full.url
            })
        }

        return ([
            <InspectorControls>
                <div>
                    <h2>Vyberte obrázek na pozadí:</h2>
                    <MediaUpload
                        onSelect={onImageSelect}
                        type="image"
                        value={backgroundImage} // make sure you destructured backgroundImage from props.attributes!
                        render={({open}) => (
                            <button onClick={open} className="components-button editor-post-featured-image__toggle">
                                Zvolit obrázek
                            </button>
                        )}
                    />
                </div>
            </InspectorControls>,

            <blockquote className={className}
                 style={{
                     backgroundImage: `url('${backgroundImage}')`,
                     backgroundPosition: 'center center',
                     backgroundSize: 'cover'
                 }}>
                <RichText
                    tagName="p"
                    className="content"
                    value={attributes.textString}
                    onChange={onTextChange}
                    placeholder="Zde napište text citace"
                />
                <RichText
                    tagName="footer"
                    className="content"
                    value={attributes.authorString}
                    onChange={onAuthorChange}
                    placeholder="Zde napište autora citace"
                />
            </blockquote>
        ]);
    },

    save(props) {

        const {attributes, className} = props;
        const {backgroundImage} = props.attributes;

        return (
            <blockquote className={className}
                 style={{
                     backgroundImage: `url('${backgroundImage}')`,
                     backgroundPosition: 'center center',
                     backgroundSize: 'cover'
                 }}>
                <RichText.Content
                    tagName="p"
                    className="content"
                    value={attributes.textString}
                />
                <RichText.Content
                    tagName="footer"
                    className="content"
                    value={attributes.authorString}
                />
            </blockquote>
        );
    }
});

export {block}

Kromě hlavního JavaScriptu mám ještě jeden, kterým si je spojuji (ve chvíli, když jich je více, zde uvádím pouze jeden). Právě tento JavaScript je totiž kompilován do „build/index.js“, který v PHP pluginu uvádím:

/wp-content/plugins/katuscak-gutenberg/src/index.js

import "../gutenberg/blocks/blockquote-with-image/editor"

Styl bloku pro editor:

/wp-content/plugins/katuscak-gutenberg/gutenberg/blocks/blockquote-with-image/editor.css

.wp-block-katuscak-gutenberg-blockquote-with-image {
    margin: 0;
    padding: 1rem;
    text-align: center;
}

.wp-block-katuscak-gutenberg-blockquote-with-image p {
    font-size: 1.4rem;
    font-style: italic;
}

.wp-block-katuscak-gutenberg-blockquote-with-image footer {
    margin-top: .5rem;
    font-size: .8rem;
}

Styl bloku pro zobrazení (zde jej mám stejný jako pro editor):

/wp-content/plugins/katuscak-gutenberg/gutenberg/blocks/blockquote-with-image/view.css

.wp-block-katuscak-gutenberg-blockquote-with-image {
    margin: 0;
    padding: 1rem;
    text-align: center;
}

.wp-block-katuscak-gutenberg-blockquote-with-image p {
    font-size: 1.4rem;
    font-style: italic;
}

.wp-block-katuscak-gutenberg-blockquote-with-image footer {
    margin-top: .5rem;
    font-size: .8rem;
}

4) Kompilace JavaScriptu

V adresáři s pluginem stačí nechat spuštěné npm a budou se Vám úpravy automaticky kompilovat:

$ npm start

A následně pro produkci (jelikož kód bude i minifikován):

$ npm run build

5) Aktivace pluginu

Je potřeba nezapomenout plugin i aktivovat :)

6) Použití

 

V databázi je potom blok uložen jeden za druhým přímo ve „wp_posts“ v tomhle stylu:

<!-- wp:katuscak-gutenberg/blockquote-with-image {"backgroundImage":"http://localhost/wordpress/wp-content/uploads/2019/05/test.png"} -->
<blockquote class="wp-block-katuscak-gutenberg-blockquote-with-image" style="background-image:url('http://localhost/wordpress/wp-content/uploads/2019/05/test.png');background-position:center center;background-size:cover">
    <p class="content">Text citace</p>
    <footer class="content">Autor citace</footer>
</blockquote>
<!-- /wp:katuscak-gutenberg/blockquote-with-image -->

 

Celý kód najdete i na Githubu: github.com/MichalKatuscak/gutenberg-blocks/

Michal Katuščák
Michal Katuščák

Navrhuji a vyvíjím aplikace nad Symfony a Reactem, zajímám se architekturu softwaru. Žiju v Českých Budějovicích.