Zbliżamy się wielkimi krokami do napisania bloku spis treści pozwalającego na dodawanie spisu treści (razem z linkami) do naszych postów na WordPressie. Tym razem zbudujemy grunt pod ten projekt tworząc shortcode, który treść przekazaną w odpowiednim formacie zamienia na spis treści właśnie.
Spis treści – jak działa short-code
Nasz shortcode działa w następujący sposób – przekazujemy do niego treść jak poniżej
[custom_ul]
**Tytuł Pierwszy#kotwica1**
**Tytuł Drugi#kotwica2**
**Tytuł Trzeci#kotwica3**
[/custom_ul]
Mamy tutaj tag oraz elementy wyróżnione znakami **. Wewnątrz elementów mamy część pierwszą – tytuł, oraz część drugą – kotwicę HTML. To wszystko jako content naszego kodu, między tagiem zamykającym i otwierającym.
Taki napisany kod powinien dać nam mniej więcej taki wynik:
<ul>
<li><a href="#kotwica1">Tytuł Pierwszy</a></li>
<li><a href="#kotwica2">Tytuł Drugi</a></li>
<li><a href="#kotwica3">Tytuł Trzeci</a></li>
</ul>
Te kotwice to mechanizmy, za pomocą których możemy utworzyć link do czegoś na stronie. W WordPressie tworzymy je bardzo łatwo – dodając nagłówek w panelu po prawej stronie w zakładce blok klikamy na zaawansowane, wybieramy „kotwica HTML” i wpisujemy nazwę kotwicy (bez znaku #).
Potem już tylko dodajemy nasz spis treści z odpowiednimi kotwicami.
Tworzymy projekt pluginu – pierwsze kroki
W folderze plugins, wewnątrz folderu wp-content w naszej instalacji WordPressa tworzymy folder o nazwie shortcode-TOC a w nim plik shortcode-TOC.php. Wklejamy następującą treść:
<?php
/**
* Plugin Name: Shortcode Builder
* Description: Create a shortcode for a Table of Contents.
* Version: 1.0
* Author: Your Name
*/
if (!defined('ABSPATH')) {
exit;
}
Jest to standardowa procedura bezpieczeństwa, którą powinniśmy już dość dobrze znać. Teraz, poniżej, dodajemy nasz shortcode w najprostszej postaci:
function custom_ul_shortcode($atts, $content = null) {
return $content;
}
add_shortcode('custom_ul', 'custom_ul_shortcode');
Tytułem bezpieczeństwa, musimy jeszcze utworzyć plik index.php w tym samym folderze o następującej treści:
<?php
// Silence is golden.
Możemy teraz włączyć nasz plugin w panelu admina w naszym WordPressie.
Problemy z contentem – niepotrzebne tagi </br>
Możemy teraz – po włączeniu pluginu – wypróbować nasz shortcode:
[custom_ul]
**Tytuł Pierwszy#kotwica1**
**Tytuł Drugi#kotwica2**
**Tytuł Trzeci#kotwica3**
[/custom_ul]
Jeżeli zobaczymy, co tam zostało wyplute, zauważymy coś mniej więcej takiego (w HTML):
</br>
"**Tytuł Pierwszy#kotwica1**"
</br>
"**Tytuł Drugi#kotwica2**"
</br>
"**Tytuł Trzeci#kotwica3**"
</br>
Od razu mówię – będą z tym problemy. Aby się ich ustrzec, wykonamy taką oto czynność:
function custom_ul_shortcode($atts, $content = null) {
$stripped_content = strip_tags($content, '<br />');
return $stripped_content;
}
add_shortcode('custom_ul', 'custom_ul_shortcode');
Funkcja strip_tags usuwa niepotrzebne tagi. Teraz już tych odstępów nieszczęsnych nie mamy. Wypada więc użyj wyrażenia regularnego i przeiterować po wszystkich elementach, dodając je do zmiennej output, którą zwrócimy:
function custom_ul_shortcode($atts, $content = null) {
$stripped_content = strip_tags($content, '<br />');
$pattern = '/\*\*(.*?)\*\*/';
preg_match_all($pattern, $stripped_content, $matches);
if (!empty($matches[1])) {
$output = '<p>';
foreach ($matches[1] as $match) {
$output .= "<span>$match</span>";
}
$output .= '</p>';
return $output;
}
return '';
}
add_shortcode('custom_ul', 'custom_ul_shortcode');
Mamy tutaj wzór wyrażenia regularnego a następnie zastosowanie go na wyczyszczonym z tagów </br> content. Jeżeli tam znajdzie się coś pasujące do naszego formatu, to przejdziemy po każdym pasującym elemencie i dodamy go wewnątrz tagu <span> do tagu <p>. Jeżeli regex niczego nie znajdzie – zwrócimy pusty string.
Powyższy kod da nam taki wynik HTML:
<p><span>Tytuł Pierwszy#kotwica1</span><span>Tytuł Drugi#kotwica2</span><span>Tytuł Trzeci#kotwica3</span></p>
Połowa sukcesu za nami.
Podziel elementy po znaku # – funkcja explode
Nasz tekst znajdujący się w każdym $match możemy podzielić za pomocą funkcji explode na część przed haszem i po haszu:
$parts = explode('#', $match);
Następnie możemy z parts wyłuskać tytuł:
$text = esc_html($parts[0]);
Podobnie możemy wyłuskać kotwicę, zakładając, że została przekazana:
$anchor = isset($parts[1]) ? esc_attr($parts[1]) : '';
Teraz możemy stworzyć nasz element <li> oraz <a>:
$output .= '<li>';
$output .= '<a href="#' . $anchor . '">' . $text . '</a>';
$output .= '</li>';
Wystarczy jeszcze zmienić tag główny z <p> na <ul> i nasza funkcja gotowa:
function custom_ul_shortcode($atts, $content = null) {
$stripped_content = strip_tags($content, '<br />');
$pattern = '/\*\*(.*?)\*\*/';
preg_match_all($pattern, $stripped_content, $matches);
if (!empty($matches[1])) {
$output = '<ul>';
foreach ($matches[1] as $match) {
$parts = explode('#', $match);
$text = esc_html($parts[0]);
$anchor = isset($parts[1]) ? esc_attr($parts[1]) : '';
$output .= '<li>';
$output .= '<a href="#' . $anchor . '">' . $text . '</a>';
$output .= '</li>';
}
$output .= '</ul>';
return $output;
}
return '';
}
add_shortcode('custom_ul', 'custom_ul_shortcode');
Już. Działa. Przyda się nam bardzo, gdy będziemy musieli zbudować komponent o nazwie spis treści. Uchylę rąbka tajemnicy, że nasz render.php będzie wyglądał dokładnie tak:
<div <?php echo get_block_wrapper_attributes(); ?>>
<?php echo do_shortcode('[custom_ul]'.$attributes["toc"].'[/custom_ul]');?>
</div>
Natomiast edit.js – cóż, tam się pobawimy Reactem i to ostro, warto odświeżyć sobie useState i useEffect. Jeżeli czujemy się na siłach, możemy sami spróbować taki blok napisać. Jeżeli nie – wkrótce go napiszemy.
Odnotujmy tylko, że shortcodes można wywoływać z poziomu PHP funkcją WordPressa do_shortcode.
Efekt smooth scroll – dodajemy własny JS
Jeżeli wypróbowaliśmy już nasz shortcode, mógł nie spodobać nam się sposób przeskakiwania do naszych kotwic – jest nagły, dzisiaj już takie przeskoki brzydko wyglądają. Docelowo zrobimy to sobie w naszym komponencie w pliku view.js, ale teraz go nie mamy.
Spróbujmy wejść na posta, do którego dodaliśmy shortcode jak i nagłówki z kotwicami odpowiednio nazwanymi (to nie muszą być nagłówki swoją drogą, ale idea spisu treści jest akurat taka).
Teraz wklejmy ten kod na tej stronie w konsoli developerskiej i zobaczmy różnicę:
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
});
});
Kod może wydawać nam się odrobinę trudny, to już zależy od naszego poziomu zaawansowania. Mamy tutaj querySelectorAll z dość zaawansowanym selektorem, który bierze wszystkie elementy <a>, które są linkami do kotwic.
Następnie mamy pętlę forEach, która dodaje listener na klik, który po pierwsze robi preventDefault, czyli zapobiega domyślnemu działaniu.
Po drugie, po kliknięciu wyszukujemy sobie w dokumencie, w drzewie DOM element, do którego kotwicy nasz link prowadzi (swoim atrybutem href) i wywołujemy na nim funckję scrollIntoView z określonym efektem 'smooth’ – po kliknięciu w link rzecz jasna.
Teraz musimy zrobić kilka rzeczy. Po pierwsze, tworzymy w naszym pluginie plik smooth.js, na razie o takiej treści:
console.log("hello smooth");
Po drugie, podłączamy w pliku shortcode-TOC.php nasz skrypt do pluginu:
function smooth_script()
{
wp_enqueue_script( 'my_custom_script', plugin_dir_url( __FILE__ ) . 'smooth.js' );
}
add_action('wp_enqueue_scripts', 'smooth_script');
Teraz po wejściu na stronę z postem (albo jakąkolwiek stronę) możemy zobaczyć nasz napis. A my zamiast tego chcemy wkleić nasz kod – ale uwaga, dopiero wtedy, gdy drzewo DOM jest gotowe:
window.addEventListener('DOMContentLoaded', function(){
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
document.querySelector(this.getAttribute('href')).scrollIntoView({
behavior: 'smooth'
});
});
});
});
Tyle wystarczy, aby mieć piękny efekt smooth. Teoretycznie moglibyśmy się bawić w dodawanie tego skryptu np. tylko do strony z pojedynczym postem albo strony zawierającej element TOC (nasz spis treści). Są na to sposoby.
Natomiast ten nasz kod jest dość uniwersalny. Plik wiele nie waży i dodaje event listenery do wszystkich linków do kotwic. A powiedzmy sobie szczerze – każdy link do kotwicy powinien mieć dzisiaj taki efekt.
Dzięki temu, na całej stronie będziemy go mieć.