Вопрос или проблема
Я только начинаю разрабатывать блоки для Gutenberg и создаю очень простую кнопку (да, я знаю, что кнопки уже включены, но этот блок будет иметь множество настроек и классов, которые не включены в основной блок).
Похоже, это довольно просто, но когда я сохраняю блок и перезагружаю, я получаю ошибку валидации и сообщение “Этот блок, похоже, был изменен извне”.
registerBlockType('franklin/button', {
title: 'Кнопка',
keywords: ['кнопка'],
icon: 'admin-links',
category: 'layout',
attributes: {
text: {
source: 'text',
selector: '.button-text'
},
},
edit({attributes, setAttributes }) {
return (
<div class="guttenberg-usa-button">
<button class="usa-button">
<PlainText
onChange={ content => setAttributes({ text: content }) }
value={ attributes.text }
placeholder="Текст вашей кнопки"
className="button-text"
/>
</button>
</div>
);
},
save({attributes}) {
return (
<button class="usa-button">
{ attributes.text }
</button>
);
}
});
Итак, в редакторе я добавлю свой блок, изменю текст (кнопки), сохраню и перезагружу, где получу сообщение “Этот блок, похоже, был изменен извне”.
Консоль показывает следующую ошибку
Ожидалось:
<button class="usa-button" class="wp-block-franklin-button"></button>
Фактически:
<button class="usa-button" class="wp-block-franklin-button">testest</button>
Я, вероятно, упускаю какой-то фундаментальный концепт или что-то еще, но я думал, что функция save() определяет, что отображается на фронте, который, кстати, выглядит так, как и ожидалось.
Вы получаете эту ошибку, потому что вывод функции редактирования и сохранения не совпадает.
save({attributes}) {
return (
<button class="usa-button">
{ attributes.text }
</button>
);
}
Точно, { attributes.text } функция save не вызывается и не используется в функции редактирования. Либо добавьте attributes.text в функцию редактирования, либо удалите это из функции сохранения. Что-то вроде этого должно сработать –
<button class="usa-button">
<PlainText
onChange={ content => setAttributes({ text: content }) }
value={ attributes.text }
placeholder="Текст вашей кнопки"
className="button-text"
/> { attributes.text }
</button>
Обратите внимание, что attributes.text также выводит тот же текст в функции редактирования, как и в функции сохранения.
Это происходит потому, что ваш атрибут использует HTML для получения своего значения, а селектор – .button-text
, но ничего, что соответствовало бы этому селектору, нет в сохраненном выводе.
save({attributes}) {
return (
<button class="usa-button">
{ attributes.text }
</button>
);
}
Обратите внимание, что button-text
нигде не находится, поэтому его значение пустое. Это противоречит компоненту редактирования, который действительно содержит такой класс.
Либо измените атрибут, чтобы не использовать HTML/текст в качестве источника, либо убедитесь, что селектор соответствует чему-то, что содержит текст в сохраненном выводе.
Ответ или решение
Вы столкнулись с ошибкой "Этот блок, кажется, был изменён внешне", потому что вывод в функции edit
и save
вашего блока не совпадает. Давайте разберёмся, как это исправить.
Во-первых, в вашей функции edit
вы используете компонент PlainText
для редактирования текста кнопки. При этом сохранённый блок не содержит элемента с классом .button-text
, который вы указали в атрибутах, а сохранённый результат состоит только из кнопки с текстом. Поэтому система считает, что блок изменён.
Ваш код может выглядеть следующим образом:
registerBlockType('franklin/button', {
title: 'Button',
keywords: ['button'],
icon: 'admin-links',
category: 'layout',
attributes: {
text: {
source: 'text',
selector: '.button-text'
},
},
edit({ attributes, setAttributes }) {
return (
<div className="guttenberg-usa-button">
<button className="usa-button">
<PlainText
onChange={content => setAttributes({ text: content })}
value={attributes.text}
placeholder="Ваш текст кнопки"
className="button-text"
/>
</button>
</div>
);
},
save({ attributes }) {
return (
<button className="usa-button">
{attributes.text}
</button>
);
}
});
Теперь, чтобы устранить ошибку, убедитесь, что структура возвращаемого HTML кода в edit
и save
соответствует друг другу. В частности, вам необходимо убедиться, что свойство text
в attributes
возвращается одинаковым образом как в функции edit
, так и в функции save
.
У вас есть два пути решения:
- Изменить функцию
save
, чтобы добавлять класс.button-text
, который вы использовали вedit
. Это даст возможность атрибутуtext
корректно обрабатываться так, как вы хотите:
save({ attributes }) {
return (
<button className="usa-button">
<span className="button-text">{attributes.text}</span>
</button>
);
}
- Изменить структуру
edit
, чтобы она соответствовалаsave
(идея в том, чтобы использоватьspan
или аналогичный элемент, но в контексте редактирования просто оставить вывод текста, как это сделано вsave
):
edit({ attributes, setAttributes }) {
return (
<div className="guttenberg-usa-button">
<button className="usa-button">
{attributes.text}
</button>
</div>
);
}
Важно, чтобы структура возвращаемого HTML в обеих функциях совпадала. Если вы используете .button-text
для извлечения текста, то в этом случае он должен существовать в выходном коде save
. Аналогично, если вы печатаете текст непосредственно, он также должен соответствовать тому, что вы сохраняете.
Таким образом, внедрив одно из предложенных решений, вы избавитесь от сообщения об ошибке "Этот блок, кажется, был изменён внешне", и всё будет работать корректно.