Szukałem rozwiązania jak zaimplementować znaczniki i klasy Bootstrapa w nawigacji po stronach posta w WordPressie. Znalazłem przeróżne, głównie skomplikowane filtry lub klasy i postanowiłem że sam coś napiszę. Domyślnie WP wyświetla napis 'Starsze posty' i 'Nowsze posty', albo to co podamy w argumentach funkcji. Można dodać klasy, ale tak czy inaczej dostaniemy taką surową formę:
<div class="nav-links"> <div class="nav-previous"> <a href="https://akademia.gaum.prostykod.pl/page/3/?s=zarz%C4%85dzanie" >Starsze wpisy</a> </div> <div class="nav-next"> <a href="https://akademia.gaum.prostykod.pl/?s=zarz%C4%85dzanie" >Nowsze wpisy</a> </div> </div>
Mi zależy na czymś takim jak na zdjęciu:
Zupełnie inna struktura kodu. Postanowiłem zatem wykorzystać oryginalną funkcję get_the_posts_navigation() do stworzenia podobnej, ale tworzącej kod wg Bootstrapa i z dodatkową obsługą numerów stron.
function sb5_get_the_posts_navigation( $args = array() ) { global $paged, $wp_query; $max_page = $wp_query->max_num_pages; $nextpage = (int) $paged + 1; if ($max_page < 2) return ''; $args = wp_parse_args( $args, array( 'prev_text' => __( 'Older posts' ), 'next_text' => __( 'Newer posts' ), 'screen_reader_text' => __( 'Posts navigation' ), 'aria_label' => __( 'Posts' ), 'class' => 'page-link', 'numbers' => false ) ); $navigation = ''; // Don't print empty markup if there's only one page. if ( $max_page > 1 ) { $navigation = '<nav aria-label="' . $args["aria_label"] . '"> <ul class="pagination justify-content-center">'; // Make sure the nav element has an aria-label attribute: fallback to the screen reader text. if ( ! empty( $args['screen_reader_text'] ) && empty( $args['aria_label'] ) ) { $args['aria_label'] = $args['screen_reader_text']; } if ( ! is_single() && ( $nextpage <= $max_page ) ) { $next_link = '<a href="' . next_posts( $max_page, false ) . '" class="' . $args["class"] . '">' . preg_replace( '/&([^#])(?![a-z]{1,8};)/i', '&$1', $args["next_text"] ) . '</a>'; } if ( ! is_single() && $paged > 1 ) { $prev_link = '<a href="' . previous_posts( false ) . '" class="' . $args["class"] . '">' . preg_replace( '/&([^#])(?![a-z]{1,8};)/i', '&$1', $args["prev_text"] ) . '</a>'; } if ( isset($prev_link) ) { $navigation .= '<li class="page-item">' . $prev_link . '</li>'; } else { $navigation .= '<li class="page-item disabled"> <a class="' . $args["class"] . '">' . $args["prev_text"] . '</a> </li>'; } if ($args["numbers"] && $max_page > 2 && $max_page < 7) { for ($i=1; $i<=$max_page; $i++) { if ($paged != $i) { $navigation .= '<li class="page-item"><a class="'. $args["class"] . '" href="' .get_pagenum_link($i). '">' . $i . '</a></li>'; } else { $navigation .= '<li class="page-item active"><span class="page-link">' . $i . '</span></li>'; } } } else if ($args["numbers"] && $max_page >= 7) { if ($paged >= 3) $navigation .= '<li class="page-item"><a class="' . $args["class"] . '" href="' .get_pagenum_link(1). '">1</a></li>'; if ($paged >= 4) { $navigation .= '<li class="page-item "><span class="page-link">...</span></li>'; } $last_step = 2; if ($paged == 1) $last_step = 3; $first_step = 1; if ($paged == $max_page) $first_step = 2; if ($paged >= 1) for ($i = $paged-$first_step; $i<$paged+$last_step; $i++) { if ($i <= 0 || ($i == $max_page && $i!=$paged) || $i > $max_page) continue; if ($paged != $i) { $navigation .= '<li class="page-item"><a class="' . $args["class"] . '" href="' .get_pagenum_link($i). '">' .$i. '</a></li>'; } else { $navigation .= '<li class="page-item active"><span class="page-link">' . $i . '</span></li>'; } } if (($max_page - $paged) >= 3) { $navigation .= '<li class="page-item "><span class="page-link">...</span></li>'; } if ($paged < $max_page) $navigation .= '<li class="page-item"><a class="' . $args["class"] . '" href="' .get_pagenum_link($max_page). '">' . $max_page . '</a></li>'; } if ( isset($next_link) ) { $navigation .= '<li class="page-item">' . $next_link . '</li>'; } else { $navigation .= '<li class="page-item disabled"> <a class="' . $args["class"] . '">' . $args["next_text"] . '</a> </li>'; } $navigation .= '</ul></nav>'; } return $navigation; }
Omówienie kodu
W odróżnieniu od oryginału, moja funkcja jest bardziej samodzielna, ale do tego potrzebuje dostęp do dwóch zmiennych globalnych: $paged – numer aktualnej strony, i $wp_query – obiekt zawierający wynik zapytania do bazy WP.
$max_page
Dzięki dostępowi do $wp_query wiemy ile jest wszystkich stron i możemy zadecydować, czy wyświetlenie linków jest sensowne i jaką formę powinno przybrać. Wartość $wp_query->max_page przypisujemy do $max_page i w linii nr 7 sprawdzamy czy stron jest więcej niż jedna. Jeżeli nie, to kończymy funkcję zwracając pusty ciąg. Żaden znacznik nie zostanie wyświetlony.
$nextpage
Warto od razu wiedzieć jaki numer będzie miała następna strona. Choćby po to, by sprawdzić, czy nie wychodzi poza zakres, czyli jest większy niż $max_page.
$args
Od linii nr 9 zaczyna się sprawdzanie przypisanych paramentów. Dzięki funkcji wp_parse_args() jesteśmy w stanie dopisać domyślne wartości dla niepodanych wartości tablicy $args. Dla przykładu nie trzeba podawać wartości dla nazwy linków. System podstawi wartości domyślne. W odróżnieniu od oryginału zmodyfikowana została wartość dla klucza 'class', na bootstrapowe 'page-link'. Od siebie dodałem 'numbers', czyli boolowski parametr decydujący, czy mają być wyświetlone linki z numerami stron. Domyślnie nie będą wyświetlane.
$navigation
Zmienna przechowująca kod HTML odpowiedzialny za nawigację z parametrami Bootstrapa. Jeżeli wartość $max_page jest większa niż 1 system rozpocznie przypisywanie kodu do $navigation. W liniach 26, 27 oraz 120 mamy obudowę dla paginacji.
$next_link i $prev_link
Od 34 do 39 linii mamy kod odpowiedzialny za wygenerowanie kodu HTML dla znacznika A, czyli linku "wstecz" i "do przodu". Dla poprawnego wygenerowania linku dla następnej strony musimy sprawdzić czy wyświetlana strona nie jest stroną pojedynczego posta oraz czy numer następnej strony nie jest większy niż $max_page. W tym celu korzystamy z funkcji is_single() i porównania $nextpage <= $max_page. Jeżeli warunki są spełnione, tworzymy zmienną $next_link i przypisujemy kod HTML.
W linii 35 zwróć uwagę na funkcję next_posts(). Jej wynikiem jest link url do następnej strony. Ma dwa argumenty: $max_page i $echo. Drugi odpowiada za wyświetlanie wartości linku. Jeżeli wpiszemy 'false', to funkcja wyświetli wartość zamiast przypisać ją do ciągu $next_link. W linii 38 jest podobna funkcja previous_posts(), odpowiedzialna za adres url do poprzedniej strony. Różni się tym, że ma tylko argument $echo.
Między liniami 42 i 50 system sprawdza czy zmienna $prev_link istnieje. Jeżeli tak, to do $navigation przypisana wartość $prev_link obudowana kodem linii listy punktowanej '<li>'. Jeżeli nie istnieje $prev_link, to do $navigation przypisywany jest kod HTML z wygaszonym, nieaktywnym linkiem.
Podobnie jest w liniach 110 – 118. Tam sprawdzamy czy istnieje $next_link.
$args["numbers"]
Jeżeli chcemy wyświetlić linki z numerami stron, co jest bardzo pomocne przy większej ilości stron, to wystarczy przypisać wartość 'true' do parametru $args["numbers"]. Za to rozwiązanie odpowiada najdłuższa część kodu – od linii 52 do 107.
Za wyświetlenie linku do strony o konkretnym numerze odpowiada funkcja get_pagenum_link().
Numeracja ma sens jeżeli stron jest więcej niż dwie. W mojej funkcji zastosowałem ograniczenie, które sprawdza ile jest stron i jeżeli jest mniej niż 7, to wyświetla wszystkie linki. Jeżeli jest inaczej, to wyświetla pierwszą i ostatnia stroną oraz aktualną, poprzednią i następną. Zapobiega to wynaturzeniom przy bardzo dużej ilości stron. Pomyśl jak wyglądałaby paginacja dla stu stron?
W pierwszym przypadku zadanie jest proste. Dzięki pętli for dodajemy kolejne linki do $navigation. W linii 59 sprawdzamy czy wartość pętli odpowiada numerowi strony. Jeżeli nie, to dodajemy zwykły link. Jeżeli tak, to musimy dodać klasę 'active' do pozycji listy '<li>'. Trudniej się robi, gdy stron jest minimum 7.
Krok po kroku
- Zaczynamy od sprawdzenia czy numer aktualnej strony to co najmniej 3. Jeżeli tak, to wyświetlamy link dla pierwszej strony. Jeżeli strona ma numer mniejszy od 3, to link do strony 1 zostanie dodany w poniższej pętli 'for'.
- Dalej czy strona jest większa czy równa 4. Jeżeli tak, to musimy dodać trzykropek czyli przerywnik, który odizoluje link do strony 1 od pozostałych.
- Tworzymy dwie nowe wartości: $last_step = 2 i $first_step = 1. Jeżeli jesteśmy na pierwszej stronie, to $last_step zwiększa wartość do 3, a jeżeli na ostatniej to rośnie wartość $first_step do 2. Wartości te są pomocne przy logice odpowiedzialnej za wyświetlanie linków do pierwszej lub ostatniej strony w pętli 'for'.
- W linii 87 jest kluczowa pętla 'for' dla linków numerycznych. Wartość początkowa obliczona jest na różnicę między numerem strony i $first_step. Wartość końcowa to suma numeru strony i $last_step.
- Dodatkowe zabezpieczenie jest poniżej. Jeżeli wartość pętli to 0 lub mniej albo numer strony jest równy $max_page i jednocześnie numer strony nie jest wartością pętli albo wartość pętli jest większa od $max_page, to krok pętli jest pomijany. Wystarczy, że jeden z trzech warunków jest spełniony.
- Następnie pozostaje sprawdzić czy wartość pętli jest równa numerowi strony. Wtedy przypisujemy nieaktywny link, a jeżeli nie, to zwykły.
- Na koniec system sprawdza czy numer strony jest mniejszy od $max_page i jeżeli to prawda, to wyświetla link do ostatniej strony.
Podsumowanie
I na tym koniec. Funkcję można rozbudować od większą liczbę numerów stron lub dodatkowe kroki dla bardzo dużej ilości stron. Jeżeli mamy np. 30 stron, to przejście z pierwszej strony do 15 teraz trochę potrwa.