Здравствуйте, уважаемые читатели. Сегодня поговорим о том как сделать содержание статьи на своем блоге.
Что такое содержание (оглавление) статьи и для чего оно используется?
Содержание или как его еще называют оглавление, не что иное, как структурированный список разделов статьи, который дает ясное понимание о чем статья и где, что искать. Вы спросите, а зачем это надо? Просто читай статью от начала до конца.
Я тоже задавался этим вопросом, когда начал посещать блоги и изучать интернет технологии. Часто бывают такие ситуации, когда поисковая система выдает статью не совсем соответствующую запросу. Вот в этом случае, достаточно первого взгляда на содержание, чтобы понять о чем статья и стоит ли ее читать.
При изучении объемных материалов, приходится часто возвращаться к уже прочитанным подразделам, таблицам и схемам. В этих случаях, оглавление статьи оказывает незаменимую помощь в ориентации по тексту и как вы понимаете, улучшает поведенческие факторы пользователей.
Поэтому в статьях объемом более 5000-6000 знаков, желательно делать разбивку по разделам и устанавливать блок с содержанием. Ну что, убедил? Это такая же нужная опция, как и “хлебные крошки”, постраничная навигация и другие. Совместно, все эти фишки, улучшают юзабилити сайта и способствуют продвижению в поисковой выдаче.
Простой способ создания содержания в статье.
Это простой способ создания оглавления. Для этого вам потребуется следующий код.
<strong>Из этой статьи вы узнаете:</strong> <a href="#a1"><li>Здесь первый пункт содержания</a><br> <a href="#a2"><li>Здесь второй пункт содержания</a><br> <a href="#a3"><li>Здесь третий пункт содержания</a><br>
<a2 id="a1">Сюда будет перебрасывать первая ссылка</a2> <a2 id="a2">Сюда будет перебрасывать вторая ссылка</a2> <a2 id="a3">Сюда будет перебрасывать третья ссылка</a2>
Давайте разберемся что здесь и зачем. Посмотрите на первый пункт содержания к этой статье (Что такое содержание (оглавление) статьи и для чего оно используется?) Чтобы сделать его ссылкой на соответствующий раздел текста необходимо, в текстовом редакторе блога, переключиться в режим «Текст». Для этого перейдите по по соответствующей вкладке.
Заключаем оглавление раздела статьи “Что такое содержание (оглавление) статьи и для чего оно используется?” в теги ссылки. Должно получится следующее.
<a href="#1"><li>Что такое содержание (оглавление)статьи и для чего оно нужно?</a><br>
Таким образом мы сделали анкорную ссылку. Теперь, чтобы сделать переход по этой ссылке на определенное место статьи, необходимо выделить нужный участок текста и заключить его в следующие теги. Таким образом вы создадите анкор (место куда ведет ссылка) .
<a2 id="1">Участок текста статьи для перехода по ссылке</a2>
Все готово, вам остается только опубликовать статью нажав кнопку «Опубликовать».
Таким образом вы можете создать сколько вам угодно пунктов содержания статьи и сделать их ссылками на определенные участки текста. Способ очень простой и при определенной сноровке, не требует больших усилий и временных затрат.
Вы думаете я на этом успокоился? Конечно нет! Хотелось максимально автоматизировать процесс, чтобы содержание формировалось автоматически, было привязано к оглавлениям абзацев (Н1-Н6) и при этом, была возможность быстро и легко разместить содержание в нужном мне месте поста. Вот такое “По щучьему велению, по моему хотению…!”
Решение было найдено на отличном сайте wp-kama.ru
, автора Тимура Камаева. Где предложено оригинальное решение данной задачи.
Автоматическое создание содержания статьи.
Для начала копируйте нижеприведенный код.
/** * Содержание (оглавление) для больших постов. * * Author: Kama * Page: http://wp-kama.ru/?p=1513 * ver: 3.9 * * Changelog: http://wp-kama.ru/?p=1513#obnovleniya */ class Kama_Contents { // defaults options public $opt = array( // Отступ слева у подразделов в px. 'margin' => 40, // Теги по умолчанию по котором будет строиться оглавление. Порядок имеет значение. // Кроме тегов, можно указать атрибут classа: array('h2','.class_name'). Можно указать строкой: 'h2 h3 .class_name' 'selectors' => array('h2','h3','h4'), // Ссылка на возврат к оглавлению. '' - убрать ссылку 'to_menu' => 'к содержанию ↑', // Заголовок. '' - убрать заголовок 'title' => 'Содержание:', // Css стили. '' - убрать стили 'css' => '.kc__gotop{ display:block; text-align:right; } .kc__title{ font-style:italic; padding:1em 0; } .kc__anchlink{ color:#ddd!important; position:absolute; margin-left:-1em; }', // Минимальное количество найденных тегов, чтобы оглавление выводилось. 'min_found' => 2, // Минимальная длина (символов) текста, чтобы оглавление выводилось. 'min_length' => 2000, // Ссылка на страницу для которой собирается оглавление. Если оглавление выводиться на другой странице... 'page_url' => '', // Название шоткода 'shortcode' => 'contents', // Оставлять символы в анкорах 'spec' => '\'.+$*~=', // Какой тип анкора использовать: 'a' - <a name="anchor"></a> или 'id' - 'anchor_type' => 'id', // Включить микроразметку? 'markup' => false, // Добавить 'знак' перед подзаголовком статьи со ссылкой на текущий анкор заголовка. Укажите '#', '&' или что вам нравится :) 'anchor_link' => '', // минимальное количество символов между заголовками содержания, для которых нужно выводить ссылку "к содержанию". // Не имеет смысла, если параметр 'to_menu' отключен. С целью производительности, кириллица считается без учета кодировки. // Поэтому 800 символов кириллицы - это примерно 1600 символов в этом параметре. 800 - расчет для сайтов на кириллице... 'tomenu_simcount' => 800, ); public $contents; // collect html contents private $temp; static $inst; function __construct( $args = array() ){ $this->set_opt( $args ); return $this; } /** * Create instance * @param array [$args = array()] Options * @return object Instance */ static function init( $args = array() ){ is_null( self::$inst ) && self::$inst = new self( $args ); if( $args ) self::$inst->set_opt( $args ); return self::$inst; } function set_opt( $args = array() ){ $this->opt = (object) array_merge( (array) $this->opt, (array) $args ); } /** * Обрабатывает текст, превращает шоткод в нем в оглавление. * @param (string) $content текст, в котором есть шоткод. * @param (string) $contents_cb callback функция, которая обработает список оглавления. * @return Обработанный текст с оглавлением, если в нем есть шоткод. */ function shortcode( $content, $contents_cb = '' ){ if( false === strpos( $content, '['. $this->opt->shortcode ) ) return $content; // get contents data if( ! preg_match('~^(.*)\['. $this->opt->shortcode .'([^\]]*)\](.*)$~s', $content, $m ) ) return $content; $contents = $this->make_contents( $m[3], $m[2] ); if( $contents && $contents_cb && is_callable($contents_cb) ) $contents = $contents_cb( $contents ); return $m[1] . $contents . $m[3]; } /** * Заменяет заголовки в переданном тексте (по ссылке), создает и возвращает оглавление. * @param (string) $content текст на основе которого нужно создать оглавление. * @param (array/string) $tags массив тегов, которые искать в переданном тексте. * Можно указать: имена тегов "h2 h3" или классы элементов ".foo .foo2". * Если в теги добавить маркер "embed" то вернется только тег <ul> * без заголовка и оборачивающего блока. Нужно для использования внутри текста, как список. * @return html код оглавления. */ function make_contents( & $content, $tags = '' ){ // return if text is too short if( mb_strlen( strip_tags($content) ) < $this->opt->min_length ) return; $this->temp = $this->opt; $this->contents = array(); if( ! $tags ) $tags = $this->opt->selectors; if( is_string($tags) ) $tags = array_map('trim', preg_split('/[ ,]+/', $tags ) ); $tags = array_filter($tags); // del empty // check tags foreach( $tags as $k => $tag ){ // remove special marker tags and set $args if( in_array( $tag, array('embed','no_to_menu') ) ){ if( $tag == 'embed' ) $this->temp->embed = true; if( $tag == 'no_to_menu' ) $this->opt->to_menu = false; unset( $tags[ $k ] ); continue; } // remove tag if it's not exists in content $patt = ( ($tag[0] == '.') ? 'class=[\'"][^\'"]*'. substr($tag, 1) : "<$tag" ); if( ! preg_match("/$patt/i", $content ) ){ unset( $tags[ $k ] ); continue; } } if( ! $tags ) return; // set patterns from given $tags // separate classes & tags & set $class_patt = $tag_patt = $level_tags = array(); foreach( $tags as $tag ){ // class if( $tag{0} == '.' ){ $tag = substr( $tag, 1 ); $link = & $class_patt; } // html tag else $link = & $tag_patt; $link[] = $tag; $level_tags[] = $tag; } $this->temp->level_tags = array_flip( $level_tags ); // replace all titles & collect contents to $this->contents $patt_in = array(); if( $tag_patt ) $patt_in[] = '(?:<('. implode('|', $tag_patt) .')([^>]*)>(.*?)<\/\1>)'; if( $class_patt ) $patt_in[] = '(?:<([^ >]+) ([^>]*class=["\'][^>]*('. implode('|', $class_patt) .')[^>]*["\'][^>]*)>(.*?)<\/'. ($patt_in?'\4':'\1') .'>)'; $patt_in = implode('|', $patt_in ); $this->temp->content = $content; // collect and replace $_content = preg_replace_callback("/$patt_in/is", array( &$this, '__make_contents_callback'), $content, -1, $count ); if( ! $count || $count < $this->opt->min_found ){ unset($this->temp); // clear cache return; } $this->temp->content = $content = $_content; // $_content was for check reasone // html static $css; $embed = isset($this->temp->embed); $_tit = & $this->opt->title; $_is_tit = ! $embed && $_tit; // markup $ItemList = $this->opt->markup ? ' itemscope itemtype="http://schema.org/ItemList"' : ''; $contents = ( $_is_tit ? '<div class="kc__wrap"'. $ItemList .' >' : '' ) . ( ( ! $css && $this->opt->css ) ? '<style>'. preg_replace('/[\n\t ]+/', ' ', $this->opt->css ) .'</style>' : '' ) . ( $_is_tit ? '<span style="display:block;" class="kc-title kc__title" id="kcmenu"'. ($ItemList?' itemprop="name"':'') .'>'. $_tit .'</span>'. "\n" : '' ) . '<ul class="contents"'. ( (! $_tit || $embed) ? ' id="kcmenu"' : '' ) . ( ($ItemList && ! $_is_tit ) ? $ItemList : '' ) .'>'. "\n". implode('', $this->contents ) . '</ul>'."\n" . ( $_is_tit ? '</div>' : '' ); unset($this->temp); // clear cache return $this->contents = $contents; } ## callback function to replace and collect contents private function __make_contents_callback( $match ){ $temp = & $this->temp; // it's only class selector in pattern if( count($match) == 5 ){ $tag = $match[1]; $attrs = $match[2]; $title = $match[4]; $level_tag = $match[3]; // class_name } // it's found tag selector elseif( count($match) == 4 ){ $tag = $match[1]; $attrs = $match[2]; $title = $match[3]; $level_tag = $tag; } // it's found class selector else{ $tag = $match[4]; $attrs = $match[5]; $title = $match[7]; $level_tag = $match[6]; // class_name } $anchor = $this->__sanitaze_anchor( $title ); $opt = $this->opt; // make live easier $level = @ $temp->level_tags[ $level_tag ]; if( $level > 0 ) $sub = ( $opt->margin ? ' style="margin-left:'. ($level*$opt->margin) .'px;"' : '') . ' class="sub sub_'. $level .'"'; else $sub = ' class="top"'; // collect contents // markup $_is_mark = $opt->markup; $temp->counter = empty($temp->counter) ? 1 : $temp->counter+1; $this->contents[] = "\t". '<li'. $sub . ($_is_mark?' itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"':'') .'> <a rel="nofollow"'. ($_is_mark?' itemprop="item"':'') .' href="'. $opt->page_url .'#'. $anchor .'"> '.( $_is_mark ? '<span itemprop="name">'. $title .'</span>' : $title ).' </a> '.( $_is_mark ? ' <meta itemprop="position" content="'. $temp->counter .'" />':'' ).' </li>'. "\n"; $anchlink = $opt->anchor_link ? '<a rel="nofollow" class="kc__anchlink" href="#'. $anchor .'">'. $opt->anchor_link .'</a> ' : ''; if( $anchlink ) $title = $anchlink . $title; $new_el = "\n<$tag id=\"$anchor\" $attrs>$anchlink$title</$tag>"; if( $opt->anchor_type == 'a' ) $new_el = '<a class="kc__anchor" name="'. $anchor .'"></a>'."\n<$tag $attrs>$title</$tag>"; $to_menu = ''; if( $opt->to_menu ){ // go to contents $to_menu = '<a rel="nofollow" class="kc-gotop kc__gotop" href="'. $opt->page_url .'#kcmenu">'. $opt->to_menu .'</a>'; // remove '$to_menu' if simbols beatween $to_menu too small (< 300) $pos = strpos( $temp->content, $match[0] ); // mb_strpos( $temp->content, $match[0] ) - в 150 раз медленнее! if( empty($temp->elpos) ){ $prevpos = 0; $temp->elpos = array( $pos ); } else { $prevpos = end($temp->elpos); $temp->elpos[] = $pos; } $simbols_count = $pos - $prevpos; if( $simbols_count < $opt->tomenu_simcount ) $to_menu = ''; } return $to_menu . $new_el; } ## URL transliteration function __sanitaze_anchor( $str ){ $str = strip_tags( $str ); $iso9 = array( 'А'=>'A', 'Б'=>'B', 'В'=>'V', 'Г'=>'G', 'Д'=>'D', 'Е'=>'E', 'Ё'=>'YO', 'Ж'=>'ZH', 'З'=>'Z', 'И'=>'I', 'Й'=>'J', 'К'=>'K', 'Л'=>'L', 'М'=>'M', 'Н'=>'N', 'О'=>'O', 'П'=>'P', 'Р'=>'R', 'С'=>'S', 'Т'=>'T', 'У'=>'U', 'Ф'=>'F', 'Х'=>'H', 'Ц'=>'TS', 'Ч'=>'CH', 'Ш'=>'SH', 'Щ'=>'SHH', 'Ъ'=>'', 'Ы'=>'Y', 'Ь'=>'', 'Э'=>'E', 'Ю'=>'YU', 'Я'=>'YA', // small 'а'=>'a', 'б'=>'b', 'в'=>'v', 'г'=>'g', 'д'=>'d', 'е'=>'e', 'ё'=>'yo', 'ж'=>'zh', 'з'=>'z', 'и'=>'i', 'й'=>'j', 'к'=>'k', 'л'=>'l', 'м'=>'m', 'н'=>'n', 'о'=>'o', 'п'=>'p', 'р'=>'r', 'с'=>'s', 'т'=>'t', 'у'=>'u', 'ф'=>'f', 'х'=>'h', 'ц'=>'ts', 'ч'=>'ch', 'ш'=>'sh', 'щ'=>'shh', 'ъ'=>'', 'ы'=>'y', 'ь'=>'', 'э'=>'e', 'ю'=>'yu', 'я'=>'ya', // other 'Ѓ'=>'G', 'Ґ'=>'G', 'Є'=>'YE', 'Ѕ'=>'Z', 'Ј'=>'J', 'І'=>'I', 'Ї'=>'YI', 'Ќ'=>'K', 'Љ'=>'L', 'Њ'=>'N', 'Ў'=>'U', 'Џ'=>'DH', 'ѓ'=>'g', 'ґ'=>'g', 'є'=>'ye', 'ѕ'=>'z', 'ј'=>'j', 'і'=>'i', 'ї'=>'yi', 'ќ'=>'k', 'љ'=>'l', 'њ'=>'n', 'ў'=>'u', 'џ'=>'dh' ); $str = strtr( $str, $iso9 ); $spec = preg_quote( $this->opt->spec ); $str = preg_replace("/[^a-zA-Z0-9_$spec\-]+/", '-', $str ); // все ненужное на '-' $str = trim( $str, '-'); return strtolower( $str ); } ## cut the shortcode from the content function strip_shortcode( $text ){ return preg_replace('~\['. $this->opt->shortcode .'[^\]]*\]~', '', $text ); } } /** * 3.9 - при 'anchor_type=a' не работал параметр 'anchor_link' * 3.8 - баг синтаксиса при заполнении свойства $this->contents в PHP 7.1 * 3.7 - добавил элемент position при маркировке schema.org * 3.6.1 - тег заголовка "Содержание" изменил с DIV на SPAN * 3.6 - исправление парсинга тегов - удаление пустых при разбиении по [ ,] * 3.5 - стабильность. в параметр selectors можно указывать строку с элементами через запятую. * 3.4 - параметр 'tomenu_simcount' * 3.3 - smart 'to contents' link show - not show next link if symbols between prev smaller than 500 */ ## Обработка шоткода [contents] в тексте add_filter('the_content', 'kama_contents_shortcode'); function kama_contents_shortcode( $content ){ $args = array(); //$args['shortcode'] = 'list'; // [list] вместо [contents] if( is_singular() ){ //$args['margin'] = 30; //$args['page_url'] = get_permalink(); $args['to_menu'] = 'к оглавлению ↑'; $args['title'] = 'Оглавление:'; return Kama_Contents::init( $args )->shortcode( $content ); } // вырежем шорткод else return Kama_Contents::init( $args )->strip_shortcode( $content ); }
/** * Содержание (оглавление) для больших постов. * * Author: Kama * Page: http://wp-kama.ru/?p=1513 * ver: 3.9 * * Changelog: http://wp-kama.ru/?p=1513#obnovleniya */ class Kama_Contents { // defaults options public $opt = array( // Отступ слева у подразделов в px. 'margin' => 40, // Теги по умолчанию по котором будет строиться оглавление. Порядок имеет значение. // Кроме тегов, можно указать атрибут classа: array('h2','.class_name'). Можно указать строкой: 'h2 h3 .class_name' 'selectors' => array('h2','h3','h4'), // Ссылка на возврат к оглавлению. '' - убрать ссылку 'to_menu' => 'к содержанию ↑', // Заголовок. '' - убрать заголовок 'title' => 'Содержание:', // Css стили. '' - убрать стили 'css' => '.kc__gotop{ display:block; text-align:right; } .kc__title{ font-style:italic; padding:1em 0; } .kc__anchlink{ color:#ddd!important; position:absolute; margin-left:-1em; }', // Минимальное количество найденных тегов, чтобы оглавление выводилось. 'min_found' => 2, // Минимальная длина (символов) текста, чтобы оглавление выводилось. 'min_length' => 2000, // Ссылка на страницу для которой собирается оглавление. Если оглавление выводиться на другой странице... 'page_url' => '', // Название шоткода 'shortcode' => 'contents', // Оставлять символы в анкорах 'spec' => '\'.+$*~=', // Какой тип анкора использовать: 'a' - <a name="anchor"></a> или 'id' - 'anchor_type' => 'id', // Включить микроразметку? 'markup' => false, // Добавить 'знак' перед подзаголовком статьи со ссылкой на текущий анкор заголовка. Укажите '#', '&' или что вам нравится :) 'anchor_link' => '', // минимальное количество символов между заголовками содержания, для которых нужно выводить ссылку "к содержанию". // Не имеет смысла, если параметр 'to_menu' отключен. С целью производительности, кириллица считается без учета кодировки. // Поэтому 800 символов кириллицы - это примерно 1600 символов в этом параметре. 800 - расчет для сайтов на кириллице... 'tomenu_simcount' => 800, ); public $contents; // collect html contents private $temp; static $inst; function __construct( $args = array() ){ $this->set_opt( $args ); return $this; } /** * Create instance * @param array [$args = array()] Options * @return object Instance */ static function init( $args = array() ){ is_null( self::$inst ) && self::$inst = new self( $args ); if( $args ) self::$inst->set_opt( $args ); return self::$inst; } function set_opt( $args = array() ){ $this->opt = (object) array_merge( (array) $this->opt, (array) $args ); } /** * Обрабатывает текст, превращает шоткод в нем в оглавление. * @param (string) $content текст, в котором есть шоткод. * @param (string) $contents_cb callback функция, которая обработает список оглавления. * @return Обработанный текст с оглавлением, если в нем есть шоткод. */ function shortcode( $content, $contents_cb = '' ){ if( false === strpos( $content, '['. $this->opt->shortcode ) ) return $content; // get contents data if( ! preg_match('~^(.*)\['. $this->opt->shortcode .'([^\]]*)\](.*)$~s', $content, $m ) ) return $content; $contents = $this->make_contents( $m[3], $m[2] ); if( $contents && $contents_cb && is_callable($contents_cb) ) $contents = $contents_cb( $contents ); return $m[1] . $contents . $m[3]; } /** * Заменяет заголовки в переданном тексте (по ссылке), создает и возвращает оглавление. * @param (string) $content текст на основе которого нужно создать оглавление. * @param (array/string) $tags массив тегов, которые искать в переданном тексте. * Можно указать: имена тегов "h2 h3" или классы элементов ".foo .foo2". * Если в теги добавить маркер "embed" то вернется только тег <ul> * без заголовка и оборачивающего блока. Нужно для использования внутри текста, как список. * @return html код оглавления. */ function make_contents( & $content, $tags = '' ){ // return if text is too short if( mb_strlen( strip_tags($content) ) < $this->opt->min_length ) return; $this->temp = $this->opt; $this->contents = array(); if( ! $tags ) $tags = $this->opt->selectors; if( is_string($tags) ) $tags = array_map('trim', preg_split('/[ ,]+/', $tags ) ); $tags = array_filter($tags); // del empty // check tags foreach( $tags as $k => $tag ){ // remove special marker tags and set $args if( in_array( $tag, array('embed','no_to_menu') ) ){ if( $tag == 'embed' ) $this->temp->embed = true; if( $tag == 'no_to_menu' ) $this->opt->to_menu = false; unset( $tags[ $k ] ); continue; } // remove tag if it's not exists in content $patt = ( ($tag[0] == '.') ? 'class=[\'"][^\'"]*'. substr($tag, 1) : "<$tag" ); if( ! preg_match("/$patt/i", $content ) ){ unset( $tags[ $k ] ); continue; } } if( ! $tags ) return; // set patterns from given $tags // separate classes & tags & set $class_patt = $tag_patt = $level_tags = array(); foreach( $tags as $tag ){ // class if( $tag{0} == '.' ){ $tag = substr( $tag, 1 ); $link = & $class_patt; } // html tag else $link = & $tag_patt; $link[] = $tag; $level_tags[] = $tag; } $this->temp->level_tags = array_flip( $level_tags ); // replace all titles & collect contents to $this->contents $patt_in = array(); if( $tag_patt ) $patt_in[] = '(?:<('. implode('|', $tag_patt) .')([^>]*)>(.*?)<\/\1>)'; if( $class_patt ) $patt_in[] = '(?:<([^ >]+) ([^>]*class=["\'][^>]*('. implode('|', $class_patt) .')[^>]*["\'][^>]*)>(.*?)<\/'. ($patt_in?'\4':'\1') .'>)'; $patt_in = implode('|', $patt_in ); $this->temp->content = $content; // collect and replace $_content = preg_replace_callback("/$patt_in/is", array( &$this, '__make_contents_callback'), $content, -1, $count ); if( ! $count || $count < $this->opt->min_found ){ unset($this->temp); // clear cache return; } $this->temp->content = $content = $_content; // $_content was for check reasone // html static $css; $embed = isset($this->temp->embed); $_tit = & $this->opt->title; $_is_tit = ! $embed && $_tit; // markup $ItemList = $this->opt->markup ? ' itemscope itemtype="http://schema.org/ItemList"' : ''; $contents = ( $_is_tit ? '<div class="kc__wrap"'. $ItemList .' >' : '' ) . ( ( ! $css && $this->opt->css ) ? '<style>'. preg_replace('/[\n\t ]+/', ' ', $this->opt->css ) .'</style>' : '' ) . ( $_is_tit ? '<span style="display:block;" class="kc-title kc__title" id="kcmenu"'. ($ItemList?' itemprop="name"':'') .'>'. $_tit .'</span>'. "\n" : '' ) . '<ul class="contents"'. ( (! $_tit || $embed) ? ' id="kcmenu"' : '' ) . ( ($ItemList && ! $_is_tit ) ? $ItemList : '' ) .'>'. "\n". implode('', $this->contents ) . '</ul>'."\n" . ( $_is_tit ? '</div>' : '' ); unset($this->temp); // clear cache return $this->contents = $contents; } ## callback function to replace and collect contents private function __make_contents_callback( $match ){ $temp = & $this->temp; // it's only class selector in pattern if( count($match) == 5 ){ $tag = $match[1]; $attrs = $match[2]; $title = $match[4]; $level_tag = $match[3]; // class_name } // it's found tag selector elseif( count($match) == 4 ){ $tag = $match[1]; $attrs = $match[2]; $title = $match[3]; $level_tag = $tag; } // it's found class selector else{ $tag = $match[4]; $attrs = $match[5]; $title = $match[7]; $level_tag = $match[6]; // class_name } $anchor = $this->__sanitaze_anchor( $title ); $opt = $this->opt; // make live easier $level = @ $temp->level_tags[ $level_tag ]; if( $level > 0 ) $sub = ( $opt->margin ? ' style="margin-left:'. ($level*$opt->margin) .'px;"' : '') . ' class="sub sub_'. $level .'"'; else $sub = ' class="top"'; // collect contents // markup $_is_mark = $opt->markup; $temp->counter = empty($temp->counter) ? 1 : $temp->counter+1; $this->contents[] = "\t". '<li'. $sub . ($_is_mark?' itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"':'') .'> <a rel="nofollow"'. ($_is_mark?' itemprop="item"':'') .' href="'. $opt->page_url .'#'. $anchor .'"> '.( $_is_mark ? '<span itemprop="name">'. $title .'</span>' : $title ).' </a> '.( $_is_mark ? ' <meta itemprop="position" content="'. $temp->counter .'" />':'' ).' </li>'. "\n"; $anchlink = $opt->anchor_link ? '<a rel="nofollow" class="kc__anchlink" href="#'. $anchor .'">'. $opt->anchor_link .'</a> ' : ''; if( $anchlink ) $title = $anchlink . $title; $new_el = "\n<$tag id=\"$anchor\" $attrs>$anchlink$title</$tag>"; if( $opt->anchor_type == 'a' ) $new_el = '<a class="kc__anchor" name="'. $anchor .'"></a>'."\n<$tag $attrs>$title</$tag>"; $to_menu = ''; if( $opt->to_menu ){ // go to contents $to_menu = '<a rel="nofollow" class="kc-gotop kc__gotop" href="'. $opt->page_url .'#kcmenu">'. $opt->to_menu .'</a>'; // remove '$to_menu' if simbols beatween $to_menu too small (< 300) $pos = strpos( $temp->content, $match[0] ); // mb_strpos( $temp->content, $match[0] ) - в 150 раз медленнее! if( empty($temp->elpos) ){ $prevpos = 0; $temp->elpos = array( $pos ); } else { $prevpos = end($temp->elpos); $temp->elpos[] = $pos; } $simbols_count = $pos - $prevpos; if( $simbols_count < $opt->tomenu_simcount ) $to_menu = ''; } return $to_menu . $new_el; } ## URL transliteration function __sanitaze_anchor( $str ){ $str = strip_tags( $str ); $iso9 = array( 'А'=>'A', 'Б'=>'B', 'В'=>'V', 'Г'=>'G', 'Д'=>'D', 'Е'=>'E', 'Ё'=>'YO', 'Ж'=>'ZH', 'З'=>'Z', 'И'=>'I', 'Й'=>'J', 'К'=>'K', 'Л'=>'L', 'М'=>'M', 'Н'=>'N', 'О'=>'O', 'П'=>'P', 'Р'=>'R', 'С'=>'S', 'Т'=>'T', 'У'=>'U', 'Ф'=>'F', 'Х'=>'H', 'Ц'=>'TS', 'Ч'=>'CH', 'Ш'=>'SH', 'Щ'=>'SHH', 'Ъ'=>'', 'Ы'=>'Y', 'Ь'=>'', 'Э'=>'E', 'Ю'=>'YU', 'Я'=>'YA', // small 'а'=>'a', 'б'=>'b', 'в'=>'v', 'г'=>'g', 'д'=>'d', 'е'=>'e', 'ё'=>'yo', 'ж'=>'zh', 'з'=>'z', 'и'=>'i', 'й'=>'j', 'к'=>'k', 'л'=>'l', 'м'=>'m', 'н'=>'n', 'о'=>'o', 'п'=>'p', 'р'=>'r', 'с'=>'s', 'т'=>'t', 'у'=>'u', 'ф'=>'f', 'х'=>'h', 'ц'=>'ts', 'ч'=>'ch', 'ш'=>'sh', 'щ'=>'shh', 'ъ'=>'', 'ы'=>'y', 'ь'=>'', 'э'=>'e', 'ю'=>'yu', 'я'=>'ya', // other 'Ѓ'=>'G', 'Ґ'=>'G', 'Є'=>'YE', 'Ѕ'=>'Z', 'Ј'=>'J', 'І'=>'I', 'Ї'=>'YI', 'Ќ'=>'K', 'Љ'=>'L', 'Њ'=>'N', 'Ў'=>'U', 'Џ'=>'DH', 'ѓ'=>'g', 'ґ'=>'g', 'є'=>'ye', 'ѕ'=>'z', 'ј'=>'j', 'і'=>'i', 'ї'=>'yi', 'ќ'=>'k', 'љ'=>'l', 'њ'=>'n', 'ў'=>'u', 'џ'=>'dh' ); $str = strtr( $str, $iso9 ); $spec = preg_quote( $this->opt->spec ); $str = preg_replace("/[^a-zA-Z0-9_$spec\-]+/", '-', $str ); // все ненужное на '-' $str = trim( $str, '-'); return strtolower( $str ); } ## cut the shortcode from the content function strip_shortcode( $text ){ return preg_replace('~\['. $this->opt->shortcode .'[^\]]*\]~', '', $text ); } } /** * 3.9 - при 'anchor_type=a' не работал параметр 'anchor_link' * 3.8 - баг синтаксиса при заполнении свойства $this->contents в PHP 7.1 * 3.7 - добавил элемент position при маркировке schema.org * 3.6.1 - тег заголовка "Содержание" изменил с DIV на SPAN * 3.6 - исправление парсинга тегов - удаление пустых при разбиении по [ ,] * 3.5 - стабильность. в параметр selectors можно указывать строку с элементами через запятую. * 3.4 - параметр 'tomenu_simcount' * 3.3 - smart 'to contents' link show - not show next link if symbols between prev smaller than 500 */ ## Обработка шоткода [contents] в тексте add_filter('the_content', 'kama_contents_shortcode'); function kama_contents_shortcode( $content ){ $args = array(); //$args['shortcode'] = 'list'; // [list] вместо [contents] if( is_singular() ){ //$args['margin'] = 30; //$args['page_url'] = get_permalink(); $args['to_menu'] = 'к оглавлению ↑'; $args['title'] = 'Оглавление:'; return Kama_Contents::init( $args )->shortcode( $content ); } // вырежем шорткод else return Kama_Contents::init( $args )->strip_shortcode( $content ); }
Теперь надо вставить данный код в файл function.php вашего шаблона сайта. Можете это сделать используя FTP соединение или при помощи админ панели управления вашего сайта. Для этого заходите в панель, переходите по вкладкам «Консоль» => « Внешний вид» (1) => «Редактор» (2) => «function.php» (3).
В самом конце файла, вставляете скопированный код и не забываете нажать кнопку «Обновить файл».
Далее копируете код стилей оформления.
.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». В самом конце файла style.css вставляете скопированный код и не забываете нажать кнопку «Обновить файл».
Основная задача выполнена. Далее от вас требуется, при написании постов, грамотно разбивать их на абзацы и проставлять заголовки ( h1-h4). Как правильно использовать теги заголовков h1-h6, можно прочитать здесь.
Для вывода содержания статьи в нужном месте, перед публикацией необходимо, вставить шорткод.
[contents]
Содержание автоматически будет создано, причем в древовидном виде и с учетом иерархии заголовков. Дополнительно, в конце каждого абзаца, появится ссылка “перейти к содержанию”, что также создает дополнительное удобство для посетителя.
Оформление блока вы можете изменить в файле стилей. Я выделил содержание отдельным блоком с синим фоном. Так лучше привлекает внимание и подходит под общий стиль оформления. Вы можете самостоятельно поэксперементировать со стилями для создания индивидуального дизайна.
Кстати, в статье Тимура Камаева, есть дополнения к коду, которые позволяют настроить место отображения блока, кому интересно можете изучить.
Плагины для создания содержания (оглавления) статей.
Для тех кто боится лезть в код, можно воспользоваться специальными плагинами для создания содержания.
- Table of Contents Plus— простой и удобный плагин, который создает кнопку в редакторе для создания блока содержания.
- Simple TOC— гибкий плагин с широкими возможностями настроек и созданием кнопки в визуальном редакторе.
Основной недостаток данных плагинов, автоматическое создание оглавления в статьях, когда оно там не требуется. Я стараюсь не использовать в большом количестве плагины на своем сайте и решать вопросы при помощи кода. Как не крути, плагины тормозят скорость загрузки сайта, и не редко конфликтуют между собой и с кодом шаблона блога.
На этом пожалуй все. Улучшайте внешний вид своего ресурса, пишите отзывы и пожелания. Всем удачи!
Пожалуйста, рад был помочь. Удачи!
Большое спасибо, установила себе на сайт, все работает отлично. Всего доброго.
Андрей, пожалуйста. Применяйте. Удачи!
Сергей ваша статья как под заказ! Я совсем недавно мучился с этим вопросом, перелопатив кучу информации я ничего путного кроме как решить проблему с помощью плагинов не нашел! Я не сторонник плагинов и поэтому ваш вариант считаю идеальным!Вариант Тимура Камаева меня пугает! Так что лучше сделаю сам ручками по вашему варианту, как по мне так надежней! Спасибо за очень интересное и простое решение проблемы! С уважением к вам и вашему блогу Андрей!