Pięć sprawdzonych w boju technik, których Twój programista API WordPress nie używa

Opublikowany: 2022-03-11

Jednym z najlepszych sposobów na podniesienie swojego statusu jako programisty WordPress, przynajmniej w oczach klientów, jest zdobycie umiejętności korzystania z interfejsów API. Oto typowy scenariusz implementacji interfejsu API WordPress: Twój klient prosi o dodanie widżetu do swojej witryny — na przykład widżetu subskrypcji e-mail. Pobierasz kod z ich usługi poczty e-mail innej firmy — być może jest to tag skryptu lub element iframe — wklejasz go na stronę i odpowiadasz klientowi: „OK!”

Niestety masz do czynienia z nieco bardziej wymagającym klientem i zauważa on następujące niedoskonałości:

  • Chociaż widżet, podobnie jak reszta witryny, zawiera czcionkę bezszeryfową, nie jest to odpowiednia. Widżet używa Helvetica zamiast zainstalowanej niestandardowej czcionki.
  • Formularz subskrypcji widżetu powoduje ładowanie nowej strony, co może być uciążliwe, jeśli zostanie umieszczone w połowie artykułu.
  • Wydaje się, że widżet potrzebuje dodatkowej chwili na załadowanie po pozostałej części strony, co jest niepokojące i tanie.
  • Klient chciałby, aby subskrybenci byli oznaczani metadanymi na podstawie postu, z którego subskrybowali, a widget nie oferuje niczego, co mogłoby zdalnie przypominać tę funkcjonalność.
  • Klient uważa za irytujące, że teraz będzie musiał zarządzać dwoma pulpitami nawigacyjnymi (wp-admin i obszarem administracyjnym usługi poczty e-mail).

W tym momencie może wydarzyć się jedna z dwóch rzeczy. Możesz zadeklarować te elementy jako „dobrze mieć” i uspokoić klienta o zaletach rozwiązania 80/20 lub możesz spełnić te prośby. Z mojego osobistego doświadczenia wiem, że spełnianie takich żądań — to znaczy demonstrowanie mistrzostwa w usługach stron trzecich — jest niezawodnym sposobem na przekonanie klienta, że ​​jesteś swego rodzaju czarodziejem WordPressa. Poza tym często fajnie jest to robić.

W ciągu ostatniej dekady używałem WordPressa jako platformy do konsumpcji API przeciwko prawdopodobnie 50 różnym API. Niektóre z najpopularniejszych interfejsów API to MailChimp, Google Analytics, Mapy Google, CloudFlare i Bitbucket. Ale co, jeśli musisz zrobić więcej, co jeśli potrzebujesz niestandardowego rozwiązania?

Jak stworzyć klienta API WordPress?

W tym artykule zamierzam rozwijać ogólny interfejs API „usług e-mail”, starając się, aby wszystko było jak najbardziej agnostyczne. Uważam jednak, że rozsądne jest założenie, że mamy do czynienia z interfejsem API JSON REST. Oto kilka podstawowych tematów, które mogą pomóc w zapoznaniu się z technicznymi punktami tego artykułu:

  • Rodzina funkcji WordPress HTTP
  • JSON
  • ODPOCZYNEK

Jeśli nie znasz tych tematów i jesteś zainteresowany głębiej, zatrzymaj się teraz i pobierz doskonałą aplikację Postman. Pozwala komunikować się z API bez pisania kodu.

Zrzut ekranu z pulpitu nawigacyjnego Postmana

Listonosz. Może moje ulubione narzędzie programistyczne?

Jeśli jednak w ogóle ich nie znasz, i tak czytaj dalej. Odbiorcy techniczni z pewnym doświadczeniem w zakresie WordPressa skorzystają z tego artykułu, ale postaram się wyjaśnić wartość każdej techniki w mniej techniczny sposób. Czytelnik nietechniczny pozostawi ten artykuł w stanie ocenić zwrot z inwestycji każdego punktu przed jego sponsorowaniem i ocenić jakość wdrożenia po dostarczeniu.

Uwaga: jeśli potrzebujesz szybkiego kursu przypominającego, możesz zapoznać się z naszym przewodnikiem WordPress REST API.

Bez dalszych wstępów, pozwólcie, że podzielę się z Wami kilkoma różnymi technikami, które doceniam w prawie każdym interfejsie API, projekcie i zespole, z którym pracuję.

Stany nieustalone: ​​kiedy je trzymać, kiedy je składać

W akapicie otwierającym zauważyłem, że dla klienta denerwuje się rozkraczanie dwóch obszarów administracyjnych: wp-admin i pulpitu nawigacyjnego ich usługi poczty e-mail. Dobrym sposobem rozwiązania tego problemu byłoby udostępnienie im widżetu pulpitu nawigacyjnego w wp-admin, który wyświetla podsumowanie ich ostatniej aktywności subskrybentów.

Zrzut ekranu widżetu pulpitu nawigacyjnego wp-admin

Przykład typu interfejsu użytkownika pulpitu nawigacyjnego, który możemy udostępnić w WordPress, aby zaoszczędzić naszym klientom podróż do ich zewnętrznego dostawcy usług poczty e-mail.

Ale z drugiej strony może to wymagać wielu żądań HTTP do zdalnego interfejsu API (API dostarczanego przez usługę poczty e-mail), co spowoduje długie ładowanie strony. Rozwiązaniem tego problemu z wydajnością jest przechowywanie wywołań API jako przejściowych. Ten artykuł w Kodeksie zawiera świetne wyjaśnienie, które zdecydowanie powinieneś przeczytać, ale streszczę to w ten sposób:

  1. Pobierz dane ze zdalnego interfejsu API.
  2. Przechowuj go za pomocą set_transient() z wybranym przez siebie czasem wygaśnięcia na podstawie własnej oceny wydajności, limitów szybkości i marginesu błędu w wyświetlaniu nieaktualnych danych w tej konkretnej aplikacji.
  3. Kontynuuj logikę biznesową — przetwarzanie danych, zwracanie wartości, niezależnie od przypadku.
  4. Kiedy potrzebujesz danych ponownie, na przykład przy następnym załadowaniu strony, sprawdź je w tymczasowej pamięci podręcznej za pomocą get_transient() , zanim dojdziesz do wniosku, że musisz je pobrać z interfejsu API.

Uważam, że jest to pomocna i realna podstawa, ale możesz pójść o krok dalej, jeśli pomyślisz przez chwilę o czasownikach REST. Z pięciu najpopularniejszych metod (GET, POST, PATCH, PUT, DELETE) tylko jedna z nich należy do tymczasowej pamięci podręcznej. Potrafisz zgadnąć który? To jest DOBRZE. W moich wtyczkach prawie zawsze mam klasę PHP dedykowaną do abstrahowania wywołań zdalnego interfejsu API, o którym mowa, a argumentem podczas tworzenia instancji tej klasy jest metoda HTTP. Jeśli to nie jest wywołanie GET, to w ogóle nie będę wywoływał żadnej warstwy pamięci podręcznej.

Co więcej, jeśli nie jest to wywołanie GET, to jest zrozumiałe, że podejmuję pewne działania, aby w jakiś sposób zmienić dane zdalne, na przykład dodając, edytując lub usuwając subskrybenta wiadomości e-mail. To może być dobry moment, aby unieważnić istniejącą pamięć podręczną dla tego zasobu, poprzez delete_transient() .

Wracając do naszego przykładu interfejsu API subskrypcji poczty e-mail WordPress, oto jak to działa w praktyce:

  • Widżet pulpitu nawigacyjnego do pokazywania ostatnich subskrybentów wywoła punkt końcowy API dla /subscribers za pośrednictwem żądania GET. Ponieważ jest to żądanie GET, jest przechowywane w mojej tymczasowej pamięci podręcznej.
  • Widżet paska bocznego do subskrybowania listy e-mailowej wywoła punkt końcowy API dla /subscribers za pośrednictwem żądania POST. Ponieważ jest to żądanie POST, nie tylko uniknie mojej tymczasowej pamięci podręcznej, ale także sprowokuje mnie do usunięcia odpowiedniej części mojej tymczasowej pamięci podręcznej, tak aby widżet pulpitu nawigacyjnego odzwierciedlał tego nowego subskrybenta.
  • Kiedy nazywam transjenty, często organizuję je, dosłownie nazywając je po zdalnym adresie URL API, który wywołuję. Jest to wygodny sposób na zidentyfikowanie prawidłowego stanu nieustalonego do usunięcia. Jeśli jest to punkt końcowy, który przyjmuje argumenty, połączę je w łańcuch i dodam je również do nazwy przejściowej.

Jako klient lub inny mniej techniczny interesariusz powinieneś w szczególności żądać tymczasowego buforowania — lub przynajmniej dyskusji na ten temat — za każdym razem, gdy aplikacja pobiera dane z usługi zdalnej. Powinieneś zapoznać się z doskonałą wtyczką Query Monitor, aby zobaczyć, jak działają transjenty. Daje ci interfejs do przeglądania, jakie dane są przechowywane jako przejściowe, jak często i na jak długo.

Czasami przejściowe nie są wystarczająco dobre

Niektóre usługi hostingowe premium WordPress w rzeczywistości nie pozwalają na używanie transjentów w produkcji. Mają uruchomiony kod, być może w postaci wtyczki MU lub innego skryptu, który przechwyci twoją próbę użycia interfejsu API transients i zamiast tego będzie przechowywać te informacje w pamięci podręcznej obiektów. WP-Engine w swojej najczęstszej konfiguracji jest tego najlepszym przykładem.

Zrzut ekranu widoku phpMyAdmin opisanego w podpisie

Alarmujący widok w interfejsie użytkownika phpMyAdmin: strona produkcyjna całkowicie pozbawiona transjentów? Prawdopodobnie oznacza to, że działa buforowanie obiektów.

Jeśli po prostu przechowujesz i pobierasz dane, w rzeczywistości nie musisz się tym przejmować i możesz nawet nie zauważyć, że to się dzieje. Cała rodzina funkcji *_transient() zapewni ci ten sam wynik końcowy, po prostu przefiltrowany tak, aby używał pamięci podręcznej obiektów zamiast tymczasowej pamięci podręcznej. Problemy mogą jednak wystąpić podczas próby usunięcia transjentów. Dlatego.

Jeśli integracja z interfejsem API jest na tyle złożona, że ​​zasługuje na własną stronę ustawień, możesz chcieć dołączyć interfejs użytkownika, aby umożliwić administratorowi wyczyszczenie całej tymczasowej pamięci podręcznej wtyczki . Najczęstszym zastosowaniem tego przycisku jest sytuacja, w której klient zmienia niektóre dane bezpośrednio w usłudze zdalnej i chce unieważnić pamięć podręczną, którą przechowujemy w WordPress. Ten przycisk może się również przydać, jeśli klient zmieni poświadczenia konta, klucze API lub po prostu jako przycisk „przywracania ustawień fabrycznych” do debugowania.

Zrzut ekranu przycisków opcji

Przykład interfejsu użytkownika umożliwiającego klientowi opróżnienie lokalnej pamięci podręcznej dla danych interfejsu API.

Nawet jeśli byłeś na tyle sprytny, aby umieścić w przestrzeni nazw wszystkie swoje klucze przejściowe, aby mieć nadzieję na zidentyfikowanie każdego z nich dla delete_transient() , najlepszy scenariusz prawdopodobnie nadal obejmuje surowy SQL, którego zawsze staram się unikać w WordPress:

 <?php // Purge all the transients associated with our plugin. function purge() { global $wpdb; $prefix = esc_sql( $this -> get_transient_prefix() ); $options = $wpdb -> options; $t = esc_sql( "_transient_timeout_$prefix%" ); $sql = $wpdb -> prepare ( " SELECT option_name FROM $options WHERE option_name LIKE '%s' ", $t ); $transients = $wpdb -> get_col( $sql ); // For each transient... foreach( $transients as $transient ) { // Strip away the WordPress prefix in order to arrive at the transient key. $key = str_replace( '_transient_timeout_', '', $transient ); // Now that we have the key, use WordPress core to the delete the transient. delete_transient( $key ); } } ?>

Niewygodne, nie wydajne. Zamiast tego ta sytuacja wymaga buforowania obiektów, ponieważ buforowanie obiektów daje nam wygodny sposób na grupowanie razem buforowanych wartości . W ten sposób, gdy musisz opróżnić wszystkie buforowane wartości związane z twoją wtyczką, jest to proste jednowierszowe wywołanie wp_cache_delete( $key, $group ) .

Podsumowałbym to wszystko, mówiąc: Nie możesz być ekspertem w korzystaniu z interfejsów API, jeśli nie jesteś jeszcze ekspertem w zarządzaniu pamięcią podręczną dla tych danych.

Jako klient, kluczową rzeczą, na którą należy uważać, jest nieprawidłowe zachowanie pamięci podręcznej między środowiskiem pomostowym a produkcyjnym. Innymi słowy, chociaż testowanie nowej partii pracy w stagingu jest zawsze dobrą praktyką, buforowanie jest czymś, co należy również testować w środowisku produkcyjnym z równą starannością.

Zdalny interfejs API może pomóc w informowaniu o hierarchii klas PHP

Kiedy układam różne klasy PHP dla mojej wtyczki, często uważam, że pomocne jest naśladowanie sposobu definiowania punktów końcowych interfejsu API — na przykład, co wydaje się mieć wspólnego następujące punkty końcowe?

  • https://api.przykładowa-usługa-e-mail.com/v1/subscribers.json
  • https://api.example-email-service.com/v1/lists.json
  • https://api.example-email-service.com/v1/campaigns.json

Wszystkie zwracają kolekcje , przez co rozumiem wynik żądania GET, zwracając wyniki zero-do-wielu, gdzie każdy wynik jest elementem tablicy. To może wydawać się dość oczywiste, ale uważam, że jest to pomocny monit o następującą strukturę klas w moim kodzie PHP:

  • class.collection.php , klasa abstrakcyjna
  • class.subscribers.php rozszerza klasę abstrakcyjną Collection .
  • class.lists.php rozszerza klasę abstrakcyjną Collection .
  • class.campaigns.php rozszerza klasę abstrakcyjną Collection .

Klasa abstrakcyjna jako jedyny argument przyjęłaby tablicę parametrów zapytania: elementy takie jak podział na strony, kolumna sortowania, porządek sortowania i filtry wyszukiwania. Miałby metody do typowych zadań, takich jak wywoływanie zdalnego interfejsu API, obsługa błędów i być może przekształcanie wyników w menu HTML <select> lub AutoSuggest jQueryUI. Klasy, które tworzą wystąpienie klasy abstrakcyjnej, mogą być dość krótkie, być może robią niewiele więcej niż określanie ciągu, który ma być używany w adresie URL punktu końcowego interfejsu API *.json .

Zrzut ekranu placu zabaw Mailchimp API

Mailchimp publikuje „plac zabaw” API dla wywołań API piaskownicy i tym podobnych. Działa również jako wygodny sposób na przeglądanie całej hierarchii danych ich interfejsu API, dając nam pomocny wgląd w to, jak możemy ustrukturyzować naszą własną hierarchię klas.

Podobnie, co mają wspólnego następujące punkty końcowe?

  • https://api.przykladowa-usługa-e-mail.com/v1/subscribers/104abyh4.json
  • https://api.example-email-service.com/v1/lists/837dy1h2.json
  • https://api.example-email-service.com/v1/campaigns/9i8udr43.json

Wszystkie zwracają element , przez co rozumiem dokładnie jednego konkretnego, unikalnego członka kolekcji: na przykład jednego konkretnego subskrybenta wiadomości e-mail, jedną listę e-mailową lub jedną kampanię e-mailową. Dlatego lubię używać następującej struktury w moim kodzie PHP:

  • class.item.php , klasa abstrakcyjna
  • class.subscriber.php rozszerza klasę abstrakcyjną Item .
  • class.list.php rozszerza klasę abstrakcyjną Item .
  • class.campaign.php rozszerza klasę abstrakcyjną Item .

Klasa abstrakcyjna przyjęłaby jako jedyny argument ciąg znaków identyfikujący określony element, którego dotyczy żądanie. Po raz kolejny tworzone wystąpienia klas mogą być dość krótkie, być może robiąc niewiele więcej niż określenie ciągu, który ma być używany w */duy736td.json .

Istnieje wiele podejść do strukturyzowania dziedziczenia klas, ale nawet jeśli przyjmiesz inne podejście do tego, co przedstawiłem powyżej, założę się, że istnieje duża szansa, że ​​struktura zdalnego API może pomóc w określeniu struktury Twojej aplikacji.

Jako klient, częstym objawem złej architektury jest sytuacja, w której musisz wielokrotnie żądać tej samej zmiany w całej aplikacji. Na przykład, jeśli poprosisz, aby raporty zwracały 100 wyników na stronę zamiast 10, i musisz powtarzać to żądanie raportów subskrybentów, raportów kampanii, raportów rezygnacji z subskrypcji itp., możesz wykryć słabą architekturę klasy. W takiej sytuacji warto zapytać swój zespół, czy skorzystałby na cyklu refaktoryzacji: zespół pracy, w którym celem nie jest zmiana zachowania produktu, ale raczej ulepszenie kodu bazowego, aby łatwiej było zmienić zachowanie produktu w przyszłości.

Idealny przypadek użycia dla WP_Error

Ze wstydem przyznaję, że zajęło mi to lata dłużej niż powinno, aby właściwie zacząć używać rodziny funkcji WP_Error w moim kodzie. Miałem tendencję do kodowania swojej drogi, albo zakładając, że nigdy nie będzie błędów, którymi warto się zająć programowo, albo radząc sobie z nimi na zasadzie indywidualnej. Praca ze zdalnymi interfejsami API przecina tę mentalność jak wiązka laserowa, ponieważ stanowi niezwykle wygodny i wydajny przypadek użycia do korzystania z WP_Error .

Jak wspomniałem wcześniej, często mam klasę PHP, której celem jest wysyłanie żądań HTTP do zdalnego API. Kiedy usuniesz wszystkie schematy, całą manipulację danymi, wszystkie drugorzędne problemy, ta klasa naprawdę sprowadza się do wywołania wp_remote_request() , aby uzyskać obiekt odpowiedzi HTTP z API. Dogodnie wp_remote_request() zamiast tego zwróci WP_Error , jeśli z jakiegoś powodu wywołanie nie zostanie wykonane, ale co z tym, jeśli wywołaniu powiedzie się zwrócenie odpowiedzi HTTP niekorzystnego typu?

Zrzut ekranu formularza subskrypcji

Technicznie rzecz biorąc, wywołanie API zadziałało , ale nie jest całkowicie wolne od zastrzeżeń. Te zastrzeżenia muszą być rejestrowane i zgłaszane w spójny sposób w całej bazie kodu.

Na przykład może wykonaliśmy wywołanie do punktu końcowego /lists.json , ale to konkretne konto nie ma jeszcze skonfigurowanych list. Spowoduje to zwrócenie prawidłowej odpowiedzi HTTP, ale z kodem stanu 400. Chociaż nie jest to błąd krytyczny per se, z perspektywy kodu interfejsu, który chce zmienić to wywołanie interfejsu API w menu rozwijane, 400 może a także być WSOD! Dlatego uważam, że pomocne jest wykonanie dodatkowego parsowania wyniku wp_remote_request() , potencjalnie zwracając w WP_Error :

 <?php function call() { $response = wp_remote_request( $this -> url, $this -> args ); $code = wp_remote_retrieve_response_code( $response ); $first_digit = $code[0]; $good_responses = array( 2, 3 ); if( ! in_array( $first_digit, $good_responses ) { $body = wp_remote_retrieve_body( $response ); $out = new WP_Error( $code, $body ); } else { $out = $response; } return $out; } ?>

Ten wzorzec może pomóc uprościć kod, który wywołuje naszą klasę wywołującą, ponieważ wiemy, że możemy bezpiecznie polegać na is_wp_error() przed kontynuowaniem naszych danych wyjściowych.

Jako klient powinieneś czasami odgrywać rolę złośliwego użytkownika, zdezorientowanego użytkownika i niecierpliwego użytkownika. Korzystaj z aplikacji w sposób, w jaki nie miała być używana. Rób rzeczy, których twoi programiści nie chcą, abyś robił. Zwróć uwagę na to, co się dzieje. Czy otrzymujesz pomocne komunikaty o błędach? Czy w ogóle otrzymujesz komunikaty o błędach? Jeśli nie, warto zasponsorować prace nad lepszą obsługą błędów.

Piękna moc debugowania ob_get_clean()

Współczesna programowalna sieć, w której prawie każda witryna wykorzystuje interfejsy API innych witryn i sama jest wykorzystywana za pośrednictwem własnego interfejsu API, stała się niezwykle potężną areną dla kodu. Ale to właśnie ta jakość może również spowalniać.

Często zdalne żądania HTTP są najbardziej czasochłonną częścią wczytywania danej strony. Z tego powodu wiele komponentów opartych na API jest wykonywanych przez Ajax lub cron. Na przykład autosugestia przeszukiwania listy subskrybentów wiadomości e-mail powinna prawdopodobnie pingować zdalne źródło danych na żądanie po każdym naciśnięciu klawisza, zamiast ładować wszystkie 100 000 subskrybentów w DOM podczas ładowania strony. Jeśli to nie jest opcja, być może duże zapytanie może zostać zsynchronizowane w nocnym zadaniu crona, dzięki czemu wyniki mogą być pobierane z lokalnego serwera lustrzanego, a nie ze zdalnego interfejsu API.

Problem z tym podejściem polega na tym, że debugowanie może być trudne. Zamiast po prostu włączyć WP_DEBUG i pozwolić komunikatom o błędach pojawiać się w oknie przeglądarki, utknąłeś patrząc w konsoli sieciowej przeglądarki lub śledząc plik dziennika jako wykonywane zadanie cron (mamy nadzieję?). Uważam to za niewygodne.

Jednym ze sposobów poprawy tej sytuacji jest wykonanie ostrożnych i strategicznych wywołań error_log() . Ale z drugiej strony częstym problemem z rejestrowaniem jest to, że w przypadku dużych lub obciążonych aplikacji dzienniki błędów mogą być zbyt duże lub rosnąć zbyt szybko, aby były przydatne do monitorowania lub analizowania. Dlatego musimy być selektywni w tym, co rejestrujemy, poświęcając na to tyle samo uwagi, co w przypadku naszej rzeczywistej logiki aplikacji . Szkoda, że ​​poświęciłem czas na zalogowanie jakiegoś egzotycznego błędu przypadku krawędzi, który wydaje się pojawiać sporadycznie w niektórych nieczęstych zadaniach crona tylko po to, aby zdać sobie sprawę, że prawdziwa natura błędu znów Cię ominęła, ponieważ nie udało Ci się zarejestrować określonego elementu tablicy powiedzmy, o obraźliwej wartości.

Dlatego moją filozofią stało się to, że nie zawsze loguję, ale jak to robię, to loguję wszystko . Innymi słowy, po zidentyfikowaniu szczególnie niepokojącej funkcji, zarejestruję ją z jak najszerszą siecią:

 <?php function debug( $bug ) { ob_start(); var_dump( $bug ); $out = ob_get_clean(); error_log( $out ); } ?>

Sprowadza się to do var_dump() umieszczania całej wartości buggy w pojedynczym wpisie w pliku dziennika błędów.

Zrzut ekranu pliku dziennika błędów

Dziennik błędów, który urósł zbyt duży, aby był ergonomiczny do debugowania.

Jako klient warto okresowo sprawdzać całkowite wykorzystanie pamięci plików przez twoją aplikację. Jeśli zauważysz, że nagle zbliżasz się do limitów miejsca na koncie hostingowym, istnieje duża szansa, że ​​winę ponosi zdziczały dziennik błędów. Twoi programiści skorzystają na cyklu pracy skoncentrowanym na lepszym rejestrowaniu — podobnie jak Twoi klienci!

Niezupełnie Clickbait, ale to wystarczy

Proszę wybaczyć strukturę listową tego artykułu. Nie mogłem zmusić tych punktów do bardziej ujednoliconego motywu artykułu, ponieważ te wzorce są bardzo ogólne: mają zastosowanie do dowolnego punktu końcowego JSON REST i dowolnego wyjścia WordPress .

Są to wzorce, które pojawiają się w kółko, niezależnie od tego, czym jest zdalny interfejs API lub do czego go używamy w WordPressie. Posunąłem się tak daleko, że zebrałem wszystkie tego rodzaju zasady w schemacie wtyczek, który znacznie przyspiesza moją pracę. Czy masz podobne punkty, które zachowujesz dla każdego projektu? Proszę, udostępnij je, abym mógł je ukraść i dodać do mojego szablonu!

Powiązane: Jak podejść do nowoczesnego programowania WordPress (część 1)