Gutenberg: Jak vytvořím vlastní blok?

WordPress

POZOR! Článek jsem napsal před více jak rokem, a tudíž už nemusí reflektovat můj nynější názor nebo může být zastaralý.

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/

Znáte někoho, komu by článek mohl pomoct? Zasdílejte mu ho :)

Komentáře