Редактор Gutenberg, который появился в WordPress версии 5.0 содержит довольно много разнообразных блоков, которые закрывают множество потребностей пользователей. Однако нет предела совершенству, поэтому всегда найдется клиент, под которого нужно разработать какой-либо уникальный блок.Давайте здесь рассмотрим, как мы можем создать свой кастомный блок для редактора Gutenberg в виде аккордеона, который можно будет использовать для секции FAQ (ЧАВО), т.е. вопросов и ответов, которая довольно часто нужна на сайте.
Как известно, редактор Gutenberg был написан на React, поэтому мы будем использовать Node.js и Visual Studio Code, которые надо установить на ваш компьютер. Все инструменты бесплатны и кроссплатформенны, поэтому подойдут владельцам разных операционных систем. Также у вас должен быть установлен любой локальный сервер (XAMPP, MAMP, OpenServer) или Docker с уже установленным WordPress на нем. Хотя, если вы читаете эту статью, думаю, все это у вас уже есть.
Для разработки блока под Gutenberg мы будем создавать WordPress-плагин, в котором больше будет JavaScript, используемого в React, чем PHP. Конечно, лучше, если вы уже писали что-либо на React, но даже знаний JavaScript для начала вам вполне будет достаточно. Кроме того, приветствуется опыт работы с Node.js, т.к. придется устанавливать пакеты и запускать скрипты в терминале.
В этой статье мы рассмотрим следующее:
- Генерируем начальные файлы с помощью WordPress blocks
- Структура файлов плагина
- Использование useBlockProps
- Активируем плагин-аккордеон
- Установка нужных npm-пакетов
- Использование компонента RichText
- Использование InnerBlocks
- Основной блок
Генерируем начальные файлы с помощью WordPress blocks
Мы воспользуемся пакетом @wordpress/create-block. Для этого вам нужно открыть командную строку (клавиши Windows + R и затем cmd
и Enter, a затем нужно перейти в папку с плагинами wp-content/plugins вашего локального тестового сайта командой cd C:\OpenServer\domains\test-wp\wp-content\plugins
- это в случае установки на OpenServer), Shift
+ правый клик
в папке plugins - Открыть окно PowerShell здесь, запустить команду Open Git Busch here
, если установлена Git, или открыть в папке VSCode и в его терминале набрать такие команды:
1 2 3 | $ npx @wordpress/create-block@latest accordion-block $ cd accordion-block $ npm start |
Можно не использовать $ cd accordion-block
и $ npm start
, а сначала открыть папку accordion-block и запустить в ней Visual Studio Code, а затем уже внутри этого редактора в терминале набрать $ npm start
.
После запуска кода в терминале вы можете увидеть сообщение о создании файлов block.json и package.json и установке пакета @wordpress/scripts
:
1 2 3 4 5 6 7 | Creating a new WordPress plugin in the accordion-block directory. Creating a "block.json" file. Creating a "package.json" file. Installing `@wordpress/scripts` package. It might take a couple of minutes... |
При успешной установке всех пакетов вы можете увидеть в консоли такое сообщение:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | Formatting JavaScript files. Compiling block. Done: WordPress plugin accordion-block bootstrapped in the accordion-block directory. You can run several commands inside: $ npm start Starts the build for development. $ npm run build Builds the code for production. $ npm run format Formats files. $ npm run lint:css Lints CSS files. $ npm run lint:js Lints JavaScript files. $ npm run plugin-zip Creates a zip file for a WordPress plugin. $ npm run packages-update Updates WordPress packages to the latest version. To enter the directory type: $ cd accordion-block You can start development with: $ npm start |
Если такого сообщения вы не увидели, а все закончилось предупреждением Installing
@wordpress/scripts
package. It might take a couple of minutes..., то вам нужно самим установить пакет @wordpress/scripts
в папку с плагином командой:
1 | npm i @wordpress/scripts |
Либо, что еще проще, набрать команду
1 | npm install |
и будет выполнена установка плагинов из package.json.
Структура файлов плагина
В корне созданной папки вы найдете файл с именем accordion-block.php. Он является основным файлом вашего плагина и содержит информацию о плагине и функцию для регистрации блока.
Код в этом файле примерно такой:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?php /** * Plugin Name: Accordion Block * Description: Example block scaffolded with Create Block tool. * Requires at least: 6.1 * Requires PHP: 7.0 * Version: 0.1.0 * Author: The WordPress Contributors * License: GPL-2.0-or-later * License URI: https://www.gnu.org/licenses/gpl-2.0.html * Text Domain: accordion-block * * @package CreateBlock */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } /** * 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 create_block_accordion_block_block_init() { register_block_type( __DIR__ . '/build' ); } add_action( 'init', 'create_block_accordion_block_block_init' ); |
Как оказалось, такой плагин уже существует в репозитории плагинов WordPress.
Поэтому мы поменяем его версию и описание. Вы также можете заменить имя автора. Здесь это не принципиально.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php /** * Plugin Name: Accordion Block * Description: Accordion Block for Gutenberg editor. * Requires at least: 6.1 * Requires PHP: 7.0 * Version: 1.1.1 * Author: The WordPress Contributors * License: GPL-2.0-or-later * License URI: https://www.gnu.org/licenses/gpl-2.0.html * Text Domain: accordion-block * * @package CreateBlock */ |
Теперь можно активировать блок и переходить в редактирование записи.
Имеет смысл открыть папку с вашим плагином в VisualStudio Code, чтобы посмотреть этот код и перейти в папку src для редактирования следующих файлов:
- block.json - файл, где собрана вся информация о вашем блоке и его атрибутах
- edit.js - файл, описывающий все опции для редактирования блока в админке. В нем есть функция
Edit()
для экспорта в index.js и параметры в виде строки{ ...useBlockProps }
. Для начала в ней есть параграф с приветственным текстом. - save.js - файл, описывающий вывод информации на сайте (фронте). В нем есть функция
save()
для экспорта в index.js и параметрыв виде строки{ ...useBlockProps.save() }
. Например, класс вашего блока. - index.js - не факт, что вам придется что-либо здесь редактировать, но код в этом файле говорит о том, что вы регистрируете блок с определенным названием (соответствует названию папки проекта), а также используете функции для редактирования блока в админке и сохранения блока для сайта в функциях
Edit
иsave
, которые доступны файлах edit.js и save.js соответственно. Однако именно здесь вы будете добавлять атрибуты, когда код в вашем блоке будет усложняться. - style.scss - для стилей блока на фронте (на сайте). Обратите внимание, что это файл, подразумевающий код в стилистике SASS (SCSS). Файл style.css, который впоследствии будет сгенерирован можно использовать для стилей как на фронте, так и в админке. В админке их можно переписать в файле editor.scss.
- editor.scss - для стилей блока в админке. Тоже для SCSS-синтаксиса.
В файле вы увидите уже некоторые стили для вашего блока:
1 2 3 4 5 | .wp-block-create-block-accordion-block { background-color: #21759b; color: #fff; padding: 2px; } |
В файле package.json вы можете найти скрипты, которые являются командами для запуска вашего кода:
1 2 3 4 5 6 7 8 9 | "scripts": { "build": "wp-scripts build", "format": "wp-scripts format", "lint:css": "wp-scripts lint-style", "lint:js": "wp-scripts lint-js", "packages-update": "wp-scripts packages-update", "plugin-zip": "wp-scripts plugin-zip", "start": "wp-scripts start" } |
Например, npm run build
сформирует папку build, из которой будет браться готовый код для блока, а npm run start
нужно будет запускать каждый раз, когда вы будете возвращаться к редактированию кода после того, как закрыли VSCode накануне или некоторое время назад, чтобы был сгенерирован новый скрипт.
Команда npm run format
красиво отформатирует ваш код.
В файле index.js вы увидите следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | /** * Registers a new block provided a unique name and an object defining its behavior. * * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/ */ import { registerBlockType } from '@wordpress/blocks'; /** * Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files. * All files containing `style` keyword are bundled together. The code used * gets applied both to the front of your site and to the editor. * * @see https://www.npmjs.com/package/@wordpress/scripts#using-css */ import './style.scss'; /** * Internal dependencies */ import Edit from './edit'; import save from './save'; import metadata from './block.json'; /** * Every block starts by registering a new block type definition. * * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/ */ registerBlockType( metadata.name, { /** * @see ./edit.js */ edit: Edit, /** * @see ./save.js */ save, } ); |
На данный момент код говорит о том, что мы регистрируем наш блок, используя 2 функции из файлов edit.js и save.js. Однако в файле edit.js функцию мы назвали с большой буквы (Edit
), поэтому указываем ее, как edit: Edit
, а в файле save.js она совпадает с названием функции для редактирования, поэтому оставляем просто save
.
В файле edit.js мы имеем такой код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /** * Retrieves the translation of text. * * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-i18n/ */ import { __ } from '@wordpress/i18n'; /** * React hook that is used to mark the block wrapper element. * It provides all the necessary props like the class name. * * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops */ import { useBlockProps } from '@wordpress/block-editor'; /** * Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files. * Those files can contain any CSS code that gets applied to the editor. * * @see https://www.npmjs.com/package/@wordpress/scripts#using-css */ import './editor.scss'; /** * The edit function describes the structure of your block in the context of the * editor. This represents what the editor will render when the block is used. * * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit * * @return {Element} Element to render. */ export default function Edit() { return ( <p { ...useBlockProps() }> { __( 'Accordion Block – hello from the editor!', 'accordion-block' ) } </p> ); } |
Все комментарии вы можете убрать, сократив код до такого:
1 2 3 4 5 6 7 8 9 10 11 12 | import { __ } from '@wordpress/i18n'; import { useBlockProps } from '@wordpress/block-editor'; import './editor.scss'; export default function Edit() { return ( <p { ...useBlockProps() }> { __( 'Accordion Block – hello from the editor!', 'accordion-block' ) } </p> ); } |
Этот код выведет вам абзац с синим фоном и белым цветом текста в админке.
В файле save.js вы найдете такой код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /** * React hook that is used to mark the block wrapper element. * It provides all the necessary props like the class name. * * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops */ import { useBlockProps } from '@wordpress/block-editor'; /** * The save function defines the way in which the different attributes should * be combined into the final markup, which is then serialized by the block * editor into `post_content`. * * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#save * * @return {Element} Element to render. */ export default function save() { return ( <p { ...useBlockProps.save() }> { 'Dynamicblock – hello from the saved content!' } </p> ); } |
Снова сокращаем код, убрав комментарии:
1 2 3 4 5 6 7 8 9 | import { useBlockProps } from '@wordpress/block-editor'; export default function save() { return ( <p { ...useBlockProps.save() }> { 'Accordion Block – hello from the saved content!' } </p> ); } |
Этот файл ответственен за вывод текста 'Accordion Block – hello from the saved content!'
на сайте.
Использование useBlockProps
useBlockProps - это хук React, который позволяет вывести все данные для вашего Gutenberg-блока. Основным является class
, или в нотации React className
, который совпадает с названием вашего блока в block.json. В нашем случае в block.json есть строка "name": "tempo/accordion-block"
, слэш в которой будет заменен пробелом.
В админке ваш блок имеет стандартные классы "block-editor-block-list__block wp-block
", если блок выбран, то еще и классы "is-selected is-highlighted
" , а также ваш кастомный класс "wp-block-tempo-accordion-block
", который вы также увидите и на сайте.
Кроме того в useBlockProps вы можете поместить дополнительный класс или data-атрибуты или стилевые свойства, чем мы воспользуемся при назначении цветовых настроек для аккордеона.
Например, код может быть таким:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | export default function Save({ attributes }) { const accordionStyleVars = { "--tempo-accordion-title-bgcolor": attributes.titleBgColor, "--tempo-accordion-title-color": attributes.titleTextColor, "--tempo-accordion-font-color": attributes.contentTextColor, "--tempo-accordion-panel-background-color": attributes.contentBgColor }; const blockProps = useBlockProps( { className: 'accordion-item', 'data-name': 'faq-accordion', style: accordionStyleVars } ); return ( <div {...blockProps}> ... </div> ) } |
То есть те атрибуты, которые вы хотите использовать в своем блоке, а точнее в его корневом элемента, вы должны перечислить в хуке useBlockProps. Учтите, что эти атрибуты нужно писать отдельно и в файле edit.js, и в файле save.js.
В результате в админке мы получим такие атрибуты в html-коде нашего блока:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <div tabindex="0" class="block-editor-block-list__block wp-block is-selected is-highlighted wp-block-tempo-accordion-block accordion-item" id="block-cdf5c44b-4414-431c-bd3e-cea7ffdbc5b9" role="document" aria-label="Блок: Accordion Block" data-block="cdf5c44b-4414-431c-bd3e-cea7ffdbc5b9" data-type="tempo/accordion-block" data-title="Accordion Block" data-name="faq-accordion" style="--tempo-accordion-title-bgcolor: #0693e3; --tempo-accordion-title-color: #ffffff; --tempo-accordion-font-color: #222222; --tempo-accordion-panel-background-color: #e0f0fa;"> ... </div> |
Активируем плагин-аккордеон
После этого перейдите в раздел Плагины в админке WordPress и активируйте ваш плагин, найдя его в списке плагинов по названию. Теперь перейдите в админку, найдите по названию блок accordion в любой новой или старой записи и добавьте его.
И кстати, вы не забыли запустить компиляцию скриптов командой npm start
? Если забыли, то сделайте это, а то не сможете найти ваш блок в админке))
Вместо npm start
имеет смысл запустить команду npm run start
, т.к. она отвечает за постоянную компиляцию скриптов после любого сохранения ваших файлов. В этом случае вам не нужно следить за обновлением кода в админке. Кроме того, имеет смысл обновлять страницу в админке с обновлением кеша (CTRL+F5
или Shift
+ кнопка обновления в браузере) - тогда вы точно будете подтягивать новую версию скрипта для блока. Также можно отключить кеш, поставив галочку в Инструментах разработчика на вкладке Сеть (Network).
Итак, выбираем наш блок среди других, используя поле поиска, добавляем в любое место статьи и видим следующий текст:
Как вы, должно быть увидели, для блока выбрана иконка смайлика, что не совсем соответствует его функционалу, не очень понятный текст описания и относится он к категории виджетов, хотя должен относится к тексту. Все это мы можем исправить в файле block.json, который вы найдете в папке src вашего плагина.
Для иконки будем использовать набор WordPress Dashicons. В качестве категорий мы можем использовать одну из списка:
- text
- media
- design
- widgets
- theme
- embed
В результате код block.json изменится и будет таким:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | { "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "create-block/accordion-block", "version": "1.1.1", "title": "Accordion Block", "category": "text", "icon": "list-view", "description": "Make spoiler for FAQ section.", "example": {}, "supports": { "html": false }, "textdomain": "accordion-block", "editorScript": "file:./index.js", "editorStyle": "file:./index.css", "style": "file:./style-index.css", "viewScript": "file:./view.js" } |
Установка нужных npm-пакетов
Для того чтобы использовать блоки, которые можно редактировать и управлять ими с помощью кнопок, нам необходимо установить еще несколько пакетов модулей следующими командами в терминале:
1 2 3 4 5 6 | npm i @wordpress-components npm install @wordpress/block-editor npm install @wordpress/components //при использовании загрузки картинок npm i @wordpress/blob |
Для установки модулей вы можете использовать команду install
или ее краткий аналог в виде буквы i
.
Скорей всего, у вас уже будет установлен и использован в коде пакет для перевода @wordpress/i18n
, но если вы его не обнаружите, нужно добавить его командой
1 | npm i @wordpress/i18n |
Этот пакет позволяет потом использовать .po и .mo-файлы, в которых вы определяете строки для различных языков (переводов). Затем вы будете импортировать функцию из этого пакета в файл edit.js и использовать ее примерно так:
1 2 3 4 5 6 7 8 9 10 | import { __ } from '@wordpress/i18n'; export default function Edit({ attributes, setAttributes }) { return ( <> <PanelBody title={ __('Settings for Image', 'accordion-block') }> ... код ... </PanelBody> <>); } |
Использование компонента RichText
На данном этапе у нас выводится статический текст. Естественно, это совсем не тот вариант, который необходим, т.к. любой пользователь захочет вставить свой текст. Поэтому мы добавляем 2 атрибута в файл index.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | registerBlockType( metadata.name, { attributes: { heading: { type: 'string', source: 'html', selector: 'div', }, content: { type: 'string', source: 'html', selector: 'div', } }, edit: Edit, save, } ); |
Атрибуты также можно добавлять в файл block.json аналогичным образом, но в формате JSON, т.е. с двойными кавычками для всех строковых по сути свойств и значений.
А в файле edit.js нам нужно добавить импорт компонента RichText и его использование:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import { __ } from '@wordpress/i18n'; import { useBlockProps, RichText } from '@wordpress/block-editor'; import './editor.scss'; export default function Edit({ attributes, setAttributes }) { const blockProps = useBlockProps({ className: 'accordion', } ); const {heading, content} = attributes; return ( <div {...blockProps}> <RichText tagName='div' className='accordion-item' allowedFormats={ [ 'core/bold', 'core/italic' ] } value={heading} onChange={(newVal) => setAttributes({heading: newVal})} placeholder="Heading text here" /> <RichText tagName='div' className='accordion-content' value={content} onChange={(newVal) => setAttributes({content: newVal})} placeholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." /> </div> ); } |
Обратите внимание, что для heading - заголовка для каждого элемента аккордеона мы разрешаем только кнопки Bold и Italic в атрибуте allowedFormats, а для основного контента (content) этот атрибут опущен, т.е. можно использовать все варианты форматирования. В const blockProps
мы помещаем данные о свойствах этого блока и добавляем в 8-й строке еще один класс, который будет виден и в админке, и на фронтенде.
Также для каждого компонента RichText указаны атрибуты value
и onChange
, которые предназначены для изменения и сохранения контента в данном поле.
В файле save.js мы также импортируем данный компонент и используем его содержимое в виде RichText.Content
, однако для каждого поля указываем другой value
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import { useBlockProps, RichText } from '@wordpress/block-editor'; export default function save({ attributes }) { const blockProps = useBlockProps.save({ className: 'accordion' }); return ( <div {...blockProps}> <RichText.Content tagName="div" className="accordion-item" value={ attributes.heading } /> <RichText.Content tagName="div" className="accordion-content" value={ attributes.content } /> </div> ) }; |
В результате при добавлении и заполнении нашего блока тестовыми данными увидим следующее в админке и на сайте:
Тем не менее и это не тот вариант, который нужен, т.к. мы должны будем добавлять несколько таких блоков-аккордеонов вместо того, чтобы использовать один блок и множество вложенных в него повторяющихся по структуре внутренних блоков.
Использование InnerBlocks
Вложенные блоки - это то, что вы можете наблюдать при использовании колонок, например. Есть некий внешний блок-оболочка, или wrapper, и вложенные в него дочерние блоки - children. Официальную справочную информацию вы можете найти здесь и на GitHub.
Для внутренних блоков можно использовать как разные виды уже существующих в ядре WordPress блоков, так и те, что вы создаете самостоятельно.
Для того чтобы начать это использовать вложенные блоки, давайте стачала изменим информацию о нашем плагине в block.json, т.к. все плагины часто используют некий префикс для того, чтобы не переопределялись стили и переменные. Поэтому в файле block.json меняем только строку "name". Наш префикс будет "tempo":
1 | "name": "tempo/accordion-block", |
Кстати, будьте готовы к тому, что при любых изменениях в вашем коде при обновлении страницы в админке у вас будет сообщение о том, что ваш блок работает не вполне правильно. Временами достаточно нажать на кнопку "Попытка восстановления блока", временами нужно удалить старый блок и добавить новый.
Теперь определимся со структурой:
- Основной блок - это, собственно, сам аккордеон, который у нас уже есть, но требует переработки кода.
- Внутри аккордеона находятся несколько раскрывающихся панелей. Мы будем создавать отдельный блок panel, а с точки зрения классов у нас там будет основным
.accordion-item
. - В каждой
.accordion-item
. мы будем размещать заголовок в виде компонента RichText + элемент в виде стрелки, который будет изменяться при открытии/закрытии панели, а также еще один блок с контентом в виде параграфов, списков, картинок и т.п., которые обычно размещают в аккордеонах.
Блок panel
Начнем с блока panel. Для этого в папке src
создаем папку panel
с 3-мя файлами: index.js, edit.js, save.js. То есть мы повторяем структуру файлов, ответственных за атрибуты, редактирование и сохранение, а также вывод нашего внутреннего блока.
Код файла index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import { registerBlockType } from '@wordpress/blocks'; import { __ } from '@wordpress/i18n'; import Edit from './edit'; import Save from './save'; registerBlockType( 'tempo/panel', { title: __('Accordion Panel', 'accordion-block'), description: __('Title and text panel in accordion', 'accordion-block'), icon: 'welcome-write-blog', parent: ['tempo/accordion-block'], supports: { html: true, reusable: false }, attributes: { title: { type: 'string', }, isOpen: { type: 'boolean', default: true }, }, edit: Edit, save: Save, } ); |
В этом коде мы регистрируем блок с тем же префиксом "tempo" и именем "panel". Обратите внимание, что вложенный блок мы описываем в файле index.js, а не в block.json.
Важным моментом является то, что мы указываем строку parent: ['tempo/accordion-block']
, которая говорит о том, что наш блок panel может быть только внутри нашего родительского блока.
Без этой строки, набирая при поиске блока название Accordion или его часть, мы увидим 2 блока, с ней - один.
Блок supports
показывает, что мы можем преобразовать наш код в HTML (html: true
), но не разрешаем переиспользовать этот блок (reusable: false
).
В качестве атрибутов мы используем title
для заголовка элемента, а isOpen
для проверки того, открыта или закрыта панель в админке.
Для редактирования панели в админке мы используем функцию Edit
из файла edit.js, который находится в папке panel, а для отображения на сайте - функцию Save
из save.js.
Код файла edit.js
Для управления внутренними блоками вам обязательно нужно импортировать компонент InnerBlocks
из пакета @wordpress/block-editor
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import { __ } from '@wordpress/i18n'; import { useBlockProps, RichText, InnerBlocks } from '@wordpress/block-editor'; export default function Edit({ attributes, setAttributes }) { const BLOCKS_TEMPLATE = [ [ 'core/paragraph', { content: __('Accordion paragraph content', 'accordion-block') } ], [ 'core/paragraph', { placeholder: __('Add accordion paragraph Content', 'accordion-block') } ], ]; //const DEFAULT_BLOCK = { name: 'core/paragraph', attributes: { content: 'Accordion Content...' } }; const { title, isOpen } = attributes; const blockProps = useBlockProps(); return ( <div {...blockProps}> <div className={`accordion-item${isOpen ? " open" : ''}`}> <div className="accordion-heading"> <RichText tagName='div' allowedFormats={ [ 'core/bold', 'core/italic' ] } value={title} onChange={(newVal) => setAttributes({title: newVal})} placeholder="Panel Title" /> <div className="switcher-up-down" onClick={()=>setAttributes({ isOpen: !isOpen })}> <div className="horizontal"></div> <div className="vertical"></div> </div> </div> <div className='accordion-content'> <InnerBlocks allowedBlocks={ ['core/image', 'core/gallery', 'core/media-text', 'core/paragraph', 'core/button', 'core/buttons', 'core/code', 'core/list', 'core/embed' ]} template={ BLOCKS_TEMPLATE } //defaultBlock={ DEFAULT_BLOCK } //directInsert={ true } /> </div> </div> </div> ); } |
Разбирать код этого файла будем со строки 19. В ней мы выводим компонент RichText с 2-мя допустимыми форматами - Bold и Italic для вывода заголовка каждой панели так, как делали ранее. RichText мы оборачиваем в <div className="accordion-heading">
, в котором еще добавляем <div className="switcher-up-down">
с двумя элементами, стили которых используем для создания стрелки. В этом же блоке есть обработка клика, которая изменяет атрибут isOpen
с true
на false
и наоборот: onClick={()=>setAttributes({ isOpen: !isOpen })}
. В случае true к классу accordion-item
добавляется класс open
, который изменяет стили. Стили мы допишем позже.
В <div className='accordion-content'>
мы разместим компонент <InnerBlocks />
с рядом атрибутов:
allowedBlocks
- массив разрешенных блоков из ядра WordPress, Это те блоки, которые могут быть использованы и вставлены как прямые потомки блока paneltemplate
- здесь мы указываем константуBLOCKS_TEMPLATE
- шаблон для внутренних блоков, который будет выводится сразу при первом добавлении нашего блока в структуру всех блоков на странице.- 2 закоментированных атрибута:
defaultBlock
- блок, который будет добавляться по умолчанию. В нашем случае это параграф из закомментированной константыDEFAULT_BLOCK
directInsert={ true }
- блок по умолчанию должен быть вставлен при клике на кнопке "Добавить блок".
Учтите, что задавая блок по умолчанию, при каждом нажатии на кнопку-аппендер в виде плюса вы будете добавлять именно такой блок. Конвертировать параграф можно при этом не во все блоки, а только в те, которые также используются для добавления текста.
Код файла save.js
В этот файл также нужно импортировать компонент InnerBlocks
из пакета @wordpress/block-editor
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import { useBlockProps, InnerBlocks, RichText } from '@wordpress/block-editor'; export default function Save({ attributes }) { const { title } = attributes; const blockProps = useBlockProps.save({ className: `accordion-item` }); return ( <div {...blockProps}> <div className="accordion-heading"> <RichText.Content tagName="div" className="accordion-title" value={ title } /> <div class="switcher-up-down"> <div class="horizontal"></div> <div class="vertical"></div> </div> </div> <div className='accordion-content'> <InnerBlocks.Content /> </div> </div> ) }; |
Тут все проще - мы просто добавляем в обертке из <div className='accordion-content'>
компонент, выводящий контент внутренних блоков в виде строки <InnerBlocks.Content />
.
Стили для блока panel
В основном стили мы опишем в файле style.scss, который управляет стилями и на сайте, и в админке. Все стили мы пишем в файлах, размещенных в корне папки src, т.к. он управляет сразу всеми элементами в разных блоках.
Код в файле style.scss
Мы будем использовать здесь переменные для того, чтобы при добавлении опций для управления цветом или паддингами можно было изменять эти переменные.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | /** * The following styles get applied both on the front of your site * and in the editor. * * Replace them with your own styles or remove the file completely. */ :root { --tempo-accordion-font-color: #222; --tempo-accordion-title-color: #222; --tempo-accordion-title-bgcolor: transparent; --tempo-accordion-font-size: 1rem; --tempo-accordion-title-font-size: 1.1rem; --tempo-accordion-panel-background-color: transparent; --tempo-accordion-panel-border: 1px solid #e7e7e7; --tempo-accordion-panel-border-radius: 0; --tempo-accordion-panel-padding: 15px 15px 15px 15px; --tempo-accordion-title-padding: 15px 15px 15px 15px; --tempo-accordion-content-padding: 0 15px 0 15px; --tempo-main-padding: 15px; --tempo-accordion-panel-spacing: 15px; } .wp-block-tempo-accordion-block { padding: 15px 0; border: var(--tempo--accordion-panel-border); border-radius: var(--tempo--accordion-panel-border-radius); margin: 0 !important; .accordion { &-item { border: var(--tempo-accordion-panel-border); margin-bottom: var(--tempo-accordion-panel-spacing); &.open { .accordion { &-heading { border-bottom: var(--tempo-accordion-panel-border); padding-bottom: var(--tempo-main-padding); .switcher-up-down { .vertical { transform: rotate(45deg); } .horizontal { transform: rotate(-45deg); } } } &-content { opacity: 1; max-height: 100rem; } } } } &-heading { display: flex; justify-content: space-between; align-items: center; background-color: var(--tempo-accordion-title-bgcolor); padding: var(--tempo-accordion-title-padding); cursor: pointer; .switcher-up-down { display: inline-block; height: 1.1rem; margin-left: auto; position: relative; top: 50%; transform: translateY(-50%); width: 1.1rem; .vertical, .horizontal { background-color: var(--tempo-accordion-title-color); bottom: 0; display: inline-block; position: absolute; width: .66rem; height: .1rem; transition: all .2s ease; } .vertical { right: 0; transform: rotate(-45deg); } .horizontal { left: 0; transform: rotate(45deg); } } } &-title { color: var(--tempo-accordion-title-color); font-size: var(--tempo-accordion-title-font-size); font-weight: bold; } &-content { font-size: var(--tempo-accordion-font-size); color: var(--tempo-accordion-font-color); background-color: var(--tempo-accordion-panel-background-color); max-height: 0; overflow: hidden; padding: var(--tempo-accordion-content-padding); opacity: 0; transition: opacity .2s linear, max-height .2s linear; will-change: opacity, max-height; } } } |
Код в файле editor.scss
Здесь мы опишем всего 1 стиль, который нужен для админки.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /** * The following styles get applied inside the editor only. * * Replace them with your own styles or remove the file completely. */ .wp-block-tempo-accordion-block { border: 1px dotted #f00; .accordion{ &-heading { .rich-text { font-weight: bold; } } } } |
Основной блок
Теперь нам нужно изменить код основного блока, добавив в него примерно те же атрибуты для InnerBlocks, как в блоке panel.
Код файла index.js
Тут изменений очень мало - просто добавим импорт блока из папки panel во второй строке:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import './style.scss'; import './panel'; import Edit from './edit'; import save from './save'; import metadata from './block.json'; registerBlockType( metadata.name, { attributes: { heading: { type: 'string', source: 'html', selector: 'h2', } }, edit: Edit, save, } ); |
Код файла edit.js
Опять нужно импортировать компонент InnerBlocks, использовать RichText для заголовка и описать в InnerBlocks
атрибуты allowedBlocks
и template
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import { __ } from '@wordpress/i18n'; import { InnerBlocks, useBlockProps, RichText } from '@wordpress/block-editor'; import './editor.scss'; export default function Edit({ attributes, setAttributes }) { const blockProps = useBlockProps(); const {heading} = attributes; return ( <div {...blockProps}> <RichText tagName='h2' allowedFormats={ [ 'core/bold', 'core/italic' ] } value={heading} onChange={(newVal) => setAttributes({heading: newVal})} placeholder="Title for Accordion Section" /> <InnerBlocks allowedBlocks={ ['tempo/panel'] } template={[ [ 'tempo/panel', {title: __("Accordion Item Title 1", 'accordion-block') } ], [ 'tempo/panel', {title: __("Accordion Item Title 2", 'accordion-block') } ] ]} /> </div> ); } |
Здесь мы разрешаем добавлять в наш основной блок только блоки panel, а в качестве шаблона задаем 2 таких блока с настройками в виде заголовка. Вот, как это будет выглядеть:
Левая часть этого скриншота - вид нашего блока в админке, а справа - на сайте, за который отвечает файл src/save.js.
Код файла save.js
Здесь мы импортируем InnerBlocks, проверяем, ввел ли пользователь-редактор поста заголовок для аккордеона - и только в этом случае его выводим. Также мы выводим контент внутренних блоков. И это все.
1 2 3 4 5 6 7 8 9 10 11 12 13 | import { RichText, InnerBlocks, useBlockProps } from '@wordpress/block-editor'; export default function save({ attributes }) { const blockProps = useBlockProps.save(); return ( <div {...blockProps}> { attributes.heading?.trim().length>0 && (<RichText.Content tagName="h2" value={ attributes.heading } />) } <InnerBlocks.Content /> </div> ) }; |
Как вы видите, большую часть работы берет на себя блок panel, однако все вместе собирается именно в основном блоке.
Но и это еще не все. Нам нужно открывать контент по клику на заголовке. И тут нужно будет написать код на обычном JavaScript.
Скрипты в файле view.js
В корне вашего проекта вы найдете файл view.js, в котором есть примерно такой контент:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | /** * Use this file for JavaScript code that you want to run in the front-end * on posts/pages that contain this block. * * When this file is defined as the value of the `viewScript` property * in `block.json` it will be enqueued on the front end of the site. * * Example: * * ```js * { * "viewScript": "file:./view.js" * } * ``` * * If you're not making any changes to this file because your project doesn't need any * JavaScript running in the front-end, then you should delete this file and remove * the `viewScript` property from `block.json`. * * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#view-script */ /* eslint-disable no-console */ console.log("Hello World! (from create-block-accordion-block block)"); /* eslint-enable no-console */ |
Именно этот файл позволяет написать нативный JavaScript-код (т.е. классический JS, а не в стилистике React), который будет управлять вашим блоком на тех страницах, на которые его добавили.
В нем разместим такой код (комментарии можно убрать):
1 2 3 4 5 6 | document.addEventListener("DOMContentLoaded",(()=> { let upDown = document.querySelectorAll('.wp-block-tempo-panel .accordion-heading'); upDown.forEach(item => item.addEventListener('click', function(){ this.closest('.accordion-item').classList.toggle('open') })); }) ) |
Тут идет обработка события onclick по заголовку с классом .accordion-heading
.
Результат с заполненным контентом:
Как вы можете видеть, в контенте аккордеона можно использовать и выделение жирным, и курсивом, и другим цветом, вставлять фото и управлять цветом абзаца.
Найти все файлы из статьи вы можете на Github. Как добавить цветовые настройки к блоку, читайте в отдельной статье.