Как создавать свои блоки контента в WordPress? Редактор Gutenberg начала 2020

Как создавать свои блоки контента в WordPress? Редактор Gutenberg начала 2020

В блочном редакторе WordPress (предыдущее название Gutenberg) есть новый способ добавления контента в ваши WordPress посты, страницы, а в скором времени, и в любое содержимое вашего сайта.

Это означает движение WordPress в сторону пейджбилдера (конструктор страниц).

Базовый набор блоков по умолчанию довольно хорош, но что если вы захотите создать собственный кастомный блок для контента? В прошлом вы использовали что-то вроде расширенных пользовательских полей (ACF) или шорткоды. Сейчас пользовательские блоки – это то, что вам надо.

В прошлом году я целыми днями работал с React, перестраивая фронтэнд для WP Migrate DB Pro. React засел у меня в уме, и учитывая то, что WordPress написан на React, я подумал, было бы неплохо посмотреть, что нужно для создания пользовательского блока. Итак, давайте разберемся!

Введени в блоки Gutenberg

Мы собираемся выяснить, что требуется для перехода от “ничто” к чему-то относительно простому, к кастомному блоку Gutenberg. Документации по редактору блоков, вроде как, навалом повсеместно, при этом в «Справочнике по редактору блоков» также имеется кое-какая достойная информация. К сожалению, она не так легка для анализа. Поэтому сделаем несколько шагов, которые сделал я, чтобы приблизиться к ее пониманию.

Прежде чем приступить к созданию блока Gutenberg, я рекомендую, по крайней мере, на данный момент, иметь четкое понимание React и современного JavaScript. Если вы не знакомы с такими вещами, как JSX, можете использовать синтаксис ES5, но для использования в долгосрочной перспективе лучше подходит современный синтаксис.

Сейчас довольно просто выполнять настройку с помощью команды WP CLI «scaffold». Она создаст тему или плагин WordPress с папкой «blocks», которая содержит PHP, базовый CSS и JavaScript, необходимые для построения пользовательского блока. Единственный недостаток, который я заметил, в том, что JavaScript использует старый синтаксис ES5, а не современный ESNext. Современный JavaScript позволяет писать более лаконичный код, а также использовать JSX в коде нашего кастомного блока.

Вы также можете использовать инструмент ‘create-guten-block’ от Ahmad Awais. Он даст вам много стандартных инструментов “из коробки”. Среди них будет Webpack, поддержка ESNext и др. Его настройка довольно проста и похожа на создание приложения в React.

Однако вместо использования стороннего инструмента, я использовал один из примеров пользовательских блоков, которые доступны на Github в репозитории gutenberg-examples. Карта примеров демонстрирует многое из того, что вы захотите видеть в минимально интерактивном пользовательском блоке. Она также включает в себя @wordpress/scripts, пакет для запуска и построения кода JavaScript, благодаря которому можно использовать синтаксис «ESNext» и JSX.

Чтобы начать работу, я просто сделал локальную копию и изменил поля в файле package.json и запустил yarn.

Блоки

Что же такое «Блок»? Мне было трудно понять эту концепцию, когда я впервые начал работать с редактором блоков.

Из документации:

Новый блочный редактор разработан для создания многофункциональных гибких макетов под веб-сайты и цифровые продукты. Его блочная система позволяет создавать и форматировать контент. Контент создается в виде блоков вместо текста произвольной формы с добавлением медиафайлов, встроенных объектов и шорткодами…

По сути, «блок» – это организационная единица для редактируемого «барахла» в WordPress. По крайней мере, таково мое понимание.

Блоки – это главный «строительный материал», но как нам его создать? Этот момент я могу объяснить! Блоки практически полностью сделаны в JavaScript. Gutenberg предлагает несколько новых действий (enqueue_block_assets и enqueue_block_editor_assets), чтобы вы могли использовать свои JavaScript и таблицы стилей в сочетании с ним.

function fancy_custom_block_block_init() {

    // automatically load dependencies and version
    $asset_file = include( plugin_dir_path( __FILE__ ) . 'build/index.asset.php');

    wp_register_script(
        'fancy-custom-block-block-editor',
        plugins_url( 'build/index.js', __FILE__ ),
        $asset_file['dependencies'],
        $asset_file['version']
    );

    wp_register_style(
        'fancy-custom-block-block-editor',
        plugins_url( 'editor.css', __FILE__ ),
        array( ),
        filemtime( plugin_dir_path( __FILE__ ) . 'editor.css' )
    );

    wp_register_style(
        'fancy-custom-block-block',
        plugins_url( 'style.css', __FILE__ ),
        array( ),
        filemtime( plugin_dir_path( __FILE__ ) . 'style.css' )
    );

    register_block_type( 'fancy-block-plugin/fancy-custom-block', array(
        'editor_script' => 'fancy-custom-block-block-editor',
        'editor_style'  => 'fancy-custom-block-block-editor',
        'style'         => 'fancy-custom-block-block',
    ) );
}

add_action( 'init', 'fancy_custom_block_block_init' );

Все, что нужно сделать на PHP – это поставить в очередь ваши JavaScript и CSS файлы и вызвать register_block_type() с дескриптором каждого актива.

Мир JavaScript

Если вы вдруг думали, что сейчас будет больше PHP, подумайте еще раз! С этого момента мы в мире JavaScript.

Ключевым аспектом создания блоков в Gutenberg является функция registerBlockType(). Она делает всю работу.

registerBlockType( 'my-block/cool-block-name', {
    // ... Massive JS object
}

И это все! До встречи!

Ну ладно, есть еще кое-что. Но в целом, речь о создани блока Gutenberg в WordPress на этом заканчивается. Зато в «Massive JS object» есть несколько вещей, на которые стоит обратить внимание.

Если заглянете в файл /05-recipe-card-esnext/src/index.js из репозитория примеров gutenberg, вы увидите множество параметров, которые используются при создании блока. Мы рассмотрим три основные секции: attributes и методы edit() и save().

Атрибуты

Если вам нужен блок, который действительно что-то делает, например, позволяет редактировать текст, вы должны использовать систему Gutenberg для управления состоянием. Вот этим и занимается объект attributes. Он в значительной степени идентичен концепции управления состоянием в React – это объект верхнего уровня, который отслеживает свойства и изменения.

attributes: {
    title: {
        type: "array",
        source: "children",
        selector: ".callout-title"
    },
    mediaID: {
        type: "number"
    },
    mediaURL: {
        type: "string",
        source: "attribute",
        selector: "img",
        attribute: "src"
    },
    body: {
        type: "array",
        source: "children",
        selector: ".callout-body"
    },
    alignment: {
        type: "string"
    }
},

Объект JavaScript, представленный выше, используется для настройки внешнего вида блока.

Вы можете заметить, что для каждой редактируемой «штуки» в вашем блоке нужно определить атрибут. Для изображений есть mediaID и mediaURL: значения заголовка и содержимого тела, а также общее выравнивание всего. Метод edit() берет эти атрибуты в качестве аргумента, чтобы мы могли менять их через интерфейс редактора.

edit()

Функция edit() позволяет вам кастомизировать интерфейс редактирования в Gutenberg. Если вы знакомы с функцией React render(), то они очень похожи. По сути, вы указываете возвратное выражение, в котором есть ваш JSX.

edit: props => {
    const {
        className,
        isSelected,
        attributes: { mediaID, mediaURL, body, alignment, title },
        setAttributes
    } = props;

    useEffect(() => {
    // console.log(props);
    });

    const onChangeTitle = value => {
        setAttributes({ title: value });
    };

    const onSelectImage = media => {
        setAttributes({
            mediaURL: media.url,
            mediaID: media.id
        });
    };

    const onChangeBody = value => {
        setAttributes({ body: value });
    };

    const [imageClasses, textClasses, wrapClass] = sortOutCSSClasses(
        alignment || 'left',
        className
    );

    return (
    <>
        {isSelected && (
            <BlockControls key="controls">
                <AlignmentToolbar
                value={alignment}
                onChange={nextAlign => {
                    setAttributes({ alignment: nextAlign });
                }}
                />
            </BlockControls>
        )}

        <div className={wrapClass} key="container">
            <div className={imageClasses}>
                <div className="callout-image">
                <MediaUpload
                    onSelect={onSelectImage}
                    type="image"
                    value={mediaID}
                    render={({ open }) => (
                    <Button
                        className={mediaID ? "image-button" : "button button-large"}
                        onClick={open}
                    >
                        {!mediaID ? __("Upload Image") : <img src={mediaURL} />}
                    </Button>
                    )}
                />
                </div>
            </div>                                  
            <div className={textClasses}>
                <RichText
                    tagName="h2"
                    className="callout-title"
                    placeholder={__("Write a callout title…")}
                    value={title}
                    onChange={onChangeTitle}
                />
                <RichText
                    tagName="div"
                    multiline="p"
                    className="callout-body"
                    placeholder={__("Write the callout body")}
                    value={body}
                    onChange={onChangeBody}
                />
            </div>
        </div>
    </>
    );
},

Первое, что мы делаем – присваиваем наши атрибуты неким локальным переменным, которые будут использоваться функцией.

const {
    className,
    isSelected,
    attributes: { mediaID, mediaURL, body, alignment, title },
    setAttributes
} = props;

Приведенный выше синтаксис – это деструктуризация объекта, и он, в основном, используется для получения эффекта «чем меньше печатать, тем лучше». Следующие несколько функций предназначены для обработки в редакторе событий onChange() . В основном, когда вы меняете какое-то значение, вы хотите обновить состояние приложения. Вот то, что делает метод setAttributes().

const onSelectImage = media => {
    setAttributes( {
        mediaURL: media.url,
        mediaID: media.id,
    } );
};

Большая часть того, что включено в метод edit() – это обработчики событий. Они устанавливают состояние в объекте атрибутов блока. Вы также заметите использование хука useEffect(). Основной метод хуков в React таков, что если залезть под капот к Gutenberg, то он, по большому счету, просто обертка для React.

Последняя часть функции edit() – это возвратный оператор. Здесь у нас есть куча JSX-кода, который определяет, как на самом деле выглядит интерфейс Gutenberg. Вы можете загрузить некоторые стандартные компоненты и блоки из пакета @wordpress/block-editor.

import {
    RichText,
    MediaUpload,
    BlockControls,
    AlignmentToolbar
} from "@wordpress/block-editor";

Затем в возвратном операторе вы можете использовать их и присваивать значения атрибутов:

  return (
        ...
            <div className={textClasses}>
                <RichText
                    tagName="h2"
                    className="callout-title"
                    placeholder={__("Write a callout title…")}
                    value={title}
                    onChange={onChangeTitle}
                />
                <RichText
                    tagName="div"
                    multiline="p"
                    className="callout-body"
                    placeholder={__("Write the callout body")}
                    value={body}
                    onChange={onChangeBody}
                />
            </div>
        ...
    );

В блочном редакторе WordPress есть блок RichText. Это основной блок, который вы захотите использовать для создания редактируемых областей. Имеются параметры для установки типа HTML тега, который он выводит и много других опций. Атрибут onChange – это место, где вы описываете функцию onChange(). Это важно, поскольку подразумевает способ, которым вы обновляете атрибуты блока и всего остального в реальном времени.

save()

Окей, это круто и все такое, но мы пока ничего не сохранили. И следующая часть нашего пользовательского блока – метод save(). Он определяет как ваш блок будет отображаться во фронт энде.

Есть что-то уникальное в том, как Gutenberg сохраняет данные. Пока вы не сохраните данные в post_meta, конфигурация блока сериализуется в HTML комментарии над самим блоком. WordPress, вероятно, фильтрует его отображение во фронтэнде, но он виден в записи базы данных.

<!-- wp:fancy-block-plugin/fancy-custom-block {"mediaID":4035} -->
<div class="wp-block-fancy-block-plugin-fancy-custom-block bootstrap-block"><div class="wrap-left-"><div class="image-left-"><img class="the-image" src="http://wpdevelop.devtest/content/uploads/2020/01/image-5.jpg"/></div><div class="text-left-"><h2 class="callout-title">Test 2</h2><div class="callout-body"><p>Test</p></div></div></div></div>
<!-- /wp:fancy-block-plugin/fancy-custom-block -->

Это немного странно, однако обеспечивает обратную совместимость. Если вы когда-нибудь отключите Gutenberg, контент не изменится.

save: props => {
    const {
        className,
        attributes: { title, mediaURL, body, alignment }
    } = props;

    const [imageClasses, textClasses, wrapClass] = sortOutCSSClasses(
        alignment || "left",
        className
    );

    return (
        <div className="bootstrap-block">
                <div className={wrapClass}>
                    <div className={imageClasses}>
                        {mediaURL && <img className="the-image" src={mediaURL} />}
                    </div>
                </div>
                <div className={textClasses}>
                    <RichText.Content
                        tagName="h2"
                        className="callout-title"
                        value={title}
                    />
                    <RichText.Content
                        tagName="div"
                        className="callout-body"
                        value={body}
                    />
                </div>
        </div>
    );
}

Метод save() на самом деле гораздо проще, чем edit(), при этом вы также получаете значения переданных атрибутов. Больше всего это имеет значение для создания вашей фронт энд разметки и вставки значений. Проще простого.

Проблемы, с которыми я столкнулся

Ладно, мы разобрались с тем, как создается пользовательский блок, но что насчет проблем? Оказывается, есть несколько 😢.

Документацию немного сложно изучать. Она не супер легка для понимания и структурирована как-то странно. Было трудно отслеживать информацию, касающуюся каждого отдельного момента в создании пользовательского блока и, в конечном счете, просто читать примеры кода блока. Придется много ковыряться в коде, чтобы разобраться, как все работает.

Кроме этого, я обнаружил, что очень раздражает работать над блоком, код которого активно меняется. Каждый раз, когда вы перезагружаете Gutenberg, вылезает сообщение «Этот блок, по-видимому, был изменен извне…», поскольку разметка блока изменилась.

Я понимаю, почему вылезает ошибка, но это тормозит работу.

У меня также были странные консольные ошибки из-за включенного SCRIPT_DEBUG. Эта постоянная нужна для локального использования некомпилированной версии React. Очевидно, это известная проблема, но немного странно видеть предупреждения в консоли из-за включенной константы ядра WordPress.

Далее, инструменты разработчика в React по сути бесполезны, так как имена компонентов React в Gutenberg состоят из одного символа…

Все это говорит о том, что еще есть острые углы.

Альтернативные варианты

Итак, чтобы создать действительно нестандартный блок, надо немного поработать. Но что, если вы хотите построить блочный тип используя UI? Оказывается, это можно сделать с помощью ACF. ACF блоки позволяют делать большую часть работы в привычном интерфейсе ACF полей. Другое преимущество в том, что вы можете написать код для ACF блоков полностью на PHP.

Блоки ACF немного отличаются от пользовательских. Рекомендуемый принцип работы с ними – редактировать поля в сайдбаре редактора и смотреть превью в его основной области. Это немного иной опыт создания блоков, но он больше соответствует традиционной работе с ACF – контент добавляется в поля, за пределами основного редактора.

Если вам надо отображать только значения полей внутри блока, тогда этот вариант может вам подойти. Еще вы можете стилизовать блок ACF с помощью таблицы стилей. Он будет выглядеть также, как на фронтэнде.

Блоки ACF больше напоминают «взлом» Gutenberg, чем официальный способ создания блоков.

Есть и другие плагины для WordPress, которые позволяют вам «собирать» блоки, например, Block Lab и Lazy Blocks. Я их еще не пробовал, но если вы ищете метод создания кастомного блока с минимумом кода – это подходящий вариант.

После того, как все сказано и сделано

Итак, у вас есть инструкция по созданию «пользовательских» блоков для WordPress (или Gutenberg).

Вы уже создавали пользовательский блок Gutenberg? Какое у вас сложилось впечатление? Дайте нам знать об этом в комментариях.

Перевод

Автор Peter Tasker

Источник: https://deliciousbrains.com/custom-gutenberg-block/

Информация была полезна для вас?

Расскажите пожалуйста что мы можем улучшить?


Обзор Gutenberg

Дизайн & Креатив Gutenberg - это новый блочный редактор WordPress

Подробнее...


Обзор WordPress

Сайты & Интернет Платформа для управления сайтами №1 в мире. Отличается большим количеством готовых плагинов и тем. Быстрым созданием сайтов.

Подробнее...

Добавить комментарий