Статьи

WordPress Gutenberg Block API: расширение блоков

Добро пожаловать в нашу серию о создании пользовательских блоков с помощью 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 из объекта isSelected и добавьте его в список констант внутри функции edit . Это полезно, поэтому мы можем ссылаться на него по сокращенному имени (т.е. isSelected а не props.isSelected ).

1
const { attributes: { category }, setAttributes, isSelected } = props;

Далее, мы можем использовать это свойство, чтобы определить, должен ли отображаться раскрывающийся элемент управления:

01
02
03
04
05
06
07
08
09
10
11
{ isSelected && (
    <form onSubmit={ setCategory }>
        <select value={ category } onChange={ setCategory }>
            <option value=»animals»>Animals</option>
            <option value=»arch»>Architecture</option>
            <option value=»nature»>Nature</option>
            <option value=»people»>People</option>
            <option value=»tech»>Tech</option>
        </select>
    </form>
) }

Это сокращенный способ проверки, что isSelected — true, поскольку мы не можем использовать полноценный JavaScript-оператор if внутри кода JSX.

Убедитесь, что вы все еще просматриваете файлы на предмет изменений, чтобы любой блочный исходный код (JSX, ES6 +, Sass и т. Д.) Транслировался в действительный JavaScript и CSS. Если вы не просматриваете файлы на предмет изменений, откройте окно командной строки в корневой папке плагина my-custom-block и введите npm start .

Откройте редактор Gutenberg и добавьте блок случайных изображений. На этот раз раскрывающийся элемент управления не отображается, если блок еще не был нажат.

Управление условным блоком

Это придает блоку более интерактивный вид.

Если вы использовали какой-либо из основных блоков Гутенберга (например, блок абзаца), то вы будете знакомы с настройками панели инструментов. Как только выбран блок «Абзац», появляется всплывающая панель инструментов, содержащая кнопки для форматирования текста. Этот тип элемента управления отлично подходит для настроек блока, которые имеют состояние типа «включено-выключено», например, для выравнивания текста или форматирования, такого как жирный или курсив.

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

Во-первых, нам нужно BlockControls компоненты AlignmentToolBar и BlockControls из wp.blocks . Это позволяет нам показывать элементы управления выравниванием внутри плавающей панели инструментов над нашим блоком, когда он выбран. Они являются частью основных компонентов, которые мы можем использовать в наших собственных блоках.

1
2
3
4
5
const {
    AlignmentToolbar,
    BlockControls,
    registerBlockType
} = wp.blocks;

Компонент BlockControls действует как контейнер панели инструментов, а AlignmentToolbar размещается внутри.

Нам все еще нужно вручную подключить поведение панели инструментов выравнивания, что мы можем сделать, добавив новый атрибут categoryAlign для хранения статуса выравнивания блоков (слева, справа или по центру).

Наш объект attributes теперь содержит две настройки.

01
02
03
04
05
06
07
08
09
10
attributes: {
    category: {
        type: ‘string’,
        default: ‘nature’
    },
    categoryAlign: {
        type: ‘string’
        default: »
    }
}

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

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

1
const { attributes: { category, categoryAlign }, setAttributes, isSelected } = props;

Все, что нам нужно сделать сейчас, это добавить два новых компонента в функцию edit и настроить свойства.

1
2
3
4
5
6
<BlockControls>
    <AlignmentToolbar
        value={ categoryAlign }
        onChange={ value => setAttributes( { categoryAlign: value } ) }
    />
</BlockControls>

Как вы можете видеть, все, что нам нужно было сделать, это присвоить атрибуту value Alignmenttoolbar атрибуту categoryAlign и вызывать функцию setAttributes при каждом нажатии новой кнопки панели инструментов. Эта функция в свою очередь обновляет атрибут categoryAlign и поддерживает синхронизацию всего.

Чтобы применить стиль выравнивания раскрывающегося элемента управления, нам нужно добавить свойство стиля к нашему элементу формы.

1
<form onSubmit={ setCategory } style={ {textAlign: categoryAlign} }>
Контроль выравнивания

Обратите внимание, что нам не нужно, чтобы этот элемент управления влиял на что-либо на внешнем интерфейсе, поэтому нам не нужно было добавлять какой-либо код в функцию save блока.

Панель инспектора блоков предоставляет большую область для добавления элементов управления блоком и является отличным местом для более сложных элементов управления.

Мы сосредоточимся на добавлении двух раскрывающихся элементов управления на панель инспектора. Первый из них будет дубликатом раскрывающегося списка категорий для выбора типа случайного изображения. Это демонстрирует, как иметь более одного элемента управления, обновляющего общий атрибут.

Когда один элемент управления обновляется, соответствующий тоже обновляется автоматически! На практике, однако, вы обычно хотите только один элемент управления на настройку.

Второй выпадающий элемент управления позволит вам выбрать фильтр, применяемый к случайному изображению. Веб-служба PlaceIMG поддерживает два типа фильтров — оттенки серого и сепия, и мы можем выбирать между ними, просто добавляя sepia или grayscale к URL-адресу HTTP-запроса. Если мы не укажем фильтр, будет возвращено стандартное цветное изображение.

Код для двух раскрывающихся списков очень похож, поэтому мы добавим их вместе.

Прежде всего, давайте определим новые блоки и компоненты, которые нам нужны.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
const {
    AlignmentToolbar,
    BlockControls,
    registerBlockType,
    InspectorControls
} = wp.blocks;
 
const {
    PanelBody,
    PanelRow
} = wp.components;
 
const {
    Fragment
} = wp.element;

Здесь новыми переменными являются InspectorControls , PanelBody , PanelRow и Fragment , которые используются для создания пользовательского интерфейса панели инспектора.

Компонент <Fragment> очень полезен, когда вам нужно вернуть несколько элементов верхнего уровня из функций edit или save но не хотите заключать их в элемент, который будет выводиться.

<Fragment> не выводит никакой разметки на интерфейс и действует как невидимый контейнер. Это просто удобный способ вернуть несколько элементов верхнего уровня и альтернатива предыдущему методу, вместо которого возвращается массив элементов.

Нам нужно добавить только один новый атрибут с именем imageFilter поскольку существующий атрибут category можно использовать повторно.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
attributes: {
    category: {
        type: ‘string’,
        default: ‘nature’
    },
    categoryAlign: {
        type: ‘string’,
        default: »
    },
    imageFilter: {
        type: ‘string’,
        default: »
    }
}

Внутри функции edit нам нужно добавить новую переменную со ссылками на новый атрибут.

1
const { attributes: { category, categoryAlign, imageFilter }, setAttributes, isSelected } = props;

Добавление панели инспектора блоков на удивление легко. Структура компонента, которую мы будем использовать, выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<InspectorControls>
    <PanelBody>
        <PanelRow>
            …
        </PanelRow>
        <PanelRow>
            …
        </PanelRow>
    </PanelBody>
    <PanelBody>
        <PanelRow>
            …
        </PanelRow>
        <PanelRow>
            …
        </PanelRow>
    </PanelBody>
</InspectorControls>

Компонент <InspectorControls> действует как контейнерный инспектор блоков, а <PanelBody> определяет отдельные складные секции. Внутри каждого из них вы можете иметь любое количество компонентов <PanelRow> , которые, в свою очередь, содержат ваши элементы управления.

Мы уже определили разметку для нашего элемента управления раскрывающимся списком категорий, который мы можем использовать повторно. Для этого абстрагируйте его в отдельную функцию:

01
02
03
04
05
06
07
08
09
10
11
12
13
function showForm() {
    return (
        <form onSubmit={ setCategory } style={ {textAlign: categoryAlign} }>
            <select id=»image-category» value={ category } onChange={ setCategory }>
                <option value=»animals»>Animals</option>
                <option value=»arch»>Architecture</option>
                <option value=»nature»>Nature</option>
                <option value=»people»>People</option>
                <option value=»tech»>Tech</option>
            </select>
        </form>
    );
}

Затем на эту функцию можно ссылаться всякий раз, когда нам нужно отобразить раскрывающийся элемент управления категорией. Разметка для панели инспектора блоков должна находиться за пределами разметки блока, поэтому мы можем использовать компонент <Fragment> чтобы обернуть их оба перед тем, как они будут возвращены.

Далее нам нужно добавить компоненты инспектора блоков для раскрывающихся списков категорий и фильтров изображений. Они должны быть определены внутри компонентов <PanelRow> , и мы также должны определить новую функцию обратного вызова для обработки события onChange . Это очень похоже на раскрывающийся код категории из предыдущего урока, поэтому он должен быть вам уже знаком.

Собрав все это вместе, функция return метода edit теперь выглядит так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
return (
    <Fragment>
        <InspectorControls>
            <PanelBody title={ __(‘Image Settings’) }>
                <PanelRow>
                    <label>Set Filter</label>
                    { showForm() }
                </PanelRow>
                <PanelRow>
                    <label>Set Filter</label>
                    <form onSubmit={ setFilter }>
                        <select id=»image-filter» value={ imageFilter } onChange={ setFilter }>
                            <option value=»»>None</option>
                            <option value=»sepia»>Sepia</option>
                            <option value=»grayscale»>Grayscale</option>
                        </select>
                    </form>
                </PanelRow>
            </PanelBody>
        </InspectorControls>
        <div className={ props.className }>
            <BlockControls>
                <AlignmentToolbar
                    value={ categoryAlign }
                    onChange={ value => setAttributes( { categoryAlign: value } ) }
                />
            </BlockControls>
            <RandomImage filter={ imageFilter } category={ category } />
            { isSelected && ( showForm() ) }
        </div>
    </Fragment>
);

И обратный вызов setFilter определяется как:

1
2
3
4
5
function setFilter( event ) {
    const selected = event.target.querySelector( ‘#image-filter option:checked’ );
    setAttributes( { imageFilter: selected.value } );
    event.preventDefault();
}

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

1
2
3
4
5
6
7
function RandomImage( { category, filter } ) {
    if(filter) {
        filter = ‘/’ + filter;
    }
    const src = ‘https://placeimg.com/320/220/’ + category + filter;
    return <img src={ src } alt={ category } />;
}

Обратите внимание, как мы используем это новое свойство компонента в методе edit чтобы отправить новое значение фильтра в PlaceIMG.

1
<RandomImage filter={ imageFilter } category={ category } />

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

Блок Инспектора Управления

Чтобы новое свойство фильтра работало и для внешнего интерфейса, нам просто нужно обновить метод save .

1
2
3
4
5
6
7
8
save: function( props ) {
    const { attributes: { category, imageFilter } } = props;
    return (
        <div>
            <RandomImage filter={ imageFilter } category={ category } />
        </div>
    );
}

Фильтр изображения внешнего интерфейса

В этом посте мы рассмотрели три различных способа добавления настроек в блок:

  • всплывающая панель инструментов
  • прямо на самом блоке
  • панель инспектора блока

Мы добавили только базовые настройки для каждого блока, но мы могли бы легко пойти еще дальше, добавив поддержку нескольких изображений, добавив подписи к изображениям и управляя стилями, такими как цвет рамки, радиус или произвольный размер изображения.

Я уверен, что к настоящему времени у вас, вероятно, есть идеи по созданию собственных блоков. Мне бы очень хотелось услышать, какие блоки вы найдете полезными в ваших собственных проектах!

Мы только начинаем с Гутенберга здесь, в Envato Tuts +, поэтому, если есть какие-то конкретные аспекты разработки блоков Гутенберга, которые вы хотели бы более подробно рассмотреть в будущих уроках, пожалуйста, сообщите нам об этом через комментарии.