Как начать работать с Gutenberg? Настройка плагина для создания расширений для нового редактора WordPress

Это PHP или JavaScript? А куда этот код добавить? Это нужно добавить в functions.php? Эти и другие вопросы я слышу, когда речь заходит о расширении функциональности Gutenberg. Будь то добавление или удаление стилей блоков, создание новых блоков или модификации интерфейса редактора.

Документация для Gutenberg до сих пор находится в процессе написания (WP сообщество даже начало фандрайзинг для ее улучшения) и некоторые моменты тяжелы к восприятию. Поэтому в этой статье я расскажу как с нуля создать плагин для расширения функционала Gutenberg и какие инструменты использовать.

Перед тем как мы перейдем к инструментам, хочу сделать небольшую ремарку. Gutenberg по своей сути — React приложение, поэтому понимание основ React, JSX и ESNext необходимо для для работы с редактором. Да, документация приводит примеры в ES5 и ESNext, но большинство инструментов заточено именно под ESNext и JSX. Да и разобраться и понять разницу не так уж и сложно.

План действий

Мы создадим новый плагин для WordPress, настроим компиляцию React/ESNext → Vanilla JavaScript, и научимся:

  • Добавлять стили блоков
  • Добавлять вариации блоков
  • Регистрировать новые блоки

Инструменты

Для создания плагина нам понадобится несколько инструментов:

  • Локальный сервер для разаработки — я буду использовать VVV, но другие инструменты типа Local или Laravel Valet тоже подойдут.
  • WP-CLI. Интерфейс для управления WordPress из терминала. В VVV и Local WP-CLI установлен из коробки.
  • @wordpress/scripts — пакет скриптов для постройки JS файлов плагина.

Создание плагина

Для создания плагина мы воспользуемся командой wp scaffold plugin которая доступна в WP-CLI. Для этого перейдем в папку wp-contet/plugins в терминале и запустим следующую команду:

wp scaffold plugin demo --plugin_name="Demo" --plugin_description="Demo plugin for Gutenberg development" --plugin_author="Dmitry Mayorov" --plugin_author_uri="https://dmtrmrv.com" --activate

Если команда выполнена успешно, в терминале вы увидите вот такое сообщение:

Success: Created plugin files. Success: Created test files.

… а в админке WordPress появится новый плагин:

А вот так выглядит структура файлов:

demo ├── .distignore ├── .editorconfig ├── .gitignore ├── .phpcs.xml.dist ├── .travis.yml ├── Gruntfile.js ├── bin │ └── install-wp-tests.sh ├── demo.php ├── package.json ├── phpunit.xml.dist ├── readme.txt └── tests ├── bootstrap.php └── test-sample.php

Как видно из сниппета выше, помимо основного файла плагина, wp scaffold plugin добавляет конфигурационные файлы, скрипты локализации, тестирования и настройки CI/CD. Подробнее о значении этих файлов можно прочитать здесь.

Постройка JS файлов

Дальше необходимо настроить скрипты постройки JavaScript файлов. Для этого, находясь в папке плагина установим пакет @wordpress/scripts:

npm install @wordpress/scripts --save-dev

Если установка прошла успешно, то в разделе зависимостей в файле package.json помимо других зависимостей вы увидите следующее (версия может отличаться):

"devDependencies": { "@wordpress/scripts": "^12.0.0", }

После установки @wordpress/scripts необходимо добавить скрипты в package.json файл. Выглядеть это должно примерно так:

"scripts": { "build": "wp-scripts build", "check-engines": "wp-scripts check-engines", "check-licenses": "wp-scripts check-licenses", "format:js": "wp-scripts format-js", "lint:css": "wp-scripts lint-style", "lint:js": "wp-scripts lint-js", "lint:md:docs": "wp-scripts lint-md-docs", "lint:md:js": "wp-scripts lint-md-js", "lint:pkg-json": "wp-scripts lint-pkg-json", "packages-update": "wp-scripts packages-update", "start": "wp-scripts start", "test:e2e": "wp-scripts test-e2e", "test:unit": "wp-scripts test-unit-js" }

Подробнее о каждом из скриптов можно прочитать здесь.

Стоит упомянуть, что команда wp plugin scaffold тоже устанавливает несколько Grunt скриптов по умолчанию, поэтому объект scripts в package.json не будет пустым:

"scripts": { "start": "grunt default", "readme": "grunt readme", "i18n": "grunt i18n" }

Видно что оба объекта имеют скрипт start. Чтобы избежать конфликта, мы переименуем Grunt скрипт в grunt-start и объединим все скрипты в один объект:

"scripts": { "build": "wp-scripts build", "check-engines": "wp-scripts check-engines", "check-licenses": "wp-scripts check-licenses", "format:js": "wp-scripts format-js", "lint:css": "wp-scripts lint-style", "lint:js": "wp-scripts lint-js", "lint:md:docs": "wp-scripts lint-md-docs", "lint:md:js": "wp-scripts lint-md-js", "lint:pkg-json": "wp-scripts lint-pkg-json", "packages-update": "wp-scripts packages-update", "start": "wp-scripts start", "test:e2e": "wp-scripts test-e2e", "test:unit": "wp-scripts test-unit-js", "grunt-start": "grunt default", "readme": "grunt readme", "i18n": "grunt i18n" }

Больше всего нас интересуют два скрипта:

  • build - генерирует production версию файлов
  • start - наблюдает за файлами и генерирует development версию файлов если видит изменения.

Но куда и какие файлы вставлять чтобы начать работать с редактором? По умолчанию build и start скрипты будут обрабатывать файл src/index.js. Создадим этот файл и поместим в него что-нибудь вроде:

console.log('We are live!');

Важно чтобы директория src находилась на том же уровне что и package.json:

├── package.json ├── src │ └── index.js

Вернемся в консоль и запустим build скрипт:

npm run build

Если скрипт выполнен успешно, то в директории плагина появится новая директория build:

├── build │ ├── index.asset.php │ └── index.js ├── package.json ├── src │ └── index.js

Далее необходимо добавить скрипт build/index.js в редактор. Для этого в Gutenberg есть специальный хук: enqueue_block_editor_assets.

Откроем файл demo.php и добавим следующий код:

<?php /** * Plugin Name: Demo * Description: Demo plugin for Gutenberg development * Author: Dmitry Mayorov * Author URI: https://dmtrmrv.com * Text Domain: demo * Domain Path: /languages * Version: 0.1.0 * * @package Demo */ // Exit if accessed directly. if ( ! defined( 'ABSPATH' ) ) { exit; }; function demo_block_editor_assets(){ wp_enqueue_script( 'demo-editor-script', plugin_dir_url( __FILE__ ) . 'build/index.js', [ 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' ], '1.0.0' ); } add_action( 'enqueue_block_editor_assets', 'demo_block_editor_assets' );

И если мы все сделали без ошибок, то в консоли редактора должно появится сообщение We are live!

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

Добавление стиля блока

Это пример из официальной документации. В директории src создадим новую директорию styles/quote и поместим в нее новый файл index.js:

├── src │ ├── index.js │ └── styles │ └── quote │ └── index.js

Со следующим содержимым:

const { registerBlockStyle } = wp.blocks; registerBlockStyle( 'core/quote', { name: 'fancy-quote', label: 'Fancy Quote', } );

Затем импортируем этот файл в src/index.js:

import './styles/quote';

Запустим npm run build и, если нигде нет ошибок, то в админке у блока Quote должен появиться новый стиль:

Добавление вариации блока

Вариации блоков модифицируют уже существующие блоки, но, в отличие от стилей блоков, позволяют заполнять атрибуты и создавать дочерние блоки. Я подробно описал эту возможность в статье на CSS-Tricks, поэтому не буду вдаваться в детали, a покажу как добавить вариацию с помощью нашего плагина.

Я буду использовать тот же пример, что и в вышеупомянутой статье. В директории src создадим новую директорию variations/buttons и поместим в нее новый файл index.js:

├── src │ ├── index.js │ ├── styles │ │ └── quote │ │ └── index.js │ └── variations │ └── buttons │ └── index.js

… co следующим содержимым:

const { registerBlockVariation } = wp.blocks; registerBlockVariation( 'core/buttons', [ { name: 'wide', title: 'Wide Buttons', attributes: { className: 'is-wide' }, }, { name: 'full', title: 'Full Buttons', attributes: { className: 'is-full' }, } ] );

Затем импортируем этот файл в src/index.js:

import './styles/quote'; import './variations/buttons';

Вернемся в консоль и запустим build скрипт:

npm run build

После его выполнения в админке должны появится две новые вариации:

Добавление нового блока

Вероятно вы уже догадались, что порядок действий для добавления нового блока примерно такой же. Я не буду подробно описывать, как создать новый блок, на эту тему написано много статей.

В качестве примера мы создадим новый блок card состоящий из заголовка и параграфа. Для этого в директории src создадим новую директорию blocks/card и поместим в нее новый файл index.js:

├── src │ ├── index.js │ ├── blocks │ │ └── card │ │ └── index.js │ ├── styles │ │ └── quote │ │ └── index.js │ └── variations │ └── buttons │ └── index.js

… co следующим содержимым:

/** * Card Block */ const { __ } = wp.i18n; const { registerBlockType } = wp.blocks; const { RichText } = wp.blockEditor; registerBlockType('demo/card', { title: __('Card', 'demo'), description: __('Display a card with heading and description', 'demo'), category: 'widgets', attributes: { title: { type: 'string', source: 'html', selector: '.demo-card__title', }, description: { type: 'string', source: 'html', selector: '.demo-card__content', }, }, supports: { className: false, }, edit: (props) => { // Destructure props and attributes. const { attributes: { title, description, }, setAttributes, } = props; return ( <div className="demo-card"> <div className="demo-card__inner"> <RichText allowedFormats={[]} className="demo-card__title" multiline={false} onChange={(value) => setAttributes({ title: value })} placeholder="Add card title" tagName="h2" value={title} /> <RichText allowedFormats={[]} className="demo-card__content" multiline={'p'} onChange={(value) => setAttributes({ description: value })} placeholder="Add card content" tagName="div" value={description} /> </div> </div> ); }, save: (props) => { // Destructure attributes. const { attributes: { title, description, } } = props; return ( <div className="demo-card"> <div className="demo-card__inner"> <h2 className="demo-card__title" dangerouslySetInnerHTML={{ __html: title }} /> <div className="demo-card__content" dangerouslySetInnerHTML={{ __html: description }} /> </div> </div> ); }, });

Запустим build скрипт:

npm run build

.. после его выполнения в админке должен появится новый блок:

O структуре файлов

Как вы возможно заметили, мы организовали разные типы модификаций(стили, вариации, блоки) в разные директории. Если в будущем потребуется добавить, например, новый блок, то он пойдет в директорию blocks:

├── src │ ├── blocks │ │ └── card │ │ └── index.js │ │ └── new-block │ │ └── index.js

Такой же порядок для стилей и вариаций. Далее мы просто импортируем их в главный файл src/index.js. Таким образом файлы плагина остаются организованными.

Несколько слов о CSS

Я намеренно не стал добавлять в плагин стили, потому что cделать это можно различными способами в зависимости от контекста.

Можно поместить CSS файлы относящиеся ка каждому блоку в те же директории где находится блок и настроить webpack конфиг таким образом, что он будет их собирать в один файл. Можно создать один Sass файл и настроить компиляцию в CSS c помощью Gulp или Grunt.

Или не делать ничего из вышеперечисленного и написать CSS вручную (да, так тоже можно) если стилей немного.

Также нужно понимать куда добавлять стили — на фронтенд, в админку или и туда и туда? Будут это одинаковые стили или нет?

Эта статья не про CSS, поэтому я покажу как подключить cтили в редактор и на фронтенд a выбор технологий оставлю за вами. Для добавления стилей мы можем воспользоваться двумя хуками:

  • enqueue_block_editor_assets – используется для добавления скриптов и стилей только в адмику редактора
  • enqueue_block_assets – используется для добавления скриптов и стилей на фронтенд и в адмику редактора.

Для примера, добавим стили к блоку из примера выше. Для этого добавим новый файл demo.css в корневую директорию плагина.

.demo-card { padding: 1.5rem; border: 1px solid #000; }

И подключим этот стиль с помощью enqueue_block_assets:

function demo_block_assets(){ wp_enqueue_style( 'demo-editor-style', plugin_dir_url( __FILE__ ) . 'demo.css', [], '1.0.0' ); } add_action( 'enqueue_block_assets', 'demo_block_assets' );

Таким образом целиком demo.php будет выглядеть примерно вот так:

<?php /** * Plugin Name: Demo * Description: Demo plugin for Gutenberg development * Author: Dmitry Mayorov * Author URI: https://dmtrmrv.com * Text Domain: demo * Domain Path: /languages * Version: 0.1.0 * * @package Demo */ // Exit if accessed directly. if ( ! defined( 'ABSPATH' ) ) { exit; }; function demo_block_editor_assets(){ wp_enqueue_script( 'demo-editor-script', plugin_dir_url( __FILE__ ) . 'build/index.js', [ 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' ], '1.0.0' ); } add_action( 'enqueue_block_editor_assets', 'demo_block_editor_assets' ); function demo_block_assets(){ wp_enqueue_style( 'demo-editor-style', plugin_dir_url( __FILE__ ) . 'demo.css', [], '1.0.0' ); } add_action( 'enqueue_block_assets', 'demo_block_assets' );

Вместо итога

Надеюсь, что примеры из статьи помогут вам быстрее разобраться с тем как писать расширения для нового редактора WordPress. Для меня ключевым моментом было понять как работают cкрипты из пакета @wordpress/scripts. Остальное было довольно просто благодаря опыту работы с WordPress и React.

Если вам интересно протестировать плагин из статьи — исходный код можно найти на Github.

А если вы уже писали расширения для Gutenberg и использовали другие инструменты, поделитесь в комментариях.

0
Комментарии
-3 комментариев
Раскрывать всегда