Фильтр wptexturize в WordPress незаметно портит встроенный JavaScript, превращая логический оператор && в HTML-сущность &&, что ломает скрипты, работающие внутри шорткодов.
Проблема возникла у разработчика, который поддерживает набор шорткодов для калькуляторов. После недель безупречной работы кнопки отправки перестали реагировать. Ни предупреждений PHP, ни ошибок в консоли, а инспектированный HTML выглядел чистым — пока в отрендеренном исходном коде не обнаружилось if (!isNaN(bf) && bf > 0). Одна единственная синтаксическая ошибка помешала выполнению всего блока скрипта.
Почему этот фильтр важен
WordPress обрабатывает контент записей через серию фильтров, прежде чем он попадет в браузер. wptexturize — один из первых таких фильтров; он преобразует прямые кавычки в типографские «умные» кавычки, заменяет несколько дефисов на длинные тире и очищает амперсанды. Фильтр предполагает, что он работает с прозой, а не с кодом. Когда шорткод внедряет встроенный тег <script>, фильтр всё равно запускается, воспринимая JavaScript как обычный текст. Таким образом, амперсанд в && экранируется в &, что браузер интерпретирует как обычную строку, а не логический оператор AND.
Разработчики, которые встраивают любой JavaScript напрямую в контент записей — калькуляторы, валидаторы форм, интерактивные виджеты — уязвимы. Проблема не ограничивается калькуляторами; любой встроенный скрипт, использующий &&, & или подобные символы, может быть поврежден. Поскольку преобразование происходит на стороне сервера, браузер никогда не видит оригинальный код, и ошибка не проявляется как типичное исключение JavaScript.
Кто затронут и какие потери несет
- Владельцы сайтов: неработающий калькулятор или форма могут раздражать посетителей, увеличивать показатель отказов и подрывать доверие.
- Разработчики: часы, потраченные на поиск «призрачных» багов, которые не оставляют следов в логах или выводе консоли.
- Редакторы контента: могут непреднамеренно нарушить функциональность при редактировании страниц, содержащих шорткоды.
Цена вопроса — не только время; это может привести к потере конверсии, особенно на сайтах, которые полагаются на кастомные калькуляторы для расчета стоимости, оценки кредитов или оценки состояния здоровья.
Что именно делает этот фильтр (простыми словами)
- Обнаруживает прямые кавычки — заменяет
'и"на «умные» типографские версии. - Очищает амперсанды — преобразует
&в&, если он уже не является частью валидной HTML-сущности. - Применяется ко всей строке контента — включая всё, что находится внутри тегов
<script>, созданных шорткодами.
Когда фильтр встречает &&, он видит два амперсанда, которые не являются частью существующей HTML-сущности, поэтому экранирует каждый из них по отдельности, в результате чего получается &&.
Как предотвратить повреждение кода
1. Отключите фильтр для страниц, содержащих код
add_action( 'template_redirect', function () {
if ( is_page() ) {
remove_filter( 'the_content', 'wptexturize' );
remove_filter( 'widget_text_content', 'wptexturize' );
}
} );
Этот фрагмент кода отключает wptexturize только в шаблонах страниц, сохраняя типографские улучшения для записей и других типов контента. Он также удаляет фильтр из текстовых виджетов, которые могут быть вторичным источником встроенных скриптов.
2. Перепишите логику, чтобы избежать &&
Если удаление фильтра нежелательно, проведите рефакторинг JavaScript так, чтобы логический оператор AND не требовался:
// Original
if (a && b) { … }
// Refactored
var ok = a;
if (ok) { ok = b; }
if (ok) { … }
Хотя это добавляет несколько лишних строк, это устраняет амперсанд, который запускает фильтр. Этот подход работает для простых условий, но может стать громоздким для сложных выражений.
3. Вынесите все скрипты во внешние файлы
Самое надежное решение — использовать очередь (enqueue) JavaScript-файлов вместо встраивания кода напрямую:
wp_enqueue_script( 'my-calculator', get_template_directory_uri() . '/js/calculator.js', [], null, true );
Скрипты, добавленные через очередь, полностью обходят фильтры the_content. Они также получают преимущества кэширования браузером и могут быть минифицированы или объединены с другими ресурсами.
Как обнаружить проблему на практике
Если скрипт перестает работать без явных ошибок, просмотрите исходный код страницы (не через инспектор DOM) и выполните поиск по &. Если вы найдете его внутри блока <script>, значит, виноват фильтр. Проблема не отобразится в консоли, так как браузер не получает синтаксически корректного скрипта для парсинга.
Контраргумент: зачем оставлять wptexturize?
wptexturize улучшает читаемость на стороне пользователя. «Умные» кавычки и правильные тире придают тексту профессиональный вид, и многие владельцы сайтов считают это обязательным эстетическим требованием. Глобальное удаление фильтра вернет текст к его исходному, типографски простому состоянию.
Компромисс заключается в выборочном отключении: отключайте фильтр только там, где находится код, или используйте пользовательский шорткод, который явно помечает свой вывод как защищенный от текстуризации. WordPress уже предоставляет wp_kses_post и другие вспомогательные функции для очистки данных; разработчики могут комбинировать их с вызовами remove_filter, чтобы получить преимущества обоих подходов.
На что обратить внимание в дальнейшем
Ядро WordPress не объявляло об изменениях в wptexturize, которые бы автоматически исключали теги <script>. Пока такие изменения не будут внедрены, разработчики должны защищать свой встроенный код вручную. Следите за трекером разработки ядра на предмет предложений сделать фильтр контекстно-зависимым. Тем временем проверьте все шорткоды или элементы конструкторов страниц, которые внедряют JavaScript, и примените одно из трех вышеупомянутых решений.
Итог: если ваш сайт на WordPress использует встроенный JavaScript, убедитесь, что wptexturize незаметно его не перезаписывает. Один единственный экранированный амперсанд может вывести из строя целую функцию, а решение обычно заключается в нескольких строках PHP или переходе на внешние скрипты.
