Добавление пользовательского элемента управления PanelColorSettings в базовый блок и использование цветового слага в пользовательском className.

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

Я пытаюсь добавить пользовательский контроль цвета в группы и блоки обложек, и если цвет выбран, создать пользовательский className для блока. Этот пользовательский класс используется для разделителя секций.

Что я сделал:

  • Я отфильтровал blocks.registerBlockType и добавил пользовательский атрибут.
  • Я создал функцию для правильной фильтрации editor.BlockEdit и добавил контроль PanelColorSettings только в группы и блоки обложек.
  • Я отфильтровал blocks.getSaveContent.extraProps чтобы добавить пользовательский класс при сохранении.
  • Я отфильтровал editor.BlockListBlock, чтобы добавить этот же пользовательский класс в обернутый блок во время редактирования, так что я могу видеть изменения на лету.

Мне удалось заставить контроль появляться, и className сохраняется в блоке при правильном сохранении поста. На фронтенде это работает. И при первом редактировании это работает.

Чего не хватает:

Проблема, с которой я сейчас сталкиваюсь, заключается в том, что эти пользовательские classNames не заменяются, когда вы выбираете другой цвет в панели цвета и публикуете изменения. Если вы выберете 1 цвет, нажмете публикацию, обновите и выберете 2 цвет, опубликуете, обновите, блок будет иметь пользовательские классы для обоих цветов.

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

Что я думаю, что является проблемой:

Мне нужно, чтобы эти фильтры удаляли пользовательские классы, которые они применяли ранее? Или абстракция между “классы, введенные в расширенном окне пользователем” и “классы, добавленные в блок моим фильтром”. Ничто в документации не удовлетворяет этому.

Мой код (обновленный):

/**
 * Внешние зависимости
 */
import classnames from 'classnames';

/**
 * Зависимости WordPress
 */
const { __ } = wp.i18n;
const { addFilter } = wp.hooks;
const { Fragment } = wp.element;
const { createHigherOrderComponent } = wp.compose;
const { InspectorControls, getColorObjectByColorValue, PanelColorSettings } = wp.blockEditor;
const { select } = wp.data;

// Ограничение по конкретным именам блоков
const allowedBlocks = ['core/group', 'core/cover'];

/**
 * Добавить пользовательский атрибут для разделителя секции.
 *
 * @param {Object} settings Настройки для блока.
 *
 * @return {Object} settings Модифицированные настройки.
 */
function addAttributes(settings) {

    //проверка, существует ли объект для совместимости со старыми версиями Gutenberg
    //добавление ограничения по allowedBlocks
    if (typeof settings.attributes !== 'undefined' && allowedBlocks.includes(settings.name)) {

        settings.attributes = Object.assign(settings.attributes, {
            dividerColor: {
                type: 'string',
                default: null,
            }
        });

    }

    return settings;
}

/**
 * Добавить элементы управления разделителем секции на панель расширенных блоков.
 *
 * @param {function} BlockEdit Компонент редактирования блока.
 *
 * @return {function} BlockEdit Модифицированный компонент редактирования блока.
 */
const withAdvancedControls = createHigherOrderComponent((BlockEdit) => {
    return (props) => {

        if (!allowedBlocks.includes(props.name)) {
            return();
        }

        const {
            name,
            attributes,
            setAttributes,
            isSelected,
        } = props;

        const {
            dividerColor
        } = attributes;

        const changeColor = (value) => {
            setAttributes({ dividerColor: value });
            console.log(props);
        }

        return (
            
                
                {isSelected && allowedBlocks.includes(name) &&
                    
                        
                    
                }
            
        );
    };
}, 'withAdvancedControls');

/**
 * Добавить пользовательский элемент класса в сохраняемый элемент.
 *
 * @param {Object} extraProps     Элемент блока.
 * @param {Object} blockType      Объект блоков.
 * @param {Object} attributes     Атрибуты блоков.
 *
 * @return {Object} extraProps Измененный элемент блока.
 */
function applyExtraClass(extraProps, blockType, attributes) {

    const { dividerColor } = attributes;

    //проверка, существует ли атрибут для совместимости со старыми версиями Gutenberg
    //добавить класс только когда dividerColor не пустой
    //добавление ограничения по allowedBlocks
    if (typeof dividerColor !== 'undefined' && dividerColor && allowedBlocks.includes(blockType.name)) {
        const settings = select('core/editor').getEditorSettings();
        const colorObject = getColorObjectByColorValue(settings.colors, dividerColor);
        if (colorObject) {
            extraProps.className = classnames(extraProps.className, 'divider divider-' + colorObject.slug);
        }
    }

    return extraProps;
}

/**
 * Добавить класс размера в блок в редактор
 *
 * @param {Object} BlockListBlock  Объект BlockListBlock.
 *
 * @return {Object}                Измененный объект BlockListBlock.
 */
 const addDividerClass = createHigherOrderComponent((BlockListBlock) => {
    return (props) => {
      const {
        attributes,
        className,
        name,
      } = props;

      const { dividerColor } = attributes;

      if (!allowedBlocks.includes(name)) {
        return ;
      }

      const settings = select('core/editor').getEditorSettings();
      const colorObject = getColorObjectByColorValue(settings.colors, dividerColor);

      if (!colorObject) {
        return ;
      }

      return (
        
      );
    };
  }, 'addDividerClass');

//добавить фильтры

addFilter(
    'blocks.registerBlockType',
    'ursa6/custom-attributes',
    addAttributes
);

addFilter(
    'editor.BlockEdit',
    'ursa6/custom-advanced-control',
    withAdvancedControls
);

addFilter(
    'blocks.getSaveContent.extraProps',
    'ursa6/applyExtraClass',
    applyExtraClass
);

addFilter(
    'editor.BlockListBlock',
    'ursa6/addDividerClass',
    addDividerClass
 );

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

add_theme_support( 'editor-color-palette', array(
    array(
        'name' => __( 'Темный 1', 'textdomain' ),
        'slug' => 'dk1',
        'color' => '#282828',
    ),
    array(
        'name' => __( 'Светлый 1', 'textdomain' ),
        'slug' => 'lt1',
        'color' => '#FCFCF8',
    ),
    array(
        'name' => __( 'Средний', 'textdomain' ),
        'slug' => 'mid',
        'color' => '#F7F7F7',
    ),
    array(
        'name' => __( 'Акцент 1', 'textdomain' ),
        'slug' => 'accent1',
        'color' => '#E6A225',
    ),
    array(
        'name' => __( 'Акцент 2', 'textdomain' ),
        'slug' => 'accent2',
        'color' => '#048081',
    ),
    array(
        'name' => __( 'Акцент 3', 'textdomain' ),
        'slug' => 'accent3',
        'color' => '#882437',
    ),
  )
);

Может кто-то сказать, где я ошибся?

Ваш код выглядит нормально и будет работать в любом другом компоненте, кроме цветов, потому что для цветов нужен высший порядковый компонент withColors. В прошлом я также сталкивался с проблемами, которые вы описываете, и нашел два решения:

  1. Если вы хотите вставить свой собственный компонент цвета, проверьте второй пример оттуда https://awhitepixel.com/blog/add-custom-settings-to-existing-wordpress-gutenberg-blocks/.

  2. В противном случае вы можете просто добавить поддержку цвета в blocks.registerBlockType. Это то, что я сейчас использую, и это работает отлично:
    if( ['core/quote'].includes(name) ){ const supports = { ...props.supports, color: true, }; props = { ...props, supports }; }

Вот также ссылка https://css-tricks.com/a-crash-course-in-wordpress-block-filters/

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

Решение проблемы с добавлением пользовательских контроллеров цвета в блоки Gutenberg

В процессе разработки блока в Gutenberg для WordPress существует необходимость добавления пользовательского контроллера цвета и использования соответствующих классов CSS в зависимости от выбранного цвета. Давайте проанализируем вашу текущую ситуацию и предложим решение, чтобы обеспечить корректное поведение при изменении цвета.

Обзор проблемы

Вы добавили пользовательский контроллер цвета в блоки core/group и core/cover, и это работает на уровне редактирования и при сохранении. Однако, как вы заметили, проблема заключается в том, что при изменении цвета уже установленный CSS-класс не удаляется, что приводит к накоплению классов при последовательных изменениях цвета.

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

Предложенное решение

  1. Очистка старых классов: Перед добавлением нового CSS-класса, необходимо удалить старый класс. Для этого мы можем обновить функцию applyExtraClass, чтобы она не добавляла классы, если цвет не был установлен:
function applyExtraClass(extraProps, blockType, attributes) {
    const { dividerColor } = attributes;

    // Проверяем, задан ли цвет
    if (typeof dividerColor === 'undefined' || !dividerColor || !allowedBlocks.includes(blockType.name)) {
        // Если цвет не задан, возвращаем начальные свойства без класса
        return {
            ...extraProps,
            className: extraProps.className.replace(/divider-([a-z0-9-_]+)/, '') // Удаляем старый класс
        };
    }

    const settings = select('core/editor').getEditorSettings();
    const colorObject = getColorObjectByColorValue(settings.colors, dividerColor);

    if (colorObject) {
        extraProps.className = classnames(extraProps.className, 'divider divider-' + colorObject.slug);
    }

    return extraProps;
}
  1. Проверка наличия других классов: Важно учитывать, что в applyExtraClass могут быть другие классы, добавленные пользователями через панель "Дополнительно". Ваша функция должна обеспечивать совместимость с этими классами, не удаляя их.

  2. Изменение цвета в редакторе: Добавление обработки в функции, которые отвечают за визуализацию в редакторе. Обновите addDividerClass, чтобы он также очищал старые классы и добавлял новые:

const addDividerClass = createHigherOrderComponent((BlockListBlock) => {
    return (props) => {
        const { attributes, className, name } = props;
        const { dividerColor } = attributes;

        if (!allowedBlocks.includes(name)) {
            return <BlockListBlock {...props} />;
        }

        const settings = select('core/editor').getEditorSettings();
        const colorObject = getColorObjectByColorValue(settings.colors, dividerColor);

        const newClassNames = classnames(className, { 
            // Удаляем старые классы
            [`divider divider-${dividerColor}`]: colorObject !== undefined 
        });

        return <BlockListBlock {...props} className={newClassNames} />;
    };
}, 'addDividerClass');

Заключение

Эти изменения помогут гарантировать, что CSS-классы, связанные с выбранными цветами, будут обновляться корректно при каждом изменении. Убедитесь, что вы тестируете свои изменения как в редакторе, так и в окончательном выводе на фронтенде, чтобы гарантировать полное соответствие функциональности и стилям.

Если вопросы остаются, не стесняйтесь уточнять, и удачи вам в работе с Gutenberg!

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

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