Czym jest spis treści na stronie internetowej?
Spis treści na stronie internetowej pełni dokładnie taką samą rolę jak w książkach. Definicja z Wikipedii brzmi następująco:
Zestawienie tytułów i śródtytułów rozmaitego szczebla, wyróżniających rozdziały i podrozdziały, ujęte w postaci oddzielnego wykazu, najczęściej na osobnej stronie, pełniące rolę podstawowego przewodnika po zawartości dokumentu.
W przypadku artykułów internetowych taki spis pojawia się na ich początku i jest listą numerowaną. Lista ta zawiera tytuły i śródtytuły kolejnych sekcji i zazwyczaj odpowiada nagłówkom od h1 do h6. Na tej stronie znajdziesz taki spis i bardzo możliwe, że już go widziałeś. Jeśli jednak nie, to zerknij kilka wierszy wyżej.
Warto również, abyś sięgnął do słownika języka angielskiego. W wersji angielskiej spis treści jest nazywany table of contents, w skrócie toc. Poszukując informacji o internetowym spisie na portalach anglojęzycznych możesz się natknąć na wyżej wymienione nazwy.
Po co i dlaczego stworzyć spis treści?
Dzięki niemu czytelnik może szybciej i sprawniej poruszać się po książce, a w naszym przypadku po stronie internetowej. Spis treści jest szczególnie istotny przy dłuższych tekstach, które zawierają wiele sekcji oraz akapitów. Niestety, ale większość osób (w tym ja i zapewne ty również) nie czyta internetowych artykułów od deski do deski. Nasza pełna uwaga skupia się na początkowym fragmencie tekstu, ale później wiele osób traci koncentracje lub po prostu nie jest zainteresowana dalszym czytaniem. W moim przypadku bardzo często kończy się na przewijaniu strony i czytaniu jedynie wyróżnionych fragmentów artykuły (o ile taki artykuł jest dobrze sformatowany).
Spis treści pozwala użytkownikowi na wstępne zapoznanie się z artykułem, a także na szybkie i łatwe przemieszczanie się do wybranych fragmentów tekstu. Dodatkowo dobrze zbudowana lista może wspomóc działania SEO. Artykuł, wpis blogowy lub inny publikacja ze spisem treści może zyskać unikalny wygląd w wynikach wyszukiwania, co może przełożyć się na większy ruch na stronie i lepszy wskaźnik CTR.
Jak można stworzyć spis treści na WordPressie?
WordPress jest bardzo przyjaznym systemem, który pozwala na wiele modyfikacji. Jeśli chcesz utworzyć spis treści w tym CMS-ie, możesz skorzystać z następujących rozwiązań:
- wtyczka – gotowe rozwiązanie, które wymaga jedynie instalacji,
- robótki ręczne – spis treści możesz stworzyć ręczenie, dla każdego wpisu osobno,
- zrób to sam – jeśli chcesz mieć na swojej stronie własne rozwiązanie.
Wtyczka
To najszybsza opcja utworzenia spisu treści dla wielu publikacji, która nie wymaga zaawansowanych umiejętności programistycznych. Wystarczy, że zainstalujesz jedną z wtyczek, a następnie odpowiednio ją skonfigurujesz. Wśród popularnych pluginów znajdziesz między innymi:
- Easy Table of Contents,
- Table of Contents Plus,
- LuckyWP Table of Contents.
Jednak jak mówi tytuł tego wpisu, miało być bez wtyczek, więc przejdźmy dalej.
Robótki ręczne
Jeśli Twoja strona internetowa nie posiada wielu artykułów i publikujesz mało, to ręczne tworzenie spisu treści dla każdego tekstu nie powinno być bardzo problematyczne. Na początku każdej publikacji dodajesz listę numerowaną, w której umieszczasz odnośniki do poszczególnych sekcji. Dodatkowo musisz każdej sekcji nadać odpowiedni atrybut id, tak aby linki w spisie przenosiły użytkownika w odpowiednie miejsce we wpisie bądź artykule.
Niestety przy wielu artykułach i wysokiej częstotliwości publikacji ręczne tworzenie listy stanie się bardzo czasochłonne. Lepszym rozwiązaniem w takiej sytuacji jest automatyczne generowanie spisu treści. Tak jak wspomniałem wyżej, możesz wtedy skorzystać ze wtyczki. Jeśli jednak chcesz stworzyć własne rozwiązanie, to trochę Tobie w tym pomogę.
Zrób to sam
Czas, abyś przyjrzał się trzeciemu rozwiązaniu. Poniżej opisałem dwa sposoby automatycznego generowania spisu treści. Pierwszy metoda wykorzystuje do tego język PHP, a druga JavaScript. Nie będę cię przekonywać, że są to najlepsze rozwiązania. Znajdziesz w Internecie lepsze, jak i gorsze skrypty. Specjaliści i magicy od PHP czy JavaScript mogliby zapewne lepiej zoptymalizować kody, które za chwilę zobaczysz.
Mogę cię jedynie zapewnić, że testowałem wielokrotnie poniższe skrypty, dobrze się sprawowały i mnie nie zawiodły. Oczywiście możesz sam przetestować poniższe skrypty i modyfikować je według własnych potrzeb.
Generowanie spisu treści w PHP
Oto gotowa funkcja PHP, która wygeneruje spis treści w WordPressie dla wybranego przez ciebie tekstu.
function generate_toc($html, $url)
{
preg_match_all('|<h[2-6]>(.*)</h[2-6]>|iU', $html, $headings);
foreach ($headings[0] as $headingValue) {
$headingType = substr($headingValue, 2, 1);
$headingContent = substr(substr($headingValue, 4), 0, -5);
echo '<li class="li-' . $headingType . '"><a href="' . $url . '/#' . str_replace(' ', '-', strtolower($headingContent)) . '">' . $headingContent . '</a></li>';
}
}
A to przykładowy kod HTML, na podstawie którego omówię działanie powyższej funkcji PHP.
<section id="main-content">
<h1>Cześć!</h1>
<h2>Nagłówek początkowy</h2>
<p>Akapit pierwszy</p>
<h3>Nagłówek środkowy</h3>
<p>Akapit drugi</p>
<h2>Nagłówek końcowy</h2>
<p>Akapit trzeci</p>
</section>
Jednak zacznijmy od początku. Nasza funkcja przyjmuje dwa argumenty – $html oraz $url. Pod $html podstawimy tekst, na podstawie którego wygenerujemy spis treści. Natomiast odnośniki do sekcji utworzymy, wykorzystując do tego zmienną $url.
W pierwszej kolejności musimy znaleźć nasze śródtytuły. Za pomocą wyrażenia regularnego wyszukujemy w tekście nagłówki od h2 do h6. Zapis [2-6] odpowiada za to, które nagłówki zostaną uwzględnione. Na przykład:
- jeśli chcesz uwzględnić wszystkie nagłówki, użyj zapisu [1-6],
- jeśli chcesz uwzględnić tylko trzy najwyższe poziomy śródtytułów, skorzystaj z zapisu [1-3].
preg_match_all('|<h[2-6]>(.*)</h[2-6]>|iU', $html, $headings);
Po wykonaniu powyższego skryptu na naszej przykładowej treści w zmiennej $headings znajdą się następujące elementy:
- <h2>Nagłówek początkowy</h2>
- <h3>Nagłówek środkowy</h3>
- <h2>Nagłówek końcowy</h2>
Następnie za pomocą pętli przechodzimy przez wszystkie znalezione elementy i dla każdego z nich wykonujemy poniższe operacje.
foreach ($headings[0] as $headingValue) {
$headingType = substr($headingValue, 2, 1);
$headingContent = substr(substr($headingValue, 4), 0, -5);
echo '<li class="li-' . $headingType . '"><a href="' . $url . '/#' . str_replace(' ', '-', strtolower($headingContent)) . '">' . $headingContent . '</a></li>';
}
Działanie pętli rozpoczynamy od ustawienia dwóch zmiennych – $headingType oraz $headingContent. Z ich pomocą nasz kod stanie się bardziej czytelny.
Zmienna $headingType typu string przechowuje trzeci znak elementu (pamiętaj, że numeracja rozpoczyna się od 0). W naszym przypadku będą to cyfry od 2 do 6, które pomogą określić, z jakim nagłówkiem mamy do czynienia. $headingType wykorzystamy do ustawienia klasy CSS.
$headingContent, druga zmienna przechowuje treść naszych nagłówków (bez znaczników HTML). Jej wartości wyświetlimy użytkownikowi końcowemu, jako kolejne tytuły sekcji w naszym spisie treści.
Za pomocą echo wyświetlimy nasz kod HTML. W wyświetlanym kodzie wygenerujemy klasę CSS, adres URL oraz treść dla każdego elementu.
Nie pozostaje nam nic innego, jak odpowiednio ulokować skrypt i wywołać funkcję przy pomocy odpowiednich argumentów. W WordPressie możemy wykorzystać do tego get_the_content() oraz home_url($wp->request). Treść wpisu pobierzemy przy pomocy get_the_content(), a adres URL uzyskamy za pomocą home_url($wp->request). Poniżej możesz zobaczyć przykładowe wywołanie naszej funkcji PHP oraz jej wynik dla omawianego przypadku, który utworzy 3 odnośniki do sekcji. W miejscu domena.pl/przykladowy-wpis wyświetli się Twój adres URL.
<ol id="table-of-contents"><?php generate_toc(get_the_content(), home_url($wp->request)) ?></ol>
<ol id="table-of-contents">
<li class="li-2"><a href="domena.pl/przykladowy-wpis/#nagłówek-początkowy">Nagłówek początkowy</a></li>
<li class="li-3"><a href="domena.pl/przykladowy-wpis/#nagłówek-środkowy">Nagłówek środkowy</a></li>
początkowy">Nagłówek początkowy</a></li>
<li class="li-2"><a href="domena.pl/przykladowy-wpis/#nagłówek-końcowy">Nagłówek końcowy</a></li>
</o>
Niestety jest jeden problem. Jeśli klikniesz któryś z wygenerowanych odnośników, nic się nie wydarzy. No właśnie… Nasze nagłówki w treści nie mają (jeszcze) przypisanych atrybutów id. Możesz dodać je ręcznie, ale po co przemęczać się. Wykorzystamy do tego JavaScript, o czym dowiesz się w kolejnej sekcji.
Aktualizacja skryptu PHP (kwiecień 2023)
Może okazać się (w zależności od wersji WordPressa), że CMS automatycznie dodaje klasę do każdego nagłówka. W takiej sytuacji musisz uaktualnić wyrażenie regularne oraz zmienną $headingContent. W poniższym przykładzie kod uwzględnia automatycznie dodawaną klasę wp-block-heading do nagłówków.
function generate_toc($html, $url)
{
preg_match_all('|<h[2-6] class="wp-block-heading">(.*)</h[2-6]>|iU', $html, $headings);
foreach ($headings[0] as $headingValue) {
$headingType = substr($headingValue, 2, 1);
$headingContent = substr(substr($headingValue, 29), 0, -5);
echo '<li class="li-' . $headingType . '"><a href="' . $url . '/#' . str_replace(' ', '-', strtolower($headingContent)) . '">' . $headingContent . '</a></li>';
}
}
Generowanie atrybutów id
Działanie skryptu JS, który wygeneruje id dla śródtyułów, jest bardzo proste. Tworzymy dwie zmienne – articleSection oraz articleHeadings. articleSection to sekcja o id równym main-content. Zmienna articleHeadings będzie zawierać wszystkie nagłówki od h2 do h6, które są zawarte w naszej sekcji.
const generateHeadingsIds = () => {
const articleSection = document.getElementById('main-content')
const articleHeadings = articleSection.querySelectorAll('h2, h3, h4, h5, h6')
articleHeadings.forEach(heading => {
heading.id = heading.innerText.toLowerCase().replace(/\s+/g, '-')
})
}
Korzystając z pętli, przechodzimy przez każdy element zmiennej articleHeadings. Dla każdego pobranego nagłówka generujemy i ustawiamy atrybut id.
articleHeadings.forEach(heading => {
heading.id = heading.innerText.toLowerCase().replace(/\s+/g, '-')
})
Po wywołaniu i wykonaniu powyższego skryptu na naszej przykładowej treści, nagłówki będą prezentować się następująco:
- <h2 id=”nagłówek-początkowy”>Nagłówek początkowy</h2>
- <h3 id=”nagłówek-środkowy”>Nagłówek środkowy</h2>
- <h2 id=”nagłówek-końcowy”>Nagłówek końcowy</h2>
Jak możesz zaobserwować, id nagłówków generujemy na podstawie ich treści. Wszystkie litery są zamieniane na małe, a w miejscu spacji wstawiamy znak myślnika. Tak samo jest w skrypcie PHP, w którym tworzymy odnośniki do sekcji. Jednak przy korzystaniu ze znaków specjalnych w niektórych sytuacjach mogą pojawić się błędy. Co wtedy zrobić? Masz trzy możliwości:
- zignorować błędy (nie polecam tej drogi),
- udoskonalić skrypt, aby wychwytywał dodatkowe wyjątki,
- uprościć schemat tworzenia atrybutów id i odnośników.
Wybierając ostatnią drogę, czyli uproszczenie schematu, możesz na przykład nadać wszystkim elementom taką samą nazwę i na ich końcu dopisywać kolejne cyfry:
- <h2 id=”naglowek-1″>Nagłówek początkowy</h2>
- <h3 id=”naglowek-2″>Nagłówek środkowy</h2>
- <h3 id=”naglowek-3″>Nagłówek końcowy</h2>
Jednak pamiętaj, aby takich zmian dokonać w obu skryptach – PHP i JavaScript. Linki w spisie treści muszą odsyłać do odpowiednich id. Jeśli nie zachowasz tego samego schematu w obu skryptach, odnośniki do sekcji nie będą działać.
Generowanie spisu treści w JavaScript
Czas na drugie rozwiązanie, czyli JavaScript. Oto nasza gotowa funkcja JS, który wygeneruje dla nas spis treści. Poniższa funkcja obejmuje utworzenie spisu treści, jak i przypisanie atrybutów id dla nagłówków.
const generateToc = () => {
const articleSection = document.getElementById('main-content')
const articleHeadings = articleSection.querySelectorAll('h2, h3, h4, h5, h6')
const tableOfContents = document.getElementById('table-of-contents')
let finalHTML = ''
articleHeadings.forEach(heading => {
heading.id = heading.innerText.toLowerCase().replace(/\s+/g, '-')
finalHTML += `<li><a href="${window.location.href}#${heading.id}">${heading.innerText}</a></li>`
})
tableOfContents.innerHTML = finalHTML
}
A to przykładowy kod HTML, na podstawie którego omówię działanie naszego skryptu JS.
<ol id="table-of-contents"></ol>
<section id="main-content">
<h1>Cześć!</h1>
<h2>Nagłówek początkowy</h2>
<p>Akapit pierwszy</p>
<h3>Nagłówek środkowy</h3>
<p>Akapit drugi</p>
<h2>Nagłówek końcowy</h2>
<p>Akapit trzeci</p>
</section>
Zacznijmy od początku, czyli od zdefiniowania naszych zmiennych. Tworzymy cztery zmienne – trzy stałe (const) oraz jedną zmienną let. articleSection to nasza sekcja o id równym main-content. Do articleHeadings dodamy wszystkie nagłówki od h2 do h6, które są zawarte w naszej sekcji. tableOfContents to nasza lista z (jeszcze) pustym spisem treści. Listę odnośników do sekcji wygenerujemy przy pomocny zmiennej finalHTML.
const articleSection = document.getElementById('main-content')
const articleHeadings = articleSection.querySelectorAll('h2, h3, h4, h5, h6')
const tableOfContents = document.getElementById('table-of-contents')
let finalHTML = ''
Przechodzimy przez każdy element zmiennej articleHeadings i dla każdego z nich wykonujemy poniższe operacje.
articleHeadings.forEach(heading => {
heading.id = heading.innerText.toLowerCase().replace(/\s+/g, '-')
finalHTML += `<li><a href="${window.location.href}#${heading.id}">${heading.innerText}</a></li>`
})
Dla każdego pobranego nagłówka generujemy i ustawiamy atrybut id. W naszym przykładowym kodzie poniższe nagłówki ulegną zmianie na:
- <h2 id=”nagłówek-początkowy”>Nagłówek początkowy</h2>
- <h3 id=”nagłówek-środkowy”>Nagłówek środkowy</h2>
- <h2 id=”nagłówek-końcowy”>Nagłówek końcowy</h2>
Następnie dodajemy ciąg znaków do wcześniej utworzonej zmiennej o nazwie finalHTML. Na ten ciąg znaków będą składać się elementy naszego spisu treści w postaci odnośników do sekcji.
Ostatnia linijka kodu doda spis treści na stronę.
tableOfContents.innerHTML = finalHTML
Efekt końcowy dotyczący omawianego przykładu możesz zobaczyć poniższej. W miejscu domena.pl/przykladowy-wpis wyświetli się Twój adres URL.
<ol id="table-of-contents">
<li><a href="domena.pl/przykladowy-wpis/#nagłówek-początkowy">Nagłówek początkowy</a></li>
<li><a href="domena.pl/przykladowy-wpis/#nagłówek-środkowy">Nagłówek środkowy</a></li>
początkowy">Nagłówek początkowy</a></li>
<li><a href="domena.pl/przykladowy-wpis/#nagłówek-końcowy">Nagłówek końcowy</a></li>
</ol>
<section id="main-content">
<h1>Cześć!</h1>
<h2 id="nagłówek-początkowy">Nagłówek początkowy</h2>
<p>Akapit pierwszy</p>
<h3 id="nagłówek-środkowy">Nagłówek środkowy</h3>
<p>Akapit drugi</p>
<h2 id="nagłówek-końcowy">Nagłówek końcowy</h2>
<p>Akapit trzeci</p>
</section>
Który skrypt wybrać? PHP czy JavaScript?
Niestety, ale nie mam dla ciebie prostej odpowiedzi. Wszystko zależy od twoich potrzeb, możliwości programistycznych i priorytetów. Warto jednak abym wspomniał o dwóch istotnych elementach, czyli o SEO i obsłudze JavaScript.
Google potrzebuje dodatkowych zasobów oraz więcej czasu, aby przetworzyć stronę, która wykorzystuje JavaScript. Jeśli nasz spis jest wykonany w JavaScript, to przy pierwszych odwiedzinach naszej strony Google najprawdopodobniej nie wykryje żadnego spisu treści. Dopiero po uruchomieniu dodatkowych zasobów (o ile to się stanie) Google wykryje spis treści na stronie.
Dodatkowo u osób, u których JavaScript jest zablokowany lub nie działa z jakiś powodów, nasz spis treści nie wyświetli się. W przeglądarce Google Chrome możesz skorzystać z wtyczki Web Developer i wyłączyć obsługę JavaScript. W ten sposób możesz przekonywać się jak wyglądają strony, na których JS nie jest obsługiwany.
Biorąc pod uwagę dwa powyższe czynniki, PHP wydaje się lepszym wyborem. Jednak należy pamiętać, że przygotowany przeze mnie skrypt PHP generuje spis treści, ale nie atrybuty id dla śródtytułów. Są one nadal generowane przy pomocy JavaScript. W tej sytuacji (jeśli JavaScript nie będzie działał) roboty oraz zwykli użytkownicy zobaczą wygenerowany spis treści, ale odnośniki zawarte w nim nie będą działać.
Jak mogłeś zauważyć, powyższe rozwiązania nie są idealne. Pamiętaj, że możesz je udoskonalić! Mam nadzieję, że powyższe wskazówki pomogą Tobie w stworzeniu własnego spisu treści na WordPressie.