Warning: preg_replace_callback(): Compilation failed: missing terminating ] for character class at offset 29 in /var/www/reclampa/data/www/reclampa.ru/wp-content/themes/reclampa2021/functions.php on line 467
Привет. Где-то пару недель назад я активно начал к объемным статьям составлять содержания (оглавления). После этого в мой адрес посыпалось куча вопросов в стиле: “Как это сделать?”. Решил ответить постом. Вот как выглядит содержание статьи:
Данное оглавление имеет массу плюсов:
- Посетитель сразу видит всю структуру статьи. Не устану повторять: главное в продвижении сайтов – это структура. Структура сайта, статьи и всего остального.
- Размещены ссылки. То есть можно кликнуть по интересующему пункту и осуществится автоматическое пролистывание вниз до выбранного пункта.
- Все это создается автоматически, за 2 секунды. Не нужно тратить время. Интересно? Еще бы. Читаем далее.
Необходимый код для составления содержания
Вручную создавать подобное содержание очень долгое занятие, ведь нужно:
- Понаставить “якори”.
- Вручную задать название каждому пункту.
- Подбирать правильные ссылки с якорями.
Из-за сложностей и неудобств, я не использовал данный метод. Только в исключительных случаях. Для реализации автоматического оглавления, мне помог код, который я взял на одном классном блоге WP-Kama (скорей всего вы слышали о нем). Вот и сама статья – “Содержание больших постов“.
В статье показаны разные возможности реализации, я покажу, как использовал все это для себя.
Сначала скопируйте этот код:
/** * Содержание для больших постов. * Автор: Тимур Камаев * Страница: http://wp-kama.ru/?p=1513 * Версия: 2.6 */ class Kama_Contents { var $margin; // отступ слева у подразделов в пикселях. 40 var $rep_tags; // теги по умолчанию по котором будет строиться содеражние. Порядок имеет значение. array('h2','h3','h4') var $to_menu; // ссылка на возврат к содержанию. '' - убрать ссылку var $title; // Заголовок. '' - убрать заголовок var $css; // css стили. '' - убрать стили var $min_found; // минимальное количество найденных тегов, чтобы содержание выводилось. var $temp; protected static $instance; function __construct( $args ){ // параметры по умолчанию $def = array( 'margin' => 40, 'rep_tags' => array('h2','h3','h4'), 'to_menu' => 'к содержанию ↑', 'title' => 'Содержание:', 'css' => '.kc_gotop{ display:block; text-align:right; } .kc_title{ font-style:normal;font-size:20px; padding:10px 0 10px; }', 'min_found' => 2, ); // установим свойства foreach( array_merge( $def, $args ) as $k => $v ) $this->$k = $v; } static function init( $args = array() ){ is_null( self::$instance ) AND self::$instance = new self( $args ); return self::$instance; } /** * Обрабатывает текст, превращает шоткод в нем в содержание. * @param (string) $content текст, в котором есть шоткод. * @return Обработанный текст с содержанием, если в нем есть шоткод. */ function shortcode( $content ){ // получаем данные о содержании if( ! preg_match('~^(.*)\[contents([^\\]]*)\](.*)$~s', $content, $m ) ) return $content; if( $tags = trim( $m[2] ) ) $tags = array_map('trim', explode(' ', $tags ) ); $contents = $this->make_contents( $m[3], $tags ); return $m[1] . $contents . $m[3]; } /** * Заменяет заголовки в переданном тексте (по ссылке), создает и возвращает содержание. * @param (string) $content текст на основе которого нужно создать содержание. * @param (array) $tags массив тегов, которые искать в переданном тексте. * @return html код содержания. */ function make_contents( $content, $tags = array() ){ // переменные $this->temp = new stdClass; $this->temp->i = 0; if( ! $tags ) $tags = $this->rep_tags; $this->temp->tag_level = array_flip( $tags ); // перевернем // заменяем все заголовки и собираем содержание в $this->temp->contents $h_patt = implode('|', $tags ); $_content = preg_replace_callback('@<('. $h_patt .')([^>]*)>(.*?)</(?:'. $h_patt .')>@is', array( $this, 'make_contents_callback'), $content, -1, $count ); if( ! $count || $count < $this->min_found ) return; $content = $_content; // опять работаем с важной $content // html содержания $contents = ''; if( $this->title ) $contents .= ' <div class='kc_title' id='kcmenu'>'. $this->title .'</div> '. '\n'; $contents .= ' <ul class='contents''. (!$this->title ? ' id='kcmenu'' : '') .'>'. '\n' . implode('', $this->temp->contents ) . '</ul> '.'\n'; $contents = ' <div class='contents-wrap'>'. $contents .'</div> '; $this->temp = new stdClass; // чистим static $css; $css = ( ! $css $this->css ) ? ' <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cstyle%3E'.%20%24this-%3Ecss%20.'%3C%2Fstyle%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="&lt;style&gt;" title="&lt;style&gt;" /> ' : ''; return $css . $contents; } ## callback функция для замены и сбора содержания protected function make_contents_callback( $match ){ $tag = $match[1]; $attrs = $match[2]; $txt = $match[3]; $anchor = $this->transl4url( $txt ); if( 0 < $level = $this->temp->tag_level[ $tag ] ) $sub = ( $this->margin ? ' style='margin-left:'. ($level*$this->margin) .'px;'' : '') . ' class='sub sub_'. $level .'''; else $sub = ' class='top''; // собираем содержание $this->temp->contents[] = '\t'. '<li'. $sub .'><a href='#'. $anchor .''>'. $txt .'</a></li> '. '\n'; // заменяем $out = ''; if( $this->to_menu ) $out .= $this->temp->i == 1 ? '' : '<a class='kc_gotop' href='#kcmenu'>'. $this->to_menu .'</a>'; $out .= '<a name=''. $anchor .''></a>'.'\n'.'<'. $tag . $attrs .'>'. $txt .'</'. $tag .'>;'; return $out; } ## транслитерация для УРЛ function transl4url( $str ){ $conv = array( 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' =>; 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'sch', 'ы' => 'y', 'э' => 'e', 'ю' => 'yu', 'я' => 'ya', 'А' => 'A', 'Б' => 'B', 'В' => 'V', 'Г' => 'G', 'Д' => 'D', 'Е' => 'E', 'Ё' => 'E', 'Ж' => 'Zh', 'З' => 'Z', 'И' => 'I', 'Й' => 'Y', 'К' => 'K', 'Л' => 'L', 'М' => 'M', 'Н' => 'N', 'О' => 'O', 'П' => 'P', 'Р' => 'R', 'С' =>'S', 'Т' => 'T', 'У' => 'U', 'Ф' => 'F', 'Х' => 'H', 'Ц' => 'C', 'Ч' => 'Ch', 'Ш' => 'Sh', 'Щ' => 'Sch', 'Ы' => 'Y', 'Э' => 'E', 'Ю' => 'Yu', 'Я' => 'Ya', ); $str = strtr( $str, $conv ); $str = strtolower( $str ); $str = preg_replace('~[^-a-z0-9_]+~u', '-', $str ); // все ненужное на '-' $str = trim( $str, '-'); // начальные и конечные '-' return $str; } } ## Обработка шоткода [contents] в тексте add_filter('the_content', 'kama_contents_shortcode'); function kama_contents_shortcode( $content ){ if( ! is_singular() ) return preg_replace('~\]*\]~', '', $content); // если не отдельная страница вырезаем выходим if( false === strpos( $content, '[content') ) return $content; // если нет шоткода выходим //$args['margin'] = 30; $args['to_menu'] = 'к оглавлению ↑'; $args['title'] = 'Оглавление:'; return Kama_Contents::init( $args )->shortcode( $content ); }
Откройте файл function.php, который располагается в папке вашего шаблона и вставьте этот код в конец файла:
Стили оглавления
Дальше скопируйте этот код:
.contents{ list-style-type:none; counter-reset:list; } /* цвет чисел */ .contents li:before{ color:#555; } /* уровень 0 */ .contents li.top{ counter-increment:list; counter-reset:list1; } .contents li.top:before{ content:counter(list) '. '; } /* уровень 1 */ .contents li.sub_1{ counter-increment:list1; counter-reset:list2; } .contents li.sub_1:before{ content:counter(list) '.' counter(list1) '. '; } /* уровень 2 */ .contents li.sub_2{ counter-increment:list2; } .contents li.sub_2:before{ content:counter(list) '.' counter(list1) '.' counter(list2) '. '; }
Откройте файл style.css Вашей темы и вставьте в его в конец файла:
Как использовать
Теперь просто в нужных местах во время написания статей используете заголовок 2 (h2) и заголовок 3 (h3) при необходимости:
Напомню, очень важно правильно использовать заголовки h1, h2, h3 в SEO. В итоге, прописанные заголовки h2 и h3 будут теми самими пунктами оглавления. Надеюсь, хоть это содержание заставит многих использовать заголовки в своих статьях, а то многие вообще игнорируют все это.
Уже потом выводим в нужном месте само меню. Как? Просто вставляем вот шорткод contents в редакторе статьи туда, где нужно вывести содержание.
Выглядит будет примерно так:
В результате получим то необходимое меню, в которым основные пункты – это использованные заголовки h2, а подпункты – заголовки h3:
Вывод
Вот так просто все это внедрить себе на блог. Спасибо Тимуру Камаеву за такой классный код. Если вы вдруг захотите добавить какие-то дополнительные “плюшки”, перейдите по ссылке, там есть интересные дополнения, которые могут кому-то пригодятся.
Я же очень хочу, чтобы вы использовали данный код хотя бы для того, чтобы Ваши статьи получались более структурированными и Вы “рвали” ТОП со своими классными статьями. Всего вам хорошего!
И спасибо за ретвит. 🙂
какие-то проблемы со временем в комментариях: получается, что на мое сообщение в 20:23 вы мне ответили в 20:12!
1. А вы не боитесь использовать чужой код? Или так хорошо разбираетесь в php, что сразу видите какие-нибудь “закладки”? Я не про данный код, а вообще.
2. Вы используете “дочернюю” тему WP или вообще “самописную”? Неплохо было бы упомянуть про влияние обновления тем на изменения в файлах function.php и style.css!
P.S. у автора уже версия 2.7.1 от 14.04.15
1. Честно, боюсь, поэтому беру только у проверенных авторов.
2. Самописная.
P.s. Да, плагин регулярно обновляется. Весь необходимый функционал есть и в этом коде этой версии. В обновлениях разные “плюшки”, которые рядовому пользователю практически не нужны.
Плагин? Не являюсь знатоком WP, как вы, но плагины, вроде бы, не в файле function.php должны быть, хотя функция add_filter намекает на сходство с плагинами 🙂
Ой, оговорился. Код. Не плагин.
Есть плагин с похожим функционалом, делает то же самое что и скрипт в статье, называется toc+
Делала содержание статьи вручную, довольно неудобно, с кодом, конечно проще. Петр, подскажите, как правильно ставить рекламные блоки РСЯ на сайт, каким инструментом или плагином пользоваться. Пробовала добавить в сайтбар через виджет, блок не отображается. Подскажите, если можно. И еще, у Вас не работает поиск по сайту, пыталась поискать информацию, не загружаются результаты.
Вставляйте сразу в файл темы – sidebar.php, single.php и прочее
Петр, спасибо, что объяснили! Как всегда, все доступно и понятно!
Рад был помочь )
Спасибо ВПкаме))
ВПкама, ВПнью, ахаххаха) Да, спасибо Тимуру.
А я всегда вручную делаю – прописываю якоря и т. д. Это поначалу кажется сложным, но, сделав так в нескольких статьях, потом получается быстрее и не так накладно.
Попробуйте через код и вы поймете насколько проще это все. 🙂
Кодом интересно было бы вставить. А структура, оглавление видел на некоторых сайтах с высокой посещаемости.
Где посты? Заболел что-ли ? Или творческий кризис?)
Весна… Хорошая погода… 🙂
Тоже этот код у Камаева видел, хотел поставить, но потом передумал – делаю руками.
Смущает то, что при смене шаблона нужно будет все коды вносить заново. Ручное содержание в этом случае никак не пострадает. Да и ручками можно более гибко все настроить.
1. Вы настолько часто меняете шаблон?
2. 1 раз сделать CTRL+C CTRL+V, по-моему проще, чем все меню вручную делать.
Ну это уже перебор, такой огород нагородил Тимур, почему не использовать ссылки-якори с тегами ul и li? Это намного проще, чем засорять код шаблона лишним мусором.
Не соглашусь с вами, что якори расставлять сложно и долго.
Тут делается упор на то, что ты установил плагин и можешь больше никогда не думать про оглавление. А якоря нужно каждый раз расставлять.. А если статья ну очень объемная? Ужас..
Код установил и сайт сломал, поэтому решил использовать вот этот плагин Table of Contents Plus, куча настроек и всё на автомате.
Ну видите, другие поставили и у них всё работает. Всё всегда работает, если руки из того места ростут 🙂
Скажу как частый читатель… С содержанием тема всегда смотрит более привлекательней, при чём даже подсознательно. Особенно удобно когда читаешь статью второй раз и нужно перейти на определённую её часть.
Да, я тоже заметил, что когда нужно вернуться к старым статьям, найти что-то конкретное, по меню (содержание) очень удобно ориентироваться.
Хрень! у меня весь код вылез в хедер.
Если вылез в шапку сайта, то значит что то упустили. Либо в вашем шаблоне немного код надо переделать.
Проверьте внимательно, все ли правильно сделали. Потому что у меня на нескольких сайтах все ок.
Оглавление – очень полезный инструмент для блога, особенно ддя авторов, которые публикуют относительно большой материал. Всё становится буквально по полочкам.
А вот чтобы не вставлять каждый раз {contents} в статью, можно эту команду как-то вставить в single.php ?
Петр, подскажи в чем может быть причина.
Копирую код, вставляю в файл functions.php сохраняю и код весь вылезает вверху админки.
Добрый день, нужно или нет добавлять к ссылкам содержания статьи тег rel=”nofollow”. Спасибо за ответ.
Нет, не надо.
подскажите, пожалуйста, как можно скрыть маркированный список? то есть, чтобы заголовки оглавления были помечены только нумерованным списком.
разобралась сама…добавила в стили: .contents li{ list-style-type:none;}. маркированный список теперь не выводится.
Наиогромнейшее спасибо! Писал обьемную статью, и вовремя нее задумался о том как долго и нудно будет составлять оглавления якорями. Но теперь то все иначе. Спасибо!
Давно искал подробную инструкцию. 😉 😉 😉
Спасибо большое 8)
Здравствуйте. Будьте добры, подскажите код, который позволял бы изменить цветовой фон оглавления с рамками вокруг него.
Спасибо!