Как создать динамические блоки для Гутенберга
Опубликовано: 2022-08-03Вы все еще озадачены Гутенбергом? Или вы среди тех, кто твердо верит в потенциал блочного редактора и хочет узнать, как далеко можно продвинуть свои творческие способности с помощью блочного редактора?
К какой бы категории пользователей вы ни относились, Гутенберг останется с вами, и этот пост даст вам подробный обзор того, что происходит за кулисами редактора блоков WordPress. Но это не все!
Следуя нашему предыдущему руководству, в котором мы представили общее введение в разработку блоков Gutenberg, эта статья выходит за рамки основ и представляет более сложные типы блоков. Эти блоки называются динамическими блоками.
Сегодня вы узнаете, что такое динамические блоки, как они работают, и все, что вам нужно знать, чтобы создавать динамические блоки с нуля.
Итак, что такое динамические блоки Гутенберга и каковы ключевые различия между статическими и динамическими блоками?
Что такое динамические блоки? Пример
В то время как со статическими блоками контент добавляется пользователем вручную при редактировании поста или страницы, с динамическими блоками контент загружается и обрабатывается «на лету» при загрузке страницы. В динамических блоках содержимое блока извлекается из базы данных и отображается как есть или в результате любого вида манипуляции с данными.
Поясним это на примере. Допустим, вы хотите создать группу вложенных блоков, показывающих информацию об авторе сообщения с выбором последних сообщений от одного и того же автора.
Как пользователи Гутенберга, вы можете использовать следующие блоки:
- Основной блок « Заголовок »
- Основной блок автора поста
- Основной блок « Последние сообщения »
Вы также можете создать группу, включающую эти блоки, и добавить группу в повторно используемые блоки для будущего использования.
Это довольно просто, не так ли? Вы можете создать динамический блок и мгновенно добавить его в свои посты и страницы.
Начиная с WordPress 5.9, редактор блоков предоставляет более 90 различных блоков, и есть вероятность, что вы найдете блок, который подходит именно вам, прямо из коробки. И, если вам нужно больше, выполните быстрый поиск в каталоге плагинов WordPress, и вы найдете множество бесплатных плагинов, предоставляющих дополнительные блоки.
Но что, если вы разработчик WordPress или планируете карьеру разработчика WordPress? Возможно, у вас очень специфические потребности и вы не можете найти блок, который ищете, или вы просто хотите получить новые профессиональные навыки. В таких ситуациях вы можете научиться создавать свои динамические блоки.
Динамические блоки Гутенберга с точки зрения разработчика
Динамические блоки имеют два основных варианта использования.
Первый вариант использования — это когда вам нужно обновить содержимое блока, когда страница, содержащая блок, не была обновлена. Например, это происходит, когда блок содержит список последних сообщений или комментариев, и вообще всякий раз, когда содержимое блока динамически генерируется с использованием данных, извлеченных из базы данных.
Второй вариант использования — когда обновление блочного кода необходимо немедленно отобразить во внешнем интерфейсе. Использование динамического блока вместо статического приводит к немедленному применению изменений ко всем экземплярам блока.
С другой стороны, если вы измените HTML-код, созданный статическим блоком, пользователь увидит диалоговое окно недействительности до тех пор, пока каждый отдельный экземпляр предыдущей версии блока не будет удален и заменен новой версией, или вы не отметите старую версию. версия как устаревшая (см. также Устаревание и проверка блоков, Устаревание и опыт миграции).
При этом есть несколько концепций, которые вам нужно понять, прежде чем вы сможете начать создавать динамические блоки.
Состояние приложения и хранилища данных
Gutenberg — это приложение React SPA, и все в Gutenberg — это компонент React. Заголовок публикации, заголовки, абзацы, изображения и любой блок содержимого HTML в редакторе является компонентом React, а также элементами управления боковой панели и панели инструментов блока.
В нашей предыдущей статье мы использовали свойства только для хранения данных. В этой статье мы пойдем еще дальше, введя понятие состояния .
Проще говоря, объект state
— это простой объект JavaScript, используемый для хранения информации о компоненте. state
компонента может меняться со временем, и каждый раз, когда оно изменяется, компонент перерисовывается.
Подобно объекту state
, свойства — это простые объекты JavaScript, используемые для хранения информации о компоненте. Но между props и state
есть ключевое различие:
props
передаются компоненту (аналогично параметрам функции), тогда какstate
управляется внутри компонента (аналогично переменным, объявленным в функции).
Вы можете думать о состоянии как о моментальном снимке данных, сделанных в определенный момент времени, которые приложение сохраняет для управления поведением компонента. Например, если боковая панель настроек редактора блоков открыта, часть информации будет храниться где-то в объекте state
.
Когда информация используется в одном компоненте, мы называем это локальным состоянием . Когда информация распределяется между компонентами внутри приложения, мы называем это состоянием приложения .
Состояние приложения тесно связано с концепцией хранилища. Согласно документам Redux:
Магазин содержит все дерево состояний вашего приложения. Единственный способ изменить состояние внутри него — отправить на него действие.
Итак, Redux хранит состояние приложения в одном неизменном дереве объектов (а именно в хранилище). Дерево объектов можно изменить, только создав новый объект с помощью действий и редюсеров.
В WordPress магазины управляются модулем данных WordPress .
Модульность, пакеты и хранилища данных в Gutenberg
Репозиторий Gutenberg построен с нуля на нескольких повторно используемых и независимых модулях , которые, объединенные вместе, создают интерфейс редактирования. Эти модули также называются пакетами .
В официальной документации перечислены два разных типа пакетов:
- Производственные пакеты составляют производственный код, который запускается в браузере. В WordPress есть два типа производственных пакетов:
- Пакеты с таблицами стилей предоставляют таблицы стилей для правильной работы.
- Пакеты с хранилищами данных определяют хранилища данных для обработки их состояния. Пакеты с хранилищами данных могут использоваться сторонними плагинами и темами для извлечения данных и управления ими.
- Пакеты разработки используются в режиме разработки. Эти пакеты включают инструменты для линтинга, тестирования, сборки и т. д.
Здесь нас в основном интересуют пакеты с хранилищами данных, используемые для извлечения данных и управления ими.
Хранилище данных WordPress
Модуль данных WordPress построен на основе Redux и разделяет три основных принципа Redux, хотя и с некоторыми ключевыми отличиями.
Официальная документация дает следующее определение:
Модуль данных WordPress служит центром управления состоянием приложения как для плагинов, так и для самого WordPress, предоставляя инструменты для управления данными внутри и между отдельными модулями. Он разработан как модульный шаблон для организации и обмена данными: достаточно простой, чтобы удовлетворить потребности небольшого плагина, и в то же время масштабируемый, чтобы удовлетворить требования сложного одностраничного приложения.
По умолчанию Gutenberg регистрирует несколько хранилищ данных в состоянии приложения. Каждый из этих магазинов имеет определенное название и назначение:
-
core
: Основные данные WordPress -
core/annotations
: Аннотации -
core/blocks
: данные о типах блоков -
core/block-editor
: данные редактора блоков -
core/editor
: Данные редактора сообщений -
core/edit-post
: Данные пользовательского интерфейса редактора. -
core/notices
: данные уведомлений -
core/nux
: данные NUX (новый пользовательский опыт) -
core/viewport
: Данные области просмотра
Через эти магазины вы сможете получить доступ к целому ряду данных:
- Данные, относящиеся к текущему сообщению , такие как заголовок сообщения, отрывок, категории и теги, блоки и т. д.
- Данные, относящиеся к пользовательскому интерфейсу , т. е. включен или выключен переключатель.
- Данные, относящиеся ко всей установке WordPress , такие как зарегистрированные таксономии, типы сообщений, название блога, авторы и т. д.
Эти хранилища находятся в глобальном объекте wp
. Чтобы получить доступ к состоянию хранилища, вы будете использовать функцию select
.
Чтобы увидеть, как это работает, создайте новый пост или страницу и запустите инспектор браузера. Найдите консоль и введите следующую строку кода:
wp.data.select("core")
Результатом будет объект, содержащий список функций, которые вы можете использовать для получения данных из core
хранилища данных. Эти функции называются селекторами и действуют как интерфейсы для доступа к значениям состояния.
Хранилище данных WordPress содержит информацию о WordPress в целом, и селекторы — это способ получения этой информации. Например, getCurrentUser()
возвращает сведения о текущем пользователе:
wp.data.select("core").getCurrentUser()
Другой селектор, который вы можете использовать для получения сведений о пользователе из хранилища данных, — это getUsers()
:
wp.data.select("core").getUsers()
На следующем изображении показан объект ответа:
Чтобы получить данные для одного пользователя, вы можете просто ввести следующую строку:
wp.data.select("core").getUsers()[0]
Используя тот же селектор, вы также можете получить пользователей сайта с назначенной ролью author
:
wp.data.select( 'core' ).getUsers({ who: 'authors' })
Вы также можете получить зарегистрированные таксономии:
wp.data.select("core").getTaxonomies()
Список зарегистрированных типов сообщений:
wp.data.select("core").getPostTypes()
Или список плагинов:
wp.data.select("core").getPlugins()
Теперь давайте попробуем получить доступ к другому хранилищу данных. Для этого вы по-прежнему будете использовать функцию select
, но с другим пространством имен. Давайте попробуем следующее:
wp.data.select("core/edit-post")
Теперь вы получите следующий объект ответа.
Если вы хотите узнать, открыта боковая панель настроек или нет, вы должны использовать селектор isEditorSidebarOpened
:
wp.data.select("core/edit-post").isEditorSidebarOpened()
Эта функция возвращает true
, если боковая панель открыта:
Как получить доступ к данным публикации
Теперь у вас должно быть общее представление о том, как получить доступ к данным. Теперь мы более подробно рассмотрим конкретный селектор, функцию getEntityRecords
, которая предоставляет доступ к данным публикации.
В редакторе блоков щелкните правой кнопкой мыши и выберите Inspect . На вкладке Консоль скопируйте и вставьте следующую строку:
wp.data.select("core").getEntityRecords('postType', 'post')
Это отправляет запрос к Rest API и возвращает массив записей, соответствующих последним опубликованным сообщениям в блоге.
getEntityRecords
принимает три параметра:
-
kind
string : Тип объекта (т.е.postType
). - строка
name
: имя объекта (т.е.post
). -
query
?Объект : Необязательный запрос терминов (т.е.{author: 0}
).
Вы можете создавать более конкретные запросы, используя объект аргументов.
Например, вы можете решить, что ответ должен содержать сообщения только в указанной категории:
wp.data.select("core").getEntityRecords('postType', 'post', {categories: 3})
Вы также можете запросить только статьи от данного автора:
wp.data.select("core").getEntityRecords('postType', 'post', {author: 2})
Если вы нажмете на любую из записей, возвращенных getEntityRecords
, вы получите список свойств для выбранной записи:
Если вы хотите, чтобы ответ включал избранное изображение, вам нужно добавить дополнительный аргумент к вашему предыдущему запросу:
wp.data.select("core").getEntityRecords('postType', 'post', {author: 2, _embed: true})
Теперь вы должны лучше понимать, как получить доступ к хранилищу данных WordPress и получить информацию о сообщениях. Подробнее о селекторе getEntityRecords
см. также в разделе Запрос данных в Gutenberg с помощью getEntityRecords.
Как создать динамический блок: пример проекта
После нашей длинной теоретической предпосылки мы можем перейти к практике и создать динамический блок, используя инструменты, которые мы представили в нашем предыдущем руководстве по разработке блоков.
В этой статье мы обсудили:
- Как настроить среду разработки WordPress
- Что такое блочные строительные леса
- Как построить статический блок Гутенберга
Вот почему мы не будем подробно рассматривать эти темы в настоящей статье, но не стесняйтесь обращаться к нашему предыдущему руководству за любой дополнительной информацией или просто для освежения знаний.
Настройка среды разработки JavaScript
Начнем с настройки среды разработки JavaScript.
Установите или обновите Node.js
Сначала установите или обновите Node.js. Когда вы закончите, запустите инструмент командной строки и выполните следующую команду:
node -v
Вы должны увидеть версию своего узла.
Настройте свою среду разработки
Далее вам понадобится среда разработки для WordPress. Для наших примеров мы использовали DevKinsta, наш бесплатный инструмент разработки WordPress, который позволяет вам быстро запустить локальный веб-сайт WordPress.
Но вы по-прежнему можете выбрать любую локальную среду разработки WordPress, такую как MAMP или XAMPP, или даже официальное решение wp-env.
Если вы используете DevKinsta, нажмите « Новый сайт WordPress » или « Пользовательский сайт », заполните поля формы и нажмите « Создать сайт ».
Процесс установки занимает минуту-две. Когда все будет готово, запустите локальный веб-сайт разработки WordPress.
Настройте свой блок-плагин
Что вам сейчас нужно, так это плагин стартового блока. Чтобы избежать всех хлопот ручной настройки, основная команда разработчиков WordPress выпустила инструмент @wordpress/create-block, который является официальным инструментом нулевой настройки для создания блоков Гутенберга .
Мы подробно рассмотрели @wordpress/create-block
в нашей предыдущей статье, так что здесь мы можем сразу приступить к настройке.
В инструменте командной строки перейдите в папку /wp-content/plugins :
Оказавшись там, выполните следующую команду:
npx @wordpress/create-block
Теперь вы готовы установить пакет @wordpress/create-block
:
Для подтверждения введите y
и нажмите Enter.
Это генерирует файлы PHP, SCSS и JS плагина в интерактивном режиме.
Ниже приведены детали, которые мы будем использовать в нашем примере. Не стесняйтесь изменять эти детали в соответствии с вашими предпочтениями:
Как только вы нажмете Enter, он загрузит и настроит плагин.
Процесс может занять пару минут. По завершении вы должны увидеть следующий экран:
Вы увидите список команд, которые вы можете запустить из каталога плагинов:
-
$ npm start
— Запустить сборку для разработки. -
$ npm run build
— собрать код для производства. -
$ npm run format
— Форматировать файлы. -
$ npm run lint:css
— CSS-файлы Lint. -
$ npm run lint:js
— файлы JavaScript Lint. -
$ npm run packages-update
— обновить пакеты WordPress до последней версии.
Хорошо, теперь перейдите в каталог плагинов с помощью следующей команды:
cd author-plugin
И начните сборку разработки:
npm start
Затем перейдите к экрану «Плагины» на панели инструментов WordPress и активируйте плагин « Авторский ящик» :
Теперь вы можете проверить, правильно ли работает плагин. Создайте новый пост и начните вводить /
, чтобы запустить инструмент быстрой вставки:
Вы также найдете блок поля « Автор» в средстве вставки блоков в категории « Виджеты ». Выберите блок, чтобы добавить его на холст редактора:
Готово. Теперь сохраните сообщение и просмотрите страницу, чтобы проверить, правильно ли отображается блок.
Блочные леса
Мы рассмотрели блочные леса в нашем предыдущем посте. Итак, здесь мы предоставим только краткий обзор файлов, которые мы собираемся изменить для наших примеров.
Корневая папка
В корневой папке вы найдете основной файл PHP и несколько подпапок.
автор-plugin.php
По умолчанию пакет @wordpress/create-block
предоставляет следующий файл PHP:
/** * Plugin Name: Author box * Description: An example block for Kinsta readers * Requires at least: 5.8 * Requires PHP: 7.0 * Version: 0.1.0 * Author: Carlo * License: GPL-2.0-or-later * License URI: https://www.gnu.org/licenses/gpl-2.0.html * Text Domain: author-plugin * * @package author-box */ /** * Registers the block using the metadata loaded from the `block.json` file. * Behind the scenes, it registers also all assets so they can be enqueued * through the block editor in the corresponding context. * * @see https://developer.wordpress.org/reference/functions/register_block_type/ */ function author_box_author_plugin_block_init() { register_block_type( __DIR__ . '/build' ); } add_action( 'init', 'author_box_author_plugin_block_init' );
В заголовке вы увидите детали, которые мы ввели при настройке.
Со статическими блоками большую часть времени вы будете работать с файлами JavaScript, расположенными в папке src . С динамическими блоками вы будете писать PHP-код для отображения содержимого блока во внешнем интерфейсе.
Папка src
Папка src — это ваша папка разработки. Здесь вы найдете следующие файлы:
- block.json
- index.js
- edit.js
- сохранить.js
- редактор.scss
- стиль.scss
block.json
block.json — это ваш файл метаданных. @wordpress/create-block
генерирует следующий файл block.json :
{ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 2, "name": "author-box/author-plugin", "version": "0.1.0", "title": "Author box", "category": "widgets", "icon": "businessperson", "description": "An example block for Kinsta readers", "supports": { "html": false }, "textdomain": "author-plugin", "editorScript": "file:./index.js", "editorStyle": "file:./index.css", "style": "file:./style-index.css" }
Для более подробного ознакомления с файлом block.json в целом, пожалуйста, обратитесь к нашему предыдущему сообщению в блоге.
index.js
В файле index.js вы регистрируете тип блока на клиенте:
import { registerBlockType } from '@wordpress/blocks'; import './style.scss'; import Edit from './edit'; import save from './save'; registerBlockType('author-box/author-plugin', { edit: Edit, save, });
edit.js
В файле edit.js вы создадите блочный интерфейс, отображаемый в редакторе:
import { __ } from '@wordpress/i18n'; import { useBlockProps } from '@wordpress/block-editor'; import './editor.scss'; export default function Edit() { return ( <p {...useBlockProps()}> {__('Author box – hello from the editor!', 'author-plugin')} </p> ); }
сохранить.js
Файл save.js содержит сценарий, который создает содержимое блока для сохранения в базе данных. Мы не будем использовать этот файл в этом уроке:
import { __ } from '@wordpress/i18n'; import { useBlockProps } from '@wordpress/block-editor'; export default function save() { return ( <p {...useBlockProps.save()}> {__('Author box – hello from the saved content!', 'author-plugin')} </p> ); }
Создание блока для рендеринга в редакторе
Откройте свой проект в Visual Studio Code или любом другом редакторе кода, который вам нравится.
Если вы используете Visual Studio Code, перейдите в Terminal -> New Terminal . Это запустит окно терминала в корневой папке вашего проекта.
В терминале (или в вашем любимом инструменте командной строки) введите следующую команду:
npm start
Теперь вы запускаете среду узла в режиме разработки.
Отсюда вы будете следовать двумя разными маршрутами. Чтобы визуализировать блок в редакторе, вы будете работать с файлом edit.js. Чтобы отобразить блок во внешнем интерфейсе, вам нужно будет написать код PHP в основном файле плагина.
Теперь засучите рукава, потому что кодирование начинается:
Зарегистрировать блок на сервере
Во-первых, вам нужно зарегистрировать блок на сервере и написать PHP-код для извлечения данных из базы данных.
В файле author-plugin.php вам нужно будет передать второй аргумент функции register_block_type
:
function author_box_author_plugin_block_init() { register_block_type( __DIR__ . '/build', array( 'render_callback' => 'author_box_author_plugin_render_author_content' ) ); } add_action( 'init', 'author_box_author_plugin_block_init' );
Второй аргумент — это массив аргументов для регистрации типа блока (см. полный список доступных аргументов здесь). В приведенном выше коде мы предоставили только render_callback
, который определяет функцию обратного вызова, которая отображает блок на экране.
Далее вы объявите функцию:
function author_box_author_plugin_render_author_content() { return 'Hello World!'; }
Сохраните файл, создайте новый пост или страницу и добавьте блок Author Box на холст редактора.
Редактор блоков по-прежнему показывает начальный блок, так как мы еще не изменили файл edit.js.
Но если вы просмотрите сообщение в интерфейсе, вы увидите, что исходное содержимое блока теперь заменено строкой «Hello World».
Теперь, поскольку HTML, отображаемый во внешнем интерфейсе, генерируется файлом PHP, функции save
не нужно ничего возвращать. Итак, давайте перейдем прямо к файлу save.js и изменим код, как показано ниже:
export default function save() { return null; }
Определить атрибуты блока
Теперь вам нужно место для хранения пользовательских настроек. Например, количество элементов сообщений, которые нужно извлечь из базы данных, отображать или нет указанное поле и т. д. Для этого вы определите ряд attributes
в файле block.json .
Например, вы можете дать пользователю возможность определять количество сообщений, которые будут включены в блок, возможность отображать избранное изображение, дату, отрывок и/или скрывать/показывать изображение профиля автора.
Вот полный список атрибутов, которые мы будем использовать для построения нашего примера блока:
{ ... "attributes": { "numberOfItems": { "type": "number", "default": 3 }, "columns": { "type": "number", "default": 1 }, "displayDate": { "type": "boolean", "default": true }, "displayExcerpt": { "type": "boolean", "default": true }, "displayThumbnail": { "type": "boolean", "default": true }, "displayAuthorInfo": { "type": "boolean", "default": true }, "showAvatar": { "type": "boolean", "default": true }, "avatarSize": { "type": "number", "default": 48 }, "showBio": { "type": "boolean", "default": true } } }
Создайте блок для рендеринга в редакторе
Селектор getEntityRecords
включен в пакет @wordpress/data
. Чтобы использовать его, вам нужно импортировать хук useSelect
из этого пакета в ваш файл edit.js
:
import { useSelect } from '@wordpress/data';
Затем добавьте следующий код в функцию Edit()
:
const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': 3 }); });
В приведенном выше коде мы жестко запрограммировали количество сообщений. Но вы можете предоставить пользователям возможность устанавливать другое количество сообщений. Вы можете использовать атрибут для этого.
В вашем block.json вы должны были определить атрибут numberOfItems
. Вы можете использовать его в своей функции Edit
, как показано ниже:
export default function Edit( { attributes } ) { const { numberOfItems } = attributes; const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': numberOfItems }); }); console.log( posts ); return ( ... ); }
Вы пока не увидите сообщения на экране, но запустите console.log
и посмотрите, что происходит в консоли инспектора вашего браузера:
useSelect
может принимать два аргумента: встроенный обратный вызов и массив зависимостей. Оба возвращают запомненную версию обратного вызова, которая изменяется только при изменении одной из зависимостей.
Итак, чтобы обновлять сообщения при каждом изменении атрибута numberOfItems
, вы должны изменить функцию Edit
, как показано ниже:
export default function Edit( { attributes } ) { const { numberOfItems } = attributes; const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': numberOfItems }); }, [ numberOfItems ] ); console.log(posts); return ( ... ); }
Затем вы должны отобразить список сообщений. Для этого вы можете использовать встроенный метод map
JavaScript:
export default function Edit( { attributes } ) { const { numberOfItems } = attributes; const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': numberOfItems }); }, [ numberOfItems ] ); console.log(posts); return ( <div { ...useBlockProps() }> <ul> { posts && posts.map( ( post ) => { return ( <li key={ post.id }> <h5> <a href={ post.link }> { post.title.rendered ? post.title.rendered : __( 'Default title', 'author-plugin' ) } </a> </h5> </li> ) })} </ul> </div> ); }
Во-первых, он проверяет, есть ли у вас хотя бы один пост в массиве, а затем запускает цикл.
Обратите внимание, что, поскольку мы используем метод map
с компонентом React, мы также используем key
атрибут для назначения идентификатора сообщения текущему элементу списка.
post.link
и post.title.rendered
отображают URL-адрес и заголовок сообщения соответственно.
На изображении ниже показан полный список свойств объекта post
.
Приведенный выше код является лишь базовым примером использования getEntityRecords
. Теперь пришло время применить наши знания на практике.
Допустим, вы хотите, чтобы ваш блок не отображал теги HTML, которые пользователь мог добавить к заголовку сообщения. Для этого WordPress предоставляет компонент RawHTML
.
Сначала вы импортируете компонент из пакета @wordpress/element:
import { RawHTML } from '@wordpress/element';
Далее вы поместите заголовок сообщения в элемент RawHTML
:
<div { ...useBlockProps() }> <ul> { posts && posts.map((post) => { return ( <li key={ post.id }> <h5> <a href={ post.link }> { post.title.rendered ? ( <RawHTML> { post.title.rendered } </RawHTML> ) : ( __( 'Default title', 'author-plugin' ) )} </a> </h5> </li> ) })} </ul> </div>
Вот и все. Теперь добавьте тег HTML к заголовку сообщения и сохраните сообщение. Затем протестируйте свой код с RawHTML
и без него и посмотрите, как содержимое вашего блока изменится на экране.
Добавить дату
WordPress предоставляет ряд функций JavaScript для управления и форматирования дат. Чтобы использовать эти функции, вам сначала нужно импортировать их из пакета @wordpress/date
в файле edit.js :
import { dateI18n, format, __experimentalGetSettings } from '@wordpress/date';
-
dateI18n
: Отформатируйте дату, переведя ее в языковой стандарт сайта. -
format
: формат даты. -
__experimentalGetSettings
: отображать дату в формате, установленном в общих настройках WordPress.
Эти функции не задокументированы, но вы найдете полезные примеры в исходном коде нескольких блоков. См., например, файлы last-posts и post-date edit.js.
Теперь добавьте атрибут displayDate
:
const { numberOfItems, displayDate } = attributes;
Затем добавьте следующий код в элемент <li>
:
{ displayDate && ( <time className='wp-block-author-box-author-plugin__post-date' dateTime={ format( 'c', post.date_gmt ) } > { dateI18n( __experimentalGetSettings().formats.date, post.date_gmt )} </time> ) }
Что здесь происходит?
- Если
displayDate
имеет значениеtrue
, тогда отображайте дату, используя элементtime
. - Атрибут
dateTime
предоставляет время и/или дату элемента в одном из допустимых форматов. -
dateI18n
извлекает дату в локализованном формате. Эта функция работает аналогично функции PHPPHPdate_i18n
WordPress.
Добавить отрывок
Теперь должно быть легко добавить отрывок из поста. Во-первых, взгляните на свойство excerpt
в инспекторе браузера. Вы увидите, что фактический контент хранится в excerpt.rendered
.
Затем добавьте атрибут displayExcerpt
в объект attributes
:
const { numberOfItems, displayDate, displayExcerpt } = attributes;
Затем добавьте следующий код перед закрывающим тегом </li>
в функции Edit
:
{ displayExcerpt && post.excerpt.rendered && ( <p> <RawHTML> { post.excerpt.rendered } </RawHTML> </p> ) }
Если вы не знакомы с JavaScript, здесь и выше мы использовали Оценку короткого замыкания , при которой, если все условия истинны, то возвращается значение последнего операнда (подробнее читайте в Inline If с логическим оператором && и логическим И (&& )).
Наконец, вы можете снова протестировать свой код. Измените значение атрибута в файле block.json и посмотрите, что произойдет в редакторе.
Добавьте избранное изображение
Теперь вам нужно добавить код, который отображает избранные изображения. Начните добавлять атрибут displayThumbnail
в attributes
:
const { numberOfItems, displayDate, displayExcerpt, displayThumbnail } = attributes;
Теперь вам нужно выяснить, где хранится избранное изображение. Как мы упоминали выше, чтобы получить избранное изображение, вам нужно добавить в запрос новый аргумент _embed
. Вернитесь к своему коду, измените аргументы запроса следующим образом:
const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': numberOfItems, '_embed': true }); }, [ numberOfItems ] );
Здесь мы просто добавили '_embed': true
к массиву аргументов. Это предоставляет объект post
, содержащий свойство _embedded
, которое предоставляет сведения об изображении, необходимые для отображения рекомендуемых изображений.
Теперь вы должны знать, где найти детали изображения.
Вам просто нужно добавить код, который отображает изображение на экране:
{ displayThumbnail && post._embedded && post._embedded['wp:featuredmedia'] && post._embedded['wp:featuredmedia'][0] && <img className='wp-block-author-box-author-plugin__post-thumbnail' src={ post._embedded['wp:featuredmedia'][0].media_details.sizes.medium.source_url } alt={ post._embedded['wp:featuredmedia'][0].alt_text } /> }
Сохраните файл, переключитесь в редактор блоков и проверьте, правильно ли отображается изображение, когда для атрибута displayThumbnail
установлено значение true
.
Добавить элементы управления боковой панели
До сих пор мы использовали значения атрибутов по умолчанию, установленные в block.json . Но из нашей предыдущей статьи мы знаем, что можем определить обработчики событий, чтобы дать пользователям возможность назначать пользовательские значения для каждого атрибута.
Для этого вы добавите набор элементов управления на боковую панель настроек блока. В edit.js импортируйте следующие компоненты из соответствующих пакетов:
import { useBlockProps, InspectorControls } from '@wordpress/block-editor'; import { PanelBody, PanelRow, QueryControls, ToggleControl, RangeControl } from '@wordpress/components';
-
InspectorControls
: содержит настройки боковой панели, влияющие на весь блок (см. на GitHub). -
PanelBody
: добавляет складной контейнер на боковую панель настроек (см. на GitHub). -
PanelRow
: создает общий контейнер для элементов управления боковой панели (см. на GitHub). -
QueryControls
: предоставляет элементы управления настройками для создания запроса (см. на GitHub). -
ToggleControl
: предоставляет пользователям кнопку-переключатель для включения/отключения определенной опции (см. на GitHub). -
RangeControl
: используется для выбора из диапазона добавочных значений (см. GitHub).
Затем вам нужно обновить функцию Edit
, чтобы использовать доступные элементы управления. Сначала измените функцию Edit
следующим образом:
export default function Edit( { attributes, setAttributes } ) { const { numberOfItems, columns, displayExcerpt, displayDate, displayThumbnail } = attributes; const posts = useSelect( ( select ) => { return select( 'core' ).getEntityRecords( 'postType', 'post', { 'per_page': numberOfItems, '_embed': true }); }, [ numberOfItems ] ); ... }
Обратите внимание на свойство setAttributes
, переданное функции Edit
.
Теперь вы можете добавить соответствующие элементы в свой код JSX:
return ( <> <InspectorControls> <PanelBody title={ __( 'Content Settings', 'author-plugin' ) }> <PanelRow> <QueryControls numberOfItems={ numberOfItems } onNumberOfItemsChange={ ( value ) => setAttributes( { numberOfItems: value } ) } minItems={ 1 } maxItems={ 10 } /> </PanelRow> <PanelRow> <RangeControl label={ __( 'Number of Columns', 'author-plugin' ) } value={ columns } onChange={ ( value ) => setAttributes( { columns: value } ) } min={ 1 } max={ 4 } required /> </PanelRow> <PanelRow> <ToggleControl label={ __( 'Show Featured Image', 'author-plugin' ) } checked={ displayThumbnail } onChange={ () => setAttributes( { displayThumbnail: ! displayThumbnail } ) } /> </PanelRow> <PanelRow> <ToggleControl label={ __( 'Show Date', 'author-plugin' ) } checked={ displayDate } onChange={ () => setAttributes( { displayDate: ! displayDate } ) } /> </PanelRow> <PanelRow> <ToggleControl label={ __( 'Display Excerpt', 'author-plugin' ) } checked={ displayExcerpt } onChange={ () => setAttributes( { displayExcerpt: ! displayExcerpt } ) } /> </PanelRow> </PanelBody> </InspectorControls> <div { ...useBlockProps() }> ... </div> </> );
Ничего себе, это много кода, не так ли? Но это довольно легко понять.
Атрибуты элементов, которые здесь наиболее достойны вашего внимания, — это onNumberOfItemsChange
в QueryControls
и onChange
в RangeControl
и ToggleControl
. Эти атрибуты устанавливают обработчики событий, необходимые для того, чтобы пользователь мог настроить внешний вид и/или поведение блока.
Вы также заметите, что мы использовали теги <>
и </>
, которые являются коротким синтаксисом для объявления фрагментов React.
Теперь сохраните файл, перейдите в редактор и обновите страницу:
Там все есть? Затем давайте продолжим и добавим информацию об авторе сообщения.
Найдите автора поста
Как мы упоминали выше, в нашем блоке будет отображаться список статей, написанных тем же автором, что и текущий пост.
Чтобы получить идентификатор автора сообщения, вы импортируете селектор getCurrentPostAttribute
из хранилища данных core/editor
:
wp.data.select( 'core/editor' ).getCurrentPostAttribute( 'author' )
getCurrentPostAttribute
возвращает значение атрибута для сохраненного сообщения.
Получив идентификатор автора, вы можете изменить запрос, как показано ниже:
const posts = useSelect( ( select ) => { const _authorId = select( 'core/editor' ).getCurrentPostAttribute( 'author' ); return select( 'core' ).getEntityRecords( 'postType', 'post', { 'author': _authorId, 'per_page': numberOfItems, '_embed': true }); }, [ numberOfItems ] );
С помощью этого кода вы получите список из n
статей того же автора, что и текущий пост.
Теперь, когда у вас есть идентификатор автора, вы также можете использовать его для извлечения дополнительных данных из базы данных.
Отображение сведений об авторе
Поскольку у нас нет доступной документации, мы использовали код из основного блока Post Author в качестве ссылки.
Чтобы отобразить сведения об авторе, сначала необходимо импортировать новую зависимость:
import { forEach } from 'lodash';
Затем в функции Edit
обновите объект attributes
следующим образом:
const { numberOfItems, columns, displayExcerpt, displayDate, displayThumbnail, displayAuthorInfo, showAvatar, avatarSize, showBio } = attributes;
После этого вы отредактируете код, показанный в предыдущем разделе, чтобы получить информацию об авторе:
const { authorDetails, posts } = useSelect( ( select ) => { const _authorId = select( 'core/editor' ).getCurrentPostAttribute( 'author' ); const authorDetails = _authorId ? select( 'core' ).getUser( _authorId ) : null; const posts = select( 'core' ).getEntityRecords( 'postType', 'post', { 'author': _authorId, 'per_page': numberOfItems, '_embed': true }); return { authorDetails: authorDetails, posts: posts }; }, [ numberOfItems ] );
Обратите внимание, что мы использовали селектор getUser
для получения сведений об авторе.
Далее вы можете захотеть получить аватар автора. В приведенном ниже коде создается массив элементов, хранящих URL-адреса и размеры аватара:
const avatarSizes = []; if ( authorDetails ) { forEach( authorDetails.avatar_urls, ( url, size ) => { avatarSizes.push( { value: size, label: `${ size } x ${ size }`, } ); } ); }
Затем вы добавите боковые панели и элементы управления, чтобы пользователи могли настраивать область автора в блоке:
return ( <> <InspectorControls> <PanelBody title={ __( 'Author Info', 'author-plugin' ) }> <PanelRow> <ToggleControl label={ __( 'Display Author Info', 'author-plugin' ) } checked={ displayAuthorInfo } onChange={ () => setAttributes( { displayAuthorInfo: ! displayAuthorInfo } ) } /> </PanelRow> { displayAuthorInfo && ( <> <PanelRow> <ToggleControl label={ __( 'Show avatar' ) } checked={ showAvatar } onChange={ () => setAttributes( { showAvatar: ! showAvatar } ) } /> { showAvatar && ( <SelectControl label={ __( 'Avatar size' ) } value={ avatarSize } options={ avatarSizes } onChange={ ( size ) => { setAttributes( { avatarSize: Number( size ), } ); } } /> ) } </PanelRow> <PanelRow> <ToggleControl label={ __( 'Show Bio', 'author-plugin' ) } checked={ showBio } onChange={ () => setAttributes( { showBio: ! showBio } ) } /> </PanelRow> </> ) } </PanelBody> ... </InspectorControls> ... </> );
На изображении ниже показана обновленная боковая панель настроек:
Наконец, вы можете добавить в свой блок авторский раздел:
return ( <> <InspectorControls> ... </InspectorControls> <div { ...useBlockProps() }> { displayAuthorInfo && authorDetails && ( <div className="wp-block-author-box-author-plugin__author"> { showAvatar && ( <div className="wp-block-author-box-author-plugin__avatar"> <img width={ avatarSize } src={ authorDetails.avatar_urls[ avatarSize ] } alt={ authorDetails.name } /> </div> ) } <div className='wp-block-author-box-author-plugin__author-content'> <p className='wp-block-author-box-author-plugin__name'> { authorDetails.name } </p> { showBio && // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining authorDetails?.description && authorDetails.description.length > 0 && ( <p className='wp-block-author-box-author-plugin__description'>{ authorDetails.description }</p> ) } </div> </div> )} <ul> ... </ul> </div> </> );
На следующем изображении показано, как это отображается на экране.
Теперь сохраните файл edit.js и запустите тесты. Ваш блок должен включать разные элементы в зависимости от настроек блока.
Не хватает еще одной последней вещи: количества столбцов для отображения статей.
Изменить количество столбцов
Чтобы дать пользователю возможность отображать превью статей в столбцах, мы определили атрибут columns
в файле block.json . Мы также включили в сценарий атрибут columns
и создали элемент управления настройками, чтобы пользователи могли изменять количество столбцов, хотя на данный момент это изменение не действует.
В приведенном выше коде JSX вы должны были заметить, что мы добавили классы CSS к нескольким элементам:
Классы, присвоенные элементам в разделе Author:
-
wp-block-author-box-author-plugin__author
-
wp-block-author-box-author-plugin__avatar
-
wp-block-author-box-author-plugin__author-content
-
wp-block-author-box-author-plugin__name
-
wp-block-author-box-author-plugin__description
Классы, назначенные элементам в разделе контента:
-
wp-block-author-box-author-plugin__post-items
-
wp-block-author-box-author-plugin__post-thumbnail
-
wp-block-author-box-author-plugin__post-title
-
wp-block-author-box-author-plugin__post-date
-
wp-block-author-box-author-plugin__post-excerpt
Одного класса по-прежнему не хватает. Имя этого класса будет сгенерировано динамически, чтобы отразить количество столбцов, заданное пользователем.
Вернитесь к файлу Edit.js
и измените элемент ul
следующим образом:
<ul className={ `wp-block-author-box-author-plugin__post-items columns-${ columns }` }> ... </ul>
Мы добавили новый класс columns-${ columns }
в соответствии с синтаксисом шаблонных литералов для вставки выражения в строку. Таким образом, атрибут, прикрепленный к элементу ul
, будет зависеть от пользовательских настроек (например, columns-1
, columns-2
и т. д.).
Теперь откройте файл style.scss
и замените существующий код следующим:
.wp-block-author-box-author-plugin { background-color: #21759b; color: #fff; padding: .6em; ul.wp-block-author-box-author-plugin__post-items { padding: 0; list-style-type: none; display: grid; gap: .5em; @for $i from 2 through 4 { &.columns-#{ $i } { grid-template-columns: repeat(#{ $i }, 1fr); } } li { list-style: none; img.wp-block-author-box-author-plugin__post-thumbnail { height: auto; max-width: 100%; } } } } .wp-block-author-box-author-plugin__author { display: flex; flex-wrap: wrap; } .wp-block-author-box-author-plugin__avatar { margin-right: 1em; } .wp-block-author-box-author-plugin__author-content { flex-basis: 0; flex-grow: 1; }
Мы не будем углубляться в этот код, поскольку он выходит за рамки этой статьи. Но если вы хотите погрузиться глубже, вы можете обратиться к следующим ресурсам:
- Макет сетки CSS
- Изучите сетку CSS
- Правило @for в Sass
- Вложение в Sass
Вот и все, что касается рендеринга блока в редакторе.
Создание блока для рендеринга на странице
Теперь, когда код, который рендерит блок в редакторе, завершен, мы можем двигаться дальше и построить блок для рендеринга во внешнем интерфейсе.
Как мы упоминали ранее, когда речь идет о динамических блоках, файл плагина отвечает за создание HTML-кода, который будет отображаться во внешнем интерфейсе.
Итак, откройте основной файл вашего плагина (в нашем примере author-plugin.php ).
Первое, что нужно сделать, это сделать атрибуты блока доступными для PHP-функции WordPress. В вашем файле PHP измените определение функции следующим образом:
function author_box_author_plugin_render_author_content( $attr ) { ... }
Теперь вы можете использовать функции WordPress для извлечения данных и управления ими. Например, вы можете использовать get_posts
для получения последних сообщений в блоге (подробнее читайте в нашей подробной статье, посвященной функции get_posts
):
function author_box_author_plugin_render_author_content( $attr ) { $args = array( 'numberposts' => $attr['numberOfItems'], ); $my_posts = get_posts( $args ); if( ! empty( $my_posts ) ){ $output = '<ul>'; foreach ( $my_posts as $p ){ $output .= '<li><a href="' . esc_url( get_permalink( $p->ID ) ) . '">' . $p->post_title . '</a></li>'; } $output .= '</ul>'; } return $output ?? '<strong>Sorry. No posts matching your criteria!</strong>'; }
Приведенная выше функция извлекает последние записи блога numberOfItems
из вашей базы данных WordPress (по умолчанию post_type
имеет значение post
) и возвращает массив объектов $post
. Затем он перебирает массив для построения элементов списка.
Если вы проверите вывод HTML, вы заметите, что это простой список сообщений, как показано на следующем изображении:
В нашей предыдущей статье мы упоминали, что вы будете использовать useBlockProps
React, чтобы пометить элемент-оболочку блока в вашем коде JSX. Вам нужно будет сделать то же самое в вашей функции PHP.
WordPress предоставляет для этого функцию get_block_wrapper_attributes
.
Итак, измените свой PHP-код следующим образом:
function author_box_author_plugin_render_author_content( $attr ) { $args = array( 'numberposts' => $attr['numberOfItems'] ); $my_posts = get_posts( $args ); if( ! empty( $my_posts ) ){ $output = '<div ' . get_block_wrapper_attributes() . '>'; $output .= '<ul>'; foreach ( $my_posts as $p ){ $title = $p->post_title ? $p->post_title : 'Default title'; $url = esc_url( get_permalink( $p->ID ) ); $output .= '<li>'; $output .= '<a href="' . $url . '">' . $title . '</a>'; $output .= '</li>'; } $output .= '</ul>'; $output .= '</div>'; } return $output ?? '<strong>Sorry. No posts matching your criteria!</strong>'; }
Теперь элементу контейнера назначен класс wp-block-author-box-author-plugin
, и у блока другой цвет фона.
Затем функция get_posts
получает данные WP_Posts
, а цикл foreach
строит элементы списка (см. также Как отображать данные, возвращаемые get_posts).
Добавить избранное изображение, дату и отрывок
Затем вам нужно будет добавить миниатюры постов, даты и выдержки. В том же файле измените код PHP следующим образом:
function author_box_author_plugin_render_author_content( $attr ) { $args = array( 'numberposts' => $attr['numberOfItems'] ); $my_posts = get_posts( $args ); if( ! empty( $my_posts ) ){ $output = '<div ' . get_block_wrapper_attributes() . '>'; $output .= '<ul class="wp-block-author-box-author-plugin__post-items columns-">'; foreach ( $my_posts as $p ){ $title = $p->post_title ? $p->post_title : 'Default title'; $url = esc_url( get_permalink( $p->ID ) ); $thumbnail = has_post_thumbnail( $p->ID ) ? get_the_post_thumbnail( $p->ID, 'medium' ) : ''; $output .= '<li>'; if( ! empty( $thumbnail ) && $attr['displayThumbnail'] ){ $output .= $thumbnail; } $output .= '<h5><a href="' . $url . '">' . $title . '</a></h5>'; if( $attr['displayDate'] ){ $output .= '<time datetime="' . esc_attr( get_the_date( 'c', $p ) ) . '">' . esc_html( get_the_date( '', $p ) ) . '</time>'; } if( get_the_excerpt( $p ) && $attr['displayExcerpt'] ){ $output .= '<p>' . get_the_excerpt( $p ) . '</p>'; } $output .= '</li>'; } $output .= '</ul>'; $output .= '</div>'; } return $output ?? '<strong>Sorry. No posts matching your criteria!</strong>'; }
Цикл foreach
перебирает массив $my_posts
. На каждой итерации несколько условий проверяют значения атрибутов и соответствующим образом строят выходные данные.
Теперь взгляните на вывод на экране:
Теперь вы можете запустить свои тесты. Измените настройки даты, отрывка и эскиза и проверьте, как меняется содержимое блока во внешнем интерфейсе.
Отображение сообщений в столбцах
В нашем коде JavaScript мы использовали класс columns-${ columns }
для отображения превью сообщений в столбцах. Теперь нам нужно сделать то же самое в PHP.
Для этого вам просто нужно добавить эти две строки кода:
$num_cols = $attr['columns'] > 1 ? strval( $attr['columns'] ) : '1'; $output .= '<ul class="wp-block-author-box-author-plugin__post-items columns-' . $num_cols . '">';
Это добавит класс columns-n
к элементу ul
, содержащему превью сообщений. Теперь количество колонок, отображаемых на странице, должно совпадать с количеством колонок, заданным в настройках блока.
Создайте ящик автора
Наконец, вам нужно создать поле, содержащее данные об авторе, включая аватар, имя и описание.
В функции обратного вызова вам нужно будет добавить набор условий для проверки текущего значения каждого атрибута:
if( $attr['displayAuthorInfo'] ){ $output .= '<div class="wp-block-author-box-author-plugin__author">'; if( $attr['showAvatar'] ){ $output .= '<div class="wp-block-author-box-author-plugin__avatar">' . get_avatar( get_the_author_meta( 'ID' ), $attr['avatarSize'] ) . '</div>'; } $output .= '<div class="wp-block-author-box-author-plugin__author-content">'; $output .= '<div class="wp-block-author-box-author-plugin__name">' . get_the_author_meta( 'display_name' ) . '</div>'; if( $attr['showBio'] ){ $output .= '<div class="wp-block-author-box-author-plugin__description">' . get_the_author_meta( 'description' ) . '</div>'; } $output .= '</div>'; $output .= '</div>'; }
Код довольно прост. Он проверяет текущее значение каждого атрибута, и если оно true
, то генерирует необходимый HTML.
Теперь сохраните файл PHP и сравните блок в редакторе с таким же блоком во внешнем интерфейсе.
Вы найдете полный код блока примера в этом общедоступном Gist.
Рекомендуемые ресурсы для разработки динамических блоков
Если вы навострили уши, читая эту статью, и начали осознавать возможности профессионального развития, связанные с изучением того, как создавать блоки Гутенберга, что ж, мы советуем продолжать изучать и приобретать новые навыки в технологиях, лежащих в основе разработки блоков.
Хотя до сих пор отсутствует надежная официальная документация, тем не менее существуют отличные ресурсы, как бесплатные, так и платные, к которым мы обращались при написании этой статьи. Среди множества доступных ресурсов мы рекомендуем следующие:
Официальные ресурсы
- Данные
- Основные данные
- Создание динамических блоков
- Введение в разработку блоков Гутенберга
- Социальное обучение WordPress на MeetUp
Рекомендуемые учебные пособия от основных участников WordPress
- Запрос данных в Гутенберге с помощью getEntityRecords Райана Уэлчера (@ryanwelcher)
- Практический обзор @wordpress/data API Даррена Этье (@nerrad)
Ресурсы JavaScript, React и Redux
- Учебники по JavaScript от MDN
- Начало работы с React (официальное)
- Учебник по Redux (официальный)
Связанные ресурсы от Kinsta
- Что такое JavaScript? Взгляд на самый популярный язык сценариев в Интернете
- Полное руководство по обработке ошибок в JavaScript
- Что такое Node.js и почему вы должны его использовать
- Как установить Node.js и npm в Windows, macOS и Linux
- Как отлаживать код Node.js с помощью нескольких инструментов
- Node.js против PHP: прямое сравнение
- 10 самых популярных типов приложений Node.js в 2022 году
- Angular и React: подробное параллельное сравнение
Резюме
Мы подошли к концу этого (второго) долгого пути по разработке блоков Гутенберга.
В этой статье мы рассмотрели некоторые дополнительные темы, такие как Application State и хранилища Redux. Но, надеюсь, теперь у вас должно быть лучшее понимание разработки блоков в целом.
Да, навыки Node.js, Webpack, Babel, React и Redux необходимы, когда дело доходит до создания расширенных блоков Gutenberg, но вам не нужно быть ниндзя React, чтобы начать. Изучение того, как разрабатывать блоки Гутенберга, не обязательно должно быть сложным. Просто делайте это с правильной мотивацией и следуя соответствующему пути обучения.
И мы надеемся, что эта статья — и предыдущая — предоставит вам правильную карту, чтобы найти свой путь и сразу приступить к разработке Gutenberg.
До вас сейчас! Вы уже создали динамические блоки? У вас есть примеры, которыми вы можете поделиться с нами? И каковы были самые большие препятствия в вашем опыте? Не стесняйтесь оставить комментарий ниже.