Остановить WordPress от оборачивания изображений в тег "P"
Я искал везде простое решение этой проблемы, но безуспешно. WordPress продолжает оборачивать мои изображения в теги p, и из-за специфической природы макета сайта, над которым я работаю, это очень раздражает.
Я создал решение на jQuery для разворачивания изображений, но оно не очень хорошее. Оно отстает из-за загрузки других элементов на странице, поэтому изменения происходят медленно. Есть ли способ предотвратить оборачивание WordPress только изображений в теги p? Возможно, какой-то хук или фильтр, который можно использовать.
Это происходит при загрузке изображения и вставке его в WYSIWYG редактор. Ручной переход в режим просмотра кода и удаление тегов p не является вариантом, так как клиент не обладает достаточными техническими навыками.
Я понимаю, что изображения являются встроенными элементами, но по моей кодировке сайта изображения находятся внутри div'ов и установлены как блочные элементы, поэтому код валидный.

Вот что мы сделали вчера на сайте клиента, где у нас была точно такая же проблема... Я быстро создал фильтр в виде плагина и активировал его.
<?php
/*
Plugin Name: Image P tag remover
Description: Плагин для удаления тегов p вокруг изображений в выводе контента, после того как фильтр autop в WordPress их добавил. (ирония)
Version: 1.0
Author: Fublo Ltd
Author URI: http://fublo.net/
*/
function filter_ptags_on_images($content)
{
// выполняем замену с помощью регулярного выражения...
// находим все теги p, которые содержат только
// <p>возможно пробелы<img весь код до /> затем возможно пробелы </p>
// заменяем их просто на тег изображения...
return preg_replace('/<p>(\s*)(<img .* \/>)(\s*)<\/p>/iU', '\2', $content);
}
// запускаем фильтр после обработки autop... приоритет 10 (по умолчанию).
add_filter('the_content', 'filter_ptags_on_images');
Если поместить этот код в PHP-файл в папку /wp-content/plugins и активировать, он должен удалять теги p из любого абзаца, который содержит только изображение.
Я не уверен, насколько надежно регулярное выражение — например, если тег img закрыт просто >, оно не сработает. Если у кого-то есть более надежное решение, буду признателен.
С уважением,
Джеймс
--- Улучшенный фильтр ---
Для работы с изображениями, обернутыми в ссылки, он сохраняет ссылки в выводе и удаляет теги p.
return preg_replace('/<p>\s*(<a .*>)?\s*(<img .* \/>)\s*(<\/a>)?\s*<\/p>/iU', '\1\2\3', $content);

Без сомнения, это правильный ответ. Спасибо, Джеймс, я попробовал, и это работает отлично.

Привет, @Dwayne - спасибо за отзыв. Я добавил улучшенный фильтр, который обрабатывает ссылки, и теперь мы используем его на сайте нашего клиента.

Вам определенно стоит добавить это в репозиторий плагинов WordPress. Быстрый поиск в Google показывает, что у многих людей есть эта проблема, но нет хорошего решения.

Обратите внимание, что это не будет работать с HTML5 разметкой по умолчанию для img
, то есть <img ...>
без закрывающего слэша. Лучше сделать этот слэш необязательным в вашем регулярном выражении. Или, что ещё лучше, можно вообще его опустить, так как .*
справится с этим.

Следующий код сработал для вынесения <img> из <p>, даже если после него идет текст:
return preg_replace('/<p>(\s*)(<img .*>)/iU', "$2<p>", $content);

@jamesc Как можно расширить это решение для работы с другими элементами, такими как <iframe>?

По сути, вам нужно заставить WordPress рассматривать img как блочный элемент для целей форматирования. Такие элементы жёстко зашиты в wpautop()
, и, к сожалению, этот список не фильтруется.
Что я бы сделал:
- Создал форк функции
wpautop()
под другим именем. - Добавил
img
в регулярное выражение в переменной$allblocks
. - Удалил
wpautop
из фильтраthe_content
. - Добавил свою версию функции в фильтр
the_content
. - Возможно, придётся поиграть с приоритетом и, возможно, удалить и заново добавить другие фильтры, если что-то сломается из-за изменения порядка обработки.

Я попробую этот подход. Никогда не думал о том, чтобы добавлять тег img в переменную allblocks, это гениальная идея. Посмотрим, как получится.

Я рассматривал этот подход, но, как я уже говорил, из-за нестандартной верстки здесь критически важны теги p. Я создаю двухколоночный текст, где p-теги выравниваются по левому краю, чтобы создать видимость двух колонок. Поэтому вы понимаете, почему обертывание изображения в p-тег создает проблему - оно тоже будет плавающим.

Я тоже рассматривал этот вариант, и он всё ещё возможен. Однако, поскольку это всего лишь одно изображение, чтобы избежать всех хлопот, я могу просто использовать миниатюры записей, что позволит мне контролировать отображение изображения.

Я разработал плагин, который решает именно эту проблему: http://wordpress.org/extend/plugins/unwrap-images/
Это лучше, чем устанавливать отступы или лезть прямо в код WordPress для тех, кто не хочет возиться с кодом, потому что он использует нативную функцию jQuery unwrap для удаления тегов p вокруг всех изображений.
Надеюсь, это поможет кому-то! С уважением, Брайан

Принятый ответ помог мне только с изображениями, но переработанный код плохо обрабатывает связанные изображения на моем сайте. В этой статье блога есть код, который работает идеально.
Вот код:
function wpautop_forked($pee, $br = 1) {
if ( trim($pee) === '' )
return '';
$pee = $pee . "\n"; // для удобства добавим перевод строки в конце
$pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
// Добавляем немного пространства
$allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li
|pre|select|option|form|map|area|blockquote|img|address|math|style|input
|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer
|nav|figure|figcaption|details|menu|summary)';
$pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee);
$pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
$pee = str_replace(array("\r\n", "\r"), "\n", $pee); // кросс-платформенные переводы строк
if ( strpos($pee, '<object') !== false ) {
$pee = preg_replace('|\s*<param([^>]*)>\s*|', "<param$1>", $pee); // не добавлять отступы внутри object/embed
$pee = preg_replace('|\s*</embed>\s*|', '</embed>', $pee);
}
$pee = preg_replace("/\n\n+/", "\n\n", $pee); // убираем дубликаты
// создаем параграфы, включая один в конце
$pees = preg_split('/\n\s*\n/', $pee, -1, PREG_SPLIT_NO_EMPTY);
$pee = '';
foreach ( $pees as $tinkle )
$pee .= '<p>' . trim($tinkle, "\n") . "</p>\n";
$pee = preg_replace('|<p>\s*</p>|', '', $pee); // в некоторых случаях может создать пустой P
$pee = preg_replace('!<p>([^<]+)</(div|address|form)>!', "<p>$1</p></$2>", $pee);
$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); // не добавлять P вокруг тегов
$pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // проблема с вложенными списками
$pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
$pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
$pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
if ($br) {
$pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', create_function('$matches', 'return str_replace("\n", "<WPPreserveNewline />", $matches[0]);'), $pee);
$pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); // опционально добавляем переносы строк
$pee = str_replace('<WPPreserveNewline />', "\n", $pee);
}
$pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
$pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
if (strpos($pee, '<pre') !== false)
$pee = preg_replace_callback('!(<pre[^>]*>)(.*?)</pre>!is', 'clean_pre', $pee );
$pee = preg_replace( "|\n</p>$|", '</p>', $pee );
return $pee;
}
remove_filter('the_content', 'wpautop');
add_filter('the_content', 'wpautop_forked');
Удачи!

Я не эксперт, но потратил весь день, пытаясь решить проблему с обёрткой изображений в теги p, и это сработало для меня.
Я работаю над темой на основе WordPress и просто добавил это в файл functions.js
Функция JQuery unwrap
> $(document).ready(function (){
>
> // для изображений, обёрнутых в теги a
>
> $(‘.entry a’).unwrap(‘p’);
>
> // для изображений, обёрнутых только в теги p
> $(‘.entry img’).unwrap(‘p’);
Теперь я могу работать с тегами p и img отдельно.
Также можно добавить div с другим классом вокруг изображения, используя это:
$(document).ready(function (){
$('.entry img').wrap('<div class="justImg"></div>');
Последний вариант не решил мою проблему, потому что я хотел сделать теги p с display:none;, поэтому мне действительно нужно было вытащить изображения из них.

Поместите ваше изображение внутрь тега <div>
без пробелов между ними. Вместо:
<div class="your_container">
<div class="element1">...</div>
<div class="element2">...</div>
<img src="image.jpg" />
</div>
Напишите так:
<div class="your_container">
<div class="element1">...</div>
<div class="element2">...</div>
<div><img src="image.jpg" /></div>
</div>
У меня была такая же проблема с элементами <a>
, и это решение помогло.

В зависимости от поста, другим решением может быть использование плагина WP Unformatted для отключения функции auto-p на уровне отдельных постов.

Это довольно полезно, хотя единственная оговорка, которую я вижу, заключается в том, что если вы хотите, чтобы изображения не имели тегов P, но при этом на странице был текст, это превратится в полный хаос. Вероятно, это подойдет для записей, которые содержат только изображения и, возможно, несколько строк текста. Тем не менее, полезно.

Если кто-то ищет быстрый и грязный способ исправить это для любого тега, вот что я сделал:
- перейдите в wp-content/formatting.php
- найдите функцию wpautop (если пропустили, это WP-AUTO-P, понятно?)
- найдите переменную "all blocks", должно быть что-то вроде
$allblocks = '(?:table|thead|tfoot|capti...
- в конце добавьте блок, который хотите исключить —
img
,a
и т.д. Например, если строка заканчивается на(...)menu|summary)';
, измените на(...)menu|summary|a)';
, чтобы добавить тегa
и избежать автоп-эффекта. Обратите внимание на разделитель|
— это синтаксис регулярных выражений!
Вот и всё, счастливого Вордпрессинга!
