# Содержание для больших постов (Kama_Contents)
Не редкость, когда мы делим большие посты на логические подзаголовки. Иногда пост содержит собрание информации, разделенной на части. Для таких постов я предпочитаю создавать "оглавление" — список ссылок на подзаголовки. Создание такого оглавления — это утомительная задача, и, в большинстве случаев, проще обойтись без него (за редкими исключениями).
## Содержание:
* Код класса Kama_Contents
* Как использовать класс Kama_Contents
* #1 Оглавление в тексте (шорткод [contents])
* #2 Оглавление вверху каждого поста
* #3 Оглавление вверху поста, после разделителя
* #4 Оглавление в боковой панели
* #5 Разные экземпляры
* Настройки оглавления
* HTML и CSS
* Деревообразная нумерация списка
* Плавная прокрутка
* "Показать/Скрыть" оглавление (код jQuery)
* Плагины для создания оглавления
Я написал небольшой класс, который позволяет быстро и красиво создавать оглавления практически любой сложности. Для этого используйте шорткод [contents] там, где это необходимо. В начале этого поста вы видите само оглавление.
Кроме того, класс позволяет создать оглавление для любого текста без использования шорткода. Затем его можно выводить, например, в начале поста или в боковой панели.
Оглавление можно настраивать различными способами:
* не показывать заголовок: "Оглавление:" - [contents embed]
;
* не показывать ссылки "Назад к началу" - параметр to_menu
;
* настраивать CSS-стили - параметр css
;
* изменить HTML-теги, на которых будет строиться оглавление. Вы можете указать любые теги, не только H1, H2 и т.д., но и strong, em и т.д. Или даже указать классы HTML-тегов, например: .foo, .bar. Например: [contents h1 em .foo]
;
* указать минимальное количество заголовков для отображения оглавления - параметр min_found
;
* указать минимальную длину текста для отображения оглавления - параметр min_length
;
* указать имя шорткода для использования в тексте, чтобы создать оглавление - параметр shortcode
;
* другие параметры, смотрите в коде класса Kama_Contents.
## Код класса KAMA_CONTENTS
```php
(проверьте полный код класса в оригинале)
Как использовать класс Kama_Contents
Сначала нужно подключить код:
- Создайте файл, например,
Kama_Contents.php
, и скопируйте туда код. Подключите этот файл вfunctions.php
вашей темы:
require_once __DIR__ .'/Kama_Contents.php';
- Используйте Composer:
composer require doiftrue/wp-kama-contents
Теперь вы можете использовать класс. Для этого выберите подходящий код из примеров ниже и добавьте его в functions.php
вашей темы.
1 Оглавление в тексте (шорткод [contents])
Когда вы пишете пост, используйте шорткод [contents]
или [contents h3]
или [contents h3 h5]
. Оглавление будет отображаться в месте, где находится шорткод:
// Обработка шорткода [contents] в тексте
add_filter( 'the_content', 'kama_contents_shortcode', 20 );
function kama_contents_shortcode( $content ) {
$args = array(
'to_menu' => 'Назад к началу ↑',
'title' => 'Оглавление:',
'min_length' => 300,
);
$toc = new KamaWPKama_Contents( $args );
if( is_singular() ){
return $toc->apply_shortcode( $content );
} else {
return $toc->strip_shortcode( $content );
}
}
2 Оглавление вверху каждого поста
Разместите этот код рядом с основным, и оглавление будет отображаться в начале каждого поста на основе указанных тегов. Например, массив array('h2','h3')
означает, что если в тексте есть теги h2 или h3, будет создано оглавление из них:
// Отображение оглавления вверху каждого поста
add_filter( 'the_content', 'contents_on_post_top', 20 );
function contents_on_post_top( $content ) {
if( ! is_singular() ){
return $content;
}
$args = array(
'selectors' => ['h2', 'h3'],
);
$toc = new KamaWPKama_Contents( $args );
$contents = $toc->make_contents( $content );
return $contents . $content;
}
3 Оглавление вверху каждого поста, после разделителя
Этот код вставит оглавление в начало каждого поста. Но не в самом начале, а после первого абзаца. Вы можете изменить номер абзаца (разделителя) и сам разделитель:
// Отображение оглавления после определенного абзаца
add_filter( 'the_content', 'contents_at_top_after_nsep', 20 );
function contents_at_top_after_nsep( $text ) {
if( ! is_singular() ){
return $text;
}
$params = (object) [
'sep' => '', // разделитель в тексте
'num' => 1, // после какого разделителя вставить оглавление?
'pos' => 'after', // до|после - куда вставить оглавление
];
$toc = new KamaWPKama_Contents( [
'min_length' => 4000,
'selectors' => ['h2', 'h3'],
]);
$ex_text = explode( $params->sep, $text, $params->num + 1 );
if( isset( $ex_text[ $params->num ] ) ){
$contents = $toc->make_contents( $ex_text[ $params->num ] );
if( 'after' === $params->pos ){
$ex_text[ $params->num ] = $contents . $ex_text[ $params->num ];
} else {
$ex_text[ $params->num - 1 ] = $ex_text[ $params->num - 1 ] . $contents;
}
$text = implode( $params->sep, $ex_text );
} else {
$contents = $toc->make_contents( $text );
$text = $contents . $text;
}
return $text;
}
4 Оглавление в боковой панели
Этот пример аналогичен второму — здесь используется метод make_contents()
, а не apply_shortcode()
, как в первом примере.
Вариант 1
Добавьте эту функцию рядом с классом и используйте её, чтобы отобразить оглавление. Необходимо передать объект поста в функцию для получения оглавления или передать текст, для которого нужно отобразить оглавление:
// Отображение оглавления
function get_kama_contents( & $post = false ) {
if( ! $post ) $post = $GLOBALS['post'];
if( is_string( $post ) ){
$post_content = & $post;
} else {
$post_content = & $post->post_content;
}
$toc = new KamaWPKama_Contents( [
'selectors' => [ 'h2', 'h3' ],
'min_found' => 1,
'margin' => 0,
'to_menu' => false,
'title' => false,
]);
$contents = $toc->make_contents( $post_content );
global $pages;
if( $pages && count($pages) == 1 ){
$pages[0] = $post_content;
} else {
// Индивидуальная обработка здесь...
}
return $contents;
}
Теперь выведите оглавление, например, в боковой панели:
echo get_kama_contents();
Обратите внимание, что get_kama_contents()
должна вызываться до того, как будет отображено содержание. Если оглавление нужно отобразить ниже содержания, вызовите эту функцию, сохраните оглавление и затем отобразите его ниже:
$contents = get_kama_contents();
// ваш код
the_content();
// отобразить оглавление
echo $contents;
Вариант 2
Разместив этот код рядом с основным классом, вы можете отобразить оглавление в любом месте шаблона, например, в боковой панели. Для этого используйте строку: echo $GLOBALS['kc_contents'];
// Отображение оглавления в боковой панели
add_action( 'wp_head', 'sidebar_contents' );
function sidebar_contents() {
global $post;
if( ! is_singular() ){
return;
}
$args = array();
$args['selectors'] = [ 'h2', 'h3' ];
$toc = new KamaWPKama_Contents( $args );
$GLOBALS['kc_contents'] = $toc->make_contents( $post->post_content );
}
5 Разные экземпляры
Если вам нужно использовать несколько классов с разными параметрами для обработки различных текстов, создайте разные экземпляры класса следующим образом:
// 1
$text1 = 'текст [toc] текст';
$kamatoc = new KamaWPKama_Contents( [
'to_menu' => 'Назад к началу ↑',
'title' => 'Оглавление:',
'shortcode' => 'toc',
] );
echo $kamatoc->apply_shortcode( $text1 );
// 2
$text2 = 'текст [list] текст';
$kamatoc2 = new KamaWPKama_Contents( [
'to_menu' => 'Назад к списку ↑',
'title' => 'Навигация:',
'shortcode' => 'list',
] );
echo $kamatoc2->apply_shortcode( $text2 );
Настройки оглавления
Вы заметили закомментированные строки в примерах, верно? Это настройки. Вы можете передавать аргументы (настройки) в экземпляр класса:
$args = [
'margin' => '2em',
'selectors' => 'h2 h3 h4',
'to_menu' => 'к оглавлению ↑',
'title' => 'Оглавление:',
'js' => '',
'min_found' => 2,
'min_length' => 2000,
'page_url' => '',
'shortcode' => 'contents',
'spec' => '',
'anchor_type' => 'id',
'anchor_attr_name' => 'id',
'markup' => false,
'anchor_link' => '',
'tomenu_simcount' => 800,
'leave_tags' => true,
];
$kamatoc = new KamaWPKama_Contents( $args );
Параметры (массив args)
- margin (string): Отступ слева у подразделов в px|em|rem.
- selectors (string): HTML теги для создания оглавления: 'h2 h3 h4'. Порядок определяет уровень вложенности. Можно указать строку или массив: ['h2', 'h3', 'h4'] или 'h2 h3 h4'.
- to_menu (string): Ссылка для возврата к оглавлению. '' - убрать ссылку.
- title (string): Заголовок. '' - убрать заголовок.
- js (string): JS код (добавляется после HTML кода).
- min_found (int): Минимальное количество найденных тегов для отображения оглавления.
- min_length (int): Минимальная длина текста для отображения оглавления.
- page_url (string): Ссылка на страницу, для которой формируется оглавление.
- shortcode (string): Имя шорткода.
- spec (string): Оставлять символы в анкорах. Например: '.+$*='.
- anchor_type (string): Какой тип анкора использовать: 'a' -
<a name="anchor"></a>
или 'id'. - anchor_attr_name (string): Название атрибута тега, по которому будет сформирован анкор.
- markup (bool): Включить микроразметку?
- anchor_link (string): Добавить 'знак' перед подзаголовком со ссылкой на текущий анкор заголовка. Укажите '#', '&' или что-то ещё.
- tomenu_simcount (int): Минимальное количество символов между заголовками для отображения ссылки "к оглавлению".
- leave_tags (bool|string): Нужно ли сохранять HTML-теги в элементах оглавления.
HTML и CSS
Всё содержание размещается в непрерывных <li>
, а CSS классы и левый отступ — margin
— настраиваются для уровней. С помощью классов вы можете настроить отображение по своему усмотрению...
Вот HTML-код, который генерирует Kama_Contents:
Оглавление:
Параметр style="margin-left:40px;"
добавляется автоматически на основе настройки $args['margin'] = 40;
. Между номерами заголовков (h1, h2) нет связи, уровни устанавливаются в зависимости от порядка, указанного в настройке.
Деревообразная нумерация списка
Чтобы сделать деревообразную нумерацию списка, как на изображении, установите такие CSS-стили для списка:
.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) '. ';
}
Плавная прокрутка
Этот код можно разместить на любом сайте, где подключен jQuery, для обеспечения плавной прокрутки к анкорам:
// document.ready
jQuery(function($){
$(document).on( 'click.smoothscroll', 'a[href*="#"]', function( e ){
let hash = this.hash;
let _hash = hash.replace( /#/, '' );
let theHref = $(this).attr('href').replace( /#.*/, '' );
if( this.onclick )
return;
if( theHref && location.href.replace( /#.*/, '' ) !== theHref )
return;
let $target = (_hash === '') ? $(document.body) : $( hash + ', a[name="'+ _hash +'"]').first();
if( ! $target.length )
return;
e.preventDefault();
let scrollTo = $target.offset().top - 50;
$('html:first, body:first')
.stop()
.animate( { scrollTop: scrollTo }, 200, 'swing', function(){
window.history.replaceState( null, document.title, hash );
});
});
});
"Показать/Скрыть" оглавление (код jQuery)
Вариант 1 ("как в Википедии"):
// document.ready
jQuery(function($){
let $title = $('.kc__title');
let showtxt = '[показать]';
let hidetxt = '[скрыть]';
let $but = $(''+ hidetxt +'');
$but.on( 'click', function(){
let $the = $(this);
let $cont = $the.parent().next('.contents');
if( $the.text() === hidetxt ){
$the.text( showtxt );
$cont.slideUp();
} else {
$the.text( hidetxt );
$cont.slideDown();
}
});
$title.append( $but );
});
Вариант 2 (кнопка-заголовок):
jQuery(document).ready(function($){
let $title = $('.kc__title').css({ cursor:'pointer' });
let showico = ' ▾';
let hideico = ' ▴';
let collapsedKey = 'contents_collapse';
let setIco = function( $that, type ){
$that.text( type === 'hide' ? $that.text().replace( showico, hideico ) : $that.text().replace( hideico, showico ) );
}
$title.each(function(){
let $the = $(this);
$the.text( $the.text().replace(':','').trim() + hideico );
$the.on( 'click', function(){
let $cont = $the.next('.contents');
if( $cont.is(':visible') ){
$cont.slideUp(function(){
$the.addClass('collapsed');
setIco( $the, 'show' );
window.localStorage.setItem( collapsedKey, '1' );
});
} else {
$cont.slideDown(function(){
$the.removeClass('collapsed');
setIco( $the, 'hide' );
window.localStorage.removeItem( collapsedKey );
});
}
});
// коллапс/развертывание на основе локальных данных
if( window.localStorage.getItem(collapsedKey) === '1' ){
setIco( $the, 'show' );
$the.next('.contents').hide();
}
});
});
Код должен добавляться к существующим JS сценариям. Этот код будет запускаться после подключения библиотеки jQuery.
Плагины для создания оглавления
Существуют множество причин использовать готовые плагины, даже для тех, кто может воспользоваться материалом из этой статьи. Это удобно! Вот несколько плагинов для создания аналогичного содержимого:
- Easy Table of Contents - удобный и функциональный плагин, который позволяет вставлять оглавление в ваши посты, страницы и пользовательские типы записей.
- Table of Contents Plus - высоконастраиваемый плагин, который добавляет оглавление в статьи. Также есть кнопка в визуальном редакторе.
- LuckyWP Table of Contents - генерирует оглавление для постов, страниц и пользовательских типов записей. Имеет множество настроек, блок Gutenberg, кнопку в классическом редакторе. Поддерживает как ручное, так и автоматическое добавление контента в посты.