WordPress Gutenberg Block API: Расширенные блоки
() translation by (you can also view the original English article)
Добро пожаловать в нашу серию о создании пользовательских блоков с помощью WordPress Gutenberg Block API. Этот урок посвящен расширению блока случайных изображений, который мы создали в предыдущем посте. Мы дошли до добавления выпадающего элемента управления, чтобы выбрать категорию изображения. Мы продолжим с этим, добавив дополнительные параметры блока, чтобы позволить дальнейшую настройку.
В частности, мы увидим, как добавить настройки блока в различных частях редактора. Правильно, вы не ограничены только добавлением элементов управления непосредственно в сам блок!
Окончательный код плагина my-custom-block доступен для скачивания. Просто нажмите на ссылку на боковой панели справа и загрузите zip-файл на свой компьютер и установите его так же, как и любой другой плагин WordPress. Вы также можете найти исходный код в нашем репозитории GitHub.
Развитие Гутенберга идет полным ходом, и с момента публикации последнего урока вышла новая значимая версия. Версия Gutenberg, используемая в этом руководстве, была обновлена до версии 3.0.1, и некоторые из интерфейсов редактора могут немного отличаться от снимков экрана, показанных в предыдущих руководствах этой серии.
Давайте расширяться!
Элемент раскрывающегося списка, который мы добавили в предыдущем уроке, находился внутри редактора, прямо под разметкой для случайного изображения. Это было удобно, но у нас есть и другие варианты.
Мы также можем добавить элементы управления блоком на всплывающую панель инструментов (которая появляется при выборе блока) и панель инспектора блоков.



На снимке экрана выше мы видим элементы управления панели инструментов для блока абзаца [1], а также связанные элементы управления в инспекторе панелей [3]. Местоположение [2] показывает раскрывающийся элемент управления для нашего блока случайных изображений.
Возможно, вы уже подумали о том, какое место вы бы выбрали для своих настроек блока, но вам не нужно выбирать только одно из этих мест. Они не являются взаимоисключающими. Например, для блока абзаца (показанного выше) вы можете видеть, что настройки разделены между панелью инспектора блоков и панелью инструментов.
Кроме того, вполне нормально иметь два отдельных элемента управления в разных местах в редакторе, которые влияют на тот же параметр. Возможно, вы не захотите делать это слишком часто, но полезно знать, как это реализовать, поэтому мы посмотрим, как это сделать чуть позже.
Настройки блока
Давайте начнем с самого простого способа добавить функциональность в ваш блок, который находится непосредственно внутри edit
функции блока. Мы уже использовали этот подход, чтобы добавить наш элемент управления выпадающим списком случайных изображений, потому что он требует совсем немного дополнительных усилий.
Мы не будем вдаваться в добавление новых элементов управления в сам блок, но мы можем настроить поведение выпадающего элемента управления, чтобы оно стало немного более интуитивным. Чтобы сделать его максимально близким к внешнему интерфейсу, мы можем ограничить раскрывающийся список, если только блок не выбран.
Давайте сделаем это изменение сейчас. Если вы читаете этот урок в продолжение прошлого урока, откройте /my-custom-block/src/random-image/index.js в вашем любимом редакторе. Это основной файл JavaScript для нашего блока случайных изображений.
Одно из свойств, передаваемых всем блокам, - это isSelected
, в котором хранится статус видимости блока. Мы можем использовать это для условного отображения раскрывающегося списка категорий.
Во-первых, вытащите isSelected
из объекта props
и добавьте его в список констант внутри функции edit
. Это полезно, так что мы можем ссылаться на него по сокращенному имени (то есть isSelected
, а не props.isSelected
).
1 |
const { attributes: { category }, setAttributes, isSelected } = props; |
Далее, мы можем использовать это свойство, чтобы определить, должен ли отображаться раскрывающийся элемент управления:
1 |
{ isSelected && ( |
2 |
<form onSubmit={ setCategory }> |
3 |
<select value={ category } onChange={ setCategory }> |
4 |
<option value="animals">Animals</option> |
5 |
<option value="arch">Architecture</option> |
6 |
<option value="nature">Nature</option> |
7 |
<option value="people">People</option> |
8 |
<option value="tech">Tech</option> |
9 |
</select> |
10 |
</form> |
11 |
) } |
Это сокращенный способ проверки, что isSelected
- true, поскольку мы не можем использовать полноценный JavaScript-оператор if
внутри кода JSX.
Убедитесь, что вы по-прежнему просматриваете файлы на предмет изменений, чтобы любой исходный код блока (JSX, ES6+, Sass и т.д.) транслировался в действительный JavaScript и CSS. Если вы не просматриваете файлы на предмет изменений, откройте окно командной строки в корневой папке плагина my-custom-block и введите npm start
.
Откройте редактор Gutenberg и добавьте блок случайных изображений. На этот раз раскрывающийся элемент управления не отображается, если блок еще не был нажат.



Это дает блоку гораздо более интерактивный вид.
Элементы управления панели инструментов
Если вы использовали какой-либо из основных блоков Гутенберга (например, блок параграфа), то вы будете знакомы с настройками панели инструментов. Как только блок «Параграф» выбран, появляется всплывающая панель инструментов, содержащая кнопки для форматирования текста. Этот тип элемента управления отлично подходит для настроек блока, которые имеют состояние типа «включено-выключено», например, для выравнивания текста или форматирования, такого как жирный или курсив.
Мы будем использовать встроенный элемент управления панели выравнивания, чтобы раскрывающийся элемент управления категориями изображений можно было выравнивать по левому краю (по умолчанию), вправо или по центру.
Во-первых, нам нужно извлечь компоненты AlignmentToolBar
и BlockControls
из wp.blocks
. Это позволяет нам показывать элементы управления выравниванием внутри плавающей панели инструментов над нашим блоком, когда он выбран. Они являются частью основных компонентов, которые мы можем использовать в наших собственных блоках.
1 |
const { |
2 |
AlignmentToolbar, |
3 |
BlockControls, |
4 |
registerBlockType
|
5 |
} = wp.blocks; |
Компонент BlockControls
действует как контейнер панели инструментов, а AlignmentToolbar
размещается внутри.
Нам все еще нужно вручную подключить поведение панели инструментов выравнивания, что можно сделать, добавив новый атрибут categoryAlign
для хранения статуса выравнивания блоков (слева, справа или по центру).
Наш объект attributes
теперь содержит две настройки.
1 |
attributes: { |
2 |
category: { |
3 |
type: 'string', |
4 |
default: 'nature' |
5 |
},
|
6 |
categoryAlign: { |
7 |
type: 'string' |
8 |
default: '' |
9 |
}
|
10 |
}
|
По умолчанию для атрибута categoryAlign
используется пустая строка, в результате чего выравнивание по умолчанию не применяется.
Чтобы сослаться на новый атрибут, мы можем извлечь это значение в его собственную постоянную переменную так же, как мы делали это для раскрывающегося списка атрибута category
.
1 |
const { attributes: { category, categoryAlign }, setAttributes, isSelected } = props; |
Все, что нам нужно сделать сейчас, это добавить два новых компонента в функцию edit
и настроить свойства.
1 |
<BlockControls> |
2 |
<AlignmentToolbar |
3 |
value={ categoryAlign } |
4 |
onChange={ value => setAttributes( { categoryAlign: value } ) } |
5 |
/> |
6 |
</BlockControls> |
Как вы можете видеть, все, что нам нужно было сделать - это присвоить значение value
компонента Alignmenttoolbar
атрибуту categoryAlign
и вызывать функцию setAttributes
при каждом нажатии новой кнопки панели инструментов. Эта функция в свою очередь обновляет атрибут categoryAlign
и поддерживает синхронизацию всего.
Чтобы применить стиль выравнивания раскрывающегося элемента управления, нам нужно добавить свойство стиля к нашему элементу формы.
1 |
<form onSubmit={ setCategory } style={ {textAlign: categoryAlign} }> |



Обратите внимание, что нам не нужно, чтобы этот элемент управления влиял на что-либо на внешнем интерфейсе, поэтому нам не нужно было добавлять какой-либо код в функцию сохранения блока save
.
Добавление панели настроек
Панель инспектора блоков предоставляет большую область для добавления элементов управления блоком и является отличным местом для более сложных элементов управления.
Мы сосредоточимся на добавлении двух раскрывающихся элементов управления на панель инспектора. Первый из них будет дубликатом раскрывающегося списка категорий для выбора типа случайного изображения. Это демонстрирует, как иметь более одного элемента управления, обновляющего общий атрибут.
Когда один элемент управления обновляется, соответствующий тоже обновляется автоматически! На практике, однако, вам обычно нужен только один элемент управления на настройку.
Второй выпадающий элемент управления позволит вам выбрать фильтр, примененный к случайному изображению. Веб-служба PlaceIMG поддерживает два типа фильтров - оттенки серого и сепия, и мы можем выбирать между ними, просто добавляя sepia
или grayscale
к URL-адресу HTTP-запроса. Если мы не укажем фильтр, будет возвращено стандартное цветное изображение.
Код для двух раскрывающихся списков очень похож, поэтому мы добавим их вместе.
Прежде всего, давайте определим новые блоки и компоненты, которые нам нужны.
1 |
const { |
2 |
AlignmentToolbar, |
3 |
BlockControls, |
4 |
registerBlockType, |
5 |
InspectorControls
|
6 |
} = wp.blocks; |
7 |
|
8 |
const { |
9 |
PanelBody, |
10 |
PanelRow
|
11 |
} = wp.components; |
12 |
|
13 |
const { |
14 |
Fragment
|
15 |
} = wp.element; |
Здесь новыми переменными являются элементы InspectorControls
, PanelBody
, PanelRow
и Fragment
, которые используются для создания пользовательского интерфейса панели инспектора.
Компонент <Fragment>
очень полезен, когда вам нужно вернуть несколько элементов верхнего уровня из функций edit
или save
, но не хотите заключать их в элемент, который будет выводиться.
<Fragment>
не выводит никакой разметки на интерфейс и действует как невидимый контейнер. Это просто удобный способ вернуть несколько элементов верхнего уровня и альтернатива предыдущему методу, вместо которого возвращается массив элементов.
Нам нужно только добавить один новый атрибут с именем imageFilter
, так как существующий атрибут category
можно использовать повторно.
1 |
attributes: { |
2 |
category: { |
3 |
type: 'string', |
4 |
default: 'nature' |
5 |
},
|
6 |
categoryAlign: { |
7 |
type: 'string', |
8 |
default: '' |
9 |
},
|
10 |
imageFilter: { |
11 |
type: 'string', |
12 |
default: '' |
13 |
}
|
14 |
}
|
Внутри функции edit
нам нужно добавить новую переменную со ссылками на новый атрибут.
1 |
const { attributes: { category, categoryAlign, imageFilter }, setAttributes, isSelected } = props; |
Добавление панели инспектора блоков на удивление легко. Структура компонента, которую мы будем использовать, выглядит следующим образом:
1 |
<InspectorControls> |
2 |
<PanelBody> |
3 |
<PanelRow> |
4 |
...
|
5 |
</PanelRow> |
6 |
<PanelRow> |
7 |
...
|
8 |
</PanelRow> |
9 |
</PanelBody> |
10 |
<PanelBody> |
11 |
<PanelRow> |
12 |
...
|
13 |
</PanelRow> |
14 |
<PanelRow> |
15 |
...
|
16 |
</PanelRow> |
17 |
</PanelBody> |
18 |
</InspectorControls> |
Компонент <InspectorControls>
действует как контейнер инспектора блоков, а <PanelBody>
определяет отдельные секции. Внутри каждого из них вы можете иметь любое количество компонентов <PanelRow>
, которые, в свою очередь, содержат ваши элементы управления.
Мы уже определили разметку для элемента управления раскрывающимся списком категорий, который мы можем использовать повторно. Чтобы сделать это, выделите его в отдельную функцию:
1 |
function showForm() { |
2 |
return ( |
3 |
<form onSubmit={ setCategory } style={ {textAlign: categoryAlign} }> |
4 |
<select id="image-category" value={ category } onChange={ setCategory }> |
5 |
<option value="animals">Animals</option> |
6 |
<option value="arch">Architecture</option> |
7 |
<option value="nature">Nature</option> |
8 |
<option value="people">People</option> |
9 |
<option value="tech">Tech</option> |
10 |
</select> |
11 |
</form> |
12 |
);
|
13 |
}
|
Затем на эту функцию можно ссылаться всякий раз, когда нам нужно отобразить раскрывающийся элемент управления категорией. Разметка для панели инспектора блоков должна находиться за пределами разметки блока, поэтому мы можем использовать компонент <Fragment>
, чтобы обернуть их оба перед тем, как они будут возвращены.
Далее нам нужно добавить компоненты инспектора блоков для раскрывающихся списков категорий и фильтров изображений. Они должны быть определены внутри компонентов <PanelRow>
, и мы также должны определить новую функцию обратного вызова для обработки события onChange
. Это очень похоже на раскрывающийся код категории из предыдущего урока, поэтому он должен быть вам уже знаком.
Собрав все это вместе, функция return
метода edit
теперь выглядит так:
1 |
return ( |
2 |
<Fragment> |
3 |
<InspectorControls> |
4 |
<PanelBody title={ __('Image Settings') }> |
5 |
<PanelRow> |
6 |
<label>Set Filter</label> |
7 |
{ showForm() } |
8 |
</PanelRow> |
9 |
<PanelRow> |
10 |
<label>Set Filter</label> |
11 |
<form onSubmit={ setFilter }> |
12 |
<select id="image-filter" value={ imageFilter } onChange={ setFilter }> |
13 |
<option value="">None</option> |
14 |
<option value="sepia">Sepia</option> |
15 |
<option value="grayscale">Grayscale</option> |
16 |
</select> |
17 |
</form> |
18 |
</PanelRow> |
19 |
</PanelBody> |
20 |
</InspectorControls> |
21 |
<div className={ props.className }> |
22 |
<BlockControls> |
23 |
<AlignmentToolbar |
24 |
value={ categoryAlign } |
25 |
onChange={ value => setAttributes( { categoryAlign: value } ) } |
26 |
/> |
27 |
</BlockControls> |
28 |
<RandomImage filter={ imageFilter } category={ category } /> |
29 |
{ isSelected && ( showForm() ) } |
30 |
</div> |
31 |
</Fragment> |
32 |
);
|
И функция обратного вызова setFilter
определяется как:
1 |
function setFilter( event ) { |
2 |
const selected = event.target.querySelector( '#image-filter option:checked' ); |
3 |
setAttributes( { imageFilter: selected.value } ); |
4 |
event.preventDefault(); |
5 |
}
|
Чтобы получить отфильтрованное изображение, нам нужно обновить компонент RandomImage
, чтобы он принимал новое значение фильтра каждый раз, когда раскрывающийся список изменяется.
1 |
function RandomImage( { category, filter } ) { |
2 |
if(filter) { |
3 |
filter = '/' + filter; |
4 |
}
|
5 |
const src = 'https://placeimg.com/320/220/' + category + filter; |
6 |
return <img src={ src } alt={ category } />; |
7 |
}
|
Обратите внимание, как мы используем это новое свойство компонента в методе edit
, чтобы отправить новое значение фильтра в PlaceIMG.
1 |
<RandomImage filter={ imageFilter } category={ category } /> |
Все эти изменения кода приводят к созданию новой панели инспектора блоков с двумя раскрывающимися элементами управления для изменения категории изображения и фильтра.



Чтобы новое свойство фильтра работало и для внешнего интерфейса, нам просто нужно обновить метод save
.
1 |
save: function( props ) { |
2 |
const { attributes: { category, imageFilter } } = props; |
3 |
return ( |
4 |
<div> |
5 |
<RandomImage filter={ imageFilter } category={ category } /> |
6 |
</div> |
7 |
);
|
8 |
}
|
Заключение
В этом посте мы рассмотрели три различных способа добавления настроек в блок:
- всплывающая панель инструментов
- прямо в сам блок
- панель инспектора блока
Мы добавили только базовые настройки для каждого блока, но мы могли бы легко продвинуться в этом еще дальше, добавив поддержку нескольких изображений, добавив подписи к изображениям и управляя стилями, такими как цвет границы, радиус или произвольный размер изображения.
Я уверен, что к настоящему времени у вас, вероятно, есть некоторые идеи для создания собственных пользовательских блоков. Мне бы очень хотелось услышать, какие блоки вы найдете полезными в ваших собственных проектах!
Мы только начинаем работу с Гутенбергом здесь, в Envato Tuts+, поэтому, если есть какие-то конкретные аспекты разработки блоков Гутенберга, которые вы хотели бы более подробно рассмотреть в будущих уроках, пожалуйста, сообщите нам об этом через комментарии.