Обновление редактирования/сохранения блока без изобретения колеса.

Вопрос или проблема

Кратко

Как я могу изменить результат edit и save основного блока, не переопределяя большую часть его функциональности в своем коде?

Вопрос

Я знаком с фильтрами блоков и уже могу использовать их для добавления атрибутов или новых InspectorControls. Тем не менее, меня беспокоит, что, похоже, я не могу обновить JSX/HTML редактирования/сохранения, не перезаписывая весь блок.

Представьте себе следующую ситуацию: я хочу добавить настройку в блок core/button, чтобы добавить иконку после текста. Поэтому конечный HTML не должен быть таким

<div class="wp-block-button">
    <a class="wp-block-button__link">Hello World</a>
</div>

а вместо этого желаемый результат будет

<div class="wp-block-button">
    <a class="wp-block-button__link">Hello World</a>
    <span class="wp-block-button__icon">X</span>
</div>

Для save я, вероятно, мог бы использовать wp.element.cloneElement, чтобы добавить свой элемент в качестве дополнительного дочернего.

Но что насчет edit? Мое текущее понимание заключается в том, что, пока блок не использует SlotFills, у меня действительно нет варианта.

В обычной конфигурации, как эта

const withInspectorControls = createHigherOrderComponent((BlockEdit) => {
  return (props) => {
    const { name, attributes, setAttributes } = props
    if (name !== 'core/button') {
      return <BlockEdit {...props} />
    }

    const { showIcon } = attributes

    return (
      <Fragment>
        <BlockEdit {...props} />
        <InspectorControls>
          <PanelBody title={__('Показать иконку?', 'my-plugin')}>
            <ToggleControl
              label={__('Показать иконку?', 'my-plugin')}
              checked={showIcon}
              onChange={(showIcon) => setAttributes({ showIcon })}
            />
          </PanelBody>
        </InspectorControls>
      </Fragment>
    )
  }
})

addFilter('editor.BlockEdit', 'my-plugin/add-icon-inspector', withInspectorControls)

Я мог бы убрать часть <BlockEdit {..props} /> и заново реализовать кнопку. Но глядя на исходный код редактирования, я знаю, что мне придется заново реализовать полный метод ButtonEdit, чего я хотел бы избежать.

Различные руководства, а также другие ответы на этом стеке подразумевают, что имеет смысл создать новый блок (и де-регистровать/занести в черный список основной), это все еще актуально на 2021 год?

Вы можете сделать это с помощью API форматов, например, этот код из справочника добавит тег <samp> вокруг текста:

import { registerFormatType, toggleFormat } from '@wordpress/rich-text';
import { RichTextToolbarButton } from '@wordpress/block-editor';

const MyCustomButton = ( props ) => {
    return <RichTextToolbarButton
        icon='editor-code'
        title="Пример вывода"
        onClick={ () => {
            props.onChange( toggleFormat(
                props.value,
                { type: 'my-custom-format/sample-output' }
            ) );
        } }
        isActive={ props.isActive }
    />;
};

registerFormatType(
    'my-custom-format/sample-output', {
        title: 'Пример вывода',
        tagName: 'samp',
        className: null,
        edit: MyCustomButton,
    }
);

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

https://github.com/WordPress/gutenberg/blob/master/packages/format-library/src/image/index.js

В частности, он импортирует insertObject:

                            insertObject( value, {
                                type: name,
                                attributes: {
                                    className: `wp-image-${ id }`,
                                    style: `width: ${ Math.min(
                                        imgWidth,
                                        150
                                    ) }px;`,
                                    url,
                                    alt,
                                },
                            } )

Где name — это имя формата, который был зарегистрирован. Результат — это встроенный тег <img>.

Ответ или решение

Обновление блока в редакторе Gutenberg: добавление функциональности без полной переимплементации

Введение

В редакторе Gutenberg система блоков обеспечивает мощное и гибкое средство для добавления контента на сайты WordPress. Однако, когда дело касается модификации существующих блоков, таких как core/button, разработчики могут столкнуться с проблемой: как внести изменения в функции редактирования и сохранения блока, не теряя при этом основные функции, реализованные в ядре. В этой статье мы рассмотрим способ добавления иконки к кнопке, используя существующую функциональность редактора и избегая полного дублирования кода.

Задача

Ваша цель — добавить иконку к блоку core/button, так чтобы при отображении HTML-кода блок выглядел следующим образом:

<div class="wp-block-button">
    <a class="wp-block-button__link">Hello World</a>
    <span class="wp-block-button__icon">X</span>
</div>

Использование Higher-Order Components

Для начала, вы можете создать Higher-Order Component (HOC), который добавит новые элементы управления к интерфейсу блока и изменит его визуальное представление.

Вот базовый пример такого HOC:

import { createHigherOrderComponent } from '@wordpress/compose';
import { Fragment } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { ToggleControl } from '@wordpress/components';
import { InspectorControls } from '@wordpress/block-editor';

const withIconControls = createHigherOrderComponent((BlockEdit) => {
  return (props) => {
    const { attributes, setAttributes } = props;
    const { showIcon } = attributes;

    return (
      <Fragment>
        <BlockEdit {...props} />
        <InspectorControls>
          <PanelBody title={__('Show Icon?', 'my-plugin')}>
            <ToggleControl
              label={__('Show Icon?', 'my-plugin')}
              checked={showIcon}
              onChange={(showIcon) => setAttributes({ showIcon })}
            />
          </PanelBody>
        </InspectorControls>
      </Fragment>
    );
  };
});

addFilter('editor.BlockEdit', 'my-plugin/add-icon-controls', withIconControls);

Модификация функции save

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

Пример того, как можно модифицировать функцию сохранения:

import { createElement } from '@wordpress/element';

const modifySave = (Element) => {
  return (props) => {
    const { attributes } = props;
    const { showIcon } = attributes;

    return (
      <div className="wp-block-button">
        <a className="wp-block-button__link">{ props.children }</a>
        { showIcon && <span className="wp-block-button__icon">X</span> }
      </div>
    );
  };
};

addFilter('blocks.saveCoreBlock', 'my-plugin/modify-button-save', modifySave);

Заключение

Путем использования Higher-Order Components и применения нужных фильтров, вы можете добавлять атрибуты и изменять визуальное представление существующих блоков в Gutenberg без необходимости полной переимплементации. Это позволяет сохранять производительность и упрощает сопровождение вашего кода.

Если вы решите создать новый блок вместо модификации существующего, это также приемлемый подход, однако, как показано в данной статье, использование HOC и фильтров часто является более эффективным методом, особенно при работе с популярными блоками, такими как core/button.

Итоги

  1. Используйте Higher-Order Components для добавления новых управляющих элементов.
  2. Измените структуру блока с помощью функции save, чтобы интегрировать ваше решение.
  3. Избегайте дублирования кода, использовав уже существующие механизмы Gutenberg.

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

Оцените материал
Добавить комментарий

Капча загружается...