Co to są filtry w WordPressie?

Filtry kojarzą się z czymś, dzięki czemu możesz odsiać niepotrzebne rzeczy, np. fusy kawy, cząstki PM lub zarazki. Filtry w WordPressie to coś znacznie więcej, bo umożliwiają dowolne modyfikowanie danych, a nawet zastąpienie ich zupełnie innymi danymi. To tak jakby filtr w maseczce zastępował spaliny świeżym górskim powietrzem 😉

Najlepiej wyjaśnić to na przykładzie. Załóżmy, że piszesz wtyczkę, która wita świeżo zarejestrowanego użytkownika. Wygląda to mniej więcej tak:

function greet_the_user() {
    $greeting = "Witaj na mojej stronie!";
    return $greeting;
}

Wtyczka zaczyna się cieszyć popularnością, ale zgłasza się do ciebie użytkownik, który chciałby, aby komunikat był spersonalizowany. Nie ma sprawy, zmieniasz kod:

function greet_the_user() {
    $user = wp_get_current_user();
    $name = $user->display_name;
    $greeting = $name . ", witaj na mojej stronie!";
    return $greeting;
}

Teraz komunikat będzie brzmiał np. „Anna, witaj na mojej stronie!”.

Ale wtedy zgłasza się do ciebie kilku innych użytkowników i mówi, że ta zmiana wszystko im psuje i oni by woleli, żeby było po staremu. Masz ci los! Głowisz się, co tu zrobić, żeby pogodzić potrzeby użytkowników, aż w końcu decydujesz się na użycie filtra:

function greet_the_user() {
    $greeting = "Witaj na mojej stronie!";
    $greeting = apply_filters( 'the_greeting', $greeting );
    return $greeting;
}

Teraz domyślnie komunikat brzmi „Witaj na mojej stronie!”, ale każdy może go dowolnie zmienić filtrem the_greeting. Jeśli masz ochotę wyświetlić imię użytkownika, możesz skorzystać z filtra w następujący sposób:

add_filter( 'the_greeting', 'my_custom_greeting' );
function my_custom_greeting( $greeting ) {
    $user = wp_get_current_user();
    $name = $user->display_name;
    $greeting = $name . ", witaj na mojej stronie!";
    return $greeting;
}

A mój syn pewnie zmieniłby ten komunikat następująco 😉

add_filter( 'the_greeting', 'hejka' );
function hejka( $greeting ) {
    $greeting = "Hejka!";
    return $greeting;
}

Pierwszy parametr funkcji add_filter to nazwa filtra (the_greeting w naszym przypadku), a drugi to nazwa funkcji, która ma być wykonana podczas wywołania filtra.

Kod należy zamieścić w pliku functions.php w motywie potomnym lub skorzystać z wtyczki typu Code Snippets. To oznacza, że nie trzeba zmieniać niczego w kodzie wtyczki, a tym samym nasze zmiany nie przepadną podczas jej aktualizacji.

Funkcja apply_filters wywoła po kolei wszystkie filtry the_greeting zarejestrowane za pomocą add_filter, a dopiero na samym końcu zwróci dane. Każdy ma szansę dorzucić swoje trzy grosze. Prawda, że genialne?

Przekazywanie do filtra dodatkowych informacji

Funkcja apply_filters może przekazywać więcej informacji do filtra, a nie tylko $greeting. W tym przypadku dobrym pomysłem jest przekazanie do filtra obiektu użytkownika:

function greet_the_user() {
    $greeting = "Witaj na mojej stronie!";
    $user = wp_get_current_user();
    $greeting = apply_filters( 'the_greeting', $greeting, $user );
    return $greeting;
}

Co ważne, taka zmiana w kodzie naszej wtyczki nie wpływa na filtry zarejestrowane funkcją add_filter. Nie musisz więc informować wszystkich o tej zmianie.

Przykłady prawidłowego wywołania naszego filtra to:

→ brak jakichkolwiek parametrów w funkcji my_custom_greeting:

add_filter( 'the_greeting', 'my_custom_greeting' );
function my_custom_greeting() {
    $greeting = "Hejka!";
    return $greeting;
}

→ jeden parametr w funkcji:

add_filter( 'the_greeting', 'my_custom_greeting' );
function my_custom_greeting( $greeting ) {
    $greeting = "Cześć czołem! " . $greeting;
    return $greeting;
}

→ dwa parametry w funkcji. Uwaga! Jeśli wykorzystujesz więcej niż jeden parametr funkcji, musisz podać ich liczbę przy rejestrowaniu filtra (to ta dwójka na końcu):

add_filter( 'the_greeting', 'my_custom_greeting', 10, 2 );
function my_custom_greeting( $greeting, $user ) {
    $name = $user->display_name;
    $greeting = $name . ", witaj na mojej stronie!";
    return $greeting;
}

Kolejność parametrów $greeting$user ma znaczenie i powinna się zgadzać z tym, co jest w funkcji apply_filters wywołującej nasz filtr. Natomiast nazwy tych parametrów mogą być inne niż w apply_filters. W tym przykładzie drugi parametr nazwałam $customer, a nie $user. Tak też jest poprawnie. Ważne, żeby potem w funkcji używać nazwy $customer, a nie $user.

add_filter( 'the_greeting', 'my_custom_greeting', 10, 2 );
function my_custom_greeting( $greeting, $customer ) {
    $name = $customer->display_name;
    $greeting = $name . ", witaj na mojej stronie!";
    return $greeting;
}

Priorytety filtrów

Funkcja add_filter, oprócz nazwy filtra i nazwy funkcji, przyjmuje jeszcze dwa opcjonalne parametry: priorytet i liczbę parametrów przekazanych do funkcji. Im niższy priorytet, tym wcześniej zostanie wywołana funkcja powiązana z filtrem. Jeśli nie podasz priorytetu, zostanie zastosowany priorytet domyślny 10.

W poniższym przykładzie wszystkie funkcje mają priorytet domyślny 10 i WordPress wywoła je po kolei: the_greeting_1, the_greeting_2the_greeting_3. Ostatecznie treść przywitania zostanie zastąpiona tekstem „The greeting 3”:

add_filter( 'the_greeting', 'the_greeting_1' );
add_filter( 'the_greeting', 'the_greeting_2' );
add_filter( 'the_greeting', 'the_greeting_3' );

function the_greeting_1( $greeting ) {
  return "The greeting 1";
}

function the_greeting_2( $greeting ) {
  return "The greeting 2";
}

function the_greeting_3( $greeting ) {
  return "The greeting 3";
}

Jednak jeśli zastosujesz priorytety, WordPress wywoła wszystkie funkcje zgodnie z ich priorytetami: the_greeting_3 (priorytet 1), the_greeting_1 (priorytet 100) i the_greeting_2 (priorytet 9999). Ostatecznie treść przywitania to „The greeting 2”:

add_filter( 'the_greeting', 'the_greeting_1', 100 );
add_filter( 'the_greeting', 'the_greeting_2', 9999 );
add_filter( 'the_greeting', 'the_greeting_3', 1 );

function the_greeting_1( $greeting ) {
  return "The greeting 1";
}

function the_greeting_2( $greeting ) {
  return "The greeting 2";
}

function the_greeting_3( $greeting ) {
  return "The greeting 3";
}

Skrócony zapis filtrów

Czasami spotkasz się ze skróconymi zapisami filtra. Nie musisz nazywać funkcji powiązanej z filtrem, lecz użyć zapisu function() {}:

add_filter( 'the_greeting', function( $greeting ) {
  return "Hejka!";
} );

Jeśli filtr ma zwrócić true lub false, możesz jeszcze bardziej pójść na skróty i napisać:

add_filter( 'example_filter', '__return_true' );

lub:

add_filter( 'example_filter', '__return_false' );

Najczęstsze błędy przy używaniu filtrów

Jeśli zarejestrowałeś filtr, ale coś jest z nim nie tak, być może popełniasz jeden z poniższych błędów:

1. Nieprawidłowa liczba parametrów.

Pamiętaj, że użycie więcej niż jednego parametru w funkcji filtrującej wymaga podania liczby parametrów. Poniższy kod zwróci błąd:

add_filter( 'the_greeting', 'my_custom_greeting' );
function my_custom_greeting( $greeting, $user ) {
    $name = $user->display_name;
    if ( $user->ID == 45 ) {
        return $name . ", witaj na mojej stronie!";
    }
}

Jeśli włączysz tryb debugowania, zobaczysz następujący komunikat:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function my_custom_greeting(), 1 passed in /app/wp-includes/class-wp-hook.php on line 310 and exactly 2 expected in /app/wp-content/themes/astra-child/functions.php:40

2. Filtr niczego nie zwraca.

Kod w powyższym przykładzie zawiera jeszcze jeden błąd, choć nie znajdzie on odzwierciedlenia w logach. A mianowicie nie zwraca niczego dla użytkownika o ID innym niż 45. Filtr zawsze musi coś zwracać. Poprawiony kod to na przykład:

add_filter( 'the_greeting', 'my_custom_greeting', 10, 2 );
function my_custom_greeting( $greeting, $user ) {
    $name = $user->display_name;
    if ( $user->ID == 45 ) {
        return $name . ", witaj na mojej stronie!";
    }
    return $greeting;
}

3. Używanie globalnych obiektów zamiast tych przekazanych jako parametr funkcji.

Załóżmy, że chcesz trochę zmodyfikować HTML dla ceny produktów WooCommerce, tak żeby HTML zawierał ID produktu. WooCommerce ma do tego specjalny filtr woocommerce_get_price_html. Możesz użyć go w ten sposób:

add_filter( 'woocommerce_get_price_html', function( $price ) {
    global $product;
    if ( $product ) {
        return '<div class="price-product-' . $product->get_id() . '">' . $price . '</div>';
    }
} );

Teraz cena produktu będzie zawierała ID produktu:

<div class="price-product-743">
    <span class="woocommerce-Price-amount amount"><span class="woocommerce-Price-currencySymbol">$</span>567.00</span>
</div>

Zauważasz jednak z niepokojem, że wszystkie produkty, które masz w panelu bocznym (sidebarze) mają takie samo ID!

Co tu się stało? Okazuje się, że 177 to ID produktu, który jest aktualnie ustawiony jako globalny. Może się również zdarzyć, że globalny produkt nie będzie ustawiony (np. na stronie checkoutu) i wtedy warunek if ( $product ) nie będzie spełniony i filtr zwróci nic. Jak to naprawić?

Jeśli spojrzysz do kodu WooCommerce, zauważysz, że filtr woocommerce_get_price_html przekazuje do filtrów dodatkowy parametr $this, który w tym przypadku jest produktem:

return apply_filters( 'woocommerce_get_price_html', $price, $this );

Zamiast używać globalnego obiektu, zawsze używaj tego przekazanego jako parametr. Unikniesz wielu niespodzianek. Poprawiony kod będzie wyglądał tak (pamiętaj o podaniu liczby parametrów!):

add_filter( 'woocommerce_get_price_html', function( $price, $product ) {
    return '<div class="price-product-' . $product->get_id() . '">' . $price . '</div>';
}, 10, 2 );

Przykłady prawdziwych filtrów

WordPress udostępnia całą masę filtrów. Są one zaszyte w kodzie WordPressa i każda wtyczka i motyw może z nich korzystać. W dodatku każda wtyczka i motyw mogą dodawać własne filtry, więc prawie wszystko w WordPressie możesz dostosować do własnych potrzeb.

Jednym z popularniejszych filtrów WordPressa jest the_content. Umożliwia on zmiany w treści strony, wpisu, produktu itd. Kojarzysz wtyczkę Sierotki? Używa ona filtru the_content, żeby wyłapać wszystkie sierotki w tekście i „przykleić” je do następnego słowa za pomocą twardej spacji (&nbsp;). Dzięki temu sierotka nigdy nie będzie stała samotnie na końcu wiersza.

To samo wtyczka robi z tytułem wpisu i zajawką, ale wykorzystuje do tego filtry – odpowiednio – the_titlethe_excerpt. Wyobrażasz sobie zmieniać ręcznie wybrane spacje na twarde spacje? Brrr!

Bardziej zaawansowanym filtrem jest the_posts. Przekazuje on tablicę wpisów pobranych z bazy danych. Możesz usunąć z tej listy konkretne wpisy, ale możesz też dodać takie, których nie ma na tej liście.

Więcej filtrów znajdziesz na stronie https://codex.wordpress.org/. Pamiętaj, że większość wtyczek i motywów udostępnia własne filtry. Ich listę znajdziesz w dokumentacji lub… przeszukując kod motywu lub wtyczki.

Sprawdź swoją wiedzę!

Pora na zagadki! Znajdź błędy w poniższych fragmentach kodu. W każdym fragmencie jest dokładnie jeden błąd.

Zagadka 1

add_filter( 'the_title', 'my_custom_title' );
function custom_title( $title ) {
  return "Polecany wpis! " . $title;
}

Zagadka 2

add_filter( 'the_title', 'my_custom_title', 10, 2 );
function my_custom_title( $post_id, $title ) {
  if ( $post_id == 78 ) {
    return "Polecany wpis! " . $title;
  }
  return $title;
}

Zagadka 3

add_filter( 'the_greeting', 'my_custom_greeting', 10, 2 );
function my_custom_greeting( $greeting, $user ) {
    $name = $client->display_name;
    if ( $client->ID == 45 ) {
        return $name . ", witaj na mojej stronie!";
    }
    return $greeting;
}

Zagadka 4

apply_filters( 'the_greeting', function( $greeting ) {
    return "Hejka!";
} );

Zagadka 5

add_filter( 'the_title', 'my_custom_title', 2 );
function my_custom_title( $title, $post_id ) {
  if ( $post_id == 78 ) {
    return "Polecany wpis! " . $title;
  }
  return $title;
}

I jak? Udało się? Daj znać w komentarzu!

Pani Marta
Jestem Marta. Pani Marta. Na moim blogu dzielę się prostymi sposobami na bezwtyczkowe ulepszenie swojej strony WordPress. Jeśli brakuje Ci czegoś w tym wpisie lub chcesz, abym poruszyła temat, na którym Ci zależy, daj znać w komentarzu!

Dodaj komentarz

*

*

*

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *