Задача. Необходимо сделать вывод оглавлений (содержания) статей в постах автоматически. Сложность заключается в том что на странице часть контента выводится не через функцию the_content()
, а выше нее по шаблону.
Решение. Для WordPress есть хорошие плагины для вывода содержания статьи, но они работают с функцией the_content()
и выведут только те заголовки, которые попали в неё. Поэтому в данной ситуации лучше будет использовать JavaScript.
Содержание
Автоматическое создание и вывод содержания статьи с помощью JavaScript и jQuery
Решение 1. Хороший вариант автоматического создания содержания статьи в плавающем блоке на Javascript и CSS bp Примера №1 приведен в Коде №1. Интересной «фишкой» здесь является выделение пункта оглавления в зависимости на каком уровне статьи находится видимый экран.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
|
<head>
<meta charset=“UTF-8”>
<title>Автоматическое оглавление (содержание) для статей насайте</title>
<meta name=“viewport” content=“width=device-width, initial-scale=1”>
<style>
.container {
max-width: 800px;
margin-left: auto;
margin-right: auto;
}
header,
footer {
padding-left: 15px;
padding-right: 15px;
}
header>div,
footer>div,
h1 {
padding-top: 15px;
padding-bottom: 15px;
font-size: 22px;
text-align: center;
}
header>div {
background-color: #ffecb3;
}
h1 {
background-color: #b2ebf2;
}
footer>div {
background-color: #e1bee7;
}
main {
display: flex;
flex-wrap: wrap;
}
article {
flex: 0 0 100%;
max-width: 100%;
width: 100%;
padding-left: 15px;
padding-right: 15px;
margin-top: 15px;
order: 2;
}
#title-content {
flex: 0 0 100%;
max-width: 100%;
width: 100%;
padding-left: 15px;
padding-right: 15px;
margin-top: 15px;
order: 1;
}
@media (min-width: 500px) {
article {
flex: 0 0 60%;
max-width: 60%;
order: 1;
}
#title-content {
flex: 0 0 40%;
max-width: 40%;
margin-bottom: 15px;
order: 2;
}
}
.article-contents {
background-color: #dcedc8;
padding: 15px;
position: sticky;
top: 15px;
}
h1 {
font-size: 20px;
margin-top: 0;
margin-bottom: 0;
}
h2 {
font-size: 18px;
}
p {
min-height: 500px;
padding: 15px;
background-color: #eee;
}
li.active {
font-weight: bold;
}
a {
text-decoration: none;
color: #007bff;
}
a:hover {
text-decoration: none;
color: #007bff;
}
/* Блок оглавления */
html {
scroll-behavior: smooth;
/* Плавный переход к якорям */
}
.toc-label {
height: 100%;
margin-top: 15px;
}
.sticky-block { /* Прилипающий блок */
position: sticky;
top: 15px;
}
.toc-block {
padding: 1.5rem;
line-height: 1;
border: 1px solid #ebebeb;
border-radius: 3px;
position: relative;
}
.toc-block ul {
list-style: none;
padding: 0;
margin: 0;
}
.toc-block > ul {
height: 100%;
transition: opacity 0.5s ease-out, height 0.5s ease 0.5s;
}
.toc-block > ul.close {
opacity: 0;
height: 0;
transition: opacity 0.5s ease-out, height 0.5s ease 0.5s;
}
:target {
/* Отступ к прокручиваемому якорю */
scroll-margin-top: 2rem;
padding-top: 50px;
margin-top: -50px;
}
.toc-block ul li {
font-size: 0.9rem;
line-height: 1.2;
margin-top: 10px;
}
.toc-block ul ul {
margin-left: 10px;
}
.toc-block li a {
text-decoration: none;
opacity: 0.65;
}
.toc-block li a.highlight {
opacity: 1;
display: list-item;
list-style-type: disc;
}
.toc-close-open {
text-align: right;
position: absolute;
bottom: 5px;
right: 5px;
line-height: 1;
cursor: pointer;
font-size: 0.9rem;
opacity: 0.7;
transition: .5s;
}
.toc-close-open:hover {
opacity: 1;
}
@media (max-width: 960px) {
.toc-label {
position: fixed !important;
top: auto;
right: 0;
left: 0;
bottom: 0;
background: azure;
z-index: 1000;
height: unset;
}
.toc-block {
border: none;
padding: 0.5rem 1rem;
}
.toc-block ul li {
font-size: 1rem;
}
}
</style>
</head>
<body>
<header class=“container”>
<div>
ШАПКА
</div>
</header>
<main class=“container entry-content”>
<article class=“article”>
<h1>Заголовок</h1>
<p>Контент…</p>
<h2>Раздел 1</h2>
<p>Контент…</p>
<h2>Раздел 2</h2>
<p>Контент…</p>
<h2>Раздел 3</h2>
<p>Контент…</p>
<h2>Раздел 4</h2>
<p>Контент…</p>
<p>Контент…</p>
</article>
<div class=“toc-label”></div>
</main>
<footer class=“container”>
<div>
ПОДВАЛ
</div>
</footer>
<script>
document.addEventListener(‘DOMContentLoaded’, function() {
/* Создание содержания */
let
rollUp = ‘Свернуть’,
expand = ‘Развернуть’,
output = document.createDocumentFragment(),
entryContent = document.querySelector(‘.entry-content’),
headers2 = entryContent.querySelectorAll(‘h2’), // Ищем заголовки только в блоке с контентом
headers3 = entryContent.querySelectorAll(‘h3’),
wrapper = document.createElement(‘nav’),
title = document.createElement(‘div’),
ul = document.createElement(‘ul’),
divCloseOpen = document.createElement(‘div’), // div для кнопки скрыть Содержимое
tocLabel = document.querySelector(‘.toc-label’); // Нужно разместить элемент с этим классом где нужно вывести TOC
wrapper.classList.add(‘toc-block’);
title.style.fontWeight = ‘bold’;
title.textContent = ‘Содержание:’;
output.appendChild(wrapper);
wrapper.appendChild(title);
wrapper.appendChild(ul);
divCloseOpen.classList.add(‘toc-close-open’);
divCloseOpen.innerHTML = rollUp;
ul.after(divCloseOpen);
/* Добавляем один класс для всех h2 и h3 и получаем все заголовки */
headers2.forEach(function(item, index) {
item.classList.add(‘header-toc’);
});
headers3.forEach(function(item, index) {
item.classList.add(‘header-toc’);
});
let allHeaders = document.querySelectorAll(‘.header-toc’);
allHeaders.forEach(function(item, index) {
let
li = document.createElement(‘li’),
link = document.createElement(‘a’);
if (item.id === ”) {
item.id = ‘id-‘ + index;
}
link.href = ‘#’ + item.id;
link.textContent = item.textContent;
li.appendChild(link);
if (item.localName == ‘h3’) {
let tocBlockUl = wrapper.querySelector(‘.toc-block ul’);
if (tocBlockUl.lastChild.lastChild.localName == ‘ul’) {
tocBlockUl.lastChild.lastChild.appendChild(li);
} else {
let ul_h3 = document.createElement(‘ul’);
ul_h3.appendChild(li);
ul.lastChild.appendChild(ul_h3);
}
} else {
ul.appendChild(li);
}
});
tocLabel.appendChild(output);
// Массив ссылок в блоке toc (оглавление)
var toc;
// Массив контента (ссылки относятся к контенту)
var content = [];
// Вызов функции prepare после загрузки HTML
prepare();
sync();
/* Эта функция получает все ссылки и содержимое toc (оглавление) и сохраняет тему */
function prepare() {
// Получить все ссылки toc (оглавление)
toc = document.querySelectorAll(‘.toc-block a’);
// Получить контент, чтобы ссылка ссылалась на него
toc.forEach(function(link) {
var id = link.getAttribute(“href”);
var element = document.querySelector(id);
content.push(element);
});
// Синхронизировать toc (оглавление) с частью контента, которая видна в окне просмотра при прокрутке
window.addEventListener(“scroll”, sync, false);
}
/*
Эта функция проверяет, виден ли элемент в области просмотра
@argument {String} элемент, который нам нужно проверить
@returns true, если элемент виден в окне просмотра, иначе вернуть false
*/
function isElementInViewport(element) {
// Получить позицию элемента
var rect = element.getBoundingClientRect();
// Вернуть true, если часть элемента видна
return (rect.bottom >= 0 && rect.top <= (window.innerHeight || document.documentElement.clientHeight));
// Пока нам нужно проверить, весь ли элемент виден в окне просмотра
// return (rect.top >= 0 &&
// rect.bottom <= (window.innerHeight || document.documentElement.clientHeight));
}
/* Эта функция выделяет ссылки toc (оглавление), которые видны в области просмотра */
function sync() {
// Проверить весь контент
for (var i = 0; i < content.length; i++) {
// Если контент виден, добавить класс highlight, иначе убрать highlight
if (isElementInViewport(content[i])) {
toc[i].classList.add(‘highlight’);
} else {
toc[i].classList.remove(‘highlight’);
}
}
}
/* Функция свернуть Содержимое */
var tocCloseOpen = document.querySelector(‘.toc-close-open’);
tocCloseOpen.addEventListener(‘click’, hiddenCloseClick);
function hiddenCloseClick(elem) {
if (elem.target.textContent == rollUp) {
elem.target.textContent = expand;
} else {
elem.target.textContent = rollUp;
}
let x = document.querySelector(‘.toc-block > ul’);
x.classList.toggle(‘close’);
};
/* Функция делает сайдбар липким если есть Содержание */
var tocBlock = document.querySelector(‘.toc-block’);
var sidebar = document.querySelector(‘.toc-label’);
if (window.screen.width > 960) {
if (tocBlock) {
sidebar.classList.add(‘sticky-block’);
}
} else {
let tocCloseOpen = document.querySelector(‘.toc-close-open’);
// Если есть Содержание то сварачиваем его для мобильной версии
if (tocCloseOpen) {
if (tocCloseOpen.textContent == rollUp) {
tocCloseOpen.textContent = expand;
} else {
tocCloseOpen.textContent = rollUp;
}
let x = document.querySelector(‘.toc-block > ul’);
x.classList.toggle(‘close’);
}
}
}, false); // конец addEventListener DOMContentLoaded
</script>
</body>
|
position: sticky;
. Некоторые моменты при оформлении липкого блока можно посмотреть здесь.Автоматический вывод оглавлений статьи в WordPress
Table of Contents Plus (Michael Tran) — мощный и популярный плагин, который автоматически создает блок содержания в статьях. Имеет различные настройки. Можо выводить во всех постах или использовать шорткод, создавать блок оглавлений при наличии заданного количества заголовков в статье.
Подборка решений оглавлений статей в HTML
Несколько интересных примеров для оформления оглавлений статей для вдохновения или применения.