Остановить WordPress от оборачивания изображений в тег "P"

17 янв. 2011 г., 06:08:51
Просмотры: 34.3K
Голосов: 39

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

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

Это происходит при загрузке изображения и вставке его в WYSIWYG редактор. Ручной переход в режим просмотра кода и удаление тегов p не является вариантом, так как клиент не обладает достаточными техническими навыками.

Я понимаю, что изображения являются встроенными элементами, но по моей кодировке сайта изображения находятся внутри div'ов и установлены как блочные элементы, поэтому код валидный.

1
Комментарии
Все ответы на вопрос 11
11
41

Вот что мы сделали вчера на сайте клиента, где у нас была точно такая же проблема... Я быстро создал фильтр в виде плагина и активировал его.

<?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);
2 февр. 2011 г. 14:26:35
Комментарии

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

Dwayne Charrington Dwayne Charrington
3 февр. 2011 г. 05:25:38

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

jamesc jamesc
4 февр. 2011 г. 19:29:20

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

Geoffrey Burdett Geoffrey Burdett
29 авг. 2014 г. 16:19:28

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

Bram Vanroy Bram Vanroy
10 мар. 2015 г. 21:41:31

Кто-нибудь смог заставить это работать для <img ...> без />?

Runnick Runnick
17 дек. 2017 г. 15:41:26

Кстати, это, похоже, не работает с Гутенбергом.

jarrodwhitley jarrodwhitley
14 мар. 2019 г. 17:06:43

Это не работает, если внутри абзаца есть текст.

Justin Putney Justin Putney
1 мая 2021 г. 01:23:57

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

Justin Putney Justin Putney
1 мая 2021 г. 02:30:19

Работает отлично... Спасибо

Dushan Dushan
24 нояб. 2021 г. 17:57:53

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

Robert Andrews Robert Andrews
31 мар. 2022 г. 15:19:49

@RobertAndrews Боюсь, не имею понятия - не работал с WordPress уже почти 10 лет.

jamesc jamesc
1 апр. 2022 г. 13:42:40
Показать остальные 6 комментариев
2
13

По сути, вам нужно заставить WordPress рассматривать img как блочный элемент для целей форматирования. Такие элементы жёстко зашиты в wpautop(), и, к сожалению, этот список не фильтруется.

Что я бы сделал:

  1. Создал форк функции wpautop() под другим именем.
  2. Добавил img в регулярное выражение в переменной $allblocks.
  3. Удалил wpautop из фильтра the_content.
  4. Добавил свою версию функции в фильтр the_content.
  5. Возможно, придётся поиграть с приоритетом и, возможно, удалить и заново добавить другие фильтры, если что-то сломается из-за изменения порядка обработки.
17 янв. 2011 г. 10:33:24
Комментарии

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

Dwayne Charrington Dwayne Charrington
17 янв. 2011 г. 12:51:15

Сначала работало хорошо, но затем я столкнулся со сценарием, когда изображение находится внутри тега якоря, и оба уже внутри абзаца (т.е. p > img > a). Когда img обрабатывается как блок, wp-autop закрывает тег абзаца перед началом тега img, что ломает вёрстку.

benz001 benz001
19 июл. 2014 г. 05:53:38
1

возможно, это поможет

remove_filter('the_content', 'wpautop')

Но тогда вам придется добавлять абзацы для всего остального вручную.

17 янв. 2011 г. 09:54:43
Комментарии

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

Dwayne Charrington Dwayne Charrington
17 янв. 2011 г. 12:49:47
0

Этот пост немного устарел, но есть гораздо более простое решение, если не использовать CSS на вашей стороне.

Обертывание тега img в div имеет минимальный негативный эффект.

19 авг. 2011 г. 21:48:51
2

Соска предложил один/простой способ.

Но я делаю по-другому - извлекаю изображение из контента и отображаю его отдельно.

17 янв. 2011 г. 11:46:33
Комментарии

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

Dwayne Charrington Dwayne Charrington
17 янв. 2011 г. 12:52:12

также вы можете добавить произвольное поле к записи/странице, например, thumb image, и сохранить путь к изображению в его значении...

Avinash Avinash
17 янв. 2011 г. 13:09:48
1

Я разработал плагин, который решает именно эту проблему: http://wordpress.org/extend/plugins/unwrap-images/

Это лучше, чем устанавливать отступы или лезть прямо в код WordPress для тех, кто не хочет возиться с кодом, потому что он использует нативную функцию jQuery unwrap для удаления тегов p вокруг всех изображений.

Надеюсь, это поможет кому-то! С уважением, Брайан

4 нояб. 2011 г. 10:18:42
Комментарии

похоже, всё ещё имеет 30+ активных установок :D

Julix Julix
6 мая 2019 г. 21:41:31
0

Принятый ответ помог мне только с изображениями, но переработанный код плохо обрабатывает связанные изображения на моем сайте. В этой статье блога есть код, который работает идеально.

Вот код:

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');

Удачи!

1 янв. 2012 г. 15:19:51
2

Я не эксперт, но потратил весь день, пытаясь решить проблему с обёрткой изображений в теги 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;, поэтому мне действительно нужно было вытащить изображения из них.

18 февр. 2013 г. 20:29:02
Комментарии

Ты действительно используешь фигурные кавычки? :)

fuxia fuxia
18 февр. 2013 г. 21:05:06

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

Dwayne Charrington Dwayne Charrington
20 февр. 2013 г. 01:29:26
0

Поместите ваше изображение внутрь тега <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>, и это решение помогло.

19 сент. 2020 г. 17:33:17
2

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

23 февр. 2011 г. 03:33:35
Комментарии

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

Dwayne Charrington Dwayne Charrington
23 февр. 2011 г. 03:59:05

Ага, поэтому я и сказал, что это зависит от поста.

Synetech Synetech
23 февр. 2011 г. 04:48:42
0

Если кто-то ищет быстрый и грязный способ исправить это для любого тега, вот что я сделал:

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

Вот и всё, счастливого Вордпрессинга!

12 авг. 2018 г. 01:04:00