Вопрос или проблема
Я пытаюсь добавить пользовательский контроль цвета в группы и блоки обложек, и если цвет выбран, создать пользовательский 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. В прошлом я также сталкивался с проблемами, которые вы описываете, и нашел два решения:
-
Если вы хотите вставить свой собственный компонент цвета, проверьте второй пример оттуда https://awhitepixel.com/blog/add-custom-settings-to-existing-wordpress-gutenberg-blocks/.
-
В противном случае вы можете просто добавить поддержку цвета в 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-класс не удаляется, что приводит к накоплению классов при последовательных изменениях цвета.
Это связано с тем, что текущая логика не очищает предыдущие классы в момент обновления состояния блока. Поэтому необходимо модифицировать ваш код для адекватного управления классами при каждом изменении.
Предложенное решение
- Очистка старых классов: Перед добавлением нового 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;
}
-
Проверка наличия других классов: Важно учитывать, что в
applyExtraClass
могут быть другие классы, добавленные пользователями через панель "Дополнительно". Ваша функция должна обеспечивать совместимость с этими классами, не удаляя их. -
Изменение цвета в редакторе: Добавление обработки в функции, которые отвечают за визуализацию в редакторе. Обновите
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!