[]

[]

Ten ebook jest chroniony znakiem wodnym

ebookpoint.pl Kopia dla:

Pawel Domanski pawel.domanski@outlook.com G07252420110
pawel.domanski@outlook.com

Brian Messenlehner, Jason Coleman

WordPress

Tworzenie aplikacji internetowych

Wydanie II

Przekład: Agnieszka Górczyńska

Tytuł oryginału: Building Web Apps with WordPress: WordPress as an
Application Framework, 2nd Edition

Tłumaczenie: Agnieszka Górczyńska

ISBN: 978-83-283-6926-9

© 2021 Helion SA

Authorized Polish translation of the English edition of Building Web
Apps with WordPress 2E ISBN 9781491990087 © 2020 Brian Messenlehner and
Jason Coleman

This translation is published and sold by permission of O’Reilly Media,
Inc., which owns or controls all rights to publish and sell the same.

All rights reserved. No part of this book may be reproduced or
transmitted in any form or by any means, electronic or mechanical,
including photocopying, recording or by any information storage
retrieval system, without permission from the Publisher.

Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości
lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest
zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a
także kopiowanie książki na nośniku filmowym, magnetycznym lub innym
powoduje naruszenie praw autorskich niniejszej publikacji.

Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi
bądź towarowymi ich właścicieli.

Autorzy oraz Helion SA dołożyli wszelkich starań, by zawarte w tej
książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej
odpowiedzialności ani za ich wykorzystanie, ani za związane z tym
ewentualne naruszenie praw patentowych lub autorskich. Autorzy oraz
Helion SA nie ponoszą również żadnej odpowiedzialności za ewentualne
szkody wynikłe z wykorzystania informacji zawartych w książce.

Helion SA
ul. Kościuszki 1c, 44-100 Gliwice
tel. 32 231 22 19, 32 230 98 63
e-mail: helion@helion.pl
WWW: http://helion.pl (księgarnia internetowa, katalog książek)

Drogi Czytelniku!
Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres
http://helion.pl/user/opinie/wordp2_ebook
Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję.

-   Poleć książkę
-   Kup w wersji papierowej
-   Oceń książkę

-   Księgarnia internetowa
-   Lubię to! » nasza społeczność

Opinie o książce WordPress. Tworzenie aplikacji internetowych. Wydanie II

„WordPress to więcej niż tylko oprogramowanie, to jest ruch, który
faktycznie stał się systemem operacyjnym internetu. To więcej niż blog
lub system zarządzania treścią, a gdy nauczysz się używać WordPressa w
charakterze platformy aplikacji, wówczas znajdziesz się na czele jego
trzeciej fali popularności”.

— Matt Mullenweg, współtwórca WordPressa

„Brian i Jason przez całe lata rozwijali się wraz z WordPressem. Dlatego
potrafią skutecznie pokazać, jak w przypadku odpowiedniego typu
aplikacji programiści mogą wykorzystać zalety silnika WordPressa do
tworzenia znacznie bezpieczniejszych i wydajniejszych aplikacji
internetowych w o połowę krótszym czasie niż wcześniej”.

— Jake Goldman, przewodniczący i założyciel 10up

„Ta książka to doskonały zasób dla programistów, którzy chcą poznać
sposoby tworzenia aplikacji internetowych WordPressa lub aktualnie
stosują w pracy rozwiązania oparte na PHP”.

— Dave Mackey, programista oprogramowania i sieci, Liquid Church

Przedmowa

Przez ostatnich kilka lat każdego roku spędzałem od 15 do 24 tygodni,
odwiedzając programistów w całym kraju. Na podstawie mniej więcej 25
tysięcy rozmów sformułowałem następujące wnioski.

Aplikacje internetowe są wszędzie

Trudno wyobrazić sobie życie bez aplikacji internetowych. W dzisiejszych
czasach korzystanie z bankowości internetowej jest czymś oczywistym.
Hotele i kwatery są rezerwowane za pomocą aplikacji internetowych.
Podatki są rozliczane za pomocą aplikacji internetowych przypominających
w działaniu tradycyjne programy. Przed wizytą u fryzjera sprawdzasz w
telefonie wolny termin za pomocą prostego formularza, który tak naprawdę
również jest przykładem aplikacji internetowej. Łatwo stwierdzić, że
aplikacje internetowe są stosowane praktycznie wszędzie.

Twórcy aplikacji internetowych nie potrafią ich budować

Podczas rozmów z osobami niezajmującymi się programowaniem można
usłyszeć, że ich koledzy programiści są geniuszami, którzy potrafią
zrobić w komputerze praktycznie wszystko. Natomiast w trakcie
bezpośrednich rozmów z programistami można odkryć, że postrzegają oni
rzeczywistość w zupełnie odmienny sposób.

Uznają za „rzeczywiste” aplikacje internetowe i stojące za nimi firmy
oraz są przekonani, że osoby pracujące w „tamtych firmach” wiedzą o
tworzeniu aplikacji internetowych znacznie więcej niż ktokolwiek inny.

Są przekonani, że mogą tworzyć jedynie małe aplikacje — nie wiedzą,
jakie umiejętności są potrzebne do tworzenia aplikacji internetowych,
które mogłyby zdobyć większą popularność.

Brakuje nieco informacji i znacznie więcej pewności siebie

Gdy usiądziesz z programistami i zaczniesz z nimi rozmawiać o
aplikacjach internetowych, szybko przekonasz się, że ich największym
problemem jest brak pewności siebie. Tworzenie kodu naprawdę nie jest
trudne, o ile wiadomo, co trzeba zrobić. To jednak nie oznacza, że
programista nie powinien nieco dokładniej przyjrzeć się procesowi.

Wspomniane wcześniej rozmowy odbywały się na terenie całego kraju
podczas konferencji lokalnych nazywanych WordCamp. Są to spotkania
społeczności, w których bierze udział zwykle od 200 do 500 osób —
zarówno programistów, jak i nieprogramistów. Cechą wspólną tych
społeczności jest korzystanie lub zamiar korzystania z produktu o nazwie
WordPress pozwalającego na publikowanie w internecie.

WordPress, jeśli nigdy wcześniej o nim nie słyszałeś, dostarcza silnik
pozwalający na działanie jednej trzeciej witryn internetowych na
świecie. Podstawowym przeznaczeniem tego produktu jest dostarczenie
platformy pozwalającej na publikowanie treści, jednak można go
wykorzystać również do opracowania aplikacji internetowej.

Ten właśnie temat został dokładnie omówiony w książce.

Według mnie plusem tego opracowania jest to, że czytelnik nie zostaje od
razu rzucony na głęboką wodę, ale powoli znajduje odpowiedzi na
nurtujące go pytania. Dzięki temu nabiera większej pewności siebie.
Doskonale wiem, jak bardzo jest to cenne. Czytelnik otrzymuje rodzaj
mapy drogowej pokazującej, co i jak zrobić dalej.

Kolejną zaletą książki jest to, że autorzy niejako motywują czytelnika
do robienia postępów i wtajemniczają w coraz większą liczbę szczegółów z
każdym następnym tworzonym wierszem kodu. Niektóre z tych informacji
będą dla Ciebie nowością, inne zaś nie. Na pewno nie znajdziesz tu
zawiłych sformułowań, które Tobie pozostawiają konieczność ustalenia,
jak można zastosować nowo zdobytą wiedzę.

Zamiast tego Brian i Jason omawiają każdy aspekt WordPressa, który
powinieneś znać i wykorzystywać jako framework aplikacji internetowej.
Obecnie istnieje wiele szkół, w których omawia się zagadnienia poruszane
w tej książce. Ty na szczęście nie musisz płacić za szkołę, tym bardziej
że koszt nauki w niej jest znacznie wyższy niż koszt zakupu niniejszej
książki.

Mam nadzieję, że zachęciłem Cię do lektury.

Być może dotąd byłeś przekonany, że istnieją dwa typy programistów:
tworzący aplikacje, których Ty nigdy nie będziesz w stanie zbudować, i
podobni do Ciebie — tworzący małe lub proste aplikacje.

Gdy zakończysz lekturę książki, jednego mogę być pewien — jeśli
zapoznasz się z przedstawionym w niej materiałem, poeksperymentujesz z
kodem i wypróbujesz go w akcji, nabierzesz przekonania, że istnieje
tylko jeden typ programistów. To programiści, którzy mogą utworzyć
wszystko, co tylko przyjdzie im do głowy. Ty jesteś przykładem takiego
programisty.

To, że czytasz teraz te słowa, jest ich potwierdzeniem. Nadeszła pora,
aby przekonać się o tym w praktyce.

— Chris Lema

wiceprezes ds. produktów i innowacji w Liquid Web

Wprowadzenie

W chwili gdy piszę te słowa, WordPress dostarcza silnik dla 32%
wszystkich witryn internetowych opublikowanych w sieci, a ta liczba
wciąż rośnie. Wielu programistów chce w jeszcze większym stopniu
wykorzystać WordPressa, ale są przekonani, że powinni przejść do
bardziej tradycyjnego frameworka aplikacji, np. Ruby on Rails, Symphony,
Yii lub Laravel, i tworzyć „rzeczywiste” aplikacje internetowe. Takie
myślenie jest błędne i jesteśmy tutaj po to, aby je wyeliminować.

Mimo że WordPress powstał jako oprogramowanie przeznaczone do obsługi
blogów i obecnie jest używany przede wszystkim jako system zarządzania
treścią (content management system, CMS), stał się elastyczną i potężną
platformą przeznaczoną do tworzenia aplikacji internetowych. W tej
książce zobaczysz, jak można zastosować WordPressa jako framework
aplikacji do utworzenia dowolnej aplikacji internetowej, zarówno małej,
jak i ogromnej.

Dla kogo jest przeznaczona ta książka

Ta książka jest najbardziej użyteczna dla programistów WordPressa,
którzy zamierzają zająć się pracą nad większymi aplikacjami, a także dla
programistów PHP mających doświadczenie w pracy z WordPressem i
szukających frameworka aplikacji opartego na PHP.

Koncepcje i techniki przedstawione w książce będą użyteczne również dla
twórców komercyjnych wtyczek i motywów, a także dla osób pracujących nad
ogromnymi rozproszonymi projektami WordPressa.

Jeżeli jesteś programistą PHP lub ogólnie programistą używającym innego
frameworka i zainteresowanym ogromną biblioteką wtyczek i motywów
WordPressa, możesz być zaskoczony tym, jak doskonale WordPress sprawdza
się w charakterze ogólnego frameworka aplikacji. Lektura materiału
i zastosowanie go w praktyce może na dobre zmienić Twoją pracę.

Przyjęliśmy założenie, że czytelnik zna ogólne koncepcje związane z
programowaniem w języku PHP. Powinien mieć również podstawową wiedzę w
zakresie technologii HTML, CSS, MySQL i zapytań SQL. Znajomość
JavaScriptu i jQuery będzie pomocna w podczas czytania rozdziału 9. oraz
podczas omawiania wielu innych przykładów.

Dla kogo nie jest to odpowiednia książka

Nie jest to książka przeznaczona dla osób, które chcą poznać obsługę
WordPressa z perspektywy użytkownika końcowego. Wprawdzie znajduje się w
niej krótkie wprowadzenie do standardowej funkcjonalności WordPressa,
ale przyjęliśmy założenie, że czytelnik ma już doświadczenie w pracy
z WordPressem z perspektywy użytkownika końcowego.

Ta książka nie jest adresowana do osób niebędących programistami.
Istnieje możliwość utworzenia dość funkcjonalnej aplikacji internetowej
przez połączenie i skonfigurowanie wielu wtyczek dostępnych dla
WordPressa, ale książka jest przeznaczona dla programistów, którzy chcą
samodzielnie tworzyć wtyczki i motywy wykorzystane później do budowania
nowych aplikacji internetowych.

Ta książka nie ma na celu nauki programowania, ma raczej pokazać, jak
należy programować „w sposób zgodny z WordPressem”.

Co znajdziesz w książce

Mamy nadzieję, że dzięki tej książce czytelnik nauczy się programowania
w WordPressie oraz pozna techniki organizacyjne i najlepsze praktyki
stosowane podczas tworzenia skomplikowanych aplikacji w WordPressie.

Rozdział 1. Tworzenie aplikacji internetowych w WordPressie

Definiuje to, co mamy na myśli, mówiąc „aplikacja internetowa”, oraz
wyjaśnia, dlaczego należy lub nie należy korzystać z WordPressa podczas
tworzenia aplikacji internetowych. Znajdziesz tutaj również porównanie
WordPressa z innymi frameworkami aplikacji. Przedstawimy również
SchoolPress, czyli aplikację WordPress używaną jako przykład w tej
książce.

Rozdział 2. Podstawy WordPressa

Rozdział zawiera omówienie podstaw WordPressa. Prezentujemy poszczególne
katalogi instalacji i ich zawartość. Wyjaśniamy również przeznaczenie
wszystkich tabel bazy danych utworzonej przez WordPressa,
przechowywanych w niej danych oraz funkcje używane przez WordPressa do
mapowania tych tabel. Nawet jeśli jesteś doświadczonym programistą
WordPressa, wciąż możesz się sporo nauczyć z lektury tego rozdziału i
dlatego zachęcamy Cię do jego przeczytania.

Rozdział 3. Stosowanie wtyczek WordPressa

Czytelnik znajdzie tu odpowiedzi na pytania: Do czego służą wtyczki? Jak
można tworzyć własne? Jak powinna się przedstawiać struktura wtyczki
głównej aplikacji? Kiedy należy korzystać z zalet wtyczek opracowanych
przez podmioty zewnętrzne, a kiedy opracowywać je samodzielnie?

Rozdział 4. Motywy

Rozdział poświęcony motywom. Jak działa motyw? Jak motyw jest mapowany
na widok w typowym frameworku typu MVC (model-view-controller)? Który
kod powinien znaleźć się w motywie, a który we wtyczce? W rozdziale
omówiony jest także temat używania frameworków motywów i frameworków UI,
a także podstawy projektu responsywnego.

Rozdział 5. Niestandardowe typy postów, metadane postów i taksonomie

W rozdziale omówiono typy postów i taksonomii. Scharakteryzowano
domyślne typy postów wbudowane w WordPressa. Dowiesz się, dlaczego
miałbyś tworzyć własne typy i jak to zrobić. Przedstawimy również temat
metadanych postów i taksonomie, ich przeznaczenie, tworzenie własnych
taksonomii oraz ich mapowanie na typy postów. Ponadto zaprezentujemy
tworzenie klas opakowujących typy postów, co pozwoli na organizowanie
kodu z zastosowaniem programowania zorientowanego obiektowo
(object-oriented programming, OOP).

Rozdział 6. Użytkownicy, role i uprawnienia

W rozdziale znajduje się omówienie użytkowników, ról i możliwości.
Pokazujemy, jak w sposób programistyczny dodawać, uaktualniać i usuwać
użytkowników, a także jak pracować z metadanymi użytkowników, rolami i
ich możliwościami. Wyjaśniamy także temat rozszerzenia klasy WP_User dla
użytkowników takich jak „klient” i „nauczyciel”, aby móc lepiej
zorganizować kod z wykorzystaniem technik OOP.

Rozdział 7. Praca z API WordPressa, obiektami i funkcjami pomocniczymi

W rozdziale znajdziesz omówienie najużyteczniejszych API WordPressa i
funkcji pomocniczych, które nie pasują do przedstawienia w innych
rozdziałach książki, a mimo tego nadal są ważne dla programistów
tworzących aplikacje internetowe za pomocą WordPressa.

Rozdział 8. Bezpieczny WordPress

Rozdział poświęcony zapewnieniu bezpieczeństwa aplikacjom, wtyczkom i
motywom WordPressa.

Rozdział 9. Frameworki JavaScript

W rozdziale znajdziesz omówienie użycia JavaScriptu i technologii AJAX w
aplikacji WordPressa. Przedstawiamy prawidłowe sposoby na zastosowanie
JavaScriptu w aplikacji WordPressa i pokazujemy, jak zapewnić
asynchroniczne działanie komponentów aplikacji.

Rozdział 10. API REST WordPressa

Omówienie API REST dla WordPressa i pokazanie możliwości jego
wykorzystania do integracji WordPressa z aplikacjami zewnętrznymi.

Rozdział 11. Projekt Gutenberg, bloki i niestandardowe typy postów

W rozdziale znajdziesz omówienie edytora bloków i dowiesz się, jak można
tworzyć własne bloki.

Rozdział 12. Sieć witryn internetowych WordPressa

Rozdział zawiera omówienie sieci WordPressa składających się z wielu
witryn. Dowiesz się, jak można je skonfigurować i na co trzeba zwracać
uwagę podczas tworzenia aplikacji dla takich sieci.

Rozdział 13. Lokalizacja aplikacji WordPressa

Omówienie tematu lokalizacji wtyczek i motywów WordPressa, m.in.
przygotowanie kodu do tłumaczenia, a także tworzenie i stosowanie plików
z tłumaczeniami.

Rozdział 14. Optymalizacja i skalowanie WordPressa

Z rozdziału dowiesz się, jak optymalizować i skalować WordPressa na
potrzeby ogromnych aplikacji internetowych. Przedstawiamy temat
przeprowadzania testów wydajności aplikacji WordPressa, a także
najpopularniejsze techniki pozwalające na przyśpieszanie i skalowanie
witryn internetowych działających za pomocą silnika WordPressa.

Rozdział 15. E-commerce

Rozdział poświęcony tematyce e-commerce. Pokazujemy różne typy
dostępnych wtyczek e-commerce i podpowiadamy, jak wybierać odpowiednie
spośród nich. Następnie dość dokładnie omawiamy użycie WordPressa do
obsługi płatności internetowych i zarządzanie kontem dla aplikacji
internetowych typu SaaS (software as a service).

Rozdział 16. Aplikacje mobilne na bazie WordPressa

Z rozdziału dowiesz się, jak wykorzystać WordPressa do budowania
natywnych aplikacji dla urządzeń mobilnych poprzez utworzenie opakowań
aplikacji dla systemów iOS i Android.

Rozdział 17. Biblioteki PHP, integracje usług sieciowych, migracje
platform

Omówienie opracowanych przez podmioty zewnętrzne bibliotek PHP, usług
sieciowych i API, które są najczęściej stosowane w aplikacjach
internetowych. Dowiesz się również, jak je zintegrować z WordPressem, a
także jak przeprowadzać pełne migracje.

Rozdział 18. Przyszłość

Zastanawiamy się nad przyszłością WordPressa, typami aplikacji
utworzonych za pomocą WordPressa, rodzajami uaktualnień, których można
się spodziewać, a także narzędziami i frameworkami, które warto
obserwować w przyszłości.

Fragmenty kodu

Wszystkie fragmenty kodu przedstawione w książce zostały umieszczone w
archiwum, które znajdziesz pod adresem
ftp://ftp.helion.pl/przyklady/wordp2.zip. Trzeba w tym miejscu dodać, że
przykłady te zostały utworzone zgodnie z koncepcjami omówionymi w
książce. Aby poprawić czytelność przykładów, często zignorowaliśmy
najlepsze praktyki dotyczące tworzenia kodu źródłowego
(https://make.wordpress.org/core/handbook/best-practices/coding-standards/),
bezpieczeństwa, lokalizacji (została omówiona w rozdziałach 8. i 13.)
oraz niektóre przypadki skrajne. Musisz o tym pamiętać, jeśli będziesz
chciał którykolwiek z przykładów wykorzystać w środowisku produkcyjnym.

Omawiana w książce aplikacja SchoolPress działa pod adresem
https://schoolpress.me/, jej kod zaś jest dostępny jako oprogramowanie
typu open source w archiwum, które znajdziesz pod adresem
ftp://ftp.helion.pl/przyklady/wordp2.zip.

Konwencje zastosowane w książce

W tej książce zastosowano następujące konwencje typograficzne.

Kursywa

Oznacza nowe terminy, adresy URL, adresy e-mail, nazwy i rozszerzenia
plików oraz komentarze w listingach.

Czcionka o stałej szerokości

Użyta w przykładowych fragmentach kodu, a także w samym tekście, aby
odwołać się do pewnych poleceń bądź innych elementów programistycznych,
takich jak: nazwy zmiennych lub funkcji, baz danych, typów danych,
zmiennych środowiskowych, poleceń i słów kluczowych.

Pogrubiona czcionka o stałej szerokości

Użyta w celu wyeksponowania poleceń bądź innego tekstu, który powinien
być wprowadzony przez czytelnika.

Pochylona czcionka o stałej szerokości

Wskazuje tekst, który powinien być zastąpiony wartościami podanymi przez
użytkownika bądź wynikającymi z kontekstu.

  ---- ----------------------------------------------------------
  []   Taka ikona oznacza wskazówkę, sugestię lub ogólną uwagę.
  ---- ----------------------------------------------------------

  ---- ----------------------------------
  []   Taka ikona oznacza ostrzeżenie.
  ---- ----------------------------------

Użycie przykładowych kodów

Jak wspomnieliśmy już wcześniej, wszystkie przykładowe fragmenty kodu
znajdują się w archiwum, które znajdziesz pod adresem
ftp://ftp.helion.pl/przyklady/wordp2.zip.

Jeżeli masz pytanie techniczne lub jakikolwiek problem związany z
użyciem tych przykładów, możesz zwrócić się z prośbą o pomoc, pisząc na
adres helion@helion.pl.

Książka ma na celu pomóc Ci w pracy. Przykłady z niej można
wykorzystywać w swoich programach i w dokumentacji. Nie trzeba
kontaktować się z nami w celu uzyskania zezwolenia, dopóki nie powiela
się znaczących ilości kodu — na przykład pisanie programu, w którym
znajdzie się kilka fragmentów kodu z tej książki, nie wymaga zezwolenia,
jednak sprzedawanie lub rozpowszechnianie płyty CD-ROM zawierającej
przykłady z książki wydawnictwa O’Reilly już tak. Odpowiedź na pytanie
poprzez zacytowanie tej książki lub przykładowego kodu nie wymaga
zezwolenia, ale włączenie wielu przykładowych kodów z książki do
dokumentacji produktu czytelnika już tak.

Jesteśmy wdzięczni za umieszczanie przypisów, ale nie wymagamy tego.
Przypis zwykle zawiera nazwę autora, tytuł, wydawcę i ISBN, miejsce i
rok wydania publikacji. Na przykład: B. Messenlehner, J. Coleman,
WordPress. Tworzenie aplikacji internetowych. Wydanie II, ISBN
978-83-283-6925-2, Helion, Gliwice 2021.

Podziękowania

Od Briana: Dziękuję Jasonowi Colemanowi i Mattowi Mullenwegowi, bez ich
udziału ta książka w ogóle by nie powstała! Bardzo specjalne
podziękowania składam Alicii Young za kierowanie projektem w O’Reilly
Media. Specjalne podziękowania kieruję również do recenzentów
merytorycznych, którzy sprawdzili tekst i zagwarantowali, że wszystkie
zawarte w nim informacje są poprawne. Pomocy udzielili mi Scott Bolinger
z AppPresser.com i Jaffe Worley z AlphaWeb.com — im również dziękuję.
Podziękowania należą się także mojej rodzinie i przyjaciołom, którzy
zawsze stali za mną murem i nigdy nie przestawali we mnie wierzyć.
Wdzięczny jestem przede wszystkim moim dzieciom — Dalya, Brian Jr.,
Nina, Cam i Aksel Messenlehner dają mi ogromną motywację i bez nich
prawdopodobnie nawet bym nie wiedział, czym jest WordPress.

Od Jasona: Dziękuję mojemu współautorowi Brianowi za zaproszenie dopracy
nad tą książką. Dziękuję redaktorkom Meghan i Allyson za nadzór nad
naszą pracą i pomoc w trzymaniu się wyznaczonego celu. Dziękuję Alicii
Young za kierowanie projektem drugiego wydania książki i wyrozumiałość
dla naszych wyjaśnień „dramatu WP”. Dziękuję wszystkim doskonałym
redaktorom merytorycznym zajmującym się obydwoma wydaniami książki,
którymi byli: Sam Hotchkiss, Peter MacIntyre, Pippin Williamson, John
James Jacoby i Andrew Lima. Dziękuję Frederikowi Townesowi za informacje
i wkład w rozdział dotyczący optymalizacji i skalowania. Wspaniałą
przedmowę do książki napisał Chris Lema, dziękuję mu za uwagi dotyczące
tekstu oraz za udzielone wskazówki i rady. Dziękuję wszystkim członkom
społeczności WordPressa, którzy odpowiadali na moje wiadomości w
serwisie Twitter, wiedząc lub nie wiedząc, że pomagają mi w pracy nad
książką. Dziękuję mojej żonie Kim za okazane wsparcie (jak zwykle) i
kolejną przygodę w naszym wspólnym życiu. Dziękuję mojej córce Marin za
wyrozumiałość dla mojej nieobecności podczas pisania książki i mojemu
synowi Isaacowi za nieustanne pytanie, czy już skończyłem. Dziękuję
także pozostałym członkom mojej rodziny, którzy zawsze okazywali mi
wsparcie podczas pracy nad książką: Mamie, Tacie, Jeremiemu i Nana Men —
to pierwsi nieprogramiści, którzy ją przeczytali.

Rozdział 1. Tworzenie aplikacji internetowych w WordPressie

Ta książka pomoże Ci utworzyć w WordPressie witrynę internetową, motyw,
wtyczkę, usługę sieciową i aplikację internetową. Zdecydowaliśmy się
skoncentrować na aplikacjach internetowych, ponieważ można je postrzegać
jako superwitryny internetowe pozwalające wykorzystywać wszystkie
techniki przedstawione w tej książce.

Wiele osób jest przekonanych, że WordPress nie ma wystarczających
możliwości do tworzenia aplikacji internetowych lub nie został
opracowany w tym celu. Do tego tematu jeszcze powrócimy w dalszej części
rozdziału. Od wielu lat tworzymy aplikacje internetowe WordPressa i
wiemy, że doskonale nadaje się on do budowania skalowalnych aplikacji.

W tym rozdziale zaczniemy od zdefiniowania aplikacji internetowej, a
następnie wyjaśnimy, dlaczego WordPress to doskonały framework
przeznaczony do jej tworzenia. Zaprezentujemy również kilka wybranych
sytuacji, w których użycie WordPressa nie będzie najlepszym rozwiązaniem
podczas tworzenia aplikacji internetowej.

Czym jest witryna internetowa?

Doskonale wiesz, czym jest witryna internetowa: to jedna lub więcej
stron internetowych zawierających informacje i dostępnych za pomocą
przeglądarki WWW.

Czym jest aplikacja?

Lubimy definicję zamieszczoną w Wikipedii
(en.wikipedia.org/wiki/Application_software): „aplikacja to
oprogramowanie zaprojektowane do wykonywania grupy powiązanych ze sobą
funkcji, zadań lub czynności, które oferują pewną korzyść
użytkownikowi”.

Czym jest aplikacja internetowa?

Aplikacja internetowa to po prostu aplikacja uruchomiona w przeglądarce
WWW.

Zwróć uwagę na to, że w przypadku niektórych aplikacji internetowych
technologia przeglądarki WWW pozostaje ukryta — np. podczas integracji
aplikacji internetowej z natywną aplikacją systemu iOS lub Android,
podczas uruchamiania witryny internetowej jako aplikacji w Google
Chrome, a także podczas uruchamiania aplikacji w środowisku Adobe AIR.
Jednak wewnątrz tych aplikacji nadal znajduje się system przetwarzający
dane w HTML, CSS i JavaScripcie.

Aplikację internetową można traktować także jako witrynę internetową
wraz z dodatkami przypominającymi aplikację. Nie istnieje wyraźna
granica, po której przekroczeniu witryna internetowa staje się aplikacją
internetową. To jest przykład jednej z tych sytuacji, w których
zobaczywszy witrynę internetową, od razu będziesz wiedzieć, że masz do
czynienia z aplikacją internetową.

Natomiast można wyjaśnić pewne funkcje aplikacji internetowej,
przedstawić przykłady i spróbować zaprezentować skróconą definicję, aby
Czytelnik ogólnie wiedział, co mamy na myśli, gdy w tekście książki
stosujemy wyrażenie „aplikacja internetowa”.

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Podczas lektury książki będziesz napotykać odwołania do SchoolPressa. Jest to aplikacja internetowa, którą budujemy, aby pomóc szkołom i nauczycielom w zarządzaniu uczniami i programem nauczania. Wszystkie przykładowe fragmenty kodu zostały przygotowane z myślą o funkcjonalności, która może istnieć w SchoolPressie. Więcej informacji na temat ogólnych koncepcji stojących za aplikacją SchoolPress znajdziesz w dalszej części rozdziału.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Funkcje aplikacji internetowej

W tej sekcji wymieniamy typowe funkcje powiązane z aplikacjami
internetowymi i ogólnie z aplikacjami. Im więcej tych funkcji znajdziesz
w witrynie internetowej, tym bardziej odpowiednie jest nazywanie jej
aplikacją internetową[1].

Elementy interaktywne

Typowa witryna internetowa oznacza poruszanie się między tworzącymi ją
stronami, wczytywanie tych stron, przewijanie treści i klikanie łączy.
Aplikacja internetowa również może mieć łącza i wymagać przewijania, ale
zwykle wykorzystuje inne metody umożliwiające poruszanie się po
aplikacji.

Witryny internetowe wraz z formularzami oferują możliwość obsługi
transakcji. Przykładem może być formularz kontaktowy w witrynie
internetowej lub formularz aplikacji na stronie zawierającej oferty
pracy w danej firmie. Formularze pozwalają użytkownikom pracować
z witryną za pomocą czegoś więcej niż tylko kliknięć.

Aplikacje internetowe oferują jeszcze bardziej interaktywne elementy
interfejsu użytkownika. Do przykładów zaliczamy paski narzędzi, elementy
typu „przeciągnij i upuść”, edytory bogatego tekstu i paski przewijania.

Zadania zamiast treści

Pamiętaj, że aplikacje internetowe są „zaprojektowane, aby pomóc
użytkownikowi w wykonywaniu określonych zadań”. Mapy Google dostarczają
użytkownikom wskazówki ułatwiające dotarcie pod wskazany adres.
Użytkownicy usługi Gmail tworzą wiadomości e-mail. Użytkownicy serwisu
Trello zarządzają listami. Użytkownicy serwisu SchoolPress komentują
zdarzenia zachodzące w klasie.

Część aplikacji nadal koncentruje się na treści. Typowa sesja w
aplikacji Facebook lub Twitter obejmuje 90% czasu czytania. Jednak same
aplikacje zapewniają możliwość przeglądania treści w inny sposób niż w
przypadku tradycyjnej witryny internetowej.

Loginy

Loginy i konta pozwalają aplikacji internetowej zapisywać informacje o
użytkownikach. Te informacje są później używane podczas wykonywania
głównych zadań aplikacji i dla zapewnienia trwałego przechowywania
danych. Po zalogowaniu się użytkownik serwisu SchoolPress widzi, których
tematów nie przeczytał. Otrzymuje również nazwę użytkownika określającą
jego aktywność w aplikacji.

Aplikacja internetowa może też mieć grupy użytkowników. W przypadku
aplikacji SchoolPress istnieją administratorzy nadzorujący wewnętrzny
sposób działania aplikacji, nauczyciele tworzący klasy oraz uczniowie
biorący udział w dyskusjach prowadzonych w klasach.

Wykorzystanie możliwości urządzeń

Aplikacja internetowa uruchomiona w smartfonie może uzyskać dostęp do
aparatu fotograficznego, książki adresowej, wewnętrznego magazynu
danych, dostarczanych przez GPS informacji o położeniu itd. Z kolei
aplikacja internetowa uruchomiona w tradycyjnym komputerze może mieć
dostęp do kamery internetowej i dysku twardego. Ta sama aplikacja
internetowa może reagować odmiennie w zależności od urządzenia, w którym
została uruchomiona. Aplikacja internetowa dostosuje się do wielkości
ekranu, rozdzielczości i możliwości urządzenia.

Praca w trybie offline

Gdy jest to możliwe, dobrym rozwiązaniem jest zapewnienie aplikacji
możliwości działania w trybie offline. Oczywiście interaktywność
internetu jest tym, co definiuje „internetową” część aplikacji. Jednak
witryna internetowa, działająca, gdy jedziesz samochodem w tunelu,
będzie przypominała bardziej aplikację.

W przypadku serwisu Gmail wiadomość e-mail można tworzyć w trybie
offline. Evernote pozwala na tworzenie notatek w trybie offline, a
następnie ich synchronizację z internetem po przywróceniu połączenia.

Mashupy

Istnieje możliwość połączenia jednej lub więcej aplikacji internetowych.
Aplikacja internetowa może wykorzystywać różne usługi sieciowe i API w
celu przekazywania i pobierania danych. Możesz mieć aplikację
internetową pobierającą dane o położeniu, np. długość i szerokość
geograficzną, z serwisu Twitter lub Foursquare i przekazującą je do
serwisu Mapy Google.

Aplikacje mobilne

Wydanie pierwsze tej książki zostało opublikowane w 2012 roku — od
tamtej chwili jesteśmy świadkami gwałtownego rozwoju aplikacji
internetowych, w szczególności aplikacji mobilnych. W większości witryn
internetowych urządzenia mobilne wyprzedziły tradycyjne komputery i
generują najwięcej ruchu sieciowego (źródło: Perficient Inc.,
https://www.perficientdigital.com/insights/
our-research/mobile-vs-desktop-usage-study).

W 2012 roku typowa aplikacja internetowa wyglądała jak Basecamp,
oprogramowanie menedżera projektu dostępne w komputerze za pomocą
przeglądarki WWW. Natomiast w 2019 roku typowa aplikacja internetowa
wygląda jak Twitter, aplikacja komunikacyjna dostępna za pomocą
smartfona działającego pod kontrolą systemu iOS lub Android.

Ponieważ w większości przypadków duża część użytkowników uzyskuje dostęp
do witryny internetowej i aplikacji za pomocą urządzeń mobilnych,
podczas projektowania i tworzenia aplikacji internetowych stosowane jest
podejście „najpierw wersja mobilna”. Temat natywnego uruchamiania
aplikacji WordPressa zostanie omówiony w rozdziale 16. Natomiast
podstawy projektu responsywnego i przygotowanie witryny internetowej do
prawidłowego wyświetlania na ekranie o każdej wielkości dokładniej
omówimy w rozdziale 4.

Progresywne aplikacje internetowe

Progresywne aplikacje internetowe (ang. progressive web apps, PWA) to
witryny internetowe, które wykorzystują zalety funkcji nowoczesnych
przeglądarek WWW umożliwiające działanie tych witryn jak natywnych
aplikacji w systemach iOS, Android oraz w tradycyjnych komputerach. W
szczególności witryny internetowe używające tzw. usług roboczych do
funkcjonowania w trybie offline mają plik manifestu aplikacji
internetowej, który pozwala zdefiniować aplikację w systemie operacyjnym
oraz spełnić kilka innych wymagań, aby możliwe było uruchamianie takiej
aplikacji bezpośrednio z przeglądarki WWW.

Orędownikiem progresywnych aplikacji internetowych był zespół Google
Chrome, a teraz te aplikacje są obsługiwane także w systemie iOS oraz w
większości nowoczesnych przeglądarek WWW. Dostępna jest wtyczka
(https://wordpress.org/plugins/pwa/) oferująca obsługę podstawowych
funkcji PWA w WordPressie. Dzięki tej wtyczce można witrynę internetową
WordPressa zmienić w aplikację PWA. Wprawdzie to jest dobry pomysł, ale
w rzeczywistości tworzenie kodu PWA jest bardziej związane z
nastawieniem niż z faktyczną konwersją. Podobnie jak w przypadku
przedstawionych wcześniej „funkcji aplikacji internetowej” strona główna
PWA w serwisie Google (https://web.dev/ progressive-web-apps/) zawiera
listę m.in. następujących funkcji oczekiwanych od większości aplikacji
typu PWA (https://web.dev/pwa-checklist/):

-   witryna korzysta z protokołu HTTPS;
-   strony są responsywne w tabletach i innych urządzeniach mobilnych;
-   wszystkie adresy URL aplikacji działają po jej przejściu do trybu
    offline;
-   dostarczone są metadane pozwalające dodać witrynę do ekranu głównego
    urządzenia;
-   pierwsze wczytanie witryny jest szybkie nawet w przypadku połączenia
    3G;
-   witryna działa w każdej przeglądarce WWW;
-   przejścia między stronami nie blokują sieci;
-   każda strona ma adres URL.

Poza wymienionymi tutaj podstawowymi funkcjami istnieje także lista
rzeczy do sprawdzenia dla „wzorowych” aplikacji typu PWA obejmujących UX
i wydajność działania. Narzędzie Lighthouse firmy Google
(https://developers.google.com/web/tools/lighthouse/) oferuje testy
zautomatyzowane i raporty dotyczące spełniania kryteriów PWA. Nawet
aplikacje w pełni natywne lub utworzone dla przeglądarki WWW mogą
czerpać korzyści z pewnych sugestii zamieszczonych na liście rzeczy do
sprawdzenia PWA oraz w raportach Lighthouse.

Dlaczego WordPress?

Żaden język programowania lub narzędzie nie będzie odpowiednim wyborem
do wykonania każdego zadania. Wkrótce się dowiesz, dlaczego nie należy
wybierać WordPressa, teraz natomiast chcemy się skoncentrować na
sytuacjach, w których wykorzystanie WordPressa do utworzenia aplikacji
internetowej jest dobrym rozwiązaniem.

Jesteś już użytkownikiem WordPressa

Jeżeli już używasz WordPressa do udostępnienia głównej witryny
internetowej, dodanie niezbędnej funkcjonalności będzie wymagało
niewiele pracy. WordPress oferuje ogromny wybór wtyczek dla e-commerce
(WooCommerce), forów (bbPress), witryn obsługi użytkowników (Paid
Member-ships Pro), funkcjonalności związanej z serwisami
społecznościowymi (BuddyPress) i gamifikacją (BadgeOS).

Budowa aplikacji internetowej na podstawie istniejącej witryny
internetowej WordPressa pozwoli na dużą oszczędność czasu i ułatwi pracę
jej użytkownikom. Dlatego jeśli aplikacja jest dość prosta, można
utworzyć dla witryny WordPressa własną wtyczkę zawierającą
funkcjonalność niezbędną dla aplikacji internetowej.

Jeżeli jesteś zadowolony z użycia WordPressa w istniejącej witrynie, nie
martw się, słysząc, że musisz uaktualnić coś jeszcze, aby dodać
określoną funkcjonalność do witryny. Prawdopodobnie to nieprawda. Nie
musisz pozbywać się wykonanej dotąd pracy w WordPressie, a wcześniej
zdobyte doświadczenie to doskonały powód, by pozostać przy wyborze tej
właśnie platformy.

Zarządzanie treścią w WordPressie jest łatwe

Na początku WordPress opracowano jako platformę przeznaczoną do
publikacji blogów. Na przestrzeni lat ewoluował i wraz z wprowadzeniem
niestandardowych typów postów (ang. custom post types, CPT) w wydaniu
3.0 WordPress zyskał w pełni funkcjonalny system zarządzania treścią
(ang. content management system, CMS). Każda strona lub post mogą być
edytowane przez administratorów za pomocą panelu głównego (ang.
dashboard), do którego dostęp odbywa się za pomocą przeglądarki WWW.
Więcej informacji na temat pracy z CPT znajdziesz w rozdziale 5.

WordPress ułatwia dodawanie i edytowanie treści dzięki edytorowi
działającemu w trybie WYSIWYG (ang. what you see is what you get), więc
nie musisz się zwracać do projektanta internetowego za każdym razem, gdy
chcesz wprowadzić prostą zmianę w witrynie internetowej. Ponadto możesz
tworzyć własne menu i elementy nawigacyjne dla witryny nawet bez
tworzenia jakiegokolwiek kodu.

Jeżeli aplikacja internetowa koncentruje się na treści (np. podstawowe
funkcje aplikacji SchoolPress to zlecanie zadań i dyskusje), to omówione
w rozdziale 5. API CPT dla WordPressa pozwala na łatwe i szybkie
przygotowanie treści dla użytkowników i zarządzanie nią.

Nawet w przypadku aplikacji bardziej ukierunkowanych na zadania zwykle
istnieje kilka stron zawierających informacje, dokumentację i inne dane,
np. związane ze sprzedażą. Użycie WordPressa do utworzenia aplikacji
internetowej oznacza, że aplikacją i jej całą treścią możesz zarządzać
w jednym miejscu.

Łatwe i bezpieczne zarządzanie użytkownikami w WordPressie

WordPress zawiera wszystko to, co jest potrzebne w celu dodawania
użytkowników administracyjnych i końcowych do witryny internetowej.

Poza kontrolą dostępu do treści system ról i możliwości w WordPressie
jest rozszerzalny oraz pozwala kontrolować, które akcje są dostępne dla
poszczególnych grup użytkowników. Na przykład domyślnie użytkownik w
roli o nazwie contributor może dodawać nowe posty, ale nie może ich
publikować. Podobnie można tworzyć nowe role i definiować nowe
możliwości, aby w ten sposób zarządzać dostępem do własnego systemu
funkcjonalności.

Wtyczki takie jak Paid Membership Pro rozszerzają wbudowane możliwości
zarządzania użytkownikami i pozwalają na desygnowanie członków na
różnych poziomach i kontrolowanie treści, do której użytkownicy mają
dostęp. Przykładowo można utworzyć poziom zapewniający dostęp do treści
dodatkowej witryny WordPressa tym użytkownikom, którzy wykupili taką
możliwość.

Wtyczki

W repozytorium WordPressa istnieje ponad 55 000 bezpłatnie dostępnych
wtyczek (https://wordpress. org/plugins/). Znacznie większa liczba
wtyczek, zarówno płatnych, jak i bezpłatnych, jest dostępna w innych
witrynach internetowych. Gdy wpadniesz na pomysł, by utworzyć
rozszerzenie dla witryny internetowej, istnieje duże prawdopodobieństwo,
że taka wtyczka została już wcześniej opracowana, co pozwala
zaoszczędzić czas i pieniądze.

W repozytorium znajdziesz wiele niezastąpionych wtyczek, które
ostatecznie znajdą zastosowanie w każdej tworzonej przez Ciebie witrynie
internetowej i aplikacji internetowej.

W praktycznie każdej tworzonej witrynie internetowej będziesz chciał
m.in. zastosować buforowanie danych wyjściowych (co pozwala przyspieszyć
operacje przeglądania stron), wykorzystać narzędzia takie jak Google
Analytics do śledzenia odwiedzających, utworzyć mapę witryny, dostosować
ustawienia strony w taki sposób, aby stała się przyjazna technikom
optymalizacji dla wyszukiwarek internetowych (ang. search engine
optimization, SEO).

Istnieje wiele doskonałych wtyczek przeznaczonych do wykonywania
wymienionych funkcji. W książce przedstawimy nasze ulubione, a pełną ich
listę znajdziesz w witrynie poświęconej książce
(https://web.archive.org/web/20191103020221/https://bwawwp.com/plugins/).

Elastyczność ma duże znaczenie

WordPress to w pełni wyposażony framework oferujący naprawdę potężne
możliwości. Został zbudowany w oparciu o technologie PHP, JavaScript i
MySQL, więc to, co można utworzyć za pomocą PHP i MySQL (czyli
praktycznie wszystko), można także dość łatwo zrobić w aplikacji
WordPressa.

Ogólnie rzecz biorąc, WordPress oraz PHP i MySQL to nie jest doskonałe
rozwiązanie dla każdego zadania, choć to połączenie sprawdza się w wielu
różnych przypadkach. Wykorzystanie jednej platformy rozwijającej się
wraz z firmą pozwala na szybsze działanie i dostosowywanie się do zmian.
Oto typowy proces rozwoju i rozbudowy witryny w przypadku witryny
internetowej startupu zbudowanej w WordPressie:

1.  Zaprezentowanie startupu za pomocą witryny internetowej składającej
    się z jednej strony.
2.  Dodanie formularza umożliwiającego gromadzenie adresów e-mail.
3.  Dodanie bloga.
4.  Skoncentrowanie się na technikach SEO i optymalizacji całej treści.
5.  Przekazywanie postów bloga do serwisów Twitter i Facebook.
6.  Dodanie forum.
7.  Użycie wtyczki Paid Membership Pro, aby umożliwić użytkownikom
    wnoszenie opłat za dostęp do treści witryny internetowej.
8.  Dodanie niestandardowych formularzy, narzędzi i funkcjonalności
    aplikacji dla użytkowników płacących za dostęp do treści.
9.  Uaktualnienie interfejsu użytkownika za pomocą frameworków i technik
    JavaScriptu.
10. Dostosowanie witryny internetowej i serwera do skalowania.
11. Lokalizacja witryny internetowej i aplikacji dla różnych krajów i
    języków.
12. Dodanie obsługi progresywnej aplikacji internetowej.
13. Przygotowanie opakowań iOS i Android dla aplikacji internetowej.

Pozytywnym aspektem przejścia przez ten proces jest to, że na każdym
etapie masz do dyspozycji tę samą bazę danych użytkowników i korzystasz
z tej samej platformy programistycznej.

Częste uaktualnienia zabezpieczeń

Fakt wykorzystywania WordPressa przez witryny internetowe powoduje, że
stanowi on cel dla hakerów próbujących złamać jego zabezpieczenia. W
przeszłości części hakerów to się udało, na szczęście programiści
tworzący WordPressa dość szybko reagują na znalezione luki w
zabezpieczeniach i wydają usuwające je poprawki. Można to porównać do
sytuacji, w której miliony osób nieustannie testują i poprawiają
oprogramowanie, ponieważ dokładnie z tym mamy do czynienia.

Architektura stojąca za WordPressem powoduje, że stosowanie uaktualnień
to proces szybki i bezproblemowy, nawet dla użytkowników dopiero
rozpoczynających pracę z tą platformą. Jeżeli potrafisz zainstalować i
uaktualnić WordPress do najnowszej dostępnej wersji, wówczas dla witryny
internetowej masz do dyspozycji znacznie bezpieczniejszą platformę niż
jakakolwiek inna aktualnie dostępna. Tematem zapewnienia bezpieczeństwa
zajmiemy się w rozdziale 8.

Koszt

WordPress jest bezpłatny, PHP jest bezpłatny, MySQL jest bezpłatny i
większość wtyczek WordPressa jest bezpłatnych.

Wprawdzie serwery i hosting wymagają opłat, ale w zależności od
wielkości aplikacji internetowej i natężenia generowanego przez nią
ruchu sieciowego ten koszt może być względnie niewielki. Jeżeli wymagasz
funkcjonalności niedostępnej w żadnej istniejącej wtyczce, wtedy będzie
trzeba zatrudnić programistę i zlecić mu utworzenie odpowiedniej
wtyczki. Jeżeli sam jesteś programistą, nie musisz ponosić tego kosztu i
wystarczy, że poświęcisz trochę czasu na opracowanie wtyczki.

Odpowiedź na często pojawiającą się krytykę wybranych aspektów WordPressa

Dość często można spotkać się z opinią, że WordPress nie jest dobrym
frameworkiem do tworzenia aplikacji internetowych lub nawet że w ogóle
nie jest frameworkiem. Szanując prawo innych do wypowiedzi, w tym
miejscu chcielibyśmy wyjaśnić, dlaczego nie zgadzamy się z takimi
opiniami. W kolejnych punktach odniesiemy się do często pojawiającej się
krytyki.

WordPress jest przeznaczony tylko do tworzenia blogów

Spora grupa osób jest przekonana, że jeśli WordPress powstał w celu
tworzenia blogów, to sprawdza się dobrze tylko w tym zakresie.

Takie stwierdzenia mogły być prawdziwe kilka lat temu. Jednak ostatnio w
WordPressie zaimplementowano oferującą dość potężne możliwości
funkcjonalność CMS, więc platforma stała się użyteczna także dla innych
witryn internetowych skoncentrowanych na treści. Obecnie WordPress to
najpopularniejszy system zarządzania treścią, a jego udział w rynku
szacuje się na 60%[2]. Na rysunku 1.1 możesz zobaczyć slajd z
prezentacji „State of WordPress”, przygotowanej przez Matta Mullenwega
na konferencję WordCamp San Francisco 2013. Widoczny po lewej stronie
trójkąt skierowany do dołu przedstawia WordPress z mniej więcej 2006
roku, gdy większość kodu tworzącego ten framework była przeznaczona do
obsługi aplikacji bloga, a tylko niewielka część dla systemu CMS i kodu
platformy. Z kolei widoczny po prawej stronie trójkąt przedstawia
aktualny stan platformy WordPress, w której większość kodu jest związana
z samą platformą wraz ze znajdującą się nad nią warstwą CMS, aplikacja
bloga zaś działa na warstwie CMS. Obecnie WordPress to znacznie
stabilniejsza platforma niż kilka lat temu.

[]

Rysunek 1.1. Wykresy przygotowane przez Matta Mullenwega w 2013 roku na
potrzeby prezentacji „State of WordPress”. WordPress nie zawsze był
stabilny

API CPT można wykorzystać do usprawnienia instalacji WordPressa i
zapewnienia obsługi typów treści innych niż posty bloga lub strony
internetowe. Więcej informacji na ten temat znajdziesz w rozdziale 5.

WordPress jest przeznaczony tylko dla stron z treściami

Podobnie jak w przypadku stwierdzenia „tylko dla bloga”, część osób
twierdzi, że WordPress jest przeznaczony tylko dla witryn internetowych
skoncentrowanych na treści.

Po pierwsze, jeżeli WordPress byłby przeznaczony tylko dla
skoncentrowanych na treści witryn internetowych i aplikacji, to i tak
oznacza ogromną liczbę aplikacji. Na ekranie głównym smartfona
prawdopodobnie masz wiele aplikacji koncentrujących się na treści, np.
Netflix, Twitter, Face-book, Reddit, Evernote. To są przykłady bardzo
popularnych aplikacji opracowanych przez ogromne firmy. Oczywiście nie
sugerujemy, że powinny one działać w oparciu o WordPress, natomiast
sugerujemy, że aplikacje o podobnym sposobie działania można zbudować,
wykorzystując do tego framework WordPress.

Po drugie, jak się dowiesz z lektury niniejszej książki, WordPress to
doskonały framework przeznaczony także do tworzenia bardziej
interaktywnych aplikacji internetowych. Podstawową funkcją pozwalającą
na wykorzystanie WordPressa jako frameworka jest API wtyczek, które
umożliwia sprawdzenie domyślnego sposobu działania WordPressa i jego
zmianę. Nie tylko masz dostęp do tysięcy wtyczek znajdujących się w
repozytorium WordPressa i na różnych stronach w internecie, ale również
za pomocą API wtyczek możesz przygotować własne wtyczki przeznaczone do
wykonywania wszelkich zadań, które są możliwe do zrealizowania z użyciem
PHP i MySQL.

WordPress się nie skaluje

Niektórzy będą wskazywać na domyślną instalację WordPressa uruchomioną w
usłudze hostingu o małych możliwościach i zwracać uwagę na spowolnienie
działania witryny internetowej lub jej awarie w przypadku dużego
obciążenia i na tej podstawie wyciągać wniosek, że WordPress się nie
skaluje.

Być może uśmiałbyś się, gdybyś usłyszał o możliwości zbudowania witryny
typu Facebook za pomocą WordPressa.

W rzeczywistości wiele witryn internetowych notujących ogromny ruch
sieciowy zbudowano w oparciu o WordPress. Witryna wordpress.com została
zbudowana w dokładnie taki sam sposób jak każda inna korzystająca z
WordPressa i jest jedną z najczęściej odwiedzanych witryn internetowych
na świecie.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeżeli masz zamiar utworzyć aplikację internetową na miarę Facebooka, nie jest to odpowiednia książka dla Ciebie. Zapytaj CTO, jaki odsetek wielomiliardowego budżetu jest przeznaczony na potrzeby związane z utworzeniem aplikacji i zatrudnieniem inżynierów z firm Google i Amazon, którzy będą potrzebni do pracy nad tą niestandardową aplikacją internetową.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Wraz ze wzrostem poziomu użycia aplikacji internetowej konieczne będzie
uaktualnianie i wymienianie poszczególnych komponentów, aby sprostać tej
skali. Problemy związane ze skalowaniem WordPressa są dokładnie takie
same jak podczas skalowania każdej innej aplikacji: buforowanie stron i
danych, znacznie szybsza obsługa zapytań do bazy danych i poprawienie
wydajności działania sieci. Ogromne witryny takie jak wordpress.com,
TechCrunch i blogi New York Timesa są skalowane w WordPressie. Podobnie
większość wniosków wyciągniętych ogólnie ze skalowania aplikacji PHP i
MySQL ma zastosowanie dla WordPressa. Tematem skalowania zajmiemy się w
rozdziale 14.

WordPress nie zapewnia bezpieczeństwa

Podobnie jak w przypadku innych produktów typu open source także
WordPress wiąże się z pewnymi kompromisami w zakresie zapewnienia
bezpieczeństwa.

Z jednej strony ogromna popularność WordPressa oznacza, że będzie on
celem hakerów szukających luk w zabezpieczeniach. Skoro kod źródłowy
został udostępniony jako open source, potencjalne luki w
zabezpieczeniach są łatwiejsze do znalezienia.

Z drugiej strony, ponieważ kod źródłowy WordPressa jest właśnie typu
open source, dość szybko dowiesz się o znalezionych lukach w
zabezpieczeniach, a ktoś inny prawdopodobnie usunie je za Ciebie.

Czujemy się znacznie bezpieczniej, wiedząc, że choć wiele osób próbuje
wykorzystać luki w zabezpieczeniach, inne starają się zabezpieczyć
WordPressa przed wykorzystaniem tych braków. Nie wierzymy w „zapewnienie
bezpieczeństwa przez niejawność”, chyba że jest ona stosowana jako
dodatkowy środek. Zamiast tego wolimy, aby znalezione luki w
zabezpieczeniach oprogramowania wychodziły na światło dzienne, niż
pozostały nieujawnione aż do najgorszego z możliwych momentów.

W rozdziale 8. znacznie dokładniej zajmiemy się omówieniem kwestii
zapewnienia bezpieczeństwa — m.in. przedstawimy listę najlepszych
praktyk w zakresie zabezpieczania instalacji WordPressa, a także
podpowiemy, jak tworzyć bezpieczniejszy kod.

Wtyczki WordPressa są beznadziejne

API wtyczek w WordPressie oraz tysiące dostępnych wtyczek opracowanych z
wykorzystaniem tego API to tajna broń i według nas podstawowy powód, dla
którego WordPress zyskał tak ogromną popularność i odniósł duży sukces
jako platforma dla witryn internetowych.

Można się spotkać ze stwierdzeniem typu „oczywiście, że są dostępne
tysiące wtyczek, ale większość z nich jest kiepska”. W porządku, część
wtyczek na pewno jest kiepska.

Jednak istnieje naprawdę wiele wtyczek, które zdecydowanie są użyteczne
— wśród nich znajduje się AppPresser opracowana przez jednego z autorów
tej książki, Briana Messenlehnera. Jeżeli używasz WordPressa do
zarządzania treścią pisaną lub sklepem internetowym, wówczas wtyczka
AppPresser i platforma to najszybszy sposób na otrzymanie tej treści lub
sklepu internetowego w aplikacji mobilnej.

Paid Memberships Pro opracowana przez drugiego autora książki, Jasona
Colemana, również zalicza się do użytecznych wtyczek. Pozwala ona
obsługiwać rachunki wystawiane użytkownikom witryny internetowej, dzięki
czemu można się skoncentrować na podstawowej funkcjonalności aplikacji
zamiast zmagać się z integracją witryny z bramkami płatności.

Wiele wtyczek wykonuje bardzo proste zadania (np. ukrycie paska
administracyjnego dla użytkowników niebędących administratorami), działa
zgodnie z oczekiwaniem i naprawdę trudno je uznać za kiepskie.

Motywy i wtyczki znajdujące się w repozytorium WordPressa są przez
wolontariuszy sprawdzane pod kątem zapewnienia bezpieczeństwa i jakości
kodu. Proces Theme Review Team (https://make.
wordpress.org/themes/handbook/review/required/) jest coraz bardziej
rygorystyczny i rozbudowany niż pozostałe. Projekt Tide
(https://make.wordpress.org/tide/) ma na celu opracowanie testów
zautomatyzowanych do sprawdzania repozytoriów wtyczek i motywów, co
powinno zapewnić dostęp do wysokiej jakości wtyczek i uaktualnień, a
jednocześnie pozwolić na szybsze wykrywanie problemów związanych z
zachowaniem zgodności i zapewnieniem bezpieczeństwa.

Nawet słaba wtyczka może zostać poprawiona, utworzona na nowo lub
stanowić punkt wyjścia do opracowania kolejnej, która będzie działała
lepiej. Czasami okazuje się, że utworzenie wtyczki od nowa jest
łatwiejsze niż poprawienie kiepskiej. Mimo to i tak jesteś w znacznie
lepszej sytuacji, niż gdybyś musiał zupełnie od początku tworzyć
wszystko to, co jest potrzebne do działania budowanej aplikacji
internetowej.

Nikt nie zmusza Cię do stosowania wtyczek WordPressa bez ich
wcześniejszego sprawdzenia. Jeżeli budujesz poważną aplikację
internetową, kod wtyczki powinieneś dokładnie sprawdzić samodzielnie
i poprawić go w taki sposób, aby spełniał Twoje standardy, a dopiero
potem przejść do następnego zadania.

Kiedy nie używać WordPressa?

WordPress na pewno nie jest rozwiązaniem dla każdej aplikacji. W tym
podrozdziale przedstawimy kilka sytuacji, w których nie należy używać
WordPressa do budowania aplikacji internetowej.

Planujesz licencjonować lub sprzedawać technologię witryny internetowej

WordPress jest dostępny na licencji GPLv2, która nakłada pewne
ograniczenia związane ze sposobem rozpowszechniania oprogramowania
utworzonego za pomocą narzędzi na tej licencji. Przede wszystkim nie
można ograniczać sposobów wykorzystania oprogramowania po jego sprzedaży
lub dostarczeniu.

Wprawdzie to jest złożony temat, ale podstawowa idea polega na tym, że
jeśli tylko sprzedajesz lub zapewniasz dostęp do aplikacji, nie musisz
się przejmować GPLv2. Jeżeli jednak sprzedajesz lub rozpowszechniasz kod
źródłowy aplikacji, wówczas licencja GPLv2 ma zastosowanie dla
rozpowszechnianego kodu.

Przykładowo jeśli na własnym serwerze prowadzisz hosting aplikacji
SchoolPress i sprzedajesz konta zapewniające dostęp do aplikacji, nie
jest to uznawane za rozpowszechnianie i licencja GPLv2 nie ma tutaj
znaczenia.

Jeżeli chcesz umożliwić instytucjom edukacyjnym instalowanie
oprogramowania i uruchamianie go na własnych serwerach, wówczas musisz
im udostępnić kod źródłowy. To jest uznawane za dystrybucję. Klient
będzie mógł legalnie i bezpłatnie przekazać dalej ten kod źródłowy,
nawet jeśli musiał zapłacić za oprogramowanie. Konieczne jest użycie
licencji GPLv2, która nie zezwala na ograniczenie tego, co użytkownik
może zrobić z kodem źródłowym po jego pobraniu.

Inna platforma szybciej doprowadzi Cię do celu

Jeżeli masz zespół doświadczonych programistów języka Ruby, aplikację
internetową powinieneś utworzyć właśnie w tym języku. Jeżeli istnieje
platforma, framework lub paczka zawierająca 80% funkcji niezbędnych dla
Twojej aplikacji internetowej, a WordPress nie oferuje niczego
podobnego, wówczas prawdopodobnie powinieneś skorzystać z innej
platformy.

Elastyczność jest bez znaczenia

Jedną z najważniejszych zalet witryny internetowej opartej na
WordPressie jest możliwość szybkiej zmiany jej poszczególnych
komponentów, aby lepiej pasowała do Twoich potrzeb. Przykładowo jeśli
„polubienia” na Facebooku przestaną być użyteczne, można odinstalować
wtyczkę Facebook Connect i zainstalować wtyczkę zapewniającą obsługę
serwisu Pinterest.

Ogólnie rzecz biorąc, uaktualnianie motywu lub zastępowanie wtyczek
witryny WordPressa będzie odbywało się szybciej niż samodzielne
opracowywanie danej funkcjonalności zupełnie od początku na innej
platformie. Jeżeli jednak optymalizacja i wydajność działania mają dużo
większe znaczenie niż możliwość szybkiego uaktualniania aplikacji, wtedy
opracowanie aplikacji natywnej lub programowanie bezpośrednio w PHP
będzie lepszym rozwiązaniem.

Jeżeli aplikacja będzie wykonywać jedno proste zadanie, powinna zostać
utworzona na niższym poziomie. Przykładowo serwer licencji wtyczki Paid
Membership Pro to w zasadzie pojedynczy plik JSON informacji dodatkowych
oraz mały skrypt sprawdzający klucze licencji i dostarczający spakowane
pliki. Jason zbudował serwer licencji bezpośrednio w kodzie PHP i w
ogromnym stopniu wykorzystał buforowanie. Ten serwer działa na
kosztującym 10 USD miesięcznie DigitalOcean Sroplet i obsługuje ponad 80
000 witryn internetowych wraz z działającą wtyczką Paid Membership Pro.

Podobnie jeśli masz zasoby dostępne dla Facebooka, możesz pozwolić sobie
na samodzielne zbudowanie czegokolwiek, wykorzystanie własnych
kompilatorów PHP do C, a także natywnych komponentów iOS w celu
skrócenia o kilka milisekund czasu wczytywania witryny internetowej
i aplikacji.

Aplikacja musi działać w czasie rzeczywistym

Jedną z potencjalnych wad WordPressa, na której temat więcej dowiesz się
z dalszej części książki, jest oparcie na typowej architekturze serwera
WWW. W typowej konfiguracji WordPressa użytkownik przechodzi pod
określony adres URL, co powoduje nawiązanie komunikacji z serwerem WWW
(takim jak Apache) za pomocą protokołu HTTP, uruchomienie skryptu PHP
generującego stronę, która następnie zostaje zwrócona użytkownikowi.

Jest wiele sposobów na poprawę wydajności działania tej architektury za
pomocą technik buforowania i/lub optymalizacji konfiguracji serwera.
Istnieje możliwość asynchronicznego działania WordPressa dzięki
wywołaniom w technologii AJAX lub dostępu do bazy danych za pomocą
alternatywnych klientów. Jeżeli jednak aplikacja musi działać w czasie
rzeczywistym i być w pełni asynchroniczna (przykładem może być aplikacja
czatu internetowego lub gra wieloosobowa), wówczas masz nasze
błogosławieństwo i możesz dobrze się zastanowić, czy na pewno chcesz
skorzystać z WordPressa.

Wielu programistów WordPressa, w tym także Matt Mullenweg — założyciel i
przywódca duchowy tej platformy, zdaje sobie sprawę ze wspomnianego
ograniczenia. Coraz więcej funkcjonalności jest przenoszonych do języka
JavaScript pozwalającego na przeprowadzanie obliczeń w przeglądarce WWW
oraz do frameworków takich jak React zapewniających wysoką
interaktywność aplikacji internetowej. Nowy edytor Gutenberg, dodany w
WordPressie 5.0, jest najlepszym przykładem tego trendu i wskazuje
kierunek, w którym podąża platforma. Jednak na razie trzeba się zmagać z
drogą pod górę, aby zapewnić asynchroniczne działanie WordPressa z
wydajnością porównywalną do aplikacji natywnej, utworzonej całkowicie w
Node.js lub za pomocą innych technologii przeznaczonych specjalnie dla
aplikacji działających w czasie rzeczywistym.

WordPress jako framework aplikacji

Systemy zarządzania treścią takie jak WordPress, Drupal i Joomla są
często wykluczane z dyskusji związanych z frameworkami. Jednak w
rzeczywistości WordPress (szczególnie) to doskonały przykład pokazujący,
do czego są przeznaczone frameworki: do szybkiego tworzenia aplikacji.

W ciągu zaledwie kilku minut można skonfigurować WordPressa i otrzymać w
pełni funkcjonalną aplikację wraz z obsługą użytkowników, zarządzaniem
sesją, zarządzaniem treścią oraz panelem głównym przeznaczonym do
monitorowania aktywności witryny internetowej.

Różne API, obiekty i funkcje pomocnicze omówione w książce umożliwiają
bardzo szybkie tworzenie skomplikowanych aplikacji, bez konieczności
zajmowania się kwestiami związanymi z integracją tej aplikacji z
systemami działającymi na niższym poziomie.

Na rysunku 1.2 pokazaliśmy trójkąt pochodzący z przedstawionej w 2013
roku prezentacji „State of WordPress”. Na podstawie tego rysunku
WordPress jawi się jako platforma wraz z umieszczoną na niej warstwą
CMS, na której z kolei znajduje się aplikacja bloga.

[]

Rysunek 1.2. Platforma WordPress

Rzeczywistość jest taka, że większość obecnej bazy kodu obsługuje
platformę aplikacji. Każde wydanie WordPressa należy traktować jako
framework aplikacji połączony z przykładową aplikacją bloga.

WordPress kontra frameworki MVC

Model – widok – kontroler (ang. model-view-controller, MVC) to wzorzec
projektowy używany w wielu frameworkach przeznaczonych do tworzenia
oprogramowania. Najważniejszą korzyścią wynikającą z użycia architektury
MVC jest możliwość wielokrotnego użycia kodu i rozdzielenia zadań.
WordPress nie stosuje architektury MVC, ale ma własny sposób zachęcający
do wielokrotnego użycia kodu i separacji zadań.

Tutaj pokrótce wyjaśnimy architekturę MVC i sposób jej mapowania na
proces programowania w WordPressie. Jeżeli masz doświadczenie w pracy z
frameworkami MVC, to informacje przedstawione w tym punkcie powinny
pomóc w zrozumieniu podejścia, które w WordPressie pozwoli programować w
sposób podobny jak w przypadku MVC.

Na rysunku 1.3 pokazaliśmy typową aplikację zbudowaną na podstawie
wzorca MVC. Użytkownik końcowy korzysta z kontrolera przeprowadzającego
operacje wpływające na stan aplikacji za pomocą modelu, który następnie
uaktualnia widok wyświetlany użytkownikowi. Przykładowo w aplikacji
bloga użytkownik może patrzeć na stronę ostatnio opublikowanych postów
(widok). Następnie może kliknąć tytuł posta, co spowoduje przejście pod
nowy adres URL (kontroler), co z kolei oznacza wczytanie danych posta
(model) i wyświetlenie pojedynczego posta (inny widok).

[]

Rysunek 1.3. Sposób działania architektury MVC

Architektura MVC obsługuje wielokrotne użycie kodu i umożliwia
współpracę modelom, widokom i kontrolerom. Przykładowo widok, zarówno
ostatnio opublikowanych postów, jak i wyświetlający treść pojedynczego
posta, może do wyświetlania danych posta używać tego samego modelu.
Z kolei te same modele można wykorzystać we frontendzie do wyświetlania
postów, w backendzie zaś do ich edycji. Architektura MVC obsługuje
separację zadań przez umożliwienie projektantom koncentracji na
widokach, a programistom — na modelach.

Możesz spróbować użyć architektury MVC w WordPressie. Istnieje wiele
projektów, które mają w tym pomóc. Jednak uważamy, że próba stosowania
architektury MVC w WordPressie może prowadzić do problemów, o ile
oficjalna obsługa MVC nie zostanie wprowadzona w jądrze WordPressa.
Dopóki tak się nie stanie, sugerujemy zastosowanie podejścia „zgodnego z
WordPressem”, które zostało omówione w tej książce.

Jeżeli mimo to wciąż jesteś zainteresowany podejściem MVC w WordPressie,
zwróć uwagę na wtyczkę WP MVC (https://wordpress.org/plugins/wp-mvc/),
która jest aktywnie rozwijana i pozwala stosować framework MVC podczas
tworzenia wtyczek WordPressa. Jeżeli nie chcesz lub nie potrzebujesz
pełnej architektury MVC, istnieje kilka sposobów mapowania procesu MVC
na WordPressa.

Modele = wtyczki

We frameworku MVC kod przechowujący struktury danych i logikę biznesową
znajduje się w modelach. To na tworzenie modeli programiści poświęcają
najwięcej czasu.

W WordPressie wtyczka to odpowiednie miejsce na przechowywanie nowych
struktur danych, złożonej logiki biznesowej oraz niestandardowych typów
postów.

Jednak takie porównanie jest nie najlepsze z kilku powodów. Po pierwsze,
wiele wtyczek dodaje funkcjonalność przypominającą widok i zawiera
elementy projektowe — rozważ np. wtyczkę dodającą widżet umieszczany na
stronach internetowych. Po drugie, formularze i inne komponenty
projektowe używane w panelu głównym WordPressa są, ogólnie rzecz biorąc,
obsługiwane przez wtyczki.

Jednym ze sposobów na zapewnienie bardziej wyraźnie zarysowanej
separacji zadań podczas dodawania przypominających widoki komponentów do
wtyczek WordPressa jest utworzenie katalogu templates lub pages i
umieszczenie w nim kodu frontendu. Często stosowana praktyka pozwala
szablonom nadpisywać szablony wykorzystane przez wtyczkę. Przykładowo
gdy używasz wtyczki Paid Membership Pro, katalog
paid-memberships-pro/pages można umieścić w aktywnym motywie, aby w ten
sposób nadpisać domyślne szablony stron. (Dokładniejsze omówienie tej
techniki nadpisywania szablonów wtyczki znajdziesz w rozdziale 4.).

Widoki = motywy

We frameworku MVC kod odpowiedzialny za wyświetlanie danych
użytkownikowi zostaje umieszczony w widokach. To właśnie na ich
tworzenie projektanci i programiści frontendu poświęcają najwięcej
czasu.

W WordPressie motywy to odpowiednie miejsce na umieszczenie kodu i
logiki szablonów.

Warto przypomnieć ponownie, że przedstawione tutaj porównanie nie jest
do końca prawidłowe. Mimo to stwierdzenie widoki = motywy to dobry punkt
wyjścia.

Kontrolery = procedury wczytujące szablony

We frameworku MVC kod odpowiedzialny za przetwarzanie danych wejściowych
użytkownika (w postaci adresów URL lub danych $_GET bądź $_POST) oraz
ustalający, które z modeli i widoków będą obsługiwały dane żądanie, jest
przechowywany w kontrolerach. Kod kontrolera jest, ogólnie rzecz biorąc,
obsługiwany przez programistę, a po pierwotnym utworzeniu często
pozostaje zapomniany. Sedno programowania w aplikacji MVC odbywa się w
modelach i widokach. Jednak pomimo tego kontrolery to komponenty
odgrywające ważne role w sposobie działania aplikacji.

W przypadku aplikacji WordPressa wszystkie żądania stron (o ile nie
dotyczą buforowanych plików .html) przechodzą przez plik index.php i są
przetwarzane przez WordPressa zgodnie z hierarchią szablonów. Procedura
wczytująca szablon ustala, który plik szablonu powinien zostać użyty do
wyświetlenia strony użytkownikowi końcowemu. Przykładowo plik search.php
jest używany do pokazania wyników wyszukiwania, plik single.php do
wyświetlenia pojedynczego posta itd.

To zachowanie domyślne można zmodyfikować za pomocą API WP_Rewrite (jego
dokładne omówienie znajdziesz w rozdziale 7.) oraz innych zaczepów i
filtrów. Informacje dotyczące hierarchii szablonów
(https://developer.wordpress.org/themes/basics/template-hierarchy/)
znajdziesz w książce WordPress Theme Handbook. W niniejszej książce
temat hierarchii szablonów będzie dokładniej omówiony w rozdziale 4.

Jeżeli chcesz lepiej zrozumieć sposób działania frameworków MVC, to na
stronie frameworka PHP o nazwie Yii
(https://www.yiiframework.com/doc/guide/1.1/en/basics.best-practices)
znajduje się doskonałe wyjaśnienie, jak najlepiej używać architektury
MVC[3].

Więcej informacji na temat tworzenia aplikacji internetowych za pomocą
frameworka WordPress znajdziesz w dalszej części tej książki.

Anatomia aplikacji internetowej WordPressa

W tym podrozdziale przedstawimy aplikację, która będzie budowana w
książce: SchoolPress. Zaprezentujemy funkcjonalność aplikacji
SchoolPress, sposób jej działania i użytkowników, dla których została
przeznaczona. Co najważniejsze z pespektywy czytelnika tej książki,
dokładnie pokażemy, jak każdy fragment tej aplikacji został utworzony w
WordPressie.

Nie przejmuj się, jeśli nie będziesz rozumieć znaczenia pewnych pojęć w
stosowanej tutaj terminologii. W dalszych rozdziałach książki powrócimy
do omówienia aplikacji SchoolPress i przedstawimy wszystko znacznie
dokładniej. Gdy tylko będzie to możliwe, będziemy starać się wskazywać
rozdział zawierający dokładniejsze omówienie danej funkcjonalności.

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Celem tej książki nie jest pokazać krok po kroku, jak utworzyć aplikację SchoolPress. Gdy ma to sens, fragment aplikacji SchoolPress został użyty w przykładowych fragmentach kodu prezentowanych w książce. Dzięki temu nie musisz poświęcać czasu na próbę zrozumienia każdego z przedstawionych przykładów.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Czym jest SchoolPress?

SchoolPress to aplikacja internetowa ułatwiająca nauczycielom pracę z
uczniami poza klasą w szkole. Nauczyciel może tworzyć klasy i zapraszać
do nich uczniów. Każda klasa ma przypisane forum przeznaczone na
dyskusje, a bardziej strukturalny system dla nauczycieli umożliwia im
publikowanie zadań, które muszą być wykonywane przez uczniów.

Działanie aplikacji SchoolPress możesz zobaczyć w witrynie internetowej
https://schoolpress.me/. Kod źródłowy aplikacji znajduje się w archiwum
dostępnym pod adresem ftp://ftp.helion.pl/ przyklady/wordp2.zip.

SchoolPress działa w sieci zawierającej wiele witryn WordPressa

SchoolPress to działająca wersja WordPressa składająca się z wielu
witryn. Witryna główna zapewnia obsługę bezpłatnych kont pozwalających
nauczycielom zapisać się do systemu i rozpocząć tworzenie klas.
Obsługuje również wszystkie informacje marketingowe dla witryn
poszczególnych szkół w sieci, łącznie ze stronami przeznaczonymi m.in.
do zapisywania się do płatnych usług.

Szkoły mogą tworzyć unikatowe poddomeny przeznaczone dla klas
organizowanych przez nauczycieli z danej szkoły. Takie podejście
zapewnia dokładniejszą kontrolę i raportowanie informacji dla wszystkich
klas w szkole. Szczegóły dotyczące używania sieci zawierającej wiele
witryn internetowych WordPressa znajdziesz w rozdziale 12.

Model biznesowy SchoolPressa

Aplikacja SchoolPress używa wtyczek Paid Memberships Pro, PMPro Register
Helper i PMPro Network w celu dostosowania do własnych potrzeb procesu
rejestracji oraz akceptowania płatności kartami kredytowymi za
korzystanie z serwisu.

Szkoła może wykupić dla siebie unikatową poddomenę za roczną opłatą.
Inni użytkownicy SchoolPressa nie muszą płacić za dostęp do serwisu. Gdy
administrator szkoły zapisze się do aplikacji, może podać nazwę szkoły i
usług dla jej poddomeny, np. <nazwa_szkoły>.schoolpress.me. Dla szkoły
zostaje utworzona nowa witryna w sieci, a szkole jest zapewniony dostęp
do uproszczonej wersji panelu głównego WordPressa przeznaczonego dla
danej witryny internetowej.

Następnie administrator szkoły rozpoczyna zapraszanie uczniów do
systemu. Nauczyciele mogą również żądać zaproszenia do szkoły, które
musi być zaakceptowane przez administratora danej szkoły. Nauczyciel
może zapraszać uczniów do utworzonej przez siebie klasy. Z kolei
uczniowie mogą żądać zaproszenia do klasy, które musi być zaakceptowane
przez tworzącego ją nauczyciela.

Nauczyciele mogą bezpłatnie zapisywać się do serwisu SchoolPress i
organizować w nim klasy. Strony wyświetlane w poddomenie klasy mogą
zawierać reklamy lub stosować inne rozwiązania pozwalające zarabiać
pieniądze. Szczegóły związane z konfiguracją e-commerce za pomocą
WordPressa będą dokładnie omówione w rozdziale 15.

Poziomy członkostwa i role użytkowników

Nauczyciele otrzymują członkostwo na poziomie Teacher (za pomocą Paid
Membership Pro) i własną rolę o nazwie Teacher, która pozwala tworzyć i
edytować klasy, moderować dyskusje na forach klasy oraz przygotowywać
zadania dla uczniów klasy.

Nauczyciele nie mają dostępu do panelu głównego WordPressa.
Organizowanie klas i zarządzanie nimi odbywa się za pomocą utworzonych
do tego celu formularzy frontendu.

Uczniowie otrzymują członkostwo na poziomie Student i domyślną rolę
Subscriber w WordPressie. Uczeń może przeglądać zajęcia tylko tych klas,
do których został zaproszony przez nauczyciela, i tylko w nich
uczestniczyć. Szczegóły związane z rolami i możliwościami użytkowników
zostaną omówione w rozdziale 6., natomiast w rozdziale 15. znajdziesz
informacje na temat poziomów członkostwa i kontroli dostępu.

Klasy są grupami BuddyPress

Gdy nauczyciel tworzy „klasę”, tak naprawdę tworzy grupę BuddyPress i
zaprasza do niej uczniów. Używając tej grupy, zyskuje dostęp do forów
dla klasy, prywatnego systemu komunikatów oraz eleganckiego sposobu
organizacji użytkowników.

Fora dyskusyjne klas działają w oparciu o wtyczkę bbPress. Dla każdej
klasy jest generowane nowe forum, BuddyPress zaś zarządza dostępem do
tych forów. Szczegóły związane z wykorzystaniem wtyczek zewnętrznych i
wtyczki bbPress znajdziesz w rozdziale 3.

Zadanie to przykład CPT

Zadanie to przykład niestandardowego typu posta (ang. custom post type,
CPT) pozwalającego nauczycielom na użycie formularza frontendu do
opublikowania nowych zadań. Zadanie przypomina domyślny post bloga w
WordPressie — zawiera tytuł, treść i dołączone pliki. Nauczyciel
publikujący dane zadanie jest autorem danego posta.

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   WordPress ma wbudowane typy, takie jak posty i strony, oraz wbudowane taksonomie, takie jak kategorie i tagi. W przypadku aplikacji SchoolPress tworzone są niestandardowe typy CPT i taksonomie. Więcej informacji na temat tworzenia niestandardowych typów postów i taksonomii znajdziesz w rozdziale 5.
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Rozwiązania zadań są podtypami CPT zadań

Uczeń może publikować komentarze dotyczące zadania, a także za pomocą
innego formularza frontendu przesyłać rozwiązanie zadania.

Rozwiązanie zadania, podobnie jak zadanie, również jest przykładem CPT.
Rozwiązanie zadania jest powiązane z zadaniem poprzez przypisanie polu
post_parent rozwiązania wartości identyfikatora zadania, dla którego
dane rozwiązanie zostało przekazane. Uczeń może przekazywać treść w
postaci tekstu, a także jednego lub więcej załączników.

Semestry to taksonomie dla CPT klasy

Niestandardowa taksonomia o nazwie Semester jest skonfigurowana dla
grupy/klasy CPT. Administrator szkoły może dodać nowe semestry do
witryn. Przykładowo można utworzyć semestr „jesień 2019”, do którego
następnie będą przypisywani nauczyciele organizujący klasy. Uczniowie
mogą bardzo łatwo przeglądać listę wszystkich klas semestru np. jesień
2019.

Wydział to taksonomia dla CPT klasy

Niestandardowa taksonomia o nazwie Department jest skonfigurowana dla
grupy/klasy CPT. Jest dostępna w postaci rozwijanej listy dla
nauczycieli podczas tworzenia przez nich klas. Uczniowie mogą przeglądać
klasy według wydziałów.

Aplikacja SchoolPress ma jedną główną niestandardową wtyczkę

W tle poszczególne fragmenty aplikacji SchoolPress są kontrolowane za
pomocą pojedynczej niestandardowej wtyczki o nazwie SchoolPress. Ta
wtyczka główna zawiera definicje dla różnych CPT, taksonomii i ról
użytkowników. We wtyczce znajduje się również kod przeznaczony do
modyfikacji sposobu działania innych wtyczek używanych przez
SchoolPress, takich jak Paid Memberships Pro i BuddyPress.

Wtyczka główna zawiera też klasy dla administratorów szkoły, nauczycieli
i uczniów, które rozszerzają klasę WP_User, oraz klasy przeznaczone do
tworzenia klas uczniów, zadań i rozwiązań — wszystkie one opakowują
klasę WP_Post. Te klasy (PHP) umożliwiają zdefiniowanie kodu w sposób
obiektowy, co ułatwia kontrolowanie sposobu wprowadzania zmian w kodzie
i jego przyszłą rozbudowę. Tworzenie tych klas przynosi radość, podobnie
jak praca z nimi. Przykład takiej klasy przedstawiliśmy na listingu 1.1.

Listing 1.1. Potencjalne zdarzenia dotyczące logowania użytkownika

    if($class->isTeacher($current_user))

    {

       // To jest nauczyciel, należy wyświetlić narzędzia dostępne dla nauczyciela

       //…

    }

    elseif($class->isStudent($current_user))

    {

        // To jest uczeń, należy wyświetlić narzędzia dostępne dla ucznia

       //…

    }

    elseif(is_user_logged_in())

    {

        // Jeżeli użytkownik jest niezalogowany, należy wyświetlić formularz logowania,

        // a dopiero później powrócić na tę stronę

        wp_redirect(wp_login_url(get_permalink($class->ID)));

        exit;

    } else {

        // Jeżeli użytkownik nie należy do klasy, należy go przekierować na stronę zaproszenia

        wp_redirect($class->invite_url);

        exit;

    }

Temat tworzenia niestandardowych wtyczek zostanie omówiony w rozdziale
3., a rozszerzenia klasy WP_User — w rozdziale 6.

Aplikacja SchoolPress używa kilku innych niestandardowych wtyczek

Czasami się zdarza, że fragmenty kodu utworzone dla konkretnej aplikacji
są użyteczne także w innych projektach. Jeżeli kod może być uruchomiony
poza kontekstem bieżącej aplikacji i wtyczki głównej, wówczas można go
umieścić w oddzielnej, niestandardowej wtyczce.

Przykładem może być tutaj wtyczka o nazwie Force First and Last Name as
Display Name (https://wordpress.org/plugins/force-first-last/), która
okazała się niezbędna dla omawianego projektu. Do działania nie wymaga
uruchomienia jakiegokolwiek innego kodu wtyczki głównej i jest użyteczna
także w innych witrynach internetowych WordPressa poza kontekstem
aplikacji School-Press. Dlatego zdecydowaliśmy się na utworzenie dla tej
funkcjonalności oddzielnej wtyczki i umieszczenie jej w repozytorium
WordPressa, aby również inni użytkownicy mieli dostęp do wymienionej
wtyczki.

Aplikacja SchoolPress używa motywu Memberlite

Witryna główna aplikacji SchoolPress wykorzystuje dostosowany do
własnych potrzeb motyw potomny Memberlite. Jeżeli administrator
zdecyduje się na wykupienie domeny premium, będzie miał do wyboru więcej
motywów potomnych Memberlite, a także możliwość zmiany kolorów, czcionek
i logo, aby w ten sposób lepiej dopasować witrynę do marki danej szkoły.
Wszystkie motywy wykorzystują projekt responsywny, więc strona
prezentuje się dobrze w urządzeniach o różnych wielkościach ekranu:
zarówno w tradycyjnych komputerach, jak i urządzeniach mobilnych.

Kod tworzący motyw Memberlite (https://memberlitetheme.com/) jest ściśle
ograniczony do zadań związanych z wyświetlaniem treści. Kod motywu
oczywiście zawiera kod HTML i CSS tworzące układ witryny, a także prostą
logikę pozwalającą na integrację z wtyczką główną SchoolPress. Natomiast
cały kod odpowiedzialny za przeprowadzanie operacji na niestandardowych
typach postów, rolach użytkowników lub wymagający wielu obliczeń znalazł
się we wtyczce głównej.

Skoro wiesz już, na czym polega działanie aplikacji SchoolPress, być
może zechcesz utworzyć podobną za pomocą WordPressa, zgodnie z podziałem
zadań w sposób „zgodny z WordPressem”. Przechodzimy więc do poznawania
WordPressa, jego zawartości i sposobu działania.

[1] Wiele idei przedstawionych w tej sekcji zostało zainspirowanych
następującymi postami z blogów: „What is a Web Application?” napisany
przez Dominique Hazae’l-Massieux i opublikowany na stronie
http://people.w3.org/~dom/ archives/2010/08/what-is-a-web-application/
oraz „What is a Web Application?” napisany przez Boba Baxleya
i opublikowany na stronie
http://boxesandarrows.com/what-is-a-web-application/.

[2] Na stronie W3Tech pod adresem
https://w3techs.com/technologies/overview/content_management dostępne są
aktualne dane dotyczące użycia różnych systemów zarządzania treścią.

[3] Yii to oparty na architekturze MVC framework PHP. Wprawdzie inne
frameworki PHP, takie jak Laravel (https://laravel.com/), są
popularniejsze wśród programistów WordPressa i ogólnie społeczności PHP,
ale dotycząca MVC dokumentacja w witrynie Yii została doskonale
napisana.

Rozdział 2. Podstawy WordPressa

WordPress opracowano w 2003 roku jako oprogramowanie przeznaczone przede
wszystkim do obsługi blogów. Jednak wraz z wydaniem wersji 3.5 obraz
WordPressa został zmieniony z oprogramowania bloga na wszechstronny
system zarządzania treścią, a słowo blog faktycznie zostało usunięte z
opisu oprogramowania i w większości z kodu źródłowego. WordPress stał
się największą platformą w internecie i obecnie jest używany w mniej
więcej 30% witryn internetowych. To niesamowite, jeśli się nad tym
głębiej zastanowić. Ponad pół miliarda witryn internetowych działa na
WordPressie.

Ta ogromna popularność WordPressa na przestrzeni lat wynika z wielu
powodów. Przede wszystkim WordPress to oprogramowanie typu open source,
dla którego istnieje duża społeczność zainteresowana usprawnianiem i
nieustannym rozwojem tej platformy. Użytkownicy WordPressa, programiści
i projektanci stale szukają nowych sposobów wykorzystania tego
frameworka i tworzą dla niego wtyczki, które są udostępniane
społeczności.

Następnym powodem ogromnego sukcesu WordPressa jest fakt, że jest to
niezwykle elastyczny system zarządzania treścią zawierający zaczepy i
filtry, więc programiści wtyczek i motywów zyskują niemalże całkowitą
kontrolę nad sposobami tworzenia zupełnie odmiennych rodzajów witryn
internetowych. Programiści nieustannie szukają nowych sposobów używania
oprogramowania, takich jak m.in. tworzenie witryn internetowych i
aplikacji mobilnych, na czym się skoncentrujemy w niniejszej książce.
Temat użycia zaczepów i filtrów zostanie omówiony w dalszej części
książki.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Przyjmujemy założenie, że potrafisz korzystać z WordPressa i zainstalowałeś najnowszą dostępną wersję tego frameworka. Jeżeli dopiero po raz pierwszy zetknąłeś się z WordPressem i chcesz go bliżej poznać, odwiedź witrynę domową platformy, którą znajdziesz pod adresem https://wordpress.org/.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Struktura katalogu WordPressa

Zapoznasz się teraz z ogólną strukturą plików i katalogów WordPressa,
które znajdują się w domyślnej instalacji frameworka.

Katalog główny

W katalogu głównym mamy kilka podstawowych plików WordPressa. O ile nie
zagłębiasz się do kodu WordPressa, szukając zaczepów do wykorzystania
lub próbując poznać sposób implementacji danej funkcjonalności, to
jedynym podstawowym plikiem tej platformy, do którego zechcesz
kiedykolwiek zajrzeć, jest wp-config.php. Nigdy przenigdy[1] nie
modyfikuj pozostałych podstawowych plików WordPressa. Grzebanie w tych
plikach jest kiepskim pomysłem, ponieważ po uaktualnieniu do nowszej
wersji wprowadzone przez Ciebie zmiany i tak zostaną nadpisane przez
WordPressa. Jedyny katalog, do którego możesz zaglądać, to wp-content,
gdyż zawiera on Twoje wtyczki, motywy i przekazane pliki.

Jeżeli zechcesz zmodyfikować któryś z podstawowych plików WordPressa,
dobrze się nad tym zastanów. Prawdopodobnie istnieje zaczep lub filtr,
który możesz wykorzystać, aby osiągnąć żądany cel. Jeśli nie ma takiego,
możesz go dodać i poprosić o dołączenie do podstawowych plików
WordPressa. Programiści tworzący WordPressa sprawnie reagują na prośby
dodania nowych zaczepów i filtrów.

W katalogu głównym WordPressa istnieje jeszcze tylko jeden plik, który
ewentualnie będziesz chciał zmodyfikować, w zależności od sposobu
konfiguracji i używania tej platformy: .htaccess. Tak naprawdę to nie
jest podstawowy plik WordPressa, lecz raczej plik serwera Apache, który
przez WordPressa jest używany do konfiguracji katalogu, łączy i
przekierowań. Ten plik nie jest domyślnie umieszczany w katalogu
WordPressa, lecz jest tworzony automatycznie dopiero podczas pierwszej
operacji definiowania struktury permalink. Zapoznaj się z opcjami
konfiguracyjnymi pliku .htaccess omówionymi na stronie pomocy
technicznej WordPressa pod adresem https://
wordpress.org/support/article/htaccess/.

/wp-admin

Ten katalog zawiera podstawowe pliki i katalogi przeznaczone do
zarządzania interfejsem panelu głównego obszaru administracyjnego
WordPressa. Plikiem o znaczeniu kluczowym w tym katalogu jest
admin-ajax.php, za pomocą którego powinny być wykonywane wszystkie
żądania w technologii AJAX. Dokładniejsze omówienie technologii AJAX
znajdziesz w rozdziale 9.

/wp-includes

Ten katalog zawiera podstawowe pliki i katalogi przeznaczone do
zarządzania różną funkcjonalnością WordPressa. Gorąco zachęcamy do
zapoznania się ze strukturą i kodem tego katalogu, aby jeszcze lepiej
zrozumieć wewnętrzny sposób działania WordPressa.

/wp-content

To jest katalog, w którym użytkownicy i programiści WordPressa mogą
robić, cokolwiek zechcą. Zawiera podkatalogi dla wtyczek i motywów
zainstalowanych w witrynie internetowej, a także dla wszelkich typów
plików multimedialnych przekazanych do witryny.

Katalog /wp-content zawiera kilka podkatalogów, które zostały pokrótce
omówione w kolejnych punktach.

/wp-content/plugins

Każda wtyczka instalowana w witrynie internetowej WordPressa trafi do
tego katalogu. Domyślnie WordPress jest dostarczany wraz z wtyczkami
Hello Dolly i Akismet.

Wtyczka Hello Dolly ma na celu pokrótce przedstawić podstawową
konfigurację wtyczki WordPressa. Działanie tej wtyczki polega na
wyświetleniu losowego wiersza z tekstu piosenki zatytułowanej Hello,
Dolly! w prawym górnym rogu panelu głównego obszaru administracyjnego.

Z kolei wtyczka Akismey pomaga w zatrzymaniu komentarzy spamu przez
sprawdzenie treści nowych komentarzy z bazą danych znajdującą się w
witrynie https://akismet.com/. Dzięki tej wtyczce i usłudze Akismet
można znacznie zmniejszyć liczbę komentarzy spamu wyświetlanych na
stronie głównej witryny internetowej. Usługa Akismet jest bezpłatna do
użytku prywatnego (projekt można również wspomóc dowolną kwotą).

/wp-content/themes

Każdy instalowany motyw WordPressa trafi to tego katalogu. Domyślnie
WordPress jest dostarczany wraz z kilkoma standardowymi motywami o
nazwach wskazujących rok ich wydania, np. Twenty Seventeen (2017),
Twenty Nineteen (2019) itd.

/wp-content/uploads

Gdy zaczniesz przekazywać zdjęcia lub pliki do biblioteki
multimedialnej, zauważysz, że ten katalog zacznie być wypełniany
przekazanymi plikami. Wszystkie przekazane pliki multimedialne są
przechowywane w katalogu uploads. Część wtyczek powoduje również
utworzenie w katalogu uploads podkatalogu przeznaczonego dla różnych
plików używanych lub zarządzanych przez wtyczkę.

/wp-content/mu-plugins

W WordPressie można wymusić stosowanie danej wtyczki przez utworzenie
podkatalogu mu-plugins w katalogu wp-content. Ten katalog nie istnieje
aż do chwili jego wyraźnego utworzenia. Człon mu w nazwie oznacza must
use (czyli używane obowiązkowo), a każda umieszczona w nim wtyczka
zostanie uruchomiona automatycznie bez konieczności jej ręcznego
aktywowania na administracyjnej stronie wtyczek. Szczerze mówiąc,
wtyczki obowiązkowe nie są nawet wyświetlane na tej stronie.

Wtyczki obowiązkowe są szczególnie użyteczne w przypadku instalacji
składających się z wielu witryn internetowych WordPressa, co pozwala
stosować wtyczki, których administratorzy poszczególnych witryn sieci
nie będą mogli dezaktywować.

Dobrym rozwiązaniem jest sprawdzanie katalogu mu-plugins po rozpoczęciu
pracy nad istniejącą witryną internetową, aby zobaczyć, czy zawiera
jakiekolwiek wtyczki, i jeśli tak, na czym polega ich działanie. Zbyt
wiele razy zdarzało się nam przeprowadzać związany z pewnym problemem
proces debugowania i byliśmy zadziwieni, skąd się bierze nieoczekiwane
zachowanie aplikacji pomimo wyłączenia wszystkich aktywnych wtyczek.
Dopiero później okazywało się, że źródłem problemu była przeoczona
wtyczka w katalogu mu-plugins.

Struktura bazy danych WordPressa

WordPress działa w oparciu o bazę danych MySQL i tworzy własne tabele
przeznaczone do przechowywania danych i treści. W tym podrozdziale
przedstawimy schemat bazy danych utworzony przez domyślną instalację
WordPressa. Zdecydowaliśmy się również na zamieszczenie pewnych
informacji podstawowych o funkcjach wbudowanych WordPressa
przeznaczonych do pracy z tymi tabelami. Jeżeli poznasz schemat bazy
danych i będziesz potrafić wygodnie pracować z funkcjami omówionymi w
tym rozdziale, zyskasz możliwość umieszczania lub pobierania dowolnych
danych z WordPressa.

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Wymienione tutaj nazwy tabel domyślnie używają prefiksu wp_. Podczas instalacji WordPressa masz możliwość zmiany tego prefiksu, więc dokładne nazwy tabel mogą być inne w Twojej instalacji.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

wp_options

Tabela wp_options zawiera tylko te dane, które mają zastosowanie dla
całej witryny internetowej. Znajdzie się tutaj nazwa, opis i e-mail
administratora podane podczas typowej instalacji WordPressa. W tej
tabeli znajduje się także kilka rekordów zawierających pewne ustawienia
domyślne WordPressa. Ogólną strukturę tabeli wp_options bazy danych
przedstawiliśmy w tabeli 2.1.

Tabela 2.1. Schemat bazy danych dla tabeli wp_options

  -------------- ------------- ------------------ --------------- ------------------ ----------------------
  Kolumna        Typ           Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  option_id      bigint(20)                       Nie             Brak               AUTO_INCREMENT
  option_name    varchar(64)   utf8_general_ci    Nie                                
  option_value   longtext      utf8_general_ci    Nie             Brak               
  autoload       varchar(20)   utf8_general_c     Nie             Yes                
  -------------- ------------- ------------------ --------------- ------------------ ----------------------

Aplikacje i wtyczki WordPressa zwykle przechowują ustawienia w tabeli
wp_options za pomocą funkcji zdefiniowanych w następnej sekcji. Te
ustawienia mogą być przechowywane w oddzielnych rekordach z użyciem
wspólnego prefiksu dla nazw opcji. W większości przypadków znacznie
większą wydajność można uzyskać dzięki umieszczeniu wszystkich opcji w
jednej tablicy i zapisaniu ich w jednym rekordzie tabeli wp_options.

Funkcje zdefiniowane w /wp-includes/option.php

Wymienione w tej sekcji funkcje zostały zdefiniowane w pliku
/wp-includes/option.php.

add_option( string $option, mixed $value = '', string $deprecated = '', string|bool $autoload = 'yes' )

Działanie tej funkcji polega na sprawdzeniu przed wstawieniem nowego
rekordu, czy option_name już istnieje.

$option

Wymagany ciąg tekstowy określający nazwę opcji option_name, która ma
zostać dodana.

$value

Opcjonalna zmienna wartości option_value przeznaczonej do dodania.
Jeżeli przekazaną zmienną jest tablica lub obiekt, wówczas wartość
zostanie zserializowana przed jej umieszczeniem w bazie danych.

$deprecated

Parametr uznany w wydaniu 2.3 WordPressa za przestarzały i nie jest już
używany[2].

$autoload

Opcjonalna wartość boolowska używana do określenia, czy opcja ma zostać
umieszczona w buforze po uruchomieniu WordPressa. Jej wartością może być
yes lub no. Wartością domyślną jest yes. Jeżeli masz pewność, że
potrzebujesz tej opcji na każdej wczytywanej stronie, wówczas możesz
pozostawić wartość domyślną yes. Jeśli natomiast dana opcja jest
potrzebna jedynie na określonych stronach, wtedy zwykle lepszym
rozwiązaniem będzie przypisanie wartości no.

update_option( $option, $newvalue )

Działanie tej funkcji polega na uaktualnieniu istniejącej opcji, a także
jej dodaniu, jeśli jeszcze nie istnieje.

$option

Wymagany ciąg tekstowy określający nazwę opcji option_name, która ma
zostać uaktualniona lub dodana.

$newvalue

Opcjonalna zmienna wartości option_value przeznaczonej do uaktualnienia
lub dodania.

get_option( $option, $default = false )

Działanie tej funkcji polega na pobraniu option_value dla podanej nazwy
option_name.

$option

Wymagany ciąg tekstowy określający nazwę opcji option_name, której
wartość ma zostać pobrana.

$newvalue

Opcjonalna zmienna, która ma zostać zwrócona, jeśli podana opcja
option_name nie istnieje w tabeli. Wartością domyślną tego parametru
jest false.

delete_option( $option )

Działanie tej funkcji polega na trwałym usunięciu opcji z bazy danych.

$option

Wymagany ciąg tekstowy określający nazwę opcji option_name, która ma
zostać usunięta.

  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Większość przykładów przedstawionych w tej książce nie ma postaci w pełni funkcjonalnego kodu, lecz są to jedynie proste teoretyczne przykłady użycia omawianej konstrukcji. Większość przykładowych fragmentów kodu można wypróbować we własnej wtyczce lub w pliku functions.php motywu.
  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

W listingu 2.1 przedstawiliśmy pewne podstawowe funkcje przeznaczone do
pracy z tabelą wp_options.

Listing 2.1. Dodawanie, uaktualnianie, pobieranie i usuwanie rekordów w
tabeli wp_options

    <?php

    // Dodanie opcji

    $twitters = array( '@bwawwp', '@bmess', '@jason_coleman' );

    add_option( 'bwawwp_twitter_accounts', $twitters );

    // Pobranie opcji

    $bwawwp_twitter_accounts = get_option( 'bwawwp_twitter_accounts' );

    echo '<pre>';

    print_r( $bwawwp_twitter_accounts );

    echo '</pre>';

    // Uaktualnienie opcji

    $twitters = array_merge(

             $twitters,

             array(

                     '@alphaweb',

                     '@pmproplugin'

             )

    );

    update_option( 'bwawwp_twitter_accounts', $twitters );

    // Pobranie opcji

    $bwawwp_twitter_accounts = get_option( 'bwawwp_twitter_accounts' );

    echo '<pre>';

    print_r( $bwawwp_twitter_accounts );

    echo '</pre>';

    // Usunięcie opcji

    delete_option( 'bwawwp_twitter_accounts' );

    /*

    Dane wyjściowe tego przykładu powinny być podobne do następujących:

    Array

    (

        [0] => @bwawwp

        [1] => @bmess

        [2] => @jason_coleman

    )

    Array

    (

        [0] => @bwawwp

        [1] => @bmess

        [2] => @jason_coleman

        [3] => @alphaweb

        [4] => @pmproplugin

    )

    */

    ?>

wp_users

Po zalogowaniu się do WordPressa za pomocą nazwy użytkownika i hasła
będziesz odwoływać się do danych przechowywanych w tej tabeli.
Informacje o wszystkich użytkownikach i ich dane domyślne są umieszczone
w tabeli wp_users. W tabeli 2.2 przedstawiliśmy strukturę bazy danych
dla tabeli wp_users.

Tabela 2.2. Schemat bazy danych dla tabeli wp_users

  --------------------- -------------- ------------------ --------------- --------------------- ----------------------
  Kolumna               Typ            Kodowanie znaków   Wartość null?   Wartość domyślna      Informacje dodatkowe
  ID                    bigint(20)                        Nie             Brak                  AUTO_INCREMENT
  user_login            varchar(60)    utf8_general_ci    Nie                                   
  user_pass             varchar(64)    utf8_general_ci    Nie                                   
  user_nicename         varchar(50)    utf8_general_ci    Nie                                   
  user_email            varchar(100)   utf8_general_ci    Nie                                   
  user_url              varchar(100)   utf8_general_ci    Nie                                   
  user_registered       datetime                          Nie             0000-00-00 00:00:00   
  user_activation_key   varchar(60)    utf8_general_ci    Nie                                   
  user_status           int(11)                           Nie             0                     
  display_name          varchar(250)   utf8_general_ci    Nie                                   
  --------------------- -------------- ------------------ --------------- --------------------- ----------------------

W przypadku wielu aplikacji WordPressa do tworzenia użytkowników i
zarządzania nimi będziesz wykorzystywać graficzny interfejs użytkownika
panelu głównego obszaru administracyjnego. Jeżeli zajdzie potrzeba
utworzenia użytkownika w kodzie lub uaktualnienia jego metadanych,
wówczas użyteczne okażą się funkcje omówione w następnej sekcji.

Funkcje zdefiniowane w plikach /wp-includes/pluggable.php i /wp-includes/user.php

Wymienione w tej sekcji funkcje zostały zdefiniowane w plikach
/wp-includes/pluggable.php i /wp-includes/user.php.

wp_insert_user( $userdata )

Ta funkcja wstawia nowego użytkownika do bazy danych. Funkcję można
wykorzystać również w celu uaktualnienia użytkownika, o ile jego
identyfikator został przekazany w $user_data. Parametr $userdata to
wymagana tablica nazw kolumn i wartości. Oto lista akceptowanych nazw
kolumn tej tablicy:

ID

Liczba całkowita, która zostanie użyta podczas uaktualniania
użytkownika.

user_pass

Ciąg tekstowy zawierający hasło dla użytkownika zapisane w postaci
zwykłego tekstu.

user_login

Ciąg tekstowy zawierający nazwę użytkownika, za pomocą której będzie się
on logował.

user_nicename

Ciąg tekstowy zawierający przyjazny dla użytkownika adres URL. Domyślnie
jest to nazwa użytkownika.

user_url

Ciąg tekstowy zawierający adres URL witryny internetowej użytkownika.

user_email

Ciąg tekstowy zawierający adres e-mail użytkownika.

display_name

Ciąg tekstowy, który zostanie wyświetlony w witrynie internetowej
użytkownika. Domyślnie jest nim nazwa użytkownika. Prawdopodobnie
zechcesz zmienić tę wartość.

nickname

Nick użytkownika. Domyślnie jest używana nazwa użytkownika.

first_name

Imię użytkownika.

last_name

Nazwisko użytkownika.

description

Ciąg tekstowy zawierający informacje o użytkowniku.

rich_editing

Ciąg tekstowy wskazujący, czy ma być włączony edytor bogatego tekstu.
Jeżeli to nie jest pusty ciąg tekstowy, oznacza wartość false.

user_registered

Data zarejestrowania użytkownika. Format daty to rok-miesiąc-dzień
godzina:minuta: sekunda.

role

Ciąg tekstowy określający rolę użytkownika.

wp_create_user( $username, $password, $email )

Ta funkcja wykorzystuje omówioną wcześniej wp_insert_user() i ułatwia
dodawanie nowego użytkownika na podstawie wymaganych kolumn.

$username

Ciąg tekstowy zawierający nazwę użytkownika, za pomocą której będzie się
on logował.

$password

Ciąg tekstowy zawierający hasło dla użytkownika zapisane w postaci
zwykłego tekstu.

$email

Ciąg tekstowy zawierający adres e-mail użytkownika.

wp_update_user( $userdata )

Tę funkcję można wykorzystać do uaktualnienia dowolnej kolumny w
tabelach wp_users i wp_usermeta (zostanie wkrótce omówiona) powiązanych
z określonym użytkownikiem. Trzeba w tym miejscu dodać, że uaktualnienie
hasła użytkownika spowoduje usunięcie wszystkich jego ciasteczek i
wylogowanie użytkownika z WordPressa.

$userdata

Wymagana tablica nazw kolumn i ich wartości. Konieczne jest podanie ID i
przynajmniej jednej innej kolumny. Te kolumny są dokładnie takie same
jak akceptowane przez funkcję wp_insert_post().

get_user_by( $field, $value )

Jeżeli działanie funkcji zakończy się pomyślnie, zwraca ona obiekt
WP_User, natomiast w przeciwnym przypadku wartością zwrotną jest false.
Klasa User WordPressa jest zdefiniowana w pliku
/wp-includes/capabilities.php i praktycznie wykonuje serię zapytań do
tabeli wp_user, np.:

    SELECT * FROM wp_users WHERE $field = $value;

Klasa WP_User buforuje wyniki, aby uniknąć wykonywania zapytań do bazy
danych za każdym razem, gdy klasa jest używana. Działanie tej klasy
obejmuje również ustalenie ról i możliwości danego użytkownika, co
znacznie dokładniej omówimy w rozdziale 6.

$field

Wymagany ciąg tekstowy kolumny, który będzie użyty w trakcie zapytania
dotyczącego danych użytkownika. Tym ciągiem tekstowym może być tylko id,
slug, email lub login.

$value

Wymagana liczba całkowita lub ciąg tekstowy wartości dla danej kolumny
id, slug, email lub login.

get_userdata( $userid )

Ta funkcja w rzeczywistości wykorzystuje omówioną wcześniej
get_user_by() i zwraca dokładnie ten sam obiekt WP_User.

$userid

Wymagana liczba całkowita określająca identyfikator użytkownika, którego
dane mają zostać pobrane.

wp_delete_user( $id, $reassign = 'brak wartości' )

Działanie tej funkcji polega na usunięciu użytkownika oraz ponownym
przypisaniu jego postów lub łączy innemu użytkownikowi.

$id

Wymagana liczba całkowita identyfikatora użytkownika przeznaczonego do
usunięcia.

$reassign

Opcjonalna liczba całkowita będąca identyfikatorem użytkownika, któremu
mają zostać przypisane posty lub łącza należące wcześniej do usuwanego
użytkownika. Na listingu 2.2 przedstawiliśmy przykłady użycia
podstawowych funkcji przeznaczonych do pracy z tabelą wp_users.

Listing 2.2. Praca z tabelą wp_users

    <?php

    // Wstawienie użytkownika

    $userdata = array(

      'user_login'    => 'brian',

      'user_pass'     => 'KO03gT7@n*',

      'user_nicename' => 'Brian',

      'user_url'      => 'https://alphaweb.com/',

      'user_email'    => 'brian@alphaweb.com',

      'display_name'  => 'Brian',

      'nickname'      => 'Brian',

      'first_name'    => 'Brian',

      'last_name'     => 'Messenlehner',

      'description'   => 'To jest konto administratora WordPressa.',

      'role'          => 'administrator'

    );

    wp_insert_user( $userdata );

    // Utworzenie użytkownika

    wp_create_user( 'jason', 'YR529G%*v@', 'jason@schoolpress.me' );

    // Pobranie użytkownika na podstawie jego loginu

    $user = get_user_by( 'login', 'brian' );

    echo 'e-mail: ' . $user->user_email  . ' / ID: ' . $user->ID . '<br>';

    echo 'Cześć: ' . $user->first_name . ' ' . $user->last_name . '<br>';

    // Pobranie użytkownika na podstawie jego adresu e-mail

    $user = get_user_by( 'email', 'jason@schoolpress.me' );

    echo 'Nazwa użytkownika: ' . $user->user_login . ' / ID: ' . $user->ID . '<br>';

    // Uaktualnienie kolumn pozwalających na zmianę nazwy użytkownika i jego roli na administratora

    $userdata = array(

      'ID'         => $user->ID,

      'first_name' => 'Jason',

      'last_name'  => 'Coleman',

      'user_url'   => 'http://strangerstudios.com/',

      'role'       => 'administrator'

    );

    wp_update_user( $userdata );

    // Pobranie danych dla użytkownika brian

    $user = get_userdata( $user->ID );

    echo 'Cześć: ' . $user->first_name . ' ' . $user->last_name . '<br>';

    // Usunięcie konta pierwotnego użytkownika administratora i przypisanie jego postów nowemu administratorowi

    // wp_delete_user( 1, $user->ID );

    /*

    Dane wyjściowe tego przykładu powinny być podobne do następujących:

    e-mail: brian@schoolpress.me / ID: 2

    Cześć: Brian Messenlehner

    Nazwa użytkownika: jason / ID: 3

    Cześć: Jason Coleman

    */

    ?>

wp_usermeta

Czasami zachodzi potrzeba przechowywania informacji dodatkowych w koncie
użytkownika. WordPress zapewnia taką możliwość bez konieczności
dodawania kolejnych kolumn do tabeli użytkowników. Dowolną ilość
niezbędnych metadanych można umieścić w tabeli wp_usermeta. Każdy rekord
zostaje za pomocą kolumny user_id powiązany z identyfikatorem
użytkownika w tabeli wp_user. W tabeli 2.3 przedstawiliśmy strukturę
bazy danych dla tabeli wp_usermeta.

Tabela 2.3. Schemat bazy danych dla tabeli wp_usermeta

  ------------ -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna      Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  umeta_id     bigint(20)                        Nie             Brak               AUTO_INCREMENT
  user_id      bigint(20)                        Nie             0                  
  meta_key     varchar(255)   utf8_general_ci    Tak             NULL               
  meta_value   longtext       utf8_general_ci    Tak             NULL               
  ------------ -------------- ------------------ --------------- ------------------ ----------------------

get_user_meta( $user_id, $key = '', $single = false )

Ta funkcja pobiera metawartość dla podanego klucza.

$user_id

Wymagana liczba całkowita określająca identyfikator użytkownika.

$key

Opcjonalny ciąg tekstowy metaklucza wartości, która ma zostać zwrócona.
Jeżeli ten parametr nie zostanie podany, zostaną zwrócone wszystkie
metadane przechowywane dla danego użytkownika.

$single

Wartość boolowska określająca, czy ma zostać zwrócona pojedyncza
wartość. Domyślnie jest to false, co oznacza, że wartością zwrotną
funkcji jest tablica.

Może istnieć więcej niż jeden metaklucz dla tego samego identyfikatora
użytkownika. Jeżeli parametrowi $single zostanie przypisana wartość
true, funkcja zwróci tylko wartość pierwszego klucza. Natomiast wartość
false parametru $single powoduje zwrócenie przez funkcję tablicy
wartości dla każdego rekordu zawierającego ten sam klucz.

update_user_meta( $user_id, $meta_key, $meta_value, $prev_value = '' )

Działanie tej funkcji polega na uaktualnieniu metadanych użytkownika, a
także na wstawieniu metadanych w sytuacji, gdy przekazany klucz jeszcze
nie istnieje.

$user_id

Wymagana liczba całkowita określająca identyfikator użytkownika.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
umieszczona w tabeli. Jeżeli podany metaklucz już istnieje, nastąpi
uaktualnienie jego wartości w bieżącym rekordzie. W przeciwnym razie
zostanie wstawiony nowy rekord.

$meta_value

Wymagana wartość w postaci liczby całkowitej, ciągu tekstowego, tablicy
lub obiektu. Tablice i obiekt będą automatycznie serializowane.

$prev_value

Wartość opcjonalna przedstawiająca bieżącą wartość metadanych. Jeżeli
zostanie znalezione dopasowanie, wartość poprzednia (bieżąca) zostanie
zastąpiona nową. Jeżeli nie podasz wartości tego parametru, nowa
metawartość zastąpi pierwsze wystąpienie dopasowanego klucza. W
przypadku gdy masz np. pięć wierszy metadanych o takim samym kluczu i
nie wskażesz rekordu przeznaczonego do uaktualnienia, zostanie
uaktualniony pierwszy z nich, cztery pozostałe zaś zostaną usunięte.

  ---- ------------------------------------------------------------------------------------------------------------------------------
  []   Działanie omawianej funkcji opiera się na funkcji update_metadata() zdefiniowanej w pliku /wp-includes/meta.php. Sprawdź to!
  ---- ------------------------------------------------------------------------------------------------------------------------------

add_user_meta( $user_id, $meta_key, $meta_value, $unique = false )

Ta funkcja powoduje wstawienie do tabeli wp_usermeta zupełnie nowych
metadanych dla użytkownika. Funkcja nie będzie używana zbyt często,
ponieważ update_user_meta() również pozwala wstawiać nowe rekordy oraz
uaktualniać istniejące. Jeżeli chcesz mieć pewność, że dany metaklucz
zostanie zastosowany tylko raz dla danego użytkownika, skorzystaj z tej
funkcji i przypisz wartość true jej parametrowi $unique.

$user_id

Wymagana liczba całkowita określająca identyfikator użytkownika.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
umieszczona w tabeli.

$meta_value

Wymagana wartość w postaci liczby całkowitej, ciągu tekstowego, tablicy
lub obiektu.

$unique

Opcjonalna wartość boolowska — jeśli będzie nią true, wymieniony
metaklucz będzie mógł być dodany tylko raz dla danego identyfikatora.

delete_user_meta( $user_id, $meta_key, $meta_value = '' )

Działanie tej funkcji polega na usunięciu metadanych dla podanego
identyfikatora użytkownika i dopasowanego klucza. Istnieje możliwość
dopasowania metawartości, jeśli chcesz usunąć tylko tę wartość, a nie
inne rekordy metadanych o takim samym metakluczu.

$user_id

Wymagana liczba całkowita określająca identyfikator użytkownika.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
usunięta z tabeli.

$meta_value

Wartość opcjonalna przedstawiająca wartość meta. Jeżeli istnieje więcej
niż jeden rekord z tym samym metakluczem, można wskazać rekord
przeznaczony do usunięcia przez dopasowanie metawartości. Domyślnie ten
parametr nie jest ustawiony, co powoduje usunięcie wszystkich
metarekordów dopasowanych przez user_id i meta_key.

Na listingu 2.3 możesz zobaczyć w działaniu podstawowe funkcje
przeznaczone do pracy z tabelą wp_username.

Listing 2.3. Praca z tabelą wp_username table

    <?php

    // Pobranie identyfikatora użytkownika brian

    $brian_id = get_user_by( 'login', 'brian' )->ID;

    // Dodanie metadanych użytkownika — wartością parametru unique jest true

    add_user_meta( $brian_id, 'bwawwp_wife', 'Married to the game', true);

    // Pobranie metadanych użytkownika — zwrot pojedynczej wartości

    $brians_wife = get_user_meta( $brian_id, 'bwawwp_wife', true);

    echo "Żona Briana: " . $brians_wife . "<br>";

    // Dodanie metadanych użytkownika — trzecim parametrem jest unikatowa wartość

    add_user_meta( $brian_id, 'bwawwp_kid', 'Dalya' );

    add_user_meta( $brian_id, 'bwawwp_kid', 'Brian' );

    add_user_meta( $brian_id, 'bwawwp_kid', 'Nina' );

    add_user_meta( $brian_id, 'bwawwp_kid', 'Cam' );

    add_user_meta( $brian_id, 'bwawwp_kid', 'Aksel' );

    // Uaktualnienie metadanych użytkownika — to wywołanie spowoduje uaktualnienie brian do postaci brian jr

    update_user_meta( $brian_id, 'bwawwp_kid', 'Brian Jr', 'Brian' );

    // Pobranie metadanych użytkownika — zwrot tablicy

    $brians_kids = get_user_meta( $brian_id, 'bwawwp_kid' );

    echo "Dzieci Briana:";

    echo '<pre>';

    print_r($brians_kids);

    echo '</pre>';

    // Usunięcie metadanych użytkownika brian

    delete_user_meta( $brian_id, 'bwawwp_wife' );

    delete_user_meta( $brian_id, 'bwawwp_kid' );

    // Pobranie identyfikatora użytkownika jason

    $jason_id = get_user_by( 'login', 'jason' )->ID;

    // Uaktualnienie metadanych użytkownika — spowoduje to utworzenie metadanych,

    // jeśli podany klucz jeszcze nie istnieje dla danego użytkownika

    update_user_meta( $jason_id, 'bwawwp_wife', 'Kimberly Ann Coleman' );

    // Pobranie tablicy metadanych użytkownika

    $jasons_wife = get_user_meta( $jason_id, 'bwawwp_wife' );

    echo "Żona Jasona:";

    echo '<pre>';

    print_r($jasons_wife);

    echo '</pre>';

    // Dodanie metadanych użytkownika — będą przechowywane w postaci tablicy

    add_user_meta( $jason_id, 'bwawwp_kid', array( 'Isaac', 'Marin' ) );

    // Pobranie metadanych użytkownika — zwrot pojedynczej wartości, która będzie tablicą

    $jasons_kids = get_user_meta( $jason_id, 'bwawwp_kid', true );

    echo "Dzieci Jasona:";

    echo '<pre>';

    print_r($jasons_kids);

    echo '</pre>';

    // Usunięcie metadanych użytkownika jason

    delete_user_meta( $jason_id, 'bwawwp_wife' );

    delete_user_meta( $jason_id, 'bwawwp_kid' );

    /*

    Dane wyjściowe tego przykładu powinny być podobne do następujących:

    Żona Briana: Married to the game

    Dzieci Briana:

    Array

    (

        [0] => Dalya

        [1] => Brian Jr

        [2] => Nina

        [3] => Cam

        [4] => Aksel

    )

    Żona Jasona:

    Array

    (

        [0] => Kimberly Ann Coleman

    )

    Dzieci Jasona:

    Array

    (

        [0] => Isaac

        [1] => Marin

    )

    */

    ?>

wp_posts

Tabela wp_posts jest przeznaczona do przechowywania większości danych
postów. Domyślnie WordPress jest dostarczany wraz z postami i stronami.
Z technicznego punktu widzenia w obu przypadkach mamy do czynienia z
postami, które są przechowywane w tej tabeli. Pole post_type pozwala na
odróżnianie typów postów — tzn. czy jest to post, strona, element menu,
wersja czy CPT, który później utworzysz (dokładne omówienie CPT
znajdziesz w rozdziale 5.). W tabeli 2.4 przedstawiliśmy strukturę bazy
danych dla tabeli wp_posts.

Tabela 2.4. Schemat bazy danych dla tabeli wp_posts

  ----------------------- -------------- ------------------ --------------- --------------------- ----------------------
  Kolumna                 Typ            Kodowanie znaków   Wartość null?   Wartość domyślna      Informacje dodatkowe
  ID                      bigint(20)                        Nie             Brak                  AUTO_INCREMENT
  post_author             bigint(20)                        Nie             0                     
  post_date               datetime                          Nie             0000-00-00 00:00:00   
  post_date_gmt           datetime                          Nie             0000-00-00 00:00:00   
  post_content            longtext       utf8_general_ci    Nie             Brak                  
  post_title              text           utf8_general_ci    Nie             Brak                  
  post_excerpt            text           utf8_general_ci    Nie             Brak                  
  post_status             varchar(20)    utf8_general_ci    Nie             publish               
  comment_status          varchar(20)    utf8_general_ci    Nie             open                  
  ping_status             varchar(20)    utf8_general_ci    Nie             open                  
  post_password           varchar(20)    utf8_general_ci    Nie                                   
  post_name               varchar(200)   utf8_general_ci    Nie                                   
  to_ping                 text           utf8_general_ci    Nie             Brak                  
  pinged                  text           utf8_general_ci    Nie             Brak                  
  post_modified           datetime                          Nie             0000-00-00 00:00:00   
  post_modified_gmt       datetime                          Nie             0000-00-00 00:00:00   
  post_content_filtered   longtext       utf8_general_ci    Nie             Brak                  
  post_parent             bigint(20)                        Nie             0                     
  guid                    varchar(255)   utf8_general_ci    Nie                                   
  menu_order              int(11)                           Nie             0                     
  post_type               varchar(20)    utf8_general_ci    Nie             post                  
  post_mime_type          varchar(100)   utf8_general_ci    Nie                                   
  comment_count           bigint(20)                        Nie             0                     
  ----------------------- -------------- ------------------ --------------- --------------------- ----------------------

Funkcje zdefiniowane w /wp-includes/post.php

Wymienione w tej sekcji funkcje zostały zdefiniowane w pliku
/wp-includes/post.php.

wp_insert_post( $postarr, $wp_error = false )

Działanie tej funkcji polega na wstawieniu nowego posta wraz z danymi
przekazanymi w poście.

$postarr

Tablica lub obiekt zawierający przekazane dane. W przypadku tablic
oczekuje się stosowania znaków sterujących, natomiast w przypadku
obiektów nie.

$wp_error

Opcjonalna wartość boolowska — jeśli jest nią false, możliwe będzie
użycie obiektu WP_Error.

Oto wartości domyślne dla parametru $postarr:

post_status

Wartością domyślną jest draft.

post_type

Wartością domyślną jest post.

post_author

Wartością domyślną jest identyfikator bieżącego użytkownika ($user_ID).
Jest to identyfikator użytkownika, który dodał post.

ping_status

Wartością domyślną jest wartość opcji default_ping_status. Ta wartość
określa, czy załącznik może akceptować żądania ping.

post_parent

Wartością domyślną jest 0. Określa post, do którego należy dany post, o
ile w ogóle istnieje post nadrzędny.

menu_order

Wartością domyślną jest 0. Określa kolejność, w jakiej jest wyświetlana
tablica.

to_ping

Określa post, do którego ma zostać wykonane żądanie ping.

pinged

Wartością domyślną jest pusty ciąg tekstowy.

post_password

Wartością domyślną jest pusty ciąg tekstowy. Jest to hasło dostępu do
załącznika.

guid

Globalnie unikatowy identyfikator odwołania do załącznika.

post_content_filtered

Określa, czy zawartość posta została przefiltrowana.

post_excerpt

Fragment posta.

wp_update_post( $postarr = array(), $wp_error = false )

Ta funkcja uaktualnia post dostarczonymi danymi posta.

$postarr

Tablica lub obiekt zawierający przekazane dane. W przypadku tablic
oczekuje się stosowania znaków sterujących, natomiast w przypadku
obiektów nie.

$wp_error

Opcjonalna wartość boolowska — jeśli jest nią false, możliwe będzie
użycie obiektu WP_Error.

get_post( $post = null, $output = OBJECT, $filter = 'raw' )

Ta funkcja pobiera dane posty z podanego identyfikatora lub obiektu
posta.

$post

Opcjonalna liczba całkowita identyfikatora lub obiektu posta, która ma
zostać pobrana. Wartością domyślną jest bieżący post w pętli posta, co
zostanie dokładnie omówione w dalszej części rozdziału.

$output

Opcjonalny ciąg tekstowy formatu danych wyjściowych. Wartością domyślną
jest OBJECT (WP_Post), innymi wartościami mogą być ARRAY_A (tablica
asocjacyjna) lub ARRAY_N (tablica liczbowa).

$filter

Opcjonalny ciąg tekstowy określający sposób oczyszczenia kontekstu
danych wyjściowych. Wartością domyślną jest raw, dostępne są także inne
wartości: edit, db, display, attribute i js. Temat oczyszczania będzie
omówiony w rozdziale 8.

get_posts( $args = null )

Ta funkcja zwraca listę postów spełniających kryteria. Wykorzystuje
klasę WP_Query, której przykłady użycia będziesz napotykać w całej
książce. Parametr $args to opcjonalna tablica argumentów posta. Oto
wartości domyślne elementów tej tablicy:

numberposts

Wartością domyślną jest 5. Całkowita liczba postów do pobrania, -1
oznacza pobranie wszystkich postów.

offset

Wartością domyślną jest 0. Jest to liczba postów do pominięcia.

category

Określa kategorię, z której mają pochodzić posty.

orderby

Wartością domyślną jest post_date. Określa kolejność postów.

order

Wartością domyślną jest DESC. Określa kolejność pobierania postów.

include

Określa listę identyfikatorów postów do uwzględnienia.

exclude

Określa listę identyfikatorów postów do wykluczenia.

meta_key

Dowolny klucz metadanych.

meta_value

Dowolna wartość metadanych. Konieczne jest również użycie meta_key.

post_type

Wartością domyślną jest post. Wartością może być również page,
attachment lub slug dla dowolnego CPT. Ciąg tekstowy any spowoduje zwrot
postów wszystkich typów.

post_parent

Identyfikator posta nadrzędnego danego posta.

post_status

Wartością domyślną jest publish. Jest to stan posta do pobrania.

wp_delete_post( $postid = 0, $force_delete = false )

Ta funkcja spowoduje wyrzucenie dowolnego posta do kosza lub jego trwałe
usunięcie, jeśli wartością $force_delete jest true.

$postid

Wymagana liczba całkowita określająca identyfikator posta przeznaczonego
do umieszczenia w koszu lub do usunięcia.

$force_delete

Opcjonalna wartość boolowska. Jeżeli będzie nią true, post zostanie
trwale usunięty. Natomiast brak wartości oznacza false i przypisanie
postowi stanu „umieszczony w koszu”.

W listingu 2.4 przedstawiliśmy przykłady użycia wybranych funkcji
podczas pracy z tabelą wp_posts.

Listing 2.4. Praca z tabelą wp_posts

    <?php

    // Wstawienie posta i zdefiniowanie jego stanu jako draft

    $args = array(

      'post_title'   => 'Tworzenie aplikacji internetowych w WordPressie',

      'post_excerpt' => 'WordPress to framework aplikacji',

      'post_content' => 'W większości sytuacji WordPress to klucz do osiągnięcia sukcesu

      podczas efektywnego pod względem kosztów przygotowywania rozwiązania internetowego.

      Niemal wszystko można utworzyć na bazie platformy WordPress. ZRÓB TO TERAZ!!!!',

      'post_status'  => 'draft',

      'post_type'    => 'post',

      'post_author'  => 1,

      'menu_order'   => 0

    );

    $post_id = wp_insert_post( $args );

    echo 'Identyfikator posta: ' . $post_id . '<br>';

    // Uaktualnienie posta i zmiana jego stanu na publish

    $args = array(

      'ID'  => $post_id,

      'post_status' => 'publish'

    );

    wp_update_post( $args );

    // Pobranie posta i zwrot jego danych w postaci obiektu

    $post = get_post( $post_id );

    echo 'Tytuł obiektu: ' . $post->post_title . '<br>';

    // Pobranie posta i zwrot jego danych w postaci tablicy

    $post = get_post( $post_id, ARRAY_A );

    echo 'Tytuł tablicy: ' . $post['post_title'] . '<br>';

    // Usunięcie posta z pominięciem kosza i jego trwałe usunięcie

    wp_delete_post( $post_id, true );

    // Pobranie postów i zwrot 100 postów

    $posts = get_posts( array( 'numberposts' => '100') );

    // Iteracja przez wszystkie posty, w trakcie której zostaną wyświetlone identyfikator i tytuł

    foreach ( $posts as $post ) {

      echo $post->ID . ': ' .$post->post_title . '<br>';

    }

    /*

    Dane wyjściowe tego przykładu powinny być podobne do następujących:

    Identyfikator posta: 589

    Tytuł obiektu: Tworzenie aplikacji internetowych w WordPressie

    Tytuł tablicy: Tworzenie aplikacji internetowych w WordPressie

    "Lista identyfikatorów postów i tytułów w Twojej instalacji"

    */

    ?>

wp_postmeta

Za każdym razem, gdy chcesz przechowywać dane dodatkowe wraz z postem,
WordPress w dość łatwy sposób oferuje taką możliwość bez konieczności
tworzenia kolejnych kolumn w tabeli postów. Dowolną ilość metadanych
można przechowywać w tabeli wp_postmeta. Każdy rekord zostaje za pomocą
kolumny post_id powiązany z postem. Gdy edytujesz dowolny post w
backendzie WordPressa, masz możliwość za pomocą interfejsu użytkownika
dodania, uaktualnienia lub usunięcia metadanych bądź kolumn
niestandardowych. W tabeli 2.5 przedstawiliśmy strukturę bazy danych dla
tabeli wp_postmeta.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Klucze metadanych o nazwach rozpoczynających się od znaku podkreślenia pozostają ukryte w interfejsie użytkownika na stronie edycji posta. Jest to użyteczne rozwiązanie pozwalające ukrywać metadane, których użytkownik nie powinien bezpośrednio edytować.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Tabela 2.5. Schemat bazy danych dla tabeli wp_postmeta

  ------------ -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna      Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  meta_id      bigint(20)                        Nie             Brak               AUTO_INCREMENT
  post_id      bigint(20)                        Nie             0                  
  meta_key     varchar(255)   utf8_general_ci    Tak             NULL               
  meta_value   longtext       utf8_general_ci    Tak             NULL               
  ------------ -------------- ------------------ --------------- ------------------ ----------------------

Funkcje zdefiniowane w /wp-includes/post.php

Wymienione w tej sekcji funkcje zostały zdefiniowane w pliku
/wp-includes/post.php.

get_post_meta( $post_id, $key = '', $single = false )

Ta funkcja pobiera metadane posta dla danego posta.

$post_id

Wymagana liczba całkowita identyfikatora posta, dla którego mają być
pobrane metadane.

$key

Opcjonalny ciąg tekstowy nazwy klucza metadanych, dla którego mają
zostać pobrane metadane. Wartością domyślną jest zwrot metadanych dla
wszystkich metakluczy zdefiniowanych dla określonego posta.

$single

Wartość boolowska określająca, czy ma zostać zwrócona pojedyncza
wartość. Wartością domyślną jest false, co oznacza zwrot wartości w
postaci tablicy.

Dla tego samego identyfikatora posta może być więcej niż jeden metaklucz
z różnymi wartościami. Jeżeli parametr $single będzie miał przypisaną
wartość true, otrzymasz wartość pierwszego klucza. Natomiast wartość
false oznacza pobranie tablicy wartości wszystkich rekordów o takim
samym kluczu.

update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' )

Ta funkcja uaktualnia metadane posta, a także wstawia metadane, jeśli
przekazany klucz jeszcze nie istnieje.

$post_id

Wymagana liczba całkowita identyfikatora posta.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
umieszczona w tabeli. Jeżeli podany metaklucz już istnieje, nastąpi
uaktualnienie jego wartości w bieżącym metarekordzie. W przeciwnym razie
zostanie wstawiony nowy rekord.

$meta_value

Wymagana wartość w postaci liczby całkowitej, ciągu tekstowego, tablicy
lub obiektu. Tablice i obiekt będą automatycznie serializowane.

$prev_value

Wartość opcjonalna przedstawiająca bieżącą wartość metadanych. Jeżeli
zostanie znalezione dopasowanie, wartość poprzednia (bieżąca) zostanie
zastąpiona nową. Jeżeli nie podasz wartości tego parametru, nowa
metawartość zastąpi pierwsze wystąpienie dopasowanego klucza. W
przypadku gdy masz np. pięć wierszy metadanych o takim samym kluczu i
nie wskażesz rekordu przeznaczonego do uaktualnienia, zostanie
uaktualniony pierwszy z nich, cztery pozostałe zaś zostaną usunięte.

  ---- ------------------------------------------------------------------------------------------------------------------------
  []   Działanie tej funkcji opiera się na funkcji update_metadata() zdefiniowanej w pliku /wp-includes/meta.php. Sprawdź to!
  ---- ------------------------------------------------------------------------------------------------------------------------

add_post_meta( $post_id, $meta_key, $meta_value, $unique = false )

Ta funkcja powoduje wstawienie do tabeli wp_postmeta zupełnie nowych
metadanych dla posta. Nie będzie używana zbyt często, ponieważ omówiona
we wcześniejszej części rozdziału funkcja update_post_meta() również
pozwala wstawiać nowe rekordy i uaktualniać istniejące. Jeżeli chcesz
mieć pewność, że dany metaklucz zostanie zastosowany tylko raz dla
danego posta, skorzystaj z tej funkcji i przypisz wartość true jej
parametrowi $unique.

$user_id

Wymagana liczba całkowita określająca identyfikator posta.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
umieszczona w tabeli.

$meta_value

Wymagana wartość w postaci liczby całkowitej, ciągu tekstowego, tablicy
lub obiektu.

$unique

Opcjonalna wartość boolowska — jeśli będzie nią true, wymieniony
metaklucz będzie mógł być dodany tylko raz dla danego identyfikatora.

delete_post_meta( $post_id, $meta_key, $meta_value = '' )

Działanie tej funkcji polega na usunięciu metadanych dla podanego
identyfikatora posta i dopasowanego klucza. Istnieje możliwość
dopasowania metawartości, jeśli chcesz usunąć tylko tę wartość, a nie
inne rekordy metadanych o takim samym metakluczu.

$user_id

Wymagana liczba całkowita określająca identyfikator posta.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
usunięta z tabeli.

$meta_value

Wartość opcjonalna przedstawiająca metawartość. Jeżeli istnieje więcej
niż jeden rekord z tym samym metakluczem, można wskazać rekord
przeznaczony do usunięcia przez dopasowanie metawartości. Domyślnie ten
parametr nie jest ustawiony, co powoduje usunięcie wszystkich
metarekordów dopasowanych przez post_id i meta_key.

Na listingu 2.5 możesz zobaczyć w działaniu podstawowe funkcje
przeznaczone do dodawania, uaktualniania i usuwania różnych metadanych
posta.

Listing 2.5. Praca z metadanymi posta

    <?php

    // Pobranie postów i zwrot najnowszego

    $posts = get_posts( array( 'numberposts' => '1', 'orderby' =>

        'post_date', 'order' => 'DESC' ) );

    foreach ( $posts as $post ) {

      $post_id = $post->ID;

      // Uaktualnienie publicznych metadanych posta

      $content = 'Ta kolumna POWINNA być widoczna podczas edycji najnowszego posta.';

      update_post_meta( $post_id, 'bwawwp_displayed_field', $content );

      // Uaktualnienie ukrytych metadanych posta

      $content = str_replace( 'POWINNA', 'NIE POWINNA', $content );

      update_post_meta( $post_id, '_bwawwp_hidden_field', $content );

      // Tablica loginów uczniów

      $students[] = 'dalya';

      $students[] = 'ashleigh';

      $students[] = 'lola';

      $students[] = 'isaac';

      $students[] = 'marin';

      $students[] = 'brian';

      $students[] = 'nina';

      $students[] = 'cam';

      // Dodanie metadanych posta — jeden klucz wraz z wartością w postaci tablicy

      // Tablica zostanie automatycznie oczyszczona

      add_post_meta( $post_id, 'bwawwp_students', $students, true );

      // Iteracja przez tablicę uczniów i dodanie rekordu metadanych posta dla każdego elementu tablicy

      foreach ( $students as $student ) {

        add_post_meta( $post_id, 'bwawwp_student', $student );

      }

      // Pobranie metadanych posta — wszystkie klucze

      $all_meta = get_post_meta( $post_id );

      echo '<pre>';

      print_r( $all_meta );

      echo '</pre>';

      // Pobranie metadanych posta — pierwszy egzemplarz klucza

      $student = get_post_meta( $post_id, 'bwawwp_student', true );

      echo 'Najstarszy użytkownik: ' . $student;

      // Usunięcie metadanych posta

      delete_post_meta( $post_id, 'bwawwp_student' );

    }

    /*

    Dane wyjściowe tego przykładu powinny być podobne do następujących:

    Array

    (

        [_bwawwp_hidden_field] => Array

            (

            [0] => Ta kolumna NIE POWINNA być widoczna podczas edycji najnowszego posta.

            )

        [bwawwp_displayed_field] => Array

            (

                [0] => Ta kolumna POWINNA być widoczna podczas edycji najnowszego posta.

            )

        [bwawwp_students] => Array

            (

            [0] => a:7:{i:0;s:5:"dalya";i:1;s:8:"ashleigh";i:2;s:4:"lola";i:3;s:5:

            "isaac";i:4;s:5:"marin";i:5;s:5:"brian";i:6;s:4:"nina";i:6;s:5:"cam";}

            )

        [bwawwp_student] => Array

            (

                [0] => dalya

                [1] => ashleigh

                [2] => lola

                [3] => isaac

                [4] => marin

                [5] => brian

                [6] => nina

      [7] => cam

            )

    )

    Najstarszy użytkownik: dalya

    */

    ?>

wp_comments

Komentarze można pominąć w dowolnym poście. Tabela wp_comments
przechowuje poszczególne komentarze i powiązane z nimi dane dla
dowolnego posta. W tabeli 2.6 przedstawiliśmy strukturę bazy danych dla
tabeli wp_comments.

Tabela 2.6. Schemat bazy danych dla tabeli wp_comments

  ---------------------- -------------- ------------------ --------------- --------------------- ----------------------
  Kolumna                Typ            Kodowanie znaków   Wartość null?   Wartość domyślna      Informacje dodatkowe
  comment_ID             bigint(20)                        Nie             Brak                  AUTO_INCREMENT
  comment_post_ID        bigint(20)                        Nie             0                     
  comment_author         tinytext       utf8_general_ci    Nie                                   
  comment_author_email   varchar(100)   utf8_general_c     Nie                                   
  comment_author_url     varchar(200)   utf8_general_ci    Nie                                   
  comment_author_IP      varchar(100)   utf8_general_ci    Nie                                   
  comment_date           datetime                          Nie                                   0000-00-00 00:00:00
  comment_date_gmt       datetime                          Nie             0000-00-00 00:00:00   
  comment_content        text           utf8_general_ci    Nie             Brak                  
  comment_karma          int(11)                           Nie             0                     
  comment_approved       varchar(20)    utf8_general_ci    Nie             1                     
  comment_agent          varchar(20)    utf8_general_ci    Nie                                   
  comment_type           varchar(20)    utf8_general_ci    Nie                                   
  comment_parent         bigint(20)                        Nie             0                     
  user_id                bigint(20)                        Nie             0                     
  ---------------------- -------------- ------------------ --------------- --------------------- ----------------------

Funkcje zdefiniowane w /wp-includes/comment.php

Wymienione w tej sekcji funkcje zostały zdefiniowane w pliku
/wp-includes/comment.php.

get_comment( $comment, $output = OBJECT )

Ta funkcja zwraca dane komentarza dla podanego identyfikatora lub
obiektu komentarza. Jeżeli komentarz jest pusty, zostanie użyta globalna
zmienna komentarza, o ile została zdefiniowana.

$comment

Opcjonalna liczba całkowita, ciąg tekstowy lub obiekt identyfikatora
bądź obiekt komentarza.

$output

Opcjonalny ciąg tekstowy definiujący format danych wyjściowych.
Dozwolonymi wartościami są OBJECT, ARRAY_A i ARRAY_N.

get_comments( $args = '' )

Ta funkcja pobiera listę komentarzy dla określonych postów lub
pojedynczego posta. Wywołuje klasę WP_Comment_Querry, która zostanie
omówiona w następnym rozdziale. Parametr $args to opcjonalna tablica lub
ciąg tekstowy argumentów używanych podczas pobierania komentarzy. Oto
wartości domyślne tych argumentów:

author_email

Ciąg tekstowy w postaci adresu e-mail autora komentarza.

ID

Liczba całkowita określająca identyfikator komentarza.

karma

Liczba całkowita, która przez wtyczki może być użyta do oceny
komentarza.

numer

Liczba całkowita określająca liczbę komentarzy do zwrócenia. Domyślnie
zwracane są wszystkie komentarze.

offset

Liczba całkowita określająca liczbę komentarzy do pominięcia. Domyślnie
nie jest pomijany żaden komentarz.

orderby

Ciąg tekstowy przedstawiający kolumnę, według której mają być sortowane
komentarze. Dozwolone wartości to: comment_agent, comment_approved,
comment_author, comment_author_email, comment_author_IP,
comment_author_url, comment_content, comment_date, comment_date_gmt,
comment_ID, comment_karma, comment_parent, comment_post_ID, comment_type
i user_id.

order

Ciąg tekstowy określający kolejność wybranego argumentu orderby.
Domyślnie jest to DESC, akceptowana jest również wartość ASC.

parent

Liczba całkowita określająca identyfikator elementu nadrzędnego
komentarza.

post_id

Liczba całkowita określająca identyfikator posta, do którego został
dołączony dany komentarz.

post_author

Liczba całkowita określająca identyfikator autora posta, do którego
został dołączony dany komentarz.

post_name

Ciąg tekstowy nazwy posta, do którego został dołączony dany komentarz.

post_parent

Liczba całkowita identyfikatora elementu nadrzędnego, do którego został
dołączony dany komentarz.

post_status

Ciąg tekstowy stanu posta, do którego został dołączony dany komentarz.

post_type

Ciąg tekstowy typu posta, do którego został dołączony dany komentarz.

status

Ciąg tekstowy określający stan komentarza. Wartościami opcjonalnymi są
hold, approve, spam i trash.

type

Ciąg tekstowy typu komentarza. Wartościami opcjonalnymi są '', pingback
i trackback.

user_id

Liczba całkowita określająca identyfikator użytkownika, który dodał dany
komentarz.

search

Ciąg tekstowy wyrażenia szukanego w komentarzu. Przeszukiwane są
następujące kolumny: comment_author, comment_author_email,
comment_author_url, comment_author_IP i comment_content.

count

Wartość boolowska określająca, co zostanie zwrócone: liczba komentarzy
czy wyniki. Wartością domyślną jest false.

meta_key

Metaklucz szukanych metadanych komentarza.

meta_value

Wartość szukanych metadanych komentarza. Konieczne jest podanie wartości
argumentu meta_key.

wp_insert_comment( $commentdata )

Ta funkcja powoduje wstawienie komentarza do bazy danych.

$commentdata

Wymagana tablica kolumn i wartości do wstawienia. Dozwolone jest
wstawianie wartości do następujących kolumn: comment_post_ID,
comment_author, comment_author_email, comment_author_url,
comment_author_IP, comment_date, comment_date_gmt, comment_content,
comment_karma, comment_approved, comment_agent, comment_type,
comment_parent i user_id.

wp_update_comment( $commentarr )

Ta funkcja powoduje uaktualnienie danych komentarza i filtruje je, aby
sprawdzić, czy wszystkie wymagane kolumny są prawidłowe, zanim nastąpi
uaktualnienie bazy danych.

$commentarr

Opcjonalna tablica argumentów zawierająca przeznaczone do uaktualnienia
kolumny komentarza i wartości. Są to te same argumenty kolumn, które
wymieniliśmy w omówieniu funkcji wp_insert_comment().

wp_delete_comment( $comment_id, $force_delete = false )

Ta funkcja powoduje usunięcie komentarza. Domyślnie komentarz zostanie
umieszczony w koszu, o ile nie nakażesz jego trwałego usunięcia.

$comment_id

Wymagana liczba całkowita identyfikatora komentarza przeznaczonego do
umieszczenia w koszu lub usunięcia.

$force_delete

Opcjonalna wartość boolowska — jeśli będzie nią true, komentarz zostanie
trwale usunięty.

Na listingu 2.6 możesz zobaczyć w działaniu podstawowe funkcje
przeznaczone do pracy z tabelą wp_comments. Ten listing pokazuje również
sposób zarządzania danymi komentarza dołączonego do posta.

Listing 2.6. Praca z tabelą wp_comments

    <?php

    // Wstawienie posta

    $args = array(

     'post_title'   => 'Dokąd powinienem się udać dziś wieczorem?',

     'post_content' => 'Pomyśl o czymś przyjemnym i napisz o tym w komentarzu!',

     'post_status'  => 'publish'

    );

    $post_id = wp_insert_post( $args );

    echo 'Identyfikator posta: ' . $post_id . ' - ' . $args['post_title'] . '<br>';

    // Utworzenie tablicy komentarzy

    $comments[] = 'NA LODY!!!!';

    $comments[] = 'Taco Bell';

    $comments[] = 'Połóż się spać i śpij dobrze';

    // Iteracja przez tablicę komentarzy

    foreach ( $comments as $key => $comment ) {

      // Wstawienie komentarzy

      $commentdata = array(

        'comment_post_ID' => $post_id,

        'comment_content' => $comments[$key],

      );

      $comment_ids[] = wp_insert_comment( $commentdata );

    }

    echo 'Komentarze:<pre>';

    print_r( $comments );

    echo '</pre>';

    // Uaktualnienie komentarza

    $commentarr['comment_ID'] = $comment_ids[0];

    $commentarr['comment_content'] = 'Przeczytaj tę książkę w całości';

    wp_update_comment( $commentarr );

    // Wstawienie komentarza — podkomentarz z elementu nadrzędnego o podanym identyfikatorze

    $commentdata = array(

      'comment_post_ID' => $post_id,

      'comment_parent' => $comment_ids[0],

      'comment_content' => 'To jest całkiem dobry pomysł...',

    );

    wp_insert_comment( $commentdata );

    // Pobranie komentarzy — wyszukiwanie komentarza zawierającego wyrażenie taco bell

    $comments = get_comments( 'search=Taco Bell&number=1' );

    foreach ( $comments as $comment ) {

      // Wstawienie komentarza — podkomentarz dla komentarza zawierającego wyrażenie taco bell

      $commentdata = array(

        'comment_post_ID' => $post_id,

        'comment_parent' => $comment->comment_ID,

        'comment_content' => '',

      );

      wp_insert_comment( $commentdata );

    }

    // Pobranie komentarza — zliczenie komentarzy dla danego posta

    $comment_count = get_comments( 'post_id= ' . $post_id . '&count=true' );

    echo 'Liczba komentarzy: ' . $comment_count . '<br>';

    // Pobranie komentarzy — wszystkie dla danego posta

    $comments = get_comments( 'post_id=' .$post_id );

    foreach ( $comments as $comment ) {

      // Uaktualnienie pierwszego komentarza

      if ( $comment_ids[0] == $comment->comment_ID ) {

       $commentarr = array(

        'comment_ID' => $comment->comment_ID,

        'comment_content' => $comment->comment_content . ' i zacznij tworzyć aplikacje!',

      );

        wp_update_comment( $commentarr );

        // Usunięcie wszystkich pozostałych komentarzy

      }else {

        // Usunięcie komentarza

        wp_delete_comment( $comment->comment_ID, true );

      }

    }

    // Pobranie komentarza — liczba nowych komentarzy

    $comment_count = get_comments( 'post_id= ' . $post_id . '&count=true' );

    echo 'Liczba nowych komentarzy: ' . $comment_count . '<br>';

    // Pobranie komentarza — pobranie najlepszego

    $comment = get_comment( $comment_ids[0] );

    echo 'Najlepszy komentarz: ' . $comment->comment_content;

    /*

    Dane wyjściowe tego przykładu powinny być podobne do następujących:

    Identyfikator posta: 91011 - Dokąd powinienem się udać dziś wieczorem?

    Komentarze:

    Array

    (

        [0] => NA LODY!!!!

        [1] => Taco Bell

        [2] => Połóż się spać i śpij dobrze

    )

    Liczba komentarzy: 5

    Liczba nowych komentarzy: 1

    Najlepszy komentarz: Przeczytaj tę książkę w całości i zacznij tworzyć aplikacje!

    */

    ?>

wp_commentsmeta

Podobnie jak wp_usermeta i wp_postmeta, także ta tabela przechowuje
niestandardowe dane dodatkowe powiązane z komentarzem za pomocą kolumny
comment_id. W tabeli 2.7 przedstawiliśmy strukturę bazy danych dla
tabeli wp_commentsmeta.

Tabela 2.7. Schemat bazy danych dla tabeli wp_commentsmeta

  ------------ -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna      Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  meta_id      bigint(20)                        Nie             Brak               AUTO_INCREMENT
  comment_id   bigint(20)                        Nie             0                  
  meta_key     varchar(255)   utf8_general_ci    Tak             NULL               
  meta_value   longtext       utf8_general_c     Tak             NULL               
  ------------ -------------- ------------------ --------------- ------------------ ----------------------

Funkcje zdefiniowane w /wp-includes/comment.php

Wymienione w tej sekcji funkcje zostały zdefiniowane w pliku
/wp-includes/comment.php.

get_comment_meta( $comment_id, $key = '', $single = false )

Działanie tej funkcji polega na pobraniu metadanych dla komentarza o
podanym identyfikatorze.

$comment_id

Wymagana liczba całkowita określająca identyfikatora komentarza, dla
którego mają zostać pobrane metadane.

$key

Opcjonalny ciąg tekstowy nazwy metaklucza, dla którego mają zostać
pobrane metadane komentarza. Domyślnie zwracane są metadane dla
wszystkich metakluczy danego posta.

$single

Wartość boolowska określająca, czy ma zostać zwrócona pojedyncza
wartość. Wartością domyślną jest false, co oznacza zwrot wartości w
postaci tablicy.

add_comment_meta( $comment_id, $meta_key, $meta_value, $unique = false )

Ta funkcja pozwala dodać metadane do komentarza o podanym
identyfikatorze.

$comment_id

Wymagana liczba całkowita określająca identyfikator komentarza.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
umieszczona w tabeli.

$meta_value

Wymagana wartość w postaci liczby całkowitej, ciągu tekstowego, tablicy
lub obiektu.

$unique

Opcjonalna wartość boolowska — jeśli będzie nią true, wymieniony
metaklucz będzie mógł być dodany tylko raz dla danego identyfikatora.

update_comment_meta( $comment_id, $meta_key, $meta_value, $prev_value = '' )

Ta funkcja uaktualnia metadane dla komentarza o podanym identyfikatorze.

$comment_id

Wymagana liczba całkowita określająca identyfikator komentarza.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
umieszczona w tabeli. Jeżeli podany metaklucz już istnieje, nastąpi
uaktualnienie jego wartości w bieżącym rekordzie. W przeciwnym razie
zostanie wstawiony nowy rekord.

$meta_value

Wymagana wartość w postaci liczby całkowitej, ciągu tekstowego, tablicy
lub obiektu. Tablice i obiekt będą automatycznie serializowane.

$prev_value

Wartość opcjonalna przedstawiająca bieżącą wartość metadanych. Jeżeli
zostanie znalezione dopasowanie, wartość poprzednia (bieżąca) zostanie
zastąpiona nową. Jeżeli nie podasz wartości tego parametru, nowa
metawartość zastąpi pierwsze wystąpienie dopasowanego klucza. W
przypadku gdy masz np. pięć wierszy metadanych o takim samym kluczu i
nie wskażesz rekordu przeznaczonego do uaktualnienia, zostanie
uaktualniony pierwszy z nich, cztery pozostałe zaś zostaną usunięte.

delete_comment_meta( $comment_id, $meta_key, $meta_value = '' )

Działanie tej funkcji polega na usunięciu metadanych dla podanego
identyfikatora komentarza i dopasowanego klucza. Istnieje możliwość
dopasowania metawartości, jeśli chcesz usunąć tylko tę wartość, a nie
inne rekordy metadanych o takim samym metakluczu.

$user_id

Wymagana liczba całkowita określająca identyfikator komentarza.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
usunięta z tabeli.

$meta_value

Wartość opcjonalna przedstawiająca metawartość. Jeżeli istnieje więcej
niż jeden rekord z tym samym metakluczem, można wskazać rekord
przeznaczony do usunięcia przez dopasowanie metawartości. Domyślnie ten
parametr nie jest ustawiony, co powoduje usunięcie wszystkich
metarekordów dopasowanych przez post_id i meta_key.

Na listingu 2.7 możesz zobaczyć w działaniu podstawowe funkcje
przeznaczone do pracy z tabelą wp_commentsmeta.

Listing 2.7. Praca z tabelą wp_commentsmeta

    <?php

    // Pobranie komentarzy — identyfikator ostatniego komentarza

    $comments = get_comments( 'number=1' );

    foreach ( $comments as $comment ) {

      $comment_id = $comment->comment_ID;

      // Dodanie metadanych komentarza — tutaj są to metadane do wyświetlania daty i adresu IP

      $viewed = array( date( "d.m.y" ), $_SERVER["REMOTE_ADDR"] );

      $comment_meta_id = add_comment_meta( $comment_id, 'bwawwp_view_date',

            $viewed, true );

      echo 'Identyfikator metadanych komentarza: ' . $comment_meta_id;

      // Uaktualnienie metadanych komentarza — zmiana formatu danych

      // na 23 paździelnika 2020, 12:00 zamiast 23.10.20

      $viewed = array( date( "j F Y, g:i" ), $_SERVER["REMOTE_ADDR"] );

      update_comment_meta( $comment_id, 'bwawwp_view_date', $viewed );

      // Pobranie metadanych komentarza — wszystkie klucze

      $comment_meta = get_comment_meta( $comment_id );

      echo '<pre>';

      print_r( $comment_meta );

      echo '</pre>';

      // Usunięcie metadanych komentarza

      delete_comment_meta( $comment_id, 'bwawwp_view_date' );

    }

    /*

    Dane wyjściowe tego przykładu powinny być podobne do następujących:

    Identyfikator metadanych komentarza: 16

    Array

    (

        [bwawwp_view_date] => Array

            (

                [0] => a:2:{i:0;s:24:"11 sierpnia 2018, 4:16";i:1;s:9:"127.0.0.1";}

            )

    )

    */

    ?>

wp_terms

Tabela wp_terms przechowuje nazwę każdej tworzonej kategorii lub
terminu. Każdy rekord jest za pomocą kolumny term_id powiązany z jego
taksonomią w tabeli wp_term_taxonomy. Tagi i kategorie postów powinny
być Ci znane, prawda? Poszczególne kategorie i tagi są przechowywane
w tej tabeli i z technicznego punktu widzenia są uznawane za taksonomie.
Każde wyrażenie umieszczone w kolumnie name jest terminem taksonomii.
Znacznie dokładniejsze omówienie taksonomii znajdziesz w rozdziale 5.,
więc jeśli nie do końca się jeszcze orientujesz w tym temacie, wkrótce
się to zmieni. W tabeli 2.8 przedstawiliśmy strukturę bazy danych dla
tabeli wp_terms.

Tabela 2.8. Schemat bazy danych dla tabeli wp_terms

  ------------ -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna      Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  term_id      bigint(20)                        Nie             Brak               AUTO_INCREMENT
  name         varchar(200)                      Nie                                
  sług         varchar(200)   utf8_general_ci    Nie                                
  term_group   bigint(10)                        Nie             0                  
  ------------ -------------- ------------------ --------------- ------------------ ----------------------

Funkcje zdefiniowane w /wp-includes/taxonomy.php

Wymienione w tej sekcji funkcje zostały zdefiniowane w pliku
/wp-includes/taxonomy.php.

get_terms( $taxonomies, $args = '' )

Ta funkcja pobiera terminy określonej taksonomii lub tablicę taksonomii.

$taxonomies

Wymagany ciąg tekstowy lub tablica taksonomii bądź też lista taksonomii.

$args

Opcjonalny ciąg tekstowy lub tablica argumentów. Oto lista dostępnych
argumentów:

orderby

Domyślnie stosowana jest kolejność według kolumny name. Do wyboru są
kolumny name, count, term_group, slug lub żadna z wymienionych, ale
zostanie będzie użyta term_id. Przekazanie niestandardowej wartości
innej niż którakolwiek z tutaj wymienionych spowoduje ułożenie elementów
według kolejności określanej przez tę wartość niestandardową.

order

Kolejność rosnąca (ASC) lub malejąca (DESC). Wartością domyślną jest
ASC.

hide_empty

Wartością domyślną jest true i powoduje ona zwrot jedynie terminów
dołączonych do posta. W przypadku wartości false można zwrócić wszystkie
terminy niezależnie od tego, czy są one wykorzystane w poście.

exclude

Tablica rozdzielonych przecinkami lub spacjami identyfikatorów terminów,
które mają być wykluczone z wyników zapytania. Jeżeli został użyty
argument include, to argument exclude zostanie zignorowany.

exclude_tree

Tablica rozdzielonych przecinkami lub spacjami identyfikatorów terminów
(łącznie z elementami potomnymi), które mają być wykluczone z wyników
zapytania. Jeżeli został użyty argument include, to argument
exclude_tree zostanie zignorowany.

include

Tablica rozdzielonych przecinkami lub spacjami identyfikatorów terminów,
które mają być uwzględnione w wynikach zapytania.

numer

Liczba terminów, które mają być zwrócone przez zapytanie. Wartością
domyślną jest all.

offset

Liczba, o którą mają zostać przesunięte terminy zapytania.

fields

Istnieje możliwość określenia, czy zwrócone mają być identyfikatory
terminów czy ich nazwy. Wartością domyślną jest all, co oznacza zwrot
tablicy obiektów terminów.

slug

Ciąg tekstowy zwracający wszystkie terminy, których slug został
dopasowany.

hierarchical

Dołączenie wszystkich elementów potomnych, jeśli zostały dołączone do
postów. Wartością domyślną jest true, więc jeśli nie chcesz zwracać
terminów w postaci hierarchicznej, temu argumentowi należy przypisać
wartość false.

search

Ciąg tekstowy zwracający wszystkie terminy o nazwach dopasowanych do
podanej wartości. Podczas wyszukiwania wielkość liter ma znaczenie.

name_like

Ciąg tekstowy zwracający wszystkie terminy o nazwach rozpoczynających
się od podanej wartości. Podobnie jak w przypadku argumentu search,
także tutaj wielkość liter ma znaczenie.

pad_counts

Jeżeli wartością tego argumentu będzie true, wyniki zapytania będą
zawierały liczbę elementów potomnych poszczególnych terminów.

get

Jeżeli wartością tego argumentu będzie all, terminy będą zwracane
niezależnie od tego, czy te terminy lub ich elementy potomne są puste.

child_of

Przypisanie wartości w postaci identyfikatora terminu powoduje, że wynik
zapytania będzie zawierał elementy potomne terminu o podanym
identyfikatorze. Wartością domyślną jest 0 i oznacza ona zwrot
wszystkiego.

parent

Przypisanie wartości w postaci identyfikatora terminu powoduje, że wynik
zapytania będzie zawierał bezpośrednie elementy potomne terminu o
podanym identyfikatorze. Wartością domyślną jest pusty ciąg tekstowy.

cache_domain

Włącza wygenerowanie unikatowego klucza buforowania, gdy dane zapytanie
zostaje umieszczone w obiekcie bufora.

get_term( $term, $taxonomy, $output = OBJECT, $filter = 'raw' )

Ta funkcja pobiera wszystkie dane terminu dla dowolnego podanego
terminu.

$term

Wymagana liczba całkowita lub obiekt terminu, który ma zostać zwrócony.

$taxonomy

Wymagany ciąg tekstowy terminu taksonomii, który ma zostać zwrócony.

$output

Opcjonalny ciąg tekstowy określający format danych wyjściowych.
Wartością domyślną jest OBJECT, natomiast pozostałymi wartościami mogą
być ARRAY_A (tablica asocjacyjna) lub ARRAY_N (tablica liczbowa).

$filter

Opcjonalny ciąg tekstowy określający sposób oczyszczenia kontekstu w
danych wyjściowych. Wartością domyślną jest raw.

wp_insert_term( $term, $taxonomy, $args = array() )

Ta funkcja pozwala dodać nowy termin do bazy danych.

$term

Wymagany ciąg tekstowy terminu, który ma zostać dodany lub uaktualniony.

$taxonomy

Wymagany ciąg tekstowy taksonomii, dla której ma zostać dodany termin.

$args

Opcjonalna tablica lub ciąg tekstowy argumentów terminu przeznaczonego
do wstawienia lub uaktualnienia. Oto lista dostępnych argumentów:

alias_of

Opcjonalny ciąg tekstowy slugu, którego aliasem ma być termin.

description

Opcjonalny ciąg tekstowy opisujący termin.

parent

Opcjonalna liczba całkowita identyfikatora terminu nadrzędnego, którego
elementem potomnym będzie dany termin.

slug

Opcjonalny ciąg tekstowy slugu terminu.

wp_update_term( $term_id, $taxonomy, $args = array() )

Ta funkcja pozwala uaktualnić istniejący termin w bazie danych.

$term_id

Wymagany ciąg tekstowy terminu, który ma zostać uaktualniony.

$taxonomy

Wymagany ciąg tekstowy taksonomii, z którą jest powiązany dany termin.

$args

Opcjonalna tablica lub ciąg tekstowy argumentów terminu przeznaczonego
do uaktualnienia. Lista dostępnych argumentów jest taka sama jak w
przypadku funkcji wp_insert_term().

wp_delete_term( $term, $taxonomy, $args = array() )

Ta funkcja usuwa termin z bazy danych. Jeżeli termin jest elementem
nadrzędnym dla innych terminów, wówczas elementy potomne zostaną
uaktualnione do postaci elementów nadrzędnych.

$term

Wymagany ciąg tekstowy terminu, który ma zostać usunięty.

$taxonomy

Wymagany ciąg tekstowy taksonomii, z którą jest powiązany dany termin.

$args

Opcjonalna tablica zawierająca wartości do nadpisania kolumn terminu.

wp_termmeta

Począwszy od wydania WordPress 4.4, dla terminów mogą być przechowywane
metadane. Opracowana przez YIKES Inc. wtyczka Simple Taxonomy Ordering
(https://wordpress.org/plugins/simple-taxonomy-ordering/) używa
metadanych terminu w celu umożliwienia zmiany kolejności, w jakiej
kategorie i pozostałe taksonomie będą wyświetlane na listach i w
widżetach. W tabeli 2.9 przedstawiliśmy strukturę bazy danych dla tabeli
wp_terms.

Tabela 2.9. Schemat bazy danych dla tabeli wp_termmeta

  ------------ -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna      Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  meta_id      bigint(20)                        Nie             Brak               AUTO_INCREMENT
  term_id      bigint(20)                        Nie             0                  
  meta_key     varchar(255)   utf8_general_ci    Tak             NULL               
  meta_value   longtext       utf8_general_ci    Tak             NULL               
  ------------ -------------- ------------------ --------------- ------------------ ----------------------

Przedstawione tutaj funkcje działają podobnie jak omówione we
wcześniejszej części rozdziału funkcje dotyczące metadanych
użytkowników, postów i komentarzy.

get_term_meta( $term_id, $key = '', $single = false )

Działanie tej funkcji polega na pobraniu wartości metadanych terminu dla
określonego klucza.

$term_id

Wymagana liczba całkowita identyfikatora terminu.

$key

Opcjonalny ciąg tekstowy klucza metadanych, którego wartość ma zostać
zwrócona. Jeżeli ten ciąg tekstowy nie zostanie podany, to zostaną
zwrócone wszystkie metadane dla danego terminu.

$single

Wartość boolowska określająca, czy ma zostać zwrócona pojedyncza
wartość. Wartością domyślną jest false, co oznacza zwrot wartości w
postaci tablicy.

Dla tego samego identyfikatora terminu może istnieć więcej niż jeden
klucz metadanych z odmiennymi wartościami. Jeżeli wartością parametru
$single będzie false, otrzymasz tablicę wartości dla każdego rekordu
wraz z tym samym kluczem.

update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' )

Ta funkcja uaktualnia metadane terminu. Jeżeli przekazany klucz nie
istnieje, funkcja wstawi dla niego metadane.

$term_id

Wymagana liczba całkowita określająca identyfikator terminu.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
umieszczona w tabeli. Jeżeli podany metaklucz już istnieje, nastąpi
uaktualnienie jego wartości w bieżącym rekordzie. W przeciwnym razie
zostanie wstawiony nowy rekord.

$meta_value

Wymagana wartość w postaci liczby całkowitej, ciągu tekstowego, tablicy
lub obiektu. Tablice i obiekt będą automatycznie serializowane.

$prev_value

Wartość opcjonalna przedstawiająca bieżącą wartość metadanych. Jeżeli
zostanie znalezione dopasowanie, wartość poprzednia (bieżąca) zostanie
zastąpiona nową. Jeżeli nie podasz wartości tego parametru, nowa
metawartość zastąpi pierwsze wystąpienie dopasowanego klucza. W
przypadku gdy masz np. pięć wierszy metadanych o takim samym kluczu i
nie wskażesz rekordu przeznaczonego do uaktualnienia, zostanie
uaktualniony pierwszy z nich, cztery pozostałe zaś zostaną usunięte.

  ---- ------------------------------------------------------------------------------------------------------------------------
  []   Działanie tej funkcji opiera się na funkcji update_metadata() zdefiniowanej w pliku /wp-includes/meta.php. Sprawdź to!
  ---- ------------------------------------------------------------------------------------------------------------------------

add_term_meta( $term_id, $meta_key, $meta_value, $unique = false )

Ta funkcja powoduje wstawienie do tabeli wp_termmeta zupełnie nowych
metadanych dla terminu. Także w przypadku tej funkcji preferowane jest
stosowanie omówionej we wcześniejszej części rozdziału funkcji
update_term_meta(), ponieważ pozwala ona wstawiać nowe rekordy i
uaktualniać istniejące. Jeżeli chcesz mieć pewność, że dany metaklucz
zostanie zastosowany tylko raz dla danego terminu, skorzystaj z
omawianej funkcji i przypisz wartość true jej parametrowi $unique.

$term_id

Wymagana liczba całkowita określająca identyfikator terminu.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
umieszczona w tabeli.

$meta_value

Wymagana wartość w postaci liczby całkowitej, ciągu tekstowego, tablicy
lub obiektu.

$unique

Opcjonalna wartość boolowska — jeśli będzie nią true, wymieniony
metaklucz będzie mógł zostać dodany tylko raz dla danego identyfikatora.

delete_term_meta( $term_id, $meta_key, $meta_value = '' )

Działanie tej funkcji polega na usunięciu metadanych dla podanego
identyfikatora terminu i dopasowanego klucza. Istnieje możliwość
dopasowania metawartości, jeśli chcesz usunąć tylko tę wartość, a nie
inne rekordy metadanych o takim samym metakluczu.

$user_id

Wymagana liczba całkowita określająca identyfikator terminu.

$meta_key

Wymagany ciąg tekstowy nazwy metaklucza dla wartości, która ma zostać
usunięta z tabeli.

$meta_value

Wartość opcjonalna przedstawiająca metawartość. Jeżeli istnieje więcej
niż jeden rekord z tym samym metakluczem, można wskazać rekord
przeznaczony do usunięcia przez dopasowanie metawartości. Domyślnie ten
parametr nie jest ustawiony, co powoduje usunięcie wszystkich
metarekordów dopasowanych przez post_id i meta_key.

wp_term_taxonomy

Tabela wp_term_taxonomy przechowuje wszystkie używane typy taksonomii.
WordPress ma dwie wbudowane taksonomie, category i post_tag, ale można
zarejestrować także własne. Po dodaniu nowego terminu do tabeli wp_terms
zostanie ona powiązana z jego taksonomią w tej tabeli, podczas tego
procesu zostaną użyte kolumny term_id, description, parent i count. W
tabeli 2.10 przedstawiliśmy strukturę bazy danych dla tabeli
wp_term_taxonomy.

Tabela 2.10. Schemat bazy danych dla tabeli wp_term_taxonomy

  ------------------ ------------- ------------------ --------------- ------------------ ----------------------
  Kolumna            Typ           Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  term_taxonomy_id   bigint(20)                       Nie             Brak               AUTO_INCREMENT
  term_id            bigint(20)                       Nie             0                  
  taxonomy           varchar(32)   utf8_general_ci    Nie                                
  description        longtext      utf8_general_ci    Nie             Brak               
  parent             bigint(20)                       Nie             0                  
  count              bigint(20)                       Nie             0                  
  ------------------ ------------- ------------------ --------------- ------------------ ----------------------

Funkcje zdefiniowane w /wp-includes/taxonomy.php

Wymienione w tej sekcji funkcje zostały zdefiniowane w pliku
/wp-includes/taxonomy.php.

get_taxonomies( $args = array(), $output = 'names', $operator = 'and' )

Ta funkcja zwraca listę obiektów zarejestrowanych taksonomii lub listę
nazw taksonomii.

$args

Opcjonalna tablica argumentów do uwzględnienia podczas zwracania
obiektów taksonomii. Tych argumentów jest naprawdę sporo, a ich
omówienie znajdziesz w rozdziale 5.

$output

Opcjonalny ciąg tekstowy nazw lub obiektów taksonomii. Wartością
domyślną jest names, co oznacza zwrot listy nazw taksonomii.

$operator

Opcjonalny ciąg tekstowy o wartości and lub or. Wartością domyślną jest
and, co oznacza, że dopasowane muszą być wszystkie przekazane argumenty.
W przypadku przypisania wartości or dopasowany może być dowolny z
przekazanych argumentów.

get_taxonomy( $taxonomy )

Ta funkcja najpierw sprawdza, czy przekazanym parametrem jest obiekt
taksonomii. Jeżeli tak, ten obiekt zostanie zwrócony.

$taxonomy

Wymagany ciąg tekstowy nazwy obiektu taksonomii, który ma zostać
zwrócony.

register_taxonomy( $taxonomy, $object_type, $args = array() )

Ta funkcja tworzy lub uaktualnia obiekt taksonomii. Rejestrowanie
własnych taksonomii może rozszerzać WordPressa, ponieważ pozwala to
kategoryzować posty w dowolny i wygodny sposób. W rozdziale 5. znacznie
dokładniej omówimy temat rejestrowania niestandardowych taksonomii.

$taxonomy

Wymagany ciąg tekstowy nazwy taksonomii.

$object_type

Wymagana tablica lub ciąg tekstowy typów obiektów (typy postów, np. post
i page), z którymi są powiązane taksonomie.

$args

Opcjonalna tablica lub ciąg tekstowy argumentów. Tych argumentów jest
naprawdę sporo, a ich omówienie znajdziesz w rozdziale 5.

wp_term_relationships

Tabela wp_term_relationships umożliwia powiązanie terminu taksonomii i
posta. Za każdym razem, gdy postowi przypisujesz kategorię lub tag,
powiązanie to zostanie odnotowane w omawianej tabeli. W tabeli 2.11
przedstawiliśmy strukturę bazy danych dla tabeli wp_term_relationships.

Tabela 2.11. Schemat bazy danych dla tabeli wp_term_relationships

  ------------------ ------------ ------------------ --------------- ------------------ ----------------------
  Kolumna            Typ          Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  object_id          bigint(20)                      Nie             0                  
  term_taxonomy_id   bigint(20)                      Nie             0                  
  term_order         int(11)                         Nie             0                  
  ------------------ ------------ ------------------ --------------- ------------------ ----------------------

get_object_taxonomies( $object, $output = 'names' )

Ta funkcja zwraca wszystkie taksonomie powiązane z typem lub obiektem
posta.

$object

Wymagana tablica, ciąg tekstowy lub obiekt nazwy typów lub obiektów
postów.

$output

Opcjonalny ciąg tekstowy names lub objects. Wartością domyślną jest
names, która powoduje zwrot listy nazw taksonomii.

wp_get_object_terms( $object_ids, $taxonomies, $args = array() )

Działanie tej funkcji polega na zwróceniu terminów powiązanych z
przekazanym identyfikatorem obiektu lub identyfikatorami obiektów postów
i taksonomii.

$object_ids

Wymagany ciąg tekstowy lub tablica identyfikatorów obiektów terminów,
które mają zostać zwrócone. Przekazanie identyfikatora posta spowoduje
zwrot terminów powiązanych z postem o podanym identyfikatorze.

$taxonomies

Wymagany ciąg tekstowy lub tablica nazw taksonomii, dla których mają
zostać zwrócone terminy. Przekazanie wartości post_tag taksonomii
spowoduje zwrot terminów taksonomii powiązanej z daną wartością
post_tag.

$args

Opcjonalny ciąg tekstowy lub tablica argumentów zmieniających sposób
zwrotu danych. Oto lista dostępnych argumentów:

orderby

Domyślnie stosowana jest kolejność według kolumny name. Do wyboru są
kolumny name, count, term_group, slug, term_order i none.

order

Kolejność rosnąca (ASC) lub malejąca (DESC). Wartością domyślną jest
ASC.

fields

Wartością domyślną jest all, poza którą akceptowane są jeszcze wartości
ids, names, slugs i all_with_object_id. Ten argument określa wartości
przeznaczone do zwrócenia.

wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false )

Ta funkcja dodaje terminy taksonomii do obiektu o podanym
identyfikatorze i taksonomii. Funkcja ma możliwość nadpisania wszystkich
terminów lub dołączenia nowych do już istniejących. Jeżeli termin
przekazany funkcji jeszcze nie istnieje, to zostanie utworzony i
powiązany z obiektem o podanym identyfikatorze i taksonomii.

$object_id

Wymagana liczba całkowita identyfikatora obiektu (identyfikator posta),
z którym zostaną powiązane nowe terminy.

$terms

Wymagany ciąg tekstowy lub tablica terminów, które mają zostać dodane do
obiektu (posta).

$taxonomy

Wymagany ciąg tekstowy lub tablica taksonomii, z którymi mają zostać
powiązane nowe terminy.

$append

Opcjonalna wartość boolowska — domyślnie jest nią false, która powoduje
zastąpienie wszystkich istniejących terminów powiązanych z
identyfikatorem obiektu nowymi terminami. Natomiast wartość true
oznacza, że nowe terminy zostaną dołączone do istniejących.

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Swego czasu była prowadzona dyskusja dotycząca usunięcia w przyszłych wydaniach WordPressa tabeli wp_terms. Kolumny name i slug zostałyby przeniesione do tabeli wp_terms_taxonomy. Utworzony zostałby widok MySQL o nazwie wp_terms w celu zapewnienia zgodności z niestandardowymi zapytaniami. Jednak wprowadzenie tej zmiany zostało odłożone na później. Byłoby dobrze, gdyby udało się zaprowadzić trochę porządku w tabelach związanych z terminami i taksonomiami.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Zaczepy — akcje i filtry

Programiści WordPressa w pracy dość często korzystają z zaczepów.
Zaczepy są doskonałe i powodują, że dodawanie nowej funkcjonalności do
wtyczek i motywów WordPressa jest bardzo proste i łatwe.

Istnieją dwa typy zaczepów — akcje i filtry — uznawane za
najpotężniejsze narzędzia WordPressa. Spędzisz dużo czasu na pracy z
akcjami i filtrami. Dokładne zrozumienie materiału przedstawionego w tym
podrozdziale ma duże znaczenie dla każdego programisty WordPressa.

Akcje

Gdy zaczep akcji (z technicznego punktu widzenia jest to funkcja
do_action()) istnieje w kodzie uruchamianym w WordPressie, własny kod
można dodać za pomocą wywołania funkcji add_action() oraz przekazania
nazwy zaczepu akcji i własnej funkcji zawierającej kod przeznaczony do
wykonania.

    do_action( $tag, $arg );

Oto dostępne argumenty tego wywołania:

$tag

Nazwa wykonywanego zaczepu akcji.

$arg

Jeden lub więcej argumentów dodatkowych, które są z poziomu funkcji
add_action() przekazywane wywoływanej funkcji odwołując się do funkcji
do_action(). O co tutaj chodzi? Czytaj dalej…

Własny zaczep można utworzyć w motywie lub we wtyczce za pomocą funkcji
do_action(). Jednak w większości przypadków będziesz wykorzystywać
zaczepy istniejące w WordPressie i w innych wtyczkach. Załóżmy, że po
pierwszym uruchomieniu aplikacji WordPressa, ale jeszcze przez
wyświetleniem jakichkolwiek danych wyjściowych w przeglądarce WWW chcesz
sprawdzić, czy użytkownik jest zalogowany. W takim przypadku można
skorzystać z zaczepu init.

    <?php

    add_action( 'init', 'my_user_check' );

    function my_user_check() {

      if ( is_user_logged_in() ) {

        // Wykonanie pewnego zadania, ponieważ użytkownik jest zalogowany

      }

    }

    ?>

Co się tutaj zdarzyło? W jądrze WordPressa znajduje się zaczep akcji,
do_action(init), a w omawianym przykładzie następuje wywołanie funkcji
my_user_check() z poziomu funkcji add_action(). Gdy przedstawiony tutaj
kod zostanie uruchomiony, po dotarciu do zaczepu akcji init nastąpi
wywołanie funkcji my_user_check() i wykonanie zdefiniowanego w niej
kodu, a dopiero później przejście dalej.

  ---- -----------------------------------------------------------------------------------------------------------------------------------
  []   Lista najczęściej używanych zaczepów WordPressa znajduje się na stronie https:// codex.wordpress.org/Plugin_API/Action_Reference.
  ---- -----------------------------------------------------------------------------------------------------------------------------------

Filtry

Filtr przypomina zaczep akcji pod tym względem, że można się do niego
podpiąć, o ile istnieje w WordPressie. Zamiast jednak wstawiać własny
kod do zaczepu lub istniejącej funkcji do_action() filtrujesz wartość
zwrotną istniejących funkcji, które wykorzystują funkcję apply_filters()
zdefiniowaną w jądrze WordPressa, wtyczkach i/lub motywach. Innymi
słowy: jeśli stosujesz filtry, masz możliwość przechwycenia treści przed
jej wstawieniem do bazy danych lub przed jej wyświetleniem w
przeglądarce WWW jako treści HTML.

    apply_filters( $tag, $value, $var );

Oto dostępne argumenty tego wywołania:

$tag

Nazwa zaczepu filtra.

$value

Wartość, na której ma być zastosowany filtr.

$var

Zmienne dodatkowe, takie jak ciąg tekstowy lub tablica, przekazywane
funkcji filtru.

Jeżeli pliki tworzące WordPressa będziesz analizować pod kątem wywołania
apply_filters(), zauważysz, że ta funkcja jest wywoływana w wielu
miejscach. I podobnie jak zaczepy akcji może być dodawana, a także
wywoływana z poziomu dowolnego motywu lub wtyczki. W każdym miejscu kodu
działającej witryny internetowej WordPressa, w którym widzisz wywołanie
funkcji apply_filters(), masz możliwość filtrowania wartości zwracanej
przez tę funkcję. Przykładowo chcesz filtrować tytuły wszystkich postów
przed ich wyświetleniem w przeglądarce WWW. W takim przypadku za pomocą
funkcji add_filter() możesz podpiąć się do istniejących filtrów.

    add_filter( $tag, $function, $priority, $accepted_args );

Oto dostępne argumenty tego wywołania:

$tag

Nazwa zaczepu używanego podczas filtrowania. Powinna odpowiadać wartości
parametru $tag wywołania funkcji apply_filters(), dla którego będą
filtrowane wyniki.

$function

Nazwa funkcji niestandardowej wykorzystanej do rzeczywistego filtrowania
wyników.

$priority

Ta liczba określa priorytet, z którym będzie wykonana funkcja
add_filter(), w porównaniu do innych miejsc w kodzie odwołujących się do
zaczepu o takim samym tagu. Wartością domyślną jest 10.

$accepted_args

Istnieje możliwość określenia liczby parametrów, które mogą być
zaakceptowane przez własną funkcję przeznaczoną do obsługi filtrowania.
Wartością domyślną jest 1, czyli wartość parametru $value funkcji
apply_filters().

No dobrze, możesz w tym miejscu zapytać: jak będzie wyglądał rzeczywisty
kod obsługi filtrów? Zaczniemy od dodania filtru pozwalającego na zmianę
tytułu dowolnego posta przekazywanego przeglądarce WWW. W tym momencie
już wiesz, że zaczep filtru the_title przedstawia się następująco:

    apply_filters( 'the_title', $title, $id );

Oto dostępne argumenty tego wywołania:

$title

Jest to tytuł posta, natomiast $id to identyfikator posta.

    <?php

    add_filter( 'the_title', 'my_filtered_title', 10, 2 );

    function my_filtered_title( $value, $id ) {

      $value = '[' . $value . ']';

      return $value;

    }

    ?>

Przedstawiony tutaj fragment kodu powinien umieścić każdy tytuł posta w
nawiasie. Jeżeli tytuł posta to Witaj, świecie!, zostanie on zmieniony
na [Witaj, świecie!]. Zwróć uwagę na to, że w funkcji niestandardowej
nie został użyty parametr $id. Jeżeli chcesz, w nawias mogą być ujęte
tylko tytuły postów o określonych identyfikatorach.

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Wprawdzie funkcja add_action() jest przeznaczona do stosowania wraz z zaczepami do_action(), a add_filter() służy do pracy z zaczepami apply_filters(), ale te funkcje działają dokładnie tak samo i są wymienne. Dla zachowania czytelności dobrym rozwiązaniem jest stosowanie właściwej funkcji w zależności od jej przeznaczenia — zwrot filtrowanego wyniku lub jedynie wykonywanie pewnego kodu w określonym momencie.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Środowiska programistyczne i hostingowe

Do działania WordPress potrzebuje serwera WWW. W tym podrozdziale
przedstawimy podstawy dotyczące konfiguracji środowiska lokalnego i
zdalnego dla budowanej aplikacji WordPressa.

Praca lokalna

Zanim przejdziemy do podstaw pracy z WordPressem, zachęcamy do
przygotowania środowiska lokalnego przeznaczonego dla instalacji
WordPressa. Do uruchomienia WordPressa wystarczy zwykły komputer lub
laptop, a dzięki środowisku lokalnemu praca będzie znacznie
efektywniejsza i szybsza. W takim przypadku nad kodem możesz pracować
lokalnie zamiast poprzez FTP albo zamiast wdrażać kod do serwera WWW z
repozytorium kodu źródłowego. Ponadto kod będzie można tworzyć i
testować bez konieczności posiadania połączenia z internetem. To oznacza
większą produktywność w trakcie dnia pracy przy komputerze, a Matka
Ziemia w przyszłości Ci za to podziękuje.

W internecie znajdziesz mnóstwo zasobów pokazujących, jak lokalnie
uruchomić WordPressa, więc tutaj nie będziemy tego szczegółowo omawiać.
W zależności od używanego systemu operacyjnego i własnych preferencji
prawdopodobnie skonfigurujesz stos MAMP (Mac, Apache, MySQL, PHP), WAMP
(Windows, Apache, MySQL, PHP) lub LAMP (Linux, Apache, MySQL, PHP).
Warto zapoznać się także z XAMPP i AMPPS, czyli stosami działającymi
niezależnie od platformy.

Mamy kilka serwerów lokalnych opracowanych specjalnie do uruchamiania
WordPressa. Desktop-Server firmy ServerPress (https://serverpress.com/)
i Local firmy Flywheel (https://localwp.com/) to dwa spośród
najpopularniejszych narzędzi tego typu umożliwiających konfigurację
lokalnej instalacji WordPressa za pomocą interfejsu użytkownika.

Narzędzia takie jak VirtualBox, Vagrant i Docker również są dość
popularne w społeczności WordPressa. Sprawdzają się one wyjątkowo dobrze
w pewnych zautomatyzowanych schematach programowania i testowania.
Witryna domowa WordPressa oferuje dobry dokument poświęcony tematowi
instalacji VVV, czyli Varying Vagrant Vagrants
(https://make.wordpress.org/core/
handbook/tutorials/installing-a-local-server/installing-vvv/), co jest
dość popularnym podejściem.

Wybór hostingu

Jeżeli jeszcze nie wybrałeś hostingu, będziesz musiał poszukać ofert w
internecie. Ujmując rzecz najkrócej: hosting to usługa pozwalająca na
publiczne udostępnienie witryny internetowej, w szczególności katalogu
WordPressa i bazy danych.

Przyjęliśmy założenie, że większość czytelników książki miała już okazję
współpracować z firmą świadczącą usługi hostingowe, część czytelników
być może pracuje w firmie posiadającej własne serwery WWW. Wybór dobrego
hostingu dla aplikacji internetowej ma znaczenie kluczowe dla
zapewnienia jej dużej wydajności, bezpieczeństwa i skalowania. Istnieje
wiele firm świadczących usługi hostingowe, większość z nich oferuje
WordPressa, choć na pewno nie wszystkie zostały zoptymalizowane
szczególnie pod kątem WordPressa.

Dla ogromnych aplikacji internetowych WordPressa najlepszym rozwiązaniem
będą usługi firmy oferującej „zarządzany” hosting WordPressa, ponieważ w
takiej firmie nacisk jest kładziony na dostarczanie zoptymalizowanych
środowisk hostingowych WordPressa. W przypadku ogromnych witryn
internetowych trzeba włożyć sporo pracy w przygotowanie mechanizmu
buforowania, co ma związek ze strukturą bazy danych WordPressa i
sposobem przechowywania w niej metadanych. Jeżeli używasz WordPressa
jako ogromnego systemu CMS wraz z wieloma postami i metadanymi, wówczas
w przypadku niewystarczająco potężnego serwera jego zasoby zostaną
szybko wykorzystane. Firmy hostingowe koncentrujące się na dostarczaniu
zoptymalizowanego środowiska dla WordPressa oferują wbudowane systemy
buforowania, które pomagają w optymalizacji sposobu dostarczania treści.

Jeżeli dostawca usług hostingowych nie oferuje buforowania, możesz
skorzystać z odpowiednich wtyczek (z rozdziału 14. dowiesz się więcej na
temat buforowania i skalowania, gdy samodzielnie zajmujesz się
zarządzaniem środowiskiem). W przypadku niektórych rozwiązań
zarządzanego hostingu WordPressa dostępne są narzędzia zaawansowane,
takie jak automatycznie uaktualniane wtyczki i integracja z usługami CDN
w celu zapewnienia lepszej optymalizacji środowiska hostingu WordPressa.

Przykładami firm zapewniających zarządzany hosting WordPressa są WP
Engine, WordPress VIP i Pagely. Dostępnych jest także wiele innych opcji
w zakresie hostingu, musisz poszukać ich w internecie.

Środowiska robocze i produkcyjne

W przypadku typowego projektu witryny internetowej kod najczęściej
znajduje się w trzech środowiskach: programistycznym, roboczym i
produkcyjnym. W idealnej sytuacji te środowiska będą znajdowały się w
oddzielnych serwerach WWW, wraz z oddzielnymi bazami danych i
instalacjami WordPressa.

Środowisko programistyczne (czasami określane mianem Dev lub DEV) to
miejsce, w którym dodajesz nowy kod i zajmujesz się konserwacją
istniejącego. Najczęściej to będzie środowisko lokalne, które
przygotowałeś na podstawie informacji zamieszczonych we wcześniejszej
części rozdziału.

Środowisko robocze (czasami określane mianem Testing lub TEST) to
miejsce, w którym przeprowadzasz testy. Dane w tym środowisku powinny
być jak najbardziej zbliżone do istniejących w środowisku produkcyjnym.
To oznacza, że niekiedy będziesz eksportować dane ze środowiska
produkcyjnego, usuwać z nich prywatne informacje użytkowników, a
następnie importować dane do środowiska testowego.

Z kolei środowisko produkcyjne (czasami określane mianem Live lub PRD)
to rzeczywista witryna internetowa udostępniona użytkownikom, którzy
mogą ją odwiedzać i korzystać z niej.

Jeżeli nie możesz umieścić kodu w takich trzech środowiskach, powinieneś
przynajmniej mieć oddzielne środowiska programistyczne i produkcyjne.
Kodu produkcyjnej wersji witryny internetowej nigdy nie uaktualniaj bez
jego uprzedniego dokładnego przetestowania w środowisku
programistycznym.

W idealnej sytuacji wszystkie prace programistyczne należy przeprowadzać
w komputerze lokalnym, przekazywać kod do repozytorium kodu źródłowego,
a następnie wdrażać go do środowiska programistycznego, aby nad kodem
mogło jednocześnie pracować wielu programistów. Gdy kod będzie gotowy do
dokładnego przetestowania, Twój szef lub klient wdroży go w środowisku
będącym dokładną kopią produkcyjnego — to będzie środowisko robocze. Po
sprawdzeniu wszystkiego kod jest gotowy do wdrożenia w środowisku
produkcyjnym. Przed wdrożeniem nowego kodu należy utworzyć kopię
zapasową istniejącej w środowisku produkcyjnym witryny internetowej — na
wypadek gdyby nastąpiła konieczność wycofania zmian. Bez przeprowadzenia
dokładnych testów nigdy nie należy przyjmować założenia o prawidłowym
działaniu kodu.

Część firm oferujących zarządzany hosting WordPressa, np. WP Engine,
oferuje automatyczne środowiska robocze dla każdej witryny internetowej
WordPressa, co jest naprawdę świetną funkcją.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeżeli myślisz o FTP podczas „wdrażania kodu”, o czym już wspomnieliśmy we wcześniejszej części rozdziału, to skorzystaj z repozytorium kodu źródłowego, takiego jak oferowane przez serwis GitHub.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Rozszerzanie WordPressa

Tak oto poznałeś podstawy dotyczące konfiguracji WordPressa i
przechowywania danych przez tę platformę oraz zapoznałeś się z
najważniejszymi narzędziami przeznaczonymi do przeprowadzania operacji
na tych danych. Zaprezentowaliśmy wprowadzenie do zaczepów akcji i
filtrów, czyli podstawowej metody rozszerzania WordPressa.

W trakcie lektury książki poznasz znacznie więcej różnych wbudowanych
funkcji i metod używanych do pracy z danymi WordPressa. W rozdziale 3.
przejdziemy do omówienia API wtyczek oraz wybranych spośród kluczowych
funkcji WordPressa, dzięki którym rozszerzanie platformy jest łatwe,
spójne i zapewnia potężne możliwości.

[1] Absolutnie nigdy, nigdy, nigdy…

[2] Trzecim parametrem funkcji add_option() uznanym w wydaniu 2.3
WordPressa za przestarzały był ciąg tekstowy „description” przechowywany
wraz z opcją w tabeli wp_options.

Rozdział 3. Stosowanie wtyczek WordPressa

Wtyczki są wspaniałe! Jeżeli jeszcze tego nie wiedziałeś, to teraz już
wiesz. Wtyczki mogą pomóc we wdrożeniu w pełni wyposażonej aplikacji
internetowej przez osobę, która wie niewiele lub nie wie nic o tworzeniu
kodu źródłowego. Niezależnie od tego, czy używasz wtyczki bezpłatnej,
komercyjnej czy utworzonej samodzielnie, wtyczka może rozszerzyć
WordPressa i dostarczyć funkcjonalność wymaganą przez aplikację.

Jak już wspomnieliśmy, doskonałą cechą oprogramowania typu open source
jest to, że członkowie społeczności są zaangażowani w usprawnianie
WordPressa i bardzo często tworzą wtyczki przeznaczone do zaoferowania
konkretnej funkcjonalności. Definicja wtyczki w WordPressie jest
następująca: „Program, zbiór jednej lub więcej funkcji utworzonych w
języku skryptowym PHP oraz dodających określony zestaw funkcjonalności
lub usług do aplikacji WordPressa. Ta funkcjonalność może być bez
problemów zintegrowana z aplikacją za pomocą punktów dostępu i metod
dostarczanych przez API wtyczek WordPressa”. Dzięki wtyczkom można
witrynę internetową zmienić w cokolwiek tylko chcesz, począwszy od
prostego bloga, poprzez witrynę typu e-commerce i serwis
społecznościowy, aż po aplikację mobilną na platformie iOS lub Android.

Wraz ze standardową instalacją WordPressa są dostarczane dwie wtyczki:
Hello Dolly i Akismet. Działanie pierwszej z nich polega na dodaniu u
góry panelu głównego dla każdej wczytywanej strony losowo wybranych słów
z piosenki Hello, Dolly! (pochodzącej z musicalu o tej samej nazwie).
Wprawdzie to nie jest zbyt użyteczna wtyczka, ale pozwala poznać
strukturę, którą należy stosować podczas tworzenia własnych wtyczek.
Wtyczka Akismet natomiast zapewnia integrację z serwisem Akismet.com w
celu automatycznego odfiltrowania spamu z komentarzy bloga. Podczas gdy
Hello Dolly to wtyczka użyteczna jedynie z perspektywy edukacyjnej,
Akismet jest niezbędna w każdej witrynie internetowej zezwalającej
użytkownikom na publikowanie komentarzy. Zawsze masz możliwość
dezaktywacji tych wtyczek lub ich usunięcia, jeśli nie znajdujesz dla
nich żadnego zastosowania w witrynie internetowej.

W oficjalnym repozytorium WordPressa (https://wordpress.org/plugins/)
masz dostęp do ponad 55 000 wtyczek. Jednak nie wszystkie znajdują się w
oficjalnym repozytorium i potrzebnej funkcjonalności będziesz musiał
szukać także w innych zakamarkach internetu. Wielu twórców wtyczek
udostępnia swoją pracę za pomocą osobistych lub firmowych witryn
internetowych, a sporo wtyczek jest bezpłatnych. Dostępne są również
wtyczki premium, za możliwość ich używania trzeba jednak zapłacić.
Podobnie jak w przypadku aplikacji mobilnych, może istnieć dostępna
bezpłatnie ograniczona wersja wtyczki typu premium, a wersja pełna
będzie dostępna za opłatą. Dla większości wtyczek typu premium istnieją
także licencje programistyczne pozwalające programistom budującym wiele
witryn internetowych wnieść jedną opłatę za pliki wtyczek, które będą
mogły być umieszczone w wielu instalacjach WordPressa.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Zachowaj ostrożność podczas wyszukiwania płatnych wtyczek w ulubionej wyszukiwarce internetowej. Zawsze upewniaj się, że wtyczkę pobierasz z oficjalnej witryny lub repozytorium jej autora. W wielu witrynach internetowych (tzw. klubach GPL) można znaleźć zmodyfikowane — „wyzerowane”, „złamane”, „pirackie” — wersje wtyczek komercyjnych dostępne bezpłatnie lub w znacznie obniżonych cenach. Większość tych wtyczek zawiera malware lub inny szkodliwy kod, którego oczywiście nie chcesz.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Licencja GPLv2

Niezależnie od sposobu zakupu lub uzyskania wtyczki WordPressa kod
każdej z nich musi być dostępny na licencji GPLv2. To oznacza, że jeśli
kod źródłowy takiej wtyczki jest rozpowszechniany (dostępny w
internecie, sprzedawany online itd.), to możesz z nim zrobić, co tylko
zechcesz, o ile powstały w wyniku tych zmian produkt wciąż będzie
dostępny na licencji GPLv2. W przypadku niektórych motywów i wtyczek
może być stosowana licencja dzielona, tzn. kod HTML, CSS i JavaScript
oraz obrazki będą dostępne na zupełnie innej licencji niż pliki PHP. W
przypadku części motywów i wtyczek nie znajdują się żadne informacje o
licencji GPLv2 lub wręcz udostępniający je zaprzeczają zastosowaniu tej
licencji. Istnieją ku temu pewne powody natury prawnej. Jednak ważne
postaci w społeczności WordPressa (mamy tutaj na myśli np. Matta
Mullenwega) twierdzą, że wszystkie motywy i wtyczki muszą być
udostępniane na licencji GPL. Według nas jeśli chcesz prowadzić
działalność komercyjną w społeczności WordPressa, musisz się stosować do
reguł.

Ogólnie rzecz biorąc, wtyczki to doskonały sposób na rozszerzenie
funkcjonalności witryny internetowej bez konieczności zmiany plików
tworzących WordPressa. Jeżeli szukasz określonej funkcjonalności, przede
wszystkim sprawdź, czy istnieje wtyczka oferująca tę funkcjonalność.
Jeżeli nie, masz wówczas dwie możliwości: pobranie i zmodyfikowanie
istniejącej wtyczki albo utworzenie nowej wtyczki zupełnie od podstaw.

Instalowanie wtyczek WordPressa

Aby zainstalować wtyczkę WordPressa, należy się zalogować do
administracyjnego panelu głównego witryny internetowej WordPressa,
znanej również pod nazwą backendu. Następnie przejdź do sekcji Wtyczki
(Plugins), jak pokazaliśmy na rysunku 3.1. Teraz masz możliwość
wyszukania wtyczki w repozytorium WordPressa albo przekazania plików
wtyczki, jeśli została pobrana z repozytorium lub innego źródła. Po
zakończeniu etapu szukania i znalezieniu interesującej Cię wtyczki
kliknij ją, aby rozpocząć instalację. Gdy już zainstalujesz wtyczkę,
możesz ją aktywować. Jeżeli nie aktywujesz wtyczki, pozostanie
nieaktywna na stronie Wtyczki/Zainstalowane wtyczki (Plugins/Installed
Plugins) witryny internetowej. Trzeba również pamiętać, że po
aktywowaniu wiele wtyczek wymaga konfiguracji, o czym najczęściej
przypomina komunikat wyświetlany w panelu głównym.

[]

Rysunek 3.1. Dodawanie nowej wtyczki w WordPressie

Jeżeli pobrałeś wtyczkę ze źródła innego niż oficjalne repozytorium
wtyczek WordPressa, powinieneś mieć archiwum ZIP zawierające pliki
wtyczki. Aby wykorzystać ją w witrynie internetowej, w panelu głównym
przejdź do sekcji Wtyczki (Plugins), kliknij przycisk Wyślij wtyczkę na
serwer (Upload), a następnie wybierz wspomniane archiwum ZIP, które
wcześniej zapisałeś na dysku komputera. Będziesz mieć możliwość
aktywowania wtyczki po jej dodaniu.

Utworzenie własnej wtyczki

Prawdziwie potężne możliwości WordPressa udostępniane twórcom aplikacji
internetowych to tworzenie własnych wtyczek pozwalających dowolnie
rozszerzać tę platformę.

Jeżeli chcesz opracować swoją wtyczkę, zacznij od utworzenia nowego
podkatalogu w katalogu wp-content/plugins, np. o nazwie my-plugin. W
nowym katalogu utwórz plik PHP o nazwie my-plugin.php. Kolejnym krokiem
jest umieszczenie w tym pliku następującego fragmentu kodu, a dowolną z
wartości możesz zastąpić inną:

    <?php

    /**

     * Nazwa wtyczki: My Plugin

     * Adres URI wtyczki: https://bwawwp.com/my-plugin/

     * Opis: To jest opis mojej wtyczki.

     * Autor: messenlehner, strangerstudios

     * Wersja: 1.0.0

     * Adres URI witryny autora: https://bwawwp.com

     * Licencja: GPL-2.0+

     * Adres URI licencji: http://www.gnu.org/licenses/gpl-2.0.txt

     */

    ?>

Zapisz plik. Nasze gratulacje, w ten sposób stałeś się autorem wtyczki
WordPressa! Wprawdzie ta wtyczka nie wykonuje jeszcze żadnego działania,
ale mimo wszystko powinieneś móc ją zobaczyć na stronie
/wp-admin/plugins.php. Śmiało, aktywuj tę wtyczkę.

Teraz wprowadzimy zmiany we wtyczce, aby wykonywała coś użytecznego. Jej
działanie będzie polegało na zmodyfikowaniu tekstu stopki wyświetlanej
przez daną instalację WordPressa. Po początkowych informacjach
dotyczących wtyczki wklej następujący fragment kodu:

    <?php

    function my_plugin_wp_footer() {

        echo 'Czytam książkę Tworzenie aplikacji internetowych WordPressa. Wydanie drugie

          i dlatego jestem mistrzem WordPressa!';

    }

    add_action( 'wp_footer', 'my_plugin_wp_footer' );

    ?>

Po zapisaniu zmian przejdź do witryny internetowej, a zobaczysz nowy
komunikat wyświetlany w stopce. Teraz możesz zabrać się za dostosowanie
tej prostej wtyczki do własnych potrzeb. Jeżeli jesteś programistą PHP,
możesz od razu przystąpić do pracy. Jeśli natomiast dopiero zaczynasz
przygodę z PHP i WordPressem, dobrym sposobem na zdobycie umiejętności
będzie pobranie i przeanalizowanie kodu w innych wtyczkach, aby
zobaczyć, na czym polega ich działanie.

To jest tylko bardzo prosty przykład pozwalający rozpocząć pracę. Więcej
kodu gotowego do wykorzystania we własnych wtyczkach napotkasz w trakcie
lektury książki.

Struktura plików we wtyczce

Gdy zaczynasz tworzenie aplikacji internetowej WordPressa, zalecamy
przygotowanie jednej wtyczki głównej zawierającej całą funkcjonalność
tej aplikacji. W przypadku motywu (dokładne omówienie motywów
zamieściliśmy w rozdziale 4.) większość kodu frontendu aplikacji będzie
przechowywana w aktywnym motywie.

Część wtyczek wykonuje tylko jedno lub dwa zadania i wówczas jeden plik
.php okazuje się całkowicie wystarczający. Wtyczka główna aplikacji
prawdopodobnie będzie znacznie bardziej skomplikowana, wraz z plikami
zasobów (CSS, obrazki i szablony), dołączonymi bibliotekami, plikami
klas oraz potencjalnie z tysiącami wierszy kodu, które będziesz chciał
umieścić w więcej niż jednym pliku.

Na liście przedstawiliśmy proponowaną strukturę plików dla wtyczki
głównej aplikacji, posłużyliśmy się przy tym przykładem wtyczki
SchoolPress. Nie wszystkie wymienione tutaj pliki i katalogi muszą być
niezbędne. Dodawaj je do wtyczki wedle potrzeb.

-   /plugins/schoolpress/adminpages/
-   /plugins/schoolpress/classes/
-   /plugins/schoolpress/css/
-   /plugins/schoolpress/css/admin.css
-   /plugins/schoolpress/css/frontend.css
-   /plugins/schoolpress/js/
-   /plugins/schoolpress/images/
-   /plugins/schoolpress/includes/
-   /plugins/schoolpress/includes/lib/
-   /plugins/schoolpress/includes/functions.php
-   /plugins/schoolpress/pages/
-   /plugins/schoolpress/services/
-   /plugins/schoolpress/scheduled/
-   /plugins/schoolpress/schoolpress.php

/adminpages/

W katalogu /adminpages/ umieszczaj pliki .php przeznaczone dla każdej
strony panelu głównego dodawanej przez wtyczkę. Przykładowo w kolejnym
fragmencie kodu pokazaliśmy, jak dodać stronę panelu głównego i wczytać
ją z katalogu /adminpages/:

    <?php

    // Dodanie menu SchoolPressa wraz ze stroną raportów

    function sp_admin_menu() {

        add_menu_page(

        'SchoolPress',

        'SchoolPress',

        'manage_options',

        'sp_reports',

        'sp_reports_page'

      );

    }

    add_action( 'admin_menu', 'sp_admin_menu' );

    // Funkcja wczytująca stronę administracyjną

    function sp_reports_page() {

      require_once dirname( __FILE__ ) . "/adminpages/reports.php";

    }

    ?>

/classes/

Definicje klas PHP umieszczaj w katalogu /classes/. Ogólnie rzecz
biorąc, każdy plik w tym katalogu powinien zawierać tylko jedną
definicję klasy. Nazwy plików klas powinny być nadawane zgodnie z
następującym schematem: class<NazwaKlasy>.php, gdzie NazwaKlasy to nazwa
nadana definiowanej klasie.

/css/

W katalogu /css/ umieszczaj pliki CSS przeznaczone dla wtyczki. Style
CSS podziel na umieszczone w plikach admin.css i frontend.css w
zależności od przeznaczenia stylów: panel główny WordPressa lub
frontend. Przykładowo w tym katalogu możesz umieścić niezbędne
biblioteki CSS i wspomagające je biblioteki JavaScript.

Oto przykład kodu zapewniającego wczytanie stylów z plików admin.css i
frontend.css, które powinny znajdować się w katalogu /css/ wtyczki:

    <?php

    function sp_load_admin_styles() {

      wp_enqueue_style(

        'schoolpress-plugin-admin',

        plugins_url( 'css/admin.css', __FILE__ ),

        array(),

        SCHOOLPRESS_VERSION,

        'screen'

      );

    }

    add_action( 'admin_enqueue_scripts', 'sp_load_admin_styles' );

    function sp_load_frontend_styles() {

        wp_enqueue_style(

            'schoolpress-plugin-frontend',

            plugins_url( 'css/frontend.css', __FILE__ ),

            array(),

            SCHOOLPRESS_VERSION,

            'screen'

        );

    }

    add_action( 'wp_enqueue_scripts', 'sp_load_frontend_styles' );

    ?>

Zaczep admin_enqueue_scripts należy wykorzystać w celu dodawania
skryptów i stylów przeznaczonych do użycia w administracyjnym panelu
głównym. Zaczepu wp_enqueue_scripts należy używać do dodawania skryptów
i stylów poznaczonych dla frontendu aplikacji internetowej.

Style CSS dotyczące komponentów panelu głównego WordPressa powinny
trafić do pliku admin.css. Style CSS definiujące wygląd frontendu
witryny internetowej powinny natomiast być umieszczone w pliku
frontend.css. Należy zachować ostrożność podczas dodawania stylów CSS do
pliku frontend.css. Dodając style frontendu do plików wtyczek, zadawaj
sobie pytanie, czy dane reguły CSS nie powinny trafić do motywu
aplikacji, ponieważ większość kodu definiującego styl frontendu powinna
być obsługiwana przez motyw.

Kod stylów CSS, który powinien trafić do pliku CSS wtyczki, to, ogólnie
rzecz biorąc, reguły definiujące wygląd strony, które zostaną
zastosowane, gdy nie zostanie wczytany motyw. Wyobraź sobie sytuację, w
której witryna internetowa nie ma zdefiniowanego żadnego motywu ani
stylów CSS. Jaka jest minimalna ilość kodu CSS niezbędna, aby
wygenerowany przez wtyczkę kod miał sens? Należy oczekiwać, że style
zdefiniowane w motywie nadpiszą te style.

Na przykład plik frontend.css nigdy nie powinien zawierać stylów
definiujących kolory. Nie ma natomiast problemu w określeniu, że awatar
ma mieć 64 piksele szerokości i jest elementem pływającym umieszczonym
przy lewej krawędzi kontenera.

/js/

W tym katalogu należy umieścić pliki JavaScript niezbędne do działania
wtyczki. Także w tym przypadku kod JavaScript można podzielić na
polecenia umieszczone w plikach admin.js i frontend.js, w zależności od
miejsca, w którym będzie potrzebny dany kod.

W katalogu /js/ można umieścić także opracowane przez podmioty
zewnętrzne biblioteki JavaScript, które będą wykorzystane w aplikacji.
Jednak w takim przypadku najlepiej będzie utworzyć dla nich osoby
podkatalog.

Oto przykładowy fragment kodu wczytującego pliki admin.js i frontend.js
z katalogu /js/:

     <?php

        function sp_load_admin_scripts() {

                wp_enqueue_script(

                        'schoolpress-plugin-admin',

                        plugins_url( 'js/admin.js', __FILE__ ),

                        array( 'jquery' ),

                        SCHOOLPRESS_VERSION

                );

        }

        add_action( 'admin_enqueue_scripts', 'sp_load_admin_scripts' );

        function sp_load_frontend_scripts() {

                wp_enqueue_script(

                        'schoolpress-plugin-frontend',

                        plugins_url( 'js/frontend.js', __FILE__ ),

                        array( 'jquery' ),

                        SCHOOLPRESS_VERSION

                );

        }

        add_action( 'wp_enqueue_scripts', 'sp_load_frontend_scripts' );

        ?>

Podobnie jak w przypadku stylów CSS, ustalenie, czy dany kod JavaScript
powinien trafić do pliku kodu wtyczki czy do pliku kodu motywu, może być
trudne. Ogólnie rzecz biorąc, kod wspomagający działanie motywu (np.
efekty menu) powinien trafić do motywu, a kod wspomagający wtyczkę (np.
odpowiedzialny za obsługę żądań AJAX) powinien trafić do wtyczki. W
praktyce jednak będziesz się przekonywać, że wtyczka używa kodu
zdefiniowanego w motywie i na odwrót.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Tę samą funkcję wywołania zwrotnego można wykorzystać do zagwarantowania, że we wtyczce zostaną dołączone pliki kodu JavaScript i stylów CSS. Dlatego funkcji wp_enqueue_script() i wp_enqueue_style() można używać wraz z zaczepami wp_enqueue_scripts i admin_enqueue_scripts. Nie istnieją zaczepy takie jak wp_enqueue_styles i admin_enqueue_styles.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/images/

Wszelkie obrazy wymagane przez wtyczkę należy umieścić w katalogu
/images/.

/includes/

Katalog /includes/ jest przeznaczony do przechowywania wszelkich plików
.php, które są wymagane przez wtyczkę, ale nie pasują do żadnego innego
katalogu. Jedynym plikiem .php umieszczonym w katalogu głównym wtyczki
powinien być główny plik wtyczki, czyli w omawianym przykładzie
schoolpress.php. Wszystkie pozostałe pliki powinny trafić do innych
katalogów. Jeżeli żaden z nich nie będzie odpowiedni, umieść pliki w
katalogu /includes/.

Standardowa procedura polega na definiowaniu plików functions.php,
common.php i helpers.php przeznaczonych dla napisanego w PHP kodu
pomocniczego wykorzystywanego przez wtyczkę. Ten plik powinien zawierać
wszystkie niewielkie skrypty, które nie odgrywają ważnej roli w logice
lub funkcjonalności wtyczki, choć są potrzebne do jej prawidłowego
działania. Przykładami takich funkcji są funkcje odpowiedzialne za
skracanie tekstu, generowanie losowych ciągów tekstowych, a także inne
przypominające framework funkcje niedostępne w standardowej instalacji
WordPressa.

/includes/lib/

W katalogu /includes/lib umieszczaj opracowane przez podmioty zewnętrzne
biblioteki niezbędne do działania wtyczki.

/pages/

W katalogu /pages/ umieszczaj wszelkie pliki kodu .php powiązane z
frontendem i dodane przez wtyczkę. Strony frontendu są zwykle dodawane
za pomocą skrótów, które można osadzić na standardowej stronie
WordPressa, i wyświetlają żądaną treść.

W kolejnym fragmencie kodu pokazaliśmy, jak można utworzyć skrót
przeznaczony do umieszczenia na stronie WordPressa w celu wygenerowania
strony przez wtyczkę. Tzw. preheader to tutaj kod wykonywany przed
wczytaniem funkcji wp_head() i tym samym uruchomiony przed wszelkimi
nagłówkami HTML bądź kodem przekazywanym przeglądarce WWW. Działanie
funkcji skrótu pozwala przekazać treść HTML do rzeczywistej strony, co
odbywa się po napotkaniu wywołania funkcji skrótu.

Ten fragment kodu umieść w pliku /plugins/<katalog
wtyczki>/pages/stub.php i następnie dołącz go (zwykle robi się to za
pomocą funkcji require_once()) z poziomu głównego pliku wtyczki.
Kolejnym krokiem jest dodanie skrótu [sp_stub] na stronie witryny
WordPressa.

    <?php

    // Definicja preheadera

    function sp_stub_preheader() {

      if ( !is_admin() ) {

        global $post, $current_user;

        if ( !empty( $post->post_content ) && strpos

           ( $post->post_content, '[sp_stub]' ) !== false ) {

          /*

            To jest miejsce na preheader

          */

        }

      }

    }

    add_action( 'wp', 'sp_stub_preheader', 1 );

    // Skrót [sp_stub]

    function sp_stub_shortcode() {

      ob_start();

      ?>

      To jest miejsce na kod, np. HTML.

      <?php

      $temp_content = ob_get_contents();

      ob_end_clean();

      return $temp_content;

    }

    add_shortcode( 'sp_stub', 'sp_stub_shortcode' );

    ?>

W kodzie preheadera za pomocą funkcji !is_admin() najpierw jest
przeprowadzane sprawdzenie, czy strona została wczytana poza sekcją
administracyjną. W przeciwnym razie ten kod mógłby zostać wykonany
podczas edycji posta w panelu głównym. Następnie zostaje odszukany ciąg
tekstowy [sp_stub] w treści zmiennej globalnej $post. Ta funkcja zostaje
dołączona do zaczepu wp uruchamianego po zdefiniowaniu przez WordPressa
zmiennej globalnej $post dla strony bieżącej, ale jeszcze przed
wygenerowaniem jakichkolwiek nagłówków lub treści HTML.

Kod preheadera można wykorzystać do sprawdzenia uprawnień, przetworzenia
przekazanych formularzy, a także przygotowania dowolnego kodu
niezbędnego na stronie. W architekturze MVC będzie to kod modelu i
kontrolera. Skoro ten kod jest wykonywany przed wygenerowaniem
jakichkolwiek nagłówków, użytkownika nadal można bezpiecznie
przekierować na inną stronę. Na przykład za pomocą funkcji wp_redirect()
można przenieść użytkownika na stronę logowania lub rejestracji, jeśli
nie ma jeszcze uprawnień do wyświetlenia strony.

W funkcji skrótu używane są wywołania ob_start(), ob_get_contents() i
ob_end_clean(), które są w PHP funkcjami umożliwiającymi buforowanie
danych wyjściowych do zmiennej. Użycie tego kodu oznacza, że wszystko
to, co znajduje się między znacznikami ?> i <?php, zostaje umieszczone w
zmiennej $temp_content zamiast zostać wygenerowane podczas przetwarzania
(w omawianym przykładzie spowodowałoby to wyświetlenie danych przed
znacznikiem <html> witryny). To nie jest konieczne: można zdefiniować
funkcję $temp_content() i wykorzystać PHP w celu dodania danych do tego
ciągu tekstowego. Buforowanie danych wyjściowych pozwala tworzyć kod w
sposób przypominający szablon i umożliwia łączenie kodu HTML z PHP,
który później jest łatwiejszy w odczycie.

/services/

Wszelkie pliki .php zawierające kod dla wywołań AJAX należy umieścić w
katalogu /services/.

/scheduled/

W katalogu /scheduled/ należy umieścić wszelkie pliki .php zawierające
kod powiązany z zadaniami mechanizmu cron lub przeznaczony do
uruchamiania w określonych odstępach czasu.

/schoolpress.php

Jest to plik główny wtyczki. W przypadku małych wtyczek będzie to jedyny
niezbędny plik. Natomiast dla dużych wtyczek ten plik będzie zawierał
jedynie polecenia include, definicje stałych i pewne komentarze
wskazujące, które z pozostałych plików zawierają szukany kod.

Dodatki dla istniejących wtyczek

Wtyczka, czyli fragment kodu działający w WordPressie i rozpowszechniany
publicznie[1], musi być dostępna jako oprogramowanie typu open source i
na licencji GPL. Z repozytorium wtyczek możesz wziąć dowolną, zmienić
jej nazwę i wydać jako zupełnie nową wtyczkę. Jednak takie działanie
może prowadzić do niepotrzebnych sporów, więc sugerujemy, aby unikać
tworzenia „rozwidleń” (ang. fork) wtyczek w taki sposób, jeśli nie masz
zamiaru usprawniać wtyczki i rozwijać jej dalej.

Co można zrobić w sytuacji, gdy istniejąca wtyczka spełnia 95% Twoich
wymagań, ale potrzebuje jeszcze kilku wierszy kodu, aby spełnić je w
100%? Rozważ utworzenie dodatku dla wtyczki.

Większość doskonale opracowanych wtyczek ma własne zaczepy i filtry,
które umożliwiają innym programistom tworzenie dodatków. Podobnie jak
opracowujesz wtyczkę do wykorzystania zaczepów i filtrów WordPressa, tak
samo możesz przygotować wtyczkę używającą zaczepów i filtrów innej
wtyczki. W pewnych sytuacjach może wystąpić konieczność modyfikacji
pierwotnej wtyczki i dostosowania jej do własnych potrzeb, co jest jak
najbardziej możliwe. Zamiast tego jednak lepiej będzie zasugerować jej
autorowi dodanie pewnych zaczepów i filtrów.

Przypadki użycia i przykłady

W takim razie co należy tworzyć na podstawie wspomnianych wtyczek
bezpłatnych i komercyjnych? Spróbujmy utworzyć społeczność wokół
WordPressa za pomocą wtyczki SchoolPress.

Każdy nauczyciel będzie administratorem własnej grupy i może łatwo
dodawać do niej uczniów. Uczeń zaś może się angażować w działalność
grupy, czyli udzielać się „na tablicy”. Dzięki BuddyPress uczeń może
dodawać kolejne osoby jako swoich przyjaciół, obserwować przyjaciół i
nauczycieli, a także wysyłać prywatne komentarze do nauczycieli, jeśli
ma pytania.

Dzięki BadgeOS i społeczności tej wtyczki nauczyciel może tworzyć
śmieszne plakietki będące nagrodami dla uczniów za wykonywanie różnych
zadań domowych i projektów. Tymi plakietami uczniowie mogą się chwalić
przyjaciołom oraz w serwisach społecznościowych.

Gravity Forms umożliwia uczniom łatwe oddawanie wykonanych prac
domowych.

Pętla WordPressa

Doskonała i oferująca potężne możliwości pętla WordPressa jest tym, co
pozwala platformie wyświetlać posty. W zależności od wywoływanego pliku
szablonu i sposobu poruszania się po witrynie internetowej WordPress
wykonuje zapytania do bazy danych i pobiera posty niezbędne do zwrócenia
użytkownikowi końcowemu, a następnie przeprowadza przez nie iteracje.

Prawidłowo zbudowany motyw WordPressa zawiera następujące pliki
składające się na pętlę WordPressa:

-   index.php
-   archive.php
-   category.php
-   tag.php
-   single.php
-   page.php

Jeżeli otworzysz dowolny z tych plików, znajdziesz w nim kod, który
będzie podobny do następującego:

    <?php

    if ( have_posts() ) {

      while ( have_posts() ) {

        the_post();

        the_title( '<h2>', '</h2>' );

        the_content();

      }

    } else {

      // Wyświetlenie komunikatu informującego o braku postów!

    }

    ?>

Funkcja have_posts() sprawdza, czy istnieją jakiekolwiek posty, przez
które będzie przeprowadzona iteracja, więc następuje zainicjowanie pętli
while. Funkcja the_post() jest wywoływana na początku każdej iteracji w
celu skonfigurowania posta wraz ze wszystkimi zmiennymi globalnymi, aby
dane powiązane z postem mogły zostać wyświetlone użytkownikowi.

Zmienne globalne WordPressa

Zmienne globalne to takie, które można zdefiniować, a następnie
wykorzystać w pozostałej części kodu. WordPress ma wiele wbudowanych
zmiennych globalnych, dzięki którym możesz zaoszczędzić naprawdę wiele
czasu i zasobów podczas tworzenia kodu.

Aby wyświetlić pełną listę wszystkich dostępnych zmiennych globalnych,
wykonaj ten oto fragment kodu:

    <?php

    echo '<pre>';

    print_r( $GLOBALS );

    echo '</pre>';

    ?>

Jeżeli z poziomu tworzonego kodu chcesz uzyskać dostęp do zmiennej
globalnej, skorzystaj z następującego rozwiązania:

    <?php

    global $global_variable_name;

    ?>

Dostępność niektórych zmiennych globalnych zależy od tego, gdzie
aktualnie się znajdujesz w WordPressie. Oto krótka lista
najpopularniejszych zmiennych globalnych WordPressa:

$post

Obiekt zawierający dane posta pobrane z tabeli wp_posts dla posta
aktualnie przetwarzanego przez pętlę WordPressa.

$authordata

Obiekt zawierający wszystkie dane autora posta aktualnie przetwarzanego
przez pętlę WordPressa.

$wpdb

Klasa $wpdb jest używana do bezpośredniej pracy z bazą danych. Po
globalizacji można ją stosować w samodzielnie zdefiniowanej
funkcjonalności w celu pobierania, uaktualniania, wstawiania i usuwania
rekordów bazy danych. Jeżeli jesteś początkującym programistą WordPressa
i jeszcze nie znasz wszystkich funkcji przeznaczonych do umieszczania
informacji w bazie danych oraz pobierania z niej informacji, klasa $wpdb
będzie Twoim najlepszym przyjacielem.

Zapytania wykonywane z użyciem $wpdb okazują się również użyteczne do
zarządzania tabelami niestandardowymi, które są wymagane przez
aplikację, lub do wykonywania skomplikowanych zapytań (prawdopodobnie
złączeń wielu tabel) znacznie szybciej, niż podstawowe funkcje
WordPressa wykonują zapytania. Nie należy na tej podstawie przyjmować
założenia, że wbudowane funkcje WordPressa przeznaczone do wykonywania
zapytań do bazy danych są wolne. Jeśli dokładnie nie wiesz, co robisz,
do pobierania postów, informacji o użytkownikach i metadanych używaj
funkcji wbudowanych. WordPress doskonale radzi sobie z optymalizacją
zapytań i buforowaniem wyników tych wywołań, które dzięki temu będą
dobrze działały we wszystkich uruchamianych zapytaniach. Jednak w
pewnych sytuacjach można zaoszczędzić trochę czasu i samodzielnie
zdefiniować zapytanie. Przykład takiego rozwiązania przedstawimy w
rozdziale 14.

Używanie niestandardowych tabel bazy danych

We wtyczce SchoolPress niestandardowa tabela jest przeznaczona do
przechowywania związku umożliwiającego połączenie ucznia z jego
zadaniami. Takie rozwiązanie pozwala zachować nieco większą
przejrzystość w podstawowych tabelach WordPressa[2] oraz łatwo wykonywać
zapytania typu „pobierz wszystkie zadania Marka”.

W celu dodania własnej tabeli do bazy danych konieczne jest
przygotowanie zapytania SQL typu CREATE TABLE i wykonanie go w bazie
danych WordPressa. Istnieje możliwość użycia metody $wpdb->query() lub
podstawowej funkcji WordPressa o nazwie dbDelta().

W przypadku tabel niestandardowych należy pamiętać o kilku kwestiach.
Przede wszystkim trzeba przechowywać kolumnę db_version dla wtyczki
aplikacji, aby znać wersję schematu używanej bazy danych na wypadek jego
uaktualnienia. Można sprawdzić wersję, aby konfigurację SQL
przeprowadzać tylko raz dla każdej wersji. Inną powszechną praktyką jest
przechowywanie nazwy tabeli niestandardowej jako właściwości $wpdb, co
powinno później nieco ułatwić wykonywanie zapytań.

Na listingu 3.1 przedstawiliśmy funkcję konfigurującą bazy danych dla
aplikacji SchoolPress.

Listing 3.1. Skonfigurowanie bazy danych dla aplikacji SchoolPress

    <?php

    // Skonfigurowanie bazy danych dla aplikacji SchoolPress

    function sp_setupDB() {

      global $wpdb;

      // Skróty dla tabel bazy danych aplikacji SchoolPress

      $wpdb->schoolpress_assignment_submissions = $wpdb->prefix .

        'schoolpress_assignment_submissions';

      $db_version = get_option( 'sp_db_version', 0 );

      // Utworzenie tabel w nowych instalacjach

      if ( empty( $db_version ) ) {

        global $wpdb;

        $sqlQuery = "

        CREATE TABLE '" . $wpdb->schoolpress_assignment_submissions . "' (

          `assignment_id` bigint(11) unsigned NOT NULL,

          `submission_id` bigint(11) unsigned NOT NULL,

        UNIQUE KEY `assignment_submission` (`assignment_id`,`submission_id`),

        UNIQUE KEY `submission_assignment` (`submission_id`,`assignment_id`)

        )

        ";

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';

        dbDelta( $sqlQuery );

        $db_version = '1.0';

        update_option( 'sp_db_version', '1.0' );

      }

    }

    add_action( 'init', 'sp_dbSetup', 0 );

    ?>

Ponieważ funkcja sp_dbSetup() jest uruchomiona na wczesnym etapie
działania init (priorytet 0), skróty tabel są dostępne w pozostałej
części działającego kodu. Nie zawsze można przyjmować założenie o
dostępności prefiksu wp_, więc właściwość $wpdb->prefix jest używana w
celu pobrania prefiksu bazy danych dla instalacji WordPressa.

Wersja bazy danych aplikacji SchoolPress jest przechowywana w tabeli
opcji WordPressa. Pobieramy tę wartość, a jeśli jest ona pusta,
uruchamiamy kod odpowiedzialny za utworzenie tabel niestandardowych.
Polecenie SQL CREATE TABLE jest tutaj dość typowe. Aby mieć pewność, że
działa prawidłowo, przed umieszczeniem takiego polecenia w kodzie
wtyczki zawsze należy je wykonać bezpośrednio względem bazy danych
MySQL.

Funkcja dbDelta() jest używana do utworzenia tabeli bazy danych. Tworzy
nową tabelę, o ile jeszcze nie istnieje. Jeżeli tabela o tej samej
nazwie już istnieje, określane jest odpowiednie zapytanie ALTER TABLE
mające na celu dopasowanie istniejącej tabeli do nowego schematu.

Aby móc używać funkcji dbDelta(), trzeba się upewnić, że został
dołączony plik wp-admin/includes/ upgrade.php, ponieważ zostanie on
wczytany, gdy zajdzie potrzeba. Następnym krokiem jest przekazanie
funkcji dbDelta() kodu SQL dla zapytania CREATE TABLE. Ten kod SQL musi
być w określonym formacie, który jest nieco ściślejszy niż ogólny format
MySQL (użyty tutaj format pochodzi ze strony WordPress Codex:
https://codex.wordpress.org/Creating_Tables_with_Plugins#
Creating_or_Updating_the_Table).

1.  Każda kolumna powinna w poleceniu SQL znajdować się w oddzielnym
    wierszu.
2.  Między słowami kluczowymi PRIMARY KEY i definicją klucza
    podstawowego powinny znajdować się dwie spacje.
3.  Należy używać słowa kluczowego KEY zamiast jego synonimu INDEX i
    dołączać przynajmniej jedno polecenie KEY.
4.  Nazw kolumn nie należy ujmować w apostrofy ani lewe apostrofy.

Wykonywanie zapytań

Stosowanie funkcji dbDelta() jest preferowane podczas tworzenia tabel,
ponieważ powoduje automatyczne uaktualnienie starszych wersji tabel.
Możliwe jest również wykonywanie zapytania CREATE TABLE za pomocą
$wpdb->query($sqlQuery);.

Do wykonania dowolnego, poprawnego zapytania SQL można wykorzystać
metodę $wpdb->query(). Metoda query() definiuje wiele właściwości
obiektu $wpdb, które okazują się użyteczne podczas debugowania lub po
prostu w trakcie monitorowania zapytań.

$wpdb->result

Zawiera niezmodyfikowany wynik zapytania SQL.

$wpdb->num_queries

Zawiera wartość inkrementowaną po każdym wykonaniu zapytania.

$wpdb->last_query

Zawiera ostatnio wykonane zapytanie SQL.

$wpdb->last_error

Zawiera ciąg tekstowy wraz z ostatnio wygenerowanym komunikatem błędu
SQL, o ile taki istnieje.

$wpdb->insert_id

Zawiera identyfikator utworzony na podstawie ostatniego zapytania
INSERT, którego wykonanie zakończyło się pomyślnie.

$wpdb->rows_affected

Zawiera liczbę rekordów, których dotyczyło zapytanie.

$wpdb->num_rows

Zawiera liczbę rekordów zwróconych przez zapytanie SELECT.

$wpdb->last_result

Zawiera tablicę obiektów rekordów wygenerowanych za pomocą funkcji PHP
mysql_fetch_object().

Wartość zwrotna metody $wpdb->query() opiera się na wykonanym zapytaniu
i na tym, czy zakończyło się ono pomyślnie.

-   Jeżeli wykonanie zapytania zakończyło się niepowodzeniem, wartością
    zwrotną metody będzie false. Można przeprowadzić sprawdzenie pod tym
    kątem za pomocą polecenia takiego jak if($wpdb->query($query) ===
    false) { wp_die("Niepowodzenie!""); }.
-   Niezmodyfikowany wynik MySQL zwracany przez zapytanie CREATE, ALTER,
    TRUNCATE i DROP.
-   Liczba wierszy, których dotyczyło zapytanie, jest zwracana dla
    zapytań INSERT, UPDATE, DELETE i REPLACE.
-   Liczba wierszy, których dotyczyło zapytanie, jest zwracana również
    dla zapytania SELECT.

Znaki sterujące w zapytaniu bazy danych

Trzeba w tym miejscu wspomnieć, że wartości przekazywane w metodzie
query() nie są automatycznie uzupełniane o niezbędne znaki sterujące.
Dlatego zawsze trzeba je dodawać samodzielnie dla niezaufanych danych
wejściowych, gdy metoda query() jest stosowana bezpośrednio.

Mamy dwa podstawowe sposoby dodawania znaków sterujących w zapytaniach
SQL. Pierwszy to opakowanie zmiennej wywołaniem funkcji esc_sql(), jak
pokazaliśmy na listingu 3.2. Drugi zaś to wykorzystanie metody
$wpdb->prepare() do przygotowania zapytania.

Listing 3.2. Zastosowanie funkcji esc_sql()

    global $wpdb;

    $user_query = $_REQUEST['uq'];

    $sqlQuery = "SELECT user_login FROM $wpdb->users WHERE

    user_login LIKE '%" . esc_sql($user_query) . "%' OR

    user_email LIKE '%" . esc_sql($user_query) . "%' OR

    display_name LIKE '%" . esc_sql($user_query) . "%'

    ";

    $user_logins = $wpdb->get_col($sqlQuery);

    if(!empty($user_logins))

    {

      echo "<ul>";

    foreach($user_logins as $user_login)

      {

        echo "<li>$user_login</li>";

    }

    echo "</ul>";

    }

Ewentualnie zapytanie można zdefiniować za pomocą metody prepare(),
która działa podobnie jak funkcje sprintf() i printf() w Pythonie. Gdy
tylko to możliwe, preferowane jest stosowanie metody prepare(), ponieważ
znacznie lepiej radzi sobie ona z dodawaniem znaków sterujących,
a ponadto pomaga uniknąć problemów związanych z błędnie umieszczonymi
apostrofami.

Metoda prepare() klasy $wpdb została zdefiniowana w pliku
wp-includes/wp-db.php i akceptuje co najmniej dwa parametry.

$query

Ciąg tekstowy niestandardowego polecenia SQL wraz z miejscami
zarezerwowanymi dla każdej wartości dynamicznej.

$args

Jeden lub więcej parametrów dodatkowych, które zostaną użyte do
zastąpienia miejsc zarezerwowanych w zapytaniu SQL.

W ciągu tekstowym zapytania SQL można użyć następujących dyrektyw:

-   %d (liczba całkowita),
-   %f (liczba zmiennoprzecinkowa),
-   %s (ciąg tekstowy),
-   %% (literał znaku procentu — nie są wymagane żadne argumenty).

Dyrektywy %d, %f i %s powinny pozostać nieujęte w znaki cytowania w
zapytaniu SQL, a każde miejsce zarezerwowane musi mieć odpowiedni
argument przekazany dla takiej dyrektywy. Literały (%) jako część
zapytania muszą być prawidłowo zapisywane w postaci %%.

    $sqlQuery = $wpdb->prepare("SELECT user_login FROM $wpdb->users WHERE

    user_login LIKE %%%s%% OR

    user_email LIKE %%%s%% OR

    display_name LIKE %%%s%%", $user_query, $user_query, $user_query);

    $user_logins = $wpdb->get_col($sqlQuery);

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeżeli używasz $wpdb->prepare() bez dołączenia parametru $args, wówczas PHP wygeneruje komunikat ostrzeżenia o brakującym argumencie dla wpdb::prepare(). Jeżeli zapytanie SQL nie używa żadnych wartości miejsc zarezerwowanych, to nie trzeba stosować wywołania prepare().
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Mógłbyś zapytać: a co ze znakiem procentu? Znak % jest używany w
charakterze znaku wieloznacznego w zapytaniach SELECT zawierających
klauzulę LIKE. Dlatego jeśli szukasz wartości user_login LIKE %coleman%,
zostaną zwrócone loginy użytkowników takich jak jcoleman, jasoncoleman
i coleman1982. Aby użyć literału znaku procentu w metodzie prepare(),
trzeba go poprzedzić drugim znakiem procentu, %% — w ostatecznym
zapytaniu będzie znajdował się tylko jeden znak %.

Znak procentu jest używany także w dyrektywie %s. Jest to miejsce
zarezerwowane, w którym parametr $user_query zostanie zastąpiony po
dodaniu znaków cytowania.

W poprzednim fragmencie kodu zapewne zauważyłeś wywołanie metody
$wpdb->get_col(). WordPress oferuje wiele użytecznych metod obiektu
$wpdb zapytań SELECT i INSERT oraz wielu innych, często wykonywanych
zapytań w MySQL.

Zapytania SELECT wraz z $wpdb

Obiekt WordPress $wpdb ma kilka użytecznych metod przeznaczonych do
wybierania tablic, obiektów, rekordów, kolumn, a nawet pojedynczych
wartości z bazy danych MySQL za pomocą zapytania SQL.

Wywołanie $wpdb→get_results($query, $output_type) wykonuje zapytanie SQL
i zwraca tablicę last_results zawierającą wszystkie rekordy z zapytania
SQL w podanym typie danych wyjściowych. Domyślnie wynikiem będzie
„liczbowo indeksowana tablica obiektów rekordów”. Oto pełna lista typów
danych wyjściowych, pobrana ze strony WordPress Codex:

OBJECT

Wynikiem jest liczbowo indeksowana tablica obiektów rekordów.

OBJECT_K

Wynikiem są dane wyjściowe w postaci tablicy asocjacyjnej obiektów
rekordów wraz z kluczami w postaci wartości pierwszych kolumn
(powtarzające się wartości będą odrzucone).

ARRAY_A

Wynikiem są dane wyjściowe w postaci liczbowo indeksowanej tablicy
tablic asocjacyjnych wraz z kluczami w postaci nazw kolumn.

ARRAY_N

Wynikiem są dane wyjściowe w postaci liczbowo indeksowanej tablicy
liczbowo indeksowanych tablic (czyli tablica tablic).

W kolejnym fragmencie kodu pokazaliśmy, jak można używać tablicy
zwróconej przez $wpdb->get_results() w przypadku stosowania typu OBJECT
jako typu danych wyjściowych:

    <?php

    global $wpdb;

    $sqlQuery = "SELECT * FROM $wpdb->posts

      WHERE post_type = 'assignment'

      AND post_status = 'publish' LIMIT 10";

    $assignments = $wpdb->get_results( $sqlQuery );

    // Rekordy są przechowywane w tablicy, do iteracji została użyta pętla foreach

    foreach ( $assignments as $assignment ) {

    // Poszczególne elementy są obiektami z nazwami właściwości odpowiadającymi nazwom kolumn SQL

    ?>

    <h3><?php echo $assignment->post_title;?></h3>

    <?php echo apply_filters( "the_content", $assignment->post_content );?>

    <?php

    }

    ?>

Wynikiem wykonania $wpdb->get_col($query, $column_offset = 0) będzie
tablica wartości w pierwszej kolumnie wyniku zwróconego przez MySQL.
Parametr $column_offset można wykorzystać do przechwycenia innych kolumn
z wyniku (0 to pierwsza kolumna, 1 to druga kolumna itd.).

Ta funkcja jest najczęściej stosowana do pobrania z tabeli bazy danych
identyfikatorów, które następnie zostaną zastosowane w innym wywołaniu
funkcji bądź zapytaniu bazy danych.

    <?php

    global $wpdb;

    $sqlQuery = "SELECT ID FROM $wpdb->posts

      WHERE post_type = 'assignment'

      AND post_status = 'publish'

      LIMIT 10";

    // Pobranie identyfikatorów

    $assignment_ids = $wpdb->get_col( $sqlQuery );

    // Wynik jest tablicą, więc trzeba przeprowadzić iterację przez poszczególne elementy

    foreach ( $assignment_ids as $assignment_id ) {

      // Mając identyfikator, można za pomocą wywołania get_post() pobrać kolejne dane

      $assignment = get_post( $assignment_id );

      ?>

      <h3><?php echo $assignment->post_title;?></h3>

      <?php echo apply_filters( "the_content", $assignment->post_content );?>

      <?php

    }

    ?>

Zwróć uwagę na polecenie global $wpdb; występujące w większości
przykładów, co ma na celu podkreślenie konieczności umieszczenia $wpdb w
zasięgu, zanim zostanie wywołana którakolwiek z metod tego obiektu. W
praktyce to polecenie jest zwykle umieszczane na początku funkcji lub
pliku.

Wywołanie $wpdb->get_row($query, $output_type, $row_offset) zostało
użyte do pobrania tylko jednego rekordu z wyniku. Zamiast tablicy
wyników z otrzymanego zbioru wynikowego jest pobierany jedynie pierwszy
obiekt (lub tablica w przypadku zdefiniowania wartości $output_type).

Parametr $row_offset pozwala pobrać inny rekord z wyniku (0 to pierwszy
rekord, 1 to drugi rekord itd.).

Wstawianie, zastępowanie i uaktualnianie. Wywołanie
$wpdb->insert($table, $data, $format) pozwala wstawić dane do bazy
danych. Zamiast tworzyć własne zapytanie INSERT wystarczy przekazać
nazwę tabeli i tablicę asocjacyjną zawierającą rekord danych, a
WordPress przygotuje zapytanie i odpowiednio zastosuje znaki cytowania.
Klucze tablicy $data muszą być mapowane na nazwy kolumn w tabeli.
Wartościami tablicy są natomiast wartości przeznaczone do wstawienia w
rekordzie tabeli.

    <?php

    // Przetwarzanie nowych zapytań w celu przypisania danych

    global $wpdb, $current_user;

    // Utworzenie zapytania

    $assignment_id = intval( $_REQUEST['assignment_id'] );

    $submission_id = wp_insert_post(

      array(

        'post_type'    => 'submission',

        'post_author'  => $current_user->ID,

        'post_title'   => sanitize_title( $_REQUEST['title'] ),

        'post_content' => sanitize_text_field( $_POST['submission'] )

      )

    );

    // Wykonanie zapytania

    $wpdb->insert(

      $wpdb->schoolpress_assignment_submissions,

      array( "assignment_id"=>$assignment_id, "submission_id"=>$submission_id ),

      array( '%d', '%d' )

    );

    /*

      To wywołanie spowoduje wygenerowanie zapytania SQL takiego jak:

      INSERT INTO

      'wp_schoolpress_assignment_submissions'

      ('assignment_id','submission_id' VALUES (101,10)

    */

    ?>

W tym fragmencie kodu wywołanie wp_insert_post() pozwala utworzyć
zapytanie, a następnie $wpdb_insert() wstawia nową kolumnę do tabeli
niestandardowej, łącząc przypisania z zapytaniem.

Trzecim parametrem jest tablica formatów wskazująca metodzie sposób
sformatowania danych podczas tworzenia zapytania SQL (w omawianym
przykładzie dane to liczby całkowite). Dostępne formaty danych to %s dla
ciągów tekstowych, %d dla liczb całkowitych i %f dla liczb
zmiennoprzecinkowych. Jeżeli format nie zostanie podany, wszystkie dane
zostaną sformatowane jako ciąg tekstowy. W większości przypadków MySQL
będzie poprawnie rzutować ciąg tekstowy na format niezbędny do
przechowywania w nim informacji w rzeczywistej tabeli.

Aby w taki sposób powiązać ze sobą dwa posty, konieczne jest również
umieszczenie assignment_id w kolumnie post_parent tabeli wp_posts. Jest
to odpowiednikiem utworzenia relacji nadrzędny – potomny. Jeżeli jednak
potrzebna jest relacja typu „wiele do wielu” (np. to samo zapytanie
można zastosować dla wielu operacji przypisania), należy przygotować
oddzielną tabelę lub inny sposób na połączenie posta z wieloma innymi
postami.

Wywołanie $wpdb->replace($table, $data, $format) jest podobne do metody
$wpdb->insert(). Metoda $wpdb->replace() spowoduje wygenerowanie
dosłownie takiego samego zapytania SQL jak $wpdb->insert(), ale
wykorzystującego klauzulę SQL REPLACE zamiast INSERT. To spowoduje
nadpisanie wszelkich rekordów o takich samych kluczach jak przekazane za
pomocą $data.

Istnieje możliwość użycia wywołania
$wpdb->update($table, $data, $where, $format = null, $where_format =
null) do uaktualnienia rekordów w tabeli bazy danych. Zamiast tworzyć
własne zapytanie UPDATE wystarczy przekazać tabelę i tablicę asocjacyjną
zawierającą uaktualnione kolumny i nowe dane, a także tablicę
asocjacyjną $where zawierającą kolumny sprawdzane za pomocą klauzuli
WHERE. Na podstawie tych danych WordPress przygotuje zapytanie i
odpowiednio zastosuje znaki cytowania w poleceniu UPDATE.

Parametry $where i $where_format działają w sposób analogiczny do tablic
odpowiednio $data i $format.

Klauzula WHERE wygenerowana przez metodę update() sprawdzi, czy kolumny
są odpowiednikami przekazanych wartości, a te operacje sprawdzenia są
połączone razem za pomocą warunku AND.

Metoda update() okazuje się szczególnie użyteczna pod tym względem, że
pozwala uaktualnić dowolną liczbę kolumn w rekordzie tabeli za pomocą
tej samej funkcji. Spójrz na fragment kodu, który można wykorzystać do
uaktualnienia zamówień we wtyczce e-commerce:

    <?php

    global $wpdb;

    // Uaktualnienie informacji o stanie

    $wpdb->update(

      'ecommerce_orders',   // Nazwa tabeli

      array( 'status' => 'paid' ),  // Kolumny danych

      array( 'id' => $order_id )  // Kolumny where

    );

    // Uaktualnienie danych dotyczących zamówienia

    $wpdb->update(

      'ecommerce_orders',   // Nazwa tabeli

      array( 'status' => 'pending',  // Kolumny danych

        'subtotal' => '100.00',

        'tax' => '6.00',

        'total' => '106.00'

      ),

      array( 'id' => $order_id )  // Kolumny where

    );

    ?>

$wp_query

Obiekt klasy WP_Query, który może wyświetlić całą treść posta zwróconego
dla WordPressa dla danej strony. Więcej informacji na temat klasy
WP_Query i jej metod znajdziesz w następnym rozdziale.

$current_user

Obiekt wszystkich danych powiązanych z aktualnie zalogowanym
użytkownikiem. Ten obiekt nie tylko zwraca wszystkie pochodzące z tabeli
wp_users dane dla bieżącego użytkownika, ale jednocześnie zapewnia
obsługę ról i możliwości dla bieżącego użytkownika.

    <?php

    // Powitanie zalogowanego użytkownika

    global $current_user;

    if ( !empty( $current_user->ID ) ) {

      echo 'Cześć, ' . $current_user->display_name;

    }

    ?>

Podczas tworzenia kodu przeznaczonego do uruchomienia przez WordPress
można zdefiniować i stosować własne zmienne globalne, o ile ma to sens.
Dzięki temu można zaoszczędzić sobie trochę wysiłku związanego z
ponownym utworzeniem kodu i zamiast tego po prostu wywoływać funkcje,
ponieważ są one już zdefiniowane i można je wykorzystać wielokrotnie.

Wtyczki bezpłatne

Istnieje wiele użytecznych wtyczek bezpłatnych, które pomagają w
rozszerzeniu aplikacji internetowej. Wprawdzie dostępne są wtyczki dla
praktycznie każdego celu, ale jeśli nie znajdujesz potrzebnej
funkcjonalności, zawsze możesz zmodyfikować istniejącą wtyczkę (to w
końcu oprogramowanie typu open source, pamiętasz?) lub utworzyć nową
zupełnie od początku, o ile jesteś gotowy na takie wyzwanie.

Admin Columns

Admin Columns (https://wordpress.org/plugins/codepress-admin-columns/)
to bardzo użyteczna wtyczka i jedna z naszych ulubionych, przeznaczona
do zarządzania kolumnami wyświetlanymi w postach WordPressa,
użytkownikami, komentarzami, plikami multimedialnymi i wszelkimi
zarejestrowanymi niestandardowymi typami postów na stronach
administracyjnych. Ta wtyczka obsługuje również dodawanie
niestandardowych kolumn, obrazków i taksonomii dla kolumn
administracyjnych. Do niezwykle użytecznych funkcji tej wtyczki
zaliczamy też możliwość dodawania sortowanych kolumn i edytowanych
kolumn oraz eksportowania plików w formacie CSV zawierających wskazane
kolumny. Wersja pro tej wtyczki zapewnia integrację z innymi wtyczkami
(m.in. Advanced Custom Fields, WooCommerce i Yoast SEO), a także pozwala
dodawać do kolumn administracyjnych metakolumny z wymienionych wtyczek.
Jedną z naszych ulubionych funkcji tej wtyczki jest możliwość grupowej
edycji wartości SEO dla wszystkich postów na stronie zamiast tylko dla
pojedynczego posta — potraktuj to jako ogromną oszczędność czasu.

Advanced Custom Fields

Advanced Custom Fields (https://www.advancedcustomfields.com/) umożliwia
administratorom łatwe definiowanie dostępnych kolumn niestandardowych
dla dowolnych typów postów. Oferuje elegancki administracyjny interfejs
użytkownika dla kolumn i typów kolumn dostępnych dla danego rodzaju
posta. Użytkownicy backendu mogą współpracować z kolumnami i
jednocześnie dodawać lub uaktualniać post. Wtyczka jest przeznaczona dla
programistów, ma wbudowanych wiele niestandardowych zaczepów i filtrów,
jak również funkcji niestandardowych, które pozwalają na łatwe
wyświetlanie danych we frontendzie. Wtyczka ACF ma także wiele dodatków,
m.in.:

Repeater field

Pozwala utworzyć zbiór podkolumn, z których każda może być wielokrotnie
powtarzana. Jest to sposób na dodawanie listy wartości.

Gallery field

Zapewnia elegancki interfejs użytkownika przeznaczony do zarządzania
wieloma obrazkami.

Options page

Oferuje funkcje pozwalające dodawać strony administracyjne w celu
uaktualniania kolumn ACF.

Flexible content field

Tworzy niestandardowe układy z interfejsem użytkownika opartym na
treści.

BadgeOS

Wtyczka BadgeOS (https://wordpress.org/plugins/badgeos/) potrafi
skonwertować każdą witrynę internetową na platformę nagradzania
użytkowników na podstawie ich aktywności. Administrator witryny może
wykorzystać tę wtyczkę do tworzenia różnych typów osiągnięć i nagród
przydzielanych użytkownikom po spełnieniu przez nich wszystkich wymagań
dla danego poziomu. Plakietki są zgodne ze standardem Open Badges
Infrastructure (OBI) firmy Mozilla i można je współdzielić za pomocą
serwisu Credly (https://info.credly.com/).

Inną świetną wtyczką dla WordPressa przeznaczoną do gamifikacji jest
GamiPress (https://gamipress. com/), która powstała na podstawie kodu
źródłowego wtyczki BadgeOS. Według nas jest lepiej obsługiwana i oferuje
więcej funkcji.

Posts 2 Posts

Posts 2 Posts (https://wordpress.org/plugins/posts-to-posts/) to kolejna
doskonała wtyczka przeznaczona do tworzenia aplikacji internetowych.
Można za jej pomocą zdefiniować relacje typu „wiele do wielu” między
postami, stronami i niestandardowymi typami postów, jak również
zdefiniować relacje typu „wiele do wielu” między postami i
użytkownikami.

Przykładowo P2P umożliwia zdefiniowanie połączenia między
niestandardowymi typami postów dla szkół, nauczycieli i przedmiotów. W
szkole może być zatrudnionych wielu nauczycieli, a każdy z nich może
prowadzić zajęcia z jednego lub kilku przedmiotów.

P2P dostarcza intuicyjne ustawienia, widżety zawierające wiele opcji
oraz łatwy w użyciu oraz dołączony do strony dodawania i edytowania
posta komponent meta box pozwalający definiować nowe połączenia.

W większości przypadków twórcy wtyczek niestandardowych powinni unikać
tworzenia dodatkowych tabel baz danych, o ile to nie jest absolutnie
konieczne. Jeżeli chcesz połączyć post z innymi, w niestandardowej
kolumnie innego posta możesz przechowywać tablicę identyfikatorów
postów, choć w ogromnej aplikacji będzie to nieefektywnym rozwiązaniem.
Wtyczka P2P pozwala tworzyć niestandardowe tabele bazy danych, wp_p2p i
wp_p2pmeta, przeznaczone do znacznie efektywniejszego przechowywania
relacji między postami (spójrz na tabele odpowiednio 3.1 i 3.2).

Tabela 3.1. Schemat bazy danych dla tabeli wp_p2p

  ---------- ------------- ------------------ --------------- ------------------ ----------------------
  Kolumna    Typ           Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  p2p_id     bigint(20)                       Nie             Brak               AUTO_INCREMENT
  p2p_from   bigint(20)                       Nie             Brak               
  p2p_to     bigint(20)                       Nie             Brak               
  p2p_type   varchar(44)   utf8_general_ci    Nie                                
  ---------- ------------- ------------------ --------------- ------------------ ----------------------

Więcej informacji na temat tej wtyczki znajdziesz na stronie wiki w
serwisie GitHub pod adresem
https://github.com/scribu/wp-posts-to-posts/wiki.

Tabela 3.2. Schemat bazy danych dla tablicy wp_p2pmeta

  ------------ -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna      Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  meta_id      bigint(20                         Nie             Brak               AUTO_INCREMENT
  p2p_id       bigint(20)                        Nie             0                  
  meta_key     varchar(255)   utf8_general_ci    Tak             NULL               
  meta_value   longtext       utf8_general_ci    Tak             NULL               
  ------------ -------------- ------------------ --------------- ------------------ ----------------------

Members

Wtyczka Members (https://wordpress.org/plugins/members/) rozszerza
kontrolę, którą masz nad rolami i możliwościami w witrynie internetowej.
Pozwala edytować, a także tworzyć i usuwać role i możliwości
użytkownika. Ta wtyczka umożliwia również zdefiniowanie zestawu
uprawnień dla różnych ról użytkowników w celu ustalenia, które z ról są
dostępne podczas dodawania, edytowania i/lub usuwania różnych fragmentów
treści. Wprawdzie informacje zamieszczone w rozdziale 6. można
wykorzystać do przygotowania własnego kodu przeznaczonego do zmiany ról
i uprawnień, ale zastosowanie wtyczki takiej jak Members może
przyśpieszyć pracę na niektórymi projektami i jest absolutnie konieczne,
jeśli osoba niebędąca programistą będzie chciała później zmienić te
reguły.

User Role Editor (https://wordpress.org/plugins/user-role-editor/) to
inna popularna wtyczka do zarządzania rolami i uprawnieniami za pomocą
graficznego interfejsu użytkownika.

W3 Total Cache

Buforowanie treści to doskonałe rozwiązanie w zakresie optymalizacji
wydajności działania witryny internetowej. Można zaoszczędzić wiele
czasu przetwarzania dzięki wyświetlaniu użytkownikom końcowym
buforowanych stron zamiast wykonywania zapytań do bazy danych za każdym
razem, gdy ktoś będzie żądał danych. Wtyczka W3 Total Cache
(https://wordpress.org/plugins/w3-total-cache/) oferuje wiele
wbudowanych funkcji przeznaczonych do zarządzania buforowaną treścią
i opróżnianiem bufora. Więcej informacji na temat stosowania wtyczki W3
Total Cache znajdziesz w rozdziale 14.

Yoast SEO

Yoast SEO (https://yoast.com/wordpress/plugins/seo/) to doskonała
wtyczka, gdy chcesz się zająć optymalizacją dla wyszukiwarek
internetowych (ang. search engine optimization, SEO). Po zainstalowaniu
ta wtyczka automatycznie optymalizuje witrynę internetową pod kątem
wyszukiwarek internetowych. Dodaje również podgląd fragmentu
pokazującego przykładowe wyniki wyszukiwarki internetowej wraz z
nadpisanymi polami tytułu i opisu. Inną użyteczną funkcją wtyczki Yoast
SEO jest raport „analizy czytelności” zawierający wskazówki pomocne w
tworzeniu bardziej zrozumiałej treści.

Dostępna jest również płatna wersja Yoast SEO wraz z funkcjami
zaawansowanymi i pomocą techniczną klasy premium.

Kolejną popularną wtyczką związaną z SEO jest All in One SEO Pack
(https://wordpress.org/plugins/ all-in-one-seo-pack/).

Wtyczki premium

Wprawdzie istnieje wiele świetnych wtyczek dostępnych bezpłatnie, ale
wtyczki premium są warte zakupu. Tego rodzaju wtyczki zwykle wymagają
jednorazowej inwestycji i oferują licencje programistyczne, które
pozwalają dokonać zakupu umożliwiającego instalację wtyczki w wielu
witrynach internetowych WordPressa.

Gravity Forms

Wtyczka Gravity Forms (https://www.gravityforms.com/) zalicza się do
absolutnie niezbędnych i pozwala łatwo tworzyć niestandardowe formularze
kontaktowe w witrynie internetowej. Proces tworzenia formularza jest
bardzo prosty i odbywa się za pomocą edytora graficznego, który
umożliwia przeciąganie i upuszczanie pól na formularzu oraz zmianę ich
położenia wedle potrzeb. Dołączone są pola standardowe, istnieje również
możliwość tworzenia własnych pól. Formularze są niezwykle elastyczne i
mogą być definiowane w postaci wielostronicowych formularzy z paskami
postępu. Pola warunkowe pozwalają wyświetlać lub ukrywać pola na
podstawie wyboru dokonanego we wcześniejszych polach. Kolejną doskonałą
cechą tej wtyczki jest możliwość przekazania ukończonego formularza w
dowolne miejsce, wybrane w ustawieniach formularza w witrynie
administracyjnej. Ta wtyczka jest elastyczna i użyteczna dla każdego,
kto musi zajmować się tworzeniem formularzy na stronie, a praca z nią
jest łatwa nawet dla osoby, która nie ma doświadczenia w tworzeniu kodu
źródłowego.

BackupBuddy

Wtyczka BackupBuddy (https://ithemes.com/backupbuddy/) umożliwia
utworzenie kopii zapasowej całej instalacji WordPressa w celu
bezpiecznego przechowywania, przywrócenia lub przeniesienia witryny
internetowej. Kopia zapasowa może być tworzona na podstawie
zdefiniowanego harmonogramu, a powstałe archiwum można pobrać do
komputera, przesłać e-mailem lub umieścić w wybranym miejscu, takim jak
Dropbox lub serwer FTP. Wtyczka oferuje również opcję przywracania
pozwalającą łatwo przywracać motywy, widżety i wtyczki. Dzięki tej
wtyczce witrynę internetową można łatwo przenieść do nowego serwera lub
domeny bezpośrednio za pomocą panelu WordPressa. To bardzo użyteczne
rozwiązanie podczas pracy w serwerze programistycznym, a następnie
przenoszenia gotowej witryny do środowiska produkcyjnego.

WP All Import

Wtyczka WP All Import (https://www.wpallimport.com/) okazuje się
przydatna, gdy dane pochodzące z innego źródła chcesz zaimportować do
WordPressa w postaci pliku XML bądź CSV, które są formatami
nieobsługiwanymi przez WordPressa. Istnieje możliwość zakupu jej wersji
Pro, która rozszerza funkcjonalność o import danych do niestandardowych
typów postów, a nawet do niestandardowych pól. Wersja Pro pozwala także
importować obrazy z podanych adresów URL, a następnie zapisywać je w
bibliotece plików multimedialnych. Za przydatną należy uznać też
możliwość zdefiniowania okresowych operacji importu, które w pewnych
odstępach czasu będą sprawdzały pod kątem zmienionych plików, a
następnie odpowiednio modyfikowały posty.

Wtyczki społecznościowe

Korzystając z kilku dostępnych bezpłatnie wtyczek, za pomocą WordPressa
można przygotować pełną witrynę społecznościową. Sieci społecznościowe
umożliwiają komunikowanie się członkom mniejszych społeczności. Jeżeli
masz aktywną sieć społecznościową, silniki wyszukiwarek internetowych
prawdopodobnie zindeksowały już wiele treści należącej do tej sieci.
Jeśli uważasz, że możesz zyskać wiele komentarzy i opinii dotyczących
istniejącej witryny internetowej WordPressa, spróbuj przekształcić ją w
sieć społecznościową, aby w ten sposób umożliwić prowadzenie
konwersacji.

BuddyPress

BuddyPress (https://buddypress.org/) to sieć społecznościowa w pudełku.
W ciągu zaledwie kilku minut możesz przygotować sieć społecznościową
oferującą większość tych samych funkcji, które znajdziesz np. w serwisie
Facebook.

Wtyczkę BuddyPress można pobrać z repozytorium wtyczek, czyli podobnie
jak inne wtyczki, albo z witryny BuddyPress. Ta wtyczka uległa poważnym
zmianom od chwili jej wydania w kwietniu 2009 roku. Jej autorem jest
Andy Peatling, a sama wtyczka pierwotnie działała dzięki WordPress MU
(Multi User). Firma Automattic dostrzegła drzemiący w niej potencjał i
zaczęła finansować projekt, co pozwoliło zmienić tę wtyczkę w aplikację
sieci społecznościowej.

Począwszy od wydania 1.7, wtyczka BuddyPress pozostaje niezależna od
motywu, co oznacza, że jeśli zostanie użyta prawidłowo, będzie działała
z dowolnym motywem — a raczej z większością motywów. Przed wydaniem
wersji 1.7, aby można było prawidłowo korzystać z wtyczki, konieczne
było użycie motywu BuddyPress. Takie rozwiązanie sprawdzało się w
przypadku użytkowników, którzy chcieli utworzyć sieć społecznościową
zupełnie od podstaw, ponieważ wtedy mogli wykorzystać dołączony motyw
domyślny, zakupić elegancki motyw potomny premium BuddyPress lub
zaplanować i przygotować własny motyw potomny BuddyPress. Jednak wtyczka
była ograniczeniem dla użytkowników już posiadających witrynę
WordPressa, nie mogli oni bowiem po prostu włączyć wtyczki BuddyPress i
uruchomić jej w istniejącym motywie. W większości przypadków osoba
posiadająca istniejącą witrynę internetową, jeśli chciała skorzystać z
BuddyPress, musiała samodzielnie dostosować wtyczkę — nie stanowiło to
problemu dla użytkowników, którzy mieli doświadczenie w pracy z CSS, PHP
i WordPressem, pozostali natomiast musieli zatrudniać programistów w
celu modyfikacji istniejącego motywu (za który wcześniej mogli już
zapłacić) do postaci motywu potomnego BuddyPress lub przynajmniej z nim
zgodnego. Na szczęście w nowych wersjach wtyczki BuddyPress (zobacz
rysunek 3.2) nie ma już takiej konieczności.

[]

Rysunek 3.2. Witamy we wtyczce BuddyPress

Obecnie jeśli użytkownik ma istniejącą witrynę internetową, może w
istniejącym motywie używać wtyczki BuddyPress i jej wszystkich funkcji.
Bardzo łatwo można nadpisywać istniejące style i dostosować
funkcjonalność BuddyPress do własnej witryny internetowej. Specjalne
podziękowania należą się programistom (John Jacoby, Boone Gorges, Paul
Gibbs i Ray „todo:” Ho) za przygotowanie wtyczki BuddyPress w jej
obecnej postaci — niezależnej od motywu wtyczki, która pozwala zmienić
WordPressa w sieć społecznościową.

Tabele bazy danych

W przeciwieństwie do wielu innych wtyczek WordPressa BuddyPress tworzy
własne tabele bazy danych w MySQL. Gdyby pierwsi twórcy wtyczki
BuddyPress zajęli się teraz jej tworzeniem zupełnie od początku,
prawdopodobnie skorzystaliby z CPT zamiast używać niestandardowych
tabel. Jednak funkcjonalność CPT nie była zaimplementowana w momencie
powstawania wtyczki BuddyPress, a zmiana jej architektury teraz
wymagałaby ogromnego wysiłku. Tabele niestandardowe są używane do
przechowywania informacji o grupach i powiązaniach między użytkownikami,
a te tabele są łatwiejsze do zrozumienia i umożliwiają szybsze
wykonywanie zapytań niż w przypadku informacji przechowywanych w
połączeniu postów, metadanych i taksonomii.

W przypadku małych i rozproszonych wtyczek unikanie tabel
niestandardowych jest sensownym podejściem, ponieważ oznacza mniej
zmartwień dla użytkowników danych wtyczek. Natomiast w przypadku wtyczki
zawierającej funkcjonalność podobną do oferowanej przez BuddyPress
tabele niestandardowe mogą przyśpieszyć lub umożliwić lepszy sposób
organizacji danych. W tabelach od 3.3 do 3.18 przedstawiliśmy schematy
wszystkich tabel MySQL używanych przez BuddyPress. Dzięki temu możesz
zobaczyć przykłady strukturyzacji tabel niestandardowych we własnych
aplikacjach, a także zrozumieć, jak wtyczka BuddyPress przechowuje dane
— na wypadek, gdybyś chciał bezpośrednio wykonywać zapytania w celu
pobierania informacji znajdujących się w tych tabelach.

Tabela 3.3. Schemat bazy danych dla tabeli wp_bp_activity

  ------------------- -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna             Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id                  bigint(20)                        Nie             Brak               AUTO_INCREMENT
  user_id             bigint(20)                        Nie             Brak               
  component           varchar(75)    utf8_general_ci    Nie             Brak               
  type                varchar(75)    utf8_general_ci    Nie             Brak               
  action              text           utf8_general_ci    Nie             Brak               
  content             longtext       utf8_general_ci    Nie             Brak               
  primary_link        varchar(255)   utf8_general_ci    Nie             Brak               
  item_id             bigint(20)                        Nie             Brak               
  secondary_item_id   bigint(20)                        Tak             NULL               
  date_recorded       datetime                          Nie             Brak               
  hide_sitewide       tinyint(1)                        Tak             0                  
  mptt_left           int(11)                           Nie             0                  
  mptt_right          int(11)                           Nie             0                  
  is_spam             tinyint(1)                        Nie             0                  
  ------------------- -------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.4. Schemat bazy danych dla tabeli wp_bp_activity_meta

  ------------- -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna       Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id            bigint(20)                        Nie             Brak               AUTO_INCREMENT
  activity_id   bigint(20)                        Nie             Brak               
  meta_key      varchar(255)   utf8_general_ci    Tak             NULL               
  meta_value    longtext       utf8_general_ci    Tak             NULL               
  ------------- -------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.5. Schemat bazy danych dla tabeli wp_bp_friends

  ------------------- ------------ ------------------ --------------- ------------------ ----------------------
  Kolumna             Typ          Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id                  bigint(20)                      Nie             Brak               AUTO_INCREMENT
  initiator_user_id   bigint(20)                      Nie             Brak               
  friend_user_id      bigint(20)                      Nie             Brak               
  is_confirmed        tinyint(1)                      Tak             0                  
  is_limited          tinyint(1)                      Tak             0                  
  date_created        datetime                        Nie             Brak               
  ------------------- ------------ ------------------ --------------- ------------------ ----------------------

Tabela 3.6. Schemat bazy danych dla tabeli wp_bp_groups

  -------------- -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna        Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id             bigint(20)                        Nie             Brak               AUTO_INCREMENT
  creator_id     bigint(20)                        Nie             Brak               
  name           varchar(100)   utf8_general_ci    Nie             Brak               
  sług           varchar(200)   utf8_general_ci    Nie             Brak               
  description    longtext       utf8_general_ci    Nie             Brak               
  status         varchar(100)   utf8_general_ci    Nie             public             
  enable_forum   tinyint(1)                        Nie             1                  
  date_created   datetime                          Nie             Brak               
  -------------- -------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.7. Schemat bazy danych dla tabeli wp_bp_groups_groupmeta

  ------------ -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna      Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id           bigint(20)                        Nie             Brak               AUTO_INCREMENT
  group_id     bigint(20)                        Nie             Brak               
  meta_key     varchar(255)   utf8_general_ci    Tak             NULL               
  meta_value   longtext       utf8_general_ci    Tak             NULL               
  ------------ -------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.8. Schemat bazy danych dla tabeli wp_bp_groups_members

  --------------- -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna         Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id              bigint(20)                        Nie             Brak               AUTO_INCREMENT
  group_id        bigint(20)                        Nie             Brak               
  user_id         bigint(20)                        Nie             Brak               
  inviter_id      bigint(20)                        Nie             Brak               
  is_admin        tinyint(1)                        Nie             0                  
  is_mod          tinyint(1)                        Nie             0                  
  user_title      varchar(100)   utf8_general_ci    Nie             Brak               
  date_modified   datetime                          Nie             Brak               
  comments        longtext       utf8_general_ci    Nie             Brak               
  is_confirmed    tinyint(1)                        Nie             0                  
  is_banned       tinyint(1)                        Nie             0                  
  invite_sent     tinyint(1)                        Nie             0                  
  --------------- -------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.9. Schemat bazy danych dla tabeli wp_bp_messages_messages

  ----------- -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna     Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id          bigint(20)                        Nie             Brak               AUTO_INCREMENT
  thread_id   bigint(20)                        Nie             Brak               
  sender_id   bigint(20)                        Nie             Brak               
  subject     varchar(200)   utf8_general_ci    Nie             Brak               
  message     longtext       utf8_general_ci    Nie             Brak               
  date_sent   datetime                          Nie             Brak               
  ----------- -------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.10. Schemat bazy danych dla tabeli wp_bp_messages_notices

  ----------- -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna     Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id          bigint(20)                        Nie             Brak               AUTO_INCREMENT
  subject     varchar(200)   utf8_general_ci    Nie             Brak               
  message     longtext       utf8_general_ci    Nie             Brak               
  date_sent   datetime                          Nie             Brak               
  is_active   tinyint(1)                        Nie             0                  
  ----------- -------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.11. Schemat bazy danych dla tabeli wp_bp_messages_recipients

  -------------- ------------ ------------------ --------------- ------------------ ----------------------
  Kolumna        Typ          Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id             bigint(20)                      Nie             Brak               AUTO_INCREMENT
  user_id        bigint(20)                      Nie             Brak               
  thread_id      bigint(20)                      Nie             Brak               
  unread_count   int(10)                         Nie             0                  
  sender_only    tinyint(1)                      Nie             0                  
  is_deleted     tinyint(1)                      Nie             0                  
  -------------- ------------ ------------------ --------------- ------------------ ----------------------

Tabela 3.12. Schemat bazy danych dla tabeli wp_bp_notifications

  ------------------- ------------- ------------------ --------------- ------------------ ----------------------
  Kolumna             Typ           Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id                  bigint(20)                       Nie             Brak               AUTO_INCREMENT
  user_id             bigint(20)                       Nie             Brak               
  item_id             bigint(20)                       Nie             Brak               
  secondary_item_id   bigint(20)                       Tak             NULL               
  component_name      varchar(75)   utf8_general_ci    Nie             Brak               
  component_action    varchar(75)   utf8_general_ci    Nie             Brak               
  date_notified       datetime                         Nie             Brak               
  is_new              tinyint(1)                       Nie             0                  
  ------------------- ------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.13. Schemat bazy danych dla tablicy wp_bp_user_blogs

  --------- ------------- ------------------ --------------- ------------------ ----------------------
  Kolumna   Typ           Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id        bigint(20)                       Nie             Brak               AUTO_INCREMENT
  user_id   bigint(20)                       Nie             Brak               
  blog_id   vbigint(20)                      Nie             Brak               
  --------- ------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.14. Schemat bazy danych dla tabeli wp_bp_user_blogs_blogmeta

  ------------ -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna      Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id           bigint(20)                        Nie             Brak               AUTO_INCREMENT
  blog_id      bigint(20)                        Nie             Brak               
  meta_key     varchar(255)   utf8_general_ci    Tak             NULL               
  meta_value   longtext       utf8_general_ci    Tak             NULL               
  ------------ -------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.15. Schemat bazy danych dla tabeli wp_bp_xprofile_data

  -------------- ------------ ------------------ --------------- ------------------ ----------------------
  Kolumna        Typ          Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id             bigint(20)                      Nie             Brak               AUTO_INCREMENT
  field_id       bigint(20)                      Nie             Brak               
  user_id        bigint(20)                      Nie             Brak               
  value          longtext     utf8_general_ci    Nie             Brak               
  last_updated   datetime                        Nie             Brak               
  -------------- ------------ ------------------ --------------- ------------------ ----------------------

Tabela 3.16. Schemat bazy danych dla tabeli wp_bp_xprofile_fields

  ------------------- -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna             Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id                  bigint(20)                        Nie             Brak               AUTO_INCREMENT
  group_id            bigint(20)                        Nie             Brak               
  parent_id           bigint(20)                        Nie             Brak               
  type                varchar(150)   utf8_general_ci    Nie             Brak               
  name                varchar(150)   utf8_general_ci    Nie             Brak               
  description         longtext       utf8_general_ci    Nie             Brak               
  is_required         tinyint(1)                        Nie             0                  
  is_default_option   tinyint(1)                        Nie             0                  
  field_order         bigint(20)                        Nie             0                  
  option_order        bigint(20)                        Nie             0                  
  order_by            varchar(15)    utf8_general_ci    Nie                                
  can_delete          tinyint(1)                        Nie             1                  
  ------------------- -------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.17. Schemat bazy danych dla tabeli wp_bp_xprofile_group

  ------------- -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna       Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id            bigint(20)                        Nie             Brak               AUTO_INCREMENT
  name          varchar(150)   utf8_general_ci    Nie             Brak               
  description   mediumtext     utf8_general_ci    Nie             Brak               
  group_order   bigint(20)                        Nie             0                  
  can_delete    tinyint(1)                        Nie             Brak               
  ------------- -------------- ------------------ --------------- ------------------ ----------------------

Tabela 3.18. Schemat bazy danych dla tabeli wp_bp_xprofile_meta

  ------------- -------------- ------------------ --------------- ------------------ ----------------------
  Kolumna       Typ            Kodowanie znaków   Wartość null?   Wartość domyślna   Informacje dodatkowe
  id            bigint(20)                        Nie             Brak               AUTO_INCREMENT
  object_id     bigint(20)                        Nie             Brak               
  object_type   varchar(150)   utf8_general_ci    Nie             Brak               
  meta_key      varchar(255)   utf8_general_ci    Tak             NULL               
  meta_value    longtext       utf8_general_ci    Tak             NULL               
  ------------- -------------- ------------------ --------------- ------------------ ----------------------

Panel Komponenty

Po aktywacji wtyczki BuddyPress należy przejść do panelu Komponenty
(Components) (zobacz rysunek 3.3) w sekcji Ustawienia/BuddyPress
(Settings/BuddyPress) lub pod adres
/wp-admin/options-general.php?page=bp-components, aby skonfigurować
komponenty w żądany sposób.

Dostępne są następujące komponenty:

Profile rozszerzone (Extended Profiles)

Podobnie jak typowa sieć społecznościowa także BuddyPress oferuje
obsługę profili użytkowników. Członek społeczności ma pełną kontrolę nad
swoim profilem. Standardowo profile wszystkich członków sieci są
dostępne w katalogu, a kliknięcie nazwy użytkownika spowoduje przejście
na stronę profilu danej osoby.

Ustawienia konta (Account Settings)

Użytkownicy sieci mogą uaktualniać adres e-mail i hasło oraz zarządzać
powiadomieniami, które otrzymują podczas komunikacji z innymi
użytkownikami serwisu.

Nawiązane znajomości (Friend Connections)

Użytkownik może dodawać znajomych. W tym celu wysyła do innego
użytkownika sieci zaproszenie lub otrzymuje je od innej osoby. Ten
system przypomina system znajomych w serwisie Facebook.

[]

Rysunek 3.3. Panel Komponenty (Components) wtyczki BuddyPress

Prywatne wiadomości (Private Messaging)

Użytkownicy mogą wysyłać prywatne wiadomości do innych użytkowników, a
także wyświetlać otrzymane wiadomości — wszystko to odbywa się w jednym
miejscu. Ponadto członek społeczności może odpowiadać na wiadomość,
oznaczać ją jako przeczytaną, usuwać wiadomość oraz przeprowadzać wiele
innych operacji na wiadomościach, podobnie jak w każdym innym ogromnym
serwisie społecznościowym.

Strumienie aktywności (Activity Streams)

Członkowie społeczności mogą publikować aktualizacje w swoich profilach,
pozostawiać komentarze dotyczące działalności innych użytkowników lub
grup społeczności, a także oznaczać posty jako ulubione. To przypomina
serwis Facebook, prawda? BuddyPress ma funkcjonalność typu @wzmianka,
podobną do tej, gdy ktoś w serwisie Twitter wspomina o innym
użytkowniku. Ta funkcjonalność powoduje automatyczne dodanie łącza
prowadzącego na stronę profilu wspomnianej osoby. Jeżeli dany użytkownik
ma wyłączone powiadomienia, otrzyma wiadomość e-mail informującą o
wzmiance o nim. Informacje o działaniach użytkownika są przekazywane
także za pomocą kanału RSS.

Grupy użytkownika (User Groups)

Jest to komponent o potężnych możliwościach. Grupa może być utworzona
przez członków społeczności. Wszystkie grupy zostają wyświetlone w
katalogu grup, a kliknięcie awatara grupy powoduje przejście na jej
stronę. Utworzenie profilu grupy odbywa się podobnie jak w przypadku
strony profilu użytkownika, choć dostępne są charakterystyczne dla grupy
podstrony, takie jak aktywność grupy, członkowie grupy, ustawienia
administracyjne i strona umożliwiająca zapraszanie przyjaciół. Grupa
może być publiczna, prywatna lub ukryta, a członkowie grupy mogą być
promowani do administratorów lub moderatorów grupy.

Śledzenie strony (Site Tracking)

Nowe posty i komentarze w witrynie internetowej tworzą posty aktywności
BuddyPress. Jeżeli uruchomiłeś BuddyPress w sieci zawierającej wiele
witryn internetowych WordPressa, to posty i komentarze utworzone w
dowolnej z tych witryn sieci również będą uznawane za posty aktywności
BuddyPress.

Wszystkie podstawowe komponenty BuddyPressa mogą być rozszerzane za
pomocą wtyczek BuddyPressa. Jeżeli dopiero zaczynasz pracę z WordPressem
i BuddyPressem, wszystko to może być nieco niezrozumiałe, ale masz
możliwość zainstalowania wtyczek dodatkowych do BuddyPressa albo
utworzenia własnych. Istnieje około 500 wtyczek rozszerzających
możliwości BuddyPressa lub integrujących się w taki bądź inny sposób z
BuddyPressem.

Panel Strony

Gdy już wybierzesz podstawowe komponenty BuddyPressa do użycia, przejdź
do panelu Strony (Pages) dostępnego w sekcji
Ustawienia/BuddyPress/Strony (Settings/BuddyPress/Pages) (zobacz rysunek
3.4). BuddyPress mapuje używane komponenty na nowe lub istniejące
strony. Domyślnie próbuje utworzyć nową stronę dla każdego komponentu.
Jeżeli każdego członka sieci chcesz określać mianem Student zamiast
Użytkownik, możesz utworzyć zwykłą stronę WordPressa o nazwie Student
i mapować komponent Członkowie (Members) na tę nową stronę. To samo
dotyczy pozostałych komponentów BuddyPressa. Proces rejestracji
użytkownika sieci wymaga dwóch stron: rejestracji i aktywacji. Konieczne
jest zdefiniowanie mapowania dla obu tych strony, jeśli ma być
zapewniona otwarta możliwość rejestracji użytkowników w tworzonym
serwisie społecznościowym.

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Aby zapewnić otwartą możliwość rejestracji, trzeba upewnić się, że każda osoba będzie mogła się zarejestrować. Wymaga to zaznaczenia pola wyboru Każdy może się zarejestrować (Anyone can register) w sekcji Ustawienia/Ogólne (Settings/General).
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Panel Opcje

Panel Opcje (Options) w sekcji Ustawienia/BuddyPress/Options
(Settings/BuddyPress/Opcje) lub po adresem
/wp-admin/admin.php?page=bp-settings pozwala skonfigurować ustawienia
dodatkowe wtyczki BuddyPress.

Pasek narzędzi (Toolbar)

Domyślnie niezalogowanym użytkownikom BuddyPress wyświetla pasek
administracyjny wraz z łączami logowania i rejestracji. W omawianej
sekcji istnieje możliwość wyłączenia tej funkcji.

[]

Rysunek 3.4. Panel Strony (Pages) wtyczki BuddyPress

Usunięcie konta (Account Deletion)

Ta sekcja pozwala określić, czy zarejestrowany użytkownik będzie miał
możliwość usunięcia konta.

Załadowane Zdjęcia profilowe (Avatar Uploads)

Zarejestrowani użytkownicy mogą dodawać awatary.

Synchronizacja profili (Profile Syncing)

Można zezwolić wtyczce BuddyPress na synchronizowanie profilu
WordPressa.

Tworzenie grupy (Group Creation)

Zarejestrowanym użytkownikom można zezwolić na tworzenie własnych grup.
Jeżeli ta funkcja będzie wyłączona, grupy będą mogły być tworzone przez
administratorów witryny.

Post Comments

W tej sekcji można zezwolić na komentowanie strumienia aktywności w
postach blogów i forach.

Sekcja Pola profilu

Sekcja Użytkownicy/Pola profilu (Users/Profile Fields) wtyczki
BuddyPress umożliwia utworzenie dowolnej liczby grup pól profilu, a
także pól profilu dla użytkowników. To pozwoli zbierać dane, takie jak
informacje o położeniu, data urodzenia, rzeczy ulubione, rzeczy
nielubiane, ulubiony kolor itd. Jest to niezwykle elastyczna funkcja,
umożliwiająca organizowanie pól profilu w różne grupy profilu, które
następnie będą się znajdowały na stronie głównej profilu każdego
użytkownika.

Podczas dodawania nowych pól profilu masz do dyspozycji elegancki
interfejs użytkownika pozwalający określić, czy dane pole jest wymagane,
jakiego typu element formularza powinien zostać użyty do wyświetlenia
pola, jaka jest domyślna widoczność pola oraz czy użytkownicy mogą
zmieniać widoczność tego pola. Formularz pokazaliśmy na rysunku 3.5.

[]

Rysunek 3.5. Sekcja Pola profilu wtyczki BuddyPress

  ---- ------------------------------------------------------------------------------------------------------
  []   Domyślnie wszystkie pola profilu w grupie Podstawowe (Base) będą wyświetlone na stronie rejestracji.
  ---- ------------------------------------------------------------------------------------------------------

Wtyczki BuddyPressa

BuddyPress to intuicyjna i łatwa w użyciu wtyczka. Wspomnieliśmy
wcześniej o możliwości zainstalowania dodatków dla BuddyPressa, więc
spójrz na krótką listę najlepszych spośród nich. Dzięki tej liście
zorientujesz się, jakie możliwości drzemią w BuddyPressie.

BuddyPress Media (https://wordpress.org/plugins/buddypress-media/)

Ta wtyczka pozwala użytkownikom serwisu umieszczać w postach zdjęcia,
muzykę i filmy. Ponadto użytkownicy będą mogli układać zdjęcia w albumy
umieszczane na stronie profilu. Wtyczka zapewnia również obsługę
urządzeń mobilnych polegającą m.in. na automatycznej konwersji treści
audio i wideo.

BuddyPress Registration Options
(https://wordpress.org/plugins/bp-registration-options/)

Jest to doskonała wtyczka uniemożliwiająca robotom rejestrowanie kont w
serwisie utworzonym za pomocą BuddyPressa. Pozwala ona moderować
tworzenie kont przez nowych użytkowników. Jeżeli moderacja jest włączona
na stronie ustawień administracyjnych, każde nowe konto użytkownika
pozostanie zablokowane i nie będzie pozwalało na interakcję z innymi
komponentami BuddyPressa (z wyjątkiem edycji profilu i przekazania
awatara) oraz nie zostanie wymienione na liście kont aż do chwili, gdy
administrator zaakceptuje dane konto. Po włączeniu moderacji
administratorzy mogą tworzyć własne komunikaty i wiadomości e-mail dla
akceptowanych i odrzucanych kont. Gdy administrator zaakceptuje lub
odrzuci konto, do użytkownika zostanie wysłany e-mail z informacją o
akceptacji lub odrzuceniu konta.

AppPresser Add-On (https://apppresser.com/introducing-appcommunity/)

Dodatek AppPresser AppComunity umożliwia użytkownikom AppPressera
tworzenie za pomocą BuddyPressa społecznościowych aplikacji mobilnych
(podobnych do aplikacji Facebooka lub Instagrama) dla witryny
WordPressa. Dzięki AppCommunity użytkownicy aplikacji zyskują m.in.
możliwość publikacji postów aktualizacyjnych i zdjęć, dodawania
znajomych, wysyłania prywatnych wiadomości, dołączania do grup.

BadgeOS Community Add-On
(https://wordpress.org/plugins/badgeos-community-add-on/)

Wtyczka BadgeOS Community Add-On pozwala na integrację funkcji BadgeOS z
BuddyPressem i bbPressem. Użytkownicy witryny zdobywają osiągnięcia i
plakietki na podstawie rangi w aktywności społeczności oraz innych
zdarzeń. Ten dodatek do BadgeOS umożliwia także wyświetlanie plakietek i
osiągnięć w profilach użytkowników i w kanałach aktywności użytkowników.

bbPress (https://bbpress.org/)

Utworzyłeś forum? bbPress spełni wszystkie związane z tym wymagania. W
przeciwieństwie do BuddyPressa bbPress wykorzystuje niestandardowe typy
postów, więc nie musi tworzyć własnych tabel w bazie danych, jak to
miało miejsce we wcześniejszych wydaniach wtyczki.

Użycie bbPressa może wymagać trochę pracy nad motywem, jeśli nie został
on jeszcze przystosowany do obsługi bbPressa. Mimo to jest to
najłatwiejszy sposób dostarczenia funkcjonalności forum w witrynie
internetowej WordPressa.

[1] W kontekście licencji GPL dystrybucja oznacza sprzedaż kodu
źródłowego lub udostępnienie go do pobrania z witryny internetowej
takiej jak repozytorium wtyczek WordPressa. Kod tworzony przez Ciebie
dla kogoś innego na jego wyłączny użytek nie musi być dostępny na
licencji GPL.

[2] Synchronizowany wpis w tabelach wp_usermeta i wp_postmeta może być
niezbędny w celu dostarczenia tej samej możliwości wyszukiwania w
pojedynczej tabeli wp_schoolpress_assignment_submissions.

Rozdział 4. Motywy

Motyw WordPressa to frontend aplikacji internetowej. W rozdziale 1.
przedstawiliśmy analogię, w której motyw WordPressa jest jak widok w
tradycyjnym frameworku MVC. Wprawdzie ta analogia nie jest doskonała,
ale motywy i widoki są podobne pod tym względem, że kontrolują wygląd
aplikacji internetowej, a na ich tworzeniu projektanci spędzają
najwięcej czasu.

Na stronie Theme Developer Handbook
(https://make.wordpress.org/docs/theme-developer-handbook/) znajdują się
zebrane przez społeczność informacje dotyczące standardowego sposobu
tworzenia motywów dla witryn internetowych WordPressa. Każdy programista
WordPressa powinien korzystać z tego zasobu. W niniejszym rozdziale
przedstawimy wybrane aspekty tworzenia motywów WordPressa, a
skoncentrujemy się na kwestiach ważnych dla programistów aplikacji.

Motyw kontra wtyczka

Na pewnym poziomie wszystkie pliki źródłowe tworzące motyw i wtyczkę to
zwykłe pliki z rozszerzeniem .php, które WordPress wczytuje w różnym
czasie. Teoretycznie cały kod aplikacji mógłby zostać umieszczony w
jednym motywie lub jednej wtyczce. W praktyce motyw pozostawiasz
zarezerwowany dla kodu związanego z frontendem (widoki) witryny
internetowej, wtyczkę natomiast — dla backendu aplikacji (modele i
kontrolery).

Miejsce umieszczenia kodu będzie zależało od tego, czy przygotowujesz w
pełni wyposażoną aplikację czy jej pojedynczą wtyczkę lub motyw.

Gdzie umieścić kod podczas tworzenia aplikacji?

Jeżeli tworzysz w pełni wyposażoną aplikację internetową (w zasadzie
jedna instalacja WordPressa), masz wówczas pełny dostęp do witryny
internetowej oraz zainstalowanych w niej motywów i wtyczek. Kod możesz
umieścić gdziekolwiek. Jednak nawet wtedy należy stosować jakiś proces,
gdy próbujesz wybrać miejsce umieszczenia kodu określonej
funkcjonalności: moduł wtyczki aplikacji, motyw lub oddzielna wtyczka.
Największą korzyść z dobrego etapu planowania odniosą programiści (być
może to będziesz Ty). Poprawna organizacja kodu ułatwia późniejszą
obsługę i rozbudowę aplikacji.

Podczas tworzenia aplikacji internetowej staraj się przestrzegać
następujących reguł:

-   Używaj wtyczki głównej do przechowywania podstawowego kodu aplikacji
    oraz motywu do zarządzania kodem frontendu.
-   Każda funkcjonalność modułowa, która mogłaby być użyteczna także w
    innych projektach lub potencjalnie zostać zastąpiona inną wtyczką,
    powinna być zdefiniowana w oddzielnej wtyczce.
-   Nigdy nie modyfikuj podstawowych plików WordPressa[1].

Czym jest więc podstawowy kod aplikacji, a czym kod frontendu?
Wspomniany już wcześniej framework pseudo-MVC przedstawia się
następująco:

Wtyczki = modele

Wszystkie zdefiniowane w kodzie struktury danych, logika biznesowa i
wywołania AJAX powinny trafić do podstawowej wtyczki. Ponadto elementy
takie jak definicje CPT i taksonomie, kod przetwarzający formularze, a
także opakowania klas Post i User również powinny trafić do wtyczki
podstawowej.

Motywy = widoki

Cały kod dotyczący szablonów i logiki frontendu powinien być
zdefiniowany w motywie. Szkielet witryny internetowej, nagłówek, stopka,
menu i paski boczne powinny być zdefiniowane w motywie. Prosta logika w
postaci if(is_user_logged_in()) { //show menu } else { //show login }
powinna znaleźć się w motywie.

Ustalając miejsce umieszczenia kodu funkcjonalności, pod uwagę trzeba
wziąć zespół programistyczny. Jeżeli jesteś projektantem i programistą,
wówczas kod dotyczący elementów przygotowywanych przez projektanta
umieść w motywie, a kod dotyczący komponentów, za które odpowiada
programista, umieść w podstawowej wtyczce. Nawet jeśli będziesz musiał
nieco pokombinować, wyraźne rozdzielenie elementów ułatwi później ich
odnajdywanie programistom.

Kiedy opracować wtyczkę?

Jeżeli tworzysz wtyczkę przeznaczoną do wykorzystania w innych witrynach
internetowych lub opracowujesz funkcjonalność modularną, która będzie
stosowana w różnych projektach, to sensowne jest umieszczenie kodu w
jednej wtyczce. W takich przypadkach pliki szablonów odpowiedzialne za
obsługę komponentów interfejsu użytkownika można przechowywać we
wtyczce. Powszechną praktyką jest umożliwienie nadpisywania tych plików
przez aktywny motyw WordPressa, co dokładniej omówimy w dalszej części
rozdziału.

Gdzie umieszczać kod podczas tworzenia motywu?

Podobnie jeśli pracujesz nad motywem, który będzie dalej rozprowadzany,
a podczas pracy opierasz się na niestandardowych typach postów lub
innych modyfikacjach wprowadzanych zwykle we wtyczce, wówczas sensowne
może być umieszczenie tego kodu w motywie. Jeżeli użytkownik musi
aktywować wtyczkę, zanim motyw zacznie działać, lepiej będzie przenieść
kod tej wtyczki do motywu. Jeśli motyw wprowadza ogromne zmiany w
WordPressie, rozważ umieszczenie kodu wtyczki w oddzielnym motywie
nadrzędnym, a kodu dotyczącego wyglądu — w motywie potomnym. Dzięki
temu, gdy użytkownik będzie chciał zmienić wygląd witryny internetowej
bez utraty funkcjonalności dostarczanej przez motyw, będzie mógł to
zrobić bardzo łatwo.

Z drugiej strony, jeśli kod dodawany do motywu nie ma znaczenia
krytycznego dla sposobu działania danego motywu lub jeśli istnieją inne
wtyczki, których można użyć jako alternatywy dla kodu, przenieś kod do
wtyczki i rozprowadzaj motyw jako paczkę zawierającą motywy i zalecane
wtyczki. Przykładowo wiele motywów klasy premium dodaje związane z SEO
pola do strony edycji postu, aby umożliwić zarządzanie tytułem strony,
opisem meta i słowami kluczowymi. To ma sens, ponieważ te związane z SEO
pola mają postać widzianą przez Google i roboty innych silników
wyszukiwarek internetowych. Istnieje jeszcze kilka dość popularnych
wtyczek oferujących tę samą funkcjonalność i trudno się nie zgodzić, że
dany motyw nie będzie działał bez funkcjonalności SEO. Twórcom motywów
zalecamy umieszczanie funkcjonalności SEO we wtyczkach lub zapewnienie
innego, łatwego sposobu na jej wyłączenie, aby można było korzystać z
innych wtyczek.

Ostatecznie decyzja dotycząca tego, gdzie umieścić kod i jak przygotować
pakiet, powinna być podejmowana na podstawie użytkowników, zarówno
końcowych, jak i programistów, którzy będą korzystali z wtyczki lub
motywu. Piękno WordPressa polega po części na jego elastyczności w
zakresie dostosowania platformy do własnych potrzeb. Nie na ściśle
ustalonych reguł. Wszystko, co przeczytasz na ten temat (także w tym
rozdziale), potraktuj jedynie jako propozycje. Jeżeli przeniesienie kodu
z pliku wtyczki do pliku motywu ułatwi pracę, zdecyduj się na takie
rozwiązanie.

Hierarchia szablonu

Gdy użytkownik odwiedza Twoją witrynę internetową i porusza się między
stronami, WordPress używa systemu określanego mianem hierarchii
szablonów do ustalenia, który plik w aktywnym motywie powinien zostać
użyty do wyświetlenia strony. Przykładowo jeśli użytkownik przechodzi na
stronę zawierającą tylko jeden post, wówczas WordPress będzie szukać
pliku o nazwie single-post.php.

Plik index.php to rozwiązanie awaryjne dla wszystkich operacji
wczytywania strony, a style.css to jedyny plik wymagany dla motywu. Z
reguły będziesz mieć listę plików podobną do tej:

-   404.php
-   author.php
-   archive.php
-   attachment.php
-   category.php
-   comments.php
-   date.php
-   footer.php
-   front-page.php
-   functions.php
-   header.php
-   home.php
-   image.php
-   index.php
-   page.php
-   search.php
-   sidebar.php
-   single.php
-   single-(post-type).php
-   style.css
-   tag.php
-   taxonomy.php

Część plików z tej listy jest wczytywanych podczas wywoływania
określonej funkcji get_*(). Na przykład funkcja get_header() wczytuje
plik header.php, get_footer() wczytuje footer.php, get_sidebar() zaś
wczytuje sidebar.php. Przekazanie parametru name do tych funkcji
spowoduje dodanie go do wczytywanego pliku. Dlatego wywołanie
get_header('alternate'); powoduje wczytanie z katalogu motywu pliku o
nazwie header-alternate.php.

Funkcja comments_template() spowoduje wczytanie pliku comments.php, o
ile nie przekażesz innej nazwy pliku w postaci pierwszego parametru
funkcji.

Funkcja get_search_form() szuka w katalogu motywu pliku o nazwie
searchform.php i jeśli go nie znajdzie, wyświetla domyślny formularz
wyszukiwania w WordPressie.

Hierarchia dokumentacji szablonów WordPressa
(https://make.wordpress.org/docs/theme-developer-handbook/) zawiera
informacje o położeniu różnych plików WordPressa w katalogu motywu
podczas jego wczytywania. Możesz również sprawdzić motyw o nazwie Twenty
Nineteen Theme
(https://github.com/WordPress/WordPress/tree/master/wp-content/themes/twentynineteen)
lub inny doskonale opracowany motyw, aby w ten sposób poznać nazwy
plików, które będzie wykrywał WordPress. Zapoznaj się z komentarzami w
tych motywach, a dowiesz się, kiedy są wczytywane poszczególne strony.

Gdy zajmujesz się tworzeniem aplikacji wykorzystującej niestandardowe
typy postów, często chcesz używać różnych szablonów podczas wyświetlania
poszczególnych typów postów we frontendzie. Istnieje możliwość
nadpisania widoków pojedynczego posta i archiwum postów, co wymaga
dodania plików o nazwach single<typ_posta>.php i archive<typ_posta>.php,
gdzie typ_posta to wartość użyta podczas rejestrowania typu posta.

Szablony strony

Jednym z najłatwiejszych sposobów pozwalających wykonać dowolny kod PHP
w witrynie internetowej WordPressa jest przygotowanie szablonu strony
dla motywu, a następnie użycie tego motywu na jednej ze stron.

Najczęściej stosowane szablony w motywach WordPressa obejmują formularze
kontaktowe i strony początkowe.

Przykładowy szablon strony

W listingu 4.1 przedstawiliśmy uproszczoną wersję szablonu formularza
kontaktowego, który można umieścić w katalogu motywu.

Listing 4.1. Szablon przykładowej strony

    <?php

    /*

    Nazwa szablonu: Strona — Formularz kontaktowy

    */

    // Pobranie wartości przekazanych za pomocą formularza

    $email = sanitize_email( $_POST['email'] );

    $cname = sanitize_text_field( $_POST['cname'] );

    $phone = sanitize_text_field( $_POST['phone'] );

    $message = sanitize_text_field( $_POST['message'] );

    $sendemail = !empty( $_POST['sendemail'] );

    // Czy formularz został wysłany?

    if ( !empty( $sendemail )

        && !empty( $cname )

            && !empty( $email )

            && empty( $lname ) ) {

            $mailto = get_bloginfo( 'admin_email' );

            $mailsubj = "Informacje z formularza kontaktowego " . get_bloginfo( 'name' );

            $mailhead = "Od: " . $cname . " <" . $email . ">\n";

            $mailbody = "Imię i nazwisko: " . $cname . "\n\n";

            $mailbody .= "E-mail: $email\n\n";

            $mailbody .= "Telefon: $phone\n\n";

            $mailbody .= "Wiadomość:\n" . $message;

            // Wysłanie wiadomości e-mail

            wp_mail( $mailto, $mailsubj, $mailbody, $mailhead );

            // Przygotowanie komunikatu dla tej strony i usunięcie wartości zmiennych

            $msg = "Wiadomość została wysłana.";

            $email = "";

            $cname = "";

            $phone = "";

            $message = "";

    }

    elseif ( !empty( $sendemail ) && !is_email( $email ) )

        $msg = "Proszę podać prawidłowy adres e-mail.";

    elseif ( !empty( $lname ) )

        $msg = "Czy jesteś spamerem?";

    elseif ( !empty( $sendemail ) && empty( $cname ) )

        $msg = "Proszę podać imię i nazwisko.";

    elseif ( !empty( $sendemail ) && !empty( $cname ) && empty( $email ) )

        $msg = "Proszę podać adres e-mail.";

    // Pobranie nagłówka

    get_header();

    ?>

    <div id="wrapper">

     <div id="content">

    <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>

      <h1><?php the_title(); ?></h1>

    <?php if ( !empty( $msg ) ) { ?>

       <div class="message"><?php echo $msg?></div>

    <?php } ?>

      <form class="general" action="<?php the_permalink(); ?>" method="post">

       <div class="form-row">

            <label for="cname">Imię</label>

            <input type="text" name="cname" value="<?php echo esc_attr($cname);?>"/>

            <small class="red">* Wymagane</small>

       </div>

       <div class="hidden">

            <label for="lname">Nazwisko</label>

            <input type="text" name="lname" value="<?php echo esc_attr($lname);?>"/>

            <small class="red">POZOSTAW TO POLE PUSTE</small>

       </div>

       <div class="form-row">

            <label for="email">E-mail</label>

            <input type="text" name="email" value="<?php echo esc_attr($email);?>"/>

            <small class="red">* Wymagane</small>

       </div>

       <div class="form-row">

            <label for="phone">Telefon</label>

            <input type="text" name="phone" value="<?php echo esc_attr($phone);?>"/>

       </div>

       <div class="form-row">

            <label for="message">Pytanie lub komentarz</label>

            <textarea class="textarea" id="message" name="message" rows="4" cols="55">

    <?php echo esc_textarea( $message )?>

            </textarea>

       </div>

       <div class="form-row">

            <label for="sendemail">&nbsp;</label>

            <input type="submit" id="sendemail" name="sendemail" value="Wyślij"/>

       </div>

      </form>

    <?php endwhile; endif; ?>

     </div>

    </div>

    <?php

    // Pobranie stopki

    get_footer();

    ?>

W poszukiwaniu szablonów WordPress sprawdzi wszystkie pliki .php w
katalogu i podkatalogach aktywnego motywu (a także w katalogu i
podkatalogach motywu nadrzędnego). Każdy znaleziony plik zawierający w
komentarzu frazę Template Name: zostanie udostępniony jako szablon.

Wczytanie szablonu następuje po wywołaniu akcji init i wp WordPressa.
Nagłówek motywu i akcja wp_head nie zostaną wczytane aż do chwili
wywołania funkcji get_header() w szablonie. Dlatego też początek pliku
szablonu można wykorzystać do przetworzenia danych wejściowych
formularza i potencjalnie przeprowadzić przekierowanie, zanim
jakiekolwiek nagłówki zostaną przekazane na stronę.

Plik szablonu musi zawierać ten sam kod znaczników HTML, który znajduje
się w pliku page.php motywu lub w szablonie strony wyświetlającej
pojedynczy post. W omawianym przykładzie zostało dostarczone opakowanie
w postaci elementu <div>, którego zawartością jest formularz kontaktowy.

W przedstawionym fragmencie kodu zostały użyte funkcje
sanitize_text_field() i sanitize_email(), odpowiedzialne za oczyszczenie
wartości przekazanych w formularzu. Podobnie funkcje esc_attr() i
esc_textarea() chronią przed atakami typu XSS. Dokładniejsze omówienie
funkcji znajdziesz w rozdziale 8.

W formularzu kontaktowym znalazł również zastosowanie „słoik miodu”.
Pole o nazwie lname pozostanie ukryte za pomocą reguły CSS, więc zwykli
użytkownicy nie będą go widzieli i tym samym pozostawią je puste podczas
wysyłania formularza. Z kolei roboty szukające możliwości wykorzystania
formularza kontaktowego w celu wysłania spamu będą widziały pole lname i
umieszczą w nim jakąś wartość. Kod przetwarzający formularz przed
wysłaniem wiadomości e-mail sprawdza, czy pole lname jest puste.
Podobnie jak słoik miodu przyciąga owady, tak samo ukryte pole lname
przyciąga spamerów i pozwala uniknąć wysyłania wiadomości e-mail w ich
imieniu.

Stosowanie zaczepów do kopiowania szablonów

Jeżeli nie chcesz zmieniać wielu plików szablonu podczas uaktualniania
identyfikatora lub nazwy klasy opakowującego elementu <div>, możesz
utworzyć szablon używający filtra the_content lub innej akcji
przeznaczonej konkretnie dla danego motywu i umieścić treść w obszarze
treści głównej na stronie. Następnie można wczytać kolejny plik
szablonu, np. page.php, który będzie zawierał wywołania odpowiedzialne
za wczytanie ramki witryny i układu domyślnego. Na listingu 4.2
pokazaliśmy, jak można utworzyć szablon strony wczytującej szablon
page.php i kolejną treść na konkretnych stronach.

Listing 4.2. Szablon zaczepu

    <?php

    /*

        Nazwa szablonu: Przykład szablonu zaczepu

    */

    // Użycie domyślnego szablonu strony

    require_once(dirname(__FILE__) . "/page.php");

    // Dodanie treści za pomocą wywołania funkcji w zaczepie the_content

    function template_content($content)

    {

        // Pobranie bieżącego posta w tej pętli

        global $post;

        // Pobranie obiektu posta dla bieżącej strony

        $queried_object = get_queried_object();

        // Nie chcemy filtrowania postów, jeśli to nie jest post główny

        if(empty($queried_object) || $queried_object->ID != $post->ID)

            return $content;

        // Przechwycenie danych wyjściowych

        ob_start();

        ?>

        <p>Ta treść zostanie wyświetlona pod treścią strony.</p>

        <?php

        $temp_content = ob_get_contents();

        ob_end_clean();

        // Dołączenie i zwrot treści szablonu

        return $content . $temp_content;

    }

    add_action("the_content", "template_content");

W omawianym przykładzie posłużyliśmy się małą sztuczką polegającą na
sprawdzeniu wartości bieżącej $post i porównaniu jej z $queried_object.
Zmienna globalna $post zwykle będzie zawierała post główny strony, na
którą przeszedł użytkownik. Jednak inne pętle na stronie będą tymczasowo
przypisywać tej zmiennej aktualnie przetwarzany post. Przykładowo jeśli
szablon wykorzystuje menu WordPressa, wówczas tak naprawdę mamy iterację
przez posty typu menu. Wiele sekcji pasków bocznych i stopki będzie
przeprowadzało iterację przez inne zestawy postów.

Funkcja get_queried_object() zwraca obiekt postu głównego dla bieżącej
strony. W przypadku strony terminu lub autora ta funkcja zwraca inny,
choć odpowiedni obiekt. Z kolei na stronach archiwum wartością zwrotną
tej funkcji jest null. Skoro przedstawiony przykład dotyczył szablonu
strony wczytywanego tylko na stronach pojedynczego widoku, wywołanie
get_queried_object() zwraca obiekt dla bieżącej strony.

Istnieje również możliwość wstawienia na stronie page.php oraz na innych
kluczowych szablonach własnego zaczepu, którego działanie będzie podobne
do omawianego przykładu. Wystarczy umieścić coś w stylu
do_action('my_template_hook'); w szablonie strony, w miejscu, w którym
ma się pojawić treść dodatkowa.

Kiedy należy używać szablonu motywu?

Z rozdziału 3. wiesz, jak można korzystać ze skrótów podczas tworzenia
stron dla wtyczek. Te skróty są użyteczne, ponieważ pozwalają dodawać
zarządzaną przez CMS treść przed skrótem i po skrócie w polu treści
posta, a jednocześnie kod wtyczki pozostaje zorganizowany. Jeżeli
wtyczka ma być rozprowadzana i potrzebujesz szablonu strony, to w
trakcie generowania strony korzystaj ze skrótów.

Podobnie jeśli chcesz rozprowadzać motyw, musisz dołączyć do jego
katalogu wszystkie szablony niezbędne do użycia motywu. Wprawdzie w
motywie można użyć kodu dla szablonów stosujących skróty, ale szablony
to znacznie bardziej standardowy sposób przygotowywania stron.

Jeżeli szablon będzie wymagał modyfikacji kodu HTML domyślnego układu
strony, w motywie musisz skorzystać z pliku szablonu. Na listingu 4.2
został zamieszczony kod szablonu page.php, aby uniknąć konieczności
ponownego tworzenia opakowującego kodu HTML. Jeżeli celem szablonu jest
dostarczenie opakowującego kodu znaczników HTML (np. strona docelowa
szablonu wraz z ukrytym domyślnym nagłówkiem, stopką i menu), wtedy
zdecydowanie należy użyć szablonu.

Funkcje WordPressa powiązane z motywem

Teraz przechodzimy do omówienia get_template_part( $slug,$name = null ).
W tym przypadku funkcji get_template_part() można użyć do wczytania
innych plików .php (fragmentów szablonu) do pliku w motywie.

Zgodnie z informacjami zamieszczonymi w serwisie Codex $slug odwołuje
się do „nazwy slugu dla ogólnego szablonu”, a $name odwołuje się do
„nazwy szablonu specjalizowanego”. W rzeczywistości oba parametry
zostały połączone za pomocą łącznika w celu utworzenia nazwy pliku w
postaci slug-name.php.

Motyw Twenty Twelve używa funkcji get_template_part() do wczytania
określonego formatu fragmentu „treści” postu w pętli WordPressa:

    <?php /* Początek pętli */ ?>

    <?php while ( have_posts() ) : the_post(); ?>

        <?php get_template_part( 'content', get_post_format() ); ?>

    <?php endwhile; ?>

Jeżeli fragment szablonu znajduje się w podkatalogu motywu, nazwę tego
podkatalogu należy umieścić na początku sluga:

    get_template_part('templates/content', 'page');

Funkcja get_template_part() używa wywołania locate_template() WordPressa
do odszukania wskazanego fragmentu szablonu, który następnie zostanie
wczytany za pomocą funkcji load_template(). Funkcja load_template()
szuka fragmentu najpierw w motywie potomnym. Jeżeli w motywie potomnym
nie zostanie znaleziony dopasowany plik, to zostanie sprawdzony motyw
nadrzędny.

Poza wyszukiwaniem danych w motywach nadrzędnym i potomnym kolejną
zaletą zastosowania funkcji get_template_part() zamiast standardowego
wywołania PHP include lub require jest to, że zestaw zmiennych
globalnych WordPressa zostanie zdefiniowany przed dołączeniem pliku.
W kolejnym przykładzie przedstawiliśmy kod źródłowy funkcji
load_template() w WordPressie 4.9.7[2], pokazujący definiowanie
zmiennych globalnych. Zwróć uwagę na wyodrębnienie do zasięgu lokalnego
także tablicy query_vars. Na szczególną uwagę i zastosowanie operacji
oczyszczenia zasługuje tutaj query_vars $s, ponieważ jest to często cel
ataków typu XSS, a w wielu motywach autorzy zapominają o oczyszczeniu
ciągu tekstowego wyszukiwania podczas jego umieszczania w polu
wyszukiwania.

    <?php

    function load_template( $_template_file, $require_once = true ) {

       global $posts, $post, $wp_did_header, $wp_query, $wp_rewrite;

       global $wpdb, $wp_version, $wp, $id, $comment, $user_ID;

       if ( is_array( $wp_query->query_vars ) )

          extract( $wp_query->query_vars, EXTR_SKIP );

    if ( isset( $s ) )

       $s = esc_attr( $s );

       if ( $require_once )

          require_once( $_template_file );

       else

          require( $_template_file );

    }

    ?>

Stosowanie funkcji locate_template() w motywach

Często stosowanym wzorcem projektowym we wtyczkach jest dołączanie
szablonów do katalogu wtyczki, aby umożliwić użytkownikom nadpisywanie
tych szablonów przez dodawanie ich własnych wersji do aktywnych wtyczek.
Przykładowo we wtyczce SchoolPress nauczyciele mogą zapraszać uczniów do
udziału w zajęciach klasowych. Formularz zaproszenia jest przechowywany
w szablonie znajdującym się we wtyczce.

    // schoolpress/templates/invite-students.php

    ?>

    <p>Enter</p>

    <form action="" method="post">

            <label for="email">E-mail:</label>

    <input type="text" id="email" name="email" value="" />

            <input type="submit" name="invite" value="Zaproś ucznia" />

    </form>

Wprawdzie wtyczka SchoolPress została zaprojektowana jako aplikacja typu
SaaS (ang. software as a service), ale planujemy również wydanie wersji
wtyczki przeznaczonej do wykorzystywania przez użytkowników we własnych
witrynach internetowych. Być może użytkownicy wtyczki będą chcieli
nadpisywać szablon domyślny bez konieczności edycji podstawowej wtyczki,
ponieważ takie zmiany zostaną utracone po aktualizacji wtyczki.

Aby umożliwić użytkownikom nadpisanie szablonu zaproszenia, podczas
dołączania pliku szablonu można skorzystać z kodu podobnego do tego:

    // schoolpress/shortcodes/invite-students.php

    function sp_invite_students_shortcode($atts, $content=null, $code="")

    {

        // Rozpoczęcie buforowania danych wyjściowych

        ob_start();

        // Wyszukanie w aktywnym motywie szablonu invite-students

        $template = locate_template('schoolpress/templates/invite-students.php');

        // Jeżeli szablon nie został znaleziony, należy użyć domyślnego

        if(empty($template))

            $template = dirname(__FILE__) .

            '/../templates/invite-students.php';

        // Wczytanie szablonu

        load_template($template);

        // Pobranie treści z bufora i jej wyświetlenie

        $temp_content = ob_get_contents();

        ob_end_clean();

            return $temp_content;

    }

    add_shortcode('invite-students', 'sp_invite_students_shortcode');

Ten kod używa szablonu skrótu pochodzącego z rozdziału 3. Zamiast jednak
osadzać kod HTML w funkcji skrótu, został wczytany z pliku szablonu.
Przede wszystkim należy użyć funkcji locate_template() do wyszukania
szablonu w aktywnych motywach nadrzędnym i potomnym. Jeżeli plik nie
zostanie znaleziony, wartość $template powinna być zdefiniowana jako
ścieżka dostępu szablonu domyślnego, który znajduje się we wtyczce.
Szablon jest wczytywany za pomocą load_template().

Plik style.css

Plik style.css musi zawierać komentarz używany przez WordPressa do
śledzenia wersji motywu i innych informacji wyświetlanych w panelu
WordPressa. Oto przykładowy komentarz, który pochodzi z początku pliku
style.css znajdującego się w motywie Twenty Nineteen:

    /*

    Nazwa motywu: Twenty Nineteen

    Adres URI motywu: https://wordpress.org/themes/twentynineteen/

    Autor: zespół WordPressa

    Adres URI witryny autora: https://wordpress.org/

    Opis: Nasz domyślny motyw na 2019 rok ma na celu pokazanie potęgi edytora bloków. Zawiera style 

    niestandardowe dla wszystkich bloków domyślnych i jest zbudowany w taki sposób, że to, co widzisz w edytorze, zobaczysz w swojej witrynie.

    Motyw Twenty Nineteen zaprojektowano w sposób zapewniający możliwość jego dostosowania do wielu różnych witryn internetowych, niezależnie od ich typu: prowadzisz blog ze zdjęciami, zakładasz nową firmę,

    wspierasz organizację typu non profit itd. Dzięki obszernym odstępom i nowoczesnym nagłówkom bezszeryfowym w połączeniu z klasycznym tekstem szeryfowym treść jest wyświetlana pięknie na ekranach o każdej wielkości.

    Wymaga przynajmniej: WordPress 4.9.6

    Wersja: 1.4

    Licencja: GNU General Public License v2 lub nowsza

    Adres URI licencji: LICENSE

    Domena tekstu: twentynineteen

    Tagi: one-column, flexible-header, accessibility-ready,

    custom-colors, custom-menu, custom-logo, editor-style,

    featured-images, footer-widgets, rtl-language-support,

    sticky-post, threaded-comments, translation-ready

    Ten motyw, podobnie jak cały WordPress, jest objęty licencją GPL.

    Użyj go, aby zrobić coś fajnego, dobrze się bawić i dzielić z innymi tym, czego się nauczyłeś.

    Twenty Nineteen oparto na Underscores https://underscores.me/,

    (C) 2012-2018 Automattic Inc.

    Oprogramowanie Underscores jest rozpowszechniane na licencji GNU GPL v2 lub nowszej.

    Style normalizacji zostały przygotowane dzięki pracy 

    Nicolasa Gallaghera i Jonathana Neala https://necolas.github.io/normalize.css/

    */

Plik style.css aktywnego motywu (i motywu nadrzędnego, o ile taki
istnieje) jest dodawany automatycznie przez WordPressa.

Wersjonowanie plików CSS motywu

Dobrą praktyką jest definiowanie wersji plików CSS podczas ich
wczytywania za pomocą funkcji wp_enqueue_style(). Dzięki temu po
uaktualnieniu pliku CSS będzie można uaktualnić także jego wersję i tym
samym uniknąć sytuacji, w której użytkownicy witryny internetowej
otrzymują wydawałoby się nieprawidłowo wyświetlaną treść, ponieważ
przeglądarka WWW używa buforowanej wersji arkuszy stylów.

Gdy WordPress pobiera plik style.css motywu, używa ogólnej wersji
WordPressa podczas wczytywania arkusza stylów. Polecenie w nagłówku
strony będzie przedstawiało się podobnie do następującego:

    <link rel='stylesheet'

        id='twentynineteen-style-css'

        href='.../wp-content/themes/twentynineteen/style.css?ver=1.4'

        type='text/css'

        media='all' />

Uaktualnienia arkusza stylów, numeru wersji aplikacji, a nawet numeru
wersji zdefiniowanego w komentarzu w pliku style.css nie będą powodowały
uaktualnienia wersji dodawanej do arkusza stylów. Zawsze dopasowany
będzie numer wersji WordPressa.

Rozwiązaniem jest usunięcie wszystkich stylów CSS z pliku style.css i
innych plików CSS w motywie oraz wczytywanie tych plików CSS za pomocą
wywołań wp_enqueue_style() zdefiniowanych w pliku functions.php motywu.
W przypadku pliku style.css kod będzie przedstawiał się następująco:

    /*

       Nazwa motywu: SchoolPress

       Wersja: 1.0

       I to tyle! Cały kod CSS znajduje się w podkatalogu "css" katalogu motywu

    */

Natomiast w pliku functions.php powinien znajdować się kod podobny do
następującego:

    <?php

    define( 'SCHOOLPRESS_VERSION', '1.0' );

    function sp_enqueue_theme_styles() {

        if ( !is_admin() ) {

            wp_enqueue_style( 'schoolpress-theme',

                get_stylesheet_directory_uri() . '/css/main.css',

                NULL,

                SCHOOLPRESS_VERSION

            );

        }

    }

    add_action( 'init', 'sp_enqueue_theme_styles' );

    ?>

Stała taka jak SCHOOLPRESS_VERSION zwykle będzie zdefiniowana w głównym
pliku wtyczki, w omawianym przykładzie zaś została dołączona w celu
jasnego pokazania rozwiązania. Ten kod wczytuje nowy plik /css/main.css
wraz z dołączonym numerem wersji aplikacji głównej, więc nowe wersje
aplikacji nie będą się kłóciły ze stylami buforowanymi przez
przeglądarkę WWW.

Istnieje jeszcze inny sposób na zmianę wersji głównego pliku style.css
bez jego całkowitego przenoszenia do innego pliku: wykorzystanie filtra
wp_default_styles. Ten filtr przekazuje obiekt zawierający wartości
domyślne używane w dołączanym arkuszu stylów. Jedną z tych wartości jest
default_version i można ją zmienić w następujący sposób:

    define('SCHOOLPRESS_VERSION', '1.0');

    function sp_wp_default_styles($styles)

    {

        // Użycie produkcyjnej wersji arkuszy stylów

        $styles->default_version = SCHOOLPRESS_VERSION;

    }

    add_action("wp_default_styles", "sp_wp_default_styles");

Ten główny arkusz stylów zostanie wczytany za pomocą wersji aplikacji
SchoolPress zamiast wersji głównej WordPressa. Style CSS można
pozostawić w pliku style.css, jeśli chcesz, choć zwykle dobrym
rozwiązaniem jest przeniesienie przynajmniej części z nich do
oddzielnych plików w katalogu css motywu.

Plik functions.php

Plik functions.php aktywnego motywu (i motywu nadrzędnego, o ile taki
istnieje) jest wczytywany razem z WordPressem. Z tego powodu
functions.php to popularne miejsce na stosowanie prostych sztuczek i
dodawanie różnych innych fragmentów kodu. W typowej witrynie
internetowej WordPressa plik functions.php bardzo szybko może stać się
zagmatwany i niezorganizowany.

Jeżeli pracujesz nad doskonale zaprojektowaną aplikacją WordPressa, plik
functions.php wcale nie musi być zagmatwany. Wystarczy podzielić
podstawowe funkcje aplikacji głównej na mniejsze fragmenty, wczytywane
później za pomocą wywołania include. To samo można zrobić w przypadku
pliku functions.php motywu. Pliki można dodawać do wymienionych tutaj
lokalizacji w katalogu motywu:

/includes/functions.php

Faktyczne miejsce umieszczenia funkcji pomocniczych.

/includes/settings.php

Miejsce na kod związany z opcjami i ustawieniami motywu.

/includes/sidebars.php

Miejsce na zdefiniowanie obszarów pasków bocznych i widżetów.

Ponadto upewnij się, że kod dodawany do pliku functions.php motywu jest
związany z frontendem wyświetlanym przez witrynę internetową. Kod, który
ma zastosowanie dla panelu WordPressa, przetwarzania backendu aplikacji
lub ogólnie dla całej aplikacji, niemal na pewno powinien być
definiowany w innych miejscach wtyczki aplikacji głównej.

Motywy i niestandardowe typy postów

Niestandardowe typy postów są to zwykłe posty, które domyślnie będą
generowane na podstawie szablonu single.php lub, w przypadku jego
niedostępności, na podstawie szablonu index.php. Istnieje również
możliwość dodania do motywu pliku w postaci single-<typ_posta>.php,
gdzie <typ_posta> to slug niestandardowego typu postów. Jeżeli taki plik
będzie dostępny, zostanie wykorzystany do generowania widoku
pojedynczego posta danego typu.

Podobnie istnieje możliwość dodania pliku archive-<typ_posta>.php
przeznaczonego do wyświetlenia widoku archiwum niestandardowych typów
postów, o ile opcja has_archive_flag ma przypisaną wartość w postaci
definicji CPT. Więcej dokładnych informacji na temat niestandardowych
typów postów znajdziesz w rozdziale 5.

Popularne frameworki motywów

Podczas tworzenia aplikacji za pomocą WordPressa masz do dyspozycji
wiele frameworków — zarówno przeznaczonych dla WordPressa, jak i
ogólnego przeznaczenia frameworków HTML i CSS. Niezależnie od tego, czy
framework chcesz wykorzystać do szybkiego przygotowania prototypu czy w
charakterze podstawowego komponentu motywu, to zastosowanie frameworka
motywu może zaoszczędzić Ci wiele czasu.

W tej sekcji przedstawimy najczęściej używane frameworki motywów, a
także nieco dokładniej pokażemy, jak podczas tworzenia aplikacji
WordPressa wykorzystać dwa spośród tych najpopularniejszych frameworków.

Jednak na początku musimy sobie wyjaśnić, co dostarcza framework motywu.

Frameworki motywów WordPressa

Frameworki motywów WordPressa to motywy przeznaczone do stosowania w
charakterze motywów nadrzędnych lub startowych, które umożliwiają
szybkie rozpoczęcie pracy nad frontendem. Taki framework zwykle zawiera
podstawowe style i układy przeznaczone dla postów bloga, a także dla
archiwum, stron, pasków bocznych i menu. Mają one różną wielkość,
niektóre z nich zawierają klasy CSS, skróty i inne użyteczne fragmenty
kodu pomocne w tworzeniu nowych układów oraz dodawaniu na stronach
elementów interfejsu użytkownika. Wszystkie frameworki pozwalają
zaoszczędzić dużo czasu.

Istnieją dwa powody, które mogą prowadzić do wyboru jednego frameworka
motywu zamiast innego: wybierasz motyw potomny wizualnie wyglądający
bardzo podobnie do Twojej wizji aplikacji albo wybierasz framework, z
którym praca przebiega (według Ciebie) odpowiednio.

_s

Motyw startowy _s (określany mianem underscores) został opublikowany
przez Automattic i zawiera wszystkie najczęściej spotykane komponenty,
które są niezbędne w motywie WordPressa. W przeciwieństwie do większości
innych frameworków _s nie jest przeznaczony do stosowania jako motyw
nadrzędny, lecz jako punkt wyjścia do opracowania własnego motywu
nadrzędnego. Większość opracowanych przez Automattic motywów dla
WordPress.com bazuje na motywie _s.

Aby użyć _s, należy pobrać kod oraz zmienić nazwę katalogu i wszystkie
odwołania do _s nazwą tworzonego motywu. Wyczerpujące informacje na ten
temat znajdują się w pliku README.me projektu
(https://github.com/Automattic/_s/blob/master/README.md). Jeszcze
lepszym pomysłem będzie użycie narzędzia, które automatycznie zrobi to
za Ciebie (odwiedź witrynę https://underscores.me/).

Arkusz stylów w _s jest naprawdę minimalny i praktycznie nie definiuje
żadnych stylów. Jest to po prostu fragment kodu zawierający ustawienia
związane z układem, czytelnością i użytecznością. Motyw _s najlepiej
sprawdza się dla projektantów, którzy chcą samodzielnie i zupełnie od
podstaw przygotować własny motyw. W zasadzie jest to kod, który trzeba
utworzyć na pewnym etapie pracy nad motywem. Kod _s nie jest oddzielony
w tak dużym stopniu jak w wielu innych frameworkach, więc rozpoczęcie
pracy z nim powinno być łatwiejsze dla projektantów, którzy mają większe
doświadczenie w pracy z HTML i CSS niż z PHP.

Memberlite

Memberlite to motyw opracowany przez Jasona Colemana i Kimberly Coleman
ze Stranger Studios. Powstał z myślą o witrynach zapewniających obsługę
użytkowników, choć może być stosowany również w wielu innych witrynach
internetowych. Człon „lite” w nazwie wskazuje na lekki (pod względem
technicznym i estetycznym) projekt motywu.

Motyw ten został zaprojektowany w sposób responsywny, zapewniający
prawidłowe działanie na ekranie o dowolnej wielkości. Ma szablony i
sekcje przeznaczone dla wszystkich komponentów niezbędnych w nowoczesnej
witrynie internetowej. Działanie motywu wspomagają wtyczki (Memberlite
Elements i Memberlite Shortcodes) wraz z narzędziami przeznaczonymi do
dokładniejszej kontroli nad paskami bocznymi, banerami, układami stron i
innymi aspektami witryny internetowej.

Memberlite to motyw najlepiej sprawdzający się w przypadku
programistów-projektantów. Jest naszym faworytem w zakresie motywu
początkowego, ponieważ oferuje dobrą równowagę między obsługą frameworka
pod względem projektu i kodu źródłowego motywu.

Genesis

Genesis (https://my.studiopress.com/themes/genesis/) to opracowany przez
StudioPress framework motywu stosowany w ponad 40 motywach potomnych
opublikowanych przez StudioPress oraz w wielu innych motywach
opracowanych przez projektantów zewnętrznych. Motyw Genesis jest
przeznaczony do użycia w charakterze motywu nadrzędnego. StudioPress
oferuje wiele motywów potomnych, które świetnie sprawdzają się w wielu
rodzajach witryn internetowych, w tym także firmowych. Ewentualnie
możesz tworzyć własne motywy potomne dziedziczące po Genesis.

Framework Genesis w większym stopniu niż inne frameworki stosuje
abstrakcję kodu HTML i CSS. Według nas to oznacza nieco większą trudność
w trakcie pracy, kiedy motyw trzeba bardziej dostosować do własnych
potrzeb. Jednak motyw Genesis to doskonały wybór, gdy ustalisz, że jeden
z motywów potomnych jest w 80% zgodny z Twoimi wymaganiami, lub uznasz,
że praca z tym frameworkiem jest łatwiejsza niż z innymi.

Frameworki motywów przeznaczone nie tylko dla WordPressa

Poza frameworkami motywów WordPressa istnieją także frameworki
interfejsu użytkownika aplikacji, które zapewniają kod znaczników,
arkusze stylów i obrazki dla najczęściej stosowanych wzorców interfejsu
użytkownika i elementów. Do najpopularniejszych frameworków interfejsu
użytkownika zaliczamy Bootstrap (https://getbootstrap.com/) opracowany
przez Twittera i Foundation (https:// get.foundation/) opracowany przez
Zurba.

Zastosowanie w motywie frameworka interfejsu użytkownika może być łatwe
i sprawdzać się do skopiowania kilku plików do katalogu motywu oraz
dodania stylów CSS i skryptów JavaScript. W ten sposób zapewniasz sobie
łatwy dostęp do zawierających nadane style elementów interfejsu
użytkownika, takich jak przyciski, karty, etykiety, powiadomienia, paski
postępu, elementy stronicowania i łącza typu „jesteś tutaj”.

Z dalszej części rozdziału dowiesz się, jak dodać zasoby frameworka
Bootstrap do motywu potomnego Memberlite. Ten sam proces będzie się
sprawdzał również w połączeniu WordPressa z innymi frameworkami
interfejsu użytkownika.

Tworzenie motywu potomnego dla Memberlite

Aby utworzyć motyw, należy wykonać następujące kroki:

1.  W katalogu wp-content/themes utwórz katalog o nazwie
    memberlite-child.

2.  W katalogu memberlite-child utwórz plik o nazwie style.css.

3.  W pliku style.css umieść ten fragment kodu:

        /*

        NAZWA MOTYWU: Memberlite Child

        ADRES URI MOTYWU: http://bwawwp.com/wp-content/themes/memberlite-child/

        OPIS: Motyw Memberlite Child

        WERSJA: 0.1

        AUTOR: Jason Coleman

        Adres URI witryny autora: http://bwawwp.com

        TAGI: memberlite, child, tag

        SZABLON: memberlite

        */

        @import url("../memberlite/style.css");

    Kluczowym polem w tym komentarzu jest TEMPLATE, którego wartość musi
    odpowiadać nazwie katalogu motywu nadrzędnego, czyli w omawianym
    przykładzie jest to memberlite. Jedynym plikiem wymaganym przez
    motyw potomny jest style.css. W tym momencie masz więc utworzony
    motyw potomny.

    Wszystkie style CSS z pliku style.css motywu nadrzędnego możesz
    skopiować do pliku style.css stylu potomnego i przeprowadzić ich
    edycję. Drugą możliwością jest użycie polecenia @import_url, jak w
    omawianym przykładzie — spowoduje to zaimportowanie reguł stylów
    z arkusza stylów motywu nadrzędnego. Następnie można dodać kolejne
    reguły i tym samym nadpisać reguły stylów motywu nadrzędnego.

    Aby wykorzystać pliki frameworka, konieczne jest utworzenie także
    pliku functions.php.

4.  W katalogu memberlite-child utwórz plik o nazwie functions.php.

Wykorzystanie frameworka Bootstrap w motywie aplikacji

Ogólnie rzecz biorąc, importowanie frameworka Bootstrap do motywu
Memberlite jest niezbyt rozsądne w stosunku do wyszukania motywu
opartego na Bootstrapie lub po prostu skopiowania niezbędnych reguł CSS.
Jednak importowanie frameworków i bibliotek do motywu to rodzaj zadania,
które być może przyjdzie Ci wykonywać. Przedstawione tutaj informacje
powinny pokazać, jak przebiega importowanie innych bibliotek i
frameworków do motywu.

Pobierz archiwum ZIP zawierające framework Bootstrap
(https://getbootstrap.com/) i umieść je w katalogu memberlite-child. Po
rozpakowaniu archiwum otrzymasz katalog dist zawierający pliki CSS i
JavaScript dla Bootstrapa. Nazwę tego katalogu możesz zmienić na
bootstrap i usunąć archiwum ZIP. Po tej operacji struktura katalogu
motywu będzie przedstawiała się następująco:

    •  memberlite-child

        — bootstrap

            — css

            — js

        — functions.php

        — style.css

Teraz dołączenie plików CSS i JavaScript Bootstrapa będzie możliwe po
dodaniu do pliku functions.php w motywie potomnym następującego kodu:

    <?php

    function memberlite_child_init() {

        wp_enqueue_style(

                'bootstrap',

                get_stylesheet_directory_uri() .

            '/bootstrap/css/bootstrap.min.css',

                'style',

                '3.0'

        );

        wp_enqueue_script(

                'bootstrap',

                get_stylesheet_directory_uri() .

            '/bootstrap/js/bootstrap.min.js',

                'jquery',

                '3.0'

        );

    }

    add_action( 'init', 'memberlite_child_init' );

    ?>

Zwróć uwagę na zdefiniowanie zależności dla stylów CSS frameworka
Bootstrap (wartość style), co gwarantuje ich wczytanie po arkuszu stylów
Memberlite. Ponadto została zdefiniowana zależność skryptów JavaScript
Bootstrapa (wartość jquery), a wersje obu plików to 3.0, co odpowiada
użytej wersji Bootstrapa.

W tym momencie w motywie WordPressa można wykorzystać ulubione style i
skrypty JavaScript frameworka Bootstrap. Wiele stylów Bootstrapa dla
kolumn i układów stron nie jest używanych w kodzie znaczników Memberlite
(ponieważ Memberlite korzysta z własnego systemu układu stron), więc nie
będą miały zastosowania w motywie. Natomiast style dla elementów
formularzy i przycisków okazują się przydatne dla każdego programisty
aplikacji internetowych.

Menu

Menu to bardzo ważny aspekt większości aplikacji, same aplikacje zaś
bardzo często mają specjalne wymagania w tym zakresie, których nie mają
inne witryny internetowe. Niektóre aplikacje zostały wyposażone w wiele
menu. Sporo aplikacji mobilnych dysponuje głównym menu nawigacyjnym na
górze strony przypominającym pasek menu na dole strony. Inne aplikacje
mają menu dynamiczne. Wiele aplikacji ma odmienne menu lub elementy menu
przeznaczone dla użytkowników zalogowanych i niezalogowanych. Elementy
menu mogą opierać się na poziomie uprawnień użytkownika lub jego
możliwościach w zakresie administrowania witryną.

Zanim przejdziemy do tematu tworzenia skomplikowanych menu i elementów
nawigacyjnych za pomocą WordPressa, warto zapoznać się ze standardowym
sposobem dodawania menu do motywu.

Menu nawigacyjne

Począwszy od WordPressa 3.0, standardowa metoda dodawania menu polega na
zarejestrowaniu menu w kodzie motywu, ustaleniu miejsca wyświetlenia
menu, a następnie zarządzaniu menu za pomocą panelu WordPressa.

Największą korzyścią płynącą z użycia wbudowanej w WordPressa
funkcjonalności menu jest to, że użytkownik końcowy może kontrolować
zawartość menu za pomocą graficznego interfejsu użytkownika panelu.
Nawet jeśli jesteś programistą zachowującym pełną kontrolę nad
aplikacją, dobrym pomysłem jest stosowanie wbudowanych menu WordPressa,
ponieważ Twoi współpracownicy mogą chcieć zarządzać menu lub w
przyszłości zdecydujesz się na rozpowszechnianie motywu zawierającego
dane menu. Menu nawigacyjne WordPressa może bardzo łatwo zmienić
położenie, a ponadto możliwe jest wykorzystanie zalet innego kodu
stosującego zaczepy związane z menu lub style CSS.

Aby zarejestrować nowe menu nawigacyjne, skorzystaj z funkcji
register_nav_menu( $location, $description ). Parametr $location to
unikatowy slug pozwalający na identyfikację menu. Parametr $description
to dłuższy tytuł dla menu wyświetlanego w rozwijanym menu.

    register_nav_menu('main', 'Main Menu');

Istnieje możliwość jednoczesnego zarejestrowania wielu menu za pomocą
wywołania register_nav_menus(). Ta funkcja akceptuje tablicę
lokalizacji, w której klucze to slugi $location, a wartości to tytuły
$description.

    register_nav_menus(array(

    'main' => 'Main',

    'logged-in' => 'Logged-In'

    ));

Aby umieścić menu nawigacyjne w motywie, należy skorzystać z funkcji
wp_nav_menu().

    wp_nav_menu( array('theme_location' => 'main' ));

Parametr theme_location powinien mieć przypisaną wartość $location za
pomocą register_nav_menus(). Funkcja wp_nav_menu() może pobierać także
inne parametry w celu zmiany sposobu działania kodu i znaczników menu.
Zamieszczona w serwisie WordPress Codex strona dotycząca menu
nawigacyjnego
(https://developer.wordpress.org/reference/functions/wp_nav_menu/) to
doskonałe źródło informacji o różnych parametrach funkcji wp_nav_menu()
oraz o innych sposobach dostosowania menu do własnych potrzeb. W dalszej
części rozdziału przedstawimy wybrane spośród naszych ulubionych
sposobów.

Menu dynamiczne

Istnieją dwie główne metody pozwalające przygotować menu dynamiczne
WordPressa, dzięki któremu zawartość menu będzie zależała od strony i
okoliczności jego wyświetlenia. Pierwsza metoda polega na zdefiniowaniu
dwóch menu i wczytaniu odpowiedniego w zależności od potrzeb. Spójrz na
pochodzący z serwisu Codex fragment kodu pokazujący, jak można
wyświetlić inne menu użytkownikom zalogowanym i niezalogowanym:

    if ( is_user_logged_in() ) {

        wp_nav_menu( array( 'theme_location' => 'logged-in-menu' ) );

    } else {

        wp_nav_menu( array( 'theme_location' => 'logged-out-menu' ) );

    }

Drugim sposobem na zdefiniowanie menu dynamicznego jest wykorzystanie
filtra nav_menu_css_class, który pozwala dodać kolejne klasy CSS do
określonych elementów menu. Następnie CSS można użyć do wyświetlenia lub
użycia określonych menu na podstawie klasy CSS.

Załóżmy, że mamy usunąć łącze logowania z menu wyświetlanego na stronie
logowania[3]. Do tego celu można wykorzystać kod podobny do
następującego:

    function remove_login_link($classes, $item)

    {

        if(is_page('login') && $item->title == 'Login')

            $classes[] = 'hide';        // Ukrycie tego elementu

        return $classes;

    }

    add_filter('nav_menu_css_class', 'sp_nav_menu_css_class', 10, 2);

Kod znaczników menu można dostosować do własnych potrzeb także za pomocą
klas Custom Walker (zajrzyj do rozdziału 7.).

Responsywny układ strony

Na temat responsywnego układu strony można napisać całą książkę. Na
szczęście inni zrobili to już za nas, np. Clarissa Peterson, która jest
autorką książki Responsywne strony WWW dla każdego (Helion). Ogólna
koncepcja kryjąca się za układem responsywnym polega na wykryciu
urządzenia klienta, a następnie dopasowaniu układu, projektu i
funkcjonalności aplikacji, aby działała jak najlepiej w danym
urządzeniu. Przedstawimy teraz kilka technik umożliwiających realizację
tego zadania.

Wykrywanie urządzenia i ekranu za pomocą CSS

Zapytanie o media to podstawowa metoda wykrywania urządzenia w CSS.
Takie zapytanie jest wykorzystywane w arkuszach stylów lub dodawane jako
właściwość znacznika <link> używanego do osadzania arkuszy stylów, a
jego celem jest ograniczenie zasięgu reguł CSS arkusza stylów do
określonego typu urządzenia, które obsługuje daną funkcjonalność. W
serwisie Mozilli przeznaczonym dla programistów
(https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_
media_queries) znajduje się świetny artykuł wyjaśniający sposób
działania zapytań o media oraz omówienie różnych właściwości i
operatorów, które można wykorzystać podczas tworzenia zapytań o media.

Zapytanie o media jest często używane do ukrywania różnych elementów
oraz dostosowywania wielkości czcionki i elementów podczas wydruku
treści. Zapytanie o media można zdefiniować w znaczniku <link> , w
arkuszu stylów, a także poprzez wywołanie wp_enqueue_style(), jak możesz
zobaczyć w kolejnym fragmencie kodu:

    <link rel="stylesheet" media="print" href="example.css" />

    <style>

    @media print

    {

        .hide-from-print {display: none;}

        .show-when-printing {display: auto;}

    }

    </style>

    <?php

        wp_enqueue_style('example', 'example.css', NULL, '1.0', 'print');

    ?>

Znacznie bardziej typowym przykładem układu responsywnego w świecie
projektowania stron internetowych jest sprawdzanie właściwości min-width
i max-width, aby dostosować style do wielkości ekranu. W kolejnym
fragmencie kodu pochodzącym z responsywnego arkusza stylów Bootstrapa
możesz zobaczyć przykład dostosowania reguł CSS dla ekranów o wielkości
od 768 do 979 pikseli (aktualnie typowa szerokość okna przeglądarki WWW
na ekranie monitora). Okno o szerokości ponad 979 pikseli należy uznać
za wyjątkowo szerokie.

    @media (min-width: 768px) and (max-width: 979px) {

      .hidden-desktop {

        display: inherit !important;

      }

      .visible-desktop {

        display: none !important ;

      }

      .visible-tablet {

        display: inherit !important;

      }

      .hidden-tablet {

        display: none !important;

      }

    }

Innym zadaniem często obsługiwanym przez zapytanie o media jest zmiana
stylów, a dokładnie zamiana obrazów, gdy okno przeglądarki WWW zostało
wyświetlone na ekranie Retina o wysokiej rozdzielczości[4].

Spójrz na połączenie zapytań o media użytych w panelu WordPressa i
odpowiedzialnych za wykrywanie ekranu wysokiej rozdzielczości. Te
zapytania sprawdzają współczynnik pikseli i wartość DPI. Wprawdzie
wartości mogą się różnić dla poszczególnych ekranów, ale większość
standardowych ekranów będzie miała współczynnik pikseli wynoszący 1:1 i
wartość DPI równą 96. Ekran Retina ma współczynnik pikseli 2:1 i wartość
DPI co najmniej 196. Oczywiście można przeprowadzić sprawdzenie pod
kątem wartości minimalnych z przedziału od wartości dla ekranu
standardowego do wartości dla ekranu Retina, aby w ten sposób ustalić
użycie innych ekranów o rozdzielczości wyższej niż standardowa.

    @media(-o-min-device-pixel-ratio: 5/4), /* Przeglądarka WWW Opera */

      (-webkit-min-device-pixel-ratio: 1.25),         /* Silnik Webkit */

      (min-resolution: 120dpi) { /* Inne przeglądarki WWW */

        /* Miejsce na kod CSS obsługi obrazków w wysokiej rozdzielczości */

    }

Zapytanie o media oferuje potężne możliwości i pozwala na zdefiniowanie
interfejsu użytkownika charakteryzującego się dużą elastycznością.
Przeglądarki WWW i standardy CSS nieustannie ewoluują. Dlatego bardzo
ważne jest, aby być na bieżąco, ponieważ dzięki temu tworzone przez
Ciebie aplikacje będą prawidłowo wyświetlane na aktualnie produkowanych
telefonach, tabletach i monitorach.

Właściwości, które powinny być sprawdzone, i sposób dostosowania arkuszy
stylów do obsługi tych właściwości to zagadnienia wykraczające poza
zakres tematyczny tej książki. Mamy nadzieję, że ogólnie przedstawiliśmy
ideę i już wiesz, jak zapytania o media wykorzystać w motywach
WordPressa.

Wykrywanie urządzeń i funkcji za pomocą kodu JavaScript

Kod JavaScript aplikacji również może odnosić korzyści z funkcjonalności
wykrywania urządzeń i funkcji. jQuery oferuje metody przeznaczone do
ustalania wielkości okna i ekranu, a także pobierania innych informacji
o przeglądarce WWW. Wiele funkcji HTML5 może, choć nie musi, być
dostępnych dla określonej przeglądarki WWW, więc dobrze jest sprawdzić
dostępność funkcjonalności przed jej użyciem.

Określanie wielkości okna i ekranu za pomocą kodu JavaScript i jQuery

JavaScript zawiera informacje o szerokości i wysokości ekranu we
właściwościach odpowiednio screen.width i screen.height. Ponadto
właściwości screen.availWidth i screen.availHeight można wykorzystać do
pobrania informacji o dostępnej szerokości i wysokości ekranu z
uwzględnieniem pikseli zabranych przez paski narzędzi oraz panele boczne
w oknie przeglądarki WWW.

Jeżeli już używasz jQuery, możesz wywołać metodę width() w dowolnym
elemencie na stronie, aby w ten sposób ustalić jego szerokość. Ponadto
masz do dyspozycji obiekty $(document) i $(window) przeznaczone do
pobrania szerokości odpowiednio dokumentu i okna. Właściwość height()
w obiektach dokumentu i okna, a także w dowolnym elemencie na stronie,
dostarcza informacje o wysokości danego elementu.

Wartości $(window).width() i $(window).height() powinny mieć takie same
wartości jak screen.availWidth i screen.availHeight. Te wartości
przedstawiają dostępną wielkość widoku przeglądarki WWW pomniejszoną o
wszelkie paski narzędzi i panele boczne — innymi słowy, jest to ilość
miejsca przeznaczonego na wyświetlenie treści HTML.

Szerokość i wysokość dokumentu, wartość $(document), zwraca całkowitą
szerokość i wysokość wygenerowanej strony internetowej (możliwą do
przewijania). Gdy w kodzie JavaScript korzystasz z wartości szerokości i
wysokości, bardzo często będziesz chciał wprowadzać uaktualnienia po
zmianie wielkości okna. To się może zdarzyć, gdy użytkownik zmieni
wielkość okna przeglądarki WWW, obróci urządzenie mobilne, zmieniając
tym samym orientację (np. z pionowej na poziomą), lub wykona
jakiekolwiek inne działanie, które może prowadzić do zmiany szerokości
lub wysokości okna. jQuery oferuje łatwy sposób wykrywania tych zmian,
co pozwala na odpowiednie uaktualnienie układu.

    // Dołączenie zdarzenia, które zostanie wywołane po zmianie wielkości okna

    jQuery(window).resize(function() {

      width = jQuery(window).width();

      height = jQuery(window).height();

      // Uaktualnienie układu itd.

    });

Zdarzenie reagujące na zmianę wielkości można dołączyć do dowolnego
elementu, a nie tylko do pełnego okna. Elementy na stronie mogą
zwiększać się lub zmniejszać w reakcji na działania podejmowane przez
użytkownika, prawdopodobnie na skutek dodawania elementów za pomocą
formularzy w technologii AJAX, przeciągania zmieniających wielkość
elementów na ekran itd.

Wykrywanie funkcji w JavaScripcie

Gdy tworzysz nowoczesny interfejs użytkownika aplikacji, korzystając z
funkcji HTML5, czasami będziesz chciał sprawdzać dostępność określonych
funkcji HTML5, aby móc dostarczać rozwiązania alternatywne lub awaryjne.
Mark Pilgrim w swojej książce Dive into HTML5
(http://diveintohtml5.info/) zamieścił użyteczną listę ogólnych metod
przeznaczonych do wykrywania funkcjonalności HTML5:

1.  Sprawdź, czy określona właściwość istnieje w obiekcie globalnym (np.
    window lub navigator).
2.  Utwórz element, a następnie sprawdź, czy określona właściwość
    istnieje w tym elemencie.
3.  Utwórz element, a następnie sprawdź, czy określona metoda istnieje w
    tym elemencie. Jeżeli tak, wywołaj tę metodę i sprawdź jej wartość
    zwrotną.
4.  Utwórz element, przypisz określoną wartość tej właściwości, a
    następnie sprawdź, czy właściwość zachowała tę wartość.

Jeżeli masz potrzebę wykonania tylko jednej takiej operacji, przykłady
przedstawione w książce Dive into HTML5 będą wystarczające do
przygotowania własnego rozwiązania w tym zakresie. Gdy natomiast musisz
przeprowadzać wiele operacji wykrywania funkcjonalności, pomocna będzie
biblioteka taka jak Modernizr.js (https://modernizr.com/).

Jeżeli chcesz skorzystać z biblioteki Modernizr.js, zacznij od pobrania
skryptu z jej witryny internetowej. Modernizr oferuje narzędzie
pozwalające ustalić, które fragmenty skryptu będą Ci potrzebne, a
następnie generuje zminimalizowany plik .js zawierający jedynie
niezbędną funkcjonalność. Tak przygotowany plik umieść w katalogu motywu
lub wtyczki i dołącz do kodu.

    <?php

    function sp_wp_footer_modernizr() {

        wp_enqueue_script(

            'modernizr',

            get_stylesheet_directory_uri() . '/js/modernizr.min.js'

        );?>

        <script>

            // Zmiana pola tekstowego wyszukiwania, jeśli jest ono nieobsługiwane

            if(!Modernizr.inputtypes.search)

                jQuery('input[type=search]').attr('type', 'text');

        </script>

    <?php

    }

    add_action( 'wp_footer', 'sp_wp_footer_modernizr' );

    ?>

Dokumentacja Modernizr (https://modernizr.com/docs/#s2) zawiera listę
funkcjonalności możliwych do wykrycia za pomocą Modernizr.js.

jQuery oferuje również podobny zestaw operacji sprawdzających,
ograniczonych do tego, co biblioteka jQuery musi sprawdzić samodzielnie
za pomocą obiektu jQuery.support. Jeżeli operacja sprawdzająca może być
przeprowadzona za pomocą jQuery, wówczas możliwe jest uniknięcie
obciążenia związanego z Modernizr.js i wykorzystanie jQuery. Listę opcji
związanych z funkcjonalnością definiowaną przez jQuery.support
znajdziesz na stronie https://api.jquery.com/jQuery.support/.

    jQuery(document).ready(function() {

      // Wczytanie kodu w technologii AJAX tylko wtedy, gdy ta technologia jest obsługiwana

      if(jQuery.support.ajax)

      {

        // Miejsce na kod AJAX

      }

    });

Wykrywanie urządzenia w PHP

Wykrywanie urządzenia w PHP odbywa się na podstawie utworzonej przez PHP
zmiennej globalnej $_SERVER['HTTP_USER_AGENT']. Wartość tej zmiennej
jest definiowana przez przeglądarkę WWW i zdecydowanie nie należy do
standaryzowanych, często jest błędna i potencjalnie może być
modyfikowana przez roboty internetowe. Dlatego najlepszym rozwiązaniem
jest unikanie wykrywania urządzeń w PHP, o ile można utworzyć kod zgodny
ze standardami oraz wykorzystujący metody CSS i JavaScript przeznaczone
do wykrywania funkcjonalności.

Jeżeli chcesz ogólnie się dowiedzieć, z jakich przeglądarek WWW
korzystają użytkownicy aplikacji, najlepszym rozwiązaniem będzie użycie
ciągu tekstowego zawierającego informacje o agencie użytkownika. Oto
prosty skrypt wyświetlający ciąg tekstowy agenta użytkownika:

    <?php

    echo $_SERVER['HTTP_USER_AGENT'];

    /*

            Wygenerowane dane wyjściowe będą podobne do następujących:

            Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4)

            AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36

    */

    ?>

Ciąg tekstowy agenta użytkownika zawiera wiele użytecznych informacji,
choć prawdopodobnie jest ich za dużo. W tym ciągu tekstowym mamy co
najmniej pięć różnych nazw przeglądarek WWW, więc z której korzysta
użytkownik: Mozilla, KHTML, Gecko, Chrome czy Safari? W omawianym
przykładzie jest to przeglądarka Chrome w komputerze MacBook Air
działającym pod kontrolą systemu operacyjnego Mac OS X.

Czy już wspomnieliśmy, że nie istnieje standard dla ciągu tekstowego
agenta użytkownika wysyłanego przez przeglądarki WWW? Wcześniej
przeglądarki WWW umieszczały w tym ciągu tekstowym również nazwy
starszych przeglądarek, jakby chciały przekazać informację: „Mam takie
same możliwości jak te aplikacje”.

Na stronie WebAIM (https://webaim.org/blog/user-agent-string-history/)
znajdziesz zabawne podsumowanie różnych ciągów tekstowych użytkownika
wraz z wyjaśnieniem ciągu, który jest generowany i wysyłany przez
przeglądarkę WWW Chrome.

A potem Google stworzył przeglądarkę Chrome, która wykorzystuje silnik
WebKit. I ta przeglądarka działała jak Safari i domagała się stron
utworzonych dla Safari, więc udawała, że jest Safari. Skoro Chrome używa
WebKita i udaje, że jest Safari, a WebKit korzysta z silnika KHTML,
który udaje Gecko, to wszystkie przeglądarki WWW udają Mozillę. Chrome
przedstawia się jako Mozilla/5.0 (Windows, U, Windows NT 5.1, en-US)
AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13,
a ciąg tekstowy agenta użytkownika jest praktycznie niezrozumiały i
nieprzydatny, a każdy podszywa się pod każdego, więc to wszystko jest
niezwykle zagmatwane.

— Aaron Anderson

Wykrywanie funkcjonalności w WordPressie

Na szczęście WordPress wykonuje w tle operacje związane z przetwarzaniem
ciągu tekstowego użytkownika i udostępnia pewne zmienne globalne i kilka
metod przeznaczonych do obsługi najczęściej wykonywanych zadań
dotyczących wykrywania przeglądarek WWW. Wymienione tutaj zmienne
globalne zostały przez WordPressa zdefiniowane w pliku
wp-includes/vars.php:

-   $is_lynx
-   $is_gecko
-   $is_winIE
-   $is_macIE
-   $is_opera
-   $is_NS4
-   $is_safari
-   $is_chrome
-   $is_iphone
-   $is_IE

Do wykrywania serwerów mamy jeszcze następujące zmienne:

-   $is_apache
-   $is_IIS
-   $is_iis7

Ponadto można wykorzystać funkcję wp_is_mobile() szukającą słowa mobile
w ciągu tekstowym agenta użytkownika, a także kilku innych słów
najczęściej stosowanych w ciągach tekstowych agentów użytkownika
mobilnych przeglądarek WWW.

Oto krótki przykład pokazujący, jak wymienione wcześniej zmienne można
stosować do wczytywania różnych skryptów i arkuszy stylów CSS:

    <?php

    function sp_init_browser_hacks() {

        global $is_IE;

        if ( $is_IE ) {

            // Sprawdzenie wersji i wczytanie arkusza stylów CSS

            $user_agent = strtolower( $_SERVER['HTTP_USER_AGENT'] );

            if ( strpos( 'msie 6.', $user_agent ) !== false &&

                strpos( 'opera', $user_agent ) === false ) {

                wp_enqueue_style(

                    'ie6-hacks',

                    get_stylesheet_directory_uri() . '/css/ie6.css'

                );

            }

        }

        if ( wp_is_mobile() ) {

            // Wczytanie kodu CSS i JS przeznaczonego dla urządzeń mobilnych

            wp_enqueue_style(

                'sp-mobile',

                get_stylesheet_directory_uri() . '/css/mobile.css'

            );

            wp_enqueue_script(

                'sp-mobile',

                get_stylesheet_directory_uri() . '/js/mobile.js'

            );

        }

    }

    add_action( 'init', 'sp_init_browser_hacks' );

    ?>

Wykrywanie funkcjonalności za pomocą wywołania get_browser() w PHP

PHP ma doskonałą, wbudowaną w język funkcję wykrywania przeglądarki WWW:
get_browser(). Oto prosty skrypt pokazujący wywołanie funkcji
get_browser() i wyświetlenie typowych wyników jej działania:

    <?php

    $browser = get_browser();

    print_r($browser);

    /*

            Wygenerowane dane wyjściowe będą podobne do następujących:

            stdClass Object (

    [browser_name_regex] => §^mozilla/5\.0 \(.*intel mac os x.*\)

    applewebkit/.* \(khtml, like gecko\).*chrome/28\..*safari/.*$§

    [browser_name_pattern] => Mozilla/5.0 (*Intel Mac OS X*)

    AppleWebKit/* (KHTML, like Gecko)*Chrome/28.*Safari/*

    [parent] => Chrome 28.0

    [platform] => MacOSX

    [win32] =>

    [comment] => Chrome 28.0

    [browser] => Chrome

    [version] => 28.0

    [majorver] => 28

    [minorver] => 0

    [frames] => 1

    [iframes] => 1

    [tables] => 1

    [cookies] => 1

    [javascript] => 1

    [javaapplets] => 1

    [cssversion] => 3

    [platform_version] => unknown

    [alpha] =>

    [beta] =>

    [win16] =>

    [win64] =>

    [backgroundsounds] =>

    [vbscript] =>

    [activexcontrols] =>

    [ismobiledevice] =>

    [issyndicationreader] =>

    [crawler] =>

    [aolversion] => 0

    )

    */

To całkiem imponujące dane wyjściowe. Dlaczego ta funkcja została
wymieniona w sekcji dotyczącej wykrywania przeglądarki WWW z poziomu
PHP? Odpowiedź jest prosta: funkcja get_browser() pozostaje niedostępna
lub jest przestarzała na większości serwerów. Aby mogła dostarczyć
użyteczne informacje — lub w ogóle zadziałać — konieczne jest pobranie i
uaktualnienie pliku o nazwie browscap.ini oraz skonfigurowanie PHP do
odszukania tego pliku. Jeżeli chcesz rozpowszechniać aplikację, będziesz
musiał skorzystać z innej metody wykrywania możliwości oferowanych przez
przeglądarkę WWW. Jeżeli natomiast samodzielnie uruchamiasz własną
aplikację w swoim serwerze, możesz skorzystać z funkcji get_browser().

Uaktualniony plik browscap.ini znajdziesz w witrynie projektu Browser
Capabilities Project (http://browscap.org/). Upewnij się, że został
pobrany plik sformatowany dla PHP. Zachęcamy do pobrania pliku
lite_php_browscap.ini, który jest mniejszy o połowę od standardowego, a
jednocześnie zawiera informacje o najpopularniejszych przeglądarkach
WWW.

Po umieszczeniu na serwerze pliku .ini kolejnym krokiem jest
uaktualnienie pliku php.ini, aby wskazywał nowo dodany plik. Twój plik
php.ini prawdopodobnie zawiera już wiersz browscap umieszczony w
komentarzu. Usuń komentarz z początku wiersza i upewnij się, że ścieżka
dostępu prowadzi do miejsca, w którym znajduje się pobrany plik
browscap.ini. Ta sekcja może mieć postać podobną do następującej:

    [browscap]

    browscap = /etc/lite_php_browscap.ini

Teraz należy ponownie uruchomić serwer WWW (Apache, Nginx itd.), a
funkcja get_browser() zacznie działać zgodnie z oczekiwaniami.

Słowo końcowe na temat wykrywania przeglądarki WWW

Wprawdzie poświęciliśmy tutaj sporo miejsca na omówienie tematu
wykrywania przeglądarki WWW, ale w praktyce należy korzystać z tej
możliwości jedynie w ostateczności. Gdy określona przeglądarka WWW
sprawia problemy związane z fragmentem układu lub funkcjonalności,
kuszące może być zastosowanie funkcji wykrywania możliwości przeglądarki
WWW i znalezienie rozwiązania dla problemu. Jeżeli jednak istnieje inne
rozwiązanie, które zapewni podobny wynik bez uciekania się do
eliminowania określonej przeglądarki WWW, wówczas lepiej będzie
zastosować właśnie takie rozwiązanie.

Po pierwsze, ciąg tekstowy agenta użytkownika nie został
ustandaryzowany, o czym już wspomnieliśmy w rozdziale, i prawdopodobnie
będziesz musiał regularnie uaktualniać kod, aby przetwarzać go z
uwzględnieniem nowych przeglądarek WWW i ich wersji.

Po drugie, w pewnych przypadkach problem typowy dla danej przeglądarki
WWW jest symptomem większego problemu w kodzie. Być może istnieje inne
rozwiązanie pozwalające uprościć projekt lub funkcjonalność, aby w ten
sposób lepiej przygotować aplikację do pracy z wieloma różnymi
przeglądarkami WWW i urządzeniami wyposażonymi w różnej wielkości
ekrany.

Celem projektu responsywnego i programowania jest utworzenie aplikacji
na tyle elastycznej, aby działała w różnych przeglądarkach WWW i
klientach, niezależnie od tego, czy będą używane znane Ci przeglądarki
WWW i urządzenia.

[1] Jeżeli uznasz, że musisz zmodyfikować podstawowe pliki WordPressa w
celu otrzymania działającego rozwiązania, najpierw się zastanów, czy na
pewno musisz to zrobić. Jeżeli kiedykolwiek wystąpi konieczność zmiany
podstawowego pliku WordPressa, lepiej dodaj nowy zaczep i przekaż tę
poprawkę jako zgłoszenie zmiany do następnej wersji WordPressa.

[2] Dodaliśmy znaki nowego wiersza i usunęliśmy niektóre nawiasy
klamrowe, aby lepiej dopasować ten kod do strony w książce drukowanej.

[3] Można sprawdzić wartość $_SERVER['PHP_SELF'], aby ustalić, czy
bieżącą stroną jest wp-login.php. W omawianym przykładzie przyjęliśmy
założenie, że logowanie odbywa się na stronie ze slugiem login.

[4] Retina to stosowana przez Apple nazwa dla ekranów o wysokiej
rozdzielczości. Jednak ze słowem retina możesz się spotykać w
komentarzach do kodu oraz w dokumentacji, w odwołaniach do każdego
ekranu o wysokiej rozdzielczości.

Rozdział 5. Niestandardowe typy postów, metadane postów i taksonomie

Dzięki niestandardowym typom postów (ang. custom post type, CPT)
WordPress jest prawdziwym systemem zarządzania treścią. Dzięki CPT można
bardzo szybko przygotować niestandardową funkcjonalność i przechowywać
dane w spójny sposób.

Domyślne i niestandardowe typy postów

W domyślnej instalacji WordPressa masz wiele typów postów gotowych do
natychmiastowego użycia. Typy postów, które mogą być Ci już znane, to
strony i posty, choć poza nimi jest jeszcze kilka innych. Wartości
określające typy postów są przechowywane w tabeli wp_posts bazy danych,
a wszystkie używają właściwości post_type umożliwiającej odróżnianie
poszczególnych typów.

Strona

Strona WordPressa jest stosowana dla stron treści statycznej, np. dla
strony głównej, informacji o autorze, informacji kontaktowych, oraz do
tworzenia wszelkich innych stron. Strony mogą być zagnieżdżane w
nieskończoność w dowolnej strukturze hierarchicznej. Sortowanie stron
odbywa się za pomocą wartości menu_order.

Post

Posty są publikowane na blogu, w wiadomościach, a także w każdym innym
miejscu będącym treścią, która później jest indeksowana przez silniki
wyszukiwarek internetowych. Masz możliwość kategoryzowania postów,
oznaczania ich słowami kluczowymi, definiowania daty publikacji itd.
Ogólnie rzecz biorąc, posty są wyświetlane na liście widoku, w
kolejności chronologicznie odwrotnej, we frontendzie witryny
internetowej.

Załącznik

Gdy do serwera przekazujesz obraz lub plik, plik jest przechowywany nie
tylko na serwerze, ale również jako post w tabeli wp_posts wraz z
załącznikiem post_type.

Wersja

Ilekroć ktoś edytuje lub zapisuje post, WordPress tworzy jego kopię,
którą przechowuje jako oddzielną wersję. Ta funkcjonalność jest włączona
domyślnie i można ją wykorzystać do przywrócenia wcześniejszej wersji
treści, jeżeli zachodzi potrzeba, np. po uszkodzeniu treści w wyniku jej
edycji.

Czasami się zdarza, że gdy aplikacja wprowadza wiele zmian w
post_content, tabela wp_posts zapełnia się wersjami danego posta. Można
więc ograniczyć liczbę wersji przechowywanych w tabeli wp_posts. To
wymaga dodania do pliku wp-config.php następującego polecenia:

    define( 'WP_POST_REVISIONS', 5 );

W omawianym przykładzie będzie przechowywanych pięć wersji danego posta.
Wartość 0 oznacza wyłączenie przechowywania wcześniejszych wersji
postów. Wartość true lub -1 powoduje natomiast przechowywanie
nieskończonej liczby wersji (przechowywanie czegoś w nieskończoność może
wymagać ogromnej ilości miejsca na dysku).

Element menu nawigacyjnego

Za każdym razem, gdy tworzysz niestandardowy element menu WordPressa za
pomocą narzędzia WordPress Core Menu Builder (adres
wp-admin/appearance/menus), tak naprawdę przechowujesz posty wraz z
informacjami o menu.

Niestandardowe style CSS

Narzędzie Customizer ma ustawienie dla „dodatkowych arkuszy stylów CSS”.
Te style CSS są przechowywane w niestandardowym typie posta o nazwie
custom_Css. Dodatkowe style CSS mają zastosowanie w aktywnym motywie, a
każdy motyw ma oddzielny post typu custom_css przeznaczony do
przechowywania arkuszy stylów. Umieszczenie dodatkowych reguł CSS w
niestandardowym poście może wydawać się dziwne, ale takie rozwiązanie
zostało zastosowane ze względu na wydajność działania. Możesz sobie
wyobrazić witrynę internetową z ogromną liczbą niestandardowych stylów
CSS. Opcje są czasami automatycznie wczytywane lub buforowane, a te
systemy mogą ulec awarii albo działać znacznie wolniej w przypadku
użycia ogromnej ilości stylów CSS.

Changeset

Changeset przypomina wersje postów, ale jest przeznaczony dla ustawień,
a nie dla treści posta. Zmianę ustawień wprowadza się w narzędziu
Customizer, a ustawienia te są przechowywane w poście typu
customize_changeset. Jeżeli przypadkowo zamkniesz kartę przeglądarki WWW
i następnie powrócisz do narzędzia Customizer, WordPress zapyta, czy
przywrócić ustawienia z changeset.

Bufor oEmbed

WordPress umożliwia osadzanie treści z obsługiwanych dostawców oEmbed
poprzez umieszczenie adresu URL do treści w oddzielnym wierszu w
edytorze posta. Jeżeli adres URL do klipu wideo w YouTubie umieścisz w
oddzielnym wierszu, WordPress wykryje, że ten adres URL prowadzi do
YouTube’a, i wykona wywołanie do odpowiedniego adresu URL oEmbed, aby na
stronie Twojej witryny internetowej umieścić odtwarzacz klipu wideo.
Osadzony kod z żądania jest buforowany w niestandardowym typie posta
oembed_cache i zdefiniowany jako post potomny edytowanego posta.

Żądania użytkowników

Począwszy od wydania WordPress 4.9, administratorzy mają możliwość
zarządzania w imieniu użytkowników operacjami eksportowania i usuwania
danych osobowych[1]. Opcje przeznaczone do zarządzania operacjami
eksportowania i usuwania danych osobistych znajdziesz w menu Narzędzia
(Tools) panelu głównego. Żądania te są przechowywane w niestandardowym
typie posta user_request. Więcej informacji na temat obsługi tych żądań
znajdziesz w dokumentacji WordPressa dotyczącej funkcji
wp_create_user_request() na stronie https://developer.wordpress.org/
reference/functions/wp_create_user_request/.

Bloki kodu wielokrotnego użycia

Częścią nowego, wprowadzonego w WordPressie 5.0 edytora opartego na
blokach jest możliwość zapisywania konfigurowanych w poście bloków jako
bloków wielokrotnego użycia. Taki blok jest później przechowywany w
niestandardowym typie posta o nazwie wp_block. Więcej informacji na
temat wielokrotnego użycia bloków znajdziesz w rozdziale 11.

Definiowanie i rejestrowanie niestandardowych typów postów

Podobnie jak w przypadku domyślnych typów postów WordPressa, istnieje
możliwość tworzenia także własnych niestandardowych typów postów
przeznaczonych do zarządzania dowolnymi danymi, w zależności od rodzaju
budowanej aplikacji. Każdy CPT to tak naprawdę post używany w nieco inny
sposób. Masz możliwość zarejestrowania CPT dla potrawy z menu w
restauracji, dla auta u dealera samochodów, dla osoby w celu
przechowywania dokumentów i informacji np. o pacjencie w klinice, a
także w praktycznie każdym innym celu, jaki może Ci przyjść do głowy.
Każdy rodzaj treści można przechowywać jako post wraz z dołączonymi
plikami, niestandardowymi metadanymi i własnymi taksonomiami.

W naszym przykładzie SchoolPressa będziemy tworzyć niestandardowy typ
posta do zadań zadawanych uczniom w witrynie internetowej używanej przez
nauczycieli. Przyjmujemy założenie, że nauczyciel chce tworzyć posty,
aby móc zadawać pracę domową uczniom oraz umożliwić im wyszukiwanie tych
zadań w witrynie internetowej klasy. Nauczyciel chciałby mieć także
możliwość przekazywania niezbędnych uczniom dokumentów i odpowiadania na
ich pytania. Dlatego niestandardowy typ posta wydaje się odpowiednim
rozwiązaniem.

Wymienione informacje można przechowywać w taki sam sposób jak inne
posty i użytkownikowi końcowemu wyświetlać je w motywie za pomocą tej
samej pętli wp_query, z której korzystamy w innych postach.

register_post_type( $post_type, $args );

Do zarejestrowania niestandardowego typu posta jest używana funkcja
register_post_type(). W większości przypadków te typy postów będą
rejestrowane w pliku functions.php motywu lub w pliku wtyczki.
Wymieniona funkcja oczekuje podania dwóch parametrów: nazwy typu posta
i tablicy argumentów.

$post_type

Nazwa niestandardowego typu postów. W omawianym przykładzie nazwą będzie
homework. Ten ciąg tekstowy może mieć maksymalnie 20 znaków, przy czym
nie mogą to być wielkie litery, spacje ani żadne znaki specjalne poza
łącznikiem i znakiem podkreślenia. Jeżeli tworzysz wtyczkę do użytku
publicznego, stosuj prefiks w nazwie CTP, aby uniknąć konfliktów z
takimi samymi nazwami w innych wtyczkach.

$args

Tablica wielu różnych argumentów, które będą decydowały o sposobie
skonfigurowania niestandardowego typu posta.

Zapoznaj się teraz z listą wszystkich dostępnych argumentów i ich
przeznaczeniem.

label

Wyświetlana nazwa danego niestandardowego typu postów. W omawianym
przykładzie będzie to Homework.

labels

Opcjonalna tablica etykiet używanych do opisania typu postów w
interfejsie użytkownika.

name

Liczba mnoga wyświetlana dla typu postów. Ta wartość będzie nadpisywała
wartość argumentu label.

singular_name

Nazwa w liczbie pojedynczej dla posta. Jeżeli ta wartość nie zostanie
podana, domyślnie będzie nią wartość argumentu name.

add_new

Domyślnie jest to ciąg tekstowy Add New.

add_new_item

Domyślnie jest to ciąg tekstowy Add New Post.

edit_item

Domyślnie jest to ciąg tekstowy Edit Post.

new_item

Domyślnie jest to ciąg tekstowy New Post.

view_item

Domyślnie jest to ciąg tekstowy View Post.

search_items

Domyślnie jest to ciąg tekstowy Search Posts.

not_found

Domyślnie jest to ciąg tekstowy No Post Found.

not_found_in_trash

Domyślnie jest to ciąg tekstowy No posts found in Trash.

parent_item_colon

Domyślnie jest to ciąg tekstowy Parent Page: i jest używany tylko w
typach postów hierarchicznych.

all_items

Domyślnie jest to ciąg tekstowy All Posts.

menu_name

Nazwa menu dla typu posta, zwykle jest to taka sama wartość jak w
argumentach label lub label->name.

description

Opcjonalny ciąg tekstowy opisujący typ posta.

publicly_queryable

Opcjonalna wartość boolowska określająca, czy zapytanie typu posta może
być wykonane we frontendzie lub motywie aplikacji. Domyślnie opcja
publicly_queryable jest włączona.

exclude_from_search

Opcjonalna wartość boolowska określająca, czy typ posta może być używany
w zapytaniach i wyświetlany w domyślnych wynikach wyszukiwania
WordPressa. Ta opcja jest domyślnie wyłączona, co oznacza, że wszystkie
posty mogą być wyszukiwane.

capability_type

Opcjonalny ciąg tekstowy lub tablica. Jeżeli ta wartość nie zostanie
zdefiniowana, domyślnie będzie nią post. W ciągu tekstowym można
przekazać istniejący typ posta, a nowy typ posta, który właśnie
rejestrujesz, będzie dziedziczył możliwości po typie istniejącego posta.
Kolejna opcja to zdefiniowanie własnego typu możliwości dla
niestandardowego typu postów w zakresie odczytywania, publikowania,
edytowania i usuwania treści. Jeżeli dla tych możliwości chcesz używać
różnych słów dla liczb pojedynczej i mnogiej, możesz przekazać tablicę
wartości. W omawianym przykładzie można przekazać ciąg tekstowy
homework, ponieważ formy liczby pojedynczej i mnogiej są takie same.
Gdyby te formy były różne, należałoby przekazać tablicę, np. array( 'sub
mission', 'submissions' ).

capabilities

Opcjonalna tablica możliwości dla rejestrowanego typu posta. Można z
niej skorzystać zamiast z capability_type, gdy chcesz zachować większą
kontrolę nad możliwościami definiowanymi dla nowego niestandardowego
typu postów.

Istnieją dwa typy możliwości: meta i podstawowe. Możliwości meta są
powiązane z określonymi postami, podczas gdy podstawowe są bardziej
ogólne. W praktyce to oznacza, że sprawdzając użytkownika pod kątem
możliwości meta, trzeba przekazać parametr $post_id.

    // Możliwości meta są powiązane z określonymi postami

    if(current_user_can("edit_post", $post_id))

    {

    // Bieżący użytkownik może edytować post za pomocą ID = $post_id

    }

W przeciwieństwie do możliwości meta, możliwości podstawowe nie są
sprawdzane względem określonego posta.

    // Możliwości podstawowe nie są powiązane z określonymi postami

    if(current_user_can("edit_posts"))

    {

    // Bieżący użytkownik ogólnie może edytować posty

    }

Zapoznaj się teraz z możliwościami, które można przypisywać
niestandardowym typom postów.

edit_post

Możliwość meta umożliwiająca użytkownikowi edytowanie określonego posta.

read_post

Możliwość meta umożliwiająca użytkownikowi odczytywanie określonego
posta.

delete_post

Możliwość meta umożliwiająca użytkownikowi usuwanie określonego posta.

edit_posts

Możliwość podstawowa umożliwiająca użytkownikowi tworzenie i edytowanie
określonego posta.

edit_others_posts

Możliwość podstawowa umożliwiająca użytkownikowi edytowanie postów
innych użytkowników.

publish_posts

Możliwość podstawowa umożliwiająca użytkownikowi publikowanie postów.

read_private_posts

Możliwość podstawowa umożliwiająca użytkownikowi odczytywanie postów
prywatnych.

read

Możliwość podstawowa umożliwiająca użytkownikowi odczytywanie postów.

delete_posts

Możliwość podstawowa umożliwiająca użytkownikowi usuwanie postów.

delete_private_posts

Możliwość podstawowa umożliwiająca użytkownikowi usuwanie postów
prywatnych.

delete_published_posts

Możliwość podstawowa umożliwiająca użytkownikowi usuwanie opublikowanych
postów.

delete_others_posts

Możliwość podstawowa umożliwiająca użytkownikowi usuwanie postów innych
użytkowników.

edit_private_posts

Możliwość podstawowa umożliwiająca użytkownikowi edytowanie postów
prywatnych.

edit_published_posts

Możliwość podstawowa umożliwiająca użytkownikowi publikowanie postów.

map_meta_cap

Określenie, czy będzie używany wewnętrzny domyślny mechanizm obsługi
możliwości meta (omówienie możliwości i ról zamieściliśmy w rozdziale
6.). Wartością domyślną tego argumentu jest false. Możliwości zawsze
można zdefiniować samodzielnie za pomocą capabilities. Jeżeli tego nie
zrobisz i przypiszesz wartość true omawianemu argumentowi, wówczas
następujące możliwości będą używane domyślnie lub w połączeniu z
wymienionymi w capability_type: read, delete_posts,
delete_private_posts, delete_published_posts, delete_others_posts,
edit_private_posts i edit_published_posts.

hierarchical

Opcjonalna wartość boolowska określająca, czy post może być
hierarchiczny i czy może mieć post nadrzędny. Strony WordPressa są
definiowane w taki sposób, co pozwala na ich zagnieżdżanie. Ten argument
jest domyślnie wyłączony.

public

Opcjonalna wartość boolowska określająca, czy typ posta jest
przeznaczony do użycia publicznego, a nie w backendzie lub frontendzie
WordPressa. Domyślnie wartością tego argumentu jest false. Jeśli ten
argument nie jest dołączony i nie została mu przypisana wartość true, w
motywie nie można używać post_type. Jeżeli argumentowi public
przypiszesz wartość true, automatycznie zostaną zdefiniowane
exclude_from_search i publicly_queryable, a wartością show_ui_nav_menus
będzie true, o ile nie zdecydujesz inaczej.

Większość niestandardowych typów postów będzie dostępna publicznie, aby
mogły być wyświetlane we frontendzie lub dostępne do zarządzania za
pomocą panelu głównego WordPressa. Pozostałe CPT (np. domyślny typ
Revisions) są uaktualniane w tle na podstawie innych interakcji z
aplikacją i będą miały przypisaną wartość false argumentu public.

rewrite

Opcjonalna wartość boolowska lub tablica używana do utworzenia
niestandardowej struktury permalink dla typu posta. Domyślnie ten
argument ma przypisaną wartość true, a strukturą permalink dla
niestandardowego typu postów jest /typ_posta/tytuł_posta/. Jeżeli
omawianemu argumentowi przypiszesz wartość false, niestandardowa
struktura permalink nie zostanie utworzona. Masz możliwość całkowitego
dostosowania struktury permalink posta do własnych potrzeb. W tym celu
wystarczy przekazać tablicę wraz z wymienionymi tutaj argumentami.

slug

Domyślnie to typ_posta, choć może być to również dowolny ciąg tekstowy.
Pamiętaj, aby nie używać tego samego slugu w więcej niż jednym typie
postów, ponieważ muszą być unikatowe.

with_front

Ten argument określa, czy należy stosować prefiks na początku permalinku
niestandardowego typu postów. Jeżeli argumentowi przypiszesz wartość
true, wówczas slug „strony głównej” zdefiniowany w Ustawienia/Czytanie
(Settings/Reading) w panelu głównym będzie dodawany do struktury
permalink postów tego typu.

feeds

Wartość boolowska określająca, czy typ posta może mieć kanał wiadomości
RSS. Wartość domyślna tego argumentu jest równa wartości argumentu
has_archive. Jeżeli wartością argumentu feeds będzie false, kanał
wiadomości będzie niedostępny.

pages

Wartość boolowska włączająca stronicowanie dla danego typu postów.
Przypisanie jej wartości true powoduje, że strony archiwum danego typu
postów również będą obsługiwały stronicowanie.

ep_mask

EP, czyli punkty końcowe (ang. end points), mogą być bardzo użyteczne.
Dzięki temu argumentowi można przypisać maskę punktów końcowych dla
danego typu postów. Przykładowo dla typu postów homework można
zdefiniować punkt końcowy o nazwie pop-quiz. Wówczas struktura permalink
będzie miała postać /homework/post-title/pop-quiz/. W terminologii
architektury MVC niestandardowy typ postów można porównać do modułu,
punkty końcowe zaś do różnych widoków tego modułu. (Dokładne omówienie
punktów końcowych i innych funkcji przepisywania znajdziesz w rozdziale
7.).

has_archive

Opcjonalna wartość boolowska lub ciąg tekstowy określający, czy dany typ
posta może mieć stronę archiwum. Domyślnie ten argument ma przypisaną
wartość false. Dlatego jeśli w motywie chcesz skorzystać ze stron
archiwum dla danych typów postów, argumentowi has_archive musisz
przypisać wartość true. Plik archive-<typ_posta>.php w motywie zostanie
użyty do wygenerowania strony archiwum. Jeżeli ten plik będzie
niedostępny, zamiast niego zostanie wykorzystany plik archive.php lub
index.php.

query_var

Opcjonalna wartość boolowska lub ciąg tekstowy definiujący klucz
query_var dla typu posta. Jest to nazwa typu posta w bazie danych i jest
używana podczas tworzenia zapytań dla danego typu posta. Wartością
domyślną tego argumentu jest wartość argumentu post_type. W większości
przypadków wartości query_var i post_type nie muszą być różne, choć
można sobie wyobrazić długą nazwę typu posta, directory_entry, dla
której będziesz chciał stosować krótszy slug, np. dir.

supports

Opcjonalna wartość boolowska lub tablica określająca funkcje meta
dostępne dla strony nowego posta lub edycji posta. Domyślnie
przekazywana jest tablica wraz z argumentami title i editor. Oto lista
wszystkich argumentów (jeśli chcesz użyć któregoś z nich w
niestandardowym typie postów, upewnij się, że został umieszczony w
tablicy supports):

-   title
-   editor
-   comments
-   revisions
-   trackbacks
-   author
-   excerpt
-   page-attributes
-   thumbnail
-   custom-fields
-   post-formats

register_meta_box_cb

Opcjonalny ciąg tekstowy umożliwiający dostarczenie niestandardowej
funkcji wywołania zwrotnego przeznaczonej do obsługi integracji z
niestandardowymi metadanymi.

permalink_epmask

Opcjonalny ciąg tekstowy przeznaczony do określenia typów punktów
końcowych, które będą powiązane z niestandardowym typem postów. Domyślna
mapa bitowa podczas przepisywania punktu końcowego to EP_PERMALINK.
Więcej informacji na temat punktów końcowych znajdziesz w rozdziale 7.

taxonomies

Opcjonalna tablica z wyszczególnieniem wszelkich wbudowanych (kategorie
i tagi) lub niestandardowych zarejestrowanych taksonomii, które będziesz
chciał powiązać z typem posta. Domyślnie nie są wskazywane żadne
taksonomie. Więcej informacji na temat taksonomii znajdziesz w rozdziale
4.

show_ui

Opcjonalna wartość boolowska określająca, czy podstawowy interfejs
użytkownika posta będzie dostępny dla typu posta w backendzie. Wartością
domyślną jest wartość argumentu public. Jeżeli argument show_ui ma
przypisaną wartość false, nie będzie możliwości wypełniania postów z
obszaru administracyjnego backendu.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Dobrym rozwiązaniem jest przypisywanie argumentowi show_ui wartości true, nawet dla niestandardowych typów postów, które, ogólnie rzecz biorąc, nie będą dodawane ani edytowane za pomocą administracyjnego panelu głównego. Przykładowo wtyczka bbPress dodaje Topics i Replies jako CPT, które są dodawane i edytowane za pomocą interfejsu użytkownika forum we frontendzie. Jednak przypisanie wartości true argumentowi show_ui powoduje dostarczenie kolejnego interfejsu, za pomocą którego administratorzy mogą przeszukiwać i wyświetlać tematy i odpowiedzi na forum oraz nimi zarządzać.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

menu_position

Opcjonalna liczba całkowita używana do zdefiniowania kolejności
elementów menu typu posta w backendzie dla nawigacji po lewej stronie.

Artykuł opublikowany w serwisie WordPress Codex zawiera przydatną listę
najczęściej stosowanych wartości położenia menu
(https://wordpress.org/plugins/custom-post-type-ui/). Zamieszczone w nim
informacje pomogą w umieszczeniu elementu menu w CPT.

-   5: poniżej sekcji Wpisy (Posts),
-   10: poniżej sekcji Media,
-   15: poniżej sekcji Odnośniki (Links),
-   20: poniżej sekcji Strony (Pages),
-   25: poniżej sekcji Komentarze (Comments),
-   60: poniżej pierwszego separatora,
-   65: poniżej sekcji Wtyczki (Plugins),
-   70: poniżej sekcji Użytkownicy (Users),
-   75: poniżej sekcji Narzędzia (Tools),
-   80: poniżej sekcji Ustawienia (Settings),
-   100: poniżej drugiego separatora.

menu_icon

Opcjonalny ciąg tekstowy lub adres URL prowadzący do niestandardowej
ikony, która może być użyta do przedstawienia typu posta.

can_export

Opcjonalna wartość boolowska określająca, czy typ posta może być
eksportowany za pomocą narzędzia WordPressa dostępnego w menu
Narzędzia/Eksport (Tools/Export). Wartością domyślną tego argumentu jest
true, co oznacza, że administrator może eksportować posty.

show_in_nav_menus

Opcjonalna wartość boolowska określająca, czy posty danego typu mogą być
dodawane do niestandardowego menu nawigacyjnego w Wygląd/Menu
(Apperance/Menus). Wartością domyślną tego argumentu jest wartość
przypisana argumentowi public.

show_in_menu

Opcjonalna wartość boolowska lub ciąg tekstowy określający, czy typ
posta może być wyświetlony w menu administracyjnym backendu, a także
gdzie może być wyświetlony. Jeżeli wartością tego argumentu jest true,
typ posta będzie wyświetlany jako oddzielny element menu. Wartość false
natomiast oznacza, że dla danego typu posta nie będzie wyświetlany
element menu. Istnieje możliwość przekazania ciągu tekstowego
zawierającego nazwę innego, dowolnego elementu menu. To spowoduje
umieszczenie typu posta w podmenu tego elementu menu. Wartością domyślną
tego argumentu jest wartość przypisana argumentowi show_ui.

show_in_admin_bar

Opcjonalna wartość boolowska określająca, czy typ posta będzie dostępny
na pasku administracyjnym WordPressa. Wartością domyślną tego argumentu
jest wartość przypisana argumentowi show_ui_menu.

delete_with_user

Opcjonalna wartość boolowska określająca, czy można usunąć wszystkie
posty danego typu posta utworzone przez danego użytkownika. Jeżeli
wartością tego argumentu będzie true, posty utworzone przez użytkownika
będzie można przenieść do kosza po usunięciu użytkownika. Wartość false
natomiast oznacza, że usunięcie użytkownika nie spowoduje przeniesienia
jego postów do kosza. Domyślnie posty są przenoszone do kosza, jeśli
wartość argumentu post_type_supports zawiera author. W przeciwnym razie
posty nie zostaną przeniesione do kosza.

show_in_rest

Opcjonalna wartość boolowska określająca, czy niestandardowy typ postów
będzie udostępniony za pomocą API REST. Wartością domyślną tego
argumentu jest false. Więcej informacji na temat API REST znajdziesz w
rozdziale 10.

rest_base

Opcjonalny ciąg tekstowy pozwalający na zmianę slugu bazowego podczas
uzyskiwania dostępu do niestandardowego typu posta za pomocą API REST.
Wartością domyślną tego argumentu jest nazwa typu posta podana jako
pierwszy parametr funkcji register_post_type().

rest_controller_class

Opcjonalny ciąg tekstowy pozwalający na zmianę kontrolera używanego
podczas uzyskiwania dostępu do danego typu posta za pomocą API REST. Ten
argument powinien mieć przypisaną wartość WP_REST_Posts_Controller lub
nazwę klasy PHP dziedziczącej po WP_REST_Posts_Controller. Wartością
domyślną tego argumentu jest WP_REST_Posts_Controller.

_builtin

Raczej nie będziesz mieć potrzeby użycia tego argumentu. Domyślne typy
postów WordPressa używają go do odróżniania się od niestandardowych
typów postów.

_edit_link

Adres URL łącza edycji posta. Ten argument również jest przeznaczony do
użytku wewnętrznego, więc nie powinna zachodzić potrzeba jego
stosowania. Jeżeli chcesz zmienić stronę docelową po kliknięciu łącza
edycji posta, użyj filtru get_edit_post_link przekazującego łącze
domyślne z identyfikatorem posta.

Na listingu 5.1 przedstawiliśmy rejestrację CPT Homework i Submissions
za pomocą funkcji register_post_type(). Kod tej funkcji znajdziesz w
pliku wp-includes/post.php. Zwróć uwagę na to, że w omawianym
przykładzie wykorzystaliśmy tylko kilka z wielu dostępnych argumentów.

Listing 5.1. Rejestracja CPT

    <?php

    // Funkcja niestandardowa przeznaczona do zarejestrowania typu posta "homework"

    function schoolpress_register_post_type_homework() {

        register_post_type( 'homework',

            array(

                'labels' => array(

                    'name' => __( 'Homework' ),

                        'singular_name' => __( 'Homework' )

                    ),

                'public' => true,

                'has_archive' => true,

                )

            );

    }

    // Wywołanie funkcji niestandardowej z zaczepem init

    add_action( 'init', 'schoolpress_register_post_type_homework' );

    // Funkcja niestandardowa przeznaczona do zarejestrowania typu posta "submissions"

    function schoolpress_register_post_type_submission() {

        register_post_type( 'submissions',

            array(

                'labels' => array(

                    'name' => __( 'Submissions' ),

                    'singular_name' => __( 'Submission' )

                ),

                'public' => true,

                'has_archive' => true,

            )

        );

    }

    // Wywołanie funkcji niestandardowej z zaczepem init

    add_action( 'init', 'schoolpress_register_post_type_submission' );

    ?>

Jeżeli przedstawiony fragment kodu umieściłeś w pliku functions.php
aktywnego motywu lub aktywnej wtyczki, to w panelu administracyjnym
WordPressa powinieneś zauważyć dwa nowe elementy o nazwach Homework i
Submissions w menu Komentarze (Comments).

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeżeli masz dość tworzenia funkcji w celu rejestrowania różnych niestandardowych typów postów, których chcesz używać, zapoznaj się z przydatną wtyczką o nazwie Custom Post Type UI (https://wordpress.org/plugins/custom-post-type-ui/).
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Co to jest taksonomia i jak należy z niej korzystać?

Taksonomia została pokrótce omówiona w rozdziale 2. Możesz jednak w tym
miejscu zapytać, czym tak dokładnie ona jest. Otóż umożliwia grupowanie
postów według terminów. Pomyśl w tym miejscu o kategoriach postów i
tagach postów: są to wbudowane taksonomie powiązane z domyślnym typem
„posta”. Istnieje możliwość definiowania wielu niestandardowych
taksonomii lub kategorii, które będą rozpościerały się na wiele typów
postów. Przykładowo można zdefiniować taksonomię o nazwie Subject (z
ang. przedmiot), w której terminami są przedmioty nauczane w szkole, a
te terminy są powiązane z naszym niestandardowym typem postów Homework.

Taksonomie kontra metadane posta

Jednym z najczęściej pojawiających się pytań, gdy chcesz dołączyć dane
do postów, jest to, czy należy używać taksonomii, właściwości metadanych
posta czy jednego i drugiego. Ogólnie rzecz biorąc, terminy pozwalające
grupować różne posty powinny być definiowane jako taksonomie. Natomiast
dane charakterystyczne dla poszczególnych postów powinny być definiowane
jako właściwości metadanych.

Właściwości metadanych posta

Sprawdzają się w przypadku danych przeznaczonych dla poszczególnych
postów i nieużywanych do grupowania postów. W przypadku wtyczki
SchoolPress sensowne jest zdefiniowanie jako właściwości metadanych
elementów takich jak „wymagana długość pracy domowej” (np. 500 słów). W
praktyce stosowanych będzie tylko kilka różnych długości, nigdy nie
zajdzie potrzeba „zebrania wszystkich zadań wymagających 500 słów”.
Dlatego właściwości metadanych sprawdzają się doskonale dla takich
informacji.

Taksonomie

Sprawdzają się w sytuacjach, w których trzeba grupować posty. We wtyczce
SchoolPress sensowne jest zdefiniowanie jako taksonomii elementu takiego
jak przedmiot, z którego została zadana praca domowa (np. matematyka lub
język angielski). W przeciwieństwie do wielkości pracy domowej będzie
zachodziła konieczność wykonywania zapytań takich jak „pobierz pracę
domową z matematyki”. Będzie można łatwo to zrobić za pomocą zapytania
taksonomii. Co ważniejsze, takie zapytania będą dla taksonomii
wykonywane szybciej niż w przypadku właściwości metadanych.

Dlaczego zapytania taksonomii są szybsze? Właściwości metadanych są
przechowywane w tabeli wp_postmeta. Jeżeli data oddania pracy domowej
będzie przechowywana jako właściwości metadanych posta, będzie miała
następującą postać:

    meta_id post_id meta_key meta_value

    1       1       due_date 2018-09-07

    2       2       due_date 2018-09-14

Kolumny meta_id, post_id i meta_key są indeksowane, kolumna meta_value
już nie. To oznacza, że zapytania takie jak „pobierz datę oddania tej
pracy domowej” będą wykonywane szybko, natomiast zapytania w stylu
„pobierz pracę domową, która ma być oddana do 2018-09-07” będą
wykonywane wolniej, zwłaszcza w przypadku ogromnej witryny internetowej
z dużą ilością danych umieszczonych w tabeli wp_postmeta. Powodem, dla
którego meta_value to jedyna w tabeli wp_postmeta kolumna bez indeksu,
jest to, że dodanie indeksu spowodowałoby znaczne zwiększenie ilości
miejsca potrzebnego na przechowywanie tej tabeli, a także wydłużyłoby
czas wstawiania w niej danych. W praktyce witryna internetowa będzie
miała wiele różnej wielkości metadanych oraz mały zbiór identyfikatorów
postów i metadanych kluczy używanych do utworzenia indeksów.

Jeżeli data oddania pracy domowej będzie przechowywana w niestandardowej
taksonomii, to zapytanie w stylu „pobierz całą pracę domową dla danego
dnia” będzie wykonywane znacznie szybciej. Każda konkretna data będzie
terminem w tabeli wp_terms wraz z odpowiadającym jej wpisem w tabeli
wp_terms_taxonomy. Tabela wp_terms_relationships zawierająca terminy
dołączane do postów ma indeksowane właściwości object_id (posty są
obiektami) i term_taxonomy_id. Dlatego zapytanie typu „pobierz wszystkie
posty z term_taxonomy_id” są wykonywane bardzo szybko.

Jeżeli chcesz na stronie po prostu wyświetlić datę oddania pracy
domowej, przechowuj ją we właściwości metadanych. Jeśli natomiast chcesz
umożliwić pobieranie wszystkich prac domowych, które mają być wykonane
do określonej daty, rozważ dodanie taksonomii pozwalającej monitorować
taką datę.

Z drugiej strony ze względu na naturę daty (potencjalnie 365 nowych
terminów każdego roku) wykorzystanie taksonomii może być zbyteczne.
Skutkiem będzie wiele bezużytecznych terminów w bazie danych
przeznaczonych do monitorowania prac domowych, które miały być oddane
np. dwa lata temu.

Ponadto w tym konkretnym przypadku wzrost wydajności działania może być
niewidoczny, ponieważ zapytanie z pewną datą jest podzbiorem prac
domowych z określoną grupą klasy. W praktyce zapytania z pewną datą nie
będą wykonywane dla całej tabeli wp_postmeta. Zapytanie będzie
filtrowane do wykonania względem jedynie postów należących do określonej
klasy. Nawet jeśli tabela wp_postmeta będzie zawierała miliony rekordów
(w ogromnej witrynie internetowej używającej wtyczki SchoolPress tylko
niewiele z nich będzie dotyczyło pracy domowej w pewnej klasie lub
grupie klas, w których zajęciach uczestniczy uczeń.

Kolejna kwestia warta uwagi podczas wyboru między właściwościami
metadanych i taksonomiami to sposób zarządzania danymi przez
użytkowników. Jeżeli właściwość będzie wykorzystana jedynie w kodzie
backendu, nie potrzebujesz szybkich zapytań, a przechowywanie informacji
w metadanych postów jest proste i sprowadza się do wywołania funkcji
update_post_meta(). Jeżeli podobnie jak administratorzy chcesz mieć
możliwość tworzenia nowych terminów, tworzenia dla nich opisów,
budowania hierarchii, stosowania rozwijanych menu lub pól wyboru do
przypisywania danych postom, dokładnie wymieniliśmy korzyści, jakie
uzyskasz po zarejestrowaniu taksonomii. Podczas stosowania właściwości
metadanych postów konieczne będzie przygotowanie własnego interfejsu
użytkownika.

Wcześniej wspomnieliśmy o sytuacjach, w których dobrze jest używać
jednocześnie właściwości metadanych i taksonomii w celu monitorowania
pewnych danych. Przykładem takiej sytuacji w aplikacji SchoolPress jest
monitorowanie książki i rozdziału w związku z pracą domową. Wyobraź
sobie, że chcesz wygenerować dla ucznia raport z wszystkimi zadanymi mu
pracami domowymi ułożonymi według książek i ich rozdziałów. Ponieważ
chcesz umożliwić nauczycielom zarządzanie książkami jako terminami w
menu administracyjnym i umożliwić wykonywanie zapytań w stylu „pobierz
wszystkie prace domowe obejmujące tę książkę”, sensowne jest
przechowywanie książek w niestandardowych taksonomiach.

Z drugiej strony rozdziały mogą być przechowywane we właściwościach
metadanych posta. Rozdziały często pojawiają się w książkach i pracach
domowych, ale nie ma sensu wykonywanie zapytania „pobierz wszystkie
rozdziały 1. w pracy domowej” dla różnych książek. Skoro będziemy mieli
możliwość filtrowania prac domowych według książek lub uczniów, można
użyć właściwości metadanych w postaci rozdziału lub prawdopodobnie
właściwości textbook_chapter wraz z danymi w stylu „PodstawyAlgebry.R1”
w celu przygotowania niezbędnego zestawienia.

Skoro już wiesz, kiedy używać taksonomii, pora dowiedzieć się, jak je
tworzyć.

Tworzenie niestandardowych taksonomii

Do zarejestrowania taksonomii służy funkcja register_taxonomy()
zdefiniowana w pliku wp-includes/taxonomy.php.

register_taxonomy( $taxonomy, $object_type, $args )

Funkcja register_taxonomy() akceptuje trzy parametry:

$taxonomy

Wymagany ciąg tekstowy nazwy taksonomii. W omawianym przykładzie nazwą
taksonomii jest subject.

$object_type

Wymagana tablica lub ciąg tekstowy niestandardowego typu postów, który
będzie dołączony do tej taksonomii. W omawianym przykładzie użyjemy
ciągu tekstowego i dołączymy taksonomię subject do typu postów homework.
Istnieje możliwość podania więcej niż jednego typu postów — w tym celu
należy przekazać tablicę nazw typów postów.

$args

Opcjonalna tablica wielu argumentów określających sposób konfiguracji
niestandardowej taksonomii. Zwróć uwagę na to, że w omawianym
przykładzie wykorzystamy tylko kilka z wielu argumentów, które mogłyby
zostać przekazane funkcji register_taxonomy().

Oto lista wszystkich dostępnych argumentów:

label

Opcjonalny ciąg tekstowy wyświetlający nazwę taksonomii.

labels

Opcjonalna tablica etykiet używanych do opisania taksonomii w
interfejsie użytkownika.

name

Liczba mnoga wyświetlanej nazwy taksonomii. Ten argument nadpisuje
wartość argumentu label.

singular_name

Nazwa jednego obiektu danej taksonomii. Wartością domyślną jest
Category.

search_items

Wartością domyślną jest Search Categories.

popular_items

Ten ciąg tekstowy nie jest używany w taksonomiach hierarchicznych.
Wartością domyślną jest Popular Tags.

all_items

Wartością domyślną jest All Categories.

parent_item

Ciąg tekstowy używany tylko w taksonomiach hierarchicznych. Wartością
domyślną jest Parent Category.

parent_item_colon

Wartość tego argumentu jest taka sama jak argumentu parent_item, ale bez
dwukropka na końcu.

edit_item

Domyślnie jest to ciąg tekstowy Edit Category.

view_item

Domyślnie jest to ciąg tekstowy View Category.

update_item

Domyślnie jest to ciąg tekstowy Update Category.

add_new_item

Domyślnie jest to ciąg tekstowy Add New Category.

new_item_name

Domyślnie jest to ciąg tekstowy New Category Name.

separate_items_with_commas

Ciąg tekstowy używany w taksonomiach niehierarchicznych. Wartością
domyślną jest ciąg tekstowy Separate tags with commas.

add_or_remove_items

Ciąg tekstowy używany w taksonomiach niehierarchicznych. Wartością
domyślną jest ciąg tekstowy Add or remove tags.

choose_from_most_used

Ciąg tekstowy używany w taksonomiach niehierarchicznych. Wartością
domyślną jest ciąg tekstowy Choose from the most used tags.

hierarchical

Opcjonalna wartość boolowska wskazująca, czy taksonomia jest
hierarchiczna lub czy termin taksonomii może mieć terminy nadrzędne bądź
podrzędne. To przypomina domyślne kategorie taksonomii, a taksonomie
niehierarchiczne przypominają domyślne tagi taksonomii. Wartością
domyślną tego argumentu jest false.

update_count_callback

Opcjonalny ciąg tekstowy, który działa jak zaczep. Jest wywoływany po
uaktualnieniu liczby powiązanych z nim typów postów.

rewrite

Opcjonalna wartość boolowska lub tablica używana w celu dostosowania do
własnych potrzeb struktury permalink taksonomii. Wartością domyślną tego
argumentu jest slug taksonomii.

query_var

Opcjonalna wartość boolowska lub ciąg tekstowy, który może być używany w
celu dostosowania do własnych potrzeb query_var i ?$query_var=$term.
Domyślnie wartością query_var jest nazwa taksonomii.

public

Opcjonalna wartość boolowska określająca, czy taksonomia jest
przeznaczona do użycia publicznego, w backendzie lub frontendzie
WordPressa. Domyślnie wartością tego argumentu jest false. Jeśli ten
argument nie zostanie dołączony i nie zostanie mu przypisana wartość
true, w motywie nie można używać danej taksonomii. Jeżeli argumentowi
public przypiszesz wartość true, automatycznie zostaną zdefiniowane
show_ui i publicly_queryable, a wartością show_ui_nav_menus będzie true,
o ile nie zdecydujesz inaczej.

publicly_queryable

Opcjonalna wartość boolowska określająca, czy zapytanie taksonomii może
być wykonane we frontendzie lub motywie aplikacji. Domyślnie opcja
publicly_queryable jest włączona.

show_ui

Opcjonalna wartość boolowska określająca, czy interfejs użytkownika
taksonomii będzie dostępny w administracyjnym interfejsie użytkownika w
backendzie, podobnie jak ma to miejsce dla interfejsu użytkownika tagów.
Wartością domyślną jest wartość argumentu public.

show_in_nav_menus

Opcjonalna wartość boolowska określająca, czy taksonomia może być
dodawana do niestandardowego menu nawigacyjnego. Wartością domyślną tego
argumentu jest wartość przypisana argumentowi public.

show_in_rest

Opcjonalna wartość boolowska określająca, czy taksonomia będzie
udostępniona za pomocą API REST. Wartością domyślną tego argumentu jest
false. Więcej informacji na temat API REST znajdziesz w rozdziale 10.

rest_base

Opcjonalny ciąg tekstowy pozwalający na zmianę slugu bazowego podczas
uzyskiwania za pomocą API REST dostępu do niestandardowego typu posta z
daną taksonomią. Wartością domyślną tego argumentu jest nazwa pierwszego
parametru funkcji register_axonomy().

rest_controller_class

Opcjonalny ciąg tekstowy pozwalający na zmianę kontrolera używanego
podczas uzyskiwania za pomocą API REST dostępu do postów z daną
taksonomią. Ten argument powinien mieć przypisaną wartość
WP_REST_Terms_Controller lub nazwę klasy PHP dziedziczącej po tej
klasie.

show_tagcloud

Opcjonalna wartość boolowska określająca, czy dana taksonomia może być
dołączona w widżecie Tag Cloud Widget. Wartością domyślną tego argumentu
jest wartość argumentu show_ui.

show_admin_column

Opcjonalna wartość boolowska określająca, czy nowa kolumna będzie
tworzona dla taksonomii typu posta dołączanej do danego typu posta na
stronie edycji lub listy postów w backendzie. Wartością domyślną jest
false.

capabilities

Opcjonalna tablica możliwości dla danej taksonomii. Domyślnie jest to
none. Istnieje możliwość przekazania następujących argumentów i/lub
wszelkich niestandardowych możliwości.

-   manage_terms
-   edit_terms
-   delete_terms
-   assign_terms

W przykładzie typu posta homework utworzymy taksonomię o nazwie Subject,
co pozwoli później tworzyć terminy dla każdego przedmiotu, np.
matematyki, fizyki itd.

    <?php

    // Funkcja niestandardowa przeznaczona do rejestracji taksonomii "subject"

    function schoolpress_register_taxonomy_subject() {

        register_taxonomy(

            'subject',

            'homework',

            array(

                'label' => __( 'Subjects' ),

                'rewrite' => array( 'slug' => 'subject' ),

                'hierarchical' => true

            )

        );

    }

    // Wywołanie funkcji niestandardowej z zaczepem init

    add_action( 'init', 'schoolpress_register_taxonomy_subject' );

    ?>

Zwróć uwagę, że w przedstawionym fragmencie kodu taksonomia została
skonfigurowana jak kategoria posta, ponieważ wartością jej argumentu
hierarchical jest true. Możesz utworzyć dowolną liczbę przedmiotów i je
zagnieżdżać.

W backendzie, a dokładnie w sekcji Homework/Subjects, możesz dodawać
terminy tak samo jak nowe kategorie do posta.

register_taxonomy_for_object_type( $taxonomy, $object_type )

Co się stanie, gdy zechcesz użyć taksonomii domyślnej w niestandardowym
typie postów? Jeżeli w typie postów homework chcesz użyć tych samych
tagów taksonomii, które zostały dołączone do typu posta, możesz
wykorzystać funkcję register_taxonomy_for_object_type(), aby dołączyć
taksonomię do typu posta. Ta funkcja została zdefiniowana w pliku
wp-includes/taxonomy.php.

Funkcja register_taxonomy_for_object_type() akceptuje dwa parametry:

$taxonomy

Zwraca ciąg tekstowy nazwy taksonomii.

$object_type

Wymagany ciąg tekstowy nazwy typu posta, do którego ma być dołączona
taksonomia.

W omawianym przykładzie dołączmy domyślne tagi taksonomii do
niestandardowego typu posta homework.

    <?php

    function schoolpress_register_taxonomy_for_object_type_homework(){

        register_taxonomy_for_object_type( 'post_tag', 'homework' );

    }

    add_action( 'init', 'schoolpress_register_taxonomy_for_object_type_homework' );

    ?>

Po uruchomieniu przykładu zauważysz, że „tagi” taksonomii są teraz
dostępne w elemencie menu Homework. Wtyczka Custom Post Types UI
(https://wordpress.org/plugins/custom-post-type-ui/) oferuje interfejs
użytkownika przeznaczony do tworzenia niestandardowych taksonomii i
zarządzania nimi.

Stosowanie niestandardowych typów postów i taksonomii we własnych motywach i wtyczkach

W kolejnych sekcjach poznasz kilka kwestii, o których trzeba pamiętać
podczas stosowania niestandardowych typów postów we własnych motywach
lub wtyczkach.

Szablony stron archiwum i pojedynczego posta w motywie

Większość motywów WordPressa ma plik o nazwie archive.php, który
generuje post na stronie archiwum lub listy postów, a także plik
single.php, który generuje informacje o pojedynczym poście. Bardzo łatwo
można utworzyć dedykowane strony archiwum i pojedynczych postów
przeznaczone dla zarejestrowanych niestandardowych typów postów.

Utwórz kopię pliku archive.php i zmień jego nazwę na
archive-homework.php. Otrzymasz automatycznie stronę, która wyświetla
archiwum wszystkich postów zawierających pracę domową, w tym samym
formacie, który jest stosowany dla stron archiwum zwykłych postów
(nazwa_domeny. com/homework/).

Tę samą metodę można zastosować względem pliku single.php. Utwórz jego
kopię i zmień jej nazwę na single-homework.php. Otrzymasz stronę
wyświetlającą pojedynczy post pracy domowej
(nazwa_domeny.com/homework/nazwa_przedmiotu/). Teraz można zmienić kod
znaczników dla pliku strony archiwum lub pojedynczego posta
niestandardowego typu, aby dane zostały wyświetlone inaczej niż zwykłe
posty bloga.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Aby użyć niestandardowego pliku strony archiwum, konieczne jest przypisanie wartości true argumentowi has_archive podczas rejestrowania niestandardowego typu postów. Argument has_archive jest częścią funkcji register_post_type().
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Stare dobre komponenty WP_Query i get_posts()

W pewnych sytuacjach utworzenie stron .php dla archiwum i pojedynczego
posta dla niestandardowych typów postów może być niewystarczające, by
zapewnić wymaganą funkcjonalność. Co się stanie, gdy zechcesz
przeprowadzić w widżecie paska bocznego lub w innym miejscu na stronie
iterację przez wszystkie posty określonych typów? Dzięki klasie WP_Query
i funkcji get_posts() możesz parametrowi post_type przypisać zapytanie i
przeprowadzić iterację przez niestandardowe typy postów, podobnie jak
robisz to podczas pracy ze zwykłymi postami.

Na listingu 5.2 pokazaliśmy przygotowanie formularza oddania pracy
domowej wyświetlanego poniżej dowolnej treści pojedynczego posta typu
homework.

Listing 5.2. Formularz oddania pracy domowej

    <?php

    function schoolpress_the_content_homework_submission($content){

        global $post, $current_user;

        // Nie dotyczy innych typów postów niż homework

        if ( ! is_single() || $post->post_type != 'homework' )

            return $content;

        // Nie dotyczy, jeśli użytkownik nie jest zalogowany

        if ( ! is_user_logged_in() )

            return $content;

            // Sprawdzenie, czy bieżący użytkownik faktycznie wysłał formularz,

            // oddając w ten sposób pracę domową

            $submissions = get_posts( array(

                'post_author'    => $current_user->ID,

                    'posts_per_page' => '1',

                    'post_type'      => 'submissions',

                    'meta_key'       => '_submission_homework_id',

                    'meta_value'     => $post->ID

                ) );

                foreach ( $submissions as $submission ) {

                    $submission_id = $submission->ID;

                }

                // Przetworzenie formularza

                if ( !$submission_id &&

                        isset( $_POST['submit-homework-submission'] ) &&

                        isset( $_POST['homework-submission'] ) ) {

                    $submission = $_POST['homework-submission'];

                    $post_title = $post->post_title;

                    $post_title .= ' - przekazana przez ' . $current_user->display_name;

                    // Wstawienie danych bieżącego użytkownika jako posta

                    // podczas wysyłania niestandardowego typu postów

                    $args = array(

                        'post_title'   => $post_title,

                        'post_content' => $submission,

                        'post_type'    => 'submissions',

                        'post_status'  => 'publish',

                        'post_author'  => $current_user->ID

                    );

                    $submission_id = wp_insert_post( $args );

                    // Dodanie metadanych posta do wysyłanego formularza

                    add_post_meta( $submission_id, '_submission_homework_id',

                        $post->ID );

                    // Utworzenie niestandardowego komunikatu

                    $message = __(

                        'Praca domowa została oddana i czeka na ocenę.',

                        'schoolpress'

                    );

                    $message = '<div class="homework-submission-message">' . $message .

                    '</div>';

                    // Wyświetlenie komunikatu przed filtrowaną zmienną $content

                    $content = $message . $content;

                }

                // Dodanie łącza do wysłanego formularza użytkownika, jeśli wysłał on już formularz

                if( $submission_id ) {

                    $message = sprintf( __(

                    'Kliknij %s tutaj %s, aby wyświetlić oddaną pracę domową.',

                    'schoolpress' ),

                    '<a href="' . get_permalink( $submission_id ) . '">',

                    '</a>' );

                    $message = '<div class="homework-submission-link">' . $message .

                    '</div>';

                    $content .= $message;

                // Dodanie prostego formularza po filtrowanej zmiennej $content

                } else {

                    ob_start();

                ?>

             <h3><?php _e( 'Wyślij pracę domową!', 'schoolpress' );?></h3>

             <form method="post">

            <?php

            wp_editor( '', 'homework-submission', array( 'media_buttons' => false ) );

            ?>

             <input type="submit" name="submit-homework-submission" value="Wyślij" />

             </form>

            <?php

            $form = ob_get_contents();

            ob_end_clean();

            $content .= $form;

        }

        return $content;

    }

    // Dodanie filtra w 'the_content', co pozwoli wykonać niestandardowy kod

    // przeznaczony do obsługi oddanej pracy domowej

    add_filter( 'the_content', 'schoolpress_the_content_homework_submission', 999 );

    ?>

Prawdopodobnie zauważyłeś, że jeszcze nie omówiliśmy następujących
funkcji:

ob_start()

Funkcja PHP używana do włączenia buforowania danych wyjściowych. Gdy
buforowanie danych wyjściowych jest włączone, przeglądarce WWW nie
zostaną przekazane żadne dane. Zamiast tego dane wyjściowe są
przechowywane w wewnętrznym buforze.

wp_editor()

Funkcja WordPressa udostępniająca ten sam edytor typu WYSIWYG, który
masz dostępny podczas tworzenia lub edytowania posta. Tę funkcję możesz
wywoływać wszędzie tam, gdzie chcesz mieć dostęp do edytora. Formularz
przeznaczony do oddania pracy domowej będzie doskonałym miejscem
wyświetlenia takiego edytora. Dokładne omówienie wszystkich parametrów
tej funkcji znajdziesz w rozdziale 7.

ob_get_contents()

Funkcja PHP, w której została zdefiniowana zmienna o nazwie $form.
Powoduje to, że cała treść między wywołaniem funkcji ob_start() i
funkcją ob_get_contents() trafi do zmiennej o nazwie $form.

ob_end_clean()

Funkcja PHP, która usuwa zawartość bufora danych wyjściowych i wyłącza
buforowanie danych wyjściowych.

Omówione funkcje zostały zastosowane w podanej kolejności, ponieważ
wp_editor() obecnie nie ma argumentu pozwalającego na zwrot edytora jako
zmiennej i po wywołaniu wyświetla edytor w przeglądarce WWW. Jeżeli nie
użyjesz tych funkcji, nie będziesz mieć możliwości umieszczenia edytora
po przekazaniu zmiennej $content do filtra the_content.

W kolejnym fragmencie kodu pokazaliśmy, jak się upewnić, że tylko
administratorzy mają dostęp do oddanych prac domowych, a pozostali
użytkownicy mogą jedynie uzyskać dostęp do własnych prac domowych.

    <?php

    function schoolpress_submissions_template_redirect(){

        global $post, $user_ID;

        // Ta funkcja będzie wywołana jedynie dla podanego typu posta

        if ( $post->post_type != 'submissions' )

            return;

        // Sprawdzenie, czy wartość post_author odpowiada wartości current user_ID

        if ( $post->post_author == $user_ID )

            $no_redirect = true;

        // Sprawdzenie, czy bieżący użytkownik jest administratorem

        if ( current_user_can( 'manage_options' ) )

            $no_redirect = true;

        // Jeżeli wartością $no_redirect jest false, należy przekierować użytkownika na stronę główną

        if ( ! $no_redirect ) {

            wp_redirect( home_url() );

            exit();

        }

    }

    // Użycie zaczepu template_redirect do wywołania funkcji ustalającej, czy bieżący

    // użytkownik może uzyskać dostęp do oddanej właśnie pracy domowej

    add_action( 'template_redirect', 'schoolpress_submissions_template_redirect' );

    ?>

Metadane w niestandardowych typach postów

Funkcje metadanych postów dokładnie omówione w rozdziale 2. można
stosować także z niestandardowymi typami postów. Pobieranie, dodawanie,
uaktualnienie i usuwanie metadanych postów odbywa się dokładnie tak
samo, niezależnie od typów postów.

Jeżeli zarejestrowałeś niestandardowy typ postów i dodałeś custom-fields
w argumencie supports, wówczas domyślnie podczas dodawania nowego posta
lub edytowania istniejącego posta danego typu zobaczysz pole metadanych
o nazwie Własne pola (Custom Fields). Powinno być Ci już znane: jest to
bardzo prosty formularz umożliwiający obsługę metadanych dodawanych do
posta.

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeżeli na dole strony edycji posta nie znajduje się sekcja Własne pola (Custom Fields), trzeba ją włączyć. Jeśli korzystasz z edytora bloków (Block Editor), kliknij opcję Więcej narzędzi (More Tools), a następnie przycisk Opcje (Options), który ma postać trzech kropek w prawym górnym rogu. Na dole strony kliknij Opcje (Options), a potem w sekcji Zaawansowane panele (Advanced Panels) odszukaj pole wyboru zatytułowane Własne pola (Custom Fields). Jeśli używasz edytora klasycznego, w prawym górnym rogu kliknij kartę Opcje ekranu (Screen Options), a następnie odszukaj pole wyboru Własne pola (Custom Fields).
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Co można zrobić w sytuacji, gdy w backendzie potrzebny jest bardziej
elegancki interfejs użytkownika dla metadanych? W kolejnej sekcji
zajmiemy się przygotowaniem odpowiedniego rozwiązania.

add_meta_box( $id, $title, $callback, $screen, $context, $priority, $callback_args )

Funkcja add_meta_box() powoduje dodanie na jednym lub więcej ekranach
elementu obsługi metadanych.

$id

Wymagany ciąg tekstowy unikalnego identyfikatora dla tworzonego elementu
obsługi metadanych.

$title

Wymagany ciąg tekstowy tytułu i widocznej nazwy dla tworzonego elementu
obsługi metadanych.

$callback

Wymagany ciąg tekstowy nazwy funkcji, która będzie wywoływana w celu
umieszczenia danych HTML w tworzonym elemencie obsługi metadanych.

$screen

Opcjonalny ekran lub ekrany, na których zostanie wyświetlony element
obsługi metadanych. Ta funkcja akceptuje identyfikator, obiekt
WP_Screen, tablicę identyfikatorów ekranów. Wartością domyślną jest
null.

$context

Opcjonalny ciąg tekstowy kontekstu, w którym na stronie powinien zostać
wyświetlony element obsługi metadanych (normal, advanced, side).
Wartością domyślną jest advanced.

$priority

Opcjonalny ciąg tekstowy priorytetu, z jakim powinien zostać wyświetlony
element obsługi metadanych (high, low).

$calback_args

Opcjonalna tablica argumentów, które będą przekazywane funkcji wywołania
zwrotnego wskazanej za pomocą parametru $callback. Ta funkcja wywołania
zwrotnego będzie automatycznie otrzymywała obiekt $post i wszelkie
pozostałe, zdefiniowane tutaj argumenty.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Wprawdzie koncentrujemy się tu na dodawaniu elementów obsługi metadanych na ekranie edycji posta, ale takie rozwiązanie można stosować na dowolnym ekranie administracyjnym. Jeżeli elementów obsługi metadanych chcesz używać na własnych stronach, to parametrowi screen musisz przypisać unikatową wartość, a następnie w funkcji wywołania zwrotnego wywołaj funkcję do_meta_boxes() (https:// developer.wordpress.org/reference/functions/do_meta_boxes/) dla danego ekranu. Jest to dobre rozwiązanie dla stron zestawień lub innych stron, na których chcesz umożliwić użytkownikom ukrywanie elementów, zmianę ich położenia, a także dodawanie nowych elementów za pomocą niestandardowych zaczepów.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Na listingu 5.3 pokazaliśmy sposób utworzenia niestandardowego elementu
obsługi metadanych dla wszystkich postów typu homework. Ten element
obsługi metadanych będzie zawierał pole wyboru określające, czy
konieczne jest oddanie pracy domowej, a także element wyboru daty, do
której praca domowa ma zostać oddana.

Listing 5.3. Niestandardowy element obsługi metadanych

    <?php

    // Funkcja wywołania zwrotnego odpowiedzialna za dodanie elementu obsługi metadanych

    function schoolpress_homework_add_meta_boxes(){

        add_meta_box(

            'homework_meta',

            'Informacje dodatkowe',

            'schoolpress_homework_meta_box',

            'homework',

            'side'

        );

    }

    // Użycie zaczepu add_meta_boxes do wywołania funkcji odpowiedzialnej za dodanie elementu obsługi metadanych

    add_action( 'add_meta_boxes', 'schoolpress_homework_add_meta_boxes' );

    // To jest funkcja wywołania zwrotnego wywoływana z poziomu elementu obsługi metadanych

    function schoolpress_homework_meta_box( $post ){

        // Użyliśmy tutaj dwóch wierszy, aby adres URL zmieścił się na stronie wydrukowanej książki

        $smoothness_url = 'http://ajax.googleapis.com/ajax/libs/';

        $smoothness_url.= 'jqueryui/1.12.1/themes/smoothness/jquery-ui.css';

        // Element wyboru daty w jQuery

        wp_enqueue_script( 'jquery-ui-datepicker' );

        wp_enqueue_style( 'jquery-style', $smoothness_url );

        // Zdefiniowanie metadanych, o ile istnieją

        $is_required = get_post_meta( $post->ID,

            '_schoolpress_homework_is_required', 1 );

        $due_date = get_post_meta( $post->ID,

            '_schoolpress_homework_due_date', 1 );

        // Wyświetlenie właściwości metadanych

        ?>

        <p>

        <input type="checkbox"

        name="is_required" value="1" <?php checked( $is_required, '1' ); ?>>

        Ta praca domowa jest obowiązkowa.

        </p>

        <p>

        Data oddania:

        <input type="text"

        name="due_date" id="due_date" value="<?php echo $due_date;?>">

        </p>

        <script>

        // Dołączenie elementu wyboru daty w jQuery do właściwości due_date 

        jQuery(document).ready(function() {

            jQuery('#due_date').datepicker({

                dateFormat : 'dd/mm/yy'

            });

        });

        </script>

    <?php

    }

    // Funkcja wywołania zwrotnego zapisująca metadane w bazie danych

    function schoolpress_homework_save_post( $post_id ){

        // Żadne dane nie będą zapisywane w przypadku włączenia automatycznego zapisu w WordPressie

        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )

            return $post_id;

        // Sprawdzenie poprawności typu posta i uprawnień użytkownika

        if ( 'homework' == $_POST['post_type'] ) {

            if ( ! current_user_can( 'edit_page', $post_id ) )

                return $post_id;

        } else {

            if ( ! current_user_can( 'edit_post', $post_id ) )

                return $post_id;

        }

        // Uaktualnienie metadanych

        update_post_meta( $post_id,

            '_schoolpress_homework_is_required',

            $_POST['is_required']

        );

        update_post_meta( $post_id,

            '_schoolpress_homework_due_date',

            $_POST['due_date']

        );

    }

    // Wywołanie funkcji wywołania zwrotnego w celu obsługi operacji zapisu metadanych

    add_action( 'save_post', 'schoolpress_homework_save_post' );

    ?>

Jeżeli jesteś dobrym programistą, prawdopodobnie zadajesz sobie pytanie:
dlaczego tak? Dlaczego wartości $_POST nie są oczyszczane? Jeżeli o tym
nie pomyślałeś, to niedobrze, ponieważ zapewnienie bezpieczeństwa to
bardzo ważna kwestia. Jeżeli nie bardzo wiesz, co mamy na myśli, zajrzyj
do rozdziału 8., w którym znacznie dokładniej przedstawiliśmy najlepsze
praktyki stosowane podczas tworzenia kodu. Celowo pominęliśmy pewne
mechanizmy w omawianym przykładzie, aby zachować jego prostotę i
zmniejszyć ilość kodu. Jeżeli będziesz pracować nad własnych projektem,
zawsze pamiętaj o oczyszczaniu i sprawdzaniu danych.

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Zalecamy, aby podczas tworzenia elementów obsługi metadanych i niestandardowych właściwości metadanych wykorzystywać wtyczkę CMB2 (https://github.com/CMB2/ CMB2). Możesz ją bardzo prosto zintegrować z motywem lub inną wtyczką, aby móc szybko i łatwo tworzyć niestandardowe elementy obsługi metadanych i właściwości metadanych wewnątrz nich.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Stosowanie elementów obsługi metadanych w edytorze bloków

Funkcja add_meta_box() działa z edytorem bloków i z edytorem klasycznym.
W obu przypadkach elementy obsługi metadanych są dodawane z kontekstem
side, co spowoduje wyświetlenie elementu w prawym pasku bocznym na
ekranie edycji posta. W edytorze klasycznym wszystkie elementy obsługi
metadanych zawsze pozostają widoczne[2]. W edytorze bloków natomiast
elementy te są wyświetlane w karcie Dokument (Document) w pasku bocznym
po prawej stronie.

W obu wersjach edytora element obsługi metadanych dodawany z kontekstem
normal lub advanced zostanie wyświetlony pod głównym obszarem edytora.

Skoro można używać bloków do uaktualniania metadanych posta, pewne
elementy obsługi metadanych mogą sprawdzać się lepiej jako bloki. Więcej
informacji na temat bloków znajdziesz w rozdziale 11. Natomiast w
kolejnych punktach znajdziesz kilka pytań, które należy sobie zadać,
decydując, czy dana właściwość lub funkcja powinna być opracowana jako
niestandardowy typ bloku czy jako element obsługi metadanych.
Przedstawione tutaj odpowiedzi nie są jedynymi prawdziwymi, lecz
sugestiami wyboru pewnych implementacji zamiast innych.

Czy metadane muszą być definiowane dla każdego posta tego typu?

Wykorzystaj standardowy element obsługi metadanych z kontekstem normal,
aby element był wyświetlany pod edytorem posta. Alternatywne rozwiązanie
polega na użyciu bloku wraz z szablonem bloku, aby każdy nowy post
domyślnie zawierał blok. Więcej informacji na temat bloków znajdziesz w
rozdziale 11.

Czy kontrolki metadanych zmieszczą się w pasku bocznym?

Jeżeli nie, użyj elementu obsługi metadanych z kontekstem normal, aby
element był wyświetlany pod edytorem posta. To będzie większy obszar
dostępny dla formularzy i właściwości. Element obsługi metadanych
Require Membership wtyczki Paid Memberships Pro z jej pojedynczym
zestawem przycisków wyboru doskonale pasuje do paska bocznego.
Właściwości WooCommerce z kartami natomiast znacznie bardziej pasują pod
treścią posta.

Czy metadane muszą być umieszczone w treści posta?

Skorzystaj z niestandardowego typu bloku, co pozwoli umieścić blok w
treści posta.

Czy użytkownicy mogą dodawać do posta kopie metadanych?

Skorzystaj z niestandardowego typu bloku, aby można było dodawać wiele
kopii metadanych do tego samego posta. Alternatywnym rozwiązaniem jest
umieszczenie elementu obsługi metadanych pod postem oraz wykorzystanie
kodu PHP i JavaScript w celu dodawania właściwości na żądanie. Takie
rozwiązanie przedstawimy w rozdziale 9.

Opakowania klas dla niestandardowych typów postów

Niestandardowy typ postów to posty. Dlatego można użyć wywołania funkcji
takiej jak get_post( $post_id ) do pobrania obiektu klasy WP_Post, z
którą później będzie odbywała się praca. W przypadku skomplikowanych
niestandardowych typów postów pomocne będzie tworzenie opakowań klas
umożliwiających pracę z CTP w sposób bardziej zorientowany obiektowo.

Podstawowa idea kryjąca się za utworzeniem niestandardowej klasy PHP
polega na dołączaniu jako właściwości obiektu posta wygenerowanego na
podstawie identyfikatora niestandardowego typu posta. Poza
przechowywaniem takiego obiektu posta klasa opakowania zawiera również
metody dla całej funkcjonalności związanej z danym CPT.

Listing 5.4 przedstawia przykładową klasę opakowania dla
niestandardowego typu postów homework.

Listing 5.4. Klasa opakowania dla CPT homework

    <?php

    /*

        Klasa opakowania dla CPT homework

        /wp-content/plugins/schoolpress/classes/class.homework.php

    */

    class Homework {

        // Konstruktor może pobrać $post_id

        function __construct( $post_id = NULL ) {

            if ( !empty( $post_id ) )

                $this->getPost( $post_id );

        }

        // Pobranie powiązanych postów i zdefiniowanie właściwości

        function getPost( $post_id ) {

            // Pobranie posta

            $this->post = get_post( $post_id );

            // Zdefiniowanie właściwości zapewniających łatwy dostęp do danych

            if ( !empty( $this->post ) ) {

                $this->id = $this->post->ID;

                $this->post_id = $this->post->ID;

                $this->title = $this->post->post_title;

                $this->teacher_id = $this->post->post_author;

                $this->content = $this->post->post_content;

                $this->required = $this->post->_schoolpress_homework_is_required;

                $this->due_date = $this->post->due_date;

            }

            // Zwrot identyfikatora znalezionego posta, w przeciwnym razie zwracaną wartością jest false

            if ( !empty( $this->id ) )

                return $this->id;

            else

                return false;

            }

        }

    ?>

Konstruktor tej klasy może pobrać $post_id jako parametr i przekazać tę
wartość metodzie getPost(), która dołącza obiekt $post do egzemplarza
klasy i definiuje kilka właściwości zapewniających łatwy dostęp do
danych. W kodzie na listingu 5.5 pokazaliśmy, jak utworzyć obiekt
konkretnej pracy domowej i wyświetlić jego zawartość.

Listing 5.5. Pobranie i wyświetlenie określonego zadania pracy domowej

    $assignment_id = 1;

    $assignment = new Homework($assignment_id);

    echo '<pre>';

    print_r($assignment);

    echo '</pre>';

    // Dane wyjściowe:

    /*

    Homework Object

    (

        [post] => WP_Post Object

            (

                [ID] => 1

                [post_author] => 1

                [post_date] => 2013-03-28 14:53:56

                [post_date_gmt] => 2013-03-28 14:53:56

                [post_content] => To jest praca domowa...

                [post_title] => Zadanie 1

                [post_excerpt] =>

                [post_status] => publish

                [comment_status] => open

                [ping_status] => open

                [post_password] =>

                [post_name] => assignment-1

                [to_ping] =>

                [pinged] =>

                [post_modified] => 2013-03-28 14:53:56

                [post_modified_gmt] => 2013-03-28 14:53:56

                [post_content_filtered] =>

                [post_parent] => 0

                [guid] => http://schoolpress.me/?p=1

                [menu_order] => 0

                [post_type] => homework

                [post_mime_type] =>

                [comment_count] => 3

                [filter] => raw

                [format_content] =>

            )

        [id] => 1

        [post_id] => 1

        [title] => Zadanie 1

        [teacher_id] => 1

        [content] => To jest praca domowa…

        [required] => 1

        [due_date] => 2013-11-05

    )

    */

Rozszerzanie klasy WP_Post kontra opakowanie obiektu tej klasy

Kolejną opcją jest rozszerzenie klasy WP_Post, choć obecnie jest to
niedostępne, ponieważ klasa została zdefiniowana z użyciem słowa
kluczowego final, co oznacza brak możliwości jej rozszerzania. Zespół
tworzący WordPressa twierdzi, że takie rozwiązanie ma uniemożliwić
tworzenie wtyczek opierających działanie na rozszerzaniu obiektu
WP_Post, gdyż może się on zmienić w przyszłych wersjach WordPressa.
Uważamy, że to podejście jest staroświeckie[3].

W rozdziale 6. przedstawimy przykład rozszerzenia klasy WP_User (nie
jest ona zdefiniowana z użyciem słowa kluczowego final). Jednak w
przypadku WP_Post najlepszym rozwiązaniem będzie przygotowanie dla niej
klasy opakowania.

Po co używać klasy opakowania?

Opracowanie klasy opakowania dla niestandardowego typu postów jest
dobrym rozwiązaniem, przynajmniej z kilku powodów:

-   Cały kod związany z rejestracją niestandardowego typu postów może
    znajdować się w jednym miejscu.
-   Cały kod związany z rejestracją taksonomii powiązanych z CPT może
    znajdować się w jednym miejscu.
-   Całą funkcjonalność związaną z CPT można definiować w postaci metod
    klasy opakowującej.
-   Kod będzie znacznie czytelniejszy.

CTP i taksonomie będą w jednym miejscu

W jednym miejscu można umieścić kod przeznaczony do rejestrowania
niestandardowego typu postów i powiązanych z nimi taksonomii. Zamiast
przygotowywać blok kodu odpowiedzialny za rejestrację CPT i definiowanie
taksonomii oraz oddzielną klasę przeznaczoną do pracy z CPT wszystkie
definicje związane z niestandardowym typem postów i jego taksonomiami
można umieścić w klasie opakowania, jak pokazaliśmy w kolejnym
fragmencie kodu:

    /*

            Wykorzystująca funkcję init() klasa opakowania dla CPT homework

            /wp-content/plugins/schoolpress/classes/class.homework.php

    */

    class Homework

    {

            // Konstruktor może pobrać $post_id

            function __construct($post_id = NULL)

            {

                if(!empty($post_id))

                    $this->getPost($post_id);

            }

            // Pobranie powiązanych postów i zdefiniowanie właściwości

            function getPost($post_id)

            {

                /* Cięcie */

            }

            // Rejestracja CPT i taksonomii w funkcji init()

            function init()

            {

                // Rejestracja niestandardowego typu postów homework

                register_post_type(

                    'homework',

                    array(

                        'labels' => array(

                            'name' => __( 'Homework' ),

                            'singular_name' => __( 'Homework' )

                        ),

                        'public' => true,

                        'has_archive' => true,

                    )

                );

                // Rejestracja taksonomii dla niestandardowego typu postów homework

                register_taxonomy(

                    'subject',

                    'homework',

                    array(

                    'label' => __( 'Subjects' ),

                    'rewrite' => array( 'slug' => 'subject' ),

                    'hierarchical' => true

                    )

                );

        }

    }

    // Uruchomienie Homework init w init

    add_action('init', array('Homework', 'init'));

Wprawdzie ten kod został skrócony (jego pełną wersję zamieściliśmy w
zawierającym materiały przygotowane dla książki archiwum, które
znajdziesz pod adresem ftp://ftp.helion.pl/przyklady/wordp2.zip), ale
pokazuje dodanie metody init() do klasy podłączonej do akcji init.
Metoda init() wykonuje cały kod niezbędny do zdefiniowania
niestandardowego typu postów. Można tutaj zdefiniować inne zaczepy i
filtry, z funkcjami wywołań zwrotnych do innych metod klasy Homework.

Kod można definiować także na inne sposoby, przy czym umieszczenie w
jednym miejscu całego kodu związanego z CPT okazuje się pomocne.

Definiowanie kodu w klasie opakowania

Całą funkcjonalność związaną z CPT definiuj w postaci metod klasy
opakowania. Po zarejestrowaniu niestandardowego typu postów homework do
panelu głównego została dodana strona, co pozwala „edytować pracę
domową”. Nauczyciele mogą tworzyć posty pracy domowej podobnie jak każde
inne posty, z tytułem i treścią. Posty pracy domowej mogą być później
publikowane, gdy nauczyciel i uczniowie będą na to gotowi. Cała
funkcjonalność związana z tym typem posta jest dostępna standardowo po
utworzeniu CPT.

Z drugiej strony większość funkcjonalności związanej z wieloma CPT,
także omawianym tutaj homework, trzeba przygotować samodzielnie. Mając
klasę opakowania, tę funkcjonalność można dodawać w postaci metod klasy
Homework.

Przykładowo jednym z zadań wykonywanych dla postów pracy domowej jest
zbieranie wszystkich prac domowych z danym zadaniem. Następnie te posty
można wyświetlić w postaci listy lub przetworzyć je w jeszcze inny
sposób. Na listingu 5.6 przedstawiliśmy kilka metod, które można dodać
do klasy Homework, aby zebrać powiązane ze sobą prace domowe lub je
ocenić.

Listing 5.6. Dodawanie metod do klasy Homework

    <?php

    class Homework

    {

    /* Usunięto konstruktor i inne metody z wcześniejszych przykładów */

    /*

      Pobranie powiązanych prac domowych

      Przypisanie $force wartości true, aby wymusić na metodzie ponowne pobranie elementów potomnych

    */

    function getSubmissions($force = false)

    {

        // Niezbędny jest identyfikator posta

        if(empty($this->id))

            return array();

        // Czy prace domowe zostały pobrane?

        if(!empty($this->submissions) && !$force)

            return $this->submissions;

        // Mamy prace domowe

        $this->submissions = get_children(array(

            'post_parent' => $this->id,

            'post_type' => 'submissions',

            'post_status' => 'published'

        ));

        // Sprawdzamy, czy mamy do czynienia z tablicą

        if(empty($this->submissions))

            $this->submissions = array();

        return $this->submissions;

    }

    /*

        Ustalenie ocen

    */

    function doFlatCurve($maxscore = 100)

    {

        $this->getSubmissions();

        // Ustalenie najlepszej oceny

        $highscore = 0;

        foreach($this->submissions as $submission)

        {

            $highscore = max($submission->score, $highscore);

        }

        // Ustalenie krzywej

        $curve = $maxscore - $highscore;

        // Poprawienie niższych ocen

        foreach($this->submissions as $submission)

        {

            

                update_post_meta(

                    $submission->ID,

                    "score",

                    min( $maxscore, $submission->score + $curve )

                );

            }

        }

    }

    ?>

Klasa opakowania jest czytelniejsza

Poza sposobem na organizację kodu tak, aby jego komponenty były
łatwiejsze do odszukania, praca z klasą opakowania ułatwia późniejsze
odczytywanie i zrozumienie kodu. Dzięki pełnemu opakowaniu
niestandardowych typów postów Homework i Submission oraz specjalnym
klasom użytkownika (zostaną omówione w rozdziale 6.) można zdefiniować
kod w następującej postaci:

    <?php

    // Użycie metody klasy Student do sprawdzenia, czy bieżący użytkownik to uczeń

    if ( Student::is_student() ) {

        // Domyślnie bieżącym użytkownikiem jest uczeń

        $student = new Student();

        // Należy ustalić datę oddania następnej pracy domowej

        $assignment = $student->getNextAssignment();

        // Wyświetlenie informacji i łączy

        if ( !empty( $assignment ) ) {

            ?>

            <p>Następna praca domowa

            <a href="<?php echo get_permalink( $assignment->id );?>">

            <?php echo $assignment->title;?></a>

            z przedmiotu

            <a href="<?php echo get_permalink( $assignment->class_id );?>">

            <?php echo $assignment->class->title;?></a>

            powinna być oddana do <?php echo $assignment->getDueDate();?>.</p>

            <?php

        }

    }

    ?>

Ten kod byłby znacznie bardziej skomplikowany, gdyby musiał zawierać
wszystkie wywołania get_post() i pętle przeprowadzające iteracje przez
tablice postów potomnych. Wykorzystanie podejścia zorientowanego
obiektowo powoduje, że kod staje się znacznie czytelniejszy dla
programistów.

[1] Te nowe reguły zostały wprowadzone w związku z przepisami ogólnego
rozporządzenia o ochronie danych osobowych (RODO) obowiązującego w Unii
Europejskiej od 2018 roku. Przepisy tego aktu prawnego dotyczą nie tylko
obywateli państw Unii Europejskiej, ale również wszystkich witryn
internetowych odwiedzanych przez obywateli tych państw, co oznacza
praktycznie wszystkie witryny internetowe. Umożliwienie użytkownikom
eksportowania lub usuwania niemających znaczenia krytycznego danych
osobowych jest dobra, niezależnie od miejsca zamieszkania.

[2] Kliknięcie nagłówka elementu obsługi metadanych, niezależnie od
miejsca jego wyświetlenia, spowoduje ukrycie lub pełne wyświetlenie
elementu obsługi metadanych.

[3] Zespół tworzący WordPressa składa się z naprawdę sprytnych
programistów i przyjęte przez nich rozwiązanie nie jest wcale złe.
Jeżeli ktokolwiek rozszerzy klasę WP_Post oraz utworzy nowe właściwości
i metody, późniejsza zmiana klasy WP_Post w WordPressie polegająca na
dodaniu właściwości i metod o takich samych nazwach jak w klasie
rozszerzonej spowoduje problemy.

Rozdział 6. Użytkownicy, role i uprawnienia

W rozdziale 1. wspomnieliśmy, że login to komponent o znaczeniu
krytycznym w praktycznie każdej aplikacji internetowej. Jedną z
doskonałych cech WordPressa jako platformy budowy aplikacji jest to, że
standardowo otrzymujesz w pełni wyposażony zestaw przeznaczony do
zarządzania użytkownikami. Oto możliwości w tym zakresie, jakie
standardowo oferuje aplikacja WordPressa:

-   bezpieczne logowanie za pomocą hasła, które stosuje ciąg zaburzający
    i wartość hash;
-   rekordy użytkownika przechowujące adres e-mail, nazwę użytkownika,
    wyświetlaną nazwę użytkownika, awatar oraz krótkie informacje o
    użytkowniku;
-   widoki administracyjne pozwalające przeglądać, wyszukiwać, dodawać,
    edytować i usuwać użytkowników;
-   role użytkownika przeznaczone do oddzielenia administratorów od
    redaktorów, autorów, współpracowników i innych;
-   strony pozwalające użytkownikom zalogować się, zarejestrować konto
    lub wyzerować hasło.

Dzięki dostępności różnych funkcji i API WordPressa można wykonać
następujące zadania:

-   dodawanie metadanych użytkownika i właściwości dotyczących
    użytkownika oraz zarządzanie nimi;
-   definiowanie niestandardowych ról i uprawnień, aby zdefiniować
    znacznie dokładniejszą kontrolę nad obszarami witryny internetowej,
    do których użytkownik ma dostęp.

Zarządzanie użytkownikami w WordPressie jest dość proste. Karta
Użytkownicy (Users) w panelu głównym pozwala łatwo przeglądać,
wyszukiwać, dodawać, edytować i usuwać użytkowników. Użytkownikami można
równie łatwo zarządzać z poziomu kodu źródłowego.

W rozdziale zostaną poruszone następujące zadania:

-   uzyskiwanie z poziomu kodu źródłowego dostępu do danych użytkownika;
-   dodawanie niestandardowych właściwości dotyczących użytkownika;
-   dostosowanie do własnych potrzeb profilu użytkownika i wyświetlanie
    w panelu głównym informacji o użytkowniku;
-   dodawanie, uaktualnianie i usuwanie użytkowników;
-   definiowanie niestandardowych ról i uprawnień użytkowników;
-   rozszerzanie klasy User WordPressa, aby tworzyć własne klasy
    przeznaczone do pracy z użytkownikami.

Pobieranie danych użytkownika

Z tego podrozdziału dowiesz się, jak utworzyć obiekt WordPressa w kodzie
i pobrać podstawowe informacje o użytkowniku, takie jak login i adres
e-mail, a także jak pobrać z obiektu metadane dotyczące użytkownika.

Klasa WP_User jest podstawowym narzędziem przeznaczonym do zarządzania
użytkownikami w kodzie WordPressa. Podobnie jak wszystko inne w
WordPressie i PHP, także w przypadku WP_User mamy kilka sposobów pracy z
tym obiektem. Oto najpopularniejsze metody tego obiektu:

    // Pobranie obiektu WP_User WordPressa dla aktualnie zalogowanego użytkownika

    global $current_user;

    // Pobranie aktualnie zalogowanego użytkownika za pomocą funkcji wp_get_current_user()

    $user = wp_get_current_user();

    // Zdefiniowanie zmiennych

    $user_id = 1;

    $username = 'jason';

    $email = 'jason@strangerstudios.com';

    // Pobranie użytkownika na podstawie jego identyfikatora

    $user = wp_getuserdata( $user_id );

    // Pobranie użytkownika na podstawie innej właściwości

    $user1 = wp_get_user_by( 'login', $username );

    $user2 = wp_get_user_by( 'email', $email );

    // Bezpośrednie użycie konstruktora WP_User

    $user = new WP_User( $user_id );

    // Użycie konstruktora WP_User z nazwą użytkownika

    $user = new WP_User( $username );

Po utworzeniu obiektu WP_User można pobrać dowolne informacje dotyczące
użytkownika:

    // Pobranie aktualnie zalogowanego użytkownika

    $user = wp_get_current_user();

    // Pobranie wyświetlanej nazwy użytkownika

    echo $user->display_name;

    // Użycie adresu e-mail do wysłania wiadomości e-mail

    wp_mail( $user->user_email, 'Temat wiadomości e-mail', 'Treść wiadomości e-mail' );

    // Pobranie dowolnych metadanych o użytkowniku

    echo 'Department: ' . $user->department;

Można uzyskać dostęp do danych przechowywanych w wp_users table
(user_login, user_nicename, user_email, user_url, user_registered,
user_status, and display_name), wystarczy w tym celu skorzystać z
operatora strzałki, np. $user->display_name.

Można również uzyskać dostęp do wartości przechowywanej w tabeli
wp_usermeta, wystarczy użyć operatora strzałki, np. $user->meta_key, lub
funkcji get_user_meta(). Te dwa polecenia powodują wygenerowanie
dokładnie tych samych danych wyjściowych.

    <?php

    $full_name = trim( $user->first_name . ' ' . $user->last_name );

    $full_name = trim( get_user_meta( $user->ID, 'first_name' ) .

        ' ' . get_user_meta( $user->ID, 'last_name' ) );

    ?>

Dobrze jest poznać sztuczkę używaną przez WordPressa w celu umożliwienia
dostępu na żądanie do metadanych, jakby poszczególne metadane były
właściwościami klasy WP_User. Klasa WP_User używa przeciążonych
właściwości „metody magicznej” __get()[1].

Dzięki metodom magicznym dowolna właściwość obiektu WP_User, którą
próbujesz pobrać, a nie jest rzeczywistą właściwością obiektu, zostanie
przekazana metodzie __get() klasy. Oto uproszczona[2] wersja metody
__get() używanej w klasie WP_User:

    function __get( $key ) {

    if ( isset( $this->data->$key ) ) {

        $value = $this->data->$key;

            } else {

                $value = get_user_meta( $this->ID, $key, true );

            }

            return $value;

    }

Przeanalizujmy ten fragment kodu. Ta metoda najpierw sprawdza, czy
wartość istnieje we właściwości $data obiektu WP_User. Jeżeli tak, ta
wartość zostanie zastosowana. W przeciwnym razie metoda wykorzysta
funkcję get_user_meta() do sprawdzenia, czy istnieją jakiekolwiek
metadane dla przekazanego klucza.

Ponieważ metadane są wczytywane na żądanie, takie rozwiązanie wymaga
mniej pamięci niż utworzenie egzemplarza nowego obiektu WP_User. Z
drugiej strony, skoro metadane są niedostępne aż do momentu ich żądania,
nie można wyświetlić wszystkich metadanych za pomocą wywołania takiego
jak print_r( $user ) lub print_r( $user->data ).

Aby przeprowadzić iterację przez wszystkie metadane użytkownika,
konieczne jest użycie funkcji get_user_meta() z przekazanym parametrem
$key.

    // Iteracja przez wszystkie metadane użytkownika

    $user_meta = get_user_meta( $user_id );

    foreach( $user_meta as $key => $value )

        echo $key . ': ' . $value . '<br />';

Wiedza o sposobie stosowania funkcji __get() w WordPressie jest
interesująca, choć znacznie ważniejsza jest umiejętność unikania pewnych
ograniczeń tej metody magicznej.

Metody __get() i __set() nie są wywoływane w przypadku łączenia wywołań
metod. Przykładowo polecenie $year = $user->graduation_year = '2012'
spowoduje wyświetlenie niespójnych wyników.

Podobnie funkcja __get() nie zostanie wywołana w połączeniu z wywołaniem
funkcji empty() lub isset(). Dlatego wynikiem wyrażenia
if(empty($user->graduation_year)) jest false, nawet jeśli istnieją
metadane użytkownika przypisane kluczowi graduation_year.

Rozwiązaniem dla tych dwóch problemów jest użycie kodu w nieco bardziej
rozwlekłej postaci:

    // Podział przypisań na więcej poleceń, gdy są stosowane metody magiczne

    $user->graduation_year = '2012';

    $year = '2012';

    // Aby sprawdzić, czy wartość metadanych istnieje, trzeba najpierw zdefiniować zmienną lokalną

    $year = $user->graduation_year;

    if ( empty( $year ) )

        $year = '2012';

Dodawanie, uaktualnianie i usuwanie użytkowników

W rozdziale 2. krótko wspomnieliśmy o podstawowych funkcjach
przeznaczonych do dodawania, uaktualniania i usuwania użytkowników.
Ponieważ praca z danymi użytkownika jest niezwykle ważna w każdej
aplikacji internetowej, zdecydowaliśmy się na zamieszczenie tutaj
dodatkowych przykładów i innych scenariuszy, z którymi można się
spotkać.

Od czasu do czasu będzie zachodziła potrzeba dodawania użytkowników z
poziomu kodu źródłowego, a nie z panelu głównego WordPressa. W aplikacji
SchoolPress chcemy umożliwić nauczycielom wprowadzenie listy adresów
e-mail i wygenerowanie wiadomości dla każdego z nich.

Wbudowany w WordPressie formularz rejestracji dość trudno jest
dostosować do własnych potrzeb. Często znacznie łatwiejszym rozwiązaniem
będzie opracowanie własnego formularza i zastosowanie funkcji WordPressa
w celu dodania tego formularza do backendu[3].

Zapewne już doskonale wiesz, że funkcją przeznaczoną do dodawania
użytkownika w WordPressie jest wp_insert_user(). Pobiera ona tablicę
danych użytkownika i wstawia je do tabel wp_users i wp_usermeta.

    // Utworzenie użytkownika na podstawie zebranych danych

    $user_id = wp_insert_user( array(

            'user_login' => $username,

            'user_pass' => $password,

            'user_email' => $email,

            'first_name' => $firstname,

            'last_name' => $lastname

        )

    );

    // Sprawdzenie, czy dana nazwa użytkownika lub adres e-mail zostały już użyte

    if ( is_wp_error( $user_id ) ){

        echo $return->get_error_message();

    } else {

        // Kontynuowanie pracy i wykonanie zadań z danymi użytkownika o identyfikatorze $user_id

    }

Kolejny fragment kodu pokazuje, jak można automatycznie zalogować
użytkownika po jego dodaniu do aplikacji. Funkcja wp_signon()
uwierzytelnia użytkownika i tworzy bezpieczne cookie, które umożliwia
zalogowanie tego użytkownika.

    // OK, można zalogować użytkownika w WP

    $creds = array();

    $creds['user_login'] = $username;

    $creds['user_password'] = $password;

    $creds['remember'] = true;

    $user = wp_signon( $creds, false );

Uaktualnienie informacji użytkownika jest równie łatwe dzięki istnieniu
funkcji wp_update_user(). Należy jej przekazać tablicę danych i
metadanych użytkownika. Jeżeli w tablicy znajduje się klucz z prawidłową
wartością w postaci identyfikatora użytkownika, WordPress automatycznie
uaktualni przekazane informacje.

    // To polecenie spowoduje uaktualnienie adresu e-mail użytkownika, a pozostałe dane nie zostaną zmienione

    $userdata = array( 'ID' => 1, 'user_email' => 'jason@strangerstudios.com' );

    wp_update_user( $userdata );

    // Ta funkcja również sprawdza się doskonale podczas uaktualniania wielu informacji o użytkowniku

    wp_update_user( array(

        'ID' => 1,

        'company' => 'Stranger Studios',

        'title' => 'CEO',

        'personality' => 'crescent fresh'

    ));

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Nie ma możliwości uaktualnienia wartości user_login użytkownika za pomocą funkcji wp_update_user(). Ponadto po uaktualnieniu wartości user_login użytkownik zostanie wylogowany. Przedstawiony wcześniej kod automatycznego logowania można wykorzystać do automatycznego zalogowania użytkownika z użyciem nowego hasła.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Do uaktualnienia pojedynczej wartości metadanych użytkownika można użyć
następującej funkcji:

    update_user_meta( $user_id, $meta_key, $meta_value, $prev_value )

Wybrane aspekty tej funkcji zaprezentowaliśmy w kolejnym fragmencie
kodu:

    // Tablice będą serializowane

    $children = array( 'Isaac', 'Marin');

    update_user_meta( $user_id, 'children', $children );

    // Istnieje możliwość przechowywania tablicy przez umieszczenie wielu wartości o takim samym kluczu

    add_user_meta( $user_id, 'children', 'Isaac' );

    add_user_meta( $user_id, 'children', 'Marin' );

    // Podczas przechowywania wielu wartości należy podać parametr $prev_value,

    // aby wskazać modyfikowaną wartość

    update_user_meta( $user_id, 'children', 'Isaac Ford', 'Isaac' );

    update_user_meta( $user_id, 'children', 'Marin Josephine', 'Marin' );

    // Usunięcie wszystkich metadanych użytkownika według klucza

    delete_user_meta( $user_id, 'children' );

    // Usunięcie tylko jednego rekordu, gdy dla danego klucza istnieje wiele wartości

    delete_user_meta( $user_id, 'children', 'Isaac Ford' );

Zwróć uwagę na przedstawienie w tym kodzie dwóch odmiennych sposobów
przechowywania tablic w metadanych użytkownika. Takie rozwiązanie jest
podobne do przechowywania opcji za pomocą funkcji update_option() lub
przekazania metadanych za pomocą funkcji update_post_meta(). Pierwsza
metoda (jedna serializowana wartość dla klucza) ogranicza liczbę
używanych rekordów tabeli wp_usermeta, co może zwiększyć wydajność
wykonywania zapytań meta_key. Natomiast druga metoda (wiele wartości dla
klucza) pozwala wykonywać zapytania według wartości meta_value. Na
przykład przechowywanie wszystkich imion dzieci jako oddzielnych
elementów metadanych umożliwia wykonywanie zapytań w następujący sposób:

    <?php

    // Pobranie identyfikatorów wszystkich użytkowników, którzy mają dzieci o podanym imieniu

    $parents_of_isaac = $wpdb->get_col( "SELECT user_id

            FROM $wpdb->usermeta

            WHERE meta_key = 'children'

            AND meta_value = 'Isaac'" );

    ?>

Wprawdzie istnieje możliwość wykonywania zapytań do tabel wp_usermeta i
wp_postmeta według wartości meta_value, ale należy zachować ostrożność
związaną z czasem wykonywania zapytań. Kolumna meta_value nie jest
indeksowana, więc zapytanie do ogromnego zbioru danych może być naprawdę
wolne. Relacja typu „wiele do jednego”, taka jak w omawianym
przykładzie, może być przechowywana w niestandardowych taksonomiach, co
poprawi nieco wydajność działania zapytań.

Usunięcie użytkownika z poziomu kodu, choć niebezpieczne, jest bardzo
łatwe.

    // Ten plik zawiera funkcję wp_delete_user() i nie zawsze jest wczytywany,

    // więc upewnij się, że to polecenie zostało dodane

    require_once( ABSPATH . '/wp-admin/includes/user.php' );

    // Usunięcie użytkownika

    wp_delete_user( $user_id );

    // Usunięcie użytkownika i przypisanie jego postów użytkownikowi o identyfikatorze ID #1

    wp_delete_user( $user_id, 1 );

W przypadku konfiguracji sieci witryn internetowych konieczne jest
zastosowanie funkcji wpmu_delete_user(), aby usunąć użytkownika z całej
sieci witryn. W przeciwnym razie funkcja wp_delete_user() usunie
użytkownika jedynie z bieżącego bloga. Za pomocą is_multisite() można
ustalić, czy konieczne jest użycie funkcji wpmu_delete_user().

    // Chcemy mieć pewność, że użytkownik faktycznie został usunięty

    if ( is_multisite() )

        wp_delete_user( $user_id );

    else

        wpmu_delete_user( $user_id );

Zaczepy i filtry

Prawdopodobnie znacznie częściej wykonywanym zadaniem niż dodawanie lub
uaktualnianie informacji o użytkowniku jest uruchamianie pewnych
fragmentów kodu po dodaniu nowego użytkownika lub uaktualnieniu
informacji o istniejącym. Na przykład po zarejestrowaniu użytkownika
chcemy utworzyć nowy post CTP i połączyć go z użytkownikiem. Albo chcemy
przeprowadzić operacje czyszczące i pozbyć się pewnych informacji po
usunięciu użytkownika. Do tego celu można wykorzystać niestandardowe
filtry i zaczepy powiązane z użytkownikiem.

Zaczep powodujący wykonanie pewnego kodu po zarejestrowaniu użytkownika
nosi nazwę user_register. Ten zaczep przekazuje identyfikator nowo
utworzonego użytkownika.

    // Utworzenie nowego CPT "course" po zarejestrowaniu nauczyciela

    function sp_user_register( $user_id ){

        // Sprawdzenie, czy nowy użytkownik to nauczyciel (więcej informacji na ten temat znajdziesz w rozdziale 15.)

        if ( pmpro_hasMembershipLevel( 'teacher', $user_id ) ) {

            // Dodanie nowego CPT "course" wraz z nowym użytkownikiem jako autorem

            wp_insert_post( array(

                'post_title' => 'Mój pierwszy kurs',

                'post_content' => 'To jest przykładowy kurs...',

                'post_author' => $user_id,

                'post_status' => 'draft',

                'post_type' => 'course'

            ) );

        }

    }

    add_action( 'user_register', 'sp_user_register' );

Zaczep umożliwiający wykonanie kodu przed usunięciem użytkownika to
delete_user. Zaczep o podobnej nazwie, deleted_user, jest wykonywany po
usunięciu użytkownika.

Te zaczepy są w większości przypadków wymienne, mimo to warto zwrócić
uwagę na kilka kwestii:

-   Jeżeli zaczep delete_user zastosujesz zbyt wcześnie, możesz przerwać
    operację usunięcia użytkownika.
-   Jeżeli użyjesz deleted_user, dane użytkownika i połączenia mogły
    zostać już usunięte i są niedostępne.

    <?php

    // Wysłanie wiadomości e-mail informującej o usunięciu użytkownika

    function sp_delete_user( $user_id ){

        $user = get_userdata( $user_id );

        wp_mail( $user->user_email,

        "Twoje konto zostało usunięte.",

        'Twoje konto w SchoolPressie zostało usunięte.'

        );

    }

    // Chcesz mieć możliwość wczesnego wykorzystania user_email

    add_action( 'delete_user', 'sp_delete_user' );

    ?>

Czym są role i uprawnienia?

Mechanizmy ról i uprawnień pozwalają WordPressowi kontrolować, jak
użytkownicy uzyskują dostęp do widoku i co robią w witrynie
internetowej. Każdy użytkownik może mieć tylko jedną rolę, a każda rola
może mieć wiele uprawnień. Poszczególne uprawnienia określają, czy
użytkownik może wyświetlać określonego typu treści lub wykonywać
konkretne akcje.

W każdej instalacji WordPressa mamy pięć ról domyślnych: Administrator,
Redaktor (Editor), Autor (Author), Współpracownik (Contributor) i
Subskrybent (Subscriber). Jeżeli uruchomiłeś witrynę sieciową, będziesz
mieć jeszcze szóstą rolę, Superadministrator, która zapewnia dostęp do
wszystkich witryn internetowych w sieci. Pełną listę uprawnień i ich
mapowanie na domyślne role WordPressa znajdziesz na stronie
https://wordpress.org/support/article/roles-and-capabilities/.

Za chwilę pokażemy, jak przebiega proces tworzenia nowych ról poza
domyślnymi rolami WordPressa. Jednak w większości aplikacji rozsądne i
wystarczające jest pozostanie przy domyślnie dostępnych rolach:
administratorzy używają roli administrator, a użytkownicy i klienci —
zwykle roli subscriber.

Jeżeli użytkownik aplikacji ma mieć uprawnienia tworzenia treści, warto
rozważyć przypisanie mu roli author (może wówczas tworzyć i publikować
posty) lub contributor (może tworzyć posty, ale nie publikować). Jeśli
aplikacja ma moderatorów, rozważ przypisanie im roli editor.

Stosowanie ról domyślnych jest dobrym rozwiązaniem, ponieważ pewne
wtyczki oczekują, że użytkownicy będą mieli przypisaną jedną z tych ról
domyślnych. Jeśli natomiast administrator jest użytkownikiem w roli
menedżera biura, będziesz potrzebować wtyczki zewnętrznej do pracy z
takim użytkownikiem. To działa także w drugą stronę. Może wystąpić
konieczność ukrycia pewnej funkcjonalności udostępnionej użytkownikom na
podstawie ich roli, zwłaszcza w przypadku stosowania ról innych niż
administrator (ma dostęp do wszystkiego) i subscriber (może jedynie
wyświetlać treść).

Sprawdzanie ról i uprawnień użytkownika

Czasami zachodzi potrzeba sprawdzenia, czy użytkownik może wykonać pewne
zadanie, zanim zostanie mu ono zlecone. Do takiego sprawdzenia przydaje
się funkcja current_user_can(). Pobiera ona jeden parametr, którym jest
wartość w postaci ciągu tekstowego, $capability, do sprawdzenia. W
kolejnym fragmencie kodu zaprezentowaliśmy przykład użycia tej funkcji.

    if ( current_user_can( 'manage_options' ) ) {

        // Ma możliwość zarządzania opcjami, najczęściej jest to administrator

    }

    if ( current_user_can( 'edit_user', $user_id ) ) {

        // Może edytować użytkownika o identyfikatorze $user_id

        // Najczęściej jest to ten użytkownik lub administrator

    }

    if ( current_user_can( 'edit_post', $post_id ) ) {

        // Może edytować post o identyfikatorze $post_id

        // Najczęściej jest to autor posta, administrator lub redaktor

    }

    if ( current_user_can( 'subscriber' ) ) {

        // Jedyny sposób na sprawdzenie, czy bieżący użytkownik jest zwykłym użytkownikiem

    }

Istnieje również możliwość użycia funkcji user_can() w celu sprawdzenia,
czy ktoś inny poza bieżącym użytkownikiem ma dane uprawnienie. Przekaż
wartość $user_id użytkownika, którego chcesz sprawdzić, interesujące Cię
uprawnienie oraz wszelkie pozostałe niezbędne argumenty.

    <?php

    /*

        Wyświetlenie komentarzy dla bieżącego posta,

        oznaczenie każdego, kto może go edytować

    */

    global $post;   // Bieżący post, który jest analizowany

    $comments = get_comments( 'post_id=' . $post->ID );

    foreach( $comments as $comment ) {

        // Domyślne klasy CSS dla wszystkich komentarzy

        $classes = 'comment';

        // Dodanie autorom klasy CSS can-edit

        if ( user_can( $comment->user_id, 'edit_post', $post->ID ) ) {

            $classes .= ' can-edit';

        }

        ?>

        <div id="comment-<?php echo $comment->comment_ID;?>"

            class="<?php echo $classes;?>">

            Komentarz napisany przez <?php echo $comment->comment_author; ?>:

        <?php echo wpautop( $comment->comment_content ); ?>

        </div>

    <?php

    }

Wprawdzie istnieje możliwość sprawdzenia roli użytkownika za pomocą
funkcji current_user_can(), ale znacznie lepszym rozwiązaniem będzie
sprawdzenie uprawnień użytkownika, a nie jego roli. Dzięki temu kod
będzie działał nawet po zmianie roli użytkownika lub po przypisaniu
różnych uprawnień rolom. Na przykład sprawdzenie manage_options działa
zgodnie z oczekiwaniami, niezależnie od tego, czy użytkownik ma
przypisaną rolę administrator czy niestandardową rolę z dodanym
usprawnieniem manage_options.

Sprawdzanie roli użytkownika powinno być ograniczone do przypadków, w
których naprawdę konieczne jest poznanie roli użytkownika, a nie jego
uprawnień. Jeżeli sprawdzasz rolę użytkownika przed zezwoleniem mu na
wykonanie określonego działania, potraktuj to jako podpowiedź, że trzeba
temu użytkownikowi nadać nowe uprawnienie.

W kolejnym fragmencie kodu pokazaliśmy, jak można uaktualnić użytkownika
w roli subscriber, którego identyfikator został przekazany roli author.
Aby mieć absolutną pewność, można sprawdzić tablicę roles obiektu
użytkownika zamiast skorzystać z funkcji user_can(). Metody set_role()
klasy użytkownika użyliśmy do przypisania nowej roli.

    function upgradeSubscriberToAuthor( $user_id ) {

        $user = new WP_User( $user_id );

        if ( in_array( 'subscriber', $user->roles ) ) {

            $user->set_role( 'author' );

        }

    }

Tworzenie niestandardowych ról i uprawnień

Jak już wiesz, najlepiej będzie ograniczyć się do domyślnych ról
WordPressa, o ile to możliwe. Jeżeli jednak masz różne klasy
użytkowników i chcesz ograniczyć ich uprawnienia na nowe sposoby, to
zdefiniowanie niestandardowych ról i uprawnień może okazać się dobrym
wyjściem.

W naszej aplikacji SchoolPress nauczyciele to użytkownicy w roli author,
uczniowie zaś to użytkownicy w roli subscriber. Potrzebna jest jednak
rola niestandardowa dla użytkowników, którzy mogą zarządzać
użytkownikami, ale nie mogą edytować treści, motywów, opcji, wtyczek i
ogólnych ustawień WordPressa. Oto sposób zdefiniowania nowej roli
office:

    function sp_roles_and_caps() {

        // Nowa rola office

        remove_role('office');      // Na wypadek uaktualnienia uprawnień roli

        add_role( 'office', 'Office Manager', array(

            'read' => true,

            'create_users' => true,

            'delete_users' => true,

            'edit_users' => true,

            'list_users' => true,

            'promote_users' => true,

            'remove_users' => true,

            'office_report' => true // Nowe uprawnienie pozwalające tworzyć zestawienia

        ));

    }

    // Ta funkcja ma zostać wywołana podczas aktywacji wtyczki

    register_activation_hook( __FILE__, 'sp_roles_and_caps' );

Po wywołaniu funkcji add_role() nastąpi uaktualnienie opcji
wp_user_roles w tabeli wp_options, z której WordPress pobiera informacje
o rolach i uprawnieniach. Dlatego ta funkcja ma być wywoływana tylko
jednokrotnie, po aktywacji wtyczki. To oznacza konieczność
zarejestrowania tej funkcji za pomocą register_activation_hook().

Na początku kodu znajduje się wywołanie remove_role('office') na
wypadek, gdyby zachodziła potrzeba całkowitego usunięcia roli. To
wywołanie okazuje się także użyteczne do usunięcia zawartości roli przed
jej ponownym dodaniem, jeśli zmienione zostały jej uprawnienia lub
ustawienia. Bez wywołania remove_role() funkcja add_role() nie zostanie
wykonana, ponieważ dana rola już istnieje.

Funkcja add_role() pobiera trzy parametry: nazwę roli, wyświetlaną nazwę
roli i tablicę uprawnień. Na stronie pomocy technicznej WordPressa
(https://wordpress.org/support/) znajdziesz informacje o uprawnieniach
domyślnych. Możesz je również odszukać w pliku /wp-admin/includes/
schema.php instalacji WordPressa.

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   WordPress wykonuje zaczepy aktywacji tylko podczas aktywowania wtyczki. Te zaczepy nie będą wykonywane po uaktualnieniu wtyczki lub po zmianie jednego z plików PHP wtyczki. Aby pobrać rolę i uprawnienia nowego użytkownika, należy dezaktywować i ponownie aktywować wtyczkę. Jeżeli tworzysz publicznie dostępną wtyczkę, możesz sprawdzić ustawienia roli i uprawnień w zaczepie admin_init oraz wyzerować role i uprawnienia, jeśli zachodzi potrzeba. Na stronie https://github.com/ strangerstudios/paid-memberships-pro/blob/master/includes/capabilities.php został zamieszczony pochodzący z wtyczki Paid Memberships Pro plik pokazujący, jak można to zrobić.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Dodawanie nowych uprawnień jest proste i sprowadza się do podania nazwy
uprawnienia w wywołaniu add_role() lub użycia metody add_cap() w
istniejącej roli. Oto przykład pobrania egzemplarza klasy roli i dodania
do niego uprawnienia:

    // Nadanie administratorom uprawnienia office_report, aby mogli wyświetlać przygotowane zestawienie

    $role = get_role( 'administrator' );

    $role->add_cap( 'office_report' );

Także ten fragment kodu musi być wykonany tylko jednokrotnie i
przeprowadzi wówczas operację zapisu w bazie danych. Umieść ten kod w
funkcji zarejestrowanej za pomocą register_activation_hook(), jak to
pokazaliśmy w ostatnim przykładzie.

Metodę remove_class() klasy roli również można wykorzystać, co okazuje
się przydatne, gdy zachodzi potrzeba usunięcia jakiejś funkcjonalności z
domyślnych ról. W kolejnym fragmencie kodu pokazaliśmy usunięcie
uprawnienia edit_pages z roli editor, aby użytkownik w takiej roli mógł
edytować dowolne posty bloga, ale nie strony (post typu page).

    // Użytkownik w roli editor nie może edytować stron

    $role = get_role( 'editor' );

    $role->remove_cap( 'edit_pages' );

Dodawanie i edytowanie ról i uprawnień zapewnia potężne możliwości.
Określenie, do której treści użytkownik może uzyskać dostęp, jest ważną
kwestią podczas tworzenia aplikacji. Poszczególne role można definiować
dla odmiennych poziomów członkostwa lub podczas uaktualnień produktu. W
rozdziale 15. poznasz wtyczkę Paid Memberships Pro, która umożliwia
stosowanie „poziomów członkostwa” jako odmiennych klasyfikacji
użytkowników. Takie rozwiązanie można zastosować zamiast
niestandardowych ról, choć często stosuje się je wraz z niestandardowymi
rolami. Więcej informacji na temat poziomów współdziałania członkostwa i
ról znajdziesz w rozdziale 15.

Rozszerzanie klasy WP_User

Podobnie jak w rozdziale 5. opakowaliśmy klasę WP_Post w celu utworzenia
konkretnej klasy dla niestandardowych typów postów, tak samo można
rozszerzyć klasę WP_User i w ten sposób tworzyć użyteczne klasy, które
pomogą w organizacji kodu związanego z różnymi typami użytkowników.

Przykładowo w naszej aplikacji SchoolPress mamy dwa podstawowe typy
użytkowników: nauczyciele i uczniowie[4]. Oba typy tak naprawdę
reprezentują zwykłych użytkowników WordPressa, ale każdy z nich będzie
miał unikatową funkcjonalność. Tę unikatową funkcjonalność można
hermetyzować przez utworzenie klas Teacher i Student rozszerzających
klasę WP_User.

Czy nie byłoby wspaniale móc utworzyć kod jak w poniższym fragmencie:

    <?php

    // Student to klasa rozszerzająca klasę WP_User

    $student = new Student();

    foreach( $student->getAssignments() as $assignment ) {

        // assignment to tutaj egzemplarz klasy rozszerzającej klasę WP_Post

        $assignment->print();

    }

    ?>

Oto ten sam kod zapisany w postaci mniej zorientowanej obiektowo:

    $student = wp_get_current_user(); // Zwrot obiektu WP_User dla bieżącego użytkownika

    foreach( sp_getAssignmentsByUser( $student->ID ) as $assignment ) {

        sp_printAssignment( $assignment->ID );

    }

Oba te fragmenty kodu działają identycznie, ale pierwszy jest łatwiejszy
w odczycie i łatwiej z nim pracować. Co ważniejsze, umieszczenie całej
funkcjonalności związanej z uczniami zdefiniowanej jako metody klasy
Student pomaga w lepszym zorganizowaniu kodu.

Zobacz przykład inicjalizacji i definicji metody getAssignments() klasy
Student:

    <?php

    class Student extends WP_User {

        // Brak konstruktora, aby można było użyć konstruktora WP_User

        // Metoda pobierająca pracę domową dla danego ucznia

        function getAssignments() {

            // Pobranie zadań za pomocą get_posts(), o ile nie zrobiono tego wcześniej

            if ( ! isset( $this->data->assignments ) )

                $this->data->assignments = get_posts( array(

                        'post_type' => 'assignment',// Zadania

                        'numberposts' => -1,        // Wszystkie posty

                        'author' => $this->ID       // Identyfikator użytkownika danego ucznia

                    ));

            return $this->data->assignments;

        }

        // Metoda magiczna do wykrywania $student->assignments

        function __get( $key ) {

            if ( $key == 'assignments' ) {

                return $this->getAssignments();

            } else {

                // Rozwiązanie awaryjne dla domyślnej metody magicznej klasy WP_User

                return parent::__get( $key );

            }

        }

    }

    ?>

W tym przykładzie zdefiniowaliśmy klasę Student rozszerzającej klasę
WP_User za pomocą wyrażenia extends WP_User dodanego do definicji klasy.

Nie zdefiniowaliśmy tutaj własnej funkcji konstruktora, ponieważ
chcieliśmy wykorzystać tę samą, która istnieje w klasie WP_User. Chcemy
mieć możliwość pobrania użytkownika za pomocą jego identyfikatora, aby
można było użyć polecenia $student = new Student($user_ID);.

Metoda getAssignments() używa funkcji get_posts() w celu pobrania
wszystkich postów typu „praca domowa”, które zostały utworzone przez
danego użytkownika klasy Student. Posty prac domowych są przechowywane w
tablicy we właściwości $data, która została zdefiniowana w klasie
WP_User przechowującej wszystkie dane i metadane użytkowników. To
pozwala później tworzyć polecenia takie jak $student->assignments w celu
pobrania postów pracy domowej.

Jeżeli polecenie $student->assignments jest zdefiniowaną właściwością
$student, zostanie zwrócona wartość tej właściwości. Natomiast jeśli nie
istnieje właściwość „pracy domowej”, PHP przekaże „prace domowe” jako
parametr $key metodzie __get(). W omawianym przykładzie przeprowadzane
jest sprawdzenie $key == "assignments", a następnie zwracana jest
wartość metody getAssignments(). Jeżeli wartość $key jest inna niż
„prace domowe”, przekazujemy ją metodzie __get() klasy nadrzędnej
WP_User, która sprawdza wartość właściwości $data egzemplarza klasy lub
(w przypadku niepowodzenia) przekazuje klucz funkcji get_user_meta().

Na pierwszy rzut oka pozwala to użyć polecenia $student->assignments
zamiast $student->getAssignments(), co technicznie jest prawdziwe.
Jednak tworzenie kodu w taki sposób umożliwia buforowanie danych we
właściwości $data obiektu, dzięki czemu można uniknąć ponownego
pobierania danych, jeśli będą potrzebne więcej niż raz. To powoduje
również zachowanie większej spójności z pozostałym kodem WordPressa.
Jeżeli chcesz pobrać adres e-mail ucznia, używasz polecenia
$student->user_email;. Jeżeli chcesz pobrać imię ucznia, używasz
polecenia $student->first_name;. Jeżeli chcesz pobrać prace domowe
ucznia, używasz polecenia $student->assignments;. Osoba korzystająca z
tego kodu nie musi wiedzieć, że niektóre z tych danych są przechowywane
w tabeli wp_users, inne w tabeli wp_usermeta, a wynikiem jest zapytanie
posta.

Dodanie właściwości rejestracji i profilu

Bardzo często zachodzi potrzeba dodania kolejnych właściwości profilu
dla użytkowników aplikacji. Z poprzedniego podrozdziału wiesz, jak użyć
funkcji wp_update_user() i update_user_meta() do zarządzania tymi
wartościami. W tym rozdziale natomiast zobaczysz, jak dodawać
modyfikowalne właściwości do metadanych użytkownika na stronach
rejestracji i profilu.

W aplikacji SchoolPress trzeba przechwytywać pewne dane o użytkownikach.
W przypadku uczniów są to rok ukończenia nauki, dane wychowawcy itd. Z
kolei w przypadku nauczycieli chcemy przechowywać dane dotyczące np.
wydziału i lokalizacji biura. Dla obu wymienionych typów użytkowników
mają być przechowywane jeszcze informacje takie jak płeć, wiek i numer
telefonu.

Dostępnych jest kilka różnych wtyczek pomocnych w efektywnym wykonywaniu
takich zadań. Przykładowo jeżeli zainstalujesz wtyczkę Paid Memberships
Pro Register Helper[5], to kod przedstawiony na listingu 6.1 będziesz
mógł wykorzystać, aby dodać niezbędne właściwości na stronach
rejestracji i profilu.

Listing 6.1. Rejestracja dodatkowych właściwości dotyczących
użytkowników

    <?php

    function ps_registration_fields(){

        // Właściwości są przechowywane w tablicy

        $fields = array();

        // Właściwości dla wszystkich użytkowników

        $fields[] = new PMProRH_Field(

            'gender',

            'select',

            array(

                'options' => array(

                    '' => 'Wybierz',

                    'male' => 'mężczyzna',

                    'female' => 'kobieta',

                    'other' => 'inna',

                    'undisclosed' => 'nie powiem'

                ),

                'profile' => true,

                'required' => true

            )

        );

        $fields[] = new PMProRH_Field(

            'age',

            'text',

            array(

                'size' => 10,

                'profile' => true,

                'required' => true

            )

        );

        $fields[] = new PMProRH_Field(

            'phone',

            'text',

            array(

                'size' => 20,

                'label' => 'Nr telefonu',

                'profile' => true,

                'required' => true

            )

        );

        // Właściwości dotyczące nauczycieli

        $fields[] = new PMProRH_Field(

            'department',

            'text',

            array(

                'size' => 40,

                'profile' => true,

                'required' => true

            )

        );

        $fields[] = new PMProRH_Field(

            'office',

            'text',

            array(

                'size' => 40,

                'profile' => true,

                'required' => true

            )

        );

        // Właściwości dotyczące uczniów

        $fields[] = new PMProRH_Field(

            'graduation_year',

            'text',

            array(

                'label' => 'Oczekiwany rok zakończenia nauki',

                'size' => 10,

                'profile' => true,

                'required' => true

            )

        );

        $fields[] = new PMProRH_Field(

            'major',

            'text',

            array( 'size' => 40, 'profile' => true, 'required' => true )

        );

        $fields[] = new PMProRH_Field(

            'minor',

            'text',

            array( 'size' => 40, 'profile' => true )

        );

        // Dodanie właściwości do strony rejestracji konta

        foreach( $fields as $field ) {

            pmprorh_add_registration_field( 'after_password', $field );

        }

    }

    add_action( 'init', 'ps_registration_fields' );

    ?>

Dokładne informacje dotyczące sposobu używania wtyczki Paid Memberships
Pro Register Helper i składni definiowania właściwości znajdziesz w
pliku README wtyczki. Zamiast powielać tutaj te informacje, pokażemy
przykład ręcznego dodania jednej właściwości na stronach rejestracji
konta i profilu użytkownika z zastosowaniem dokładnie tych samych
zaczepów i filtrów, które wykorzystuje Paid Memberships Pro Register
Helper.

1.  Dodanie właściwości na stronie rejestracji.

        <?php

        function sp_register_form(){

            // Pobranie wartości age podanej w formularzu

            if ( ! empty( $_REQUEST['age'] ) )

                $age = intval( $_REQUEST['age'] );

            else

                $age = '';

            // Wyświetlenie danych wejściowych

            ?>

            <p>

            <label for="age">Wiek<br />

            <input type="text" name="age" id="age" class="input"

                value="<?php echo esc_attr( $age ); ?>" />

            </label>

            </p>

        <?php

        }

        add_action( 'register_form', 'sp_register_form' );

        ?>

      ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
      []   Użyliśmy polecenia if ( ! empty( $_REQUEST['age'] ) ), aby uniknąć ostrzeżenia PHP generowanego podczas pierwszej wizyty użytkownika na stronie rejestracji, gdy tablica $REQUEST nie zawiera jeszcze żadnych danych formularza. Podczas wyświetlania wieku na stronie została użyta funkcja esc_attr(). Funkcje przeznaczone do zmiany znaczenia znaków omawiamy dokładnie w rozdziale 8.
      ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

2.  Uaktualnienie wieku użytkownika po zarejestrowaniu konta.

        function sp_register_user( $user_id ){

            // Pobranie wartości age podanej w formularzu

            $age = intval( $_REQUEST['age'] );

            // Uaktualnienie metadanych użytkownika

            update_user_meta( $user_id, 'age', $age );

        }

        add_action( 'register_user', 'sp_register_user' );

3.  Dodanie właściwości age na stronie profilu użytkownika. Konieczne
    jest wykorzystanie zaczepów show_user_profile i edit_user_profile w
    celu wyświetlenia pól formularza dla tych właściwości, gdy
    użytkownik znajduje się na stronie swojego profilu lub gdy
    administrator edytuje profil innego użytkownika.

        <?php

        function sp_user_profile( $user ){

            // Wyświetlenie danych wejściowych

            $age = $user->age;

            ?>

            <table class="form-table">

            <tbody>

            <tr>

                        <th><label for="age">Wiek</label></th>

                        <td>

                        <input type="text" name="age" id="age" class="input"

                    value="<?php echo esc_attr( $age ); ?>"/>

                        </td>

                </tr>

            </tbody>

            </table>

        <?php

        }

        // Użytkownik wyświetla stronę swojego profilu

        add_action( 'show_user_profile', 'sp_user_profile' );

        // Administrator edytuje profil użytkownika

        add_action( 'edit_user_profile', 'sp_user_profile' );

        ?>

    Zwróć uwagę na to, że w kodzie HTML na domyślnej stronie rejestracji
    WordPressa użyto znaczników <p> do rozdzielenia pól, podczas gdy w
    kodzie HTML w panelu głównym użyto do tego wierszy tabeli.

4.  Uaktualnienie właściwości podczas operacji zmiany informacji na
    stronie profilu.

        <?php

        function sp_profile_update( $user_id ){

            // Umożliwienie bieżącemu użytkownikowi edycji danych tego użytkownika

            if ( ! current_user_can( 'edit_user', $user_id ) ) {

                return false;

            }

            // Sprawdzenie, czy wartość została przekazana

            if ( isset( $_POST['age'] ) ){

                // Uaktualnienie metadanych użytkownika

                update_user_meta( $user_id, 'age', intval( $_POST['age'] ) );

            }

        }

        //  Użytkownik wyświetla stronę swojego profilu

        add_action( 'personal_options_update', 'sp_profile_update' );

        // Administrator edytuje dane

        add_action( 'edit_user_profile_update', 'sp_profile_update' );

        ?>

Także w tym przypadku korzystamy z dwóch oddzielnych zaczepów: pierwszy
jest przeznaczony dla użytkownika wyświetlającego swój profil, a drugi
dla administratora, który edytuje profil innego użytkownika.

W ten sposób zobaczyłeś, jak można dodawać właściwości na stronach
rejestracji i profilu. Teraz wystarczy przeprowadzić iterację przez
właściwości przeznaczone do dodania lub skorzystać z wtyczki takiej jak
Paid Memberships Pro Register Helper, która zrobi to za Ciebie.

Dostosowanie do własnych potrzeb tabeli użytkowników w panelu głównym

Po dodaniu dodatkowych metadanych dla informacji o użytkowniku czasami
zachodzi potrzeba rozszerzenia podstawowej tabeli listy użytkowników w
panelu głównym WordPressa.

Możesz opracować własną stronę administracyjną z niestandardowymi
zapytaniami, która przygotowuje zestawienie odpowiadające stylem tabelom
w panelu głównym WordPressa (takie podejście zastosowaliśmy we wtyczce
Paid Memberships Pro). Ewentualnie dostarczane przez WordPressa zaczepy
i filtry możesz wykorzystać w celu dodania kolumn i filtrów do
standardowej listy użytkowników, co zamierzamy pokazać w tym
podrozdziale.

W omawianym przykładzie skorzystamy z filtrów manage_users_columns i
manage_users_custom_column. Zaczynamy od dodania właściwości do listy
użytkowników.

    // Dodanie nowej kolumny do tabeli

    function sp_manage_users_columns( $columns ){

        $columns['age'] = 'Age';

        return $columns;

    }

    add_filter( 'manage_users_columns', 'sp_manage_users_columns' );

    // Wskazanie WordPressowi, jak ma umieścić dane w nowej kolumnie

    function sp_manage_users_custom_column( $value, $column_name, $user_id ){

        $user = get_userdata( $user_id );

        if ( $column_name == 'age' )

            $value = $user->age;

        return $value;

    }

    add_filter( 'manage_users_custom_column',

        'sp_manage_users_custom_column', 10, 3);

Filtr manage_users_columns przekazuje tablicę zawierającą wszystkie
domyślne kolumny WordPressa (i wszelkie dodane przez inne wtyczki).
Możesz dodawać nowe kolumny, usuwać istniejące za pomocą
unset( $columns['column_name' ]), a także zmieniać ich kolejność. Klucze
w tablicy $columns to unikatowe ciągi tekstowe identyfikujące te
kolumny. Natomiast wartościami w tablicy $columns są nagłówki
poszczególnych kolumn.

Filtr manage_users_custom_column jest stosowany dla każdej
niestandardowej kolumny WordPressa w tablicy manage_users_columns (czyli
np. dla każdej dodanej przez Ciebie). Funkcja wywołania zwrotnego
sp_manage_users_custom_column() może przeprowadzać wszelkie operacje
niezbędne do pobrania wartości niestandardowych kolumn. Ta funkcja
zwykle zawiera ogromny blok if-then-else lub konstrukcję switch
odpowiedzialną za sprawdzenie wartości $column_name i zwrot odpowiedniej
wartości dla każdej z kolumn.

Jeżeli użyjesz przedstawionego tutaj kodu, kolumna Age zostanie dodana
na stronie użytkowników, choć domyślnie nie będzie można jej kliknąć,
aby sortować listę użytkowników według ich wieku, jak to można zrobić
domyślnymi kolumnami na liście. Spójrz na kod, który pozwoli sortować
elementy według nowo dodanej kolumny:

    <?php

    // Umożliwienie sortowania według wartości tej kolumny

    function sp_manage_users_sortable_columns( $columns ){

        $columns['age'] = 'Age';

            return $columns;

    }

    add_filter( 'manage_users_sortable_columns',

        'sp_manage_users_sortable_columns' );

    // Uaktualnienie user_query w przypadku sortowania według wieku

    function sp_pre_user_query( $user_query ){

        global $wpdb, $current_screen;

        // Sprawdzenie, czy lista użytkowników jest wyświetlana w panelu głównym

        if ( $current_screen->id != 'users' ) {

            return;

        }

        // Sortowanie według wieku

        if ( $user_query->query_vars['orderby'] == 'Age' ) {

            $user_query->query_from .= " INNER JOIN $wpdb->usermeta m1

                ON $wpdb->users u1

                AND (u1.ID = m1.user_id)

                AND (m1.meta_key = 'age')";

            $user_query->query_orderby = " ORDER BY m1.meta_value

                " . esc_sql( $user_query->query_vars['order'] );

        }

    }

    add_action( 'pre_user_query', 'sp_pre_user_query' );

    ?>

W tym kodzie kolumna Age została zdefiniowana jako umożliwiająca
sortowanie według jej wartości. Było to możliwe dzięki użyciu filtra
manage_users_sortable_columns. Filtr pre_user_query został wykorzystany
do wykrycia parametru &sortby=Age na stronie listy użytkowników i
uaktualnienia obiektu $user_query, aby użyć złączenia z tabelą
wp_usermeta i sortować dane według wieku. Zwróć uwagę na użycie wartości
globalnej $current_screen, która została zdefiniowana na stronie
administracyjnej i ma na celu sprawdzenie (przed edycją zapytania), czy
aktualną stroną jest strona wyświetlająca listę użytkowników.

Wartością $user_query→query_vars[order] będzie ASC lub DESC, choć
zmienną opakowujemy funkcją esc_sql(), aby w ten sposób chronić
aplikację przed atakami polegającymi na wstrzyknięciu kodu SQL. Jeszcze
lepszym rozwiązaniem będzie sprawdzenie, czy wartością jest dokładnie
ASC lub DESC, i zgłoszenie błędu, gdy jest inaczej.

Wtyczki

Skoro wiesz już, jak dostosować do własnych potrzeb różne aspekty
systemu zarządzania użytkownikami w WordPressie, warto poznać kilka
wtyczek przeznaczonych do pracy z użytkownikami. Pomogą one w znacznie
łatwiejszym budowaniu aplikacji internetowej.

Theme My Login

Użytkownicy witryny internetowej nie muszą wiedzieć, że została ona
zbudowana na podstawie WordPressa. Możesz skorzystać z formularza
logowania zintegrowanego z projektem Twojej witryny internetowej zamiast
z domyślnego formularza logowania WordPressa. Tutaj doskonale sprawdza
się wtyczka Theme My Login
(https://wordpress.org/plugins/theme-my-login/). Ruch sieciowy do
wp-login.php zostaje przekierowany na stronę logowania, wizualnie spójną
z pozostałą częścią witryny, zamiast do backendu WordPressa.

Ta wtyczka oferuje również użyteczne płatne moduły umożliwiające
stosowanie motywów dla profili użytkowników, ukrycie panelu głównego dla
użytkowników niebędących administratorami, a także określenie miejsc, do
których zostanie przekierowany użytkownik po zalogowaniu i wylogowaniu.

Ukrycie paska administracyjnego przed użytkownikami niebędącymi administratorami

Działanie wtyczki Hide the Admin Bar
(https://wordpress.org/plugins/hide-admin-bar-from-non-admins/) polega
na ukryciu paska administracyjnego. Tylko użytkownicy o roli
administrator będą widzieli tenże pasek podczas odwiedzania witryny
internetowej. Ta wtyczka to zaledwie kilka wierszy kodu i można ją
dostosować do własnych potrzeb, np. umożliwić wyświetlenie paska
administracyjnego użytkownikom w roli editor lub author.

Paid Memberships Pro

Wtyczka Paid Memberships Pro
(https://wordpress.org/plugins/paid-memberships-pro/) została opracowana
przez Stranger Studios i pozwala pobierać opłaty za uzyskanie dostępu do
treści witryny internetowej poprzez utworzenie społeczności członków.
Jest to idealne rozwiązanie dla firm lub blogerów szukających możliwości
zablokowania bezpłatnego dostępu do treści i pobierania opłat za usługi.
Wtyczkę można bardzo łatwo zintegrować z bramkami płatności, takimi jak
Stripe, Paypal i Authorize.net. Dostępna jest m.in. obsługa płatności
jednorazowych i cyklicznych. Wtyczka Paid Memberships Pro pozwala
tworzyć różne poziomy członkostwa w witrynie internetowej.

Paid Memberships Pro Register Helper

Wtyczka Paid Memberships Pro Register Helper
(https://github.com/strangerstudios/pmpro-register-helper) została
opracowana z myślą o współdziałaniu z Paid Memberships Pro, choć można
ją stosować także z innymi projektami. Ułatwia ona proces dodawania
właściwości na stronach rejestracji i profilu użytkownika. Zamiast
zestawu trzech zaczepów i funkcji dla każdej właściwości można dodawać
właściwości w kilku wierszach kodu, jak pokazaliśmy w kolejnym
fragmencie kodu.

    <?php

    $text = new PMProRH_Field(

        'company',

        'text',

        array(

            'size' => 40,

            'class' => 'company',

            'profile' => true,

            'required' => true

        )

    );

    pmprorh_add_registration_field( 'after_billing_fields', $text );

    ?>

Wtyczka Register Helper zawiera również skróty przeznaczone do
wstawiania na stronach i w paskach bocznych formularzy logowania oraz
oferuje moduły działające jako punkty wyjścia podczas tworzenia własnych
stron rejestracji, profilu i członkostwa.

Members

Wtyczka Members (https://wordpress.org/plugins/members/) rozszerza
kontrolę, jaką masz nad rolami i uprawnieniami użytkowników witryny
internetowej. Umożliwia edytowanie, tworzenie i usuwanie ról
użytkowników i ich uprawnień. Pozwala także definiować uprawnienia dla
poszczególnych ról, a także ustalić, która rola ma uprawnienia
umożliwiające dodawanie, edytowanie i/lub usuwanie różnych fragmentów
treści.

Wprawdzie możesz samodzielnie utworzyć kod odpowiedzialny za dodawanie
ról i uprawnień, ale wtyczka Members oferuje elegancki graficzny
interfejs użytkownika dla tej funkcjonalności i bardzo często okazuje
się niezwykle użyteczna.

WP User Fields

Żartowaliśmy. Jeszcze nie istnieje wtyczka o nazwie „WP User Fields”.
Mamy 2020 rok i wciąż nie istnieje dobra i przyjazna dla użytkownika
wtyczka umożliwiająca dodawanie właściwości do domyślnych stron
rejestracji, profilu i listy użytkowników w WordPressie. Najlepszym
rozwiązaniem jest opieranie się w tym zakresie na innej wtyczce
zapewniającej obsługę członkostwa lub formularzy.

Czy będziesz tym, który utworzy taką wtyczkę dla WordPressa? Dokończ
lekturę książki, a będziesz mieć do dyspozycji wszystkie niezbędne
narzędzia. Rozpocznij od następnego rozdziału, w którym poznasz sposób
pracy z API WordPressa, obiektami i funkcjami pomocniczymi.

[1] Każda metoda klasy o nazwie rozpoczynającej się od dwóch znaków
podkreślenia jest w PHP uznawana za metodę magiczną, ponieważ jest
wywoływana automatycznie w trakcie określonych zdarzeń.

[2] Dla zachowania przejrzystości usunęliśmy fragmenty metody
pozostawione w celu zachowania wstecznej zgodności i filtrowania danych
w pewnych sytuacjach. Omawiany kod jest zgodny z duchem tej metody.

[3] Takie rozwiązanie zostało zastosowane we wtyczce Paid Membership Pro
na stronie rejestracji użytkownika, po przejściu na nią ze strony
koszyka.

[4] Gdy mówimy o nauczycielach i uczniach jako osobach, używamy zapisu
małą literą. Gdy natomiast mamy na myśli typy reprezentujące nauczyciela
(ang. teacher) lub ucznia (ang. student), pierwsza litera jest wielka.

[5] Wtyczka Paid Memberships Pro Register Helper
(https://www.paidmembershipspro.com/add-ons/pmpro-register-helper-add-checkout-and-profile-fields/)
została opracowana z myślą o wtyczce Paid Memberships Pro, ale bez niej
działa równie dobrze.

Rozdział 7. Praca z API WordPressa, obiektami i funkcjami pomocniczymi

W tym rozdziale przedstawimy wiele API WordPressa, obiektów i funkcji
pomocniczych, które choć nie zostały omówione w innych miejscach
książki, stanowią ważne narzędzia w arsenale programisty WordPressa.

API skrótów

Skróty to specjalnie sformatowane fragmenty tekstu, których można używać
do wstawiania dynamicznych danych wyjściowych do postów, stron, widżetów
i innych statycznych obszarów treści.

Skróty istnieją w trzech podstawowych odmianach:

-   pojedynczy skrót typu [myshortcode];
-   skróty z atrybutami, np. [myshortcode id="1" type="text"];
-   skróty zawierające inną treść, np. [myshortcode id="1"] ... miejsce
    na jakąś treść ... [/myshortcode].

W rozdziale 3. zamieściliśmy przykład pokazujący, jak można wykorzystać
skróty, aby dodać dowolną treść do postu lub strony WordPressa. W owym
przykładzie skrót zastąpiliśmy treścią. Istnieje możliwość dodawania
atrybutów do skrótów, aby w ten sposób mieć wpływ na funkcje wywołania
zwrotnego używane do przetwarzania skrótów lub do opakowania treści w
parę skrótów (otwierający i zamykający), które przeprowadzą filtrowanie
treści.

Podstawowym krokiem podczas tworzenia skrótów jest zdefiniowanie funkcji
wywołania zwrotnego za pomocą funkcji add_shortcode(). Wszelkie jej
atrybuty zostają dodane do tablicy przekazywanej funkcji wywołania
zwrotnego jako pierwszy parametr, $atts. Treść w parze skrótów jest
natomiast przekazywana funkcji wywołania zwrotnego jako drugi parametr,
$content.

W przedstawionym tutaj fragmencie kodu został zdefiniowany skrót o
nazwie msg, który wykorzystuje atrybuty i inną treść.

    <?php

    /*

      Funkcja wywołania zwrotnego dla skrótu [msg]

      Przykład: [msg type="error"]To jest komunikat błędu.[/msg]

      Dane wyjściowe:

      <div class="message message-error">

          <p>To jest komunikat błędu.</p>

      </div>

    */

    function sp_msg_shortcode($atts, $content)

    {

        // Atrybuty domyślne

        extract( shortcode_atts( array(

            'type' => 'information',

            ), $atts ) );

        $content = do_shortcode($content);    // Dozwolone jest zagnieżdżanie skrótów

        $r = '<div class="message message-' .

            $type . '"><p>' . $content . '</p></div>';

        return $r;

    }

    add_shortcode('msg', 'sp_msg_shortcode');

    ?>

Zwróć uwagę na to, że treść przeznaczona do wyświetlenia zostaje
zwrócona przez funkcję wywołania zwrotnego, a nie przekazana do bufora
danych wyjściowych. Tak się dzieje, ponieważ filtr skrótu jest zwykle
wykonywany przed przekazaniem jakiejkolwiek treści do wyświetlenia.
Jeżeli funkcja wywołania zwrotnego zawierałaby polecenie echo, dane
wyjściowe pojawiłyby się na górze strony, a nie tam, gdzie ich
oczekiwano.

Atrybuty skrótu

Omawiany fragment kodu pokazuje jeszcze jedną ważną kwestię, a
mianowicie sposób definiowania atrybutów domyślnych. Funkcja
shortcode_atts() pobiera trzy parametry: $pairs, $atts i $shortcode.

Parametr $pairs to tablica atrybutów domyślnych, w której kluczem jest
nazwa atrybutu, a wartością wartość danego atrybutu.

Parametr $atts to podobna tablica atrybutów, zwykle przekazywana prosto
z parametru $atts do funkcji wywołania zwrotnego skrótu. Funkcja
shortcode_atts() łączy w jedną tablicę atrybuty domyślne i otrzymane.

Parametr $shortcode jest opcjonalny. Jeżeli jego wartość będzie
odpowiadała nazwie skrótu, spowoduje wywołanie filtru
shortcode_atts_{shortcode}, który może być wykorzystywany przez inne
wtyczki w celu nadpisania atrybutów domyślnych.

Wynik wywołania shortcode_atts() jest przekazywany funkcji PHP o nazwie
extract(), która w zasięgu lokalnym tworzy zmienną dla każdego klucza w
tablicy atrybutów.

W ten sposób zmienna $type w naszym przykładzie stała się dostępna dla
pozostałych funkcji i zawiera wartość domyślną message lub wartość
zdefiniowaną w skrócie.

Skróty zagnieżdżone

Następnie wartość parametru $content jest przekazywana funkcji
do_shortcode(), aby włączyć zagnieżdżone skróty. Jeżeli masz skrót
[help_link] odpowiedzialny za wygenerowanie w dokumentacji łącza w
zależności od aktualnej sekcji witryny internetowej lub zalogowanego
użytkownika, być może zechcesz skorzystać z tego skrótu w skrócie [msg].

    [msg type="error"]

        Wystąpił błąd. Więcej informacji na ten temat znajdziesz pod adresem [help_link].

    [/msg]

O ile funkcja wywołania zwrotnego skrótu [msg] przekazuje wynik
działania za pomocą do_shortcode(), to wewnętrzny skrót [help_link]
będzie filtrowany zgodnie z oczekiwaniami.

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Wprawdzie skróty zagnieżdżone różnych typów działają, ale zagnieżdżenie tego samego skrótu w innym nie będzie działało. W celu zapewnienia szybkości działania został opracowany analizator składni wyrażeń regularnych (regex) pobierający skróty z treści. Ten analizator musi przeanalizować treść tylko jednokrotnie. Obsługa zagnieżdżonych takich samych skrótów wymagałaby wielokrotnego analizowania treści, co oznaczałoby spowolnienie algorytmu. Mamy więc trzy rozwiązania. Pierwsze to unikanie zagnieżdżania skrótu w takim samym skrócie, drugie to stosowanie różnych nazw dla skrótów powiązanych z tą samą funkcją wywołania zwrotnego a trzecie — opracowanie własnego analizatora składni wyrażeń regularnych dla swoich skrótów i przetwarzanie ich za jego pomocą.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Funkcji do_shortcode() można użyć także w celu zastosowania skrótów dla
niestandardowych właściwości, treści pobranej z tabel niestandardowych,
a także dla innej treści niedostępnej za pomocą filtru the_content. W
większości przypadków poza samą funkcją wywołania zwrotnego skrótu
bardziej odpowiednim rozwiązaniem będzie wykorzystanie funkcji
apply_filters( "the_content", $content ), która zastosuje wszystkie
filtry w zaczepie the_content, łącznie z filtrem skrótu.

    <?php

    global $post;

    $sidebar_content = $post->sidebar_content;

    ?>

    <div class="post">

        <?php the_content(); ?>

    </div>

    <div class="sidebar">

    <?php

        //echo do_shortcode($sidebar_content);

        echo apply_filters('the_content', $sidebar_content);

    ?>

    </div>

Usunięcie skrótu

Podobnie jak w przypadku akcji i filtrów, zarejestrowane skróty można
usunąć, aby nie były stosowane w określonych postach lub w treści
przekazywanej bezpośrednio funkcji do_shortcode() bądź poprzez filtr
the_content. Funkcja remove_shortcode() pobiera nazwę skrótu jako jej
jedyny parametr, a następnie wyrejestrowuje ten skrót. Z kolei funkcja
remove_all_shortcodes() usuwa wszystkie zarejestrowane skróty.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Podczas wywoływania funkcji remove_shortcode() należy się upewnić, że to wywołanie odbędzie się na tyle późno podczas działania WordPressa, że będzie w stanie usunąć żądane skróty. Przykładowo jeśli wtyczka powoduje dodanie skrótu podczas akcji init o priorytecie 10, wówczas wywołanie remove_shortcode() powinno znaleźć się w akcji init o priorytecie 11 lub wyższym albo w zaczepie wywoływanym po akcji init.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Tablica zarejestrowanych skrótów jest przechowywana w zmiennej globalnej
$shortcode_tags. Użyteczne może być utworzenie kopii tej zmiennej lub
jej bezpośrednia edycja. Przykładowo jeśli pewne skróty chcesz usunąć z
określonego fragmentu treści, możesz utworzyć kopię wszystkich skrótów,
usunąć niepotrzebne, zastosować skróty, a następnie przywrócić
początkową listę skrótów.

    // Utworzenie kopii początkowej listy skrótów

    global $shortcode_tags;

    $original_shortcode_tags = $shortcode_tags;

    // Usunięcie skrótu [msg]

    unset($shortcode_tags['msg']);

    // Wykonanie funkcji i wyświetlenie treści

    $content = do_shortcode($content);

    echo $content;

    // Przywrócenie początkowej listy skrótów

    $shortcode_tags = $original_shortcode_tags;

Inne użyteczne funkcje powiązane ze skrótami

Oto funkcje użyteczne podczas pracy ze skrótami:

shortcode_exists( $tag )

Sprawdzenie, czy skrót $tag został zarezerwowany.

has_shortcode( $content, $tag )

Sprawdzenie, czy skrót $tag znajduje się w zmiennej $content.

shortcode_parse_atts( $text )

Wyodrębnienie atrybutów ze skrótu. Odbywa się to podczas przetwarzania
skrótu, choć tę funkcję można wywołać również bezpośrednio, gdy zachodzi
potrzeba pobrania atrybutów z innych miejsc, takich jak znaczniki HTML
lub szablony.

strip_shortcodes( $text )

Usunięcie wszystkich skrótów ze zmiennej $text i zastąpienie ich pustym
ciągiem tekstowym zamiast wykonywania funkcji wywołania zwrotnego.

Więcej informacji na temat API skrótów znajdziesz w serwisie WordPress
Codex pod adresem https://codex.wordpress.org/Shortcode_API.

API widżetów

Widżet pozwala umieszczać oddzielne fragmenty kodu i treści z różnych
obszarów widżetów witryny internetowej WordPressa. Najbardziej typowym
przypadkiem użycia jest dodawanie widżetów do paska bocznego lub stopki.
Wprawdzie te sekcje zawsze można na stałe zdefiniować w witrynie
internetowej, ale wykorzystanie widżetów umożliwia osobom o mniejszej
wiedzy technicznej przeciąganie i upuszczanie widżetów z jednego obszaru
na inny albo dostosowanie ich ustawień do własnych potrzeb za pomocą
strony widżetów w administracyjnym panelu głównym. WordPress jest
dostarczany wraz z wieloma wbudowanymi widżetami, m.in. z prostym
widżetem tekstowym, który pokazaliśmy na rysunku 7.1.

[]

Rysunek 7.1. Ustawienia widżetu tekstowego

Wiele wtyczek również zawiera widżety przeznaczone do wyświetlania
różnej treści. W tej książce nie będziemy się zagłębiać w temat
stosowania widżetów i nadawania im stylów, ponieważ wiele informacji na
ten temat znajdziesz w serwisie WordPress Codex na stronie
https://wordpress.org/ support/article/wordpress-widgets/. Wyjaśnimy
natomiast, jak dodawać widżety i obszary widżetów do wtyczek i motywów.

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Interfejs użytkownika strony widżetów w administracyjnym panelu głównym uległ dużym zmianom w WordPressie 3.8. Jednak funkcje i wywołania API przeznaczone do dodawania nowych widżetów z poziomu kodu nie powinny ulec zbyt dużym zmianom, o ile w ogóle zostały zmodyfikowane.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Zanim zaczniesz dodawać własny widżet

Zanim rozpoczniesz pracę nad nowym widżetem, warto poświęcić trochę
czasu na sprawdzenie, czy istniejący widżet nie spełnia Twoich wymagań.
Jeżeli wykażesz się dostateczną kreatywnością, czasami unikniesz
tworzenia nowego widżetu.

Przeszukaj repozytoria widżetów, może się bowiem w nich znajdować ten,
którego szukasz. Jeżeli go znajdziesz, dokładnie sprawdź kod i upewnij
się, że działa zgodnie z oczekiwaniami.

Widżety tekstowe można stosować w celu dodawania dowolnego tekstu do
obszaru przeznaczonego dla widżetu. Istnieje również możliwość osadzenia
kodu JavaScript w ten sam sposób lub dodania skrótu do obszaru tekstu i
później wykorzystania skrótu do otrzymania żądanej funkcjonalności (być
może odpowiedni skrót przygotowałeś już w innym celu) zamiast zajmować
się tworzeniem nowego widżetu.

Jeżeli widżet wyświetla listę łączy, rozsądne może być zdefiniowanie
menu tych łączy, a następnie wykorzystanie widżetu Własne Menu
wbudowanego w WordPressa. Inne widżety wyświetlające najnowsze posty z
danej kategorii bardzo często działają też z CPT i niestandardowymi
taksonomiami, często nie wymagając przy tym żadnych modyfikacji.

Jeśli chcesz dodać zupełnie nowy widżet, w kolejnych sekcjach
przedstawiliśmy kroki, które trzeba w tym celu wykonać.

Dodawanie widżetu

Aby dodać nowy widżet do WordPressa, konieczne jest utworzenie nowej
klasy PHP dla tego widżetu, rozszerzającej klasę WP_Widget WordPressa.
Klasa WP_Widget została zdefiniowana w pliku wp-includes/widgets.php i
warto zapoznać się z jej kodem źródłowym. Umieszczone w kodzie
komentarze wyjaśniają sposób działania klasy i wskazują metody, które
trzeba nadpisać podczas tworzenia własnej klasy widżetu. Mamy cztery
podstawowe metody, które trzeba nadpisać. Wszystkie wyraźnie
wymieniliśmy w kolejnym fragmencie kodu pochodzącym z przykładowej klasy
widżetu, ze strony serwisu WordPress Codex dla Widgets API
(https://codex.wordpress.org/Widgets_API).

    /*

      Ten kod pochodzi ze strony Widgets API serwisu Codex Page:

      http://codex.wordpress.org/Widgets_API

    */

    class My_Widget extends WP_Widget {

        public function __construct() {

            // Rzeczywiste procesy widżetu

        }

        public function widget( $args, $instance ) {

            // Wyświetlenie danych wyjściowych widżetu

        }

        public function form( $instance ) {

            // Wyświetlenie formularza opcji dla administratora

        }

        public function update( $new_instance, $old_instance ) {

            // Przetworzone opcje widżetu do zapisania

        }

    }

    add_action( 'widgets_init', function(){

        register_widget( 'My_Widget' );

    });

Wywołanie add_action() przekazuje funkcję anonimową jako drugi parametr,
który jest obsługiwany jedynie w PHP 5.3 lub nowszych wydaniach. Z
technicznego punktu widzenia WordPress wymaga PHP w wersji 5.2.4 lub
nowszej. Alternatywą będzie użycie funkcji create_function() w PHP,
której wydajność działania jest mniejsza, a sama funkcja znacznie mniej
bezpieczna niż wykorzystanie funkcji anonimowej. Jeżeli jednak planujesz
udostępnienie kodu szerszemu gronu odbiorców, możesz zdecydować się na
metodę alternatywną, którą przedstawiliśmy w kolejnym fragmencie kodu.

    /*

      Ten kod pochodzi ze strony Widgets API serwisu Codex Page:

      http://codex.wordpress.org/Widgets_API

    */

    add_action('widgets_init',

        create_function('', 'return register_widget("My_Widget");')

    );

Po połączeniu wszystkiego w całość na listingu 7.1 przedstawiliśmy nowy
widżet dla witryny internetowej SchoolPress. Ten widżet zostanie
wyświetlony w globalnie zdefiniowanym zbiorze notatek w ustawieniach
widżetu lub w notatce powiązanej z aktualną grupą BuddyPress wybraną
przez grupę administratorów.

Listing 7.1. Widżet programu SchoolPress Note

    <?php

    /*

      Widżet wyświetlający notatkę aktualnej klasy

      Nauczyciele (grupa administratorów) może ją zmieniać dla poszczególnych grup

      Ustawienie globalne jest wyświetlane w ustawieniach widżetu

    */

    class SchoolPress_Note_Widget extends WP_Widget

    {

        public function __construct() {

            parent::__construct(

                'schoolpress_note',

                'SchoolPress Note',

                array( 'description' => 'Notatka do wyświetlenia na stronach grupy' );

        }

        public function widget( $args, $instance ) {

            global $current_user;

            // Czy zapisać notatkę przy wyjściu?

            if ( !empty( $_POST['schoolpress_note_text'] )

                    && !empty( $_POST['class_id'] ) ) {

                // Czy użytkownik na pewno jest administratorem?

                if(groups_is_user_admin($current_user->ID,intval($_POST['class_id']))){

                    // Tekst należy oczyścić

                    update_option(

                        'schoolpress_note_' . intval( $_POST['class_id'] ),

                        $_POST['schoolpress_note_text']

                    );

                }

            }

            // Wyszukanie notatki globalnej

            $note = $instance['note'];

            // Pobranie identyfikatora klasy danej grupy

            $class_id = bp_get_current_group_id();

            // Wyszukanie klasy notatki

            if ( empty( $note ) && !empty( $class_id ) ) {

                $note = get_option( "schoolpress_note_" . $class_id );

            }

            // Wyświetlenie notatki

            if ( !empty( $note ) ) {

                ?>

                    <div id="schoolpress_note">

                    <?php echo wpautop( $note );?>

                    </div>

                    <?php

                    // Administrator grupy ma możliwość edycji

                    if ( groups_is_user_admin( $current_user->ID, $class_id ) ) {

                    ?>

                    <a id="schoolpress_note_edit_trigger">Edycja</a>

                    <div id="schoolpress_note_edit" style="display: none;">

                    <form action="" method="post">

                    <input type="hidden"

                            name="class_id"

                            value="<?php echo intval($class_id);?>" />

                    <textarea name="schoolpress_note_text" cols="30" rows="5">

                    <?php echo esc_textarea(get_option('schoolpress_note_'.$class_id))

                    ;?>

                    </textarea>

                    <input type="submit" value="Zapisz" />

                    <a id="schoolpress_note_edit_cancel" href="javascript:void(0);">

                            Anuluj

                    </a>

                    </form>

                    </div>

                    <script>

                    jQuery(document).ready(function() {

                            jQuery('#schoolpress_note_edit_trigger').click(function(){

                                    jQuery('#schoolpress_note').hide();

                                    jQuery('#schoolpress_note_edit').show();

                            });

                            jQuery('#schoolpress_note_edit_cancel').click(function(){

                                    jQuery('#schoolpress_note').show();

                                    jQuery('#schoolpress_note_edit').hide();

                            });

                    });

                    </script>

                    <?php

                    }

            }

        }

        public function form( $instance ) {

            if ( isset( $instance['note'] ) )

                $note = $instance['note'];

            else

                $note = "";

            ?>

            <p>

                    <label for="<?php echo $this->get_field_id( 'note' ); ?>">

                            <?php _e( 'Note:' ); ?>

                    </label>

                    <textarea id="<?php echo $this->get_field_id( 'note' ); ?>"

                            name="<?php echo $this->get_field_name( 'note' ); ?>">

                            <?php echo esc_textarea( $note );?>

                    </textarea>

            </p>

            <?php

        }

        public function update( $new_instance, $old_instance ) {

            $instance = array();

            $instance['note'] = $new_instance['note'];

            return $instance;

        }

    }

    add_action( 'widgets_init', function() {

        register_widget( 'SchoolPress_Note_Widget' );

    } );

    ?>

Definiowanie obszaru widżetu

Aby dodać do motywu obszar widżetu lub pasek boczny, trzeba wykonać dwie
operacje: zarejestrować obszar widżetu w WordPressie oraz dodać kod do
motywu, w miejscu w którym ma się pojawić obszar widżetu.

Rejestracja widżetu jest dość prosta, dzięki istnieniu funkcji
register_sidebar(), której jedynym parametrem jest tablica argumentów.
Zapoznaj się z dostępnymi argumentami. Ta lista pochodzi z dotyczącej
funkcji register_sidebar() strony
https://developer.wordpress.org/reference/functions/ register_sidebar/ w
serwisie WordPress Codex.

name

Nazwa paska bocznego (domyślnie jest to Sidebar#, gdzie # to
identyfikator paska bocznego).

id

Identyfikator paska bocznego — musi być zapisany małymi literami bez
spacji (domyślnie jest to automatycznie inkrementowana wartość
liczbowa).

description

Opis tekstowy przedstawiający pasek boczny i jego położenie. Począwszy
od wersji 2.9 WordPressa, wyświetlany na oknie zarządzania widżetem
(wartość domyślna to empty).

class

Nazwa klasy, która ma zostać przypisana kodowi HTML widżetu (wartość
domyślna to empty).

before_widget

Kod HTML przeznaczony do umieszczenia przed każdym widżetem (domyślnie
jest to <li id="%1$s" class="widget %2$s">). Do zastępowania zmiennych
używa wywołania sprintf().

after_widget

Kod HTML przeznaczony do umieszczenia po każdym widżecie (domyślnie jest
to </li>\n).

before_title

Kod HTML przeznaczony do umieszczenia przed każdym tytułem (domyślnie
jest to <h2 class="widgettitle">).

after_title

Kod HTML przeznaczony do umieszczenia po każdym tytule (domyślnie jest
to </h2>\n).

Aby zarejestrować zwykły pasek boczny na stronach pracy domowej w
motywie SchoolPress, konieczne jest dodanie następującego fragmentu kodu
do pliku functions.php lub includes/sidebars.php motywu:

    register_sidebar(array(

      'name' => 'Pasek boczny stron pracy domowej',

      'id' => 'schoolpress_assignment_pages',

      'description' => 'Pasek boczny wyświetlany na stronach pracy domowej.',

      'before_widget' => '',

      'after_widget' => '',

      'before_title' => '',

      'after_title' => ''

    ));

Wartości before/after_widget i before/after_title zostaną zdefiniowanie
na podstawie tego, jak motyw nadaje style widżetom i tytułom. W
niektórych przypadkach oczekiwane są elementy <li>, w innych zaś
elementy <div>. Jeżeli nadaniem stylów zajmuje się kod widżetu,
wszystkie wartości można zdefiniować jako puste ciągi tekstowe.
Następnym krokiem jest rzeczywiste osadzenie obszaru widżetu w motywie.
Odbywa się to za pomocą wywołania funkcji dynamic_sidebar(), której
jedynym parametrem jest identyfikator zarejestrowanego paska bocznego.

    if(!dynamic_sidebar('schoolpress_student_status'))

    {

      // Kod rozwiązania awaryjnego w przypadku nieznalezienia paska bocznego my_widget_area

    }

Ten kod spowoduje wczytanie paska bocznego schoolpress_student_status, o
ile taki zostanie znaleziony. Jeżeli ten pasek nie zostanie znaleziony,
wartością zwrotną fynamic_sidebar() będzie false i nastąpi wykonanie
kodu zdefiniowanego w nawiasie klamrowym. Można to wykorzystać do
wyświetlenia treści domyślnej w obszarze paska bocznego, jeśli pasek
boczny nie zawiera żadnych widżetów lub w ogóle nie istnieje.

Wcześniej motywy WordPressa były opracowywane wraz z obszarem paska
bocznego i miały na stałe zdefiniowane w nim określone funkcje. Celem
wprowadzenia widżetów było przede wszystkim zastąpienie statycznych
pasków bocznych dynamicznymi, które można kontrolować za pomocą strony
widżetów w panelu głównym. Dlatego wyrażenie pasek boczny jest używane
do definiowania obszaru widżetu, nawet jeśli widżety są stosowane w
innych miejscach niż paski boczne.

Jeżeli zachodzi potrzeba sprawdzenia, czy pasek boczny jest
zarejestrowany i pozostaje w użyciu (ma widżety), bez rzeczywistego
osadzania w nim widżetów, można skorzystać z funkcji
is_active_sidebar(). Wystarczy przekazać identyfikator paska bocznego, a
wartością zwrotną funkcji będzie true, jeśli pasek boczny został
zarejestrowany, w przeciwnym przypadku funkcja zwróci false. Motyw
Twenty Thirteen używa tej funkcji do sprawdzenia (przed przygotowaniem
kodu HTML dla paska bocznego), czy pasek boczny zawiera widżety.

    <?php

    // Kod pochodzi z pliku twenty-thirteen/sidebar.php

    if ( is_active_sidebar( 'sidebar-2' ) ) : ?>

            <div id="tertiary" class="sidebar-container" role="complementary">

                    <div class="sidebar-inner">

                            <div class="widget-area">

                                    <?php dynamic_sidebar( 'sidebar-2' ); ?>

                            </div><!-- .widget-area -->

                    </div><!-- .sidebar-inner -->

            </div><!-- #tertiary -->

    <?php endif; ?>

Osadzanie widżetu poza dynamicznym paskiem bocznym

Standardowy proces dodawania widżetu na stronie internetowej
przedstawiliśmy w poprzedniej sekcji, w której zdefiniowaliśmy
dynamiczny pasek boczny, a następnie dodaliśmy do niego widżet za pomocą
strony widżetów w administracyjnym panelu głównym.

Ewentualnie jeśli dokładnie wiesz, który widżet chcesz umieścić, a nie
chcesz tego zadania pozostawić administratorom mającym dostęp do strony
ustawień widżetów w administracyjnym panelu głównym, możesz go osadzić
za pomocą funkcji the_widget( $widget, $instance, $args ).

$widget

Nazwa klasy PHP dla widżetu.

$instance

Tablica zawierająca ustawienia widżetu.

$args

Tablica zawierająca argumenty standardowo przekazywane funkcji
register_sidebar().

Poza zdefiniowaniem na stałe w kodzie położenia widżetu funkcja
the_widget() umożliwia również programowe definiowanie ustawień widżetu.
W kolejnym fragmencie kodu widżet SchoolPress Note osadziliśmy
bezpośrednio na stronie motywu. Zdefiniowana została tablica egzemplarza
zawierająca pusty ciąg tekstowy jako wartość $note, co gwarantuje, że
notatka zostanie wyświetlona, o ile będzie dostępna.

    // Wyświetlenie widżetu notatki, nadpisanie notatki globalnej

    the_widget('SchoolPress_Note_Widget',  // Nazwa klasy

        array('note'=>''), // Zmienne egzemplarza

        array( // Zmienne widżetu

            'before_widget' => '',

            'after_widget' => '',

            'before_title' => '',

            'after_title' => ''

        )

    );

API widżetów w panelu głównym WordPressa

Widżety panelu głównego to elementy wyświetlane na stronie głównej
administracyjnego panelu głównego WordPressa, jak pokazaliśmy na rysunku
7.2.

[]

Rysunek 7.2. Widżety w panelu głównym

Domyślnie WordPress zawiera kilka różnych widżetów panelu głównego.
Dzięki ich dodawaniu i usuwaniu za pomocą dostępnego API widżetów
tworzona aplikacja WordPressa może być znacznie użyteczniejsza, ponieważ
więcej przydatnych informacji i narzędzi wymaganych przez tę aplikację
znajduje się bezpośrednio na stronie głównej panelu. Takie rozwiązanie
powinno być stosowane we wszystkich aplikacjach WordPressa, których
użytkownicy będą mieli dostęp do administratora WordPressa.

Usunięcie widżetu panelu głównego

Widżety panelu głównego to tak naprawdę metaelementy przypisane do
strony panelu głównego przez administratora. Strona Widgets API w
serwisie WordPress Codex (https://codex.wordpress.org/ Widgets_API)
zawiera listę widżetów domyślnych wyświetlanych w panelu głównym
WordPressa.

    // Lista pochodzi ze strony Dashboard Widgets API w serwisie Codex Page

    // Kolumna główna

    $wp_meta_boxes['dashboard']['normal']['high']['dashboard_browser_nag']

    $wp_meta_boxes['dashboard']['normal']['core']['dashboard_right_now']

    $wp_meta_boxes['dashboard']['normal']['core']['dashboard_recent_comments']

    $wp_meta_boxes['dashboard']['normal']['core']['dashboard_incoming_links']

    $wp_meta_boxes['dashboard']['normal']['core']['dashboard_plugins']

    // Kolumna boczna

    $wp_meta_boxes['dashboard']['side']['core']['dashboard_quick_press']

    $wp_meta_boxes['dashboard']['side']['core']['dashboard_recent_drafts']

    $wp_meta_boxes['dashboard']['side']['core']['dashboard_primary']

    $wp_meta_boxes['dashboard']['side']['core']['dashboard_secondary']

Aby usunąć widżety z panelu głównego, należy wywołać funkcję
remove_meta_box( $id, $page, $context ).

$id

Identyfikator użyty podczas dodawania elementu. Jest to wartość atrybutu
id elementu <div> utworzonego dla elementu meta.

$page

Nazwa strony administracyjnej, do której został dodany element meta.
Jeżeli chcesz usunąć elementy z panelu głównego, użyj opcji dashboard.

$context

W zależności od miejsca dodania elementu wartością będzie normal,
advanced lub side.

Aby usunąć wszystkie widżety domyślne, można skorzystać z zaczepu
wp_dashboard_setup i wywołać funkcję remove_meta_box() dla każdego
widżetu przeznaczonego do usunięcia.

    // Usunięcie wszystkich domyślnych widżetów panelu głównego WordPressa

    function sp_remove_dashboard_widgets()

    {

        remove_meta_box('dashboard_browser_nag', 'dashboard', 'normal');

        remove_meta_box('dashboard_right_now', 'dashboard', 'normal');

        remove_meta_box('dashboard_recent_comments', 'dashboard', 'normal');

        remove_meta_box('dashboard_incoming_links', 'dashboard', 'normal');

        remove_meta_box('dashboard_plugins', 'dashboard', 'normal');

        remove_meta_box('dashboard_quick_press', 'dashboard', 'side');

        remove_meta_box('dashboard_recent_drafts', 'dashboard', 'side');

        remove_meta_box('dashboard_primary', 'dashboard', 'side');

        remove_meta_box('dashboard_secondary', 'dashboard', 'side');

    }

    add_action('wp_dashboard_setup', 'sp_remove_dashboard_widgets');

Inny zestaw widżetów znajduje się w panelu głównym sieci wielu witryn
internetowych i dlatego trzeba skorzystać z innego zaczepu, aby je
usunąć. W kolejnym fragmencie kodu pokazaliśmy użycie zaczepu
wp_network_setup i usunięcie elementów dodanych do strony, której
wartością $page jest dashboard-network.

    // Usunięcie widżetów z panelu głównego sieci witryn

    function sp_remove_network_dashboard_widgets()

    {

      remove_meta_box('network_dashboard_right_now', 'dashboard-network', 'normal');

      remove_meta_box('dashboard_plugins', 'dashboard-network', 'normal');

      remove_meta_box('dashboard_primary', 'dashboard-network', 'side');

      remove_meta_box('dashboard_secondary', 'dashboard-network', 'side');

    }

    add_action('wp_network_dashboard_setup', 'sp_remove_network_dashboard_widgets');

Podobny kod można wykorzystać do usunięcia elementów domyślnych z innych
stron panelu głównego, np. stron edycji i postów. W takich przypadkach
wartością $page podczas usuwania elementów będzie odpowiednio page i
post.

Dodawanie własnego widżetu panelu głównego

Funkcja wp_add_dashboard_widget() jest opakowaniem dla funkcji
add_meta_box(), która dodaje widżet do strony administracyjnego panelu
głównego. Funkcja wp_add_dashboard_widget() pobiera cztery parametry.

$widget_id

Identyfikator dodawanego widżetu jako nazwa klasy CSS opakowania dla
widżetu. Ta wartość jest używana również jako klucz tablicy widżetów
panelu głównego.

$widget_name

Nazwa widżetu wyświetlana w jego nagłówku.

$callback

Funkcja wywołania zwrotnego odpowiedzialna za wygenerowanie widżetu.

$control_callback

Parametr opcjonalny. Wartością domyślną jest null. Jest to funkcja
wywołania zwrotnego przeznaczona do obsługi operacji wyświetlenia i
przetworzenia strony konfiguracji dla widżetu.

Na listingu 7.2 pokazaliśmy dodanie widżetu wyświetlającego stan
aktualnej pracy domowej (zobacz rysunek 7.3). Kod zawiera wywołanie
funkcji wp_add_dashboard_widget() odpowiedzialnej za rejestrację widżetu
panelu głównego, a także funkcję wywołania zwrotnego wyświetlającą
rzeczywisty widżet oraz drugą funkcję wywołania zwrotnego, która
obsługuje widok konfiguracyjny widżetu (zobacz rysunek 7.4).

[]

Rysunek 7.3. Widżet pracy domowej

[]

Rysunek 7.4. Widok konfiguracyjny widżetu pracy domowej

Listing 7.2. Widżet pracy domowej

    <?php

    /*

        Dodanie widżetu do panelu głównego

    */

    function sp_add_dashboard_widgets() {

        wp_add_dashboard_widget(

            'schoolpress_assignments',

            'Assignments',

            'sp_assignments_dashboard_widget',

            'sp_assignments_dashboard_widget_configuration'

        );

    }

    add_action( 'wp_dashboard_setup', 'sp_add_dashboard_widgets' );

    /*

            Widżet pracy domowej

    */

    // Widżet

    function sp_assignments_dashboard_widget() {

        $options = get_option( "assignments_dashboard_widget_options", array() );

        if ( !empty( $options['course_id'] ) ) {

            $group = groups_get_group( array(

                'group_id'=>$options['course_id']

            ) );

        }

        if ( !empty( $group ) ) {

            echo "Wyświetlenie pracy domowej dla klasy " .

                $group->name . ".<br />...";

            /*

                Pobranie pracy domowej dla tej grupy i wyświetlenie jej stanu

            */

        }

        else {

            echo "Wyświetlenie całej pracy domowej .<br />...";

            /*

                Pobranie całej pracy domowej i wyświetlenie jej stanu

            */

        }

    }

    // Konfiguracja

    function sp_assignments_dashboard_widget_configuration() {

        // Pobranie poprzednich ustawień lub domyślne przypisanie pustej tablicy

        $options = get_option( "assignments_dashboard_widget_options", array() );

        // Czy opcje mają zostać zapisane?

        if ( isset( $_POST['assignments_dashboard_options_save'] ) ) {

            // Pobranie wartości course_id

            $options['course_id'] = intval(

                $_POST['assignments_dashboard_course_id']

            );

            // Zapisanie opcji

            update_option( "assignments_dashboard_widget_options", $options );

        }

        // Wyświetlenie formularza opcji

        $groups = groups_get_groups( array( 'orderby'=>'name', 'order'=>'ASC' ) );

        ?>

        <p>Wybór klasy lub grupy, dla której ma być wyświetlona praca domowa.</p>

        <div class="feature_post_class_wrap">

            <label>Klasa</label>

            <select name="assignments_dashboard_course_id">

            <option value="" <?php selected( $options['course_id'], "" );?>>

                Wszystkie klasy

            </option>

            <?php

            $groups = groups_get_groups( array( 'orderby'=>'name', 'order'=>'ASC' ) );

            if ( !empty( $groups ) && !empty( $groups['groups'] ) ) {

                foreach ( $groups['groups'] as $group ) {

                ?>

                <option value="<?php echo intval( $group->id );?>"

                <?php selected( $options['course_id'], $group->id );?>>

                <?php echo $group->name;?>

                </option>

                <?php

                }

            }

            ?>

            </select>

        </div>

        <input type="hidden" name="assignments_dashboard_options_save" value="1" />

        <?php

    }

    ?>

Zwróć uwagę na zaczep wp_dashboard_setup dla funkcji umożliwiającej
dodanie widżetu. Jeżeli widżet ma się pojawić w panelu głównym sieci
witryn internetowych, konieczne jest użycie zaczepu
wp_network_dashboard_setup.

Funkcja sp_assignments_dashboard_widget() odpowiada za faktyczne
wyświetlenie widżetu na stronie panelu głównego. Definiujemy w niej kod
przeprowadzający iterację przez pracę domową i wyświetlający dane
statystyczne związane z tą pracą domową.

Funkcja p_assignments_dashboard_widget_configuration() wyświetla
formularz konfiguracyjny i zawiera kod odpowiedzialny za przetworzenie
wysłanego formularza i uaktualnienie opcji używanych do przechowywania
konfiguracji.

API ustawień

WordPress oferuje API, które można wykorzystać do generowania formularzy
opcji i ustawień dla wtyczek w administracyjnym panelu głównym. To API
zostało bardzo dokładnie udokumentowane w serwisie WordPress Codex
(https://codex.wordpress.org/Settings_API). Tom McFarlin przygotował
doskonały samouczek dotyczący API ustawień w WordPressie, dostępny w
serwisie Envato Tutsplus
(https://code.tutsplus.com/tutorials/the-wordpress-settings-api-part-1-what-it-is-why-it-matters--wp-24060).
Zasoby te zwierają wiele informacji szczegółowych na temat dodawania
stron menu i ustawień w nich przeznaczonych do stosowania we wtyczkach i
motywach. W kolejnych sekcjach przedstawiliśmy wiele podpowiedzi dla
programistów aplikacji.

Czy naprawdę potrzebna jest strona ustawień?

Zanim poświęcisz czas na utworzenie strony ustawień i tym samym dodasz
kolejną warstwę kodu do aplikacji, zastanów się, czy nie wystarczy użyć
zmiennej globalnej do przechowywania tablicy opcji wtyczki lub
aplikacji.

    global $schoolpress_settings;

    $schoolpress_settings = array(

      'info_email' => 'info@schoolpress.me',

      'info_email_name' => 'SchoolPress'

    );

W przypadku aplikacji, którymi będą zarządzali programiści i/lub które
nie będą rozpowszechniane zastosowanie zmiennej globalnej do
przechowywania ustawień może być rozwiązaniem w zupełności
wystarczającym. Wystarczy zmienną globalną zdefiniować na początku pliku
wtyczki lub includes/settings.php, jak pokazaliśmy w poprzednim
fragmencie kodu. Po co tworzyć interfejs użytkownika, skoro i tak nie
będziesz z niego korzystać?

Nawet jeśli wtyczka lub motyw ostatecznie będą rozpowszechniane, i tak
lubimy na początkowym etapie pracy nad projektem korzystać ze zmiennej
globalnej. Ustawienia, które na początku pracy uważasz za niezbędne,
mogą okazać się niepotrzebne po ukończeniu projektu. Ustawienia można
dodawać lub usuwać podczas pracy. Czasami ustawienia, które zdają się
wymagać rozwijanego menu, doskonale sprawdzają się po zastosowaniu pola
tekstowego. Wprawdzie API Settings niezwykle ułatwia dodawanie ustawień
i ich późniejsze uaktualnianie, ale znacznie łatwiej jest zmienić jeden
element w tablicy globalnej niż dodawać lub modyfikować wiele definicji
i wywołań funkcji.

W następujących sytuacjach rozważ użycie zmiennej globalnej dla ustawień
zamiast tworzyć interfejs użytkownika ustawień:

-   Wtyczka będzie dostępna tylko dla członków zespołu.
-   Jedynymi osobami zmieniającymi ustawienia będą programiści.
-   Te ustawienia nie muszą być inne w poszczególnych środowiskach.
-   Te ustawienia prawdopodobnie zmienią się przed wydaniem wtyczki.

Czy zamiast ustawień można użyć zaczepu lub filtru?

Kolejną alternatywą dla dodawania ustawień do wtyczki za pomocą API
Settings jest użycie zaczepu lub wtyczki. Jeżeli ustawienie będzie
stosowane jedynie przez niewielką grupę użytkowników, rozważ dodanie
zaczepu lub filtru.

Przykładowo osoba korzystająca z wtyczki WP-Doc może oczekiwać
możliwości ograniczenia operacji generowania plików w formacie .doc
jedynie dla administratorów lub użytkowników w określonym podzbiorze
ról. Można dodać stronę ustawień wraz z listą pól wyboru oznaczających
role, aby użytkownik mógł wybrać, które z tych ról pozwalają pobierać
pliki .doc. Ewentualnie mogłoby istnieć tylko jedno pole wyboru
umożliwiające pobieranie tych plików wszystkim użytkownikom lub jedynie
administratorom. Jeszcze inne rozwiązanie to dodanie pola tekstowego, w
którym podawana jest nazwa uprawnienia, które trzeba sprawdzić przed
umożliwieniem pobrania pliku.

Jednak najlepszym rozwiązaniem będzie użycie filtru. Sprawdzenie
uprawnień może odbywać się przed udostępnieniem pliku .doc, a filtr
pozwoli programistom pominąć sprawdzenie domyślnej tabeli uprawnień.
Przedstawiony tutaj fragment kodu można dodać do funkcji
wpdoc_template_redirect() wtyczki WP-Doc przed wygenerowaniem pliku w
formacie .doc:

    // Domyślnie nie są wymagane żadne uprawnienia, ale można umożliwić programistom sprawdzanie konkretnych uprawnień

    $caps = apply_filters('wpdoc_caps', array());

    if(!empty($caps))

    {

        // Winny, dopóki nie udowodni swojej niewinności

        $hascap = false;

        // Użytkownik musi być zalogowany, aby w ogóle mieć jakiekolwiek uprawnienia

        if(is_user_logged_in())

        {

            // Upewnienie się, że bieżący użytkownik ma jedno z uprawnień

            foreach($caps as $cap)

            {

                if(current_user_can($cap))

                {

                    $hascap = true;

                    break;  // Zatrzymanie sprawdzania

                }

            }

        }

        if(!$hascap)

        {

            // Pliki nie zostaną wyświetlone

            header('HTTP/1.1 503 Usługa niedostępna', true, 503);

            echo "HTTP/1.1 503 Usługa niedostępna";

            exit;

        }

    }

Istnieje możliwość nadpisania tablicy wpdoc_caps przez dodanie
następujących akcji:

    // Wymagane jest dowolne konto użytkownika

    add_filter('wpdoc_caps', function($caps) { return array('read'); });

    // Wymagane jest konto administratora

    add_filter('wpdoc_caps', function($caps) { return array('manage_options'); });

    // Tylko autorzy lub użytkownicy z uprawnieniem doc

    add_filter('wpdoc_caps', function($caps) { return array('edit_post', 'doc'); });

  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   W poprzednim fragmencie kodu zostały użyte funkcje anonimowe, znane również pod nazwą domknięć. Dlatego wywołanie add_filter() może znajdować się w jednym wierszu, bez konieczności zastosowania oddzielnej funkcji wywołania zwrotnego. Ta składnia wymaga PHP w wersji 5.3 lub nowszej.
  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Warto w tym miejscu przypomnieć, że im więcej wymienionych tutaj punktów
jest prawdziwych, tym większy sens ma użycie zaczepu lub filtru zamiast
interfejsu użytkownika ustawień:

-   Tylko niewielka liczba użytkowników będzie chciała mieć dostęp do
    danego ustawienia.
-   Użytkownikami korzystającymi z danego ustawienia prawdopodobnie będą
    programiści.
-   Użytkownicy korzystający z danego ustawienia prawdopodobnie będą
    mieli własne potrzeby w tym zakresie.
-   Dane ustawienie będzie wymagało ogromnej liczby poszczególnych
    ustawień lub bardziej skomplikowanego interfejsu użytkownika.

Stosowanie standardów podczas dodawania ustawień

Jeżeli zajdzie potrzeba dodania ustawienia do wtyczki lub motywu,
skorzystaj z wymienionych we wcześniejszej części rozdziału źródeł, aby
upewnić się o prawidłowym stosowaniu API ustawień podczas dodawania
niezbędnych ustawień.

Wprawdzie użycie API ustawień wymaga więcej pracy na początku, ale
jednocześnie umożliwia później znacznie łatwiejsze dodawanie i
edytowanie ustawień. Jeżeli zadania wykonujesz zgodnie z duchem
WordPressa, inni programiści będą rozumieli sposób działania Twojego
kodu źródłowego i będą potrafili z niego korzystać. Jeśli programista
zechce utworzyć rozszerzenie dla Twojej wtyczki, skorzysta z zaczepu dla
istniejącego menu i ustawień, aby w ten sposób dodać ustawienia dla tego
rozszerzenia.

Użycie API ustawień gwarantuje również, że dodane przez Ciebie
ustawienia będą wyglądały podobnie do innych ustawień znajdujących się w
panelu głównym użytkownika WordPressa. Na pewno nie chcesz zmuszać
programistów do uczenia się nowego interfejsu użytkownika, aby mogli
korzystać z Twojej wtyczki.

Ignorowanie standardów podczas dodawania ustawień

Wprawdzie zazwyczaj będziesz chciał używać API ustawień i standardów
WordPressa podczas dodawania ustawień dla wtyczki, ale czasami rozsądne
będzie zignorowanie tych standardów.

Najważniejszym powodem podjęcia takiej decyzji jest ogromna liczba
ustawień, dla których powinien zostać utworzony niestandardowy interfejs
użytkownika. Jeżeli masz tylko jedno lub dwa ustawienia, użytkownicy nie
będą spędzać zbyt wiele czasu na ekranach ustawień. Będą chcieli mieć
możliwość jak najszybszej zmiany tych ustawień.

Jeżeli jednak tworzona wtyczka będzie wymagała dziesiątek ustawień,
prawdopodobnie umieszczonych na wielu kartach lub ekranach i powiązanych
ze sobą, wówczas rozsądne będzie potraktowanie ustawień aplikacji jako
oddzielnej aplikacji. Poświęć trochę czasu na dopracowanie interfejsu
użytkownika ekranu ustawień, aby maksymalnie go zoptymalizować.

API ustawień WordPressa jest dość elastyczne w zakresie sposobu
wyświetlania elementów. Zachowujesz kontrolę nad generowaniem
poszczególnych sekcji i pól ustawień. Jednak ostatecznie to oznacza
koncentrację na jednej lub więcej kart wraz z sekcjami elementów. W
przypadku aplikacji zawierających ogromną liczbę ustawień
współdziałających ze sobą być może będziesz chciał skorzystać z innego
sposobu organizacji tych ustawień.

W takich sytuacjach nie powinna Cię przerażać możliwość zignorowania
standardów WordPressa. Do panelu głównego dodaj menu, zdefiniuj funkcję
wywołania zwrotnego odpowiedzialną za dołączenie zbioru zorganizowanych
plików .php w celu wygenerowania formularza i jego przetworzenia oraz, o
ile to możliwe, zastosuj się do następujących wskazówek:

-   Dodaj sekcje menu i elementy zgodnie ze standardami, nawet jeśli
    strony ustawień korzystają z niestandardowego układu.
-   Pamiętaj o oczyszczeniu danych wejściowych.
-   Jeżeli chcesz umożliwić innym użytkownikom rozszerzanie tych
    ustawień, stosuje zaczepy i filtry.
-   Gdy tylko jest to możliwe, stosuj te same elementy HTML i klasy CSS,
    aby ogólny styl był spójny z pozostałą częścią WordPressa, teraz i
    po późniejszych uaktualnieniach frameworka.

Ze względu na stopień skomplikowania oprogramowania typu e-commerce
sensowne jest przyjęcie założenia, że wtyczki typu e-commerce często
wymagają skomplikowanych ekranów ustawień. Oto dwa przykłady wtyczek, w
których zostały zastosowane niestandardowe strony ustawień:

-   Paid Memberships Pro
    (https://wordpress.org/plugins/paid-memberships-pro/) — kod tej
    wtyczki został umieszczony w repozytorium GitHub pod adresem
    https://github.com/strangerstudios/
    paid-memberships-pro/tree/dev/adminpages.
-   WooCommerce (https://wordpress.org/plugins/woocommerce/) — kod tej
    wtyczki został umieszczony w repozytorium GitHub pod adresem
    https://github.com/woocommerce/woocommerce/
    tree/master/includes/admin).

API przepisywania adresów URL

Serwer Apache jest dostarczany wraz z przydatnym modułem o nazwie
mod_rewrite, który pozwala przekierować przychodzące adresy URL do
innych adresów URL lub plików. Te przekierowania odbywają się na
podstawie reguł, które zwykle są definiowane w pliku .htaccess w
katalogu głównym witryny internetowej. Inne serwery WWW oferują podobne
systemy przepisywania adresów URL. Oto standardowe reguły stosowane w
WordPressie:

    # Początek reguł dla WordPressa

    <IfModule mod_rewrite.c>

    RewriteEngine On

    RewriteBase /

    RewriteRule ^index\.php$ - [L]

    RewriteCond %{REQUEST_FILENAME} !-f

    RewriteCond %{REQUEST_FILENAME} !-d

    RewriteRule . /index.php [L]

    </IfModule>

    # Koniec reguł dla WordPressa

Jeżeli chcesz dowiedzieć się więcej na temat modułu mod_rewrite Apache i
sposobu działania reguł WordPressa, David Walsh przygotował doskonałe
wprowadzenie do pliku .htaccess w WordPressie, które opublikował na
stronie https://davidwalsh.name/wordpress-htaccess). Ogólnie rzecz
biorąc, te reguły powodują, że cały ruch przychodzy kierowany do
dowolnego adresu URL nieprowadzącego do katalogu lub pliku będzie
przekierowany do pliku index.php instalacji WordPressa.

Następnie WordPress przetworzy rzeczywisty adres URL w celu ustalenia
posta, strony lub innej treści, która powinna być wyświetlona.
Przykładowo w większości ustawień permalink adres URL w postaci /about/
spowoduje przekierowanie na stronę lub do posta o slugu about.

W większości przypadków można pozostawić WordPressowi obsługę
przekierowań permalink. Jeżeli jednak kiedykolwiek zajdzie potrzeba
dodania reguły niestandardowej, przeznaczonej do obsługi konkretnych
adresów URL w określony sposób, wówczas do tego celu można wykorzystać
API przepisywania adresów URL.

Dodawanie reguły przepisywania adresu URL

Podstawową funkcją pozwalającą dodać regułę przepisywania adresu URL
jest add_rewrite_rule($rule, $rewrite, $position).

$rule

Wyrażenie regularne dopasowujące adres URL, podobne do używanego w
Apache do tworzenia reguł przepisywania adresów URL.

$rewrite

Adres URL do przepisania w przypadku dopasowania reguły. Dopasowane
grupy z wyrażenia regularnego reguły są umieszczane w tablicy o nazwie
$matches.

$position

Wskazuje miejsce umieszczenia danej reguły: przed (top) lub za (bottom)
regułami domyślnymi WordPressa.

Jeżeli za pomocą adresu URL chcesz przekazać do formularza zawartość
tematu, możesz skorzystać z adresu URL w postaci
/contact/special-offer/, który spowoduje przejście na stronę kontaktu i
umieszczenie w wierszu tematu wartości special-offer. Spójrz na regułę,
która pozwala osiągnąć taki efekt:

    add_rewrite_rule(

            '/contact/([^/]+)/?',

            'index.php?name=contact&subject=' . $matches[1],

            'top'

        );

    add_rewrite_rule(

    flush_rewrite_rules();

Po dodaniu tej reguły przejście na stronę /contact/special-offer/
spowoduje przekierowanie na stronę /contact/ i przypisanie
$wp_query->query_vars['subject'] wartości special-offer lub innej, która
została podana po /contact/. Dzięki temu formularz kontaktowy może
używać podanej wartości jako tematu dla wysyłanej wiadomości e-mail.

Usuwanie reguły przepisywania adresu URL

WordPress buforuje reguły przepisywania adresów URL. Dlatego po dodaniu
reguły takiej jak pokazana konieczne jest ponowne wczytanie reguł, aby
zostały one zastosowane. Taka operacja wymaga trochę czasu i dlatego
bardzo ważne jest, aby nie przeprowadzać jej podczas każdego wczytywania
strony. Dla zachowania kolejności reguł przepisywania adresów URL każda
modyfikująca je wtyczka powinna stosować się do następujących zasad:

1.  Dodanie reguły podczas aktywacji wtyczki i natychmiastowe ponowne
    wczytanie wszystkich reguł za pomocą funkcji flush_rewrite_rules().
2.  Dodanie reguły w zaczepie init na wypadek, gdyby operacja ponownego
    wczytywania reguł była wywoływana ręcznie na stronie
    Ustawienia/Bezpośrednie odnośniki (Settings/Permalinks) panelu
    głównego lub przez inną wtyczkę.
3.  Dodanie wywołania flush_rewrite_rules() podczas dezaktywacji
    wtyczki, aby reguła została usunięta wraz z wtyczką.

W kolejnym fragmencie kodu pokazaliśmy, jak wcześniejsza reguła
dotycząca tematu wiadomości pobieranego z adresu URL strony kontaktu
powinna być dodawana zgodnie z trzema wymienionymi tutaj zasadami.

    // Dodanie reguły i ponowne wczytanie reguł podczas aktywacji wtyczki

    function sp_activation()

    {

        add_rewrite_rule(

            '/contact/([^/]+)/?',

            'index.php?name=contact&subject=' . $matches[1],

            'top'

        );

        flush_rewrite_rules();

    }

    register_activation_hook(__FILE__, 'sp_activation');

    /*

      Dodanie reguły w zaczepie init, na wypadek gdyby inna wtyczka wywołała

      operację ponownego wczytania reguł; jest to kosztowna operacja

    */

    function sp_init()

    {

        add_rewrite_rule(

            '/contact/([^/]+)/?',

            'index.php?name=contact&subject=' . $matches[1],

            'top'

        );

    }

    add_action('init', 'sp_init');

    // Ponowne wczytanie reguł podczas dezaktywacji wtyczki, aby usunąć regułę wraz z wtyczką

    function sp_deactivation()

    {

        flush_rewrite_rules();

    }

    register_deactivation_hook(__FILE__, 'sp_deactivation');

Inne funkcje przepisywania adresów URL

WordPress oferuje jeszcze inne funkcje przydatne podczas przepisywania
adresów URL:

add_rewrite_tag()
(https://codex.wordpress.org/Rewrite_API/add_rewrite_tag)

Zapewnia inny sposób dodawania niestandardowych zmiennych ciągu
tekstowego zapytania.

add_feed() (https://codex.wordpress.org/Rewrite_API/add_feed)

Dodaje nowy rodzaj kanału, np. RSS lub ATOM.

add_rewrite_endpoint()
(https://codex.wordpress.org/Rewrite_API/add_rewrite_endpoint)

Dodaje na końcu adresu URL zmienne ciągu tekstowego zapytania.

Dokładniejsze objaśnienie sposobu działania wymienionych funkcji
znajdziesz na poświęconych im stronach w serwisie Codex. Stosowanie
niektórych z tych funkcji ma sens w określonych sytuacjach. Na listingu
7.3 pokazaliśmy, jak można użyć funkcji add_rewrite_endpoint() do
wykrycia, czy na końcu adresu URL został dodany człon /doc/, a następnie
do wymuszenia pobrania pliku .doc. W tym kodzie wykorzystano fakt, że
każdy dokument HTML w pliku o rozszerzeniu .doc będzie otwierany w
aplikacji Microsoft Word.

Funkcja add_rewrite_endpoint() pobiera dwa parametry:

$name*

Bazwa punktu końcowego, np. 'doc'.

$places*

Określa strony, do których będzie dodana reguła punktu końcowego.
Stosowane są stałe EP_* zdefiniowane w pliku wp-includes/rewrite.php.

Listing 7.3. Wtyczka WP DOC

    <?php

    /*

    Nazwa wtyczki: WP DOC

    Adres URI wtyczki: http://bwawwp.com/wp-docx/

    Opis: Dodanie /doc/ na końcu strony lub posta, aby pobrać wersję .docx

    Wersja: .1

    Autor: Stranger Studios

    */

    /*

            Rejestracja punktu końcowego

    */

    // Dodanie punktu końcowego /doc/ podczas aktywacji

    function wpdoc_activation()

    {

        add_rewrite_endpoint('doc', EP_PERMALINK | EP_PAGES);

        flush_rewrite_rules();

    }

    register_activation_hook(__FILE__, 'wpdoc_activation');

    // Użycie zaczepu init, na wypadek gdyby inna wtyczka wywołała operację ponownego

    // wczytania reguł; jest to kosztowna operacja

    function wpdoc_init()

    {

        add_rewrite_endpoint('doc', EP_PERMALINK | EP_PAGES);

    }

    add_action('init', 'wpdoc_init');

    // Ponowne wczytanie reguł podczas dezaktywacji wtyczki, aby usunąć punkt końcowy wraz z wtyczką

    function wpdoc_deactivation()

    {

        flush_rewrite_rules();

    }

    register_deactivation_hook(__FILE__, 'wpdoc_deactivation');

    /*

            Wykrycie użycia /doc/ i zwrot pliku z rozszerzeniem .doc

    */

    function wpdoc_template_redirect()

    {

        global $wp_query;

        if(isset($wp_query->query_vars['doc']))

        {

            global $post;

            // Sprawdzenie, czy mamy do czynienia z postem

            if(empty($post->ID))

                return;

            // Nagłówki dla aplikacji Microsoft Word

            header("Content-type: application/vnd.ms-word");

            header('Content-Disposition: attachment;Filename='.

                $post->post_name.'.doc');

            // Kod HTML

            ?>

            <html>

            <body>

            <h1><?php echo $post->post_title; ?></h1>

            <?php

                echo apply_filters('the_content', $post->post_content);

            ?>

            </body>

            </html>

            <?php

            exit;

        }

    }

    add_action('template_redirect', 'wpdoc_template_redirect');

    ?>

W omawianym fragmencie kodu zwróć uwagę na zastosowanie się do trzech
zasad wymienionych w przykładzie add_rewrite_rule(). Te zasady są
związane z aktywacją i inicjalizacją reguł oraz usuwaniem reguł wraz z
wtyczką.

Podczas definiowania punktu końcowego użyliśmy EP_PERMALINK | EP_PAGES,
co pozwala dodać punkt końcowy do strony pojedynczego posta lub strony
stron[1]. Oto pełna lista stałych maski punktu końcowego:

    EP_NONE

    EP_PERMALINK

    EP_ATTACHMENT

    EP_DATE

    EP_YEAR

    EP_MONTH

    EP_DAY

    EP_ROOT

    EP_COMMENTS

    EP_SEARCH

    EP_CATEGORIES

    EP_TAGS

    EP_AUTHORS

    EP_PAGES

    EP_ALL

Więcej informacji na temat API przepisywania adresów URL znajdziesz w
serwisie Codex na stronach API Rewrite
(https://codex.wordpress.org/Rewrite_API) i klasy WP_Rewrite
(https://codex. wordpress.org/Class_Reference/WP_Rewrite). Klasa
WP_Rewrite oferuje znacznie większe możliwości, ale nie będziemy ich
tutaj prezentować.

WP-Cron

Zadanie mechanizmu cron to skrypt uruchamiany w serwerze w stałych
odstępach czasu. Funkcje Wp-Cron w WordPressie rozszerzają tę
funkcjonalność na Twoją witrynę internetową WordPressa. Zadania
mechanizmu cron, czasami określane mianem zdarzeń, mogą być zdefiniowane
do wykonywania co kilka minut, godzin, dni lub w określonych daniach
tygodnia bądź miesiąca. Do typowych przypadków wykorzystania zadań
mechanizmu cron zaliczamy generowanie wiadomości e-mail, synchronizację
danych z zewnętrznym API, przetwarzanie obliczeń wymagających dużej mocy
obliczeniowej, które następnie są stosowane w raportach i analizach.

Istnieją trzy podstawowe kroki związane z dodawaniem zadania mechanizmu
cron do aplikacji:

1.  Zdefiniowanie harmonogramu dla zadania mechanizmu cron. Zostanie ono
    wywołane w określonym zaczepie lub akcji, w zdefiniowanym odstępie
    czasu.
2.  Przypisanie funkcji do danej akcji.
3.  Zdefiniowanie w funkcji wywołania zwrotnego kodu, który faktycznie
    ma zostać wykonany.

Przedstawiony tutaj fragment kodu może zostać dodany do pliku
niestandardowej wtyczki i pozwala zdefiniować harmonogram pewnych zadań
mechanizmu cron[2]:

    // Utworzenie harmonogramu zadań mechanizmu cron podczas aktywacji wtyczki

    function sp_activation()

    {

        // Wywołanie do_action('sp_daily_cron'); będzie wykonywane codziennie

        wp_schedule_event(time(), 'daily', 'sp_daily_cron');

    }

    register_activation_hook(__FILE__, 'sp_activation');

    // Zadania mechanizmu cron będą usuwane podczas dezaktywacji wtyczki

    function sp_deactivation()

    {

        wp_clear_scheduled_hook('sp_daily_cron');

    }

    register_deactivation_hook(__FILE__, 'sp_deactivation');

    // Funkcja, która będzie wykonywana codziennie

    function sp_daily_cron()

    {

        // Ten kod ma być wykonywany każdego dnia

    }

    add_action("sp_daily_cron", "sp_daily_cron");

Atrybuty funkcji
wp_schedule_event( $timestamp, $recurrence, $hook, $args ) przedstawiają
się następująco:

$timestamp

Znacznik czasu pierwszego wywołania zaczepu. Zwykle będzie to wartość
dostarczana przez funkcję time().

$recurrence

Definiuje częstotliwość wykonywania danego zdarzenia. Można użyć
wartości hourly, daily lub twicedaily albo wykorzystać zaczep
cron_schedules w celu przygotowania innych odstępów czasu.

$hook

Nazwa akcji przeznaczonej do wywołania w trakcie każdego powtórzenia.

$args

Wszelkie argumenty przekazywane do wywoływanego zaczepu mogą być dodane
na końcu wywołania wp_schedule_event().

Lubimy nadawać zadaniom mechanizmu cron nazwy na podstawie
zdefiniowanego odstępu czasu. Dlatego jeżeli będziemy chcieli wykonywać
inną funkcję każdego dnia, do bazy kodu będzie można dodać wywołanie w
postaci add_action('sp_daily_cron', 'nazwa_nowej_funkcji');.

Definiowanie niestandardowego odstępu czasu

Domyślnie funkcja wp_schedule_event() akceptuje jedynie odstępy czasu
hourly, daily i twicedaily. Jeżeli chcesz dodać inny odstęp czasu,
musisz skorzystać z zaczepu cron_schedules, jak pokazaliśmy w kolejnym
fragmencie kodu:

    // Dodanie miesięcznego odstępu czasu przeznaczonego do stosowania w zadaniach mechanizmu cron

    function sp_cron_schedules($schedules)

    {

        $schedules['monthly'] = array(

            'interval' => 60*60*24*30, // Częstotliwość faktycznie wynosi 30 dni

            'display' => 'Raz na miesiąc'

        );

    }

    add_filter( 'cron_schedules', 'sp_cron_schedules' );

W przeciwieństwie do zadań mechanizmu cron w systemie UNIX WP-Cron nie
obsługuje odstępów czasu na podstawie dnia tygodnia. Jeżeli chcesz
skorzystać z takich odstępów czasu, możesz użyć wartości daily, a
następnie sprawdzić dzień tygodnia w wywołaniu funkcji.

    // To zadanie jest wykonywane w poniedziałki

    function sp_monday_cron()

    {

        // Pobranie dania tygodnia, 0 – 6, gdzie 0 oznacza niedzielę

        $weekday = date("w");

        // Czy dzisiaj jest poniedziałek?

        if($weekday == "1")

        {

            // Zdefiniowany w tym miejscu kod będzie wykonywany w poniedziałki

        }

    }

    add_action("sp_daily_cron", "sp_monday_cron");

Podobnie działający kod można wykorzystać do sprawdzania określonego
dnia miesiąca (date("j")) lub nawet konkretnego miesiąca (date("m")).

Tworzenie harmonogramu dla pojedynczych zdarzeń

W poprzednich przykładach pokazaliśmy, jak można wykonywać kod w pewnych
odstępach czasu. Zdarzają się również sytuacje, gdy zdarzenie ma zostać
wywołane kiedyś w przyszłości. Przykładowo chcesz zdefiniować wysyłanie
wiadomości e-mail informującej o nowym poście bloga godzinę po jego
opublikowaniu. W ten sposób autor będzie miał godzinę na usunięcie
ewentualnych problemów z postem bloga, zanim zostaną dostrzeżone przez
użytkowników. Funkcję wp_schedule_single_event() można wykorzystać w
sytuacjach, gdy zdarzenie ma zostać wywołane jednokrotnie.

Wywoływanie zadań mechanizmu cron z serwera

We wszystkich przedstawionych dotychczas przykładach przyjęliśmy
założenie, że zdarzenia zdefiniowane za pomocą wp_schedule_event() nie
zostaną faktycznie uruchomione podczas ich definiowania. Tak się dzieje
niemal zawsze.

W systemie UNIX działa usługa mechanizmu cron i co minutę sprawdza, czy
istnieje skrypt do wykonania. W WordPressie takie sprawdzenie jest
przeprowadzane podczas każdego wczytywania strony. Dlatego jeśli nikt
nie wczyta Twojej witryny internetowej w danym dniu lub wczytywane będą
jedynie strony z bufora statycznego, zadanie mechanizmu cron może nie
zostać uruchomione zgodnie z harmonogramem. Wykonanie zadania nastąpi
podczas kolejnego wczytania strony.

Taka konfiguracja sprawdza się doskonale w przypadku wielu witryn
internetowych opartych na WordPressie, ale nasza aplikacja wymaga
większej niezawodności. Na szczęście można łatwo wyłączyć wewnętrzny
licznik odstępu czasu dla zadań mechanizmu cron i skonfigurować serwer
WWW, aby wywoływał zdarzenie, gdy zajdzie potrzeba.

Jeżeli chcesz wyłączyć licznik odstępu czasu dla zadań mechanizmu cron w
WordPressie, wystarczy w pliku wp-config.php umieścić następujące
polecenie:

    define('DISABLE_WP_CRON', true);

Zdarzenia nadal można dodawać i zarządzać nimi jak wcześniej. Ta stała
umożliwia włączenie lub wyłączenie operacji sprawdzenia, czy zdarzenia
są gotowe do wywołania. Konieczne będzie ręczne sięgnięcie do pliku
wp-cron.php w instalacji WordPressa, aby skrypty były wykonywane wedle
potrzeb.

Jeżeli zdefiniowane są skrypty wykonywane codziennie, wówczas zadanie
mechanizmu cron można dodać za pomocą polecenia crontab -e:

    0 0 * * * wget -O - -q -t 1 http://nazwa_witryny.pl/wp-cron.php?doing_wp_cron=1

  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Informacje dotyczące pracy z mechanizmem cron znajdziesz w artykule Wikipedii na stronie https://pl.wikipedia.org/wiki/Cron. Jeżeli chcesz się dowiedzieć, jak działa polecenie wget, zajrzyj do podręcznika, który znajdziesz na stronie http://www.gnu. org/software/wget/manual/.
  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Zapis 0 0 * * * we wcześniejszym poleceniu nakazuje mechanizmowi cron
wykonywanie danego skryptu 0 minut po godzinie 0 (czyli o północy)
każdego dnia tygodnia.

Z kolei wget -O - -q -t 1
http://nazwa_witryny.pl/wp-cron.php?doing_wp_cron=1 używa polecenia wget
w celu wczytania strony wp-cron.php w instalacji WordPressa. Opcja -O
powoduje przekazanie danych wyjściowych do urządzenia devnull, a -q
włącza tryb cichy. W ten sposób unikniesz dodawania plików do serwera
lub wysyłania danych wyjściowych w trakcie każdego uruchomienia zadania
mechanizmu cron. Opcja -t 1 nakazuje podjęcie tylko jednej próby.
Narzędzie wget nie będzie próbowało wielokrotnie pobrać danych, gdy
pierwsza próba zakończy się niepowodzeniem. W przypadku niepowodzenia
wywołania wp-cron.php pozostała część witryny internetowej
prawdopodobnie również jest niedostępna i raczej zostaniesz o tym
poinformowany.

Upewnij, że adres nazwa_witryny.pl został zmieniony na rzeczywisty adres
URL witryny internetowej. Człon ?doing_wp_cron=1 na końcu adresu URL
jest niezbędny, ponieważ wp-cron.php sprawdzi parametr $_GET przed
wykonaniem kodu.

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Dokładnie upewnij się, czy adres URL w wp-cron.php został wykluczony w ewentualnych mechanizmach buforowania, które mogły zostać zainstalowane w witrynie internetowej.
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

To zadanie mechanizmu cron będzie wywoływane codziennie, a takie zadania
zdefiniowane w WordPressie są wykonywane raz dziennie. Jeżeli zadanie ma
być wykonywane częściej, można zmienić zadanie, aby było wywoływane np.
raz na godzinę lub co kilka minut. Zwróć uwagę na to, że wywołanie
wp-cron.php praktycznie oznacza odwiedziny witryny internetowej.
Sprawdzenie co minutę ma taki sam efekt jak dodatkowe 1440 odwiedzin
Twojej witryny internetowej. Dlatego zachowaj rozsądek podczas
definiowania zadań mechanizmu cron.

Stosowanie zadań mechanizmu cron jedynie po stronie serwera

Jeżeli nie rozpowszechniasz kodu i nie informujesz użytkowników o
konieczności zdefiniowania pewnych zadań mechanizmu cron po stronie
serwera, wówczas w ogóle nie musisz tworzyć harmonogramu zdarzeń cron w
WordPressie. Wystarczy zdefiniować po stronie serwera zadanie mechanizmu
cron, które będzie wywoływało określony adres URL w celu wykonania
funkcji wywołania zwrotnego. Jest to szczególnie użyteczne, gdy chcesz
zachować większą kontrolę nad godzinami wykonywania zadań mechanizmu
cron lub jeśli wolisz zarządzać tymi zadaniami za pomocą systemu UNIX, a
nie w WordPressie.

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Przedstawione w tej sekcji informacje dotyczące tworzenia po stronie serwera harmonogramu zadań mechanizmu cron można wykorzystać do zastąpienia WP-Cron dla powtarzających się zadań. Pojedyncze zdarzenia zdefiniowane za pomocą wp_schedule_single_event() nadal będą musiały być obsługiwane przez WP-Cron lub inny mechanizm.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Jeżeli powrócimy do poprzedniego przykładu zadania wykonywanego w
poniedziałki, kod w WordPressie trzeba uaktualnić do następującej
postaci:

    // Ten kod będzie wykonywany w poniedziałki

    function sp_monday_cron()

    {

        // Sprawdzenie, czy został przekazany parametr zadania mechanizmu cron

        if(empty($_REQUEST['sp_cron_monday']))

            return false;

        // Ten kod będzie wykonywany w poniedziałki

    }

    add_action("init", "sp_monday_cron");

Definicja zadania mechanizmu cron będzie przedstawiała się następująco:

    0 0 * * 1 wget -O - -q -t 1 http://yoursite.com/?sp_cron_monday=1

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Przypominamy ponownie o konieczności upewnienia się, że adres URL ?sp_cron_monday=1 będzie wykluczony z wszelkich mechanizmów buforowania, które mogły zostać dodane do witryny internetowej.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

WP Mail

Funkcja wp_mail() to zamiennik dla wbudowanej w PHP funkcji mail().
Spójrz na wywołanie funkcji wp_mail():

    wp_mail( $to, $subject, $message, $headers, $attachments )

Oto atrybuty tej funkcji:

$to

Pojedynczy adres e-mail, lista rozdzielonych przecinkami adresów e-mail
lub tablica adresów e-mail, na które zostanie wysłana wiadomość.

$subject

Temat wiadomości e-mail.

$message

Treść wiadomości e-mail. Domyślnie wiadomość e-mail jest wysyłana w
postaci zwykłego tekstu i nie powinna zawierać żadnego kodu HTML. Jeżeli
jednak zmienisz typ treści (zapoznaj się z przykładem w dalszej części
rozdziału), powinieneś umieścić kod HTML w wiadomości.

$headers

Opcjonalna tablica nagłówków poczty elektronicznej, które są
przekazywane wraz z wiadomością. Ten atrybut umożliwia dodanie nagłówków
takich jak DW, UDW i innych zaawansowanych nagłówków poczty
elektronicznej.

$attachments

Pojedyncza nazwa pliku lub tablica nazw plików, które mają być dołączone
do wychodzącej wiadomości e-mail.

Mamy dwa duże usprawnienia funkcji wp_mail() względem mail():

-   Funkcja wp_mail() pozwala stosować zaczepy. Filtr wp_mail przekazuje
    tablicę wszystkich parametrów, które funkcja wp_mail() otrzymała w
    celu filtrowania danych. Istnieje również możliwość filtrowania
    nadawców wiadomości za pomocą filtrów wp_mail_from i
    wp_mail_from_name.
-   Funkcja wp_mail() może otrzymać pojedynczą nazwę pliku lub tablicę
    nazw plików w parametrze $attachments, które zostaną dołączone do
    wychodzącej wiadomości e-mail. Dołączanie plików do tych wiadomości
    jest bardzo skomplikowane, ale funkcja wp_mail() ułatwia to zadanie
    dzięki opakowaniu klasy PHPMailer, która z kolei jest opakowaniem
    dla domyślnej w PHP funkcji mail().

Wysyłanie ładniejszych wiadomości e-mail za pomocą WordPressa

Domyślnie nadawcą wiadomości wysyłanych za pomocą funkcji wp_mail() jest
administracyjny adres e-mail zdefiniowany na stronie Ustawienia/Ogólne
(Settings/General) administracyjnego panelu głównego, a zastosowaną
nazwą jest WordPress. Nie jest to idealne rozwiązanie. Do zmiany tych
wartości można wykorzystać filtry wp_mail_from i wp_mail_from_name.

Domyślnie wiadomości e-mail mają format zwykłego tekstu. Jeżeli użyjesz
filtru wp_mail_content_type, wiadomości będą wysyłane w formacie HTML.

Istnieje możliwość dodania eleganckiego nagłówka i stopki do wysyłanych
wiadomości e-mail. Do tego celu można wykorzystać filtr wp_email().

W kolejnym fragmencie kodu przedstawiliśmy połączenie wymienionych
technik, które ma na celu upiększenie wiadomości e-mail wysyłanych z
aplikacji WordPressa.

    // Modyfikacja nazwy i adresu nadawcy

    function sp_wp_mail_from($from_email)

    {

        return 'info@schoolpress.me';

    }

    function sp_wp_mail_from_name($from_name)

    {

        return 'SchoolPress';

    }

    add_filter('wp_mail_from', 'sp_wp_mail_from');

    add_filter('wp_mail_from_name', 'sp_wp_mail_from_name');

    // Wysyłanie wiadomości e-mail w formacie HTML zamiast w zwykłym tekście

    function sp_wp_mail_content_type( $content_type )

    {

        if( $content_type == 'text/plain')

        {

            $content_type = 'text/html';

        }

        return $content_type;

    }

    add_filter('wp_mail_content_type', 'sp_wp_mail_content_type');

    // Dodanie nagłówka i stopki z plików aktywnego motywu

    function sp_wp_mail_header_footer($email)

    {

        // Pobranie nagłówka

        $headerfile = get_stylesheet_directory() . "email_header.html";

        if(file_exists($headerfile))

            $header = file_get_contents($headerfile);

        else

            $header = "";

        // Pobranie stopki

        $footerfile = get_stylesheet_directory() . "email_footer.html";

        if(file_exists($footerfile))

            $footer = file_get_contents($footerfile);

        else

            $footer = "";

        // Uaktualnienie wiadomości e-mail

        $email['message'] = $header . $email['message'] . $footer;

        return $email;

    }

    add_filter('wp_mail', 'sp_wp_mail_header_footer');

Wysyłanie wiadomości e-mail z własnego serwera WWW może rodzić
interesujące problemy sieciowe. Przygotowanie działającego lokalnie na
bazie serwera WWW serwera SMTP przeznaczonego do wysyłania wiadomości
e-mail może być czasochłonne. Na pomyślne dostarczenie wiadomości e-mail
wpływ mają filtry antyspamowe, które mogą nie zawierać na białych
listach adresów IP z zakresu używanego przez Twoją aplikację
internetową. Wtyczki Configure SMTP
(https://wordpress.org/plugins/configure-smtp/) można użyć do wysyłania
wiadomości e-mail za pomocą zewnętrznego serwera SMTP, np. takiego jak
dostępny w ramach konta Aplikacji Google. Usługi typu Mandrill i
SendGrid oferują własne wtyczki WordPressa oraz możliwość wysyłania
wiadomości e-mail poprzez zaufane serwery, zapewniając przy tym
dodatkową możliwość w zakresie obsługi liczników otwarcia lub odrzucenia
wiadomości.

API nagłówka pliku

Blok komentarza na początku plików głównych motywu i wtyczki jest często
określany mianem nagłówka. API nagłówka pliku składa się z trzech
funkcji: get_plugin_data(), wp_get_theme() i get_file_data(), które
pozwalają przetwarzać bloki komentarzy.

Dla przypomnienia pokazujemy, jak może wyglądać nagłówek pliku wtyczki:

    /*

    Nazwa wtyczki: Paid Memberships Pro

    Adres URI wtyczki: http://www.paidmembershipspro.com

    Opis: Wtyczka przeznaczona do obsługi użytkowników witryny internetowej

    Wersja: 1.7.3.2

    Autor: Stranger Studios

    Author URI: http://www.strangerstudios.com

    */

Dzięki wywołaniu funkcji get_plugin_data() te dane można umieścić w
tablicy.

    get_plugin_data( $plugin_file, $markup = true, $translate = true )

Oto atrybuty funkcji get_plugin_data():

$plugin_file

Bezwzględna ścieżka dostępu do głównego pliku wtyczki zawierającego
nagłówek przeznaczony do przetworzenia.

$markup

Opcja, która jeśli przyjmie wartość true, spowoduje zastosowanie kodu
znaczników HTML dla wybranych wartości nagłówka. Przykładowo adres URI
wtyczki zostanie zamieniony na łącze.

$translate

Opcja, która jeśli przyjmie wartość true, przeprowadzi konwersję
wartości nagłówka z użyciem bieżących ustawień lokalizacji.

W kolejnym fragmencie kodu przeprowadzana jest iteracja przez katalog
wtyczek i następuje wyświetlenie danych dla większości wtyczek.
Wyszukanie wtyczek we wszystkich formatach wymaga całkiem sporo logiki.
Do tego celu można użyć funkcji get_plugins(), która zwraca tablicę
wszystkich wtyczek. Kod tej funkcji znajduje się w pliku
wp-admin/includes/plugin.php. Więcej informacji na temat funkcji
get_plugins() znajdziesz w serwisie Codex na stronie
https://codex.wordpress.org/ Function_Reference/get_plugins.

    // Dołączenie tego pliku jest konieczne

    require_once(ABSPATH . "wp-admin/includes/plugin.php");

    // Zachowanie informacji o katalogu bieżącym

    $cwd = getcwd();

    // Przejście do katalogu wtyczek

    $plugins_dir = ABSPATH . "wp-content/plugins";

    chdir($plugins_dir);

    echo "<pre>";

    // Iteracja przez katalog wtyczek i wyświetlenie informacji

    foreach(glob("*", GLOB_ONLYDIR) as $dir)

    {

        $plugin = get_plugin_data($plugins_dir .

        "/" . $dir . "/" . $dir . ".php", false, false);

        print_r($plugin);

    }

    echo "</pre>";

    // Przejście z powrotem do katalogu bieżącego

    chdir($cwd);

Istnieje możliwość użycia funkcji wp_get_theme() w celu pobrania
informacji nagłówka pliku motywu.

    wp_get_theme( $stylesheet, $theme_root )+

Atrybuty tej funkcji przedstawiają się następująco:

$stylesheet

Nazwa katalogu motywu. Jeżeli nie zostanie podana, zostanie użyty
katalog bieżącego motywu.

$theme_root

Bezwzględna ścieżka dostępu do katalogu głównego motywu. Jeżeli nie
zostanie podana, zostanie użyta wartość zwrócona przez funkcję
get_raw_theme_root().

W kolejnym fragmencie kodu przeprowadzana jest iteracja przez katalog
motywów i następuje wyświetlenie danych dla większości motywów.
Wyszukanie wszystkich motywów wymaga całkiem sporo logiki. Do tego celu
można użyć funkcji wp_get_themes(), która zwraca tablicę wszystkich
obiektów typu WP_Theme. Kod tej funkcji znajduje się w pliku
wp-includes/theme.php. Więcej informacji na temat funkcji
wp_get_themes() znajdziesz w serwisie Codex na stronie
https://developer. wordpress.org/reference/functions/wp_get_themes/.

    // Zachowanie informacji o katalogu bieżącym

    $cwd = getcwd();

    // Przejście do katalogu motywów

    $themes_dir = dirname(get_template_directory());

    chdir($themes_dir);

    echo "<pre>";

    // Iteracja przez katalog motywów i wyświetlenie informacji.

    foreach(glob("*", GLOB_ONLYDIR) as $dir)

    {

        $theme = wp_get_theme($dir);

        print_r($theme);

    }

    echo "</pre>";

    // Przejście z powrotem do katalogu bieżącego.

    chdir($cwd);

Dodawanie nagłówków plików do własnych plików

Funkcje get_plugin_info() i wp_get_theme() wykorzystują funkcję
get_file_data() w celu bezpośredniego pobrania nagłówków z dowolnego
pliku. Pozwala to opracować własne podwtyczki (często nazywane modułami
lub dodatkami) dla tworzonych wtyczek.

Funkcja get_file_data( $file, $default_headers, $context = "" ) ma
następujące atrybuty:

$file

Pełna ścieżka dostępu i nazwa pliku, z którego mają zostać pobrane dane.

$default_headers

Tablica właściwości nagłówka. Kluczami w tej tablicy powinny być nazwy
właściwości nagłówka, a wartościami wyrażenia regularne przeznaczone do
przetwarzania etykiet znajdujących się przed dwukropkiem w komentarzu.
Nazwa nagłówka zwykle jest podana jako wyrażenie regularne.

$context

Etykieta umożliwiająca odróżnianie poszczególnych rodzajów nagłówka. Ten
parametr określa, który filtr extra_{context}_headers będzie zastosowany
do domyślnie przekazanych nagłówków.

    // Zdefiniowanie nagłówków dla plików

    $default_headers = array(

        "Title" => "Title",

        "Slug" => "Slug",

        "Version" => "Version"

    );

    // Zachowanie informacji o katalogu bieżącym

    $cwd = getcwd();

    // Przejście do katalogu reports

    $reports_dir = dirname(__FILE__) . "/reports";

    chdir($reports_dir);

    echo "<pre>";

    // Iteracja przez pliki .php w katalogu reports

    foreach (glob("*.php") as $filename)

    {

        $data = get_file_data($filename, $default_headers, "report");

        print_r($data);

    }

    echo "</pre>";

    // Przejście z powrotem do katalogu bieżącego na wypadek, gdy użytkownik oczekuje katalogu domyślnego

    chdir($cwd);

Dodawanie nowych nagłówków do wtyczek i motywów

Filtry extra_plugin_headers i extra_theme_headers można stosować w celu
dodania kolejnych nagłówków do informacji zwróconych przez funkcje
odpowiednio get_plugin_data() i wp_get_theme(). Istnieje również
możliwość wykorzystania filtrów w niestandardowym kontekście pracy
z funkcją get_file_data(). Format ma postać extra_{context}_headers.

Na listingu 7.4 pokazaliśmy dodanie nagłówka Allow Updates do wtyczek.
Jeżeli nagłówek zostanie znaleziony, a jego wartością jest no lub false,
wówczas wtyczka nie będzie mogła zostać uaktualniona.

Listing 7.4. Wtyczka Stop Plugin Updates

    <?php

    /*

    Nazwa wtyczki: Stop Plugin Updates

    Adres URI wtyczki: http://bwawwp.com/plugins/stop-plugin-updates/

    Opis: "Allow Updates: No" i wówczas wtyczka nie będzie uaktualniana

    Wersja: .1

    Autor: Stranger Studios

    Author URI: http://www.strangerstudios.com

    */

    // Dodanie nagłówka AllowUpdates do wtyczki

    function spu_extra_plugin_headers( $headers ) {

        $headers['AllowUpdates'] = "Allow Updates";

            return $headers;

    }

    add_filter( "extra_plugin_headers", "spu_extra_plugin_headers" );

    /*

            Iteracja przez wtyczki; sprawdzenie, czy uaktualnienie jest

            niedozwolone, i jeśli tak, usunięcie wtyczki z listy

    */

    function spu_pre_set_site_transient_update_plugins( $update_plugins ) {

        // Sprawdzenie, czy któraś z wtyczek wymaga uaktualnienia

        if ( !empty( $update_plugins ) && !empty( $update_plugins->response ) ) {

            // Iteracja przez wtyczki

            $new_plugins = array();

            foreach ( $update_plugins->response as $pluginpath => $plugin ) {

                // Sprawdzenie, czy dozwolone jest uaktualnienie wtyczki

                $plugin_data = ABSPATH . '/wp-content/plugins/' . $pluginpath;

                $plugin_data = get_plugin_data( $plugin_data );

                if ( strtolower( $plugin_data['Allow Updates'] ) == "no" ||

                    strtolower( $plugin_data['Allow Updates'] ) == "false" ) {

                    // Zmiana sprawdzonej wersji i niedodawanie do nowej odpowiedzi

                    $update_plugins->checked[$pluginpath] = $plugin_data['Version'];

                }

                else {

                    // Wtyczkę można uaktualnić; dodanie wtyczki do nowej odpowiedzi

                    $new_plugins[$pluginpath] = $plugin;

                }

            }

            $update_plugins->response = $new_plugins;

        }

    return $update_plugins;

    }

    add_action(

        'pre_set_site_transient_update_plugins',

        'spu_pre_set_site_transient_update_plugins'

    );

    ?>

API Heartbeat

API Heartbeat, wprowadzone w WordPressie 3.9, zapewnia komunikację AJAX
niemalże w czasie rzeczywistym oraz pobieranie i przekazywanie
określonej treści do bazy danych WordPressa. Po aktywowaniu API to
będzie co 15 – 30 sekund (domyślnie) sprawdzało wczytaną stronę, aby
ustalić, czy cokolwiek się na niej dzieje. Jest to określane mianem
tętna (ang. heartbeat pulse). Częstotliwość operacji sprawdzania można
ustalić samodzielnie w kodzie (maksymalnie co 60 sekund).

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Zapoznaj się z wtyczką Heartbat Control opracowaną przez Jeffa Matsona. Umożliwia ona łatwą zmianę częstotliwości sprawdzania wczytanej strony, a nawet wyłączenie tej operacji.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

API Heartbeat to bardziej funkcja backendu WordPressa. Wprawdzie można
jej użyć we frontendzie, ale raczej nie powinno się tego robić (można co
najwyżej w ostateczności). Obsługa API Heartbeat może być znacznym
obciążeniem dla serwera, w zależności od sposobu korzystania z niej i
liczby użytkowników. To API jest stosowane w aplikacji WordPressa do
zadań takich jak nakładanie blokad na posty. Na pewno znasz te małe
powiadomienia administracyjne wyświetlane na aktualnie edytowanym poście
i informujące, że ktoś inny czeka na swoją kolej. Jeśli Ci się to
przytrafiło, być może zastanawiałeś się: czy nie widzi on ikony obok
posta i powiadomienia, że właśnie pracuję nad tym postem? To jest
doskonały przykład użycia API Heartbeat do sprawdzenia, kto pracuje nad
postem, i do podjęcia odpowiedniego działania. Podczas wczytywania
strony zawierającej listę postów wiadomo, kto pracuje nad postami.
Następnie API Heartbeat sprawdza co x sekund, czy użytkownik zakończył
pracę nad postem lub ktoś inny otworzył kolejny post i rozpoczął nad nim
pracę. WordPress będzie wiedział o tych akcjach, ponieważ wczytana
strona za pomocą API Heartbeat asynchronicznie przekazuje dane do
serwera w celu ich przetworzenia, a następnie zwrócone dane są przez
JavaScript używane do uaktualnienia wczytanej strony. Tak więc inny
użytkownik wiedział, że pracujesz nad postem i mimo to zdecydował się go
otworzyć… Wrr!

Działanie API Heartbeat opiera się na trzech głównych krokach:

1.  Klient używa jQuery w celu wysyłania danych do serwera. Odbywa się
    to za pomocą zdarzenia heartbeat-send.
2.  Żądanie jest przetwarzane w serwerze i dostarczana jest odpowiedź za
    pomocą PHP. Odbywa się to za pomocą filtra heartbeat_received.
3.  Klient używa jQuery do przetworzenia odpowiedzi otrzymanej z
    serwera. Odbywa się to za pomocą zdarzenia heartbeat-tick.

W omawianym przykładzie opracujemy prostą wtyczkę wykorzystującą API
Heartbeat do wyświetlenia pracownikom szkoły podstawowej, kiedy odebrać
dziecko z samochodu rodzica, który przywiózł je do placówki. Niemalże
każda szkoła podstawowa, z którą mieliśmy do czynienia, stosuje ten
archaiczny i niebezpieczny model. Pracownik szkoły musi niezależnie od
pogody podejść do samochodu, aby rodzic podpisał dokument pozwalający
zabrać dziecko. Mamy 2020 rok i jesteśmy przekonani, że istnieje lepsze
rozwiązanie.

Przystępujemy do opracowania prostej wtyczki wyświetlającej ekran
administracyjny na monitorze w pomieszczeniu, w którym uczniowie
cierpliwie czekają na przybycie rodziców. Będzie to skrócona wersja
wtyczki WordPressa, aby na podstawie jak najmniejszej ilości kodu
pokazać najważniejszą funkcjonalność API Heartbeat.

1.  W katalogu wtyczki utwórz katalog o nazwie the-teacher-life-saver.
2.  W utworzonym katalogu utwórz plik o nazwie
    the-teacher-life-saver.php.
3.  Przeanalizuj i skopiuj przedstawiony tutaj fragment kodu.
4.  Zapisz i aktywuj wtyczkę, a następnie przetestuj ją w
    administracyjnym panelu głównym.

Na listingu 7.5 pokazaliśmy utworzenie widżetu administracyjnego panelu
głównego, który za pomocą API Heartbeat będzie automatycznie wyświetlał
treść przetworzoną przez serwer bez konieczności ręcznego odświeżania
strony.

Listing 7.5. Wtyczka The Teacher Life Saver

    <?php

    /**

    * Nazwa wtyczki: The Teacher Life Saver

    * Adres URI wtyczki:  https://schoolpress.me/

    * Opis: Informuje nauczyciela o przybyciu rodzica ucznia

    * Wersja:     0.0.1

    */

    // Zaczep akcji przeznaczony do utworzenia widżetu panelu głównego

    function ttls_dashboard_widget() {

        global $wp_meta_boxes;

        // Identyfikator widżetu, nazwa widżetu i funkcji wywołania zwrotnego

        wp_add_dashboard_widget('ttls_widget', 'Student Pick Ups', 'ttls_dashboard');

    }

    add_action('wp_dashboard_setup', 'ttls_dashboard_widget');

    // Kod znaczników dla widżetu panelu głównego

    function ttls_dashboard() {

        echo "<div id='ttls_message'></div>";

    }

    // Zmiana domyślnej częstotliwości na 15 sekund, aby nie czekać zbyt długo

    function ttls_heartbeat_settings( $settings ) {

        $settings['interval'] = 15; // Dowolna wartość z przedziału 15 – 60 sekund

        return $settings;

    }

    add_filter( 'heartbeat_settings', 'ttls_heartbeat_settings', 1 );

    // Kolejkowanie heartbeat.js i funkcji JavaScriptu

    function ttls_heartbeat_init()

    {

        // Widżet można uruchomić tylko na stronie panelu głównego (index.php)

        global $pagenow;

        if( $pagenow != 'index.php' )

            return;

        // Kolejkowanie API Heartbeat

        wp_enqueue_script('heartbeat');

        // Wczytanie w stopce funkcji JavaScriptu

        add_action("admin_footer", "ttls_js_wp_footer");

    }

    add_action("admin_init", "ttls_heartbeat_init");

    // Funkcje JavaScriptu wykonane w stopce

    function ttls_js_wp_footer()

    {

        ?>

        <script>

        jQuery(document).ready(function() {

        // Użycie zdarzenia heartbeat-send do wysłania dowolnych kluczy i wartości w tablicy danych

        jQuery(document).on('heartbeat-send', function(e, data) {

            data['client'] = 'check-for-parents';

        });

        // Użycie funkcji heartbeat-tick do sprawdzenia danych i podjęcia akcji

        jQuery(document).on('heartbeat-tick', function(e, data) {

        if(data['server'])

            document.getElementById("ttls_message").innerHTML = data['server']

            + document.getElementById("ttls_message").innerHTML;

            });

        });

        </script>

        <?php

    }

    // Działająca po stronie serwera funkcja, która otrzymuje i przetwarza żądanie, a następnie zwraca odpowiedź

    function ttls_heartbeat_received($response, $data)

    {

        // Wyszukanie danych przekazanych przez funkcję JS heartbeat-send

        if($data['client'] == 'check-for-parents')

        {

            // Przygotowanie dowolnej odpowiedzi

            $r = '<p>';

            $r .= date( 'm/j/y g:i a', current_time( 'timestamp', 0 ) );

            $r .= " - Brian Messenlehner, tata Niny Messenlehner ";

            $r .= "przyjechał białym samochodem Hummer H2 z 2007 roku.";

            $r .= '</p>';

            return $r;

        }

    }

    add_filter('heartbeat_received', 'ttls_heartbeat_received', 10, 2);

    ?>

Jeżeli wszystko zrobiłeś prawidłowo, co mniej więcej 15 sekund będziesz
widzieć w panelu głównym widżet wyświetlający treść umieszczoną w
zmiennej $response[server] w funkcji ttls_heartbeat_received. Po stronie
serwera można przeprowadzić dowolne operacje przetwarzające i zwrócić
dowolną odpowiedź, która następnie zostanie przetworzona po stronie
klienta. W omawianym przykładzie w kodzie została na stałe zdefiniowana
prosta odpowiedź mająca pokazać, że to rozwiązanie działa. Oczywiście
możesz je dowolnie rozbudować. Wyobraź sobie rodzica, który ma
w smartfonie aplikację wykorzystującą geolokalizację do ustalenia wjazdu
na teren szkolnego parkingu. Gdy rodzic zaparkuje, jego położenie
zostanie uaktualnione. W trakcie następnej operacji sprawdzenia, czy
przybyli nowi rodzice, informacje o nowo przybyłym rodzicu zostaną
wyświetlone na monitorze. Wprawdzie w przykładzie przedstawiliśmy tylko
podstawowe informacje, ale mogą być one znacznie bardziej rozbudowane i
zawierać dane ucznia, dane rodzica, zdjęcie rodzica, dane pojazdu, w tym
numer rejestracyjny, zdjęcie pojazdu i wszelkie inne istotne informacje.

[1] Mamy tutaj na myśli posty z właściwością post_type o wartości page.

[2] Jeżeli ten kod umieścisz w podkatalogu projektu, konieczne będzie
uaktualnienie wywołań register_activation_hook() i
register_deactivation_hook(), aby wskazywały główny plik wtyczki.

Rozdział 8. Bezpieczny WordPress

Hakerzy, strzeżcie się! Ten rozdział jest wypełniony wskazówkami i
poradami, jak zapewnić większe bezpieczeństwo witrynom internetowym
utworzonym na podstawie WordPressa. Mamy nadzieję, że dzięki tym
informacjom uda się uniemożliwić hakerom skuteczny atak na aplikację
WordPressa.

Dlaczego bezpieczeństwo jest ważne?

Niezależnie od wielkości witryny internetowej zapewnienie bezpieczeństwa
to kwestia, której nie wolno pominąć. Każda witryna może stać się celem
hakera lub oprogramowania malware. Odpowiednia wiedza i profilaktyka w
zakresie bezpieczeństwa WordPressa spowoduje, że nie będziesz już
bezbronny i zdołasz uniknąć (mamy nadzieję) skutecznych ataków.

Jeden z najpopularniejszych typów ataku nosi nazwę brute-force attack i
polega na tym, że bot lub skrypt próbuje uzyskać dostęp do witryny
internetowej przez odgadnięcie poprawnego połączenia nazwy użytkownika i
hasła. Jeżeli to Cię nie przeraża, to musisz wiedzieć, że te boty to
ogromne sieci komputerów wykonujących w ciągu sekundy setki lub nawet
tysiące prób odgadnięcia owego połączenia nazwy użytkownika i hasła.
Nawet jeśli bot nie uzyska dostępu do obszaru administracyjnego
WordPressa, i tak może skutecznie zablokować witrynę internetową ogromną
liczbą wykonywanych żądań, których serwer nie będzie w stanie obsłużyć
lub nie będzie odpowiadał na podejrzane żądania. Taki rodzaj ataku jest
określany mianem ataku odmowy usług (ang. denial of service attack) i
może być celowym atakiem lub przeprowadzanym przez zautomatyzowane
spamery i skrypty ataków typu brute force.

W tym rozdziale przedstawimy wbudowane w WordPress standardowe funkcje
związane z zapewnieniem bezpieczeństwa oraz zaprezentujemy wskazówki,
dzięki którym możesz bardzo łatwo zwiększyć bezpieczeństwo witryny
internetowej. Wskażemy także wtyczki pomocne w walce z innymi
zagrożeniami, np. ze spamem.

Jeżeli zdecydujesz się pominąć ten rozdział, możesz później bardzo tego
żałować. Oto niebezpieczeństwa, z którymi można się najczęściej spotkać:

-   Próbujesz przejść do witryny internetowej, ale okazuje się, że jest
    ona niedostępna. Przestój jest niedopuszczalny! Mamy nadzieję, że
    regularnie tworzysz kopię zapasową witryny i możesz ją szybko
    przywrócić.
-   Zauważyłeś, że Twoja witryna zaczyna się pojawiać w wynikasz
    wyszukiwania viagry oraz innych podobnych specyfików. To kiepska
    wiadomość, o ile nie prowadzisz firmy prowadzącej sprzedaż takich
    produktów.
-   Twoja witryna internetowa wysyła wszystkim jej użytkownikom
    wiadomości e-mail z łączami prowadzącymi do wirusów komputerowych.
    Nikt nie chce otrzymywać takich wiadomości.
-   Twoja witryna internetowa została skutecznie zaatakowana, co
    doprowadziło do ujawnienia danych osobowych jej użytkowników
    (imienia i nazwiska, adresu, numeru telefonu, adresu e-mail itd.).
-   Twoja witryna internetowa została skutecznie zaatakowana i jest
    wykorzystywana w celu przekazywania oprogramowania o złośliwym
    działaniu (np. malware) do innych witryn internetowych. Jest to
    najkrótsza droga do skreślenia z listy wyników w wyszukiwarce
    internetowej Google oraz z wielu innych podobnych katalogów witryn.

Podstawy zapewnienia bezpieczeństwa

W dalszej części rozdziału omawiamy proste, choć jednocześnie ważne
kwestie dotyczące zapewnienia bezpieczeństwa. Zapoznaj się z nimi
dokładnie, ponieważ dzięki temu możesz zaoszczędzić wiele czasu i
pieniędzy oraz uniknąć niezadowolenia użytkowników Twojej aplikacji
internetowej.

Regularnie uaktualniaj oprogramowanie

Pierwsza i najważniejsza kwestia wiąże się z tym, aby zawsze uaktualniać
framework do najnowszej dostępnej wersji WordPressa. To samo dotyczy
wszystkich zainstalowanych wtyczek i motywów. Wiele tych uaktualnień ma
związek z poprawkami bezpieczeństwa. Dlatego tak ważne dla zachowania
bezpieczeństwa jest regularne uaktualnianie oprogramowania.

Nie używaj nazwy użytkownika admin

Kolejną kwestią jest to, że żadne konto użytkownika nie może mieć nazwy
admin. Wiele botów automatycznie próbuje zalogować się do witryny
internetowej, posługując się tą nazwą użytkownika. Wiedza o tym, że
sporo osób nie zmienia tej nazwy, to już połowa sukcesu i atakujący może
skoncentrować się na złamaniu hasła. Podczas instalacji WordPressa
domyślną nazwą użytkownika jest admin i trzeba ją zmienić. Jeżeli
używasz instalacji WordPressa zawierającej konto o nazwie użytkownika
admin, utwórz nowe konto z uprawnieniami administratora, zaloguj się do
nowego konta, a następnie usuń domyślne konto administracyjne admin.
Upewnij się również, że została zmieniona nazwa autora dla wszystkich
postów lub stron, które wcześniej utworzyłeś za pomocą domyślnego konta
admin.

Używaj silnych haseł

Wybór silnego hasła także jest bardzo ważny, zwłaszcza w przypadku kont
z uprawnieniami administracyjnymi. Nie używaj pojedynczego słowa ani
imienia. Zdefiniuj trudne do odgadnięcia hasło, które w żaden sposób nie
będzie z Tobą powiązane.

Hasło powinno się składać z małych i wielkich liter, cyfr oraz znaków
specjalnych. Silne hasło powinno mieć przynajmniej 10 znaków, a im jest
dłuższe, tym jest silniejsze. Jeżeli masz trudność z wymyśleniem takiego
hasła, spróbuj naciskać losowo wybrane klawisze lub skorzystaj z usługi
takiej jak Random.org (https://www.random.org/passwords/). Zapamiętaj
hasło lub zapisz je w bezpiecznym miejscu. WordPress informuje, czy
hasło można uznać za bezpieczne, i tymi informacjami należy się
kierować.

Przykłady beznadziejnych haseł

Oto kilka przykładów beznadziejnych haseł:

-   hasło,
-   hasło123,
-   hasł0,
-   123456789,
-   qwerty,
-   batman,
-   mustang,
-   1qaz2wsx.

Równie kiepskim pomysłem jest wykorzystanie w haśle słów kojarzących się
z użytkownikiem, jego imienia i nazwiska lub ważnej daty z jego życia:

-   wojskopolskie (użytkownik służył w wojsku),
-   jankowalski (imię i nazwisko użytkownika),
-   janek&anna050507 (imię użytkownika, imię jego żony i data ich
    ślubu),
-   Dorota-Bartek (imiona dzieci),
-   AzorPuszekPimpek (imiona zwierząt),
-   JESTEMBOSKI (każdy o tym wie, więc nietrudno zgadnąć).

Każdy, kto wie cokolwiek o danej osobie lub jej rodzinie, będzie mógł
odgadnąć takie hasło.

Przykłady dobrych haseł

Oto kilka przykładów silnych haseł:

-   U$s(#8H27@!,
-   !lik32EaTF1$h&CHIp5,
-   #Uk@nN0tBr3akTh1s$h1t!!!,
-   [0mG-LoL-R0Fl-T0T3$CraY]!.

Wpisanie silnego hasła będzie wymagało kilku dodatkowych sekund, ale
zdecydowanie warto je poświęcić, aby zminimalizować niebezpieczeństwo
skutecznego ataku na witrynę lub aplikację.

Zabezpieczenie WordPressa

Zabezpieczanie witryny internetowej jest w języku angielskim często
określane mianem hardening. Sekcja Hardening WordPress w dokumentacji
WordPressa (https://wordpress.org/support/article/ hardening-wordpress/)
zawiera informacje podobne do tych, które zamieściliśmy w tym rozdziale,
oraz wiele innych. Dlatego najpierw zapoznaj się z materiałem
przedstawionym w rozdziale, a następnie sięgnij do dokumentacji.

Przechodzimy teraz do kilku technik utrudniających przeprowadzenie
skutecznego ataku na aplikację internetową.

Nie zezwalaj administratorowi na edycję wtyczek lub motywów

Domyślnie WordPress zezwala administratorom na edycję kodu źródłowego
dowolnej wtyczki lub motywu bezpośrednio w przeglądarce WWW. Należy
wyłączyć tę funkcjonalność, ponieważ jeśli hakerowi uda się zalogować do
jednego z kont administracyjnych, nie będzie w stanie dodać za pomocą
interfejsu użytkownika żadnego kodu o złośliwym działaniu. Aby wyłączyć
tę funkcję, do pliku wp-config.php dodaj następujące polecenie:

    define( 'DISALLOW_FILE_EDIT', true );

Zmień domyślny prefiks tabel bazy danych

Standardowa instalacja WordPressa używa wp_ jako prefiksu dla wszystkich
tabel bazy danych. Prosta zmiana prefiksu na inny powoduje, że witryna
internetowa staje się odporniejsza na ataki hakerów próbujących
wstrzyknąć kod SQL. W zupełnie nowej instalacji WordPressa masz
możliwość wykorzystania dowolnego prefiksu tabeli. Zawsze należy zmienić
domyślny prefiks wp_ na inny.

Jeżeli taką zmianę chcesz przeprowadzić w już działającej witrynie
internetowej, wykonaj następujące kroki:

1.  Utwórz kopię bazy danych na wypadek awarii lub błędu podczas
    operacji zmiany prefiksu.

2.  Przejdź do pliku wp-config.php i zmień polecenie $table_prefix =
    wp_; na $table_prefix = dowolnyprefiks_;.

3.  Uaktualnij nazwy istniejących tabel w bazie danych, aby zawierały
    nowy prefiks. Możesz w tym celu skorzystać z wymienionych tutaj
    poleceń SQL i narzędzia phpMyAdmin lub jakiegokolwiek innego klienta
    SQL, np. MySQL Workbench.

        rename table wp_commentmeta to dowolnyprefiks_commentmeta;

        rename table wp_comments to dowolnyprefiks_comments;

        rename table wp_links to dowolnyprefiks_links;

        rename table wp_options to dowolnyprefiks_options;

        rename table wp_postmeta to dowolnyprefiks_postmeta;

        rename table wp_posts to dowolnyprefiks_posts;

        rename table wp_terms to dowolnyprefiks_terms;

        rename table wp_term_relationships to dowolnyprefiks_term_relationships;

        rename table wp_term_taxonomy to dowolnyprefiks_term_taxonomy;

        rename table wp_usermeta to dowolnyprefiks_usermeta;

        rename table wp_users to dowolnyprefiks_users;

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------
  []   Podobne polecenia SQL rename musisz wydać dla wszelkich tabel niestandardowych, które zostały dodane przez Twoją aplikację lub stosowane wtyczki.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------

Używając poleceń SQL lub klienta SQL, uaktualnij wszystkie wystąpienia
wp_ w tabelach prefiks_options i dowolnyprefiks_usermeta oraz zmień
wartości wp_ na prefiks_:

    update dowolnyprefiks_options set option_name = replace(

    option_name,'wp_','dowolnyprefiks_');

    update dowolnyprefiks_usermeta set meta_key = replace(

    meta_key,'wp_','dowolnyprefiks_');

Przetestuj witrynę internetową i upewnij się, że działa zgodnie z
oczekiwaniami.

Jeżeli nie czujesz się pewnie, by ręcznie wprowadzać takie zmiany,
możesz skorzystać z dostępnych wtyczek, które pozwolą zmienić prefiks
tabeli:

-   Change Table Prefix
    (https://wordpress.org/plugins/change-table-prefix/),
-   Brozzme DB Prefix & Tools Addons
    (https://wordpress.org/plugins/brozzme-db-prefix-change/).

Przenieś wp-config.php

Plik wp-config.php WordPressa przechowuje cenne informacje, takie jak
lokalizacja bazy danych, nazwa użytkownika, hasło i klucze
uwierzytelnienia w WordPressie. Ponieważ te wartości są przechowywane w
zmiennych PHP i nie są wyświetlane w przeglądarce WWW, nikt nie może
uzyskać dostępu do tych danych, choć teoretycznie może do tego dojść.
Plik wp-config.php można przenieść w hierarchii instalacji WordPressa o
jeden poziom w górę, co w większości przypadków będzie oznaczało katalog
niepubliczny. Jeżeli plik nie zostanie znaleziony w katalogu głównym,
WordPress automatycznie poszuka go na poziomie o jeden wyższym.
Przykładowo po przeniesieniu pliku
/nazwa_użytkownika/public_html/wp-config.php o jeden poziom wyżej jego
ścieżka dostępu będzie miała następującą postać:
/nazwa_użytkownika/wp-config.php.

Istnieje również możliwość przechowywania pliku wp-config.php pod
dowolną nazwą w dowolnym katalogu. W tym celu utwórz kopię pliku, zmień
jego nazwę na dowolną, a następnie przenieś go do dowolnego katalogu
znajdującego się na poziomie wyższym od katalogu głównego instalacji
WordPressa. W oryginalnym pliku wp-config.php usuń całą zawartość i
dodaj polecenie include ze względną ścieżką dostępu do nowo utworzonego
pliku. Przykładowo plik /nazwa_użytkownika/ public_html/wp-config.php
zmień na /nazwa_użytkownika/dowolny_katalog/nazwa_pliku.php. Następnie w
pliku wp-config.php musisz umieścić polecenie
include('/nazwa_użytkownika/dowolny_katalog/nazwa_pliku.php');.

Ukryj komunikaty błędów logowania

Standardowo, gdy próbujesz zalogować się do witryny internetowej,
WordPress wyświetla komunikat błędu w przypadku podania nieprawidłowej
nazwy użytkownika lub hasła. Niestety dzięki temu haker będzie dokładnie
wiedział, czy popełnił błąd, próbując uzyskać dostęp do witryny.

Na szczęście istnieje proste rozwiązanie. Wystarczy do pliku
functions.php motywu lub niestandardowej wtyczki dodać przedstawiony
tutaj fragment kodu, który ukryje lub zmodyfikuje ów komunikat.

    add_filter( 'login_errors', function ( $message ) {

        return "Nieprawidłowa nazwa użytkownika lub hasło.";

    } );

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Przedstawiony tutaj fragment kodu używa funkcji anonimowej (https://www.php.net/ manual/en/functions.anonymous.php) jako funkcji wywołania zwrotnego w drugim parametrze funkcji add_filter(). To wymaga PHP w wersji 5.3 lub nowszej. Można również zdefiniować funkcję nazwaną dla wywołania add_filter(), choć w takim przypadku nie będziemy mieli rozwiązania w postaci jednego wiersza kodu.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Ukryj numer wersji WordPressa

Wiele botów przeczesuje internet w poszukiwaniu witryn internetowych
zbudowanych na podstawie WordPressa i sprawdza wykorzystaną wersję
WordPressa. Te boty szukają witryn, które używają wersji zawierających
doskonale znane luki w zabezpieczeniach, by je wykorzystać do ataku.
Domyślnie WordPress umieszcza następujący kod w elemencie <head> na
każdej stronie:

    `<meta name="generator" content="WordPress 3.8.1" />`

Bardzo łatwo można ukryć wersję WordPressa za pomocą następującego
polecenia:

    add_filter( 'the_generator', '__return_null' );

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Istnieją różne sposoby, by ustalić, czy witryna internetowa została zbudowana na podstawie WordPressa i wersję frameworka. Przykładowo jeśli nie jest podana wersja skryptu, wersja WordPressa będzie dołączana do adresów URL plików JavaScript. Istnieją inne, jeszcze bardziej subtelne sposoby, w jakie haker może ustalić wersję WordPressa stosowaną w witrynie internetowej. Mimo to mile widziane jest każde dodatkowe zabezpieczenie pomocne w odpieraniu zautomatyzowanych ataków, które nieustannie mają miejsce w internecie.
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Uniemożliw logowanie poprzez stronę wp-login.php

Niektóre boty są wyjątkowo sprytne. Wiesz już, jak ukryć numer wersji
WordPressa przed wybranymi botami. Jednak niektórym botom wystarczy
jedynie informacja, że używany jest framework WordPress. Bardzo łatwo ją
uzyskać, gdy będzie wykonywane żądanie POST do strony wp-login.php.
Kiedy bot ustali istnienie tej strony, może rozpocząć próby zalogowania
się do witryny internetowej.

Dobrym rozwiązaniem jest zastosowanie przekierowania ze strony
wp-login.php na stronę główną, co uniemożliwi botom podjęcie prób
zalogowania się do witryny. Wykonaj następujące kroki, aby przygotować
alternatywną stronę logowania i ukryć domyślną wp-login.php:

1.  Do pliku .htaccess dodaj następującą regułę:

        RewriteRule ^new-login$ wp-login.php

    Zwróć uwagę na to, że /new-login/ będzie adresem URL, który posłuży
    do faktycznego zalogowania się na stronie wp-admin. Tę wartość
    możesz zmienić na dowolnie wybraną.

2.  W pliku functions.php motywu lub wtyczki umieść następujący fragment
    kodu:

        function schoolpress_wp_login_filter( $url, $path, $orig_scheme ) {

            $old = array( "/(wp-login\.php)/" );

            $new = array( "new-login" );

            return preg_replace( $old, $new, $url, 1 );

        }

        add_filter( 'site_url', 'schoolpress_wp_login_filter', 10, 3 );

        function schoolpress_wp_login_redirect() {

            if ( strpos( $_SERVER["REQUEST_URI"], 'new-login' ) === false ) {

                wp_redirect( site_url() );

                exit();

              }

        }

        add_action( 'login_init', 'schoolpress_wp_login_redirect' );

Jeżeli nie zamierzasz tworzyć żadnego niestandardowego kodu, ten sam
wynik możesz osiągnąć dzięki użyciu następujących wtyczek:

-   iThemes Security
    (https://wordpress.org/plugins/better-wp-security/),
-   Lockdown WP Admin
    (https://wordpress.org/plugins/lockdown-wp-admin/).

Dodaj niestandardowe reguły .htaccess w celu zabezpieczenia strony wp-admin

Jeżeli jesteś jedynym użytkownikiem wymagającym zalogowania się do
backendu aplikacji lub w przypadku istnienia niewielkiej liczby
użytkowników backendu, dostęp do backendu można ograniczyć do wskazanych
adresów IP. W katalogu wp-admin instalacji WordPressa utwórz plik
.htaccess i dodaj przedstawiony tutaj fragment kodu. Pamiętaj, aby
127.0.0.1 zastąpić swoim rzeczywistym zewnętrznym adresem IP. Jeżeli nie
znasz tego adresu, odwiedź witrynę https://ipchicken.com/.

    order deny,allow

    allow from 127.0.0.1 # (W przypadku wielu adresów IP ten wiersz musisz powtórzyć)

    deny from all

Gdy podejrzewasz, że z pewnych adresów IP odwiedzającymi aplikację są
boty lub złośliwie działający użytkownicy, możesz te adresy zablokować
za pomocą następującego fragmentu kodu:

    order allow,deny

    deny from 127.0.0.1 # (W przypadku wielu adresów IP ten wiersz musisz powtórzyć)

    allow from all

Jeżeli ktoś będzie chciał się dostać do witryny internetowej z
zablokowanego adresu, będzie musiał skorzystać z serwera proxy.

Gdy uważasz, że użytkownicy backendu lub adresy IP zmieniają się zbyt
często, albo jeśli masz zbyt dużą grupę użytkowników, których adresami
IP musisz zarządzać, wówczas można dodać nazwę użytkownika i hasło, a
otrzyma on dostęp do katalogu wp-admin. W ten sposób do aplikacji
zostanie dodana elegancka druga warstwa uwierzytelniania, ponieważ
wszyscy użytkownicy backendu będą musieli podać nazwę użytkownika
htaccess i hasło oraz standardową nazwę użytkownika i hasło w
WordPressie.

    AuthType Basic

    AuthName "restricted area"

    AuthUserFile /ścieżka/dostępu/do/chronionego/katalogu/.htpasswd

    require valid-user

Zwróć uwagę na wiersz zawierający polecenie AuthUserFile. Plik .htpasswd
musisz utworzyć w katalogu nadrzędnym dla instalacji WordPressa. W pliku
trzeba umieścić nazwę użytkownika i hasło. Jako hasła nie używaj
wartości w postaci zwykłego tekstu, lecz skorzystaj z narzędzia takiego
jak generator hasła htaccess
(http://www.kxs.net/support/htaccess_pw.html), które utworzy
zaszyfrowane hasło.

Dlatego jeśli jako nazwę użytkownika i hasło podasz
letmein/Pr3tTyPL3a$3!, po zaszyfrowaniu otrzymasz letmein:E5Dj7cUaQVcN..

Następnie ten cały zaszyfrowany ciąg tekstowy, letmein:E5Dj7cUaQVcN.,
umieść w pliku .htpasswd. Gdy użytkownik przejdzie na stronę /wp-admin,
będzie musiał podać nazwę użytkownika i hasło. Przekaż użytkownikom
backendu ich dane uwierzytelniające i poinformuj ich, aby nikomu ich nie
udostępniali.

Certyfikaty SSL i HTTPS

Podczas pobierania danych wrażliwych z formularza internetowego, np.
numeru karty kredytowej, informacje powinny być szyfrowane poprzez ich
wczytywanie i wysyłanie z użyciem SSL przez protokół HTTPS. Na początek
zapoznaj się z kilkoma definicjami:

SSL

Skrót od secure socket layer; technologia szyfrowania danych
przekazywanych do strony internetowej i ze strony internetowej.

HTTP

Skrót od hypertext transfer protocol; standardowy protokół przekazywania
stron internetowych za pomocą nieszyfrowanego kanału transmisji.

HTTPS

Skrót od http secure; protokół przekazywania stron internetowych za
pomocą połączenia szyfrowanego z użyciem SSL.

Podczas konfigurowania SSL w serwerze i instalowania certyfikatu SSL
masz do dyspozycji wiele opcji. Obecnie wszystkie witryny internetowe
(nie tylko witryny e-commerce) powinny używać protokołu HTTPS dla całej
komunikacji, a nie jedynie podczas przekazywania danych wrażliwych.
W kolejnych sekcjach przedstawimy nieco więcej informacji na temat
wspomnianych opcji.

Instalacja certyfikatu SSL w serwerze

Przede wszystkim trzeba włączyć SSL w serwerze WWW. Sposób włączenia
zależy od konkretnego hosta i serwera WWW. Firma DigitalOcean
przygotowała doskonałe dokumenty administracyjne i bardzo użyteczny
artykuł na temat konfiguracji SSL w serwerze Apache. Zajrzyj na stronę
https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-apache-in-ubuntu-16-04.

Po włączeniu usługi SSL w hoście konieczne jest zainstalowanie
certyfikatu SSL. Wprawdzie do celów testowych można wykorzystać
samodzielnie podpisane certyfikaty, ale nowoczesne przeglądarki WWW będą
wyświetlały komunikat ostrzeżenia po przejściu na witrynę internetową,
na której został użyty taki certyfikat. Przykład takiego ostrzeżenia
wyświetlanego przez przeglądarkę WWW Chrome pokazaliśmy na rysunku 8.1.

[]

Rysunek 8.1. Wyświetlane przez Chrome ostrzeżenie o użyciu samodzielnie
podpisanego certyfikatu SSL

W środowisku produkcyjnym należy używać certyfikatu klucza publicznego
wydanego przez urząd certyfikacji (ang. certificate authority). Taki
certyfikat można kupić, często jest dodawany również do pakietu usług
hostingowych. Istnieje też możliwość zakupu certyfikatu SSL w firmie
zewnętrznej. Wszystkie nowoczesne przeglądarki WWW akceptują dobre
certyfikaty SSL, na co wskazuje ikona przedstawiająca zieloną lub złotą
kłódkę zamiast złamanej lub czerwonej kłódki.

Do dyspozycji mamy dobre rozwiązania w zakresie zarówno płatnych, jak i
bezpłatnych certyfikatów SSL. Kupując certyfikat SSL, tak naprawdę
potwierdzasz prawo własności domeny, na której ten certyfikat będzie
użyty. Prawo własności jest zwykle potwierdzane za pomocą adresu e-mail
wysyłanego na adres domeny. Ewentualnie, jak w przypadku usługi Let’s
Encrypt, potwierdzenie odbywa się za pomocą zautomatyzowanych skryptów
uruchamianych z poziomu danego serwera.

Przypominamy ponownie, że każda witryna internetowa powinna mieć
zainstalowany certyfikat SSL. W pierwszym wydaniu książki
przedstawiliśmy metody pozwalające wyświetlać strony administracyjne i
finalizacji zamówienia poprzez połączenie HTTPS, a pozostałe strony
witryny poprzez nieszyfrowane połączenie HTTP. Obecnie nie zalecamy już
stosowania takiego podejścia hybrydowego. Internet stał się miejscem, w
którym całą witrynę internetową najlepiej jest udostępniać poprzez
połączenie HTTPS. Jest to jeden z aspektów większego ruchu
„bezpieczeństwo przede wszystkim”.

+----------------------------------------------------------------------+
| Usługa Let’s Encrypt                                                 |
|                                                                      |
| W czasie, jaki minął od opublikowania pierwszego wydania tej         |
| książki, pojawiła się nowa usługa, Let’s Encrypt, która oferuje      |
| certyfikaty klucza publicznego, jest łatwa w instalacji i całkowicie |
| bezpłatna. Certyfikaty Let’s Encrypt są instalowane z poziomu        |
| powłoki za pomocą narzędzia o nazwie Certbot. Narzędzie to jest      |
| dostępne dla większości platform serwerów WWW. Jeżeli serwer WWW     |
| został skonfigurowany prawidłowo i ma połączenie z internetem,       |
| Certbot będzie w stanie samodzielnie się zweryfikować z urzędem      |
| certyfikacji Let’s Encrypt, wygenerować certyfikat, a następnie      |
| zainstalować go w systemie. Istnieje możliwość przygotowania zadania |
| mechanizmu cron, które będzie automatycznie odnawiało ten certyfikat |
| np. co trzy miesiące.                                                |
|                                                                      |
| Nawet jeśli nie zarządzasz serwerem WWW, możesz skorzystać z         |
| certyfikatu Let’s Encrypt w tym serwerze WWW. Rozwiązania płatne     |
| zwykle są doskonale widoczne w panelu sterowania serwera WWW, a      |
| opcje takie jak Let’s Encrypt mogą być dostępne na żądanie.          |
+----------------------------------------------------------------------+

Istnieje kilka powodów, dla których warto stosować połączenie HTTPS dla
całej witryny internetowej:

-   Bezpieczeństwo przede wszystkim. Wyobraź sobie, że jedynie strony
    logowania i finalizacji zamówienia są szyfrowane. Co się stanie po
    aktualizacji witryny i pojawieniu się formularza logowania na pasku
    bocznym? Teraz każda strona witryny musi stosować szyfrowane
    połączenie. Jeżeli cała witryna internetowa jest udostępniana
    poprzez HTTPS, nie ma obaw o przypadkowe dodanie w dowolnym miejscu
    nieszyfrowanego formularza.
-   Użytkownicy internetu coraz częściej sprawdzają, czy w przeglądarce
    WWW jest wyświetlana kłódka (zobacz rysunek 8.2). Zarówno
    początkujący, jak i doświadczeniu internauci czują się pewniej,
    widząc taką kłódkę. Co więcej, nowoczesne przeglądarki WWW
    wyświetlają groźnie brzmiące ostrzeżenie, gdy jakiś fragment witryny
    nie jest przekazywany poprzez połączenie HTTP.

[]

Rysunek 8.2. Kłódki oznaczające szyfrowane połączenie SSL wyświetlane w
różnych przeglądarkach WWW

-   Google i inne silniki wyszukiwarek internetowych zaczęły preferować
    w wynikach wyszukiwania witryny internetowe, które są całkowicie
    dostarczane poprzez połączenie HTTPS.
-   Stosowanie połączenia HTTPS w serwerze nie wiąże się już z większym
    obciążeniem procesora. Stos serwera WWW został uaktualniony i
    zapewnia lepszą obsługę ruchu sieciowego HTTPS. Szczerze mówiąc, nie
    można już używać czasu wczytywania strony jako wymówki dla
    wyłączenia szyfrowania HTTPS w witrynie internetowej.

Użycie jednego katalogu dla ruchu sieciowego HTTPS i HTTP

Poza użyciem certyfikatu wydanego przez urząd certyfikacji inną ważną
kwestią podczas konfiguracji szyfrowania SSL jest istnienie tzw.
dowiązania symbolicznego z katalogu HTTPS do katalogu HTTP. Dowiązanie
symboliczne to inaczej skrót, który znasz z systemu Windows. Nie jest
ono katalogiem, lecz jedynie wskazuje inny katalog.

Ostatecznie wynik użycia dowiązania symbolicznego do katalogu HTTPS jest
taki, że te same pliki kodu źródłowego .php będą wczytywane zarówno po
odwiedzeniu witryny https://nazwawitryny.pl, jak i witryny
http://nazwawitryny.pl. Serwer WWW zagwarantuje, że ruch sieciowy
poprzez połączenie HTTPS będzie szyfrowany, a zarówno WordPress, jak i
wtyczka typu e-commerce zapewnią wyświetlanie użytkownikowi bezpiecznej
strony, która zostanie przekazana za pomocą połączenia szyfrowanego
przez SSL.

Jeżeli katalog HTTP nosi nazwę http, a katalog HTTPS ma się nazywać
ssl_http, to następujące polecenie spowoduje utworzenie dowiązania
symbolicznego do tego katalogu: ln -s http ssl_http.

Stosowanie szyfrowania SSL na stronach logowania i administracyjnych

Dostarczanie poprzez SSL strony finalizacji zamówienia to minimum, które
trzeba spełnić, aby zapewnić prywatność danych przekazywanych do witryny
i z witryny. Istnieje możliwość skonfigurowania szyfrowania SSL na
stronie logowania, w administracyjnym panelu głównym, w całej witrynie
internetowej, a także tylko na wybranych stronach.

W przypadku szyfrowania SSL na stronie logowania w WordPressie konieczne
jest zdefiniowanie w pliku wp-config.php stałej FORCE_SSL_LOGIN i
przypisanie jej wartości true. Na końcu pliku umieść ten wiersz kodu:

    define('FORCE_SSL_LOGIN', true);

Jeżeli szyfrowania SSL chcesz użyć na stronie logowania i w
administracyjnym panelu głównym, zamiast poprzedniego polecenia użyj
następującego:

    define('FORCE_SSL_ADMIN', true);

  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Stała FORCE_SSL_ADMIN nadpisuje stałą FORCE_SSL_LOGIN. Wartość true należy przypisać tylko jednej z tych stałych. Jeżeli wartością stałej FORCE_SSL_LOGIN jest false, a wartością stałej FORCE_SSL_ADMIN jest true, na stronie logowania i tak będzie zastosowane szyfrowanie.
  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Debugowanie problemów związanych z HTTPS

Utworzymy teraz niewielką funkcję, która służy do filtrowania adresów
URL generowanych przez WordPressa, aby używały tego samego protokołu,
który zastosowano na bieżącej stronie. Wcześniej wspomnieliśmy, że adres
URL taki jak https://nazwa-witryny.pl/nazwa-strony (HTTP) pokazywany na
stronie takiej jak https://nazwa-witryny.pl/kasa (HTTPS) spowoduje
wygenerowanie przez przeglądarkę WWW ostrzeżenia dotyczącego
niebezpieczeństwa.

    function my_https_filter($s) {

        if(is_ssl())

            return str_replace("http:", "https:", $s);

        else

            return str_replace("https:", "http:", $s);

    }

    add_filter('bloginfo_url', 'my_https_filter');

    add_filter('wp_list_pages', 'my_https_filter');

    add_filter('option_home', 'my_https_filter');

    add_filter('option_siteurl', 'my_https_filter');

    add_filter('logout_url', 'my_https_filter');

    add_filter('login_url', 'my_https_filter');

    add_filter('home_url', 'my_https_filter');

Dostarczana przez WordPressa funkcja is_ssl() zwraca wartość true, jeśli
strona bieżąca została wczytana poprzez połączenie HTTPS. Ta funkcja
sprawdza, czy wartością zmiennej globalnej $_SERVER['HTTPS'] jest on lub
1 albo czy wartością zmiennej globalnej $_SERVER['SERVER_PORT'] jest
443. W przypadku części serwerów w tle są definiowane mechanizmy
równoważenia obciążenia lub odwrotne proxy, które będą wczytywały strony
poprzez połączenie HTTPS bez konieczności prawidłowego zdefiniowania w
PHP tych zmiennych. Można to naprawić przez umieszczenie w pliku
wp-config.php następującego fragmentu kodu:

    if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])

            && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {

        $_SERVER['HTTPS'] = 'on';

    }

Użyty tutaj filtr https wykorzystuje funkcję str_replace(), by zamienić
http: na https: i odwrotnie. Jest on przygotowany do wykorzystania w
wielu wbudowanych zaczepach WordPressa stosowanych w różnych miejscach
bazy kodu WordPressa, gdzie następuje generowanie adresów URL.

Podczas wyświetlania adresu URL w innych miejscach niestandardowego kodu
aplikacji należy się upewnić, że została użyta funkcja home_url(), aby
mieć gwarancję prawidłowego wygenerowania adresu URL i wykonania w nim
filtru my_https_filter.

Zapobieganie błędom dzięki „opcji nuklearnej”

Funkcja my_https_filter() gwarantuje, że łącza wyświetlane na stronie
będą korzystały z odpowiedniego protokołu. Czasami jednak zdarza się, że
adresy URL są na stałe zdefiniowane w postach w postaci http:// albo
używana wtyczka nie korzysta z wbudowanych funkcji WordPressa, które
powinny być stosowane podczas wyświetlania adresów URL lub w trakcie
wczytywania skryptów JavaScript i arkuszy stylów CSS. Na rysunku 8.3
pokazaliśmy dostępne w przeglądarce WWW Chrome narzędzia
programistyczne, które pozwalają wyszukiwać takie błędy.

[]

Rysunek 8.3. Błąd związany z SSL wyświetlony przez narzędzia
programistyczne w przeglądarce WWW Chrome

W takich przypadkach należy odszukać nieprawidłowe adresy URL i poprawić
łącza w poście lub kodzie, aby były stosowane względne adresy URL bądź
odpowiednie funkcje WordPressa gwarantujące wyświetlenie frontendu za
pomocą właściwego protokołu. Czasami jednak łatwiejsze będzie
skorzystanie z tzw. opcji nuklearnej.

    constant('MY_SITE_DOMAIN', 'nazwa-witryny.pl');

    function my_NuclearHTTPS() {

        ob_start("my_replaceURLsInBuffer");

    }

    add_action("init", "my_NuclearHTTPS");

    function my_replaceURLsInBuffer($buffer) {

        global $besecure;

        // Zastąpienie adresu URL tylko wtedy, gdy strona jest bezpieczna

        if(is_ssl())

        {

            /*

                Można zastąpić adresy we wszystkich łączach typu:

                * http://nazwa-witryny.pl

                * http://dowolna-poddomena.nazwa-witryny.pl

                * http://dowolna.liczba.poddomen.domeny.nazwa-witryny.pl

            */

            $buffer = preg_replace(

                '/http\:\/\/([a-zA-Z0-9\.\-]*'.str_replace('.','\.',MY_SITE_DOMAIN).')/i',

                'https://$1',

                $buffer

            );

        }

        return $buffer;

    }

Przede wszystkim konieczne jest zdefiniowanie stałej MY_SITE_DOMAIN i
użycie jej do przygotowania domeny drugiego poziomu dla domeny. Funkcja
site_url() w WordPressie może mieć postać http:/<www.nazwa-domeny.pl,
przy czym tutaj jesteśmy zainteresowani tylko fragmentem
nazwa-witryny.pl.

Następnie funkcja my_NuclearHTTPS() jest wywoływana w zaczepie init i
używa funkcji PHP ob_start() do włączenia buforowania danych
wyjściowych. Buforowanie danych wyjściowych oznacza, że wszystkie dane
wygenerowane przez PHP (np. za pomocą wywołań echo lub osadzonego kodu
HTML) zostaną przekazane do ciągu tekstowego bufora zamiast bezpośrednio
do przeglądarki WWW. Następnie gdy PHP zakończy generowanie danych
wyjściowych (lub po pierwszym wywołaniu funkcji ob_end_flush()), ciąg
tekstowy bufora zostanie przekazany funkcji wywołania zwrotnego, którą w
omawianym przykładzie jest my_replaceURLsInBuffer().

Funkcja my_replaceURLsInBuffer() filtruje ciąg tekstowy bufora i dla
każdego łącza zastępuje http: przez https:. Wyrażenie regularne w
wywołaniu preg_replace() gwarantuje, że filtrowane będą również
wszystkie łącza prowadzące do dowolnej poddomeny i używające tej samej
nazwy domeny (dlatego konieczne było zdefiniowanie stałej
MY_SITE_DOMAIN).

Być może się zastanawiasz, skąd nazwa rozwiązania — opcja nuklearna.
Zamiast wyszukiwać w kodzie źródłowym aplikacji nieprawidłowych adresów
URL i je poprawiać modyfikowane są wszystkie adresy URL przed
przekazaniem danych wyjściowych przeglądarce WWW. Takie rozwiązanie
oznacza minimalne zmniejszenie wydajności działania, w zależności od
wielkości danych wyjściowych HTML. Metoda ta jednak może być użyteczna w
razie konieczności, zwłaszcza jeśli masz wiele wtyczek zewnętrznych,
których nie możesz lub nie chcesz modyfikować, aby generowały
odpowiednie adresy URL.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Wtyczka Really Simple SSL (https://wordpress.org/plugins/really-simple-ssl/) zawiera wiele poprawek dotyczących HTTPS, o którym wspomnieliśmy w tekście. Ponadto oferuje inne narzędzia umożliwiające prawidłowe działanie protokołu HTTPS w witrynie internetowej utworzonej za pomocą frameworka WordPress.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Twórz kopię zapasową całości!

Bardzo ważne jest regularne tworzenie kopii zapasowej całej treści
witryny internetowej (bazy danych) i katalogu wp-content. Dzięki temu
znacznie łatwiej będzie można przywrócić witrynę w przypadku skutecznego
ataku na nią. Zalecamy tworzenie kopii zapasowej przynajmniej raz
w tygodniu. Zależnie od ilości nowej treści publikowanej w witrynie
internetowej możesz zwiększyć lub zmniejszyć częstotliwość tworzenia
kopii zapasowej. Oczywiście najlepszym rozwiązaniem zawsze będzie
codzienne tworzenie kopii zapasowej.

+----+----------------------------------------------------------------+
| [] | Czy wiesz, gdzie znajduje się kopia zapasowa?                  |
|    |                                                                |
|    | Jesteś pewien, że będziesz mógł skorzystać z kopii zapasowej,  |
|    | gdy zajdzie potrzeba przywrócenia witryny internetowej? Co     |
|    | kilka miesięcy należy przeprowadzić przywracanie witryny na    |
|    | podstawie kopii zapasowej. Tylko w ten sposób możesz mieć      |
|    | pewność, że kopia zapasowa działa, zawiera wszystkie niezbędne |
|    | dane i umożliwia szybkie przywrócenie witryny. Można znaleźć   |
|    | mnóstwo przerażających opowieści osób, które były przekonane,  |
|    | że posiadają kopię zapasową, a okazywało się, iż jest ona      |
|    | uszkodzona, niekompletna lub w inny sposób nie pozwala         |
|    | przywrócić witryny.                                            |
+----+----------------------------------------------------------------+

Skanuj, skanuj i skanuj!

Skanowanie, lub inaczej monitorowanie, aplikacji pozwala dowiedzieć się,
że został na nią przeprowadzony atak. Jeżeli aplikacja kiedykolwiek
zostanie skutecznie zaatakowana przez hakera, najważniejszą kwestią jest
jak najszybciej dowiedzieć się o tym, aby można być szybko zareagować.

Bądź proaktywny podczas ochrony aplikacji internetowej przed
oprogramowaniem typu malware. Istnieje wiele usług przeprowadzających
skanowanie aplikacji, więc możesz skorzystać z takiego rozwiązania,
które nie wymaga od Ciebie żadnego działania. Polecamy usługę Sucuri
(https://sucuri.net/). Nie tylko wyszukuje ona malware i informuje o
zainfekowaniu aplikacji, ale również potrafi ją oczyścić. Tony Perez,
dyrektor operacyjny Sucuri, to były żołnierz piechoty morskiej USA i
mistrz sztuk walki, więc warto mieć Sucuri po swojej stronie. Sucuri
oferuje również doskonałą wtyczkę zapewnienia bezpieczeństwa
(https://growmeo.com/wordpress-security-checklist/) dla WordPressa.

Użyteczne wtyczki zapewnienia bezpieczeństwa

W kolejnych sekcjach wymienimy więcej użytecznych i oferujących potężne
możliwości wtyczek WordPressa, które pomogą w zapewnieniu większego
bezpieczeństwa aplikacji, a także w szybkim podniesieniu witryny
internetowej, gdy padnie ona ofiarą ataku.

Wtyczki związane z blokowaniem spamu

Spam to problem każdej witryny internetowej. Pomocne mogą się okazać
wtyczki zaliczane do tej grupy.

Akismet

Ta wtyczka służy do blokowania spamu w komentarzach publikowanych w
witrynie internetowej. Została opracowana przez Automattic, czyli
twórców WordPressa, i dlatego jest dostarczana standardowo wraz z każdą
jego nową instalacją. Wprawdzie wtyczka zostanie zainstalowana w
witrynie internetowej, ale wymaga aktywacji przez rejestrację klucza API
na stronie https://akismet.com/. Klucz API jest bezpłatny w przypadku
osobistych witryn internetowych, natomiast w przypadku komercyjnych
konieczne jest uiszczenie niewielkiej opłaty. Sposób działania wtyczki
Akismet jest następujący: podczas umieszczania komentarza na stronie
jest on poddawany kilku testom, dzięki którym zyskujemy pewność, że mamy
do czynienia z prawdziwym komentarzem. Gdy komentarz zostanie określony
jako spam, nastąpi jego automatyczne przeniesienie do katalogu spam w
panelu głównym. Dzięki temu można zaoszczędzić mnóstwo czasu, który
trzeba byłoby poświęcić na ręczne przeglądanie komentarzy i ustalenie,
które z nich są prawdziwe.

Bad Behavior

Wtyczka Bad Behavior (https://wordpress.org/plugins/bad-behavior/)
działa poprzez blokowanie łączy spamu prowadzących do witryny
internetowej. Najlepsze efekty daje w połączeniu z inną usługą walki ze
spamem. Ta wtyczka nie tylko sprawdza treść spamu, ale też próbuje
ustalić metodę, za pomocą której spam jest dostarczany przez spamera, i
używane przez niego oprogramowanie, a następnie również je blokuje.

Wtyczki związane z tworzeniem kopii zapasowej

Dobrze jest mieć kopię zapasową na wypadek, gdy witryna internetowa
stanie się celem skutecznego ataku. W tej sekcji przedstawiamy kilka
użytecznych wtyczek związanych z tworzeniem kopii zapasowej.

BackupBuddy

Jak wspomnieliśmy w rozdziale 3., BackupBuddy
(https://ithemes.com/backupbuddy/) to wtyczka premium, która pozwala
tworzyć kopię zapasową całej treści witryny internetowej WordPressa na
wypadek, gdyby zaszła konieczność przywrócenia witryny lub potrzeba jej
przeniesienia. Istnieje możliwość zdefiniowania harmonogramu operacji
tworzenia kopii zapasowej, a pliki mogą być przekazywane poprzez pocztę
elektroniczną albo umieszczane w usługach takich jak Dropbox lub w
serwerze FTP. Opcje tej wtyczki umożliwiają łatwe przywracanie motywów,
widżetów i wtyczek. Dzięki BackupBuddy panel główny WordPressa można
wykorzystać do przeniesienia witryny internetowej do nowego serwera lub
domeny, co jest użyteczną funkcją, jeśli pracujesz w serwerze
programistycznym i chcesz ją przenieść do serwera produkcyjnego.

VaultPress

VaultPress (https://vaultpress.com/) to kolejna wtyczka utworzona przez
zespół Automattic i umożliwiająca tworzenie kopii zapasowej całej
witryny internetowej w czasie rzeczywistym i umieszczenie jej w usłudze
chmury. Po zainstalowaniu wtyczka automatycznie wykrywa wszelkie zmiany
wprowadzone zarówno w treści witryny, jak i w ustawieniach, a następnie
uwzględnia te zmiany w kopii zapasowej. Oferuje również możliwość
przywrócenia bazy danych jednym kliknięciem w sytuacji, gdy baza została
uszkodzona np. na skutek ataku. Jest to wtyczka typu premium, co oznacza
płatność za usługę. Dostępne są różne poziomy usług. Wersja premium
umożliwia też codzienne skanowanie bezpieczeństwa witryny mające na celu
wychwycenie wszelkich problemów i dostarczenie dla nich rozwiązania.

Wtyczki związane z zaporą sieciową i skanowaniem

Wtyczki w tej kategorii są użyteczne podczas wykrywania i łagodzenia
skutków wszelkich zautomatyzowanych ataków, które są plagą dotykającą
praktycznie każdą witrynę internetową.

WordFence

WordFence (https://wordpress.org/plugins/wordfence/) działa jako rodzaj
zapory sieciowej dla witryny internetowej, ponieważ skanuje cały ruch
przychodzący, a następnie blokuje wszelkie rodzaje podejrzanych żądań.
Istnieje również możliwość przeprowadzenia skanowania na żądanie i
podjęcia próby wykrycia potencjalnych luk w zabezpieczeniach witryny
internetowej. Po uaktualnieniu wtyczki do płatnej wersji otrzymujesz
narzędzia dodatkowe i dostęp do bardziej aktualnej bazy danych
oprogramowania malware i informacji o lukach w zabezpieczeniach.

All In One WP Security & Firewall

Wtyczka All In One WP Security & Firewall
(https://wordpress.org/plugins/all-in-one-wp-security-and-firewall/)
zapewnia zaporę sieciową i skaner podobne do oferowanych przez wtyczkę
WordFence. Zawiera również narzędzia pozwalające zwiększyć
bezpieczeństwo użytkowników i operacji logowania. Bardzo ważną kwestią
bezpieczeństwa, jaką rozwiązuje ta wtyczka, jest pomoc w zmianie
prefiksu tabeli bazy danych, co może być dość trudną operacją, jeśli nie
znasz standardowej struktury bazy danych.

Exploit Scanner

Obsługiwana przez firmę Automattic wtyczka Exploit Scanner
(https://wordpress.org/plugins/ exploit-scanner/) przeprowadza
skanowanie wszystkich plików witryny internetowej i informuje o
wszystkich elementach, które wyglądają podejrzanie i mogą stanowić
zagrożenie.

Wtyczki związane z logowaniem i hasłami

Celem tej grupy wtyczek jest ograniczenie dostępu do strony logowania w
aplikacji WordPressa oraz stron panelu głównego.

Limit Login Attempts

Wtyczka Limit Login Attempts
(https://wordpress.org/plugins/limit-login-attempts/) to doskonałe
rozwiązanie pomocne w obronie przed atakami typu brute force, np. gdy
ktoś uruchamia zautomatyzowany skrypt, który próbuje zalogować się do
witryny internetowej WordPressa, używając do tego losowo wybieranych
kombinacji słów. Domyślnie WordPress zezwala na nieograniczoną liczbę
prób zalogowania, a omawiana wtyczka tę liczbę ogranicza. Jeżeli ktoś
podejmie x prób zalogowania i każda z nich zakończy się niepowodzeniem,
taki użytkownik będzie zablokowany przez określony czas.

AskApache Password Protect

Wtyczka AskApache Password Protect
(https://wordpress.org/plugins/askapache-password-protect/) różni się od
innych wtyczek WordPressa związanych z zapewnieniem bezpieczeństwa,
ponieważ działa na poziomie sieci i tam stara się chronić przed atakami.
Większość pozostałych wtyczek działa na poziomie witryny internetowej.
Trzeba wybrać nazwę użytkownika i hasło, które będą chroniły stronę
logowania i cały katalog wp-admin. Omawiana wtyczka wymaga użycia
serwera WWW Apache i obsługi plików .htaccess.

Tworzenie bezpiecznego kodu

Chcesz mieć pewność, że tworzony przez Ciebie kod jest bezpieczny i nie
będzie furtką umożliwiającą atakującemu dostanie się do witryny
internetowej. Jeżeli zapoznasz się z omówionymi tutaj metodami i
będziesz je stosować, zyskasz dość dobrą ochronę przed różnymi atakami.

Sprawdzenie uprawnień użytkownika

Każdy z użytkowników aplikacji ma unikatowe standardowe i niestandardowe
role i uprawnienia. Jeżeli tworzysz kod zapewniający niestandardową
funkcjonalność administratorom, upewnij się, że tylko administratorzy
będą mieli do niej dostęp. WordPress ma kilka wbudowanych funkcji
informujących o rolach i uprawnieniach użytkownika. Wszystkie te funkcje
zostały zdefiniowane w pliku wp-includes/capabilities.php i zwracają
wartość boolowską wskazującą, czy użytkownik ma daną rolę lub
uprawnienie. Masz możliwość sprawdzania zarówno domyślnych, jak i
niestandardowych ról i uprawnień.

user_can( $user, $capability )

Funkcja określająca, czy dany użytkownik ma sprawdzaną rolę lub
uprawnienie.

$user

Wymagana liczba całkowita identyfikatora użytkownika lub obiektu
użytkownika.

$capability

Wymagany ciąg tekstowy nazwy roli lub uprawnienia.

current_user_can( $capability )

Funkcja określająca, czy bieżący użytkownik ma sprawdzaną rolę lub
uprawnienie.

$capability

Wymagany ciąg tekstowy nazwy roli lub uprawnienia.

current_user_can_for_blog( $blog_id, $capability )

Funkcja określająca, czy bieżący użytkownik ma sprawdzaną rolę lub
uprawnienie w danej witrynie w sieci składającej się z wielu witryn
internetowych.

$user

Wymagana liczba całkowita identyfikatora bloga.

$capability

Wymagany ciąg tekstowy nazwy roli lub uprawnienia.

W przedstawionym tutaj fragmencie kodu nie chcemy pozwolić zwykłym
użytkownikom na uzyskanie dostępu do backendu aplikacji. Wymienionym
użytkownikom chcemy zapewnić jedynie możliwość pracy z niestandardowym
interfejsem użytkownika utworzonym w motywie frontendu. Każdy, kto nie
jest administratorem i przejdzie na stronę /wp-admin, zostanie
przekierowany do frontendu.

    function schoolpress_admin_check() {

        global $user_ID;

        if ( ! user_can( $user_ID, 'administrator' ) ) {

            wp_redirect( site_url() );

        }

    }

    add_action( 'admin_init', 'schoolpress_admin_check' );

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Inną dość często stosowaną praktyką w wielu wtyczkach WordPressa jest przeprowadzenie operacji sprawdzenia pod kątem uprawnienia manage_options, a nie roli administratora. W domyślnej instalacji WordPressa to uprawnienie ma jedynie administrator, więc masz pewność, że taka operacja sprawdzenia będzie działała również w witrynach internetowych, w których zostały zdefiniowanie niestandardowe role.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Dokładne omówienie standardowych ról i uprawnień dostępnych w domyślnej
instalacji WordPressa znajdziesz w rozdziale 6. oraz w serwisie
WordPress Codex na stronie https://wordpress.
org/support/article/roles-and-capabilities/.

Niestandardowe zapytania SQL

Czasami wbudowane funkcje WordPressa przeznaczone do pracy z bazą danych
mogą okazać się niewystarczające dla Twoich potrzeb. W zależności od
tworzonej aplikacji może zaistnieć konieczność przygotowania
niestandardowych zapytań SQL. Jeżeli definiujesz własne zapytania SQL,
pamiętaj o ich przygotowaniu tak, aby uniknąć potencjalnych ataków
polegających na wstrzyknięciu kodu SQL. Przede wszystkim zawsze
korzystaj z obiektu $wpdb i nie zapominaj o prawidłowym zastosowaniu
znaków sterujących w zapytaniach SQL.

Jak już wspomnieliśmy w rozdziale 3., obiekt $wpdb można wykorzystać w
celu uzyskania dostępu do każdej standardowej lub niestandardowej tabeli
w bazie danych WordPressa. Obiekt ten zapewnia łatwe w użyciu metody
umożliwiające ów dostęp. Bardzo ważną kwestią do zapamiętania jest to,
że podczas tworzenia zapytań niestandardowych wykorzystujących wartości
dynamiczne należy używać funkcji esc_sql() lub metody prepare(), aby
oczyścić te wartości i zastosować w nich znaki sterujące. Dzięki
oczyszczeniu i zastosowaniu znaków sterujących unikamy potencjalnego
niebezpieczeństwa polegającego na podaniu niepoprawnych znaków lub kodu
SQL o złośliwym działaniu, który mógłby przechwycić zapytanie (jest to
właśnie przykład ataku polegającego na wstrzyknięciu kodu SQL).

Dokładne omówienie funkcji esc_sql() i metody $wpdb->prepare()
zamieściliśmy w rozdziale 3.

Weryfikacja danych, ich oczyszczanie i stosowanie znaków sterujących

Nie ufaj użytkownikom aplikacji! Powtórz za nami: nie ufaj użytkownikom
aplikacji! Nie bądź autorem witryny, aplikacji lub bloga, które
rozpowszechniają malware.

Każdy element danych przekazywany do bazy danych powinien być
zweryfikowany, oczyszczony i mieć znaki sterujące. Trzeba się koniecznie
upewnić, że dane przekazywane przez użytkowników do bazy danych są w
prawidłowym formacie. Z perspektywy bazy danych treść tych informacji
nie ma znaczenia, o ile przekazywane do niej dane mają ten sam typ.

Załóżmy, że tworzymy niestandardowy formularz, którego celem jest
pobieranie od użytkowników daty urodzenia. Planujesz umieścić ją w
kolumnie meta_value tabeli wp_usermeta. Typem danych kolumny meta_value
jest longtext, więc przekazywana wartość może być bardzo długa[1], przy
czym dla bazy danych nie ma absolutnie żadnego znaczenia, jaka wartość
będzie w tym miejscu przechowywana. Do Ciebie jako programisty należy
upewnienie się, że przechowywane dane to data urodzenia i nic więcej.

Mógłbyś w tym miejscu zapytać, jaka jest różnica między weryfikacją
danych, ich oczyszczaniem i stosowaniem znaków sterujących.

Weryfikacja danych

Ten proces ma na celu zagwarantowanie, że dane otrzymane od użytkownika
końcowego znajdują się w oczekiwanym formacie. Dane powinny być
weryfikowane przed ich zapisaniem w bazie.

Oczyszczanie danych

Ten proces ma na celu usunięcie niechcianych elementów z danych
otrzymanych od użytkownika końcowego przed ich zapisaniem w bazie lub
przed ich użyciem w aplikacji.

Stosowanie znaków sterujących

Ten proces ma na celu zastąpienie potencjalnie niebezpiecznych elementów
danych encjami przed ich wyświetleniem użytkownikowi końcowemu, przed
ich zapisaniem w bazie albo przed ich przekazaniem do API.

Teraz już wiesz!

Konieczne jest weryfikowanie i oczyszczanie wszelkich danych
przekazywanych aplikacji poprzez formularze internetowe, parametry
adresów URL lub wywołania API. Znaki sterujące należy stosować w danych
przed ich zapisaniem w bazie lub przed ich wyświetleniem na ekranie.
Podczas pobierania danych z bazy należy je oczyścić na wypadek, gdyby z
jakiegokolwiek powodu doszło do umieszczenia w bazie nie oczyszczonych
informacji.

Wprawdzie PHP ma funkcje przeznaczone do weryfikacji i oczyszczania
danych, ale WordPress oferuje własne funkcje pomocnicze, które do tego
służą. Skoro to jest książka o WordPressie, omówimy dostępne w tym
frameworku funkcje związane z weryfikacją i oczyszczaniem danych.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------
  []   Większość funkcji związanych z oczyszczaniem danych i stosowaniem znaków sterujących została zdefiniowana w pliku wp-includes/formatting.php.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------

esc_url( $url, $protocols = null, $_context = 'display' )

Działanie tej funkcji polega na sprawdzeniu i oczyszczeniu adresu URL
przez ustalenie, czy używany jest prawidłowy protokół, usunięcie
nieprawidłowych znaków i zastosowanie znaków sterujących dla znaków
specjalnych. Skorzystaj z tej funkcji, jeśli chcesz wyświetlić adres URL
użytkownikowi końcowemu.

$url

Wymagany ciąg tekstowy adresu URL przeznaczonego do oczyszczenia.

$protocols

Opcjonalna tablica protokołów, które zostały umieszczone na białej
liście. Jeżeli nie podasz tego argumentu, domyślnie zostanie użyta
następująca tablica: array( http, https, ftp, ftps, mailto, news, irc,
gopher, nntp, feed, telnet, mms, rtsp, svn ).

$context

Opcjonalny ciąg tekstowy określający, jak zostanie użyty adres URL.
Domyślnie ten parametr ma wartość display, która powoduje przekazanie
adresu URL za pomocą funkcji wp_kses_normalize_entities() i zastąpienie
wszystkich wystąpień &amp za pomocą &#038;, a wystąpień ' za pomocą
&#039;.

esc_url_raw( $url, $protocols = null )

Wywołuje funkcję esc_url(), przy czym przekazuje db jako wartość
parametru $_context. Nie używaj tej funkcji do wyświetlania adresów URL
użytkownikowi końcowemu, lecz jedynie w zapytaniach do bazy danych.

esc_html( $text )

Działanie tej funkcji polega na zastosowaniu znaków cytowania bloków
HTML w dowolnej treści. Funkcja ta jest eleganckim, niewielkim
opakowaniem dla _wp_specialchars(), która w zasadzie przeprowadza
konwersję pewnej liczby znaków specjalnych na odpowiadające im encje
HTML.

$text

Wymagany ciąg tekstowy zawierający treść, w której znaki specjalne mają
być zastąpione encjami.

esc_js( $text )

Działanie tej funkcji polega na zastosowaniu znaków cytowania w ciągach
tekstowych osadzonych skryptów JavaScript. Aby rozwiązanie zadziałało,
wynikowy ciąg tekstowy musi być ujęty w apostrofy.

$text

Wymagany ciąg tekstowy zawierający treść, w której mają być użyte znaki
sterujące, a znaki specjalne HTML (takie jak " < > &) i znaki nowego
wiersza zastąpione encjami.

esc_attr( $text )

Działanie tej funkcji polega na zastosowaniu znaków sterujących i
zakodowaniu znaków takich jak <, >, &, " i '. Bardzo ważne jest użycie
tej funkcji podczas dołączania wartości w elementach danych wejściowych
formularza takich jak id, name, alt, title i value.

$text

Wymagany ciąg tekstowy zawierający treść atrybutów HTML, która ma zostać
przetworzona.

esc_textarea( $text )

Stosuje znaki sterujące dla wartości elementu <textarea>. Zakodowany
tekst jest przeznaczony do umieszczenia w elemencie <textarea>.

$text

Wymagany ciąg tekstowy zawierający treść, w której znaki specjalne mają
być zastąpione encjami.

sanitize_option( $option, $value )

Musi być stosowana w celu oczyszczenia wartości wszelkich
predefiniowanych opcji WordPressa. W zależności od użytej opcji wartość
zostanie oczyszczona za pomocą różnych funkcji.

$option

Wymagany ciąg tekstowy zawierający nazwę opcji.

$value

Wymagany ciąg tekstowy zawierający nieoczyszczoną wartość opcji, która
ma zostać oczyszczona.

sanitize_text_field( $str )

Oczyszcza dowolny ciąg tekstowy danych wejściowych dostarczonych przez
użytkownika lub pochodzących z bazy danych. Sprawdza pod kątem
nieprawidłowych wartości UTF-8, konwertuje pojedynczy znak < na encję,
usuwa wszystkie znaczniki, znaki nowego wiersza, tabulatory, białe znaki
itd.

$str

Wymagany ciąg tekstowy zawierający wartość przeznaczoną do oczyszczenia.

sanitize_user( $username, $strict = false )

Oczyszcza nazwę użytkownika z wszelkich niedozwolonych znaków.

$username

Wymagany ciąg tekstowy zawierający nazwę użytkownika przeznaczoną do
oczyszczenia.

$strict

Opcjonalna wartość boolowska. Jeśli będzie nią true, nazwa użytkownika
zostanie ograniczona do podanej liczby znaków.

sanitize_title( $title, $fallback_title = '' )

Oczyszcza tytuł z wszelkich znaczników HTML lub PHP albo zwraca awaryjny
tytuł dla podanego ciągu tekstowego.

$title

Wymagany ciąg tekstowy zawierający tytuł przeznaczony do oczyszczenia.

$fallback_title

Opcjonalny ciąg tekstowy przeznaczony do użycia, gdy tytuł będzie pusty.

sanitize_email( $email )

O oczyszcza adresy e-mail przez usunięcie z nich wszystkich znaków,
które są niedozwolone w adresach e-mail.

$email

Adres e-mail przeznaczony do oczyszczenia.

sanitize_file_name( $filename )

Działanie tej funkcji polega na oczyszczeniu nazwy pliku i zastąpieniu
białych znaków łącznikami. Usuwane są znaki specjalne uznawane za
niedozwolone w nazwach plików w niektórych systemach operacyjnych oraz
znaki specjalne wymagające stosowania znaków sterujących do
przeprowadzania operacji w powłoce. Spacje i kolejne łączniki zostają
zastąpione pojedynczym łącznikiem. Na początku i końcu nazwy pliku
usuwane są kropki, łączniki i znaki podkreślenia.

$filemane

Wymagany ciąg tekstowy zawierający nazwę pliku przeznaczoną do
oczyszczenia.

wp_kses( $string, $allowed_html, $allowed_protocols = array () )

Ta funkcja gwarantuje, że tylko dozwolone nazwy elementów HTML, nazwy
atrybutów i wartości atrybutów oraz encje HTML będą znajdowały się w
dostarczonych ciągach tekstowych. Przed wywołaniem tej funkcji,
konieczne jest usunięcie wszelkich ukośników z magicznych znaków
cytowania PHP.

$string

Wymagany ciąg tekstowy, który ma być filtrowany za pomocą funkcji
kses().

$allowed_html

Wymagana tablica zawierająca dozwolone elementy HTML.

$allowed_protocols

Opcjonalna tablica protokołów dozwolonych w adresach URL ciągów
tekstowych przekazywanych do filtrowania. Domyślnie dozwolonymi
protokołami są: http, https, ftp, mailto, news, irc, gopher, nntp, feed,
telnet, mms, rtsp i svn. Zapewnia obsługę wszystkich najczęściej
stosowanych protokołów łączy, z wyjątkiem javascript, którego użycie nie
powinno być dozwolone, gdy pochodzi od niezaufanych użytkowników.

wp_kses_post( $data )

Działanie tej funkcji polega na oczyszczeniu przekazanych jej danych,
przy czym dozwolone są znaczniki HTML i protokoły, które można stosować
w sekcji treści posta na stronie edycji. Jeżeli chcesz zastosować nieco
ściślejsze reguły niż dla autorów, redaktorów i administratorów witryny
internetowej, skorzystaj z funkcji wp_kses() i przekaż jej odpowiednie
znaczniki i protokoły. Jeśli element jest przeznaczony dla
administratorów i chcesz go oczyścić w dokładnie taki sam sposób, jak
oczyszczana jest treść posta, wówczas funkcja wp_kses_post() jest dobrym
skrótem.

$data

Wymagany ciąg tekstowy, który ma być filtrowany przez funkcję kses.

W kolejnym fragmencie kodu pokazaliśmy, jak zweryfikować i oczyścić
adres e-mail.

    // Przyjmujemy założenie, że dodanym przez użytkownika adresem e-mail jest "jason @ stranger$tudios.com"

    $user_email = 'jason @ stranger$tudios.com';

    // Można sprawdzić, czy mamy do czynienia z poprawnym adresem e-mail

    $valid_email = is_email( $user_email );

    // Wiemy, że adres jest nieprawidłowy, ponieważ funkcja is_email() zwróciła pusty ciąg tekstowy

    if ( ! $valid_email )

        echo 'Nieprawidłowy adres e-mail<br />';

    // Próbujemy ponownie, zaczynamy od oczyszczenia adresu e-mail

    $user_email = 'jason @ stranger$tudios.com';

    // Za pomocą funkcji sanitize_email() próbujemy poprawić niepoprawny adres e-mail

    $user_email = sanitize_email( $user_email );

    $valid_email = is_email( $user_email );

    if ( ! $valid_email )

        echo 'Nieprawidłowy adres e-mail<br />';

    else

        echo 'Prawidłowy adres e-mail: ' . $user_email;

Zwróć uwagę, że w omawianym przykładzie funkcja sanitize_email() usunęła
spacje i znak dolara z niepoprawnego adresu e-mail. Wprawdzie z
technicznego punktu widzenia adres jest poprawny, ale to nie jest
rzeczywisty adres Jasona, ponieważ funkcja nie rozpoznaje zastąpienia
litery s znakiem $. Zauważ również, że zwrócona wartość nie zawsze
będzie poprawnym adresem e-mail. Jeżeli nie ma znaku @, brakuje tekstu
przed znakiem @ lub po znaku @ nie znajduje się nazwa domeny, wówczas
wartością zwrotną jest nieprawidłowy adres e-mail.

Więcej informacji na temat weryfikowania i oczyszczania danych oraz
stosowania znaków sterujących w danych znajdziesz w serwisie WordPress
Codex na stronie https://codex.wordpress.org/
Validating_Sanitizing_and_Escaping_User_Datahttps://codex.wordpress.org/Validating_Sanitizing_and_
Escaping_User_Data.

Jednokrotnie używana liczba

W języku angielskim słowo nonce oznacza w kryptografii „jednokrotnie
używaną liczbę”. Stosowanie takich liczb ma znaczenie krytyczne w
ochronie aplikacji przed atakami typu CSRF (ang. cross-site request
forgery). Standardowo działający po stronie serwera skrypt przeznaczony
do przetwarzania formularzy odpowiada za przetwarzanie formularzy
wypełnianych przez użytkowników witryny internetowej. Użytkownicy
odwiedzają witrynę, logują się do niej oraz wysyłają formularz w celu
przeprowadzenia jakiejś operacji w witrynie. Jeżeli jednak działający po
stronie serwera skrypt jedynie szuka wartości $_POST w celu ustalenia
następnej operacji, te wartości mogą być przekazane z dowolnego
formularza internetowego, nawet zdefiniowanego w innych witrynach.

Pierwszą linią obrony jest sprawdzenie, czy użytkownik faktycznie
zalogował się w witrynie i ma uprawnienia pozwalające wykonać daną
akcję. Jest to jednak niewystarczające do zatrzymania ataków typu CSRF,
ponieważ można być zalogowanym w witrynie WordPressa (np. karta
działająca w tle), a jednocześnie kod o złośliwym działaniu w innej
witrynie internetowej lub na innej karcie spowoduje wykonanie żądania z
odpowiednią zmienną $_POST i wyśle niechcianą wiadomość do Twoich
przyjaciół, zainicjuje operację usunięcia konta lub jeszcze inną, której
na pewno nie chciałeś przeprowadzić.

Trzeba zastosować rozwiązanie gwarantujące, że żądanie pochodzi z
witryny internetowej WordPressa, a nie z innej. Do tego celu przydają
się właśnie jednokrotnie używane liczby. Oto ogólny mechanizm ich
zastosowania:

1.  W trakcie każdej operacji wczytywania strony następuje wygenerowanie
    jednokrotnie używanej liczby.
2.  Ta liczba zostaje umieszczona jako ciąg tekstowy w ukrytym elemencie
    formularza.
3.  Podczas przetwarzania wysłanego formularza następuje wygenerowanie w
    ten sam sposób jednokrotnie używanej liczby, a następnie porównanie
    jej z otrzymaną w formularzu.

Ponieważ jednokrotnie używana liczba jest generowana za pomocą
połączenia ukrytego klucza ciągu zaburzającego w pliku wp-config.php i
bieżącej godziny w serwerze, atakującemu trudno jest przygotować w
spreparowanym formularzu odpowiedni ciąg tekstowy jednokrotnie używanej
liczby.

Jednokrotnie używane liczby przydają się również w łączach niezwiązanych
z formularzami oraz w wywołaniach w technologii AJAX. Proces
zastosowania takiej liczby jest podobny do wcześniej przedstawionego:

1.  W trakcie każdej operacji wczytywania strony następuje wygenerowanie
    jednokrotnie używanej liczby.
2.  Ta liczba zostaje umieszczona jako ciąg tekstowy w parametrze adresu
    URL.
3.  Podczas przetwarzania żądania następuje wygenerowanie w ten sam
    sposób jednokrotnie używanej liczby, a następnie porównanie jej z
    otrzymaną w adresie URL.

Niezależnie od tego, czy chronisz formularze internetowe, łącza czy
żądania w technologii AJAX, WordPress oferuje kilka funkcji
pomocniczych, które niezwykle ułatwiają implementację tego procesu.

wp_create_nonce( $action = -1 )

Tworzy losowo wybrany token, który znajduje się w pliku
wp-includes/pluggable.php i może zostać użyty tylko raz.

$action

Opcjonalny ciąg tekstowy lub liczba całkowita opisująca akcję
podejmowaną po utworzeniu jednokrotnie używanej liczby. Zawsze należy
definiować akcję, aby zapewnić większe bezpieczeństwo.

    function schoolpress_footer_create_nonce(){

        $nonce = wp_create_nonce('random_nonce_action');

        $url = add_query_arg( array( 'sp_nonce' => $nonce ) );

        echo '<p><a href="' . $url . '">Weryfikacja jednokrotnie używanej wartości</a></p>';

    }

    add_action( 'wp_footer', 'schoolpress_footer_create_nonce' );

wp_verify_nonce( $nonce, $action = -1 )

Wykorzystywana do sprawdzenia, czy jednokrotnie używana liczba była
zastosowana w określonym przedziale czasu. Jeżeli funkcji została
przekazana prawidłowa liczba i wszystkie pozostałe operacje sprawdzenia
nie zgłosiły błędów, wówczas funkcja zwraca wartość określaną jako
true[2]. W przeciwnym przypadku wartością zwrotną będzie false. Funkcja
ta została zdefiniowana w pliku wp-includes/pluggable.php.

$nonce

Wymagany ciąg tekstowy wartości w postaci jednokrotnie używanej liczby
przeznaczonej do sprawdzenia.

$action

Opcjonalny ciąg tekstowy lub liczba całkowita, która powinna w opisowy
sposób przedstawiać operację i pasować do akcji zdefiniowanej podczas
tworzenia jednokrotnie używanej liczby.

    function schoolpress_init_verify_nonce(){

        if ( isset( $_GET['sp_nonce'] )

                && wp_verify_nonce( $_GET['sp_nonce'], 'random_nonce_action' ) ) {

            echo 'Sprawdzana wartość jest prawidłowa!';

        } else {

            echo 'Sprawdzana wartość jest nieprawidłowa!';

        }

    }

    add_action( 'init', 'schoolpress_init_verify_nonce' );

check_admin_referer( $action = -1, $query_arg = '_wpnonce’ )

Wywołuje wp_verify_once() i sprawdza jednokrotnie używaną liczbę.
Ponadto sprawdza, czy tzw. referrer, czyli poprzednia strona, znajduje
się w tej samej witrynie internetowej. Funkcja ta została zdefiniowana w
wp-includes/pluggable.php.

$action

Opcjonalny ciąg tekstowy, ale należy podać akcję związaną z weryfikacją
jednokrotnie używanej liczby.

$query_arg

Opcjonalny ciąg tekstowy argumentu zapytania, którego wartością jest
jednokrotnie używana liczba.

    // Sprawdzenie tej samej jednokrotnie używanej liczby "sp_nonce" co w poprzednim przykładzie

    function schoolpress_init_check_admin_referer(){

        if ( isset( $_GET['sp_nonce'] ) &&

                check_admin_referer( 'random_nonce_action', 'sp_nonce' ) ) {

            echo '<p>Sprawdzana wartość jest prawidłowa!</p>';

        } else {

            echo '<p>Sprawdzana wartość jest nieprawidłowa!</p>';

        }

    }

    add_action( 'init', 'schoolpress_init_check_admin_referer' );

wp_nonce_url( $actionurl, $action = -1 )

Wykorzystuje wp_create_nonce() w celu dodania jednokrotnie używanej
liczby do dowolnego adresu URL. Jeżeli definiujesz dowolną akcję na
podstawie ciągu tekstowego zapytania, zawsze za pomocą tej funkcji
powiąż jednokrotnie używaną liczbę z adresem URL.

$actionurl

Wymagany ciąg tekstowy adresu URL, do którego ma zostać dodana akcja
jednokrotnie używanej liczby.

$action

Opcjonalny ciąg tekstowy zawierający nazwę akcji. Tę wartość zawsze
należy definiować.

Funkcja ta została zdefiniowana w wp-includes/functions.php.

    // Prosty adres URL z przykładowym ciągiem tekstowym zapytania

    function schoolpress_footer_nonce_url(){

        $url = wp_nonce_url(

            add_query_arg( array( 'action' => 'get_users' ) ),

            'get_users_nonce'

        );

        echo '<p><a href="' . esc_url( $url ) . '">Pobierz użytkowników</a></p>';

    }

    add_action( 'wp_footer', 'schoolpress_footer_nonce_url' );

    // Ciąg tekstowy zapytania z akcją

    function schoolpress_footer_nonce_url_action(){

        // Sprawdzenie, czy ciąg tekstowy z akcją to get_users i zawiera jednokrotnie używaną liczbę

        if ( isset( $_GET['action'] )

                && 'get_users' == $_GET['action']

                && check_admin_referer( 'get_users_nonce' ) ) {

            echo 'Twoja akcja: ' . esc_html( $_GET['action'] );

            // Ewentualnie należy pobrać użytkowników i wyświetlić ich w tym miejscu

        }

    }

    add_action( 'init', 'schoolpress_footer_nonce_url_action' );

W omawianym przykładzie zwróć uwagę na użycie funkcji esc_html() podczas
wyświetlania nazwy akcji przekazanej w ciągu tekstowym zapytania. W
poprzednich przykładach nie używaliśmy tej funkcji, ponieważ
niepotrzebnie utrudnia ona zrozumienie faktycznego działania
interesującego nas fragmentu kodu. Jednak to jest rozdział poświęcony
zapewnieniu bezpieczeństwa, a beztroskie wyświetlanie parametrów adresu
URL to jeden z najczęstszych sposobów na wprowadzenie luki w
zabezpieczeniach umożliwiającej przeprowadzenie ataku typu XSS.

Zwróć również uwagę na użycie funkcji esc_url() podczas umieszczania w
łączu pochodzącej z adresu URL jednokrotnie używanej liczby. Nawet
podczas tworzenia adresu URL za pomocą funkcji dostarczanych przez
WordPressa konieczne jest stosowanie znaków sterujących przed
przekazaniem ostatecznych danych. Funkcja esc_url() nie pozwala na jej
wielokrotne wywołanie i tym samym zniszczenie adresu URL.

wp_nonce_field( $action = -1, $name = ''_wpnonce'', $referer = true , $echo = true )

Działanie tej funkcji polega na pobraniu lub wyświetleniu w formularzu
ukrytego pola jednokrotnie używanej liczby. Swoje działanie opiera na
funkcji wp_create_nonce(), więc podczas pracy z formularzami
internetowymi zawsze korzystaj z tej eleganckiej funkcji pomocniczej.

Pole jednokrotnie używanej liczby jest wykorzystywane do sprawdzenia
treści formularza pochodzącego z bieżącej witryny internetowej, a nie z
zewnątrz. Wprawdzie jednokrotnie używana liczba nie zapewnia ochrony
absolutnej, ale w większości przypadków powinna spełniać swoją rolę.
Dlatego tak ważne jest jej stosowanie w formularzach.

Parametry $action i $name są opcjonalne, ale jeśli chcesz zapewnić
lepszy poziom bezpieczeństwa, gorąco zachęcamy do stosowania obu tych
parametrów. Wywołanie samej funkcji bez żadnych parametrów jest znacznie
łatwiejsze, lecz atakujący zwykle znają jej wartości domyślne. Nie
będzie dla nich stanowiło trudności odszukanie jednokrotnie używanej
liczby i spowodowanie poważnych problemów.

Nazwa pola danych wejściowych będzie ciągiem tekstowym podanym w
parametrze $name. Wartością tego pola będzie natomiast utworzona
jednokrotnie używana liczba. Funkcja została zdefiniowana w pliku
wp-includes/functions.php.

$action

Opcjonalny ciąg tekstowy zawierający nazwę akcji. Tę wartość zawsze
należy definiować.

$name

Opcjonalny ciąg tekstowy zawierający nazwę jednokrotnie używanej liczby.
Tę wartość zawsze należy definiować.

$referer

Opcjonalna wartość boolowska określająca, czy pole referer ma być
zdefiniowane na potrzeby weryfikacji danych. Wartością domyślną jest
true.

$echo

Opcjonalna wartość boolowska wskazująca, czy należy wyświetlić lub
zwrócić ukryte pole formularza. Wartością domyślną jest true.

    <?php

    // Prosty przykład wysłania formularza

    function schoolpress_footer_form(){

        ?>

        <form method="post">

        <?php // Utworzenie jednokrotnie używanej liczby

        wp_nonce_field( 'email_list_form', 'email_list_form_nonce' );

        ?>

        <h3>Dołącz do naszej listy dystrybucyjnej</h3>

        Adres e-mail: <input type="text" name="email_address">

        <input type="submit" name="submit_email" value="Wyślij" />

        </form>

        <?php

    }

    add_action( 'wp_footer', 'schoolpress_footer_form' );

    // Akcja formularza

    function schoolpress_footer_form_action(){

        if ( isset( $_POST['submit_email'] )

                && isset( $_POST['email_address'] )

                && check_admin_referer( 'email_list_form',

                'email_list_form_nonce' ) ) {

            echo 'Przekazane dane: ' . esc_html( $_POST['email_address'] );

            // Miejsce na kod przetwarzający formularz

        }

    }

    add_action( 'init', 'schoolpress_footer_form_action' );

    ?>

check_ajax_referer( $action = -1, $query_arg = false, $die = true )

Korzystając z technologii AJAX, należy stosować jednokrotnie używane
liczby. Ta funkcja pozwoli wygenerować taką liczbę i sprawdzić ją
podczas przetwarzania żądania AJAX. Została zdefiniowana w pliku
wp-includes/pluggable.php.

$action

Opcjonalny ciąg tekstowy akcji.

$query_arg

Opcjonalny ciąg tekstowy wskazujący, gdzie w tablicy $_REQUEST szukać
jednokrotnie używanej liczby.

$die

Opcjonalna wartość boolowska określająca, czy skrypt zawierający kod w
technologii AJAX ma zakończyć działanie, gdy jednokrotnie używana liczba
jest nieprawidłowa.

W tej książce możesz napotykać fragmenty kodu, w których nie zastosowano
jednokrotnie używanych liczb lub nie jest przeprowadzane oczyszczanie
danych. Zdecydowaliśmy się na to, aby uprościć te przykłady. Trzeba w
tym miejscu koniecznie podkreślić, że zawsze należy stosować
jednokrotnie używane liczby i oczyszczać dane. Wszelkie operacje
związane z wysyłaniem formularzy lub adresami URL zawierającymi
niestandardowe ciągi tekstowe zapytania powinny zawierać jednokrotnie
używane liczby. Ponadto ilekroć używasz polecenia $_POST['anything'] lub
$_GET['anything'], powinno zostać ono opakowane funkcją oczyszczającą
dane lub stosującą znaki sterujące.

[1] Pod względem technicznym pojęcie „bardzo długa wartość” oznacza
dane, które mają około 4 GB.

[2] Funkcja wp_verify_nonce() zwróci 1, jeśli jednokrotnie używana
liczba została wygenerowana maksymalnie 12 godzin wcześniej. W przypadku
liczby wygenerowanej od 12 do 24 godzin wcześniej wartością zwrotną jest
2. W przypadku starszej liczby funkcja zwraca false. Dzięki temu można
ustalić, czy wynikiem sprawdzenia jest true. Jeżeli chcesz przeprowadzić
sprawdzenie pod kątem nieco nowszej jednokrotnie używanej liczby,
wystarczy ustalić, czy wartością zwrotną funkcji jest 1.

Rozdział 9. Frameworki JavaScript

JavaScript to ważny komponent każdej nowoczesnej aplikacji internetowej.
Gdy pojawiły się framework Node.js, pozwalający na uruchamianie kodu
JavaScript w serwerze, oraz frameworki takie jak React, JavaScript
bardzo szybko stał się podstawowym komponentem każdej nowoczesnej
aplikacji internetowej.

W 2012 roku współczynnik kodu PHP do kodu JavaScript w wersji 3.6
WordPressa wynosił mniej więcej 6:7 i 1:7 dla JavaScriptu. W 2018 roku
wtyczka Gutenberg zapewniła nowy edytor blokowy w WordPressie 5.0, a
wymienione współczynniki uległy zmianie i wynoszą teraz tylko 1:9 dla
kodu PHP i 8:9 dla kodu JavaScript. Edytor blokowy został oczywiście
zbudowany na podstawie działającego po stronie serwera kodu PHP, ale
mimo wszystko pokazuje to, jak wiele nowych funkcji WordPressa powstało
w języku JavaScript. Gdy edytor blokowy stanie się zintegrowany z innymi
elementami panelu głównego WordPressa, można oczekiwać zwiększenia się
ilości kodu JavaScript we frameworku WordPress.

Skąd bierze się ten pęd do języka JavaScript? Jeżeli chodzi o kwestie
związane z frontendem, generowanie witryny internetowej za pomocą
JavaScriptu będzie dla serwera znacznie łatwiejsze niż za pomocą PHP.
Gdy poruszasz się po typowej witrynie internetowej, wczytywanie
wszystkich zasobów HTML DOM jest czystym marnotrawstwem. Nagłówek,
stopka, menu i wiele innych elementów witryny internetowej mogą nigdy
nie ulegać zmianie. Dzięki kodowi JavaScript można wczytać nową treść
strony, zmienić klasy elementów w menu i gotowe: mamy nową stronę. Takie
podejście bardziej przypomina stosowane w tradycyjnych aplikacjach i
okazuje się doskonałe w przypadku aplikacji internetowych udostępnianych
poprzez sieci mobilne, w których przepustowość łącza jest cennym
zasobem.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Używanie technologii AJAX do uaktualniania strony zamiast wczytywania nowej jest czasami określane mianem aplikacji w postaci pojedynczej strony (single-page application).
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Zanim zagłębimy się w świat JavaScriptu, musimy koniecznie wyjaśnić, jak
trudne jest napisanie tego rozdziału w taki sposób, aby pozostawał
aktualny. Język programowania i platforma często określane jako
JavaScript to tak naprawdę skomplikowana kolekcja standardów,
frameworków i narzędzi.

Z technicznego punktu widzenia każda oddzielna przeglądarka WWW ma swoją
wersję JavaScriptu z odmienną obsługą poszczególnych funkcji. Producenci
przeglądarek WWW wraz z innymi podmiotami działają w ramach komitetu
Ecma International Technical Committe 39 (TC39) odpowiedzialnego za
publikowanie standardu JavaScriptu. Ten standard nosi nazwę ECMAScript,
a JavaScript to po prostu jedna z jego implementacji[1]. Najnowsza w
chwili pisania książki wersja ECMAScript to ECMAScript2018 (inaczej
ES2018 lub ES9), przy czym „nowoczesny JavaScript” jest często nazywany
ES6. Ta wersja ECMAScript została wydana w 2015 roku, zaś ES6 była
pierwszą wersją zawierającą wiele funkcji, na które programiści od dawna
czekali.

Nie zgubiłeś się jeszcze? Naprawdę chcieliśmy pominąć ten cały nonsens i
zająć się wyjaśnieniem JavaScriptu w jak najprostszy sposób. Wymienione
pojęcia będziesz jednak spotykał podczas tworzenia aplikacji i dlatego
postanowiliśmy Cię z nimi zapoznać.

W rozdziale będą zdefiniowane terminy i narzędzia wybrane z najczęściej
stosowanych podczas programowania w WordPressie z użyciem JavaScriptu.
Następnie zgłębimy metody, które przez innych programistów JavaScript są
używane od lat. Na koniec przedstawimy nieco informacji o kilku nowszych
frameworkach JavaScript i sposobach pracy, które zyskały popularność w
społeczności WordPressa.

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Pojęcie „JavaScript”, używane w rozdziale i w pozostałej części książki, odnosi się do każdego kodu utworzonego w dowolnej wersji JavaScriptu działającego w przeglądarce WWW po stronie klienta. To obejmuje także wywołania jQuery i AJAX wykonywane z poziomu biblioteki jQuery.
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Co to jest ECMAScript

ECMAScript to standard publikowany przez Ecma International TC39. Na
witrynie internetowej komitetu
(https://www.ecma-international.org/memento/tc39.htm) można przeczytać
m.in.: „Standaryzacja ogólnego przeznaczenia, niezależna od platformy i
neutralna od producentów języka programowania o nazwie ECMAScript.
Obejmuje składnię języka, semantykę, biblioteki oraz wszelkie
technologie dodatkowe wspomagające język”.

JavaScript to najpopularniejsza implementacja ECMAScript. We wszystkich
przypadkach ECMAScript można potraktować jako nazwę standardu, zaś
JavaScript jako nazwę języka programowania implementowanego w
przeglądarkach WWW[2].

Co to jest ES6

ES6 to wersja standardu ECMAScript opublikowanego w 2015 roku. Dlaczego
wspominamy o nim, skoro mamy (w chwili pisania książki) rok 2018? W
standardzie ES6 wprowadzono wiele popularnych funkcji języka, które są
używane po dziś dzień: polecenia let i const stosowane wraz ze
zmiennymi, możliwość stosowania wartości domyślnych parametrów w
definicjach funkcji, a także obsługa funkcji strzałek. Ta wersja języka
zapoczątkowała stosowanie pojęcia „nowoczesny JavaScript”, więc czasami
ES6 to skrót oznaczający właśnie nowoczesny język JavaScript.

Wszystkie najnowsze wersje przeglądarek WWW oferują niemalże pełną
obsługę standardu ES6, natomiast najpopularniejsze funkcje są na pewno
obsługiwane. Możesz bezpiecznie tworzyć kod ES6 JavaScript bez używania
kompilatora gwarantującego możliwość uruchamiania kodu w przeglądarkach
WWW.

Co to jest ES9

ES9 to wersja standardu ECMAScript opublikowanego w 2018 roku. W chwili
pisania książki była to najnowsza dostępna wersja standardu.

Co to jest ESNext

ESNext to termin używany w odniesieniu do przyszłej wersji ECMAScript,
nad którą aktualnie trwają prace.

Co to jest AJAX

Technologia AJAX (asynchronous javascript and xml) pozwala na używanie
JavaScriptu do wykonywania zapytań do serwera już po wczytaniu strony.
Kiedyś zwracane były dane w formacie XML, które następnie były
przetwarzane w przeglądarce WWW za pomocą kodu JavaScript. Obecnie coraz
częściej serwer przekazuje dane w formacie JSON lub kod HTML gotowy
bezpośrednio do wstawienia w aplikacji. W rozdziale omówiono wykonywanie
zapytań w technologii AJAX za pomocą metody ajax() biblioteki jQuery, a
także z użyciem nowego API Heartbeat w WordPressie.

Co to jest JSON

JSON (javascript object notation) to czytelny zarówno dla komputera, jak
i dla człowieka format przeznaczony do przekazywania danych. Szczególnie
użyteczny okazuje się podczas pracy z kodem JavaScriptu, ponieważ
poprawnie przygotowane polecenie JSON może być wykonane przez JavaScript
bez konieczności jego dodatkowego przetwarzania. Aby z danymi w formacie
JSON móc pracować w kodzie PHP, trzeba skorzystać z funkcji
json_encode() i json_decode() będących częścią PHP już od wydania 5.2
języka.

jQuery i WordPress

jQuery to popularna biblioteka JavaScriptu, dzięki której wykonywanie
wielu operacji w języku JavaScript stało się znacznie prostsze. Jednym z
zadań ułatwianych przez jQuery jest wykonywanie żądań w technologii
AJAX.

WordPress jest dostarczany wraz z własną wersją jQuery, która jest
wykorzystywana w administracyjnym panelu głównym do wykonywania wielu
zadań związanych z interfejsem użytkownika i żądaniami AJAX. Skoro
biblioteka jQuery znajduje się już w serwerze, dodanie jej do aplikacji
WordPressa działającej we frontendzie jest bardzo proste.

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   W chwili pisania książki WordPress był dostarczany wraz z biblioteką jQuery w wersji 1.12.4, podczas gdy najnowszą dostępną była wersja 3.3.1. Większość motywów i wtyczek WordPressa używa biblioteki jQuery dostarczanej wraz z WordPressem, więc z tej wersji będziemy korzystać w prezentowanych przykładach. Przejście do nowszej wersji jQuery będzie raczej trudniejszym zadaniem. Więcej informacji na ten temat znajdziesz na stronie https://core.trac.wordpress.org/ticket/37110.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Plik biblioteki JavaScript jQuery znajduje się pod adresem:
/wp-includes/lib/js/jquery.js. W celu wczytania tej biblioteki zwykle do
znacznika <head> witryny internetowej dodaje się przedstawione tutaj
łącze:

    <script lang="JavaScript" src="/wp-includes/lib/js/jquery.js" />

Takie rozwiązanie zadziała, jeśli to łącze będzie dodane do pliku
header.php motywu lub poprzez zaczep wp_head. Jednak prawidłowy sposób
na dodanie pliku .js do witryny internetowej WordPressa polega na użyciu
funkcji wp_enqueue_script(). Dodaj wiersz wp_enqueue_script('jquery') do
funkcji init wywoływanej z wewnątrz głównego pliku wtyczki, np.:

    function sp_enqueue_scripts() {

      wp_enqueue_script( 'jquery' );

    }

    add_action( 'init', 'sp_enqueue_scripts' );

Pierwszym parametrem funkcji wp_enqueue_script() jest etykieta dla
kolejkowanego pliku JavaScript. WordPress doskonale zna wartość jquery i
wie, gdzie znajduje się odpowiedni plik[3]. Dlatego jest to jedyny
wymagany parametr.

Dodawanie innych bibliotek JavaScript

Jeżeli chcesz dodać bibliotekę JavaScript nieznaną WordPressowi,
konieczne jest przekazanie pełnej listy parametrów. Główny plik wtyczki
może zawierać kod taki jak przedstawiony w kolejnym fragmencie kodu i
odpowiedzialny za wczytywanie jQuery oraz wielu innych, niezbędnych
bibliotek JavaScript. Wprawdzie istnieje możliwość dodawania skryptów za
pomocą zaczepu init, ale zamiast niego powinieneś korzystać z zaczepów
wp_enqueue_scripts i admin_enqueue_scripts. Pierwszy z wymienionych
zaczepów jest wywoływany we frontendzie tuż przed operacją dodawania
skryptów, natomiast drugi — w panelu głównym tuż przed operacją
dodawania skryptów.

    <?php

    // Frontend JavaScriptu

    function sp_wp_enqueue_scripts() {

        wp_enqueue_script( 'jquery' );

        wp_enqueue_script(

            'schoolpress-plugin-frontend',

            plugins_url( 'js/frontend.js', __FILE__ ),

            array( 'jquery' ),

            '1.0'

       );

    }

    add_action( "wp_enqueue_scripts", "sp_wp_enqueue_scripts" );

    // Sekcja administracyjna JavaScriptu

    function sp_admin_enqueue_scripts() {

        wp_enqueue_script(

            'schoolpress-plugin-admin',

            plugins_url( 'js/admin.js', __FILE__ ),

            array( 'jquery' ),

            '1.0'

        );

    }

    add_action( 'admin_enqueue_scripts', 'sp_admin_enqueue_scripts' );

    ?>

Używanie zaczepów wp_enqueue_scripts i admin_enqueue_scripts pozwala na
wczytywanie odmiennych plików JavaScript we frontendzie i backendzie
witryny internetowej. W tym miejscu można dodać kolejne operacje
sprawdzające, aby mieć pewność wczytywania biblioteki jQuery tylko na
określonych stronach, co skróci czas wczytywania stron niewymagających
tej biblioteki. Do często stosowanych rozwiązań zalicza się sprawdzenie
atrybutów wartości globalnych $post i $_REQUEST używanych w sekcjach
administracyjnych, np. $_REQUEST['page'] lub $_REQUEST['post_type'].

Pamiętaj, że pierwszym parametrem funkcji wp_enqueue_script() jest
etykieta występująca w charakterze odwołania. Drugi parametr funkcji
wskazuje WordPressowi położenie skryptu. W omawianym przykładzie funkcja
plugins_url() została użyta do ustalenia adresu URL względem bieżącego
pliku, __FILE__. Takie rozwiązanie działa, gdy kod jest dołączany w
głównym pliku wtyczki. Istnieje możliwość przekazania parametru w
postaci dirname(__FILE__) w tym wywołaniu, jeśli edytowany plik znajduje
się w podkatalogu wtyczki.

Trzeci parametr funkcji wp_enqueue_script() pozwala na zdefiniowanie
stanu zależności dla skryptu. Przekazując wartość array('jquery') dla
skryptów frontend.js i admin.js, mamy pewność, że biblioteka jQuery
będzie wczytana jako pierwsza.

Gdzie umieszczać niestandardowy kod JavaScript

Na pewno znajdziesz się w sytuacji, w której będziesz musiał zdecydować,
gdzie umieścić dany fragment kodu. Czy powinien trafić do kodu wtyczki,
czy może do kodu motywu? Oto kilka reguł, którymi warto się kierować
podczas określania miejsca umieszczenia danego fragmentu kodu
JavaScript:

-   Jeżeli dany fragment kodu ma być użyty jednokrotnie i ma ogólne
    przeznaczenie dla strony, powinien być umieszczony bezpośrednio na
    tej stronie w znaczniku <script>.
-   Jeżeli kod JavaScript jest używany więcej niż raz (funkcja lub
    moduł) i ma związek z funkcjonalnością motywu lub interfejsu
    użytkownika, powinien być umieszczony w pliku JavaScript w katalogu
    motywu (np. /themes/schoolpress/js/schoolpress.js).
-   Jeżeli kod JavaScript będzie używany więcej niż raz na stronach
    administracyjnych, należy go umieścić w pliku admin.js w katalogu
    wtyczki (np. /themes/schoolpress/js/admin.js).
-   Jeżeli kod JavaScript będzie używany więcej niż raz w aplikacji
    frontendu, ale nie jest częścią interfejsu użytkownika motywu,
    należy go umieścić w pliku frontend.js w katalogu wtyczki (np.
    /themes/schoolpress/js/frontend.js).
-   Jeżeli zdecydujesz się podzielić kod JavaScript i umieścić go w
    oddzielnych plikach, które są wczytywane na konkretnych stronach,
    skutkiem będzie większa wydajność działania aplikacji niż w
    przypadku kodu umieszczonego w jednym oddzielnym pliku
    JavaScript[4].
-   Jeżeli korzystasz z zaawansowanych frameworków JavaScript lub
    ogromne fragmenty aplikacji zostały utworzone w języku JavaScript,
    będzie potrzebna nieco bardziej skomplikowana struktura plików
    JavaScript. Zastosuj się do konwencji przyjętych w wybranym
    frameworku lub zdaj się na swoją intuicję podpowiadającą, jak należy
    podzielić pliki kodu JavaScript.

Te reguły wynikają ze sposobu, w jaki tworzymy kod JavaScript, dlatego
potraktuj je tylko jako sugestie. Część programistów broni się przed
dodawaniem jakiegokolwiek kodu JavaScript w znacznikach <script> zamiast
umieszczenia całego kodu JavaScript w plikach .js[5]. Obecnie stosowany
cykl tworzenia aplikacji internetowych przesuwa się w kierunku kodu
frontendu, co z kolei oznacza jeszcze więcej kodu JavaScript. Dlatego
umieszczenie całego kodu JavaScript w oddzielnych plikach .js jest
bezpiecznym sposobem na tworzenie aplikacji WordPress wykorzystujących
JavaScript.

Najważniejszą kwestią jest zrozumienie sposobów organizacji plików
JavaScriptu i zdefiniowanego w nich kodu, aby praca nad witryną
internetową była intuicyjna.

Wywołania AJAX za pomocą WordPressa i jQuery

Istnieje wiele sposobów wykonania wywołań AJAX w aplikacji WordPressa.
Czysty kod JavaScript oferuje już od 2000 roku funkcję XMLHttpRequest(),
której można używać bezpośrednio. Obecna generacja przeglądarek WWW
obsługuje nowsze funkcje języka JavaScript — takie jak obietnice, słowa
kluczowe async i await, metoda fetch() — które można wykorzystać do
wykonywania żądań w technologii AJAX tylko za pomocą samego JavaScriptu.
Angular, Vue.js, React i inne frameworki JavaScript mają własne metody
przeznaczone do wykonywania zadań związanych z technologią AJAX.
Najpopularniejszą w WordPressie metodą wykonywania żądań AJAX jest
użycie biblioteki jQuery. Na takie rozwiązanie zdecydowaliśmy się w
zaprezentowanych przykładach.

Wywołanie AJAX w aplikacji WordPressa wymaga dwóch komponentów.
Pierwszym jest działający we frontendzie kod JavaScript odpowiedzialny
za inicjację żądania AJAX. Drugi to działający po stronie backendu kod
PHP odpowiedzialny za przetworzenie żądania i zwrot danych w formacie
HTML lub JSON. Przyjmujemy założenie, że chcesz zmodyfikować stronę
rejestracji w taki sposób, aby automatycznie sprawdzała, czy wpisana
nazwa użytkownika jest już zajęta. Dzięki temu rejestrującą się osobę
można ostrzec o niedostępności wybranej nazwy użytkownika, jeszcze zanim
kliknie przycisk wysłania formularza, co pozwoli jej zaoszczędzić nieco
trudu i czasu.

Przygotowanie takiego rozwiązania trzeba zacząć od dodania JavaScriptu w
nagłówku stron i zdefiniowanie ajaxurl. To będzie adres URL, do którego
zostaną wykonane żądania AJAX. Niezbędny fragment kodu może przedstawiać
się następująco:

    <script type="text/JavaScript">

    var ajaxurl = '/wp-admin/admin-ajax.php';

    </script>

Ten skrypt będzie domyślnie osadzony w panelu głównym WordPressa.
Natomiast dla wykonywanych we frontendzie żądań AJAX kod trzeba osadzić
samodzielnie. Spójrz więc na kod definiujący ajaxurl dla frontendu.

    function my_wp_head_ajax_url()

    {

    ?>

    <script type=”text/JavaScript”>

    var ajaxurl = '<?php echo admin_url("admin-ajax.php");?>';

    </script>

    <?php

    }

    add_action('wp_head', 'my_wp_head_ajax_url');

W ten sposób zmienna ajaxurl jest dostępna w pozostałej części kodu
JavaScript na stronach frontendu i może być wykorzystywana podczas
wykonywania żądań AJAX. Oto kod JavaScript przeznaczony do umieszczenia
w stopce strony rejestracji konta użytkownika. Działanie tego kodu
polega na sprawdzeniu, czy wpisana nazwa użytkownika jest już zajęta.

    <?php

    // Kod JavaScript przeznaczony dla strony

    function my_wp_footer_registration_JavaScript()

    {

        // Upewniamy się, czy bieżąca strona to strona rejestracji konta użytkownika

        if(empty($_REQUEST['action']) || $_REQUEST['action'] != 'register')

            return;

    ?>

    <script>

        // Oczekiwanie na wczytanie modelu DOM

        jQuery(document).ready(function() {

            // Zmienna przechowująca czas

            var timer_checkUsername;

            // Sprawdzenie, czy wartość pola user_login uległa zmianie

            jQuery('#user_login').bind.('keyup change', function() {

                // Użycie wartości czasu do wywołania operacji sprawdzenia po upływie sekundy 

                // od podania nazwy użytkownika

                timer_checkUsername = setTimeout(function(){checkUsername();}, 1000);

            });

            });

        function checkUsername()

        {

            // Zagwarantowanie, że nazwa użytkownika istnieje

            var username = jQuery('#user_login').val();

            if(!username)

                return;

            // Sprawdzenie nazwy użytkownika

            jQuery.ajax({

            url: ajaxurl,type:'GET',timeout:5000,

                    dataType: 'html',

                    data: "action=check_username&username="+username,

                    error: function(xml){

                            // Przekroczenie czasu oczekiwania, ale nie ma potrzeby niepokojenia użytkownika

                    },

                    success: function(response){

                    // Ukrycie wszystkich opcji, które mogły być wyświetlone

                    jQuery('#username_check').remove();

                    // Wyświetlenie informacji o dostępnej (1) lub zajętej nazwie użytkownika (0)

                    if(response == 1)

                        jQuery('#user_login').after(

                         '<span id="username_check" class="okay">Nazwa użytkownika jest dostępna</span>'

                        );

                    else

                        jQuery('#user_login').after(

                         '<span id="username_check" class="taken">Nazwa użytkownika jest zajęta</span>'

                        );

                    }

            });

        }

    </script>

    <?php

    }

    add_action('wp_footer', 'my_wp_footer_registration_JavaScript');

    ?>

Przedstawiony tutaj kod został dołączony do zaczepu wp_footer, aby kod
JavaScript pojawił się na końcu danych wyjściowych HTML. Najpierw trzeba
sprawdzić warunek $_REQUEST['action'] == "register", aby mieć pewność,
że stroną bieżącą jest domyślna w WordPressie strona rejestracji konta.

Jeżeli korzystasz z wtyczki takiej jak Paid Memberships Pro oferującej
własną stronę rejestracji konta, będziesz musiał przeprowadzić także
sprawdzenie if(!is_page("membership-checkout")) w celu ustalenia
bieżącej strony. Trzeba się również upewnić o uaktualnieniu wartości
#user_login w kodzie JavaScript, aby odpowiadała identyfikatorowi
użytemu dla pola nazwy użytkownika wyświetlanemu na stronie rejestracji
konta.

W omawianym przykładzie wywołanie jQuery(document).ready() ma na celu
wykrycie, że zakończyła się operacja wczytywania modelu DOM. Następnie
wywołanie jQuery('#user_login').bind('keyup change', ...) jest używane
do wykrycia tego, że użytkownik wpisał pewne dane w polu danych
wejściowych lub w inny sposób je zmodyfikował. W takiej sytuacji funkcja
setTimeout() definiuje czas oczekiwania (tutaj sekunda), po upływie
którego podana nazwa użytkownika zostanie sprawdzona. Jeżeli cokolwiek
zostanie wpisane przed upływem zdefiniowanego czasu, licznik czasu
zaczyna biec od początku. W efekcie po sekundzie od chwili zakończenia
wpisywania danych lub modyfikacji pola danych wejściowych następuje
wywołanie funkcji checkUsername().

W funkcji checkUsername() znajduje się wywołanie jQuery.ajax(). Zanim
jednak zostanie ono wykonane, trzeba sprawdzić, czy pole nazwy
użytkownika nie jest puste. W wywołaniu jQuery.ajax() przypisujemy adres
URL (wartość ajaxurl), który został zdefiniowany nieco wcześniej za
pomocą wp_head.

Typem wywołania jest GET. Oczywiście można wykorzystać również metodę
typu POST. Wprawdzie dostępne są także metody DELETE i PUT, ale nie są
obsługiwane przez wszystkie przeglądarki WWW. Podczas podejmowania
decyzji o typie metody w żądaniu AJAX użyj tej samej logiki co podczas
określania typu żądania dla elementu <form>. Do pobierania (get) danych,
jak w omawianym przykładzie, sensowne będzie użycie metody GET,
natomiast podczas przekazywania danych do zapisania użyj metody POST.

Dla żądania AJAX w tym kodzie został zdefiniowany czas oczekiwania
wynoszący 5000 ms (5 sekund). Po jego upływie wykonywanie żądania będzie
przerwane i nastąpi uruchomienie procedury obsługi błędów. Czas
oczekiwania należy zdefiniować na podstawie rozsądnych założeń i tego,
ile czasu serwer potrzebuje na przetworzenie danego żądania. Jeżeli
podasz zbyt krótki czas oczekiwania, wykonywanie żądań będzie kończyło
się przedwcześnie. Natomiast zbyt długi czas oczekiwania spowoduje, że
użytkownicy będą musieli długo czekać, aby ostatecznie żądanie i tak
zakończyło się niepowodzeniem.

Typ danych został określony jako html. To nakazuje jQuery umieszczenie
danych wyjściowych w ciągu tekstowym. Natomiast typ danych json
spowodowałby umieszczenie wygenerowanych danych wyjściowych w zmiennej
obiektu JavaScriptu. Dostępnych jest jeszcze kilka innych typów danych,
m.in.: xml, jsonp, script i text. W dokumentacji biblioteki jQuery
znajdziesz informacje o tym, kiedy należy korzystać z wymienionych typów
danych i jak są one przetwarzane przez jQuery.

Jako dane zdefiniowaliśmy "action=check_username&username="+username, co
spowoduje przekazanie parametrów w postaci przygotowanej akcji i nazwy
użytkownika do skryptu wp-admin-ajax.php i kodu działającego po stronie
serwera.

Następnym krokiem jest zdefiniowanie procedur obsługi wywoływanych w
przypadku błędu lub oczywiście sukcesu. W pierwszym przypadku należy
wyświetlić użytkownikowi komunikat błędu. Ponieważ nie mamy do czynienia
z funkcją o znaczeniu krytycznym, nie trzeba przeszkadzać użytkownikowi
w wykonywaniu bieżącego zadania. Natomiast jeśli operacja zakończy się
sukcesem, należy usunąć element #username_check i do pola nazwy
użytkownika dołączyć odpowiedni komunikat.

  ---- ---------------------------------------------------------------------------------------------------------------
  []   Pełną dokumentację API dla wywołania jQuery.ajax() znajdziesz na stronie https://api.jquery.com/jQuery.ajax/.
  ---- ---------------------------------------------------------------------------------------------------------------

Przechodzimy teraz do kodu backendu. Przedstawiony tutaj fragment kodu
należy umieścić w pliku functions.php wtyczki lub w pliku .php w
katalogu /services/ wtyczki, aby nasłuchiwać żądania w technologii AJAX
i zwracać wartość 1 lub 0 oznaczającą odpowiednio dostępność i
niedostępność podanej nazwy użytkownika.

    <?php

    // Wykrycie żądania AJAX dla check_username

    function wp_ajax_check_username() {

        global $wpdb;

        $username = $_REQUEST['username'];

        $taken = username_exists( $username );

        if ( $taken )

            echo "0";   // Nazwa użytkownika jest zajęta

        else

            echo "1";   // Nazwa użytkownika jest dostępna

    }

    add_action( 'wp_ajax_check_username', 'wp_ajax_check_username' );

    add_action( 'wp_ajax_nopriv_check_username', 'wp_ajax_check_username' );

    ?>

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeżeli użytkownik o podanej nazwie istnieje, funkcja username_exists() zwraca jego identyfikator. W przeciwnym razie wartością zwrotną jest false. Więcej informacji na temat tej funkcji znajdziesz w serwisie WordPress Codex na stronie https://developer.wordpress.org/reference/functions/username_exists/.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Dostępne są dwa zaczepy przeznaczone do definiowania w WordPressie
funkcji wykonujących żądania AJAX. W omawianym przykładzie zostały użyte
obydwa.

wp_ajax_{action}

Wykonywany dla zalogowanych użytkowników.

wp_ajax_nopriv_{action}

Wykonywany dla niezalogowanych użytkowników.

Na stronie rejestracji użytkownik z definicji nie jest zalogowany, więc
trzeba skorzystać z zaczepu wp_ajax_nopriv_. Jednak może zachodzić
potrzeba użycia tej operacji sprawdzenia również podczas dodawania
nowego użytkownika na stronie administracyjnej i wówczas będzie użyty
zaczep wp_ajax_.

Jeżeli masz usługę AJAX, która będzie używana przez użytkowników,
skorzystaj z zaczepu wp_ajax_. Natomiast jeśli potrzebujesz usługi
udostępnianej użytkownikom zalogowanym i niezalogowanym, musisz
skorzystać z obu zaczepów.

Zwróć również uwagę na to, jak parametr action (check_username) został
dodany do zaczepu w definicji akcji. Ten zaczep będzie użyty tylko
wtedy, gdy sprawdzenie $_REQUEST['action'] == "check_username" zakończy
się sukcesem.

Zarządzanie wieloma żądaniami AJAX

Podczas pracy z żądaniami AJAX bardzo ważne jest monitorowanie ich
liczby. W przeciwnym razie możesz doprowadzić do zbyt dużego obciążenia
serwera i przeglądarki WWW klienta, co doprowadzi do zablokowania jego
sesji lub całej witryny internetowej.

Na przykład w poprzednim fragmencie kodu program czekał sekundę od
chwili zakończenia wpisywania nazwy użytkownika lub modyfikowania pola.
Dopiero po upływie tego czasu następowało wykonanie żądania AJAX,
którego celem było sprawdzenie dostępności nazwy użytkownika. Jednak po
wykonaniu jednego żądania użytkownik może ponownie wprowadzać zmiany
w polu, a tym samym spowodować wykonanie kolejnego żądania AJAX. Jeżeli
serwer nie będzie w stanie udzielić odpowiedzi w ciągu sekundy, te
żądania zaczną się kumulować.

Omawiana procedura sprawdzenia dostępności nazwy użytkownika nie daje
zbyt dużych możliwości na wymknięcie się spod kontroli, choć w wielu
innych przypadkach jest to możliwe. Prostym przykładem może być
sytuacja, w której żądanie AJAX jest wykonywane po kliknięciu przycisku
przez użytkownika. Jeżeli użytkownik kliknie przycisk 20 razy, do
serwera może być skierowanych 20 żądań AJAX. Dlatego dobrze jest
monitorować ich liczbę.

Ogólnie rzecz biorąc, podczas zarządzania żądaniami AJAX będziesz
stosować jedno z dwóch przedstawionych tutaj rozwiązań:

-   Uniemożliwienie użytkownikowi wykonania kolejnego żądania, gdy wciąż
    przetwarzane jest poprzednie żądanie AJAX tego samego typu.
-   Anulowanie wszystkich istniejących żądań tego samego typu po
    wykonaniu nowego.

Użyta opcja zależy od zadania wykonywanego przez żądanie AJAX. Jeżeli
dane są pobierane, lepiej anulować wcześniejsze żądania i wykonać to
najnowsze. Natomiast w przypadku przekazywania danych najlepiej
zignorować nowe żądanie, dopóki poprzednie nie zostanie zakończone.

W zależności od aplikacji i żądania możemy mieć wiele sposobów na
wyłączanie lub anulowanie żądań. Ponieważ wywołanie zwrotne complete
jest w metodzie jQuery.ajax() wywoływane niezależnie od wyniku żądania
(sukces lub niepowodzenie), można je wykorzystać do ponownego
udostępnienia przycisku lub innego elementu, który wcześniej spowodował
wykonanie żądania AJAX.

    // Opcja #1: wyłączenie przycisku podczas przetwarzania żądania AJAX

    jQuery('#button').click(function() {

        // Wyłączenie przycisku

        jQuery(this).attr('disabled', 'disabled');

        // Wykonanie żądania AJAX

        jQuery.ajax({

            url: ajaxurl,type:'GET',timeout:5000,

            dataType: 'html',

            error: function(xml){

                // Polecenia przeznaczone do obsługi błędów

            },

            success: function(response){

                // Polecenia przeznaczone do wykonania w przypadku sukcesu operacji

            }

            complete: function() {

                // Ponowne włączenie przycisku

                jQuery('#button').removeAttr('disabled');

            }

        });

    });

Spójrz teraz na kod, który spowoduje anulowanie starego żądania AJAX po
pojawieniu się nowego.

    // Opcja #2: anulowanie starego żądania AJAX po pojawieniu się nowego

    var ajax_request;

    jQuery('#button').click(function() {

        // Anulowanie wszelkich istniejących żądań AJAX

        if(typeof ajax_request !== 'undefined')

            ajax_request.abort();

        // Wykonanie żądania AJAX

        ajax_request = jQuery.ajax({

            url: ajaxurl,type:'GET',timeout:5000,

            dataType: 'html',

            error: function(xml){

                // Polecenia przeznaczone do obsługi błędów

            },

            success: function(response){

                // Polecenia przeznaczone do wykonania w przypadku sukcesu operacji

            }

        });

    });

API Heartbeat

W początkowej części rozdziału przygotowaliśmy wywołanie w technologii
AJAX, uzyskiwane przez uaktualnienie pola formularza. Czasami chcemy,
aby pewne operacje uaktualnienia były przeprowadzane w określonych
odstępach czasu w działającej aplikacji internetowej. Być może chcesz
sprawdzać, czy na forum pojawiły się nowe komentarze, a następnie
automatycznie je pobierać. Dzięki JavaScriptowi można to zrobić przez
sprawdzanie backendu co kilka sekund, za pomocą wywołania AJAX
wykonywanego z poziomu funkcji setInterval(). Rozwiązaniem alternatywnym
jest wykorzystanie API Heartbeat w WordPressie.

API Heartbeat jest dostępne w WordPressie, począwszy od wydania 3.6.
Może być używane do uaktualniania aplikacji praktycznie w czasie
rzeczywistym. Co 15 sekund (lub mniej, o ile wprowadzisz odpowiednią
zmianę w ustawieniach) aplikacja będzie wykonywała żądanie z klienta do
serwera oraz na odwrót. W trakcie tych żądań można przeprowadzić różne
operacje, np. automatycznie zapisać stan aplikacji lub wczytać nową
treść. W WordPressie 3.6 omawiane API jest używane do automatycznego
zapisywania postów, nakładania blokad na posty i wyświetlania
komunikatów ostrzeżenia związanych z logowaniem. W tym podrozdziale
dowiesz się, jak API Heartbeat można wykorzystać w aplikacji.

Podobnie jak wiele innych komponentów, API Heartbeat może wydawać się
skomplikowane. Jednak w rzeczywistości składa się z pewnego zbioru
danych, które za pomocą wywołań AJAX są przekazywane między klientem i
serwerem. Używając zaczepów, można „dobrać się” do tych danych i tym
samym otrzymać niezbędne informacje.

Spójrz na prosty przykład pokazujący API Heartbeat w akcji. Działanie
tego kodu polega wyłącznie na wysłaniu komunikatu marco do serwera.
Jeżeli serwer otrzyma ten komunikat, udzieli klientowi odpowiedzi w
postaci komunikatu polo. Obydwa komunikaty będą zarejestrowane w konsoli
JavaScriptu, więc co 15 sekund powinieneś zobaczyć w konsoli JavaScriptu
następujące dane:

    Klient: marco

    Serwer: polo

Użycie API Heartbeat można podzielić na trzy etapy: inicjalizacja,
wykonanie kodu JavaScript po stronie klienta, wykonanie kodu PHP po
stronie serwera.

Inicjalizacja

Oto przykład etapu inicjalizacji w kodzie używającym API Heartbeat.

    // Zagwarantowanie użycia heartbeat.js i kodu JavaScript

    function hbdemo_init()

    {

        /*

        // Dodanie danych uwierzytelniających, aby można było np. wyświetlać dowolne strony

        if(is_admin())

            return;         // Nie wykonuj tego kodu, jeśli użytkownik jest administratorem

        */

        // Zapewnienie możliwości użycia API Heartbeat

        wp_enqueue_script('heartbeat');

        

        // Wczytanie kodu JavaScript w stopce strony

        add_action("wp_footer", "hbdemo_wp_footer");

    }

    add_action('init', 'hbdemo_init');

Pierwsza funkcja zapewnia możliwość użycia pliku heartbeat.js i
przygotowuje akcję pozwalającą na umieszczenie kodu JavaScript w stopce
za pomocą zaczepu wp_footer. Jeżeli ten kod ma być wykonywany tylko na
określonych stronach (co jest bardzo prawdopodobne), należy w tym
miejscu zdefiniować odpowiednie operacje sprawdzenia.

Wykonanie kodu JavaScript po stronie klienta

Oto przykład etapu wykonania kodu JavaScript po stronie klienta podczas
pracy z API Heartbeat.

    <?php

    // Kod JavaScript odpowiedzialny za wysyłanie i przetwarzanie danych po stronie klienta

    function hbdemo_wp_footer()

    {

    ?>

    <script>

      jQuery(document).ready(function() {

            // Użycie zaczepu heartbeat-send: klient wysyła komunikat

            //'marco' w zmiennej 'client' wewnątrz tablicy data

            jQuery(document).on('heartbeat-send', function(e, data) {

                    console.log('Klient: marco');

                    // Potrzebne są pewne dane do wykonania żądania AJAX

                    data['client'] = 'marco';

            });

            // Użycie zaczepu heartbeat-tick: klient szuka zmiennej 'server'

            // w tablicy data, a następnie wyświetla jej wartość w konsoli

            jQuery(document).on('heartbeat-tick', function(e, data) {

                    if(data['server'])

                            console.log('Serwer: ' + data['server']);

            });

            // Zaczep heartbeat-error przeznaczony do obsługi błędów

            jQuery(document).on('heartbeat-error',

                    function(e, jqXHR, textStatus, error) {

                            console.log('POCZĄTEK BŁĘDU');

                            console.log(textStatus);

                            console.log(error);

                            console.log('KONIEC BŁĘDU');

                    });

      });

    </script>

    <?php

    }

    ?>

Działanie drugiej funkcji polega na umieszczeniu kodu JavaScript w
stopce. W tym kodzie JavaScript używamy wywołania
jQuery(document).ready() w celu uruchomienia kodu po zakończeniu
wczytywania modelu DOM. Następnym krokiem jest wykorzystanie trzech
zdarzeń JavaScript wywoływanych przez API Heartbeat.

1.  Zdarzenie heartbeat-send jest wywoływane bezpośrednio przed
    wysłaniem danych do serwera. Aby przekazać dane do serwera,
    odpowiednią wartość należy dodać do tablicy data przekazywanej za
    pomocą tego zdarzenia.
2.  Zdarzenie heartbeat-tick jest wywoływane, gdy serwer udziela
    odpowiedzi. Aby zobaczyć dane otrzymane z serwera, należy odszukać
    je w tablicy data przekazywanej za pomocą tego zdarzenia.
3.  Zdarzenie heartbeat-error jest wywoływane po wystąpieniu błędu w
    metodzie jQuery.ajax() użytej w celu przekazania danych do serwera.
    W tym miejscu można zdefiniować kod przeznaczony do debugowania lub
    eleganckiego zakończenia działania, gdy żądanie AJAX nie funkcjonuje
    w środowisku produkcyjnym.

Wykonywanie kodu PHP po stronie serwera

Oto przykład etapu wykonania kodu PHP po stronie serwera podczas pracy z
API Heartbeat.

    // Przetwarzanie komunikatu po stronie serwera

    function hbdemo_heartbeat_received($response, $data)

    {

        if($data['client'] == 'marco')

            $response['server'] = 'polo';

        return $response;

    }

    add_filter('heartbeat_received', 'hbdemo_heartbeat_received', 10, 2);

To jest trzecia funkcja w omawianym przykładzie. Jest wywoływana w
zaczepie heartbeat_received i przetwarza dane pochodzące od klienta.
Dane przeznaczone do odesłania klientowi należy umieścić w zmiennej
response.

Przechodzimy teraz do znacznie bardziej praktycznego przykładu. Wtyczka
SchoolPress ma na stronie pracy domowej sekcję pokazującą, ile zadań
zostało odesłanych, a ile jeszcze pozostało. API Heartbeat wykorzystamy
teraz do uaktualnienia tej liczby po opublikowaniu nowych zadań.

W szablonie licznik zadań będzie wyświetlony w sposób podobny do
przedstawionego tutaj.

    ?>

    <div>

        Odesłane:

        <span id="assignment_count">

            <?php echo count($assignment->submissions);?>

        </span>

        /

        <?php echo count($course->students);?>

    </div>

    <?php

Inicjalizacja

Oto etap inicjalizacji w omawianym przykładzie.

    function sp_init_assignments_heartbeat()

    {

        // Zignorowanie kodu, jeśli bieżąca strona nie jest stroną pracy domowej

        if(strpos($_SERVER['REQUEST_URI'], "/assignment/") === false)

            return;

        // Zapewnienie możliwości użycia API Heartbeat

        wp_enqueue_script('heartbeat');

        // Wczytanie kodu JavaScript w stopce strony

        add_action("wp_footer", "sp_wp_footer_assignments_heartbeat");

    }

    add_action('init', 'sp_init_assignments_heartbeat');

Kod inicjalizacji w omawianym przypadku jest bardzo podobny do
zastosowanego wcześniej w przykładzie użycia API Heartbeat. Dzięki
sprawdzeniu pod kątem /assignment/ w adresie URL upewniamy się, że ten
kod nie będzie wykonany na stronie innej niż strona pracy domowej.

Wykonanie kodu JavaScript po stronie klienta

Oto etap wykonania kodu JavaScript w omawianym przykładzie.

    <?php

    function sp_wp_footer_assignments_heartbeat()

    {

        global $post;   // Zmienna globalna dla bieżącej pracy domowej

    ?>

    <script>

    jQuery(document).ready(function() {

      // Zdarzenie heartbeat-send

      jQuery(document).on('heartbeat-send', function(e, data) {

            // Upewniamy się o istnieniu tablicy schoolpress w tablicy data

      if(!data['schoolpress'])

        data['schoolpress'] = new Array();

      // Przekazanie do serwera wartości post_id danej pracy domowej i liczby bieżących zadań do wykonania

      data['schoolpress']['assignment_post_id'] = '<?php echo $post->ID;?>';

      data['schoolpress']['assignment_count'] = jQuery('#assignment-count').val();

      });

      // Zdarzenie heartbeat-tick

      jQuery(document).on('heartbeat-tick', function(e, data) {

            // Uaktualnienie liczby pozostałych zadań

      if(data['schoolpress']['assignment_count'])

            jQuery('#assignment-count').val(data['schoolpress']['assignment_count']);

      });

    });

    </script>

    <?php

    }

    ?>

Zwróć uwagę na przechowywanie danych w tablicy schoolarray, która
znajduje się w tablicy data. Wszystkie dane związane z obsługą API
Heartbeat będą umieszczone w tej tablicy. To jest rodzaj przestrzeni
nazw gwarantującej, że nazwy zmiennych nie będą kolidowały z innymi
wtyczkami, które również będą korzystały z API Heartbeat. Za każdym
razem, gdy API Heartbeat przekazuje dane do serwera, te dane będą
zawierały identyfikator posta pracy domowej i bieżącą liczbę zadań do
wykonania.

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Bardzo duże znaczenie ma wysłanie czegokolwiek do serwera za pomocą API Heart-beat. Jeżeli nie będzie żadnych danych do wysłania, żądanie nie zostanie wykonane.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------

Wykonywanie kodu PHP po stronie serwera

Oto etap wykonania kodu PHP po stronie serwera w omawianym przykładzie.

    // Przetwarzanie komunikatu po stronie serwera

    function sp_heartbeat_received_assignment_count($response, $data)

    {

        // Sprawdzenie identyfikatora posta pracy domowej

        if(!empty($data['schoolpress']['assignment_post_id']))

        {

            $assignment = new Assignment(

                $data['schoolpress']['assignment_post_id']

            );

            $response['schoolpress']['assignment_count'] = count(

                $assignment->submissions

            );

        }

        return $response;

    }

    add_filter('heartbeat_received',

        'sp_heartbeat_received_assignment_count', 10, 2);

W tej funkcji sprawdzana jest wartość assignment_post_id przekazana
przez klienta. Jeżeli ta wartość zostanie znaleziona, następuje
wczytanie pracy domowej i zwrot liczby pozostałych zadań do wykonania
(wartość assignment_count), która jest oczekiwana przez kod JavaScript
frontendu.

Ten kod może być uaktualniony w celu wykrywania zmian w liczbie zadań do
wykonania (np. przez porównanie liczby wysłanej przez klienta z liczbą
przechowywaną w serwerze). W takim przypadku można wysłać nauczycielowi
komunikat inicjujący odświeżenie strony z pracą domową oddaną przez
ucznia. Ewentualnie mogą być wysłane pewne dane dotyczące nowej pracy
domowej i następnie umieszczone na stronie.

Jeżeli chcesz skrócić lub wydłużyć czas między wysyłaniem komunikatów,
możesz nadpisać ustawienia za pomocą przedstawionego tutaj fragmentu
kodu.

    function sp_heartbeat_settings($settings = array())

    {

        $settings['interval'] = 20;  // 20 sekund zamiast domyślnych 15

        return $settings;

    }

    add_filter('heartbeat_settings', 'sp_heartbeat_settings');

Warto zwrócić uwagę na to, że w trakcie pisania książki omawiane API
pozwalało na stosowanie odstępu jedynie w przedziale od 15 do 60 sekund.
Każda wartość mniejsza lub większa zostanie zmieniona na odpowiednio 15
lub 60 sekund. To ograniczenie jest w rzeczywistości dobrym rozwiązaniem
w API Heartbeat, ponieważ w danej chwili wiele wtyczek i procesów może
korzystać z tego samego wywołania. Jeżeli chcesz, aby operacja
sprawdzenia występowała częściej niż co 15 sekund, prawdopodobnie
powinieneś zdefiniować ją jako oddzielne wywołanie AJAX za pomocą
samodzielnie zdefiniowanej w JavaScript funkcji setInterval() lub
setTimeout().

API Heartbeat możesz uznać za mechanizm pozwalający jedynie na
okazjonalną komunikację między klientem i serwerem. Jeżeli potrzebujesz
rozwiązania oferującego nieco większe możliwości (wymagającym zadaniem
jest na przykład komunikacja z serwerem co sekundę), powinieneś
zaimplementować własne rozwiązanie podobne do stosowanego w API
Heartbeat.

Ograniczenia WordPressa związane z przetwarzaniem asynchronicznym

Większość aplikacji WordPressa wykonuje skrypty PHP za pomocą serwera
Apache lub NGINX. Po zastosowaniu prawidłowej optymalizacji taki serwer
potrafi obsłużyć wiele małych, jednoczesnych połączeń, co czyni go
doskonałym rozwiązaniem dla asynchronicznie działających aplikacji
JavaScript. Jednak obciążenie powodowane przez sam serwer, a co
ważniejsze również ogólne obciążenie związane z wywołaniami WordPressa
po stronie serwera, oznacza, że usługa WordPressa uruchomiona w Apache
lub NGINX nigdy nie dorówna wydajnością działania mniejszej usłudze
JavaScript uruchomionej np. w Node.js. Framework Node.js został
opracowany specjalnie do obsługi asynchronicznych wywołań JavaScript.

Mimo tego nadal możesz wiele zdziałać, wykorzystując WordPressa i
stojącą za nim architekturę. Sugerujemy jedynie, aby zawsze przygotować
rozwiązanie w oczywisty z perspektywy WordPressa sposób, a następnie po
kolei zajmować się skalowaniem wymagających tego komponentów, gdy
wydajność działania aplikacji okaże się niewystarczająca.

Czy aplikacja ma bazę użytkowników składającą się jedynie z np. 30 osób
będących pracownikami Twojej firmy? W takim przypadku możesz śmiało
korzystać z WordPressa wraz z kodem JavaScript działającym w czasie
rzeczywistym.

Czy przewidujesz, że aplikacja będzie miała tysiące użytkowników i
będzie musiała obsługiwać dziesiątki jednoczesnych połączeń? W takim
przypadku potrzebujesz sprzętu komputerowego z nieco wyższej półki, a
także musisz zapewnić płynne działanie całości rozwiązania w
WordPressie.

Czy przewidujesz, że aplikacja będzie miała miliony użytkowników i
będzie musiała obsługiwać dziesiątki tysięcy połączeń jednocześnie? W
takim przypadku potrzebujesz najwyższej klasy inżynierów, a także
pieniędzy na ich utrzymanie. To oznacza wykorzystanie maksimum
możliwości oferowanych przez WordPressa lub użycie innej platformy,
która pozwoli na pracę w czasie rzeczywistym.

Więcej informacji na temat zagadnień związanych ze skalowaniem
znajdziesz w rozdziale 14.

Frameworki JavaScript

Jednym z czynników ograniczających przejście do JavaScriptu jest to, że
wszystkie przydatne funkcje i struktury danych są natywne dla PHP. Im
większa liczba zadań programistycznych na platformie WordPressa odbywa
się w języku JavaScript, tym większa potrzeba użycia pewnego frameworka,
który pomoże w organizacji programowania w JavaScripcie.

Backbone.js

Backbone.js to framework JavaScriptu składający się z modeli, widoków i
kolekcji modeli. Taka konfiguracja jest bardzo podobna do frameworków
MVC używanych do programowania PHP po stronie serwera. W tradycyjnych
frameworkach MVC litera C skrótu oznacza kontroler (controller). W
przypadku Backbone.js zadania związane z kontrolowaniem aplikacji są
obsługiwane w widokach i poza samym frameworkiem JavaScriptu.

Backbone.js dodano do WordPressa w wersji 3.5 i od tamtej chwili
framework Backbone.js jest intensywnie używany do obsługi biblioteki
mediów i motywów. Zespół odpowiadający na WordPressa i programiści
skupieni wokół niego porzucili lub zupełnie zignorowali Backbone.js na
rzecz innych bibliotek i frameworków JavaScriptu.

Mimo tego wciąż warto wiedzieć, jak można używać Backbone.js podczas
programowania w języku JavaScript na platformie WordPressa. Jeżeli
używasz Backbone.js do wygenerowania frontendu aplikacji, najważniejszym
punktem przecięcia z WordPressem będzie zapisywanie za pomocą backendu
kolekcji i modeli w bazie danych.

Wyobraź sobie interfejs na witrynie internetowej SchoolPress
przeznaczony do dodawania grupy uczniów do prac domowych. Ten interfejs
może zawierać pole tekstowe pozwalające na nadanie nazwy grupy i
przycisk, np. Dodaj grupę, powodujący dodanie grupy. Jeżeli skorzystasz
z tradycyjnej, omówionej wcześniej w rozdziale techniki wykonywania
żądań w technologii AJAX, ciąg zdarzeń może mieć następującą postać:

1.  Użytkownik podaje nową nazwę grupy.
2.  Użytkownik klika przycisk Dodaj grupę.
3.  Nazwa grupy zostaje przekazana do serwera za pomocą żądania w
    technologii AJAX.
4.  Serwer (WordPress) przetwarza tę nazwę, dodaje nową grupę, a
    następnie udziela odpowiedzi klientowi (przekazuje pewne dane).
5.  Działający po stronie klienta kod JavaScript przetwarza otrzymaną
    odpowiedź, a następnie uaktualnia listę grup wyświetlaną we
    frontendzie.

Natomiast w aplikacji Backbone.js lista grup jest odzwierciedlona w
modelu i kolekcji zdefiniowanych w JavaScripcie. Stosujesz podejście
podobne do używanego w typowej aplikacji AJAX, ale bardziej odpowiednia
lista zadań w aplikacji Backbone.js ma następującą postać:

1.  Użytkownik podaje nową nazwę grupy.
2.  Użytkownik klika przycisk Dodaj grupę.
3.  Nazwa grupy zostaje użyta do utworzenia nowego egzemplarza modelu
    grupy, który następnie będzie dodany do kolekcji grup w Backbone.js.
4.  Każda zmiana kolekcji spowoduje uaktualnienie serwera (WordPress) za
    pomocą żądania w technologii AJAX.
5.  Reprezentacja bieżącej kolekcji grup zostaje przekazana do serwera.
6.  WordPress uaktualnia wewnętrzną reprezentację kolekcji w bazie
    danych, aby odpowiadała otrzymanym danym.

Dlatego zamiast najpierw uaktualniać coś w backendzie, a następnie
propagować tę zmianę do frontendu, w aplikacji Backbone.js najpierw
zmiana jest wyświetlana we frontendzie, który dopiero później nakazuje
backendowi zapisanie danych.

Na stronie https://bwawwp.com/backbonejs-example/ znajdziesz przykładową
funkcjonalność wtyczki SchoolPress utworzoną najpierw za pomocą
tradycyjnego podejścia wykorzystującego żądania AJAX, a następnie
opracowaną z użyciem frameworka Backbone.js.

Oto kilka zasobów, dzięki którym dowiesz się więcej o Backbone.js i
nauczysz się korzystać z tego frameworka w aplikacji WordPressa:

-   oficjalna witryna internetowa Backbone.js (https://backbonejs.org/),
-   artykuł Backbone.js And WordPress Resources napisany przez Petera R.
    Knighta i opublikowany na stronie
    http://www.peterrknight.com/2013/03/04/backbone-and-wordpress-resources/.

React

React to biblioteka JavaScriptu przeznaczona do tworzenia interaktywnego
interfejsu użytkownika. W przeciwieństwie do innych omówionych tutaj
bibliotek React nie jest pełnym frameworkiem aplikacji. Zamiast tego
koncentruje się na komponentach widoku tradycyjnego frameworka MVC.

W React definiuje się widok dla każdego stanu aplikacji. Następnie React
monitoruje stan aplikacji i odpowiednio uaktualnia interfejs użytkownika
na podstawie zmiany danych. Przykładowo licznik pokazujący całkowitą
liczbę użytkowników witryny internetowej (i prawidłowo utworzony w
React) będzie na ekranie uaktualniany automatycznie po dodaniu nowego
użytkownika lub nawet wtedy, gdy inny użytkownik zaloguje się z własnego
urządzenia.

React opiera się na komponentach. Komponentem może być coś prostego, np.
pole tekstowe lub przycisk. Podkomponenty można ze sobą łączyć i tym
samym tworzyć znacznie bardziej skomplikowane komponenty. Wiele
komponentów React użytych w WordPressie można zobaczyć na stronie
repozytorium Gutenberg w serwisie GitHub
(https://github.com/WordPress/gutenberg/tree/
master/packages/components/src). Poszczególne funkcjonalności
WordPressa, np. edytor tekstu, mają własne biblioteki komponentów
wspomagających ich działanie (https://github.com/WordPress/
gutenberg/tree/master/packages/editor/src/components).

React można wykorzystać także do tworzenia natywnych aplikacji
mobilnych, używając do tego odpowiednio nazwanej biblioteki React
Native. To nie będzie aplikacja internetowa typu „utwórz raz i
uruchamiaj gdziekolwiek”, ale raczej aplikacja działająca natywnie w
urządzeniach mobilnych. Ten sam kod React aplikacji internetowej nie
może zostać użyty w aplikacji mobilnej. Jednak ten sam język
programowania, JavaScript, i koncepcje React można wykorzystać do
przygotowania interfejsu użytkownika dla aplikacji internetowej lub
mobilnej, w zależności od wymagań.

Interfejs użytkownika nowego edytora blokowego WordPressa i jego
komponenty zostały utworzone w React. Więcej informacji na temat
tworzenia i rozszerzania bloków znajdziesz w rozdziale 11.
Przedstawiliśmy w nim także przykładowy sposób pracy odwołujący się do
pewnych koncepcji, które zostały poruszone w tym rozdziale. Jednak
wcześniej zachęcamy Cię do poznania API REST WordPressa.

[1] Przykładami innych implementacji ECMAScript są JScript i
ActionScript.

[2] Nie wiemy, dlaczego nazwa ECMAScript zawiera zapisany wielkimi
literami człon ECMA, a nazwa komitetu jest zapisywana jako Ecma
International. Taka pisownia została zastosowana w oficjalnej witrynie
internetowej komitetu.

[3] Jeżeli chcesz poznać wszystkie pliki JavaScript dołączone do
WordPressa i zarejestrowane w nim, zajrzyj do definicji funkcji
wp_default_scripts() w pliku /wp-includes/script-loader.php.

[4] Oddzielne pliki JavaScript mogą być buforowane lub dostarczane za
pomocą serwerów CDN (content delivery network). Z kolei kod JavaScript
osadzony w dynamicznie przetwarzanych plikach PHP nie może być w łatwy
sposób buforowany.

[5] Jason, współautor książki, jest jednym z takich programistów. Jeżeli
mógłby się cofnąć w czasie, powiedziałby Jasonowi z 2012 roku, aby cały
kod JavaScript wtyczki Paid Memberships Pro był umieszczony w
oddzielnych plikach .js. To ma szczególnie duże znaczenie dla wtyczek i
motywów, które będą rozpowszechniane poza Twoją kontrolą. Umieszczenie
kodu JavaScript w oddzielnych plikach ułatwia optymalizację witryn
internetowych poprzez połączenie wszystkich plików JavaScript w jeden i
dołączenie go w stopce strony zamiast w nagłówku. Ponadto kod JavaScript
w oddzielnym pliku pomaga unikać problemów pojawiających się, gdy inny
kod osadzony na stronie działa niezgodnie z założeniami i uniemożliwia
wczytanie Twojego kodu JavaScript. Pomimo tego wciąż uważamy, że w
określonych sytuacjach nie ma nic złego w umieszczaniu kodu JavaScript w
plikach .php, gdy zachowujesz kontrolę nad całą aplikacją i próbujesz
uprościć rozwiązanie.

Rozdział 10. API REST WordPressa

W wydaniu 4.4 WordPressa wprowadzono do projektu API REST, dzięki
któremu WordPress stał się jeszcze bardziej rozszerzalny. To API REST
pozwala programistom na przekazywanie danych do WordPressa i pobieranie
z niego, z zewnątrz platformy. Dzięki temu zyskują oni możliwość
tworzenia wielu wspaniałych i użytecznych aplikacji, które niekoniecznie
używają tradycyjnego interfejsu użytkownika WordPressa, ale działają na
podstawie silnika WordPressa i są przez niego integrowane. API REST
pozwala na prowadzenie komunikacji z innymi aplikacjami, niezależnie od
języka programowania, w którym zostały utworzone. Zanim zagłębimy się w
specyfikę używania API REST WordPressa, najpierw chcielibyśmy pokrótce
przedstawić to, co mamy na myśli, używając tego terminu.

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   W rozdziale znajduje się większość materiału, który został zamieszczony w opublikowanej przez WordPressa pozycji dotyczącej pracy z API REST (https://developer. wordpress.org/rest-api/). Wybrane zagadnienia zostały jednak omówione dokładniej lub zawierają przykłady, które są bardziej przydatne w kontekście tej książki. Warto również dodać, że pewne zagadnienia przedstawiono jedynie pokrótce; więcej szczegółowych informacji na ich temat znajdziesz w wymienionej pozycji WordPressa.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Czym jest API REST?

Być może wiesz, czym jest API REST, i jesteś zaskoczony tym, że nie
trafił on do WordPressa wcześniej. Spróbujemy więc nieco dokładniej
wyjaśnić to zagadnienie.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Część czytelników będzie traktowała API REST WordPressa jako API REST JSON. W rozdziale rezygnujemy więc z członu „WordPress” w nazwie API i pozostajemy przy jedynie API REST.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

API

Interfejs programowania aplikacji (application programming interface) to
zbiór funkcji i narzędzi wbudowanych w aplikację. Te funkcje i narzędzia
są przez programistów używane do pracy z daną aplikacją w sposób
wewnętrzny lub zewnętrzny, zwykle poprzez połączenie sieciowe między
aplikacjami internetowymi. W zależności od sposobu konfiguracji API
istnieje możliwość przekazywania treści do innej aplikacji i pobierania
z niej, co w praktyce oznacza integrację tych dwóch aplikacji.

API REST pozwala na pracę z bazą danych WordPressa, z którą można się
połączyć spoza witryny internetowej WordPressa.

REST

REST (representational state transfer) to styl architekturalny stosowany
podczas definiowania opartej na protokole HTTP komunikacji między
aplikacjami internetowymi. Istnieją pewne reguły związane z tworzeniem
API REST. Aby interfejs mógł zostać określony mianem RESTful, musi być:

-   zbudowany w architekturze klient – serwer,
-   bezstanowy,
-   możliwy do buforowania,
-   ujednolicony,
-   oparty na warstwach,
-   stosujący kod na żądanie.

JSON

Jak już wspomnieliśmy, JSON to otwarty standard formatu tekstowego
przeznaczony do wysyłania czytelnego tekstu w obiektach danych, takich
jak tablice i pary klucz – wartość. Odpowiedź udzielona na żądanie HTTP
do API REST powinna być w formacie JSON. Kod aplikacji powinien mieć
możliwość przetwarzania otrzymanych w odpowiedzi HTTP danych JSON, a
następnie ich użycia w aplikacji.

HTTP

HTTP to standardowy protokół używany podczas wykonywania żądań i
udzielania na nie odpowiedzi w trakcie komunikacji prowadzonej między
klientem i serwerem. Za każdym razem, gdy w przeglądarce WWW odwiedzasz
witrynę internetową, wykonywane jest żądanie HTTP i udzielana jest na
nie odpowiedź HTTP zawierająca stronę internetową, którą następnie
wczytuje przeglądarka WWW. Przekazywanie i pobieranie danych między
klientem i WordPressem za pomocą API REST odbywa się z użyciem tego
samego protokołu. Odpowiedź nie zawiera jednak strony internetowej, ale
dane w formacie JSON. W domyślnej instalacji WordPressa można wykonywać
żądania HTTP w celu uzyskania dostępu do treści publicznej, takiej jak
posty i strony, w formacie JSON, jeśli bezpośrednio w przeglądarce WWW
podasz odpowiedni adres URL lub trasę API.

Są cztery podstawowe typy metod żądań HTTP podczas pracy z API RESTful
takim jak WordPress:

-   POST
-   GET
-   PUT
-   DELETE

Bardzo często można się spotkać z określeniem tych metod mianem akcji
CRUD (create, read, update, delete), czyli akcji tworzenia (create),
odczytywania (read), uaktualniania (update) i usuwania (delete). Te
metody są używane w żądaniach HTTP w celu wykonywania określonych akcji,
których wyniki są następnie przekazywane klientowi w udzielonej
odpowiedzi HTTP.

Spróbuj na końcu adresu URL domeny witryny internetowej WordPressa
wpisać /wp-json/wp/v2/ posts, a otrzymasz listę postów Twojej witryny
wygenerowaną w formacie JSON. To jest przykład pokazujący w akcji
żądanie HTTP GET i udzieloną na nie odpowiedź. Proces wykonywania
żądania HTTP i pobierania odpowiedzi HTTP jest nazywany wymianą
komunikatów HTTP.

Każdy komunikat HTTP składa się z trzech elementów: żądanie, nagłówki i
treść.

Żądanie

Żądanie (inaczej wiersz żądania) jest wysyłane przez klienta do serwera
i zawiera metodę żądania, adres URL żądania i użytą wersję protokołu
HTTP.

Metoda żądania

GET, POST, PUT lub DELETE.

Adres URL żądania

Adres URL prowadzący do trasy API.

Wersja protokołu HTTP

Użyta w żądaniu wersja protokołu HTTP.

Po połączeniu tych wszystkich elementów otrzymujemy wiersz żądania w
postaci podobnej do następującej:

    GET URL HTTP/1.1

Wiersz informacji o stanie to odpowiedź udzielona na żądanie,
zawierająca wersję użytego protokołu HTTP oraz kod informacji o stanie,
np.:

    HTTP/1.1 200 OK

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeżeli w ulubionej wyszukiwarce internetowej poszukasz informacji o „znaczeniu kodów stanu HTTP”, otrzymasz wyniki o wszystkich dostępnych kodach stanu, które mogą być zwrócone w odpowiedzi udzielonej na żądanie HTTP. Jeżeli naprawdę chcesz zrozumieć HTTP, zajrzyj do wydanej przez O’Reilly książki HTTP: The Definitive Guide, której autorami są David Gourley, Brian Totty, Marjorie Sayer, Anshu Aggarwal i Sailu Reddy.
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Na rysunku 10.1 pokazaliśmy schemat żądania wykonywanego do serwera i
odpowiedzi udzielanej klientowi.

[]

Rysunek 10.1. Wiersz żądania

Nagłówki

Nagłówki HTTP wysyłane w komunikacie HTTP zawierają metadane, które mogą
być przekazane do żądania HTTP i pobrane z odpowiedzi HTTP. Dostępnych
jest wiele standardowych pól w żądaniu i odpowiedzi, które można
wykorzystać w nagłówku, m.in. pola dla nagłówków niestandardowych.
Nagłówki są, ogólnie rzecz biorąc, używane do przekazywania informacji
(np. związanych z uwierzytelnianiem i uprawnieniami) między klientem i
serwerem. W artykule opublikowanym w Wikipedii na stronie
https://pl.wikipedia.org/wiki/Lista_nagłówków_HTTP znajdziesz pełną
listę standardowych pól nagłówków żądania i odpowiedzi.

W przeglądarce WWW Chrome, a także w innych opartych na silniku WebKit,
istnieje możliwość wyświetlenia nagłówków dla strony bieżącej i
wszelkich wykonanych wywołań API. W tym celu wystarczy otworzyć panel
narzędzi programistycznych, a następnie przejść na kartę Network. Na
liście widocznej po lewej stronie kliknij dokument lub wywołanie AJAX, a
następnie podkartę Headers. Na rysunku 10.2 pokazaliśmy nagłówki na
stronie Wikipedii, do której łącze przedstawiliśmy w poprzednim
akapicie.

[]

Rysunek 10.2. Za pomocą narzędzi programistycznych Chrome można
wyświetlić nagłówki bieżącej strony internetowej

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Najczęściej będzie Cię interesował nagłówek Status Code. W przypadku typowej strony internetowej wczytanej bez błędów wartością tego nagłówka będzie 200 (OK). W przypadku strony Wikipedii pokazanej na rysunku 10.2 wartością jest 304 (nie zmodyfikowano). Wikipedia używa oferowanego przez przeglądarkę WWW mechanizmu buforowania, aby nie marnować zasobów podczas ponownego przekazywania odświeżonej strony, która nie została zmodyfikowana od chwili jej poprzedniego wyświetlenia. W rozdziale 14. dowiesz się, jak można skonfigurować buforowanie w przeglądarce WWW za pomocą wtyczki W3 Total Cache.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Treść

Treść komunikatu nie zawsze jest wymagana, ale może być przekazana z
żądaniem lub odpowiedzią. API REST zwykle zwraca treść, zawierającą dane
WordPressa wskazane w wykonanym żądaniu HTTP, w formacie JSON . W
zależności od metody żądania udzielona odpowiedź może nie zawierać
żadnej treści.

Dlaczego warto używać API REST WordPressa

API REST WordPressa pozwala na wykonanie każdego zadania, które jest
możliwe z poziomu panelu głównego WordPressa. Pozwala na zrobienie tego
z dowolnego miejsca, a ponadto stanowi standardowy i bezpieczny sposób
na wykonywanie tych żądań. Przykładowe możliwości, jakie oferuje API
REST.

Uzyskanie publicznego dostępu do danych WordPressa

API jest włączone domyślnie w najnowszych wersjach WordPressa i pozwala
każdemu na łatwe pobranie całej publicznie dostępnej treści, czyli
postów, stron, plików multimedialnych i komentarzy. Wprawdzie
niestandardowe typy postów i ich dane nie są domyślnie publiczne, ale
można to zmienić. W ten sposób i one staną się publicznie dostępne za
pomocą API REST. Istnieje nawet możliwość utworzenia własnych punktów
końcowych, które będą otwarte publicznie i pozwolą na pobieranie
wskazanych danych.

Używanie operacji CRUD do zarządzania danymi WordPressa

Mamy tu do czynienia z sytuacją całkowicie odwrotną do omówionej
wcześniej. Jeżeli chcesz aplikacjom zewnętrznym umożliwić zarządzanie
danymi WordPressa, musisz skorzystać z autoryzacji. API REST obsługuje
kilka różnych sposobów uwierzytelniania, więc możesz tworzyć,
odczytywać, uaktualniać i usuwać dane w imieniu WordPressa. Po
prawidłowym uwierzytelnianiu wszystkimi danymi WordPressa będzie można
zarządzać z zewnątrz WordPressa. Dostępne obecnie metody
uwierzytelniania zostaną omówione w dalszej części rozdziału.

Wymiana danych między witrynami internetowymi WordPressa

Jest to dość typowy przypadek użycia: wyobraź sobie możliwość łatwej
wymiany danych między dwiema lub większą liczbą witryn internetowych
WordPressa.

Działanie witryn internetowych WordPressa w trybie headless

Tryb headless oznacza całkowitą rezygnację z frontendu WordPressa, a
zamiast niego pracę z backendem. Być może przygotujesz instalację
WordPressa w trybie headless przeznaczoną wyłącznie do przechowywania
danych, które za pomocą API REST są używane w innej aplikacji.

Oparte na WordPressie aplikacje mobilne

W naszej firmie zajmujemy się tym nieustannie. Wykorzystując API REST,
można budować aplikacje mobilne, dla których WordPress będzie źródłem
danych. Jeżeli zdecydowałeś się na budowę samodzielnej aplikacji
mobilnej i nie potrzebujesz dla niej witryny internetowej, możesz
skorzystać z działającej w trybie headless instalacji WordPressa, która
zapewni silnik dla Twojej aplikacji. Natomiast jeśli już masz witrynę
internetową, możesz utworzyć uzupełniającą ją aplikację mobilną i
współdzielić dane tej witryny. Więcej informacji na temat tworzenia
aplikacji mobilnych za pomocą WordPressa znajdziesz w rozdziale 16.

Asynchroniczne przekazywanie danych

Programiści bardzo często napotykają problemy podczas tworzenia nowych
witryn internetowych WordPressa na podstawie produkcyjnych migawek baz
danych WordPressa. (Takie rozwiązanie jest najczęściej wybierane w celu
zachowania oryginalnej treści, a także dostarczenia programistom
rzeczywistych danych do użycia podczas tworzenia witryny internetowej).
Treść, taka jak posty, komentarze i informacje o użytkownikach, będzie
tworzona w produkcyjnej witrynie internetowej, podczas gdy prace nad
nową witryną internetową już trwają. To może stanowić poważny problem,
gdy nadejdzie chwila uruchomienia nowej witryny. W zależności od
projektu możesz zdecydować się na zamrożenie treści w produkcyjnej
witrynie internetowej, a następnie zaimportowanie danych do nowej
witryny, która w ten sposób stanie się produkcyjną. Ewentualnie większy
sens może mieć przeniesienie wszystkich nowych danych w programistycznej
bazie danych, takich jak ustawienia, nowe typy postów i metadanych, do
produkcyjnej witryny internetowej. Jeżeli wcześniej przeprowadziłeś
wiele wdrożeń nowych witryn internetowych WordPressa na podstawie
istniejących witryn WordPressa, prawdopodobnie wiesz, jak ten proces
wygląda. Gdy nowa witryna internetowa będzie gotowa do publicznego
udostępnienia, niezbędne dane będą znajdowały się w obu witrynach
(produkcyjnej i programistycznej). W tym momencie musisz przygotować
niestandardowe skrypty pobierające niezbędne dane z odpowiedniego
środowiska. API REST można użyć do uaktualnienia w czasie rzeczywistym
programistycznej wersji witryny, czyli jednocześnie z wprowadzaniem tych
zmian w produkcyjnej witrynie internetowej. Takie rozwiązanie pozwala
zaoszczędzić czas, który trzeba byłoby poświęcić na ręczne
synchronizowanie danych przed uruchomieniem nowej witryny internetowej.

Rzeczywistość wirtualna i gry

Wyobraź sobie wciągające środowiska rzeczywistości wirtualnej, w której
treść niestandardowa jest dostarczana za pomocą API REST. Przykładowo,
przyjmujemy założenie, że tworzysz grę typu wyścigi samochodowe i
chcesz, aby bilbordy w tej grze wyświetlały treść niestandardową.

Alexa i Google Home

Aleksa, zrób mi kanapkę[1]. Jesteśmy przekonani, że jest to możliwe za
pomocą API REST.

Używanie wersji drugiej API REST WordPressa

Skoro dowiedziałeś się, dlaczego miałbyś korzystać z API REST, a także
nieco więcej o wybranych technologiach ogólnie stojących za API, możemy
przejść do omówienia pracy z API REST.

Odkrycie

W bieżących wersjach WordPressa API REST jest włączone domyślnie. Mimo
wszystko nadal należy sprawdzić, czy API faktycznie jest włączone i do
której treści zapewnia dostęp. Najłatwiejszym sposobem na
skontrolowanie, czy pracujesz z API, jest dodanie fragmentu /wp-json/
lub /?rest_route=/[2] na końcu domeny WordPressa w przeglądarce WWW lub
narzędziu typu Postman, np. localhost/ wordpress/wp-json/.

Powinieneś otrzymać odpowiedź JSON dla schematu zwróconego przez
wszystkie punkty końcowe API zarejestrowane w witrynie internetowej.

Uwierzytelnianie

Uwierzytelnianie ma duże znaczenie, gdy API REST będzie używane do
więcej niż tylko pobierania treści publicznej z witryny internetowej
WordPressa. API REST oferuje opcje związane z uwierzytelnianiem, które
można zastosować w zależności od budowanej aplikacji.

Uwierzytelnianie na podstawie cookie

Uwierzytelnianie na podstawie cookie jest stosowane domyślnie i w chwili
pisania książki to jedyna metoda uwierzytelnienia wbudowana w
WordPressa. Istnieje możliwość implementacji innych metod
uwierzytelniania, ale wówczas trzeba zastosować wtyczki oferowane przez
podmioty zewnętrzne lub opracować własną metodę. W przypadku
uwierzytelnienia na podstawie cookie użytkownik musi być zalogowany do
WordPressa. Po wykonaniu jakiegokolwiek żądania API będzie ono
ograniczone akcjami, które są dostępne dla zalogowanego użytkownika.

API REST stosuje jednokrotnie używane liczby w celu ochrony przed
atakami typu CSRF. Dlatego jeśli atakujący spróbuje wykonać złośliwe
operacje, nie będzie mógł użyć do tego cookie i będzie potrzebował
prawidłowej jednokrotnie używanej liczby. Zalecaną metodą stosowania API
REST dla niestandardowych motywów i wtyczek jest użycie wbudowanego API
JavaScript, w którym jednokrotnie używane liczby są tworzone
automatycznie. Istnieje również możliwość ręcznego wykonywania żądań,
ale wówczas jednokrotnie używaną liczbę trzeba będzie przekazywać
z każdym wykonywanym żądaniem.

Uwierzytelnianie na podstawie cookie pozwala na niezwykle łatwe
tworzenie doskonałych funkcji i funkcjonalności we frontendzie witryny
internetowej za pomocą motywu lub wtyczki. Dzięki temu użytkownik
zyskuje możliwość pracy z danymi WordPressa bez konieczności uciekania
się do backendu.

Spójrz na przykład pokazujący, jak wbudowany w WordPressie klient
JavaScript tworzy jednokrotnie używaną liczbę.

    wp_localize_script( 'wp-api', 'apiSettings', array(

        'root' => esc_url_raw( rest_url() ),

        'nonce' => wp_create_nonce( 'wp_rest' )

    ) );

Ten fragment kodu powoduje umieszczenie w nagłówku HTML obiektu
JavaScriptu, który następnie może być używany w wywołaniach AJAX do
punktu końcowego API. Z żądaniem AJAX należy przekazać używaną liczbę, a
będzie ona wykorzystana do uwierzytelnienia wywołań API. Wspomniana
liczba zapewnia również ochronę witryny internetowej przed atakami typu
CSRF. Dokładne omówienie jednokrotnie używanych liczb i zagadnień
związanych z zapewnieniem bezpieczeństwa przedstawiliśmy w rozdziale 8.

W kolejnym fragmencie kodu zamieściliśmy przykład wywołania AJAX
wykonywanego za pomocą biblioteki jQuery.

    $.ajax( {

        url: apiSettings.root + 'wp/v2/posts/1',

        method: 'POST',

        beforeSend: function ( xhr ) {

            xhr.setRequestHeader( 'X-WP-Nonce', apiSettings.nonce );

        },

        data:{

            'title' : 'Witaj, świecie!'

        }

        } ).done( function ( response ) {

            console.log( response );

        } );

Działanie tego kodu polega na uaktualnieniu tytułu posta o
identyfikatorze 1. Jednokrotnie używana liczba jest przekazywana w
nagłówku X-WP-Nonce żądania. Jeżeli tworzysz niestandardowe punkty
końcowe, nie będziesz musiał weryfikować jednokrotnie używanej liczby,
ponieważ API zajmie się tym automatycznie.

Uwierzytelnianie proste

Uwierzytelnianie proste to szybkie rozwiązanie przeznaczone do
zastosowania podczas tworzenia aplikacji dla klientów zewnętrznych,
które później są integrowane z danymi WordPressa. Najpierw jednak
skoncentrujemy się na najważniejszej kwestii: ta metoda uwierzytelniania
nie jest przeznaczona do stosowania w środowisku produkcyjnym ani w
żadnej witrynie internetowej WordPressa. Uwierzytelnianie proste powinno
być stosowane jedynie podczas pracy nad aplikacją, ponieważ wymaga
przekazania zakodowanych jako base64 nazwy użytkownika i hasła w
nagłówku każdego żądania API REST. Ciąg tekstowy zakodowany jako base64
może być przechwycony i odkodowany, więc nie jest to bezpieczna metoda
uwierzytelniania.

Aby móc szybko przetestować API REST z zewnętrzną dla WordPressa
aplikacją, powinieneś zapoznać się z wtyczką WP-API Basic-Auth
(https://github.com/WP-API/Basic-Auth).

Jeżeli witryna internetowa została skonfigurowana do obsługi żądań stron
jedynie za pomocą protokołu HTTPS, a używany punkt końcowy API również
został skonfigurowany do wykonywania żądań jedynie poprzez HTTPS,
uwierzytelnianie proste jest znacznie bezpieczniejsze. Ten sam
zaszyfrowany ciąg tekstowy będzie dołączany do każdego żądania, a jeśli
hasło jest wystarczająco silne (zapoznaj się z informacjami
przedstawionymi w rozdziale 8.), wspomniany ciąg tekstowy powinien być
bezpieczny.

Istnieje możliwość modyfikacji kodu uwierzytelniania prostego, tak aby
działał jedynie z określonymi punktami końcowymi. Oznacza to możliwość
zastosowania uwierzytelniania prostego dla wybranych punktów końcowych
bez włączania tego rodzaju uwierzytelniania dla całej witryny
internetowej WordPressa. Wtyczka WP SSO, którą poznasz w dalszej części
rozdziału, właśnie w taki sposób używa uwierzytelnienia prostego. Pomimo
to warto, byś rozważył inne metody uwierzytelniania, zanim zdecydujesz
się na użycie uwierzytelniania prostego dla API aplikacji.

Spójrz na przykład pokazujący żądanie API REST, w którym użyto
uwierzytelniania prostego.

    $.ajax( {

        url: 'localhost/wp-json/wp/v2/posts/1',

        method: 'POST',

        beforeSend: function ( xhr ) {

            xhr.setRequestHeader( 'Authorization',

                'Basic ' + btoa( username + ':' + password ) );

        },

        data:{

            'title' : 'Witaj, świecie!'

        }

        } ).done( function ( response ) {

            console.log( response );

        } );

Token JWT

Token JWT (json web token) to oparty na formacie JSON otwarty standard
tworzenia tokenów dostępu, które można wykorzystać do automatyzacji
dostępu API do usługi sieciowej. Jest to bezpieczny sposób na
współdzielenie informacji między usługą sieciową i aplikacją działającą
po stronie klienta. Token JWT to zwykły obiekt JSON składający się z
nagłówka, treści i sygnatury. Proces tworzenia tokena JWT rozpoczyna się
z chwilą, gdy użytkownik loguje się do uwierzytelnionej usługi (np.
logowanie na stronie wp-admin). Token JWT jest tworzony wówczas z
przeznaczeniem do użycia w aplikacji zewnętrznej. Gdy usługa sieciowa
(mamy tutaj na myśli API REST) otrzymuje token JWT z aplikacji
zewnętrznej, sprawdza jego poprawność. Jeżeli klient jest
uwierzytelniony, będzie mógł wykorzystać API do wykonywania wszelkich
akcji CRUD, do których ma uprawnienia użytkownik odpowiadający temu
tokenowi.

Według nas prawdopodobnie najszybszym i najłatwiejszym sposobem na
rozpoczęcie bezpiecznej pracy z API REST jest użycie wtyczki JWT
Authentication for the WP REST API (https://github.com/
Tmeister/wp-api-jwt-auth). Rozszerza ona możliwości API REST o obsługę
tokenów JWT jako metody uwierzytelniania API. Konfiguracja tej wtyczki
jest bardzo prosta. Warto po nią sięgnąć, gdy szukasz najszybszego
sposobu na bezpieczne używanie API REST.

Uwierzytelnianie OAuth

Open Authorization (OAuth) to wydany w 2007 roku otwarty standard
opartego na tokenie uwierzytelniania i autoryzacji. OAuth to preferowana
metoda uwierzytelniania podczas tworzenia dla klientów zewnętrznych
aplikacji, które są zintegrowane z danymi WordPressa. Dzięki temu
użytkownik zyskuje możliwości uwierzytelnienia bez konieczności
umieszczania hasła w jakimkolwiek żądaniu. OAuth Flow to proces
otrzymywania tokena, który następnie jest używany do autoryzacji
określonej liczby informacji dla użytkownika, przeznaczonych później do
współdzielenia z aplikacją.

Obecnie istnieją dwie wersje OAuth, 1.0 i 2.0. Największa różnica między
nimi polega na tym, że wersja 2.0 wymaga żądań API uwierzytelnianych za
pomocą HTTPS lub SSL/TLS. Dostępne są również dwie wtyczki OAuth
WordPress, które zespół tworzący API REST opracował dla obu wersji
OAuth.

https://github.com/WP-API/OAuth1

Ta wtyczka w rzeczywistości używa OAuth 1.0a, ponieważ nie wymaga ona
SSL dla żadnego punktu końcowego, podczas gdy OAuth 1.0 wymaga SSL dla
niektórych punktów końcowych. Skoro WordPress nie wymaga ani SSL, ani
stosowania protokołu HTTPS w witrynie internetowej, to jest to znacznie
częściej używana i popularniejsza wtyczka.

https://github.com/WP-API/OAuth2

To może być kolejna wtyczka do użycia, ale pamiętaj, że obecnie znajduje
się ona we wczesnej wersji beta.

Wprawdzie zawsze możesz opracować własne rozwiązanie zupełnie od
początku lub wykorzystać istniejącą bibliotekę, ale po co poświęcać czas
na wyważanie otwartych drzwi. Obydwie wymienione wtyczki OAuth są
określane mianem trójnożnego uwierzytelnienia (three-legged
authentication), w którym każda „noga” pełni odrębną rolę w procesie
uwierzytelniania.

Klient

Aplikacja zewnętrzna, która chce prowadzić komunikację z WordPressem.

Serwer

Instalacja WordPressa, do której aplikacja zewnętrzna będzie wykonywała
żądania API.

Właściciel zasobu

Użytkownik końcowy zalogowany w instalacji WordPressa i używający
aplikacji zewnętrznej.

OAuth używa uwierzytelnienia na podstawie tokena wygenerowanego przez
serwer, podczas gdy właściciel zasobu uwierzytelnia się za pomocą
własnych danych uwierzytelniających. Wymieniony token jest używany przez
klienta w celu uzyskania dostępu do serwera. Token może być w dowolnym
momencie unieważniony przez serwer lub przez właściciela zasobu. Jeżeli
tak się nie stanie, token ostatecznie i tak utraci swoją ważność, co
będzie wymagało ponownego uwierzytelnienia się przez właściciela zasobu.

Szczegółowy sposób pracy z uwierzytelnianiem OAuth wygląda następująco:

1.  Klient wykonuje podpisane żądanie do serwera mające na celu pobranie
    tokena żądania, co jest określane mianem uzyskania tymczasowych
    danych uwierzytelniających. To żądanie zostaje przekazane do adresu
    URI tymczasowych danych uwierzytelniających. Zawiera następujące
    dane:
    -   oauth_consumer_key: dostarczony przez serwer
    -   oauth_timestamp
    -   oauth_nonce
    -   oauth_signature
    -   oauth_signature_method
    -   oath_callback
    -   oauth_version (opcjonalnie).
2.  Serwer weryfikuje żądanie i jeśli jest ono prawidłowe, generuje
    tokena żądania, który zawiera następujące dane:
    -   oauth_token
    -   oauth_token_secret
    -   oauth_callback_confirmed.
3.  Klient przekazuje dane właściciela zasobu (użytkownika) do serwera w
    celu autoryzacji żądania. Odbywa się to przez przygotowanie adresu
    URI żądania i dodanie do niego oauth_token (te dane zostały
    otrzymane w poprzednim kroku). To żądanie jest wykonywane do adresu
    URI punktu końcowego Resource Owner Authorization.
4.  Właściciel zasobu (użytkownik) autoryzuje się w serwerze przez
    podanie danych uwierzytelniających.
5.  Jeżeli w pierwszym kroku został podany adres URI oauth_callback,
    serwer przekierowuje klienta pod ten adres URI i dołącza wymienione
    tutaj dane jako zawartość ciągu tekstowego zapytania:
    -   oauth_token (otrzymane w kroku drugim)
    -   oauth_verifier (weryfikuje klientowi właściciela zasobu).
6.  Jeżeli adres URI oauth_callback nie został podany w pierwszym kroku,
    serwer wyświetli wartość oauth_verifier, aby właściciel zasobu mógł
    ręcznie przekazać klientowi niezbędne informacje.
7.  Po otrzymaniu wartości oauth_verifier klient wykonuje żądanie do
    serwera w celu otrzymania tokena uwierzytelniającego. To żądanie
    jest kierowane do adresu URI punktu końcowego Token Request i
    zawiera następujące dane:
    -   oauth_token (otrzymane w drugim kroku)
    -   oauth_verifier (otrzymane w poprzednim kroku).
    -   oauth_consumer_key (dostarczone przez dostawcę zasobu, serwer,
        jeszcze przed rozpoczęciem połączenia OAuth)
    -   oauth_signature
    -   oauth_signature_method
    -   oauth_nonce
    -   oauth_version.
8.  Serwer weryfikuje żądanie i przekazuje następujące dane, które są
    znane pod nazwą tokena uwierzytelnienia:
    -   oauth_token
    -   oauth_token_secret.
9.  Klient następnie używa tego tokena w celu uzyskania dostępu do
    potrzebnych mu danych z serwera.

Jeżeli nie masz doświadczenia w pracy z OAuth, być może na podstawie
przedstawionego tutaj procesu doszedłeś do wniosku, że konfiguracja
OAuth wymaga sporo pracy. Ponieważ używamy wtyczki WordPressa utworzonej
przez zespół stojący za API REST, proces ten został uproszczony pod
wieloma względami. Dlatego nie musisz próbować w pełni zrozumieć całego
ciągu uwierzytelnienia OAuth. Jeżeli jednak ten temat Cię zainteresował
i chcesz dokładniej zapoznać się z przedstawionym tutaj procesem,
przeanalizuj kod źródłowy wtyczki. Znajdziesz w nim piękny przykład
oprogramowania typu open source!

Wtyczkę OAuth1 możesz pobrać bezpośrednio z repozytorium wtyczek
WordPressa (https://wordpress. org/plugins/rest-api-oauth1/).
Przystępujemy teraz do skonfigurowania tej wtyczki w programistycznej
wersji witryny internetowej. Zatem do dzieła: zainstaluj, a następnie
aktywuj tę wtyczkę, podobnie jak każdą inną wtyczkę WordPressa.

Trasy i punkty końcowe

W rozdziale 9. dowiedziałeś się, jak można używać adresu URL
/wp-admin/admin-ajax.php w celu uzyskania dostępu do usług w technologii
AJAX. Podczas używania API REST każda metoda API ma własny adres URL
zawierający trasę i punkt końcowy.

Czym jest trasa?

Trasa prowadzi do zasobu, takiego jak /wp-json/wp/v2/posts, który w
omawianym przykładzie jest adresem HTTP dla trasy „postów”. Punktów
końcowych można używać do przeprowadzania operacji typu CRUD, o ile
zostały zdefiniowane dla danej trasy.

Czym jest punkt końcowy?

Punkt końcowy wywołuje pewną metodę lub funkcję po wykonaniu żądania do
określonej trasy. Każda trasa może mieć wiele różnych punktów końcowych.

Spójrz na przykłady żądania trasy za pomocą różnych punktów końcowych.

GET /wp/post/1

Ta trasa może mieć metodę lub funkcję o nazwie get_post(), której
działanie będzie polegało na zwrocie żądanego posta.

POST /wp/post/1

Ta trasa może mieć metodę lub funkcję o nazwie update_post(), której
działanie będzie polegało na uaktualnieniu żądanego posta.

Wprawdzie odwiedzamy tę samą trasę /wp/post/1, ale to operacja CRUD
określa wykonywaną metodę lub funkcję, i to jest punkt końcowy.

Czym jest przestrzeń nazw

Przestrzeń nazw to „prefiks” do tras API pozwalający na identyfikowanie
punktów końcowych i zabezpieczenie ich przed kolizjami między sobą.

Podstawową przestrzenią nazw jest wp. Ta przestrzeń nazw jest
zarezerwowana i nie powinna być stosowana podczas tworzenia
niestandardowych punktów końcowych. Jeżeli inna wtyczka lub motyw
zostaną zarejestrowane po tym, jak zapiszesz swoją trasę, poprzednio
zarejestrowana trasa będzie nadpisana nową.

Żądania

Wewnętrznie, gdy żądanie jest kierowane do punktu końcowego API, wówczas
to API wykorzystuje WP_REST_Request, czyli klasę podstawową, za pomocą
której zaimplementowano obiekt żądania API REST.

Ten obiekt żądania zawiera wiele metod użytecznych podczas przetwarzania
żądania. Za pomocą metody get_posts() przedstawionej w kolejnym
przykładzie po liście parametrów można odwiedzić /wp/posts?hello=world.
Metoda get_params() będzie wymieniała listę parametru hello w jej
tablicy o wartości world.

Dostępne są następujące metody:

add_header

Dołącza wartość nagłówka dla wskazanego nagłówka.

canonicalize_header_name

Gwarantuje, że nazwa nagłówka jest w formacie standardowym.

from_url

Pobiera obiekt WP_REST_Request z pełnego adresu URL.

get_attributes

Pobiera atrybuty żądania.

get_body

Pobiera treść żądania.

get_body_params

Pobiera parametry z treści żądania.

get_content_type

Pobiera typ treści w żądaniu.

get_default_params

Pobiera parametry domyślne.

get_file_params

Pobiera z treści żądania parametry w przypadku żądania dotyczącego pliku
składającego się z wielu fragmentów.

get_header

Pobiera wskazany nagłówek z żądania.

get_header_as_array

Pobiera wartości nagłówków z żądania.

get_headers

Pobiera wszystkie nagłówki z żądania.

get_json_params

Pobiera parametry z treści sformatowanej jako JSON.

get_method

Pobiera metodę HTTP żądania.

get_param

Pobiera parametr z żądania.

get_parameter_order

Pobiera priorytet parametru.

get_params

Pobiera złączone parametry z żądania.

get_query_params

Pobiera parametry z ciągu tekstowego zapytania.

get_route

Pobiera trasę dopasowaną do żądania.

get_url_params

Pobiera parametry z samej trasy żądania.

has_valid_params

Sprawdza, czy żądanie jest prawidłowe, zgodne z jego atrybutami.

offsetExists

Sprawdza, czy parametr został zdefiniowany.

offsetGet

Pobiera parametr z żądania.

offsetSet

Definiuje parametr żądania.

offsetUnset

Usuwa parametr z żądania.

parse_body_params

Przetwarza parametry treści żądania.

parse_json_params

Przetwarza parametry JSON.

remove_header

Usuwa wszystkie wartości nagłówka.

sanitize_params

Oczyszcza (gdzie jest to możliwe) parametry żądania.

set_attributes

Definiuje atrybuty żądania.

set_body

Definiuje treść żądania.

set_body_params

Definiuje parametry w treści żądania.

set_default_params

Definiuje parametry domyślne żądania.

set_file_params

Definiuje parametry w treści żądania dotyczącego pliku składającego się
z wielu fragmentów.

set_header

Definiuje nagłówek żądania.

set_headers

Definiuje nagłówki żądania.

set_method

Definiuje metodę HTTP żądania.

set_param

Definiuje parametr żądania.

set_query_params

Definiuje parametry w ciągu tekstowym żądania.

set_route

Definiuje trasę dopasowaną do żądania.

set_url_params

Definiuje parametry trasy.

Odpowiedź

Obiektowi WP_REST_Request towarzyszy WP_REST_Response, czyli klasa
podstawowa używana do implementacji obiektu odpowiedzi REST.

Ta klasa jest używana do przygotowania treści odpowiedzi, kodu stanu
HTTP oraz wszelkich nagłówków odpowiedzi.

add_link

Dodaje łącze do odpowiedzi.

add_links

Dodaje wiele łączy do odpowiedzi.

as_error

Pobiera obiekt WP_Error z odpowiedzi.

get_curies

Pobiera CURIE (zwięzłe adresy URI) używane w relacjach.

get_links

Pobiera łącza odpowiedzi.

get_matched_handler

Pobiera procedurę obsługi użytą do wygenerowania odpowiedzi.

get_matched_route

Pobiera użytą trasę.

is_error

Sprawdza, czy odpowiedź jest błędem, czyli czy jej kod stanu ma wartość
większą lub równą 400.

link_header

Definiuje pojedyncze łącze odpowiedzi.

remove_link

Usuwa łącze z odpowiedzi.

set_matched_handler

Definiuje procedurę obsługi odpowiedzialną za wygenerowanie odpowiedzi.

set_matched_route

Definiuje trasę (wyrażenie regularne dla ścieżki dostępu) odpowiedzialną
za wygenerowanie odpowiedzi.

Dodawanie własnych tras i punktów końcowych

Używanie wbudowanych tras i punktów końcowych API REST zapewnia potężne
możliwości, ale sytuacja staje się znacznie ciekawsza, gdy zaczynasz
tworzyć własne trasy i punkty końcowe. Nowe punkty końcowe mogą być
używane w celu udostępniania niestandardowych typów postów i innych
danych aplikacji, które następnie są wykorzystywane przez usługi
zewnętrzne lub kod JavaScript działający we frontendzie aplikacji.

Podczas pisania tej książki utworzyliśmy wtyczkę o nazwie WP Single
Sign-On (https://github.com/ strangerstudios/wp-sso), aby zaprezentować
wybrane funkcje API REST, w tym także te zdefiniowane samodzielnie.
Single Sign-On (SSO) oznacza, że dostęp do wielu oddzielnych witryn
internetowych można uzyskać za pomocą tych samych danych
uwierzytelniających. Istnieje wiele metod implementacji rozwiązania typu
SSO, znajdziesz do tego wiele usług i wtyczek WordPressa oferowanych
przez firmy zewnętrzne. Rozwiązanie przygotowane przez nas ma być
proste, byśmy na jego podstawie mogli przedstawić pewne kwestie i
odwoływać się do niego. Ta sama wtyczka pokazuje, jak można utworzyć
własną trasę API REST i jak korzystać z niestandardowej trasy API REST.

register_rest_route( $namespace, $route, $args, $override );

Funkcja pozwalająca na zarejestrowanie nowych tras API REST to
register_rest_route(). Musi być ona wywołana w zaczepie akcji
rest_api_init.

$namespace

Segment adresu URL znajdujący się między podstawowym prefiksem[3] i
dodawaną trasą. Ten ciąg tekstowy powinien być unikatowy dla wtyczki lub
aplikacji.

$route

Ciąg tekstowy bazowego adresu URL dodawanej trasy.

$args

Tablica opcji dla punktu końcowego. W przypadku dodawania wielu metod
dla danego punktu końcowego istnieje również możliwość przekazania
tablicy tablic. Najczęściej używane argumenty, które będą przekazywane,
to: methods (określa metody HTTP dostępne dla danego punktu końcowego),
callback (określa funkcję wywołania zwrotnego przeznaczoną do obsługi
żądań kierowanych do danego punktu końcowego) i args (definiuje
parametry zapytania możliwe do przekazania punktowi końcowemu).

$override

Określa, czy nowa trasa powinna nadpisać istniejącą trasę o takiej samej
nazwie. Wartość true oznacza, że nowa trasa nadpisze istniejącą. Z kolei
wartość false spowoduje złączenie tras ze sobą, przy czym pierwszeństwo
mają nowsze opcje. Wartością domyślną jest false.

Aby zaprezentować dodawanie własnej trasy, musimy zagłębić się w kod
wspomnianej wcześniej wtyczki Single Sign-On. Zawiera ona zarówno kod
definiujący punkt końcowy API REST i obsługujący kierowane do niego
żądania, jak i kod wykonujący w PHP wywołania do punktu końcowego API
REST.

Konfiguracja wtyczki Single Sign-On w WordPressie

Jeżeli chcesz przetestować w akcji wtyczkę WP Single Sign-On, powinieneś
ją pobrać i aktywować na dwóch witrynach internetowych WordPressa. W
każdej z nich przejdź do menu Ustawienia/ WP SSO (Settings/WP SSO).
Jedna witryna musi być skonfigurowana jako host, druga jako klient.
Konieczne jest skopiowanie wartości Host URL z witryny internetowej
hosta i wklejenie jej w ustawieniach witryny klienta. Wspomniana wartość
to adres URL niestandardowego punktu końcowego API REST, który został
utworzony przez wtyczkę.

Gdy wtyczka jest zainstalowana w obu witrynach internetowych, będzie
można zalogować się w witrynie klienta za pomocą nazwy użytkownika i
hasła dla prawidłowego użytkownika witryny internetowej hosta.
Użytkownicy witryny klienta (np. administratorzy) wciąż mogą logować się
za pomocą istniejących nazw użytkowników i haseł dla danej witryny.
Działanie wtyczki polega na sprawdzeniu w witrynie hosta, czy nastąpiło
logowanie. W przeciwnym razie w witrynie klienta będzie wygenerowany
błąd.

Dodanie trasy /wp-sso/v1/check

Przede wszystkim trzeba zarejestrować nową trasę. Wykorzystany będzie
zaczep akcji rest_api_init, a następnie do zdefiniowania trasy zostanie
użyta funkcja register_rest_route().

    function wpsso_register_routes() {

        $options = wpsso_get_options();

        // Upewnienie się o włączeniu opcji host

        if ( ! $options['host'] ) {

            return;

        }

        register_rest_route(

            'wp-sso/v1',

            '/check',

            array(

                'methods'  => WP_REST_Server::READABLE,

                'callback' => 'wpsso_check_authentication_endpoint',

            )

        );

    }

    add_action( 'rest_api_init', 'wpsso_register_routes' );

Ta funkcja najpierw pobiera tablicę opcji dla wtyczki Single Sign-On.
Jeżeli opcja host nie została włączona, trasa nie będzie zarejestrowana.
Dodawana tutaj trasa powoduje, że system będzie działał w roli hosta.

Wybrana przestrzeń nazw to wp-sso/v1. Użyty został slug dla wtyczki, a
także dodany kolejny segment, v1, do adresu URL. Jeżeli kiedykolwiek
trzeba będzie wprowadzić zmianę niezgodną ze sposobem działania
dotychczasowego API, będzie można je pozostawić jako v1, a następnie
utworzyć nowe trasy z prefiksem v2. Dzięki temu użytkownicy API będą
mogli zdecydować, czy chcą korzystać z nowej wersji API. Dodany w
omawianym przykładzie punkt końcowy to check. Zostanie on skonfigurowany
do sprawdzenia, czy nazwa użytkownika i hasła przekazane za pomocą
uwierzytelnienia prostego działają dla prawidłowych użytkowników
witryny.

Przekazane argumenty definiują dostępne metody i funkcję wywołania
zwrotnego przeznaczoną do obsługi żądań kierowanych do tej trasy.
Wartością WP_REST_Server::READABLE jest alias dla GET. Funkcja wywołania
zwrotnego to wpsso_check_authentication_endpoint().

    function wpsso_check_authentication_endpoint() {

        global $current_user;

        if ( ! empty( $current_user->user_login ) ) {

            $r = array(

                'success' => true,

                'message' => sprintf( 'Zalogowany jako %s', $current_user->user_login ),

                'user_login' => $current_user->user_login,

                'user_email' => $current_user->user_email,

                'first_name' => $current_user->first_name,

                'last_name' => $current_user->last_name,

            );

        } else {

            $r = array(

                'success' => false,

                'message' => 'Niezalogowany.',

                'user_email' => null,

                'user_login' => $current_user->user_login,

                'first_name' => null,

                'last_name' => null,

            );

        }

        $r = rest_ensure_response( $r );

        return $r;

    }

Zdefiniowana tutaj funkcja wywołania zwrotnego sprawdza, czy użytkownik
jest zalogowany. Jeżeli tak, wartością success jest true i następuje
przekazanie nazwy użytkownika, jego adresu e-mail, imienia i nazwiska.
Natomiast w przypadku niezalogowanego użytkownika wartością success jest
false, a dla danych użytkownika zostają przekazane wartości null.

Zwróć uwagę na to, że tablica zwracana w poprzednim przykładzie
przekazywana jest za pomocą funkcji rest_ensure_response(). Działanie
tej funkcji polega na skonwertowaniu tablicy na obiekt WP_REST_Response.
Jak zobaczysz w dalszej części rozdziału, podczas wykonywania żądań do
tego nowego punktu końcowego otrzymujemy w wyniku dane JSON zawierające
tablicę wartości zdefiniowanych w funkcji wywołania zwrotnego.

Stosowanie uwierzytelniania prostego w omawianej wtyczce

Aby sprawdzenie $current_user działało zgodnie z oczekiwaniami,
konieczne jest uwierzytelnianie wykonywanych żądań API. W tym celu
została dołączona klasa uwierzytelniania prostego, która jest
zdefiniowana w pliku /includes/basic-auth.php. Procedura obsługi
uwierzytelniania jest dokładnie taka sama, jak używana w podanej
wcześniej dokumentacji API REST. Jednak w omawianym przykładzie nazwy
funkcji zostały poprzedzony prefiksami, aby uniknąć konfliktów nazw.
Ponadto został dodany przedstawiony tutaj fragment kodu, aby
uwierzytelnianie proste było stosowane jedynie dla ruchu HTTPS
kierowanego do konkretnego punktu końcowego.

    // Kod nie będzie wykonany, jeśli nie jest stosowane szyfrowanie SSL

    if ( ! is_ssl() ) {

        return $user;

    }

    // Kod nie będzie wykonany, jeśli nie jest użyta nasza trasa

    if ( ! empty( $_REQUEST['rest_route'] ) ) {

        $rest_route = '/' . rest_get_url_prefix() . $_REQUEST['rest_route'];

    } else {

        $rest_route = $_SERVER['REQUEST_URI'];

    }

    if ( $rest_route != '/' . rest_get_url_prefix() . '/wp-sso/v1/check' ) {

        return $user;

    }

Używanie zdefiniowanego punktu końcowego do sprawdzenia danych uwierzytelniających użytkownika

Witryny internetowe zawierające wtyczkę Single Sign-On i skonfigurowane
jako host będą miały omówiony wcześniej punkt końcowy API REST. Gdy
dostęp spróbuje uzyskać uwierzytelniony użytkownik, zwrócona będzie
tablica zawierająca informacje szczegółowe o tym użytkowniku. Z kolei
witryny internetowe skonfigurowane jako klienci będą miały dostęp do
tego punktu końcowego API podczas logowania, aby sprawdzić, czy
użytkownik próbujący się zalogować istnieje w witrynie internetowej
hosta. Poniżej przedstawiamy odpowiedni fragment kodu.

W głównym pliku omawianej wtyczki, wp-sso.php, została zdefiniowana
funkcja wpsso_authenticate(), która korzysta z zaczepu akcji
wp_authenticate. Wymieniona funkcja przeprowadza sprawdzenie, aby
ustalić, czy zostały podane nazwa użytkownika i hasło, a następnie
sprawdza, czy te dane uwierzytelniające działają w lokalnej witrynie
internetowej. Jeżeli nie, zostaną one użyte w celu wykonania stosującego
uwierzytelnianie proste żądania do punktu końcowego WordPress Single
Sign-On w witrynie internetowej hosta. Żądanie ma pokazaną tutaj postać.

    $url = $options['host_url'];

    $args = array(

        'headers' => array(

            'Authorization' => 'Basic ' . base64_encode( $username . ':' . $password ),

        ),

    );

    $response = wp_remote_get( $url, $args );

Adres URL hosta został pobrany z opcji. Przygotowana została także
tablica nagłówków przeznaczonych do przekazania z żądaniem GET. Zmienne
$username i $password przekazywane do zaczepu wp_authenticate są
zakodowane i dołączone do nagłówka autoryzacji. Skoro zostało włączone
uwierzytelnianie proste dla punktu końcowego w witrynie internetowej
hosta, ten host spróbuje uwierzytelnić żądanie za pomocą przekazanej
nazwy użytkownika i hasła. Do wykonania żądania zostaje użyta funkcja
wp_remote_get().

Jeżeli podane dane uwierzytelniające nie działają w witrynie
internetowej hosta, odpowiedzią na żądanie jest błąd o kodzie stanu 500
i komunikat informujący o podaniu nieprawidłowego hasła.

Jeżeli dane uwierzytelniające pozwolą na zalogowanie się w witrynie
internetowej hosta, odpowiedź będzie miała postać podobną do
przedstawionej.

    array(6) {

        ["headers"]=>

            ...

        }

        ["body"]=>

        string(162) "{"success":true,...}"

        ["response"]=>

        array(2) {

            ["code"]=>

            int(200)

            ["message"]=>

            string(2) "OK"

        }

        ["cookies"]=>

        array(0) {

        }

        ["filename"]=>

        NULL

        ["http_response"]=>

        ...

    }

Pozostały kod funkcji wpsso_authenticate() sprawdza, czy kod stanu
odpowiedzi wynosi 200, a następnie używa funkcji json_decode() z treścią
odpowiedzi, aby w ten sposób wyodrębnić dane. Jeżeli w lokalnej witrynie
internetowej istnieje użytkownik o takim samym adresie e-mail, jego
hasło zostanie uaktualnione. Natomiast jeśli jeszcze nie występuje
użytkownik o podanym adresie e-mail, kod spowoduje utworzenie nowego
użytkownika.

Popularne wtyczki używające API REST WordPressa

Wiele wtyczek WordPressa używa API REST zarówno do obsługi własnych
interfejsów, jak i do tworzenia danych i funkcjonalności, które później
będą udostępnione innym aplikacjom. W tym podrozdziale omówiliśmy
wybrane wtyczki szczególnie dobrze współdziałające z API REST WordPressa
i mogące stanowić punkty odniesienia.

WooCommerce

WooCommerce ma w pełni wyposażone API pozwalające na wykonanie każdego
zadania, jakie zlecisz tej wtyczce w celu przetworzenia operacji
sfinalizowania zamówienia. Masz możliwość przeprowadzania operacji CRUD
dla produktów, zamówień, kuponów i klientów. Ponadto masz zapewniony
dostęp do raportów i informacji o należnych podatkach. Zapoznaj się
dokładnie ze szczegółową dokumentacją techniczną API REST WooCommerce,
którą znajdziesz pod adresem
https://woocommerce.github.io/woocommerce-rest-api-docs/).

API REST WooCommerce używa uwierzytelnienia prostego poprzez szyfrowane
połączenie SSL. Jednak zamiast korzystać z tej samej nazwy użytkownika i
hasła co podczas logowania do administracyjnego panelu głównego
WordPressa, WooCommerce ma w ustawieniach stronę pozwalającą na
wygenerowanie zestawu kluczy API dla określonych użytkowników. Te klucze
API mogą mieć uprawnienia ograniczone do odczytu, zapisu lub odczytu i
zapisu.

Wprawdzie klucze są oznaczone jako consumer key i consumer secret, ale
podczas używania ich w stosujących uwierzytelnianie proste żądaniach API
podajesz je odpowiednio jako nazwę użytkownika i hasło.

Przykład — niewyświetlanie banerów zarejestrowanym klientom

Obiekt Customer zwracany przez API WooCommerce ma użyteczną właściwość o
nazwie is_paying_customer. W niektórych przypadkach chcesz mieć
możliwość wyświetlania określonych banerów i reklam niezarejestrowanym
użytkownikom. W tym punkcie znajdziesz krótki przykład pokazujący, jak
takie rozwiązanie można przygotować w kodzie JavaScriptu, korzystając z
API Woo-Commerce.

Przede wszystkim potrzebny jest kod PHP odpowiedzialny za
zarejestrowanie, zlokalizowanie i zakolejkowanie kodu JavaScriptu. Jest
to przykład podobny do tego dotyczącego uwierzytelniania plików cookie,
który miałeś okazję poznać we wcześniejszej części rozdziału. Tym razem
przekazywany jest również identyfikator bieżącego użytkownika, a ponadto
kolejkujemy kod JavaScriptu.

    function my_hide_sale_banner_script() {

        global $current_user;

        wp_register_script(

            'hide-sale-banner',

            plugins_url( 'js/hide-sale-banner.js', __FILE__ ),

            array( 'jquery' )

        );

        wp_localize_script( 'hide-sale-banner', 'HSBSettings', array(

            'root' => esc_url_raw( rest_url() ),

            'nonce' => wp_create_nonce( 'wp_rest' ),

            'current_user_id' => $current_user->ID,

        ) );

        wp_enqueue_script( 'hide-sale-banner' );

    }

    add_action( 'wp_enqueue_scripts', 'my_hide_sale_banner_script' );

Spójrz teraz na kod JavaScriptu, którego zadanie polega na pobraniu za
pomocą API WooCommerce informacji o bieżącym użytkowniku. Jeżeli ten
użytkownik jest klientem, ze strony zostanie usunięty element
zawierający baner.

    jQuery(document).ready(function() {

        jQuery.ajax( {

            url: HSBSettings.root + 'wc/v3/customers/'

                + HSBSettings.current_user_id,

            method: 'GET',

            beforeSend: function ( xhr ) {

                xhr.setRequestHeader( 'X-WP-Nonce', HSBSettings.nonce );

            },

        } ).done( function ( customer ) {

            if ( customer['is_paying_customer'] ) {

                jQuery('#sale-banner').remove();

            }

        } );

    } );

Jest to całkiem eleganckie rozwiązanie. Do innych przykładów użycia API
WooCommerce można zaliczyć m.in.: generowanie kuponów „w locie”,
używanie danych statystycznych raportów sprzedaży do uaktualniania
wyświetlanego na stronie komunikatu w stylu „Mamy już x klientów!”,
a także uaktualniania „w locie” informacji o produkcie, gdy pewne
dotyczące go szczegóły zostaną zmienione w innych systemach.

BuddyPress

Zespół tworzący wtyczkę BuddyPress pracował nad przygotowaniem pełnego
rozwiązania WP REST CRUD dla typów danych BuddyPress. W trakcie pisania
tej książki projekt był ukończony mniej więcej w 90 procentach[4].

Praca nad API REST BuddyPress odbyła się za pomocą wtyczki
(https://github.com/buddypress/ BP-REST). Aby skorzystać z API REST
BuddyPress, konieczne jest zainstalowanie i aktywowanie wymienionej
wtyczki, poza oczywiście samą wtyczką BuddyPress. Celem postawionym
sobie przez twórców jest zintegrowanie obsługi API REST z wersją 5.0
wtyczki BuddyPress.

Wprawdzie API BuddyPress jest obecnie na etapie aktywnego rozwoju, ale
mimo to można je w obecnej postaci wykorzystać do osiągnięcia
zadziwiających efektów. Dostępne są punkty końcowe m.in. dla działań
podejmowanych przez użytkowników, grup, pól XProfile i grup,
użytkowników, powiadomień, komentarzy itd.

Aby zostały zwrócone jakiekolwiek dane, większość punktów końcowych
wymaga uwierzytelnienia, np. za pomocą wtyczki API REST WordPress: OAuth
1.0a Server (https://wordpress.org/plugins/ rest-api-oauth1/).

Przykład — podkreślenie aktywności określonych użytkowników

Domyślnie punkt końcowy /wp-json/buddypress/v1/activity zwraca ostatnie
działania podejmowane przez wszystkich użytkowników. Istnieje możliwość
zawężenia tych danych poprzez przekazanie parametru w postaci
identyfikatora użytkownika (user_id) oraz użycie parametru per_page do
zmiany liczby zwróconych wyników. Dlatego uwierzytelnione żądanie
wykonane pod adres URL, taki jak
https://yoursite.com/wp-json/buddypress/v1/activity?user_id=1$per_page=1+,
zwróci ostatnie działanie podjęte przez użytkownika o identyfikatorze 1.

Istnieje możliwość wykorzystania kodu, podobnego do przedstawionego w
kolejnym przykładzie, do pobrania ostatniej aktywności użytkownika i
wyświetlenia jej na górze strony.

    function my_highlight_admin_activity_script() {

    ?>

    <style>

            li.activity.highlighted {

                    background-color: #FFFFCC;

            }

    </style>

    <script>

            fetch( '/wp-json/buddypress/v1/activity?user_id=1&per_page=1' )

            .then( function( response ) {

                    return response.json();

            })

            .then( function( activity ) {

                    const elements = document.querySelectorAll(

          "a[href='" + activity[0].link + "']"

        );

                    elements.forEach( function( element ) {

                            const wrapping_div = element.closest( 'li.activity' );

                            wrapping_div.classList.add( 'highlighted' );

                    } );

            } );

    </script>

    <?php

    }

    add_action( 'wp_footer', 'my_highlight_admin_activity_script' );

Dodanie tego fragmentu kodu do pliku functions.php wtyczki lub motywu
spowoduje umieszczenie kodu JavaScript w stopce na wszystkich stronach
frontendu. Zwykle taki kod umieszcza się w oddzielnym pliku .js i
kolejkuje, podobnie jak w przykładzie BuddyPress. Wybierając pokazane
tutaj rozwiązanie, chcieliśmy pokazać inną możliwość wykonania zadania.

W poprzednim przykładzie w celu pobrania danych z API BuddyPress użyta
została metoda fetch() zamiast jQuery.ajax(). Skorzystaliśmy z kilku
zwykłych selektorów JavaScript zamiast z ich odpowiedników jQuery.
Przedstawiony kod powinien działać w większości nowoczesnych
przeglądarek WWW bez konieczności wczytywania API jQuery.

Punkt końcowy w API REST BuddyPress dotyczący działań podejmowanych
przez użytkowników nie wymaga uwierzytelniania. Wystarczy wykonać
żądanie pod adres /wp-json/buddypress/ v1/activity?user_id=1&per_page=1
i przekazać parametr user_id=1, a wynikiem będzie pobranie informacji
dotyczących tylko wskazanego użytkownika. Jeżeli przekażesz parametr
per_page=1, pobrane informacje będą dotyczyły tylko ostatniej operacji
danego użytkownika.

Paid Memberships Pro

Wtyczka Paid Memberships Pro ma proste, choć jednocześnie oferujące
potężne możliwości API REST, które można wykorzystać do udzielenia
odpowiedzi na ważne pytanie: czy użytkownik jest klientem?

Wprawdzie dostępne są jeszcze inne punkty końcowe obsługiwane przez Paid
Memberships Pro, a wiele kolejnych jest opracowywanych, ale punkt
końcowy /wp-json/wp/v2/users/2/pmpro_ membership_level okazuje się
niezwykle użyteczny do połączenia z innymi aplikacjami bazy danych
użytkowników w WordPressie i Paid Memberships Pro.

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   W przeciwieństwie do innych wymienionych w tym podrozdziale wtyczek, które tworzą własne, nowe trasy do API, wtyczka Paid Memberships Pro rozszerza istniejącą trasę /users/, aby zawierała nowy punkt końcowy do sprawdzenia poziomu członkostwa użytkownika.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Można sobie wyobrazić technikę Zapier lub IFTTT (if this then that)
sprawdzającą poziom członkostwa użytkownika za pomocą tego punktu
końcowego, a następnie na podstawie wyniku tej operacji przekazującą
dane użytkownika do innego silosu CRM (customer relationship
management). Omawiany tutaj punkt końcowy pozwala również na zarządzanie
klientami z poziomu WordPressa, a jednocześnie na kontrolowanie dostępu
do zbudowanych na dowolnej platformie aplikacji, które wykonują
uwierzytelnione wywołania API.

Przykład — sprawdzenie, czy dany adres należy do klienta

Aby móc użyć punktu końcowego pmpro_membership_level, trzeba ustalić
identyfikator użytkownika. W tym celu można przeprowadzić operację
wyszukiwania za pomocą wbudowanego punktu końcowego users. Następnie
pobieramy ustalony identyfikator i używamy go w zapytaniu dotyczącym
poziomu członkostwa.

Zwróć uwagę, że w omawianym tutaj przykładzie zostało zastosowane
uwierzytelnianie proste. W chwili pisania książki wtyczka Paid
Memberships Pro nie obsługiwała własnego uwierzytelniania. Dlatego
konieczne jest użycie aktywnej wtyczki uwierzytelniania prostego lub
zmiana przedstawionego fragmentu kodu.

    function my_check_host_site_membership() {

        global $current_user;

        // Zmień te wartości

        $host_site_url = 'https://hostsite.com/';

        $restricted_post_id = 2;

        $apiuser = 'apiuser';

        $apipassword = 'apipassword';

        // Blokowany jest jedynie identyfikator określonego posta

        $queried_object = get_queried_object();

        if ( empty( $queried_object )

                || $queried_object->ID != $restricted_post_id ) {

            return;

        }

        // Jeżeli użytkownik nie jest zalogowany, trzeba go przekierować na odpowiednią stronę

        if ( ! is_user_logged_in() ) {

            wp_redirect( $host_site_url );

            exit;

        }

        // Sprawdzenie poziomu członkostwa

        $url = esc_url(

            $host_site_url

            . '/wp-json/wp/v2/users/?search='

            . urlencode( $current_user->user_email )

        );

        $args = array(

            'headers' => array(

                'Authorization' => 'Basic '

                . base64_encode( $apiuser . ':' . $apipassword ),

            ),

        );

        // Upewnienie się, że pierwsze żądanie zakończyło się sukcesem

        $response = wp_remote_get( $url, $args );

        if ( empty( $response ) || $response['response']['code'] != '200' ) {

            wp_redirect( $host_site_url );

            exit;

        }

        // Upewnienie się o znalezieniu użytkownika

        $response_body = json_decode( $response['body'] );

        if ( empty( $response_body ) ) {

            wp_redirect( $host_site_url );

            exit;

        }

        // Wynikiem wyszukiwania użytkownika jest tablica. Pobieramy z niej pierwszy element

        $host_user = $response_body[0];

        // Sprawdzenie poziomu członkostwa użytkownika

        $url = esc_url(

            $host_site_url

            . '/wp-json/wp/v2/users/'

            . $host_user->id

            . '/pmpro_membership_level'

        );

        $response = wp_remote_get( $url, $args );

        // Upewnienie się, że drugie żądanie zakończyło się sukcesem

        if ( empty( $response ) || $response['response']['code'] != '200' ) {

            wp_redirect( $host_site_url );

            exit;

        }

        // Sprawdzenie poziomu członkostwa użytkownika

        $membership_level = json_decode( $response['body'] );

        if ( empty( $membership_level ) ) {

            wp_redirect( $host_site_url );

            exit;

        }

        /*

            Jeżeli tutaj dotrzemy, zmienna $membership_level będzie zawierała informacje

            o poziomie członkostwa użytkownika. Można to sprawdzić pod kątem określonego

            poziomu lub zakończyć operację i pozwolić użytkownikom na wyświetlenie

            na stronie danych dotyczących wszystkich poziomów członkostwa

        */

    }

    add_action( 'template_redirect', 'my_check_host_site_membership' );

W omawianym przykładzie został zmieniony adres URL, aby prowadził na
stronę główną witryny internetowej WordPressa, na której aktywna jest
wtyczka Paid Memberships Pro. Użytkownik zostanie przekierowany na
stronę pod tym adresem URL. Wartość $restricted_post_id jest
identyfikatorem posta, który ma być niedostępny dla zwykłych
użytkowników. Ten przykład można uaktualnić, aby sprawdzał metadane
posta w tablicy postów, lub skorzystać z innych czynników podczas
ograniczania dostępu. Dzięki włączeniu uwierzytelniania prostego w
witrynie internetowej używającej wtyczki Paid Memberships Pro wartości
$apiuser i $apipassword muszą zawierać odpowiednio nazwę użytkownika i
hasło użytkownika, który ma właściwość edit_users.

API REST to potężne narzędzie pozwalające tworzyć na podstawie
WordPressa szybsze i elastyczniejsze pod względem funkcjonalności
aplikacje. Jedną z wewnętrznych funkcjonalności, która dość intensywnie
korzysta z API REST, jest nowy edytor blokowy Gutenberg. W następnym
rozdziale przeanalizujemy ten edytor, bloki i tworzenie niestandardowych
typów postów.

[1] To zdanie należy usunąć w audiobooku.

[2] Fragment /?rest_route=/ jest przeznaczony dla witryn internetowych,
które nie mają włączonej obsługi łączy tzw. permalinks.

[3] Domyślnie to wp-json.

[4] Oczywiście ostatnie 10% każdego projektu wymaga przynajmniej tyle
czasu, ile zajęło przygotowanie wcześniejszych 90% projektu.

Rozdział 11. Projekt Gutenberg, bloki i niestandardowe typy postów

Gdy nowy edytor WordPressa został zapowiedziany w styczniu 2017 roku,
Matt Mullenweg napisał
(https://make.wordpress.org/core/2017/01/04/focus-tech-and-design-leads/):

Dołożyliśmy starań, aby tworzenie nowych stron i postów za pomocą tego
edytora mogło odbywać się praktycznie bez wysiłku. Ponadto edytor został
wyposażony w „bloki” ułatwiające wykonywanie zadań, które dzisiaj
wymagają stosowania skrótów, niestandardowego kodu HTML lub innych
„tajemniczych kroków”.

Niecałe dwa lata później edytor blokowy (znany pod nazwą edytora
Gutenberg) został wprowadzony w wydaniu WordPress 5.0. Ten edytor
oferuje nowy sposób edycji postów i nowy sposób tworzenia treści w
WordPressie.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Pierwotny projekt, którego celem było utworzenie edytora blokowego, był znany pod nazwą kodową „Gutenberg”. Obecnie preferujemy stosowanie terminu edytor blokowy lub zwyczajnie edytor WordPress, choć wiele osób w sporej liczbie postów wciąż określa go mianem edytora Gutenberg.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Zespół odpowiedzialny za utworzenie edytora Gutenberg opracował
podręcznik (https://developer. wordpress.org/block-editor/), który ma
pomóc użytkownikom i programistom w szybkim rozpoczęciu pracy z tym
edytorem. Jest to pozycja zwięzła, doskonale napisana i nieustannie
ulepszana. Innymi słowy, to dokumentacja, z którą powinieneś się
zapoznać. Najlepiej będzie, jeśli teraz odłożysz na bok tę książkę,
zapoznasz się z podaną lekturą, a dopiero później powrócisz do tego
rozdziału. W dalszej części będziemy bowiem zamieszczać odwołania do
wymienionego podręcznika.

W rozdziale pokrótce przedstawiamy ogólne funkcje edytora blokowego i
opracowujemy minimalny blok jako punkt wyjścia pewnej funkcjonalności.
Następnie nieco dokładniej omówimy najważniejsze funkcje, które mają
związek z tworzeniem aplikacji.

Edytor blokowy został utworzony przede wszystkim w JavaScripcie (z
użyciem interfejsu użytkownika) i jest zarządzany jako projekt Node.js.
Wprawdzie wspomniany wcześniej podręcznik pomoże w rozpoczęciu pracy z
edytorem Gutenberg, ale podczas jego lektury napotkasz przykładowe
fragmenty kodu utworzone za pomocą technologii JavaScript, React i
Gutenberg. Zrozumienie sposobu współdziałania tych technologii na pewno
pomoże podczas rozszerzania WordPressa. Dołożyliśmy starań, aby
przykłady przedstawione w rozdziale były czytelne.

Edytor WordPressa

Aktualny edytor WordPressa został utworzony wokół jednostki bloku. Te
bloki — przedstawiające akapity, nagłówki, listy, obrazy i bardziej
skomplikowane komponenty — są umieszczone seriami. Część bloków, np.
grupy i kolumny, mają wewnątrz zagnieżdżone inne bloki. Istnieje
możliwość przeciągania i upuszczania bloków w celu zmiany ich kolejności
(zobacz rysunek 11.1).

[]

Rysunek 11.1. Edytor bloków w WordPressie

Bloki można dodawać przez kliknięcie przycisku + w interfejsie
użytkownika lub poprzez wpisanie w pustym miejscu edytora znaku ukośnika
(/) i nazwy bloku. Po naciśnięciu klawisza w akapicie nastąpi utworzenie
nowego bloku akapitu. Część bloków będzie się automatycznie pojawiać po
wpisaniu w pustym bloku określonych znaków formatowania Markdown.
Dlatego znak * powoduje rozpoczęcie listy nieuporządkowanej, natomiast
znaki ## oznaczają początek nagłówka drugiego poziomu[1].

W danej chwili można edytować tylko jeden blok. Po kliknięciu bloku
staje się on aktywny i następuje przejście do trybu edytora. Gdy blok
pozostaje aktywny, karta Blok (Block) w pasku bocznym po prawej stronie
zawiera ustawienia przeznaczone dla danego bloku. Kliknięcie innego
bloku w pustym obszarze edytora spowoduje jego aktywowanie i
przeniesienie go do widoku edytora.

Edytor WordPressa stara się maksymalnie wiernie odwzorowywać frontend.
Część bloków będzie używała miejsc zarezerwowanych lub nieco odmiennych
stylów, co ma ułatwić edycję treści. Programiści zostali pouczeni, aby
widoki edytora ich bloków maksymalnie najlepiej odzwierciedlały widoki
innych bloków frontendu.

Wtyczka Classic Editor

Jeżeli masz witrynę internetową zawierającą wtyczki lub funkcje
wymagające edytora klasycznego, bądź też jesteś fanem starego, dobrego
edytora opartego na TinyMCE, możesz w niej zainstalować wtyczkę Classic
Editor (https://wordpress.org/plugins/classic-editor/). Pozwala ona na
selektywne lub globalne użycie edytora klasycznego podczas edycji
dowolnego posta lub strony. Zgodnie z informacjami zamieszczonymi w
pliku README „Classic Editor to oficjalna wtyczka WordPressa, będzie w
pełni obsługiwana i konserwowana przynajmniej do 2022 roku lub dłużej,
jeśli zajdzie potrzeba”.

Sugerujemy skorzystanie z tej wtyczki jedynie w ostateczności. Wprawdzie
ma być obsługiwana do 2022 roku, ale nowy edytor blokowy będzie coraz
bardziej stawał się integralną częścią panelu głównego WordPressa, a
ponadto zaczną się pojawiać inne wtyczki i motywy zbudowane na jego
bazie.

Używanie bloków podczas tworzenia treści i projektu

Większość dostępnych bloków jest związana z tworzeniem treści i
projektu. Te bloki pomagają w opracowywaniu rozbudowanych projektów bez
konieczności sięgania po kod. Wprawdzie omówienie popularnych bloków
związanych na przykład z tworzeniem układów stron, karuzeli i galerii
wykracza poza zakres tematyczny książki, trzeba jednak w tym miejscu
dodać, że masz do dyspozycji wiele bloków pomagających w wykonywaniu
tego rodzaju zadań.

Używanie bloków do tworzenia funkcjonalności

Część bloków jest ściśle powiązana z funkcjonalnością witryny
internetowej lub aplikacji WordPressa. Wtyczka Paid Memberships Pro
zawiera blok obsługi członkostwa pozwalający na ograniczenie na
podstawie poziomu członkostwa dostępu do wszystkich pozostałych bloków
zagnieżdżonych. Wraz z upływem czasu wtyczki zawierające bardziej
skomplikowany interfejs użytkownika frontendu będą dostarczane wraz z
blokami, które zapewnią większą kontrolę nad ułożeniem elementów
interfejsu użytkownika oraz ich konfiguracją. Możesz wyobrazić sobie
dostosowanie do własnych potrzeb widoku katalogu we wtyczce BuddyPress
za pomocą bloków i ich ustawień.

Tworzenie własnego bloku

Praca z blokami daje radość. Tworzenie własnych bloków daje jeszcze
więcej radości. Wprawdzie utworzenie bloku może być trudnym zadaniem,
ale można rozpocząć pracę od najmniejszego możliwego bloku, a następnie
zacząć go rozbudowywać.

Przykład minimalnego bloku

Absolutnym minimum wymaganym w celu dodania bloku do edytora jest
wywołanie funkcji wp.blocks.registerBlockType() w pewnym kodzie
JavaScript działającym na stronie edytora.

    wp.blocks.registerBlockType( 'bwawwp/minimal', {

        title: 'Przykład minimalnego bloku',

        category: 'common',

        edit() {

            return 'Treść minimalnego bloku edytora.';

        },

        save() {

            return 'Treść minimalnego bloku frontendu.';

        },

    } );

Pełna dokumentacja i lista opcji znajdują się w sekcji „Block
Registration” podręcznika Block Editor Handbook
(https://developer.wordpress.org/block-editor/developers/block-api/block-registration/).

Przedstawiony tutaj minimalny blok przekazuje jego nazwę i tablicę
argumentów. Nazwy muszą być unikatowe i powinny zawierać prefiks w
postaci przestrzeni nazw lub slugu wtyczki wczytującej dany blok. Nazwa
musi rozpoczynać się od litery i zawierać tylko małe litery, cyfry i
łączniki.

Nasz minimalny blok przekazuje tytuł i kategorię. Tytułem może być
dowolny opisowy ciąg tekstowy, który pomoże użytkownikowi odszukać dany
blok na liście. W dalszej części rozdziału dowiesz się, jak można
dodawać nowe kategorie do grupy powiązanych ze sobą bloków. Domyślne
kategorie w instalacji WordPressa to common, formatting, layout, widgets
i embed.

Ważnymi atrybutami registerBlockType są edit i save, dla których
przekazywane są przeznaczone do wykonania funkcje zwracające strukturę
bloku. Funkcja podana w atrybucie edit będzie wykonywana podczas
generowania bloku w edytorze (zobacz rysunek 11.2). Z kolei funkcja
podana w atrybucie save będzie wykonywana podczas zapisywania posta,
przed serializacją bloków na post_content.

[]

Rysunek 11.2. Minimalny blok wyświetlony w edytorze

W przykładzie minimalnego bloku wartością zwrotną jest prosty ciąg
tekstowy. Warto w tym miejscu dodać, że każdy kod HTML umieszczony w tym
ciągu tekstowym zostanie oczyszczony i skonwertowany na encje HTML. W
celu wygenerowania kodu znaczników w bloku konieczne jest użycie funkcji
wp.element.createElement().

Aby wczytać blok, wystarczy utworzyć wtyczkę zawierającą tylko jeden
katalog i dwa pliki.

-   block.js
-   minimal-block-example.php

Spójrz na kod minimal-block-example.php, który zakolejkuje plik
block.js.

    /**

     * Nazwa wtyczki: Minimal Block Example

     */

    function enqueue_min_block() {

        wp_enqueue_script(

            'minimal-block',

            plugins_url( 'block.js', __FILE__ ),

            array( 'wp-blocks' )

        );

    }

    add_action( 'enqueue_block_editor_assets', 'enqueue_min_block' );

To rozwiązanie jest podobne do stosowanego z innym kodem JavaScriptu w
rozdziale 9. W omawianym przykładzie korzystamy z zaczepu
enqueue_block_editor_assets zamiast standardowego wp_enqueue_scripts.
Zwróć również uwagę, że ten blok JavaScript ma zależność w postaci
wp-blocks. W trakcie dodawania funkcjonalności do bloków, konieczne
będzie dołączenie innych pakietów związanych z technologią Gutenberg.

  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Ten przykład pokazuje minimalne wymagania dla wtyczki. Jedyną wartością wymaganą w nagłówku jest nazwa wtyczki (Nazwa wtyczki), pozostałe są opcjonalne. Część właściwości jest wysoce zalecanych, o czym już wspomnieliśmy w rozdziale 3.
  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

W tym miejscu powróć do dokumentacji w witrynie WordPressa i zapoznaj
się z artykułem Writing Your First Block Type, który znajduje się na
stronie https://developer.wordpress.org/block-editor/
tutorials/block-tutorial/writing-your-first-block-type/. Omówiono w nim
dodawanie stylów, używanie edytowalnych pól, dodawanie pasków
narzędziowych i ustawień, a także tworzenie dynamicznych bloków, które
są uaktualniane w locie.

Używanie bloków niestandardowych do tworzenia aplikacji

Wyobraź sobie sytuację, w której nauczyciele SchoolPress chcą mieć
możliwość tworzenia nowych prac domowych. Jedną z możliwości jest użycie
oprogramowania Microsoft Word lub Adobe Acrobat, ewentualnie wpisanie
tekstu w postaci zwykłego posta WordPressa. Jednak potrzebne jest
rozwiązanie zapewniające integrację z pozostałą częścią budowanej
aplikacji, a oddane przez uczniów prace domowe należy umieścić w bazie
danych w celach tworzenia raportów bądź innej funkcjonalności.

Jedną z możliwości będzie opracowanie formularza w kodzie PHP. Za pomocą
technologii React można przygotować znacznie bardziej dynamiczne
rozwiązanie, w którym dane będą przechowywane w WordPressie za pomocą
API REST WordPressa. Do ułożenia danych w określony sposób można
skorzystać z wtyczki Advanced Custom Fields oraz z niestandardowego typu
postów pracy domowej. Podobnie jak w przypadku wielu innych zadań
wykonywanych podczas programowania w WordPressie, dostępnych jest wiele
rozsądnych opcji.

Jedną z nich jest utworzenie niestandardowego typu postów oraz
niestandardowych bloków i szablonów bloków. Dzięki wykorzystaniu edytora
bloków pracę rozpoczynamy od interfejsu użytkownika, który jest już
znany użytkownikom aplikacji. Istnieje możliwość przygotowania
niestandardowych bloków i szablonów bloków, aby zadania pracy domowej
zawsze zawierały dane w formacie strukturalnym, wymaganym przez
aplikację opartą na WordPressie.

Włączenie edytora bloków w niestandardowych typach postów

Podczas pracy z niestandardowym typem postów w WordPressie 5.3 domyślnie
używany jest edytor klasyczny. W pewnym momencie podczas pracy z
wszystkimi niestandardowymi typami postów trzeba będzie skorzystać z
nowego edytora bloków. Obecnie tę możliwość trzeba specjalnie włączyć
podczas rejestrowania CPT.

Spójrz ponownie na przykład wykorzystujący niestandardowy typ postów,
tym razem z włączoną opcją użycia edytora bloków.

    register_post_type(

        'homework',

        array(

            'labels' => array(

                'name' => __( 'Homework' ),

                'singular_name' => __( 'Homework' )

            ),

            'public' => true,

            'has_archive' => true,

            'supports' => array( 'title', 'editor' ), // Nowa opcja

            'show_in_rest' => true,          // Nowa opcja

        )

    );

Właściwość 'supports' => array( 'title', 'editor' ) zapewnia obsługę
pola tytułu i edytora bloków. Skoro edytor bloków używa API REST do
uaktualniania postów, konieczne jest zapewnienie obsługi API REST przez
dodanie polecenia 'show_in_rest' => true.

Kategorie bloków

Gdy dodajesz wiele powiązanych ze sobą bloków, pomocne będzie
umieszczenie ich w tej samej kategorii, aby pojawiały się razem na
liście bloków. Określenie kategorii bloku jest proste i sprowadza się do
zmiany wartości atrybutu category w argumentach wywołania
registerBlockType() w bloku JavaScriptu. WordPress trzeba jednak
poinformować o nowej kategorii bloku. Do tego celu można wykorzystać
filtr block_categories.

    // Określenie kategorii bloku Homework

    function my_block_categories( $categories, $post ) {

        return array_merge(

            $categories,

            array(

                array(

                    'slug'  => 'homework',

                    'title' => 'Homework',

                ),

            )

        );

    }

    add_filter( 'block_categories', 'my_block_categories' ), 10, 2 );

Każda kategoria w tablicy $categories jest tablicą zawierającą dwa
klucze, slug i title, jak pokazaliśmy na rysunku 11.3.

[]

Rysunek 11.3. Kategoria bloku Homework wraz z blokami Homework i
Instructions

Bloki Homework

Aby zapewnić obsługę naszej aplikacji, dodamy kilka bloków. Blok
homework/instructions będzie znajdował się na początku pracy domowej i
będzie zawierał datę jego oddania, którą można zdefiniować za pomocą
ustawień bloku. Poniżej będzie znajdowało się kilka bloków
homework/question. Każdy z nich będzie zawierał pole Rich Text
pozwalające na wpisanie pytania i określenie jego typu za pomocą
ustawień bloku. Pytanie może być typu prawda czy fałsz, wielokrotnego
wyboru lub wypracowanie.

Pełny kod źródłowy tych bloków zamieściliśmy w archiwum, które
znajdziesz pod adresem ftp:// ftp.helion.pl/przyklady/wordp2.zip.
Poszukaj tam katalogu zawierającego przykłady dla rozdziału 11.

Ograniczenie bloków do określonych CPT

Chcemy, aby bloki instructions i question były używane jedynie z postami
typu homework. W celu wymuszenia takiego ograniczenia można dodać kod,
który będzie sprawdzał typ aktualnie edytowanego posta, a następnie
wyrejestruje typ posta, jeśli jest on inny niż homework.

Na końcu pliku block.js umieść przedstawiony tutaj fragment kodu.

    // Wyrejestrowanie bloku instructions w postach innych niż typu homework

    wp.domReady( function() {

        if( wp.data.select('core/editor').getCurrentPostType() != 'homework' ) {

            wp.blocks.unregisterBlockType( 'homework/instructions' );

        }

    });

Działanie funkcji wp.domReady() jest podobne do document.ready() w
bibliotece jQuery — oczekiwanie na pełne wczytanie strony, a dopiero
później wykonanie zdefiniowanego w niej kodu. Konieczne jest
zastosowanie takiego rozwiązania, ponieważ typ aktualnie edytowanego
posta nie będzie dostępny przed zakończeniem wczytywania strony. Dlatego
trzeba wyrejestrować blok zamiast sprawdzać typ posta przed rejestracją.
Dzięki użyciu funkcji wp.domReady() masz pewność, że blok JavaScriptu
będzie za pomocą wp-dom-ready kolejkowany jako zależność.

Typ aktualnego posta jest pobierany z modułu data WordPressa za pomocą
wywołania wp.data.select('core/editor').getCurrentPostType(). Aby móc z
niego skorzystać, trzeba się upewnić, że blok JavaScript został za
pomocą wp-edit-post kolejkowany jako zależność.

Wiele użytecznych informacji jest dostępnych za pomocą podobnie
działających metod, które zostały wymienione w dokumentacji Data Module
Reference (https://developer.wordpress.org/block-editor/data/). Więcej
informacji na temat budowy modułu data i konfiguracji własnych magazynów
danych znajdziesz w dokumentacji zamieszczonej na stronie
https://developer.wordpress.org/ block-editor/packages/packages-data/.

Ograniczenie CPT do określonych bloków

Wcześniej pokazaliśmy, jak uniemożliwić używanie bloków w innych typach
postów. WordPress zawiera także filtr o nazwie allowed_blocks. Można go
wykorzystać do wybrania typów bloków dla całej witryny internetowej lub
sieci. Rozwiązanie alternatywne polega na sprawdzeniu wartości post_type
w przekazanym parametrze $post i zezwoleniu na stosowanie tylko
wybranych typów bloków podczas edytowania postów danego typu.

W kolejnym fragmencie kodu pokazujemy, jak umożliwić w postach typu
homework dostęp jedynie do bloków wspomnianych wcześniej.

    // W postach typu homework dozwolone jest stosowanie tylko określonych bloków

    function my_allowed_block_types( $allowed_blocks, $post ) {

        if ( $post->post_type == 'homework' ) {

            $allowed_blocks = array(

                'core/block',

                'core/image',

                'core/paragraph',

                'core/heading',

                'core/list',

                'homework/instructions',

                'homework/question',

            );

        }

        return $allowed_blocks;

    }

    add_filter( 'allowed_block_types', 'my_allowed_block_types', 10, 2);

Wartością domyślną $allowed_blocks jest null, co wskazuje WordPressowi,
że dozwolone są wszystkie bloki. Od chwili dodania bloków do
JavaScriptu, po wczytaniu PHP, filtr nie wie, czy dodane zostały bloki
niestandardowe. Jeżeli za pomocą kodu takiego jak przedstawiony w
poprzednim przykładzie zdefiniujesz listę dozwolonych bloków, masz
pewność, że tylko te bloki zostaną wczytane.

Szablon bloku

Podczas rejestrowania niestandardowego typu postów można przekazać
atrybut template, który będzie określał grupę bloków przeznaczonych
domyślnie do dodania do nowych postów danego typu. Spójrz na nową wersję
funkcji wywołania zwrotnego odpowiedzialnego za rejestrację posta pracy
domowej. W omawianym przykładzie domyślnie jest używany blok
instructions, po nim blok pytania typu prawda czy fałsz, a następnie
blok wypracowania.

    // Rejestracja niestandardowego typu postów

    register_homework_post_type(

        'homework',

        array(

            'labels' => array(

                'name' => __( 'Homework' ),

                'singular_name' => __( 'Homework' )

            ),

            'public' => true,

            'has_archive' => true,

        'supports' => array( 'title', 'editor' ),

        'show_in_rest' => true,

        'template' => array(

            array( 'homework/instructions' ),

            array( 'homework/question',

                array( 'content' => 'True/false 1.',

                    'question_type' => 'true_false'

                )

            ),

            array( 'homework/question',

                array( 'content' => 'Essay question.',

                    'question_type' => 'essay'

                )

            ),

        )

        )

    );

Po dodaniu tego kodu nowe posty pracy domowej będą używały naszego
szablonu i będą się rozpoczynały od bloku instructions, po którym
znajdzie się kilka innych bloków z pytaniami. Istnieje możliwość
klikania poszczególnych bloków, aby edytować ich zawartość (zobacz
rysunek 11.4).

[]

Rysunek 11.4. Szablon domyślny dla posta pracy domowej

Szablony można dodawać również do podstawowych typów postów oraz innych
niestandardowych typów postów już po ich zarejestrowaniu. Szablony mogą
być dodawane w blokach JavaScriptu, mogą także być zabezpieczone, aby
nie można było zmieniać lub usuwać szablonów. Więcej informacji na temat
szablonów bloków znajdziesz w sekcji „Block Templates” książki Block
Editor Handbook, która umieszczona jest na stronie
https://developer.wordpress.org/block-editor/developers/
block-api/block-templates/.

Zapisywanie danych bloku w metadanych posta

Domyślnie atrybuty bloku są przechowywane wewnątrz specjalnie
sformatowanych komentarzy HTML w post_content. Spójrz na przykładowe
instrukcje bloku przed ich skonwertowaniem na postać frontendu.

    <!-- wp:homework/instructions -->

    <p class="wp-block-homework-instructions-content">Odeślij pracę domową.</p>

    <p class="wp-block-homework-instructions-due_date">Termin: 2020-11-01</p>

    <!-- /wp:homework/instructions -->

Jeżeli blok został skonfigurowany prawidłowo, jego zawartość i termin
oddania pracy domowej będą edytowane w edytorze blokowym oraz w
ustawieniach panelu dla tego bloku. Warto w tym miejscu przypomnieć, że
ta treść zostanie następnie wyświetlona we frontendzie witryny
internetowej.

Jednak być może będzie zachodziła potrzeba sortowania zadań pracy
domowej według daty bądź też opracowania innych raportów na podstawie
zbiorów danych w blokach. Będzie to możliwe, o ile dane są przechowywane
w metadanych postów.

W celu powiązania atrybutów bloku z metadanymi posta konieczne jest
zarejestrowanie pól metadanych. Nie zawsze będziesz rejestrować
metadane. Wystarczy po prostu wywołać bezpośrednio funkcję
update_post_meta(), a następnie dodać żądane dane. Jeżeli metadanymi
posta chcesz operować poprzez API REST, konieczne jest ich
zarejestrowanie.

    register_post_meta( 'homework', '_homework_due_date', array(

        'show_in_rest' => true,

        'single' => true,

        'type' => 'string',

        'auth_callback' => function() {

            return current_user_can( 'edit_posts' );

        }

    ) );

Teraz wystarczy zdefiniować źródło w atrybucie bloku, aby w ten sposób
połączyć go z metadanymi posta.

    wp.blocks.registerBlockType( 'homework/instructions', {

        // …

        attributes: {

            content: {

                type: 'array',

                source: 'children',

                selector: 'p',

            },

            due_date: {

                type: 'string',

                meta: '_homework_due_date',

                source: 'meta',

                default: '',

            }

        },

        // …

    }

Więcej informacji szczegółowych na temat edytowania metadanych posta za
pomocą bloków znajdziesz w sekcji „Store Post Meta with a Block” w
książce Block Editor Handbook na stronie
https://developer.wordpress.org/block-editor/tutorials/metabox/meta-block-1-intro/).

Podpowiedzi

Prace nad technologią Gutenberg są skomplikowane, szybko postępują i są
warte poświęcenia im oddzielnej książki. Omówiliśmy tutaj podstawy i
kilka technik, które powinny być użyteczne dla programistów aplikacji
korzystających z projektu Gutenberg. Przedstawimy kilka ogólnych
podpowiedzi, które pomogą w pracy, oraz wskażemy kilka kolejnych źródeł
zawierających cenne informacje.

Włączenie WP_SCRIPT_DEBUG

Domyślnie WordPress używa zminimalizowanej wersji kodu JavaScript i
łączy wszystkie skrypty w jeden plik. To powoduje, że błędy JavaScriptu
wyświetlane w konsoli są praktycznie bezużyteczne. Podczas
przeprowadzania wszelkiego rodzaju prac programistycznych z użyciem
JavaScriptu, a szczególnie podczas pracy z projektem Gutenberg, dobrym
rozwiązaniem jest włączenie opcji WP_SCRIPT_DEBUG.

Dodanie polecenia define( 'WP_SCRIPT_DEBUG', true ); do pliku
wp-config.php nakazuje WordPressowi użycie niezminimalizowanych wersji
skryptów i oddzielne wczytywanie wszystkich skryptów JavaScript. Dzięki
temu błędy wyświetlane w konsoli debugowania będą zawierały użyteczne
nazwy plików oraz numery wierszy, co ułatwi analizowanie błędów.

Używanie wywołania filemtime() dla wersji skryptu

Gdy kolejkujesz skrypt JavaScript, możesz zdefiniować jego wersję.
Ponieważ przeglądarki WWW agresywnie buforują pliki JavaScriptu,
uaktualnienie wersji skryptu powoduje wymuszenie jego pobrania z
serwera, a nie z bufora. Podczas pracy z plikami JavaScriptu będziesz
dość często je edytował i uaktualniał. Zdefiniowanie wersji skryptu na
podstawie daty ostatniej modyfikacji jego pliku to jeden ze sposobów na
wymuszenie użycia aktualnej wersji skryptu, a nie starszej, buforowanej
przez przeglądarkę WWW.

Spójrz na przykładowy fragment kodu, w którym następuje kolejkowanie
bloków używających funkcji filemtime() do zdefiniowania wersji skryptu.

    wp_register_script(

        'homework-question',

        BWAWWP_URL . 'homework-cpt/blocks/question/blocks.js',

        array( 'wp-blocks',

            'wp-element',

            'wp-editor',

            'wp-components',

            'wp-dom-ready',

            'wp-edit-post',

        ),

        filemtime( BWAWWP_DIR . 'homework-cpt/blocks/question/blocks.js' )

    );

Zanim wdrożysz ten kod w postaci wtyczki, powinieneś uaktualnić wersję
skryptu w taki sposób, aby odpowiadała wersji wtyczki lub określonej
wersji skryptu.

Więcej podpowiedzi

Opublikowany na stronie
https://gutenberghub.com/31-days-of-gutenberg-development-beginners-tips-by-zac-gordon/
artykuł 31 Tips for Gutenberg Development zawiera wiele cennych
podpowiedzi i wskazuje kierunek, w którym się możesz udać, jeśli chcesz
poznać bardziej zaawansowane zagadnienia związane z używaniem bloków
podczas programowania w WordPressie.

Poznaj dokładnie JavaScript, Node.js i React

Lepsze poznanie sztuki programowania za pomocą niezmodyfikowanych wersji
JavaScriptu, Node.js i frameworka React na pewno pomoże podczas
stosowania bloków w aplikacjach WordPressa. Poświęć nieco czasu na
lekturę, poeksperymentuj z kodem i spróbuj poznać sposób działania
wszystkich wymienionych tutaj technologii. Przekonasz się, że
rozwiązywanie problemów napotykanych podczas programowania z użyciem
technologii Gutenberg stanie się znacznie łatwiejsze, gdy będziesz
wiedział, na której warstwie stosu powstał błąd.

JavaScript

Więcej informacji na temat języka JavaScript i jego historii związanej z
WordPressem przedstawiliśmy w rozdziale 9. Im lepsze będziesz miał
umiejętności w zakresie programowania w WordPressie, tym łatwiej pójdzie
Ci praca z blokami. Książki JavaScript: The Definitive Guide napisana
przez Davida Flanagana i JavaScript — mocne strony autorstwa Douglasa
Crockforda to dwie doskonałe pozycje dla osób, które chcą poznać
JavaScript. Możesz je przejrzeć i skoncentrować się na podstawach oraz
używać w charakterze przewodnika encyklopedycznego bądź też zagłębić się
w nie, aby dokładniej poznać JavaScript.

Node.js*

Node.js to środowisko uruchomieniowe JavaScriptu, które działa w
środowisku serwerowym. Kilka opartych na Node.js narzędzi jest używanych
w typowej konfiguracji rozwiązania opartego na technologii Gutenberg;
należą do nich webpack, Babel i npm (menedżer pakietów Node.js).
Narzędzie webpack jest używane do kompilacji wszystkich skryptów
JavaScript do postaci pojedynczego pliku paczki, którą następnie można
wdrożyć w przeglądarce WWW. Narzędzie Babel jest używane do konwersji
kodu ESNext i JSX na kod JavaScript, który działa w różnych
przeglądarkach WWW. Z kolei menedżer pakietów npm służy do instalowania
pakietów JavaScriptu i zarządzania zależnościami między nimi. Zarówno
webpack, jak i Babel są typowo instalowane jako moduły Node.js. W kodzie
JavaScript dla bloków być może będziesz korzystać z jeszcze innych
bibliotek JavaScriptu. Instalacja i zarządzanie nimi odbywa się za
pomocą menedżera pakietów npm. Sekcja „JavaScript Build Setup” w
podręczniku Block Editor Handbook
(https://developer.wordpress.org/block-editor/tutorials/javascript/js-build-setup/)
zawiera wiele informacji szczegółowych o instalacji Node.js i npm, a
także pakietu @wordpress/scripts, który zawiera zalecaną konfigurację
domyślną dla pakietów webpack i Babel.

React

Dokładne omówienie frameworka React przedstawiliśmy w rozdziale 9.
Przypominamy, że jest to biblioteka JavaScript przeznaczona do tworzenia
interaktywnych interfejsów użytkownika, które są intensywnie używane w
edytorze bloków. Blok WordPressa można uznać za kolekcję komponentów
interfejsu użytkownika w React, zaprojektowanych do działania w
charakterze edytora lub do nadawania stylu. WordPress ma własną
bibliotekę komponentów React przeznaczonych do tworzenia bloków. Można
je łączyć z innymi komponentami React lub z opracowanymi samodzielnie.
Eksperymentowanie z frameworkiem React poza kontekstem tworzenia bloków
Gutenberg pomoże Ci w ogólnym jego poznaniu. Gdy pojawią się problemy
związane z tworzeniem bloków WordPressa, będziesz miał większą wiedzę i
łatwiej ustalisz źródło tych problemów, co pomoże podczas szukania
pomocy. Jeżeli chciałbyś dowiedzieć się więcej na temat frameworka
React, zajrzyj do książki Learning React autorstwa Aleksa Banksa i Eve
Porcello. Dobrze jest również wykonać oficjalny samouczek zamieszczony w
witrynie internetowej frameworka React
(https://reactjs.org/tutorial/tutorial.html). Użyteczne są też pozostałe
przykłady, które znajdziesz w tej witrynie
(https://reactjs.org/community/examples.html).

[1] Pełną listę skrótów formatowania oraz innych użytecznych skrótów
znajdziesz w witrynie WordPressa na stronie
https://wordpress.org/support/article/keyboard-shortcuts/#formatting-shortcuts.

Rozdział 12. Sieć witryn internetowych WordPressa

Wraz z wydaniem WordPressa 3.0 pojawiła się możliwość tworzenia sieci
witryn internetowych WordPressa za pomocą funkcjonalności nazywanej
WordPress Multisite. W wersjach WordPressa poprzedzajacych wersję 3.0
projekt sieci witryn internetowych WordPressa nosił nazwę WPMU
(WordPress Multiuser) i był oddzielnym projektem typu open source. Skoro
WordPress i WPMU współdzieliły większość tego samego kodu, sensowne
okazało się ich połączenie w jeden projekt. Dzięki sieci witryn
internetowych administrator WordPressa zyskuje możliwość utworzenia
własnej sieci, na którą składa się wiele witryn. Wszystkie witryny
takiej sieci współdzielą tę samą bazę danych i pliki kodu źródłowego.
Podczas tworzenia sieci witryn następuje utworzenie nowych tabel w bazie
danych dla każdej nowej witryny internetowej będącej częścią sieci.

Dlaczego sieć witryn internetowych

Jeżeli korzystasz z więcej niż jednej instalacji WordPressa, a w
szczególności gdy są to bardzo podobne witryny internetowe, powinieneś
rozważyć wykorzystanie funkcjonalności Multisite (sieci witryn),
ponieważ w ten sposób będziesz mógł zaoszczędzić cenny czas i/lub
pieniądze. Wyobraź sobie uaktualnienie wszystkich instalacji WordPressa
jednocześnie zamiast robić to po kolei. Oto wybrane korzyści, jakie daje
utworzenie sieci witryn internetowych (zobacz rysunek 12.1):

-   Współdzielenie przez wiele witryn internetowych tego samego zestawu
    wtyczek, motywów i niestandardowego kodu.
-   Zarządzanie wszystkimi użytkownikami sieci w jednym miejscu.
-   Dostęp do wszystkich witryn internetowych za pomocą jednego konta z
    uprawnieniami administratora.
-   Uaktualnianie WordPressa oraz zainstalowanych wtyczek i motywów
    jednocześnie, w jednym miejscu, bez konieczności zajmowania się tym
    w wielu witrynach internetowych.
-   Łatwe wdrażanie nowej witryny internetowej za pomocą kilku kliknięć,
    zamiast tworzenia nowej instalacji zupełnie od początku.
-   Jeżeli używasz frameworka motywu potomnego dla wszystkich witryn w
    sieci, uaktualnienia wszystkich motywów możesz przeprowadzić
    jednocześnie, wykorzystując dostępne we frameworku zaczepy.
-   Umożliwienie użytkownikom konfigurowania i zarządzania witrynami
    internetowymi w sieci. Administrator w jednej witrynie sieci może
    pełnić zupełnie odmienną rolę w innej.

[]

Rysunek 12.1. Sieć składająca się z wielu witryn internetowych kontra
oddzielne witryny internetowe

Oto kilka przykładów przedstawiających sytuacje, w których warto tworzyć
sieć witryn internetowych.

-   Potrzebujesz sieci podobnych witryn internetowych. W każdej z nich
    administrator zajmuje się zarządzaniem treści udostępnianej w danej
    witrynie. Przyjmujemy założenie, że chcesz utworzyć sieć szkolnych
    witryn internetowych dla wybranego kuratorium. W takiej sieci
    poszczególne szkoły mają własne witryny internetowe oferujące
    praktycznie takie same funkcje. Administrator każdej z nich musi się
    zajmować uaktualnieniami brandingu za pomocą ustawień motywu i
    uaktualnień treści.
-   Chcesz mieć jedną witrynę internetową, ale w wielu językach,
    obsługiwaną przez różne osoby, a nie ufasz wtyczce WPML (WordPress
    Multilingual Plugin).
-   Musisz skonfigurować setki powiązanych ze sobą witryn internetowych,
    którymi chcesz łatwo zarządzać i do których chcesz dodawać nowe
    funkcjonalności.

Dlaczego nie należy korzystać z sieci witryn

Wprawdzie istnieje wiele powodów, dla których warto używać sieci witryn
internetowych WordPressa, ale są też sytuacje, w których należy unikać
takiego rozwiązania. W przypadku wybranych projektów zarządzanie
wszystkimi użytkownikami w tej samej sieci może być dezorientujące, a
nawet może rodzić problemy natury prawnej. Istnieje ryzyko, że w pewnych
projektach zajdzie potrzeba uruchamiania odmiennych wersji określonych
motywów, wtyczek lub nawet samej platformy WordPressa.

Gdy używana jest sieć witryn internetowych problemy mogą powodować
wtyczki opracowane przez podmioty zewnętrzne. Wprawdzie większość z nich
działa bezproblemowo w takiej konfiguracji, ale niestety niektóre nie
działają zgodnie z oczekiwaniami. Przykładowo wtyczka modyfikująca
wyświetlany administratorowi ekran dodawania nowego użytkownika może nie
uwzględniać faktu, że ten ekran będzie inny w przypadku sieci witryn.
Ewentualnie wtyczka może przechowywać dane w sieci, gdy Ty chcesz
korzystać z niej w określonych blogach. Warto podkreślić ponownie, że
większość wtyczek nie sprawia problemów. Jednak możesz napotkać taką,
która będzie wymagała poprawienia, zastąpienia inną lub zmodyfikowania,
aby mogła działać w określonej sieci witryn internetowych WordPressa.

Ogólnie rzecz biorąc, nie powinieneś uaktualniać instalacji WordPressa
do sieci witryn internetowych WordPressa, o ile naprawdę nie
potrzebujesz takiej sieci. Jeżeli chcesz korzystać z wielu witryn
internetowych, rozważ wady i zalety ich hostingu w tej samej sieci
WordPressa.

Alternatywy dla sieci witryn

Oto kilka alternatyw, które warto rozważyć przed użyciem sieci wielu
witryn WordPressa.

Wielu autorów lub kategorii w tej samej witrynie WordPressa

Jeżeli jesteś zainteresowany przede wszystkim organizacją treści w
oddzielnych witrynach lub sekcjach, zastanów się nad możliwością
zdefiniowania wielu autorów bloga lub kategorii w jednej witrynie
WordPressa. Jeżeli masz wielu autorów w tej samej witrynie internetowej,
możesz uaktualnić motyw w taki sposób, aby archiwum postów każdego z
autorów wyglądało jak oddzielna witryna internetowa.

Jeżeli chciałbyś publikować jakąś treść w oddzielnym blogu, zawsze
możesz utworzyć kategorię posta dla tej treści. Następnie za pomocą
filtrów można zdefiniować warunek, aby ta treść nie została umieszczona
w indeksie głównym. Kolejnym krokiem jest utworzenie łącza do widoku
archiwum dla tej kategorii posta i zdefiniowanie mu oddzielnego stylu
przypominającego blog w większej witrynie internetowej.

Niestandardowe typy postów

Następnym sposobem na organizację treści w celu nadania stylu
wskazującego na „oddzielną witrynę internetową”, ale bez konieczności
rzeczywistego tworzenia oddzielnej witryny, jest użycie niestandardowego
typu postów. Podobnie jak w przypadku używania oddzielnych kategorii
posta, można filtrować indeks główny i wykluczyć pewne niestandardowe
typy postów oraz traktować widok archiwum określonych CPT jako oddzielną
witrynę internetową

Oddzielne witryny internetowe

Jeżeli próbujesz współdzielić treść między kilkoma witrynami
internetowymi lub zmusić kilka witryn do ściślejszego działania, możesz
rozważyć umieszczenie ich w tej samej sieci witryn WordPressa.
Alternatywne rozwiązanie polega na zachowaniu całkowicie oddzielnych
witryn internetowych oraz wykorzystaniu API REST lub narzędzia takiego
jak opracowana przez nas wtyczka SSO (WordPress Single Sign-On) do
współdzielenia treści i użytkowników między tymi witrynami internetowymi
(więcej informacji na ten temat przedstawiliśmy w rozdziale 10.).

Używanie usługi konserwacji WordPressa

Jeżeli jesteś podekscytowany możliwością uaktualniania wtyczek i motywów
WordPressa w jednym miejscu, rozważ wykorzystanie usługi konserwacji
WordPressa. Istnieje wiele popularnych rozwiązań w tej kategorii.
Aplikacje, wtyczki i usługi pozwalające na zarządzanie wieloma witrynami
internetowymi WordPressa i uaktualnianie ich za pomocą pojedynczego
panelu głównego:

-   Calypso (https://github.com/Automattic/wp-calypso)
-   WordPress Website Management Dashboard (https://managewp.com/)
-   WordPress Management for Professionals (https://mainwp.com/)
-   InfiniteWP (https://infinitewp.com/).

Interfejs powłoki dla WordPressa, The WordPress Command Line Interface
(https://wp-cli.org/), również można wykorzystać do jednoczesnego
uaktualniania wielu witryn internetowych zbudowanych na podstawie
WordPressa. Więcej informacji na temat znajdziesz w artykule autorstwa
Phila Banka opublikowanym na stronie
https://bnks.xyz/managing-multiple-wordpress-installs-with-bash-and-wp-cli/.

Wielodostępność

Jeżeli lubisz koncepcję współdzielonego repozytorium dla WordPressa oraz
plików jego motywów i wtyczek, ale jednocześnie nie chcesz architektury
współdzielonej bazy danych sieci witryn WordPressa, powinieneś
zainteresować się rozwiązaniami w zakresie wielodostępności. Z
uproszczonym widokiem wielodostępności w WordPressie mamy do czynienia
na przykład po utworzeniu dowiązania symbolicznego do podstawowego
katalogu WordPressa i współdzielenia znajdujących się tam plików z
kilkoma instalacjami WordPressa w tym samym serwerze lub klastrze
serwerów. W praktyce taka konfiguracja wymaga nieco pracy z Twojej
strony. Dobrym miejscem na rozpoczęcie poznawania tematu
współdostępności WordPressa są przygotowane przez Cliffa Seala klipy
wideo zamieszczone w serwisie WordPress.tv na stronie
https://wordpress.tv/2016/02/12/cliff-seal-introducing-wordpress-multitenancy/.

Przygotowanie sieci witryn

Po ustaleniu, że sieć witryn internetowych to rozwiązanie, które
chciałbyś zastosować, konieczne jest jego przygotowanie. Wprawdzie nie
jest to łatwa operacja ograniczająca się do włączenia odpowiedniej
funkcjonalności w ustawieniach WordPressa, ale mimo wszystko nadal mamy
do czynienia z dość prostym procesem. Przede wszystkim, jeśli nie jest
konfigurowana zupełnie nowa instalacja WordPressa, konieczne jest
wykonanie kopii zapasowej bazy danych i katalogu plików.

Otwórz plik wp-config.php w katalogu głównym WordPressa, a następnie
dodaj przedstawione tutaj polecenie po wierszu /* That’s all, stop
editing! Happy blogging. */ (/* To wszystko, nie edytuj dalej!
Szczęśliwego publikowania. */):

    define( 'WP_ALLOW_MULTISITE', true );

Odśwież administracyjny panel główny WordPressa i umieść kursor myszy
nad opcją menu Narzędzia (Tools). W wyświetlonym podmenu kliknij opcję
Uruchamianie sieci witryn (Network Setup). Na wyświetlonej stronie
konfiguracyjnej znajduje się kilka pól formularza, w których trzeba
wprowadzić określone informacje.

Instalacja poddomenowa lub podkatalogowa (Subdomain or Subdirectory)

W jaki sposób chcesz przygotować podwitryny internetowe w budowanej
sieci? Jeżeli to mają być poddomeny w stylu poddomena.domena.pl, wybierz
opcję subdomain. Natomiast jeśli chcesz użyć stylu domena.pl/poddomena,
wybierz opcję subdirectory. Zawsze możesz skorzystać z wtyczki mapowania
domeny, aby zapewnić mapowanie dowolnych domen niezależnie od
zastosowanego w tym miejscu rozwiązania: poddomeny lub podkatalogu.

Nazwa sieci witryn (Network title)

Nazwa sieci składającej się z wielu witryn internetowych.

Adres e-mail administratora sieci witryn (Admin email address)

Adres e-mail administratora sieci witryn, czyli prawdopodobnie Twój.

Po podaniu wymaganych informacji należy kliknąć przycisk Zainstaluj
(Install).

Powinieneś teraz zobaczyć dwa pola tekstowe. Pierwsze zawiera kod, który
trzeba skopiować i wkleić do pliku wp-config.php tuż po dodanym przed
chwilą poleceniu.

    define( 'MULTISITE', true );

    define( 'SUBDOMAIN_INSTALL', false );

    define( 'DOMAIN_CURRENT_SITE', 'whatever.com' );

    define( 'PATH_CURRENT_SITE', '/' );

    define( 'SITE_ID_CURRENT_SITE', 1 );

    define( 'BLOG_ID_CURRENT_SITE', 1 );

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Kiedy mówimy o sieci witryn internetowych WordPressa, mamy na myśli jedną sieć zawierającą wiele podwitryn internetowych. Termin blog nie jest już stosowany w wielu kontekstach, choć nadal pojawia się w funkcjach i tabelach bazy danych związanych z siecią witryn. Sieć jest identyfikowana przez wartość site_id, natomiast podwitryna jest identyfikowana przez wartość blog_id. Używanie wyrażenia podwitryna internetowa podczas odwoływania się do witryn w sieci pomaga uniknąć dezorientacji. Trzeba jednak przywyknąć do ustalenia, do jakiego rodzaju witryny odwołuje się dany fragment kodu lub dokumentacji.
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

W omawianym przykładzie zdecydowaliśmy się na użycie podkatalogów, więc
wartością SUBDOMAIN_INSTALL jest false. Jeśli wybralibyśmy subdomeny,
wartością SUBDOMAIN_INSTALL powinno być true.

Drugie pole tekstowe zawiera kod przeznaczony do skopiowania i wklejenia
w pliku .htaccess, który powinien znajdować się w katalogu głównym
instalacji WordPressa.

    RewriteEngine On

    RewriteBase /

    RewriteRule ^index\.php$ - [L]

    # Dodanie ukośnika na końcu adresu /wp-admin

    RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]

    RewriteCond %{REQUEST_FILENAME} -f [OR]

    RewriteCond %{REQUEST_FILENAME} -d

    RewriteRule ^ - [L]

    RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]

    RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]

    RewriteRule . index.php [L]

  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeśli masz zmodyfikowany plik .htaccess (np. ze względu na hosting lub inne potrzeby), upewnij się, że zostały zastąpione jedynie domyślne reguły dodane przez WordPressa. Zwróć również uwagę na to, że w zależności od wybranego rozwiązania (poddomeny lub podkatalogi) otrzymasz nieco inny zestaw reguł nadpisujących domyślne.
  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Po skopiowaniu kodu z wymienionych pól tekstowych, wklejeniu go w
odpowiednich plikach i zapisaniu w serwerze WWW można odświeżyć
przeglądarkę WWW.

Teraz konieczne będzie ponowne zalogowanie się. W formularzu podaj nazwę
użytkownika i hasło konta administratora. Bum! W tym momencie masz sieć
witryn internetowych WordPressa, jesteś zalogowany jako
superadministrator i otrzymałeś pełny dostęp do wszystkich witryn sieci
(zwykły administrator ma pełny dostęp jedynie do witryn, których
administracją się zajmuje). Zachowaj dużą ostrożność co do tego, komu
udzielasz uprawnień superadministratora.

Jeżeli zdecydowałeś się na użycie poddomen zamiast podkatalogów,
powinieneś jeszcze wykonać kilka kroków, dzięki którym możesz
zaoszczędzić sporo czasu. Przede wszystkim należy zdefiniować rekord
wieloznaczny na stronie ustawień DNS Twojego rejestratora domeny. Czy
pamiętasz, jak podczas pierwszej instalacji WordPressa przypisałeś
rekordowi A (Host) adres IP Twojego konta usługi hostingu? Dokładnie w
tym samym miejscu powinieneś mieć możliwość dodania nazwy hosta *
zamiast @ i wskazania tego samego adresu IP, który wcześniej podałeś dla
rekordu @. Tak przygotowane rozwiązanie powoduje przechwytywanie wywołań
wszystkich poddomen w domenie głównej. Innymi słowy,
dowolna-poddomena.domena.pl lub inna-poddomena.domena.pl będą mapowane
na ten sam adres IP w domenie głównej.

W zależności od konta w usłudze hostingu być może konieczne okaże się
skonfigurowanie takiego samego elementu wieloznacznego poddomeny dla
katalogu wskazywanego przez domenę główną. Dlatego zarejestruj nową
poddomenę w stylu *.<cokolwiek>.pl i wskaż jej ten sam katalog, do
którego prowadzi <cokolwiek>.pl.

Dlaczego to wszystko robimy? Skonfigurowaliśmy element wieloznaczny dla
poddomen, więc po utworzeniu nowych witryn internetowych w sieci
WordPressa będą one działały automatycznie. Jeżeli nie
przeprowadzilibyśmy takiej konfiguracji, konieczne byłoby ręczne
dodawanie każdej nowo utworzonej poddomeny do rejestratora domeny i
hosta. Natomiast pod jednokrotnym skonfigurowaniu elementu
wieloznacznego poddomeny automatycznie działa on dla każdej witryny
internetowej poddomeny utworzonej w sieci WordPressa.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   W zależności od hosta nadal może istnieć konieczność ręcznego przeprowadzania pewnych ustawień po stronie serwera. Jeżeli używasz cPanel i chcesz wskazać domenę w instalacji sieci witryn WordPressa, wybierz opcję Dodaj domenę (Add on domain) i upewnij się o podaniu wartości prowadzącej do katalogu głównego instalacji sieci witryn WordPressa.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Zarządzanie siecią witryn WordPressa

Z paska menu administracyjnego WordPressa wybierz opcję Moje
witryny/Administracja siecią witryn (My Sites/Network Administrator),
aby w ten sposób móc administrować nową siecią witryn WordPressa. Jeżeli
chcesz dostać się do panelu głównego sieci, możesz przejść pod adres
<cokolwiek> .pl/wp-admin/network/. Panel administracyjny ustawień
sieciowych jest podobny do innych paneli administracyjnych w sieci
WordPressa. Aby ułatwić sobie ustalenie bieżącego położenia, szukaj
/network/ na końcu paska adresu w przeglądarce WWW, ponieważ w
przeciwnym razie możesz łatwo się zgubić.

Panel główny

Panel główny ustawień sieci jest bardzo podobny do domyślnego panelu
głównego, z którego korzystasz w standardowej instalacji WordPressa.
Wyjątkiem jest tylko widżet Right Now wyświetlający łącza pozwalające na
szybkie dodawanie do sieci nowych witryn internetowych lub użytkowników.
W panelu znajdują się również dwa pola tekstowe przeznaczone do
wyszukiwania określonych użytkowników lub witryn. Podobnie jak w
przypadku panelu głównego zwykłej instalacji WordPressa, także panel
główny ustawień sieci można całkowicie dostosować do własnych potrzeb za
pomocą wtyczek i samodzielnie utworzonego kodu.

Witryny internetowe

Panel witryn internetowych pozwala na zarządzanie wszystkimi witrynami
tworzącymi sieć. Możesz dodawać dowolną liczbę witryn internetowych, a
nawet udzielać użytkownikom sieciowym uprawnień pozwalających im na
tworzenie własnych witryn.

Dodawanie nowej witryny internetowej jest niezwykle prostym zadaniem. Na
górze strony kliknij przycisk Utwórz nową witrynę (Add New) lub z
podmenu Witryny (Sites) wybierz opcję Dodaj nową (Add New). To spowoduje
przejście na stronę Dodaj nową witrynę (Add New Site), na której
znajdują się wymienione tutaj pola tekstowe.

Adres witryny (Site address)

W zależności od sposobu konfiguracji sieci w tym miejscu należy podać
adres poddomeny lub podkatalogu.

Tytuł witryny (Site title)

To jest nazwa nowej witryny internetowej.

Email administratora (Administrator email)

Adres e-mail administratora nowej witryny internetowej. To nie musi być
Twój adres e-mail, a na przykład klienta lub użytkownika, dla którego
konfigurujesz nową witrynę internetową WordPressa.

Kliknij przycisk Dodaj witrynę (Add Site) i gotowe — natychmiast
otrzymasz nową witrynę internetową WordPressa. W ten sposób można
zaoszczędzić sporo czasu w porównaniu do tradycyjnej procedury
konfiguracji nowej instalacji WordPressa.

Użytkownicy

Wszystkie witryny internetowe tworzone w sieci będą korzystały z tej
samej puli użytkowników. Z technicznego punktu widzenia informacje o
wszystkich użytkownikach są przechowywane w tabeli wp_users, a dla
każdego z nich są zdefiniowane metadane pozwalające na powiązanie
użytkownika z jedną lub więcej witryn w sieci. Na stronie konfiguracji
użytkowników sieci można zarządzać wszystkimi użytkownikami, utworzyć
superadministratora z uprawnieniami pozwalającymi na zarządzanie całą
siecią WordPressa, a także sprawdzić, których witryn internetowych dany
użytkownik jest członkiem.

Aby dostać się na stronę Dodaj nowego użytkownika (Add New User), na
górze strony Użytkownicy (Users) należy kliknąć przycisk Dodaj nowego
(Add New) bądź z podmenu Użytkownicy (Users) wybrać łącze Dodaj nowego
(Add New). Na stronie Dodaj nowego użytkownika (Add New User) znajdują
się następujące pola tekstowe.

Nazwa użytkownika (Username)

Nazwa nowo tworzonego użytkownika. Pamiętaj o użyciu jedynie małych
liter, nieużywaniu spacji i znaków specjalnych.

Email

Adres e-mail dla nowo tworzonego użytkownika.

Po kliknięciu przycisku Dodaj użytkownika (Add User) dodany użytkownik
otrzyma wiadomość e-mail zawierającą nazwę użytkownika i hasło
pozwalające na zalogowanie się do domyślnej witryny internetowej
najwyższego poziomu z domyślną rolą przypisaną temu użytkownikowi.
Dodawanie użytkowników w ten sposób może nie być idealnym rozwiązaniem,
ponieważ trzeba wykonać jeszcze jeden krok związany z dodaniem danego
użytkownika do podwitryn sieci. W zależności od sytuacji łatwiejszym
rozwiązaniem może być bezpośrednie dodawanie nowych użytkowników do
podwitryny, co odbywa się w taki sam sposób, jak w przypadku tradycyjnej
instalacji WordPressa. Jeżeli spróbujesz dodać użytkownika do witryny, w
której podana nazwa użytkownika już istnieje, otrzymasz odpowiedni
komunikat. Na tym etapie możesz dodać użytkownika do witryny przez
dołączenie jego nazwy do sekcji Dodaj użytkownika (Add Existing User) i
wskazanie jego roli, a także określenie, czy użytkownikowi ma zostać
wysłana wiadomość e-mail z potwierdzeniem jego dodania.

Motywy

Wszystkie motywy są dostępne w katalogu /wp-content/themes. Masz
możliwość kontrolowania wszystkich motywów, które mogą być używane w
witrynach internetowych Twojej sieci. Konieczne jest włączenie motywu
dla całej sieci, zanim będzie mógł zostać użyty. Jeżeli tego nie
zrobisz, motyw nie zostanie nawet wyświetlony jako możliwy do
aktywowania na stronie Wygląd/Motywy (Appearance/Themes) witryny.

Wtyczki

Wszystkie wtyczki znajdują się w katalogu /wp-content/plugins. Możesz je
aktywować na poziomie sieci, aby automatycznie działały we wszystkich
witrynach internetowych Twojej sieci, także w tych nowych. Aktywowane na
poziomie sieci wtyczki nie będą wyświetlane na stronach wtyczek
poszczególnych witryn. Tak naprawę, jeśli wyraźnie nie włączysz menu
wtyczek na stronie ustawień sieci (odpowiednie informacje o tym
przedstawiamy w następnej sekcji), administratorzy poszczególnych witryn
internetowych w sieci w ogóle nie będą widzieli strony wtyczek.

Jeżeli zezwolisz administratorom poszczególnych witryn internetowych na
zarządzanie własnymi wtyczkami, będą mogli aktywować tylko te, które są
już zainstalowane. Nie będą mogli instalować innych wtyczek. Jest to
dobre rozwiązanie, ponieważ na pewno chcesz wiedzieć, które wtyczki będą
dostępne dla wszystkich witryn internetowych w Twojej sieci. Nie chcesz
zezwalać administratorom poszczególnych witryn na instalowanie dowolnych
wtyczek lub wtyczek opracowanych samodzielnie, ponieważ mogłyby mieć
negatywny wpływ na inne witryny internetowe sieci.

W celu dodania nowej wtyczki na poziomie sieci trzeba skorzystać z tej
samej procedury, która jest stosowana w tradycyjnej instalacji
WordPressa.

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Nie wszystkie wtyczki powinny być aktywowane na poziomie sieci. Zajrzyj do dokumentacji danej wtyczki, zanim zdecydujesz, czy można ją włączyć na poziomie sieci, czy powinna być aktywowana oddzielnie na każdej witrynie internetowej. Ogólnie rzecz biorąc, jeżeli wtyczka jest potrzebna tylko w pewnej części sieci i musi obsługiwać dane lub niestandardowe typy postów oddzielnie w danej witrynie, powinna być aktywowana oddzielnie na każdej wymagającej tego witrynie internetowej.
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Ustawienia

Te ustawienia są nieco inne niż typowe ustawienia WordPressa, z których
korzystasz w standardowej witrynie internetowej WordPressa. Tutaj mamy
do czynienia z ustawieniami na poziomie sieci.

Jeżeli klikniesz łącze Ustawienia (Settings) w administracyjnym menu
nawigacyjnym wyświetlonym po lewej stronie, powinieneś zobaczyć
wymienione tutaj opcje.

Ustawienia operacyjne (Operational settings)

-   Nazwa sieci witryn (Network name)
-   Adres email administratora sieci witryn (Network administrator
    email)

Ustawienia rejestracji (Registration settings)

-   Możliwość rejestracji (Allow new registrations)
-   Powiadomienie o rejestracji (Registration notification)
-   Dodawanie nowych użytkowników (Add new users)
-   Zablokowane nazwy (Banned names )
-   Dozwolone domeny adresów email (Limited email registrations)
-   Zablokowane domeny adresów email (Banned email domains)

Ustawienia dot. nowych witryn (New site settings)

-   Email witający administratora witryny (Welcome email)
-   Email witający użytkownika (Welcome user email)
-   Pierwszy wpis (First post)
-   Pierwsza strona (First page)
-   Autor pierwszego komentarza (First comment author)
-   URL autora pierwszego komentarza (First comment URL)

Ustawienia dot. wysyłania na serwer (Upload settings)

-   Przydzielona przestrzeń dyskowa (Site upload space)
-   Dozwolone typy plików (Upload file types)
-   Maksymalny dopuszczalny rozmiar pliku (Max upload file size)

Ustawienia menu (Menu settings)

-   Włącz administracyjne menu (Enable administration menus)

Uaktualnienia

Podobnie jak w przypadku standardowej instalacji WordPressa, istnieje
możliwość uaktualnienia frameworka, a także nieaktualnych wtyczek i/lub
motywów za pomocą omawianej strony. Piękno sieci witryn internetowych
polega na możliwości ich jednoczesnego uaktualnienia. To jest znacznie
efektywniejsze rozwiązanie niż inicjowanie operacji uaktualnienia
oddzielnie w każdej instalacji WordPressa. Wystarczy na omawianej tutaj
stronie uaktualnić WordPressa, wtyczki oraz motywy… i na tym koniec!

Struktura bazy danych sieci witryn

Wszystkie witryny internetowe sieci współdzielą tę samą bazę danych.
Utworzenie sieci witryn powoduje dodanie kilku tabel do istniejącej bazy
danych.

Tabele o zasięgu sieci

wp_site

Tabela wp_site przechowuje informacje podstawowe dla sieci witryn
internetowych, takie jak identyfikator, nazwa domeny i ścieżka dostępu.
Ta tabela zwykle zawiera jeden rekord (zobacz tabela 12.1).

Tabela 12.1. Schemat tabeli wp_site bazy danych WordPressa

  --------- -------------- ------------------ -------------- ------------------ ----------------------
  Kolumna   Typ            Kodowanie znaków   Wartość null   Wartość domyślna   Informacje dodatkowe
  id        bigint(20)                        Nie            Brak               AUTO_INCREMENT
  domain    varchar(200)   utf8_general_ci    Nie                               
  path      varchar(100)   utf8_general_ci    Nie                               
  --------- -------------- ------------------ -------------- ------------------ ----------------------

wp_sitemeta

Tabela wp_sitemeta przechowuje wszystkie opcje i ustawienia dotyczące
sieci witryn (zobacz tabela 12.2).

Tabela 12.2. Schemat tabeli wp_sitemeta bazy danych WordPressa

  ------------ -------------- ------------------ -------------- ------------------ ----------------------
  Kolumna      Typ            Kodowanie znaków   Wartość null   Wartość domyślna   Informacje dodatkowe
  meta_id      bigint(20)                        Nie            Brak               AUTO_INCREMENT
  site_id      bigint(20)                        Nie            0                  
  meta_key     varchar(255)   utf8_general_ci    Tak            NULL               
  meta_value   longtext       utf8_general_ci    Tak            NULL               
  ------------ -------------- ------------------ -------------- ------------------ ----------------------

wp_blogs

Tabela wp_blogs zawiera informacje o poszczególnych witrynach
internetowych utworzonych w ramach sieci (zobacz tabela 12.3).

Tabela 12.3. Schemat tabeli wp_blogs bazy danych WordPressa

  -------------- ---------------- ------------------ -------------- --------------------- ----------------------
  Kolumna        Typ              Kodowanie znaków   Wartość null   Wartość domyślna      Informacje dodatkowe
  blog_id        bigint(20)                          Nie            Brak                  AUTO_INCREMENT
  site_id        bigint(20)                          Nie            0                     
  domain         varchar(200)     utf8_general_ci    Nie                                  
  path           varchar(100)     utf8_general_ci    Nie                                  
  registered     datetime                            Nie            0000-00-00 00:00:00   
  last_updated   datetime                            Nie            0000-00-00 00:00:00   
  public         tinyint(2)                          Nie            1                     
  archived       enum('0', '1')   utf8_general_ci    Nie            0                     
  mature         tinyint(2)                          Nie            0                     
  spam           tinyint(2)                          Nie            0                     
  deleted        tinyint(2)                          Nie                                  
  lang_id        int(11)                             Nie            0                     
  -------------- ---------------- ------------------ -------------- --------------------- ----------------------

wp_blog_versions

Tabela wp_blog_versions zawiera informacje o tym, który schemat bazy
danych jest używany w poszczególnych witrynach (zobacz tabela 12.4).

Tabela 12.4. Schemat tabeli wp_blog_versions bazy danych WordPressa

  -------------- ------------- ------------------ -------------- --------------------- ----------------------
  Kolumna        Typ           Kodowanie znaków   Wartość null   Wartość domyślna      Informacje dodatkowe
  blog_id        bigint(20)                       Nie            0                     
  db_version     varchar(20)   utf8_general_ci    Nie                                  
  last_updated   datetime                         Nie            0000-00-00 00:00:00   
  -------------- ------------- ------------------ -------------- --------------------- ----------------------

wp_signups

W tabeli wp_signups są przechowywane informacje o poszczególnych
użytkownikach zarejestrowanych w sieci (zobacz tabela 12.5).

Tabela 12.5. Schemat tabeli wp_signups bazy danych WordPressa

  ---------------- -------------- ------------------ -------------- --------------------- ----------------------
  Kolumna          Typ            Kodowanie znaków   Wartość null   Wartość domyślna      Informacje dodatkowe
  domain           varchar(200)   utf8_general_ci    Nie                                  
  path             varchar(100)   utf8_general_ci    Nie                                  
  title            longtext       utf8_general_ci    Brak                                 
  user_login       varchar(60)    utf8_general_ci    Nie                                  
  user_email       varchar(100)   utf8_general_ci    Nie                                  
  registered       datetime                          Nie            0000-00-00 00:00:00   
  activated        datetime                          Nie            0000-00-00 00:00:00   
  active           tinyint(1)                        Nie            0                     
  activation_key   varchar(50)    utf8_general_ci    Nie                                  
  meta             longtext       utf8_general_ci    Tak            NULL                  
  ---------------- -------------- ------------------ -------------- --------------------- ----------------------

wp_registration_log

Tabela wp_registration_log przechowuje informacje o poszczególnych
użytkownikach zarejestrowanych w sieci. Znajdujące się w tej tabeli
informacje to m.in.: identyfikator użytkownika, jego adres e-mail i
identyfikator bloga (zobacz tabela 12.6).

Tabela 12.6. Schemat tabeli wp_registration_log bazy danych WordPressa

  ----------------- -------------- ------------------ -------------- --------------------- ----------------------
  Kolumna           Typ            Kodowanie znaków   Wartość null   Wartość domyślna      Informacje dodatkowe
  ID                bigint(20)                        Nie            Brak                  AUTO_INCREMENT
  email             varchar(255)   utf8_general_ci    Nie                                  
  IP                varchar(30)    utf8_general_ci    Nie                                  
  blog_id           bigint(20)                        Nie            0                     
  date_registered   datetime                          Nie            0000-00-00 00:00:00   
  ----------------- -------------- ------------------ -------------- --------------------- ----------------------

Tabele poszczególnych witryn

Każda witryna internetowa dodawana do sieci w trakcie operacji tworzenia
automatycznie otrzymuje identyfikator blog_id. Dla każdej witryny są
tworzone tabele, w nazwie których również jest umieszczany wspomniany
identyfikator blog_id. Przyjmujemy założenie o utworzeniu pierwszej
dodatkowej witryny internetowej sieci poza istniejącą w niej domyślną
witryną. Otrzyma ona identyfikator blog_id o wartości 2, w bazie danych
natomiast zostaną utworzone wymienione tutaj tabele:

-   wp_$blog_id_options
-   wp_$blog_id_posts
-   wp_$blog_id_postmeta
-   wp_$blog_id_comments
-   wp_$blog_id_commentsmeta
-   wp_$blog_id_links
-   wp_$blog_id_term_taxonomy
-   wp_$blog_id_terms
-   wp_$blog_id_term_relationships.

Łatwo zauważyć, że są to tabele analogiczne do tych znajdujących się w
standardowej instalacji WordPressa. Różnią się jedynie nazwami, które
tutaj zawierają wartość identyfikatora blog_id. Dla każdej nowej witryny
internetowej tworzonej w sieci powstaną również te tabele, przy czym
wartość blog_id będzie inna dla poszczególnych witryn.

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   W WordPressie 3.5 z panelu administracyjnego usunięto interfejs użytkownika dla łączy, ale tabele bazy danych pozostały w celu zapewnienia wstecznej zgodności. Jeżeli potrzebujesz funkcjonalności łączy, możesz skorzystać z wtyczki Link Manager (https://wordpress.org/plugins/link-manager/).
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Współdzielone tabele witryny internetowej

Wszyscy użytkownicy sieci witryn internetowych współdzielą te same
tabele wp_users i wp_usermeta.

Użytkownicy są powiązani z różnymi witrynami internetowymi sieci za
pomocą kilku kluczy meta w tabeli wp_usermeta. Jeżeli dodasz nowego
użytkownika do drugiej witryny internetowej sieci, zostaną utworzone
następujące klucze meta:

-   primary_blog
-   wp_2_capabilities
-   wp_2_user_level.

Użytkownik może mieć tylko jeden klucz primary_blog, choć jednocześnie
za pomocą kluczy meta wp_2_capabilities i wp_2_user_level może być
powiązany z wieloma witrynami internetowymi. W domyślnej instalacji
WordPressa i najwyższego poziomu witrynie internetowej sieci klucze meta
są przechowywane jako wp_capabilities i wp_user_level. Podczas dodawania
użytkowników do witryn internetowych sieci dla każdego użytkownika
mającego przypisaną wartość blog_id tworzone są nowe rekordy kluczy meta
z informacjami o roli, którą pełni.

Mapowanie domeny

Domyślnie każda podwitryna internetowa w sieci WordPressa będzie używała
witryny najwyższego poziomu jako poddomeny lub podkatalogu, o ile
wyraźnie nie nakażesz podwitrynie użycia oddzielnej domeny.

Gdy ustawienia DNS są prawidłowe i wskazują na domenę hosta, który z
kolei ma rekord domeny prowadzący do instalacji sieci witryn
internetowych WordPressa, mapowanie domeny powinno być prostym zadaniem.

1.  Przejdź do panelu głównego sieci, a następnie kliknij menu Witryny
    (Sites).
2.  Umieść kursor myszy nad podwitryną internetową w sieci i kliknij
    przycisk Edytuj (Edit).
3.  Wartość pola Site Address (URL) zmień na nazwę domeny, której chcesz
    użyć. Upewnij się o podaniu pełnego adresu w postaci
    https://<cokolwiek>.pl. Jeżeli masz certyfikat SSL dla nowo
    mapowanej domeny, nie zapomnij o jego dodaniu i skonfigurowaniu.
4.  Kliknij przycisk Save i tym samym zapisz ustawienia strony.
    Następnie w przeglądarce WWW przejdź do nowej domeny i sprawdź, czy
    wszystko działa zgodnie z oczekiwaniami.

Jeżeli napotkasz jakiekolwiek problemy związane z mechanizmem cookies
podczas próby zalogowania się do backendu mapowanej domeny, być może
trzeba będzie uaktualnić plik wp-config.php przez dodanie następującego
wiersza po kodzie sieci witryn, który dodałeś już wcześniej.

    define('COOKIE_DOMAIN', $_SERVER['HTTP_HOST']);

Niektóre firmy oferujące usługi hostingu WordPressa, np. WP Engine,
udostępniają API pozwalające na dodawanie w sposób programowy domen do
ustawień DNS hostingu. W ten sposób można uniknąć konieczności
samodzielnego konfigurowania rekordów dodanych lub zaparkowanych domen.
Dzięki integracji sieci WordPressa z takim API Twoje zadanie sprowadza
się jedynie do dodania nowej podwitryny internetowej lub domeny w
administracyjnym panelu ustawień sieci WordPressa, a wspomniane API
zajmuje się resztą, czyli m.in. konfiguracją rekordów DNS w hoście.
Więcej informacji na temat znajdziesz w dokumentacji API WP Engine
(https://wpengineapi.com/).

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Mapowanie domeny i jej konfigurowanie za pomocą wcześniejszych wersji WordPress 4.5 wymaga użycia wtyczki zewnętrznej. W nowszych wydaniach niezbędna funkcjonalność została wbudowana w WordPressa.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Wtyczki użyteczne w sieci witryn internetowych

Jeżeli zwykła wtyczka WordPressa została utworzona prawidłowo, powinna
działać zgodnie z oczekiwaniami także na jednej lub więcej witryn w
sieci. Programiści zajmują się również opracowywaniem wtyczek specjalnie
przeznaczonych dla sieci witryn. W tym podrozdziale wymieniamy kilka
najpopularniejszych wtyczek tego rodzaju i wyjaśniamy sposób ich budowy.

Gravity Forms User Registration Add-On

Wtyczka Gravity Forms User Registration Add-On
(https://www.gravityforms.com/add-ons/user-registration/) jest
doskonałym rozwiązaniem, gdy zachodzi potrzeba umożliwienia użytkownikom
łatwego rejestrowania różnych witryn internetowych w sieci za pomocą
skrótu Gravity Forms lub umieszczonego gdzieś widżetu. Wtyczka może
zostać skonfigurowana do utworzenia nowej witryny internetowej w sieci
WordPressa, gdy użytkownik utworzy konto. Takie rozwiązanie okaże się
użyteczne, jeśli będziesz chciał wywołać operację utworzenia nowej
witryny internetowej dla nowych użytkowników dołączających do sieci.

Dodatek Member Network Sites dla wtyczki Paid Memberships Pro

Dodatek Member Network Sites dla wtyczki Paid Memberships Pro
(https://www.paidmembershipspro.
com/add-ons/pmpro-network-multisite-membership/) pozwala na pobieranie
opłat od użytkowników tworzących nowe witryny internetowe w Twojej
sieci. Więcej informacji na temat konfiguracji takiego rozwiązania
znajdziesz w rozdziale 15.

Multisite Global Media

Wtyczka Multisite Global Media
(https://github.com/bueltge/multisite-global-media) pozwala na
współdzielenie globalnej biblioteki treści multimedialnych między
witrynami internetowymi sieci. W zasadzie ta wtyczka używa biblioteki
treści multimedialnych określonej witryny internetowej, więc wszystkie
pozostałe witryny w sieci mogą uzyskać dostęp do tych samych
współdzielonych zasobów.

Multisite Plugin Manager

Jeżeli masz sieć witryn internetowych i chcesz umożliwić administratorom
witryn dostęp pozwalający na zarządzanie wybranymi wtyczkami, będzie to
bardzo łatwe dzięki wtyczce Multisite Plugin Manager
(https://wordpress.org/plugins/multisite-plugin-manager/). Jej działanie
umożliwia dostarczenie administratorowi sieci interfejsu użytkownika
pozwalającego na definiowanie ustawień domyślnych dla poszczególnych
witryn internetowych. Możliwe będzie również nadpisywanie ustawień
globalnych dla sieci. Istnieją trzy podstawowe ustawienia przeznaczone
do zarządzania wtyczkami:

-   automatyczna aktywacja,
-   kontrola użytkownika,
-   masowa aktywacja i dezaktywacja.

Multisite Robots.txt Manager

Wtyczka Multisite Robots.txt Manager
(https://wordpress.org/plugins/multisite-robotstxt-manager/) pozwala na
tworzenie własnych plików robots.txt dla poszczególnych witryn
internetowych w sieci WordPressa, a następnie na ich szybkie
publikowanie w witrynie lub w sieci. Ta wtyczka natychmiast dodaje adres
URL mapy witryny do wszystkich plików robots.txt. Ponadto potrafi
automatycznie wykrywać błędy o kodzie stanu 404 lub starsze wersje
plików robots.txt, a następnie umożliwia poprawienie znalezionych
nieścisłości.

NS Cloner — Site Copier

Wprawdzie istnieje wiele wtyczek pozwalających na kopiowanie witryn
internetowych do sieci WordPressa, ale NS Cloner — Site Copier
(https://wordpress.org/plugins/ns-cloner-site-copier/) należy do naszych
ulubionych. Ta wtyczka okazuje się niezwykle użyteczna dla każdego, kto
musi duplikować ustawienia i treść z witryny internetowej do innej
witryny w sieci. Jeżeli przygotowujesz podobne witryny internetowe,
możesz utworzyć „szablonową” witrynę internetową skonfigurowaną w
dokładnie żądany sposób (ustawienia motywów i wtyczek, a także treść
domyślna). W treści tej szablonowej witryny internetowej możesz umieścić
miejsca zarezerwowane, aby podczas operacji klonowania prowadzącej do
utworzenia nowej witryny wspomniane miejsca zarezerwowane zostały
zastąpione odpowiednimi wartościami. Dlaczego miałbyś rozpoczynać pracę
od zupełnie pustej witryny internetowej, w której wszystko trzeba
konfigurować od początku? Lepszym rozwiązaniem jest klonowanie żądanej
witryny internetowej i potraktowanie jej jako szablonu dla kolejnych.
Oszczędzasz w ten sposób czas i pieniądze!

WP Multi Network

Wtyczka WP Multi Network
(https://wordpress.org/plugins/wp-multi-network/) pozwala, aby jedna
instalacja WordPressa miała wiele sieci, każdą z własnymi podwitrynami
internetowymi. W ten sposób można utworzyć sieć sieci! Czy pamiętasz,
jak podczas aktywowania sieci WordPressa, wstawiłeś tylko jeden rekord
do tabeli wp_site? Omawiana wtyczka w zasadzie pozwala na wstawienie
kolejnych rekordów do tej tabeli i tym samym na przygotowanie następnych
podsieci z różnymi identyfikatorami site_id.

Podstawowa funkcjonalność sieci witryn WordPressa

Po aktywowaniu sieci witryn WordPressa można zacząć korzystać ze
specjalnej funkcjonalności, która została wbudowana w platformę i czeka
na użycie.

$blog_id

Po przejrzeniu tabel utworzonych po aktywowaniu sieci witryn WordPressa
wiesz, że każda witryna internetowa ma unikatowy identyfikator
przechowywany w blog_id. Ten identyfikator można wykorzystać do
wskazania WordPressowi witryny, z której mają być pobierane dane lub do
której dane mają być przekazywane.

Zmienna globalna $blog_id zostanie zdefiniowana automatycznie dla
witryny internetowej, o ile nie zmienisz tej wartości za pomocą
wywołania funkcji switch_to_blog(). Wymieniona zmienna jest użyteczna
podczas tworzenia niestandardowej funkcjonalności sieci witryn
WordPressa.

    function wds_show_blog_id(){

        global $blog_id;

        echo 'Identyfikator bieżącej witryny internetowej: ' . $blog_id;

    }

    add_action( 'init', 'wds_show_blog_id' );

Jeżeli znajdujesz się w witrynie najwyższego poziomu (lub na początkowej
witrynie) sieci WordPressa, powinieneś otrzymać wartość 1. W przypadku
witryny utworzonej jako druga w sieci wartością będzie 2 itd.

is_multisite()

Ta funkcja sprawdza, czy została utworzona sieć witryn internetowych
WordPressa. Jeżeli sieć nie została utworzona, a spróbujesz skorzystać z
funkcjonalności zdefiniowanej dla sieci, otrzymasz komunikat błędu.
Przed wykonaniem kodu przeznaczonego dla sieci witryn WordPressa zawsze
powinieneś sprawdzić, czy taka sieć została utworzona.

    function wds_run_multisite_functions(){

        if ( is_multisite() )

            echo 'Uruchom dowolną funkcjonalność sieci witryn internetowych WordPressa!';

    }

    add_action( 'init' , 'wds_run_multisite_functions' );

get_current_blog_id()

Wartością zwrotną tej funkcji jest blog_id witryny, w której aktualnie
się znajdujesz. Omawiana funkcja składa się z dwóch wierszy kodu.

    // Kod funkcji get_current_blog_id()

    function get_current_blog_id() {

        global $blog_id;

        return absint($blog_id);

    }

Omawiana funkcja została zdefiniowana w pliku wp-includes/load.php.

switch_to_blog( $new_blog )

Ta funkcja pozwala na przejście z bieżącego bloga do wskazanego. Okazuje
się użyteczna, gdy zachodzi potrzeba pobrania postów lub informacji z
innych witryn internetowych sieci WordPressa. Po wykonaniu niezbędnej
operacji, za pomocą funkcji restore_current_blog() można powrócić do
poprzedniego bloga. Automatycznie wczytywane opcje i wtyczki nie będą
uwzględniane podczas wykonywania omawianej funkcji. Akceptuje ona jeden
parametr, $new_blog, który jest wymaganą liczbą całkowitą
przedstawiającą identyfikator witryny, do której ma nastąpić przejście.

Jeżeli chcesz zmienić aktualną witrynę internetową, możesz w dowolnej
funkcji wtyczki lub motywu wykonać przedstawiony tutaj fragment kodu.

    echo 'Identyfikator bieżącej witryny internetowej: ' . get_current_blog_id() . '<br>';

    switch_to_blog(2);

    echo 'Identyfikator nowej bieżącej witryny internetowej: ' . get_current_blog_id();

Po wykonaniu ten kod powinien wygenerować następujące dane wyjściowe:

    Identyfikator bieżącej witryny internetowej: 1

    Identyfikator nowej bieżącej witryny internetowej: 2

Omawiana funkcja została zdefiniowana w pliku wp-includes/ms-blogs.php.

restore_current_blog()

Tej funkcji można użyć do przywrócenia bieżącej witryny internetowej po
wywołaniu switch_to_blog(). Omawiana funkcja nie akceptuje żadnych
parametrów.

Jeżeli chcesz przywrócić do poprzedniej witryny internetowej, możesz
skorzystać z przedstawionego tutaj fragment kodu.

    echo 'Identyfikator bieżącej witryny internetowej: ' . get_current_blog_id() . '<br>';

    switch_to_blog(2);

    echo 'Identyfikator nowej bieżącej witryny internetowej' . get_current_blog_id() . '<br>';

    restore_current_blog();

    echo 'Identyfikator pierwotnej witryny internetowej: ' . get_current_blog_id();

Oto dane wyjściowe wygenerowane przez ten kod.

    Identyfikator bieżącej witryny internetowej: 1

    Identyfikator nowej bieżącej witryny internetowej: 2

    Identyfikator pierwotnej witryny internetowej: 1

Omawiana funkcja została zdefiniowana w pliku wp-includes/ms-blogs.php.

get_blog_details( $fields = null, $get_all = true )

Ta funkcja pobiera wszystkie dostępne szczegóły dotyczące witryny
internetowej i akceptuje dwa parametry.

$fields

Identyfikator lub nazwa określonego bloga bądź tablica identyfikatorów
lub nazw blogów. Domyślnie będzie to identyfikator bieżącego bloga.

$getall

Domyślnie będzie to wartość true oznaczająca zwrot wszystkich danych w
obiekcie.

W wyniku działania funkcji zostaje zwrócony obiekt z następującymi
właściwościami:

blog_id

Identyfikator bloga, którego dotyczy wywołanie.

site_id

Identyfikator witryny, do której jest dołączony blog o danym
identyfikatorze.

domain

Nazwa domeny używanej w celu uzyskania dostępu do bloga.

path

Ścieżka dostępu używana w celu uzyskania dostępu do witryny
internetowej.

registered

Znacznik czasu określający dokładną datę i godzinę rejestracji bloga.

last_updated

Znacznik czasu określający dokładną datę i godzinę uaktualnienia bloga.

public

Wartość 1 lub 0 określająca, czy blog jest dostępny publicznie, czy nie.

archived

Wartość 1 lub 0 określająca, czy blog jest zarchiwizowany, czy nie.

mature

Wartość 1 lub 0 określająca, czy blog zawiera treści dla dorosłych, czy
nie.

spam

Wartość 1 lub 0 określająca, czy blog został oznaczony jako spam, czy
nie.

deleted

Wartość 1 lub 0 określająca, czy blog został usunięty, czy nie.

lang_id

Identyfikator języka, w którym została napisana treść bloga.

blogname

Nazwa bloga.

siteurl

Adres URL witryny internetowej, do której należy blog.

post_content

Liczba postów w blogu.

W celu wyświetlenia całego obiektu zwróconego przez funkcję
get_blog_details()należy wykonać przedstawiony tutaj fragment kodu.

    $details = get_blog_details( 1 );

    echo '<pre>';

    print_r($details);

    echo '</pre>';

    echo 'Adres URL witryny:' . $details->siteurl;

    echo 'Liczba postów:' . $details->post_count;

Wynikiem działania tego kodu powinien być obiekt podobny do tutaj
przedstawionego.

    stdClass Object

    (

        [blog_id] => 1

        [site_id] => 1

        [domain] => schoolpress.me

        [path] => /

        [registered] => 2013-03-01 00:23:26

        [last_updated] => 2013-04-01 14:18:59

        [public] => 1

        [archived] => 0

        [mature] => 0

        [spam] => 0

        [deleted] => 0

        [lang_id] => 0

        [blogname] => School Press

        [siteurl] => http://schoolpress.me

        [post_count] => 10

    )

Adres URL przykładowej witryny to http://schoolpress.me; zawiera ona 10
postów.

Omawiana funkcja została zdefiniowana w pliku wp-includes/ms-blogs.php.

update_blog_details( $blog_id, $details = array() )

Działanie tej funkcji polega na uaktualnieniu informacji szczegółowych
dotyczących bloga. Akceptuje ona dwa parametry.

$blog_id

Wymagana liczba całkowita będąca identyfikatorem bloga, który ma zostać
uaktualniony.

$details

Wymagana tablica dowolnych kolumn z tabeli bloga będących kluczami
tablicy i wartości, które mają być uaktualnione.

W celu oznaczenia określonej witryny internetowej jako usuniętej należy
użyć polecenia.

    update_blog_details( 2, array( 'deleted' => '0' ) );

Omawiana funkcja została zdefiniowana w pliku wp-includes/ms-blogs.php.

get_blog_status( $id, $pref )

Działanie tej funkcji jest podobne do get_blog_details(), z tą różnicą,
że zamiast zwrócić obiekt wraz z wszystkimi kolumnami tabeli wp_blogs,
zwraca wartość tylko jednej, wskazanej kolumny.

$id

Wymagana liczba całkowita identyfikatora witryny internetowej, dla
której ma być zwrócona kolumna z tabeli wp_blogs.

$pref

Wymagany ciąg tekstowy nazwy kolumny, która ma być zwrócona z tabeli
wp_blogs.

W celu wyświetlenia informacji o tym, kiedy bieżąca witryna internetowa
została zarejestrowana, należy użyć następującego polecenia.

    echo get_blog_status( get_current_blog_id(), 'registered' );

Omawiana funkcja została zdefiniowana w pliku wp-includes/ms-blogs.php.

update_blog_status( $blog_id, $pref, $value )

Działanie tej funkcji jest podobne do update_blog_details() z wyjątkiem
tego, że zamiast uaktualniać tablicę kolumn tabeli wp_blogs, uaktualnia
wartość tylko jednej, wskazanej kolumny.

$blog_id

Wymagana liczba całkowita identyfikatora witryny internetowej, dla
której ma być uaktualniona kolumna w tabeli wp_blogs.

$pref

Wymagany ciąg tekstowy nazwy kolumny, która ma być uaktualniona w tabeli
wp_blogs.

$value

Wymagany ciąg tekstowy wartości kolumny, która ma być uaktualniona.

W celu oznaczenia bieżącej witryny internetowej jako usuniętej należy
użyć polecenia.

    update_blog_status( get_current_blog_id(), 'deleted', '1' );

Omawiana funkcja została zdefiniowana w pliku wp-includes/ms-blogs.php.

get_blog_option( $id, $option, $default = false )

Dzięki tej funkcji można uniknąć problemów związanych z wywołaniem
switch_to_blog(), a następnie użyć zwykłej funkcji WordPressa
get_option() lub przygotować niestandardowe zapytanie SQL, gdy ma być
pobrana opcja z określonej witryny internetowej. Ta funkcja zwraca
wartość opcji z dowolnej witryny internetowej sieci WordPressa, co jest
możliwe dzięki przekazanym funkcji następującym parametrom.

$id

Wymagana liczba całkowita identyfikatora witryny internetowej, dla
której ma być pobrana opcja. W przypadku pobierania opcji z bieżącej
witryny internetowej można przekazać wartość null.

$option

Wymagany ciąg tekstowy nazwy opcji, która ma zostać pobrana.

$default

Opcjonalny ciąg tekstowy do zwrócenia, jeśli funkcja nie znajdzie
dopasowanej opcji.

W celu pobrania opcji admin_email z określonej witryny internetowej
należy skorzystać z polecenia.

    echo 'Adres e-mail administratora witryny o identyfikatorze 2 to ' . get_blog_option( 2, 'admin_email' );

Omawiana funkcja została zdefiniowana w pliku wp-includes/ms-blogs.php.

update_blog_option( $id, $option, $value )

Ta funkcja uaktualnia dowolną opcję w podanej witrynie internetowej i
akceptuje trzy parametry.

$id

Wymagana liczba całkowita identyfikatora witryny internetowej, dla
której ma być uaktualniona opcja.

$option

Wymagany ciąg tekstowy nazwy opcji, która ma zostać uaktualniona.

$value

Wymagany ciąg tekstowy wartości opcji, która ma zostać uaktualniona.

W celu uaktualnienia opcji admin_email z określonej witryny internetowej
należy skorzystać z polecenia.

    update_blog_option( 2, 'admin_email', 'brian@alphaweb.com' );

Omawiana funkcja została zdefiniowana w pliku wp-includes/ms-blogs.php.

delete_blog_option( $id, $option )

Ta funkcja usuwa dowolną opcję w podanej witrynie internetowej i
akceptuje dwa parametry.

$id

Wymagana liczba całkowita identyfikatora witryny internetowej, dla
której ma być usunięta opcja.

$option

Wymagany ciąg tekstowy nazwy opcji, która ma zostać usunięta.

W celu usunięcia opcji z określonej witryny internetowej należy
skorzystać z polecenia.

    delete_blog_option( 2, 'wds_custom_option' );

Omawiana funkcja została zdefiniowana w pliku wp-includes/ms-blogs.php.

get_blog_post( $blog_id, $post_id )

Ta funkcja pobiera post z dowolnej witryny internetowej w sieci i
akceptuje dwa parametry.

$blog_id

Wymagana liczba całkowita identyfikatora bloga, z którego ma zostać
pobrany post.

$post_id

Wymagana liczba całkowita identyfikatora posta, który ma zostać pobrany.

W celu pobrania tytułu posta z drugiej witryny internetowej sieci
WordPressa można wykonać fragment kodu.

    $post = get_blog_post( 2, 3 );

    echo $post->post_title;

Omawiana funkcja została zdefiniowana w pliku
wp-includes/ms-functions.php.

add_user_to_blog( $blog_id, $user_id, $role )

Ta funkcja pozwala dodać do dowolnej witryny internetowej sieci
WordPressa użytkownika w podanej roli. Omawiana funkcja akceptuje trzy
parametry.

$blog_id

Wymagana liczba całkowita identyfikatora bloga witryny internetowej, do
której ma zostać dodany użytkownik.

$user_id

Wymagana liczba całkowita identyfikatora użytkownika, który ma zostać
dodany do witryny internetowej.

$role

Wymagany ciąg tekstowy nazwy roli, którą użytkownik ma odgrywać.

Jeżeli operacja dodania użytkownika zakończyła się sukcesem, wartością
zwrotną funkcji będzie true. W przeciwnym przypadku funkcja zwróci
WP_Error.

W celu dodania określonego użytkownika w roli Administrator do drugiej
witryny internetowej sieci WordPressa można skorzystać z polecenia.

    add_user_to_blog( 2, 5, 'administrator' );

Omawiana funkcja została zdefiniowana w pliku
wp-includes/ms-functions.php.

wpmu_delete_user( $user_id )

Ta funkcja powoduje usunięcie użytkownika z całej sieci, a także
usunięcie wszystkich utworzonych przez niego postów.

$user_id

Wymagana liczba całkowita identyfikatora użytkownika, który ma zostać
usunięty.

Ta funkcja zwraca wartość true, jeśli operacja usunięcia użytkownika
zakończy się sukcesem. W przeciwnym razie wartością zwrotną będzie
false.

W przypadku utworzenia sieci witryn internetowych WordPressa zwykła
funkcja wp_delete_user() spowoduje usunięcie użytkownika tylko z
bieżącej witryny internetowej zamiast usunąć go całkowicie. Dlatego
bardzo duże znaczenie ma upewnienie się, że funkcja wpmu_delete_user()
jest używana z zaczepami wp_delete_user i wpmu_delete_user w przypadku
sieci witryn. Jeżeli tworzysz fragment kodu, który ma działać zarówno
dla sieci witryn, jak i dla pojedynczej witryny internetowej, możesz
skorzystać z funkcji is_multisite().

    if ( is_multisite() ) {

        wpmpu_delete_user( $user_id );

    } else {

        wp_delete_user( $user_id );

    }

Omawiana funkcja została zdefiniowana w pliku
wp-includes/ms-functions.php.

create_empty_blog( $domain, $path, $weblog_title, $site_id = 1 )

Ta funkcja tworzy nową witrynę internetową w sieci, przy czym najpierw
sprawdza, czy taka witryna na pewno jeszcze nie istnieje. Funkcja
akceptuje cztery parametry i jest używana przez administratorów sieci w
celu dodawania nowych witryn.

$domain

Wymagany ciąg tekstowy domeny nowego bloga.

$path

Wymagany ciąg tekstowy ścieżki dostępu nowego bloga.

$weblog_title

Wymagany ciąg tekstowy tytułu lub nazwy nowego bloga.

$site_id

Opcjonalna liczba całkowita identyfikatora witryny internetowej
powiązanej z nowym blogiem. Wartością domyślną jest 1.

Jeżeli chcesz dodać nową witrynę internetową do sieci, możesz użyć
polecenia.

    create_empty_blog( 'someteacher.schoolpress.me', '/', 'Mr. Some Teacher' );

Omawiana funkcja została zdefiniowana w pliku
wp-includes/ms-functions.php.

Funkcje niewymienione w tym podrozdziale

W podrozdziale nie wymieniliśmy wszystkich funkcji używanych podczas
pracy z siecią witryn WordPressa, a jedynie najważniejsze z nich. Wybór
funkcji zależy od tego, jaki efekt ma zostać osiągnięty. W celu
wyszukania wszystkich dostępnych funkcji sieci witryn WordPressa zajrzyj
do kodu źródłowego platformy. Funkcje związane z siecią witryn
znajdziesz w wymienionych plikach:

-   wp-admin/includes/ms.php
-   wp-includes/ms-blogs.php
-   wp-includes/ms-functions.php.

Więcej informacji na ten temat znajduje się w sekcji Multisite functions
dokumentacji WordPressa zamieszczonej w serwisie Codex
https://codex.wordpress.org/Function_Reference#Multisite_function.

Rozdział 13. Lokalizacja aplikacji WordPressa

Lokalizacja (inaczej internacjonalizacja) to proces przetłumaczenia
aplikacji w celu jej użycia w innych językach i ustawieniach
regionalnych. W tym rozdziale przedstawiamy narzędzia i metody dostępne
podczas lokalizacji aplikacji, motywów i wtyczek.

  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Czasami można się spotkać ze skróconymi wersjami angielskich słów lokalizacja (localization, l10n) i internacjonalizacja (internationalization, i18n).
  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------

Czy w ogóle zachodzi potrzeba lokalizacji aplikacji

Rynek aplikacji internetowych staje się coraz bardziej globalny.
Oferowanie aplikacji w innych językach może być ogromną zaletą
pomagającą w zdobyciu dodatkowego rynku i przewagi nad konkurencją w
swoim języku (i ustawieniach regionalnych), a także pomaga pokonać
konkurencję w innych językach (i ustawieniach regionalnych).

Jeżeli utworzony kod źródłowy planujesz wydać na licencji typu open
source, jego wcześniejsza lokalizacja jest doskonałym sposobem na
zwiększenie liczby programistów, którzy zaangażują się w prace nad
projektem. Gdy przygotowana przez Ciebie wtyczka lub motyw będą
zlokalizowane, istnieje większe prawdopodobieństwo, że programiści
posługujący się innymi językami zaangażują się bezpośrednio w pracę nad
projektem zamiast utworzyć jego kopię w celu przeprowadzenia lokalizacji
projektu.

Jeżeli planujesz rozprowadzanie komercyjnej wtyczki lub motywu,
lokalizacja kodu źródłowego zwiększa liczbę potencjalnych klientów.

Gdy celem jest zdobycie rynku tylko we własnym kraju i nie ma planów na
ekspansję w innych regionach lub językach, nie trzeba poświęcać czasu na
przygotowywanie aplikacji do jej lokalizacji. Pamiętaj również, że każda
językowa lub regionalna wersja aplikacji prawdopodobnie będzie wymagała
oddzielnego hostingu, obsługi, pomocy technicznej i konserwacji. Dla
większości firm będzie to zbyt duży koszt, na wczesnym etapie istnienia
aplikacji. Z drugiej strony okazuje się, że podstawy związane z
przygotowaniem kodu do lokalizacji (opakowanie danych wyjściowych ciągu
tekstowego wywołaniami __(), _e() i _x()) są bardzo proste i często mają
także inne zastosowania niż tylko lokalizacja.

Trzeba również zwrócić uwagę na to, że czasami lokalizacja oznacza dużo
więcej niż tylko przetłumaczenie kodu źródłowego. Jeżeli kod ma działać
z innymi usługami, trzeba się upewnić, że te usługi działają w różnych
regionach lub przygotować się na opracowanie rozwiązań alternatywnych.
Na przykład bardzo ważnym komponentem wtyczki Paid Memberships Pro jest
integracja z bramkami płatności. Przed przystąpieniem do lokalizacji
wtyczki Jason upewnił się o jej dobrej integracji z międzynarodowymi
bramkami płatności. W przeciwnym razie użytkownicy mogliby używać bramki
w swoich ojczystych językach, ale jednocześnie nie mieliby możliwości
użycia ważnych bramek płatności działających w ich krajach.

Jak lokalizacja jest przeprowadzana w WordPressie

WordPress używa systemu gettext opracowanego na potrzeby
internacjonalizacji projektu GNU. Ten system w WordPressie zawiera
następujące komponenty:

-   sposób na definiowanie ustawień regionalnych i języka
-   sposób na definiowanie tekstu domen
-   sposób na tłumaczenie ciągów tekstowych w kodzie
-   pliki .pot zawierające wszystkie słowa i wyrażenia, które mają być
    przetłumaczone
-   pliki .po dla każdego języka, dla którego jest tworzone tłumaczenie
-   pliki .mo dla każdego języka zawierającego skompilowaną wersję
    tłumaczenia w pliku .po.

Aby tłumaczenie działało, każdy z tych komponentów musi znajdować się w
odpowiednim miejscu. W dalszej części rozdziału dokładnie przedstawiamy
poszczególne kroki. Gdy zakończysz lekturę rozdziału, powinieneś znać
wszystkie narzędzia niezbędne do tworzenia lokalizowanych wtyczek
i plików tłumaczeń.

Definiowanie lokalizacji w WordPressie

W celu zdefiniowania lokalizacji w WordPressie należy zdefiniować
wartość stałej WPLANG w pliku wp-config.php.

    <?php

        // Użycie plików języka i ustawień regionalnych dla języka hiszpańskiego używanego w Hiszpanii

        define('WPLANG', 'es_ES');

    ?>

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Używa się pojęcia „ustawień regionalnych” zamiast „języka”, ponieważ zdarza się istnienie wielu tłumaczeń dla tego samego języka. Przykładowo angielski brytyjski różni się od angielskiego w USA, hiszpański w Meksyku zaś różni się od hiszpańskiego, którym posługują się mieszkańcy Hiszpanii.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Domeny tekstu

W specyfikacji gettext tzw. domeny tekstu są używane do organizowania
tabel tłumaczeń. W WordPressie oznacza to, że każda wtyczka i motyw
powinny mieć własną unikatową domenę tekstu.

Z technicznego punktu widzenia można użyć dowolnej wartości jako domeny
tekstu, o ile będzie ona unikatowa, spójna i będzie stosowała poprawną
składnię (tylko małe litery i łączniki, znaki podkreślenia są
niedozwolone). W praktyce domena tekstu wtyczki lub motywu powinna
odpowiadać slugowi, ponieważ to jest rozwiązanie oczekiwane przez
większość wtyczek i narzędzi. Przykładowo wtyczki znajdujące się w
repozytorium WordPress.org wymagają dopasowania domeny tekstu do slugu,
aby GlotPress i inne narzędzia witryny internetowej WordPress.org
funkcjonowały prawidłowo.

Oto kilka przykładów domen tekstu używanych w rzeczywistych projektach:

-   cały podstawowy kod tworzący platformę WordPressa używa domeny
    tekstu defualt
-   wtyczka Paid Memberships Pro używa domeny tekstu
    paid-memberships-pro
-   wtyczka Memberlite używa domeny tekstu memberlite.

Definiowanie domeny tekstu

W przypadku wtyczki i motywu każdej lokalizowanej witryny internetowej
WordPress musi wiedzieć, jak odszukać pliki lokalizacji. Odbywa się to
za pomocą funkcji load_plugin_textdomain(), load_textdomain() i
load_theme_textdomain(). Wszystkie trzy wymienione funkcje są podobne,
ale pobierają różne parametry, a ich wywołanie ma sens w odmiennych
sytuacjach.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Specyfikacja gettext i funkcje WordPressa używają terminu textdomain w odniesieniu do domen tekstu. Przyjęło się jednak stosowanie zapisu w postaci dwóch oddzielnych słów — domena tekstu.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Niezależnie od używanej funkcji powinna być ona wywoływana jak
najwcześniej w aplikacji, ponieważ wszelkie ciągi tekstowe, użyte lub
wyświetlone za pomocą funkcji tłumaczenia przed wczytaniem domeny
tekstu, nie zostaną przetłumaczone.

W dalszej części przedstawiamy kilka sposobów na wczytanie domeny tekstu
w includes/localization.php.

load_plugin_textdomain( $domain, $abs_rel_path, $plugin_rel_path )

Ta funkcja pobiera trzy parametry. Pierwszym jest domena ($domain)
wtyczki lub aplikacji (w omawianym przykładzie to schoolpress).
Następnie drugi lub trzeci parametr może zostać użyty do wskazania
katalogu języków, z którego ma zostać pobrany plik .mo. Parametr
$abs_rel_path jest uznawany za przestarzały, ale pozostał w celu
zapewnienia wstecznej zgodności. Istnieje możliwość przekazania dla
niego wartości FALSE i użycie parametru $plugin_rel_path.

    <?php

    function schoolpress_load_textdomain(){

        // Wczytanie domeny tekstu z katalogu /plugins/schoolpress/languages/

        load_plugin_textdomain(

            'schoolpress',

            FALSE,

            dirname( plugin_basename(__FILE__) ) . '/languages/'

        );

    }

    add_action( 'init', 'schoolpress_load_textdomain', 1 );

    ?>

Ten kod wczytuje z podanego katalogu odpowiedni plik języka na podstawie
wartości stałej WPLANG w pliku wp-config.php. Aby pobrać ścieżkę dostępu
do bieżącego pliku, używana jest funkcja plugin_basename(__FILE__), a
następnie dirname(...) — w celu pobrania ścieżki dostępu do katalogu
głównego wtyczki, ponieważ został wskazany podkatalog includes w
katalogu wtyczki schoolpress.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   W nagłówku komentarza PHP wtyczki lub motywu można się spotkać z elementem Text Domain. Jest on używany przez WordPress do tłumaczenia informacji meta wtyczki, nawet jeśli została ona wyłączona. Od wydania WordPress 4.6 to ustawienie nagłówka jest opcjonalne i jeśli nie będzie użyte, wartością domyślną jest slug wtyczki lub motywu.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

load_theme_textdomain( $domain, $path )

Jeżeli masz pliki językowe dla motywu, możesz je wczytać za pomocą
funkcji load_theme_textdomain(), jak pokazujemy to w kolejnym fragmencie
kodu.

    <?php

    function schoolpress_load_textdomain() {

        load_theme_textdomain(

            'schoolpress', get_template_directory() . '/languages/'

        );

    }

    add_action( 'init', 'schoolpress_load_textdomain', 1 );

    ?>

load_textdomain( $domain, $path )

Ta funkcja może być używana do wczytywania domeny tekstu, przy czym
ustawienia regionalne trzeba pobrać oddzielnie.

Bezpośrednie wywołanie funkcji load_textdomain() nie jest zalecane w
przypadku wtyczek lub motywów, choć może okazać się użyteczne w
projektach, w których ma być wykorzystana pojedyncza domena dla wielu
różnych wtyczek. Bezpośrednie wywołania omawianej funkcji zapewniają
również pewną elastyczność, jeśli chcesz zapewnić innym programistom
możliwość łatwego wyszukiwania i rozszerzania plików językowych. Kod
podobny do przedstawionego w kolejnym fragmencie można wykorzystać do
wczytywania najpierw pliku .mo, znajdującego się w globalnym katalogu
plików językowych WordPressa (zwykle jest nim wp-content/languages/),
a dopiero później pliku .mo z lokalnego dla wtyczki katalogu językowego.
Dzięki temu programiści mogą nadpisywać tłumaczenia przez dodanie
własnych plików.mo do globalnego katalogu plików językowych.

    <?php

    function schoolpress_load_textdomain() {

        // Pobranie ustawień regionalnych

        $locale = apply_filters( 'plugin_locale',

            get_locale(), 'schoolpress' );

        $mofile = 'schoolpress-' . $locale . '.mo';

        /*

            Ścieżki dostępu do lokalnych (plugin) i globalnych (WP) plików językowych.

            Uwaga: wywołanie dirname(__FILE__) spowoduje zmianę, jeśli ten kod zostanie

            umieszczony poza podstawowym plikiem wtyczki

        */

        $mofile_local  = dirname( __FILE__ ).'/languages/' . $mofile;

        $mofile_global = WP_LANG_DIR . '/schoolpress/' . $mofile;

        // Najpierw będzie wczytany plik globalny

        load_textdomain( 'schoolpress', $mofile_global );

        // Następnie zostanie wczytany plik lokalny

        load_textdomain( 'schoolpress', $mofile_local );

    }

    add_action( 'init', 'schoolpress_load_textdomain', 1 );

    ?>

Ta wersja kodu pobiera ustawienia regionalne za pomocą funkcji
get_locale(), stosuje filtr plugin_locale, a następnie szuka plików .mo
w katalogach plików językowych: globalnym (zwykle
/wp-content/languages/) i lokalnym dla wtyczki.

Przygotowanie ciągów tekstowych za pomocą funkcji tłumaczeń

Pierwszym krokiem podczas lokalizacji kodu jest upewnienie się, że każdy
wyświetlany ciąg tekstowy został opakowany jedną z funkcji tłumaczenia
dostarczanych przez WordPressa. Wszystkie te funkcje działają
praktycznie w taki sam sposób: funkcji przekazywany jest pewien tekst
domyślny z nazwą domeny i/lub innymi informacjami, które przedstawiają
tłumaczom kontekst, w którym występuje dany fragment tekstu.

Omówimy tu najużyteczniejsze funkcje lokalizacji tekstu.

__( $text, $domain = "default" )

Ta funkcja oczekuje dwóch parametrów: $text, zawierającego tekst
przeznaczony do tłumaczenia, i $domain, zawierającego domenę tekstu dla
wtyczki lub motywu. Wartością zwrotną omawianej funkcji jest tekst
przetłumaczony na podstawie domeny tekstu i języka wybranego w pliku
wp-config.php.

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Funkcja __() jest tak naprawdę aliasem dla funkcji translate() używanej w tle przez WordPressa. Wprawdzie nie ma żadnego powodu, dla którego nie powinieneś bezpośrednio wywoływać funkcji translate(), ale __() jest znacznie krótsza, więc bardzo często będziesz spotykał się z jej użyciem.
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Spójrz na przykład pokazujący, jak można opakować pewne ciągi tekstowe
za pomocą funkcji __().

    <?php

    // Przypisanie zmiennej ciągu tekstowego bez użycia funkcji lokalizacji

    $title = 'Assignments';

    // Przypisanie zmiennej ciągu tekstowego z użyciem funkcji lokalizacji

    $title = __( 'Assignments', 'schoolpress' );

    ?>

_e( $text, $domain = "default" )

Ta funkcja oczekuje dwóch parametrów: $text, zawierającego tekst
przeznaczony do tłumaczenia, i $domain, zawierającego domenę tekstu dla
wtyczki lub motywu. Wartością zwrotną omawianej funkcji jest tekst
przetłumaczony na podstawie domeny tekstu i języka wybranego w pliku
wp-config.php.

Omawiana funkcja jest podobna do __(), z tą różnicą, że dane wyjściowe
umieszcza na ekranie zamiast je zwrócić. Spójrz na przykład pokazujący,
jak można opakować pewne ciągi tekstowe za pomocą funkcji _e().

    <?php

    // Wyświetlenie zawartości zmiennej bez wykorzystania lokalizacji

    ?>

    <h2><?php echo $title; ?></h2>

    <?php

    // Wyświetlenie zawartości zmiennej z wykorzystaniem lokalizacji

    ?>

    <h2><?php _e( $title, 'schoolpress' ); ?></h2>

W praktyce funkcję __() będziesz używać podczas definiowania zmiennej,
natomiast funkcję _e() podczas wyświetlania jej wartości.

_x( $text, $context, $domain = "default" )

Ta funkcja oczekuje trzech parametrów: $text, zawierającego tekst
przeznaczony do tłumaczenia, $context, zawierającego kontekst przydatny
podczas tłumaczenia, i $domain, zawierającego domenę tekstu dla wtyczki
lub motywu. Wartością zwrotną omawianej funkcji jest tekst
przetłumaczony na podstawie kontekstu, domeny tekstu i języka wybranego
w pliku wp-config.php.

Funkcja _x() działa podobnie jak __(), ale oferuje parametr dodatkowy
$context, pomagający tłumaczom w przygotowaniu tekstu. Jest to wymagane,
jeśli kod używa tego samego słowa lub wyrażenia w wielu miejscach, które
mogą wymagać odmiennych tłumaczeń.

Przykładowo słowo tytuł w języku polskim odwołuje się do tytułu książki,
a także formy używanej w stosunku do osób. W wielu językach te same
słowa mogą być stosowane w różnych kontekstach. Do odróżniania
wspomnianych kontekstów służy funkcja _x().

W kolejnym fragmencie kodu przedstawiamy (nieco sztuczny) przykład, w
którym następuje zdefiniowanie kilku zmiennych używanych podczas
tworzenia ekranu we wtyczce SchoolPress.

    <?php

    $class_title_field_label = _x( 'Title', 'class title', 'schoolpress' );

    $class_professor_title_field_label = _x( 'Title', 'name prefix', 'schoolpress' );

    ?>

    <h3>Opis klasy</h3>

    <label><?php echo $class_title_field_label; ?></label>

    <input type="text" name="title" value="" />

    <h3>Profesor</h3>

    <label><?php echo $class_professor_title_field_label; ?></label>

    <input type="text" name="professor_title" value="" />

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Funkcje _x() i _ex() są czasami określane mianem funkcji _ex_plain, ponieważ używają parametru $context w celu dalszego wyjaśnienia (explain), jak dany tekst powinien zostać przetłumaczony.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

_ex( $title, $context, $domain = "default" )

Funkcja _ex() działa w taki sam sposób jak _x(), ale wyświetla
przetłumaczony tekst zamiast go zwrócić do komponentu wywołującego
funkcję.

Jednoczesne tłumaczenie tekstu i stosowanie znaków sterujących

W rozdziale 7. powiedzieliśmy dużo o wadze stosowania znaków sterujących
w ciągach tekstowych, które są wyświetlane w atrybutach HTML oraz w
innych elementach wrażliwych. Podczas tłumaczenia tych ciągów
tekstowych, zamiast wywoływania dwóch funkcji, można wywołać tylko jedną
łączącą w sobie obie wymagane funkcjonalności. WordPress oferuje kilka
takich funkcji. Działają one dokładnie w oczekiwany sposób: tekst jest
najpierw tłumaczony, a dopiero później są w nim stosowane znaki
sterujące.

-   esc_attr__()
-   esc_attr_e()
-   esc_attr_x()
-   esc_html__()
-   esc_html_e()
-   esc_html_x()

Tworzenie i wczytywanie plików tłumaczeń

Po przygotowaniu kodu do używania funkcji tłumaczeń konieczne jest
wygenerowanie pliku .pot dla tłumaczy, którzy będą zajmować się
tłumaczeniem aplikacji. Plik .pot zawiera dla każdego ciągu tekstowego w
kodzie sekcję podobną do przedstawionych poniżej.

    #: schoolpress.php:108

    #: schoolpress.php:188

    #: pages/courses.php:10

    msgid "School"

    msgstr ""

Zgodnie z informacjami zamieszczonymi w tej sekcji słowo School zostało
użyte w wierszach 108. i 188. pliku schoolpress.php oraz w wierszu 10.
pliku pages/courses.php.

Jeżeli przygotowujesz tłumaczenie wtyczki na przykład na język
hiszpański, tworzysz kopię pliku schoolpress.pot, zmieniasz jego nazwę
na schoolpress-es_ES.po, a następnie wypełniasz wartość msgstr każdego
wyrażenia, jak pokazaliśmy w kolejnym fragmencie kodu.

    #: schoolpress.php:108

    #: schoolpress.php:188

    #: pages/courses.php:10

    msgid "School"

    msgstr "Escuela"

Pliki .po muszą zostać skompilowane na format .mo, który jest
zoptymalizowany do przetwarzania tłumaczeń.

W przypadku ogromnych wtyczek i aplikacji niepraktyczne jest
wyszukiwanie numeru wiersza dla każdego ciągu tekstowego, a następnie
ręczne uaktualnianie tych danych po każdej modyfikacji wtyczki. W
następnej sekcji dowiesz się, jak można wykorzystać polecenie xgettext
powłoki systemu Linux w celu wygenerowania pliku .pot, a następnie
polecenia msgfmt do skompilowania pliku .po na plik w formacie .mo.
Alternatywnym rozwiązaniem jest użycie bezpłatnego i wyposażonego
w elegancki graficzny interfejs użytkownika programu Poedit
(https://poedit.net/) do przekazywania kodu oraz wygenerowania plików
.pot, .po i .mo. Wymieniony program jest przeznaczony na platformy
Windows, macOS i Linux.

Struktura pliku do lokalizacji

Zanim przejdziemy do szczegółów związanych z generowaniem wymienionych
plików, warto dowiedzieć się, jak te pliki są zwykle przechowywane we
wtyczkach. W przypadku aplikacji SchoolPress pliki lokalizacji są
umieszczone w katalogu languages wewnątrz wtyczki głównej. Cały kod
lokalizacji, w tym także wywołania funkcji load_plugin_textdomain(),
zostanie dodany do pliku localization.php w katalogu languages.

Struktura plików przedstawia się więc następująco:

-   ../plugins/schoolpress/schoolpress.php (zawiera plik
    localization.php)
-   ../plugins/schoolpress/includes/localization.php (wczytuje domenę
    tekstu i inne funkcje lokalizacji)
-   ../plugins/schoolpress/languages/schoolpress.pot (lista ciągów
    tekstowych przeznaczonych do tłumaczenia)
-   ../plugins/schoolpress/languages/schoolpress.po (domyślne ciągi
    tekstowe/zawartość w języku angielskim)
-   ../plugins/schoolpress/languages/schoolpress.mo (skompilowane
    domyślne ciągi tekstowe/ zawartość w języku angielskim)
-   ../plugins/schoolpress/languages/schoolpress-es_ES.po (tłumaczenie
    tekstu w języku hiszpańskim)
-   ../plugins/schoolpress/languages/schoolpress-es_ES.mo (skompilowane
    tłumaczenie zawartości w języku hiszpańskim).

Podczas tworzenia większej aplikacji zawierającej wiele niestandardowych
wtyczek i motywów lokalizacja będzie łatwiejsza do zarządzania, jeśli
poszczególne wtyczki i motywy będą tłumaczone oddzielnie zamiast
podejmowania próby wygenerowania jednego pliku tłumaczenia zawierającego
cały tekst. Jeżeli wtyczka ma być dostępna tylko dla jednego projektu,
prawdopodobnie zostanie utworzona w postaci includes lub modułu plików
.php w głównej aplikacji wtyczki. Natomiast gdy wtyczka ma zostać użyta
w innym projekcie, powinna być lokalizowana oddzielnie, aby można było
przenosić pliki lokalizacyjne wraz z wtyczką.

Generowanie pliku .pot

Polecenie xgttext zainstalowane w większości dystrybucji systemu
Linux[1] wykorzystamy do wygenerowania pliku .pot wtyczki.

Aby wygenerować plik .pot dla aplikacji SchoolPress, należy przejść do
powłoki, a następnie za pomocą polecenia cd do katalogu wtyczki,
wp-content/plugins/schoolpress. Kolejnym krokiem jest wydanie
przedstawionego tutaj polecenia.

    xgettext -o languages/schoolpress.pot \

    --default-domain=schoolpress \

    --language=PHP \

    --keyword=_ \

    --keyword=__ \

    --keyword=_e \

    --keyword=_ex \

    --keyword=_x \

    --keyword=_n \

    --sort-by-file \

    --copyright-holder="SchoolPress" \

    --package-name=schoolpress \

    --package-version=1.0 \

    --msgid-bugs-address="info@schoolpress.me" \

    --directory=. \

    $(find . -name "*.php")

Przeanalizujemy teraz poszczególne fragmenty tego polecenia.

-o languages/schoolpress.pot

Określa miejsce umieszczenia danych wyjściowych.

--default-domain=schoolpress

Wskazuje, że domeną tekstu jest schoolpress.

--language=PHP

Wskazuje, że używanym językiem programowania jest PHP.

--keyword=…

Określa, że xgettext będzie pobierać dowolny ciąg tekstowy użyty w
funkcjach. Upewnij się o dodaniu podobnego parametru dla wszystkich
pozostałych funkcji tłumaczenia, np. esc_attr__, z których zamierzasz
korzystać.

--sort-by-file

Pomaga w organizacji danych wyjściowych, o ile to możliwe.

--copyright-holder="SchoolPress"

Definiuje właściciela praw autorskich, który będzie wymieniony w
nagłówku pliku .pot. Wartością tej opcji powinny być dane osoby lub
organizacji zachowującej prawa autorskie do budowanej aplikacji, wtyczki
lub motywu.

+----+----------------------------------------------------------------+
| [] | Oto fragment pochodzący z oficjalnej witryny internetowej GNU  |
|    | (http://www.                                                   |
|    | gnu.or                                                         |
|    | g/software/gettext/manual/html_node/xgettext-Invocation.html): |
|    |                                                                |
|    | Tłumacze powinni zrzec się praw autorskich lub je przenieść,   |
|    | aby osoby odpowiedzialne za rozwój danego pakietu mogły go     |
|    | dalej rozpowszechniać bez obaw o potencjalne skutki prawne.    |
|    | Jeżeli [wartość wskazująca posiadacza praw autorskich] jest    |
|    | pustym ciągiem tekstowym, pliki danych wyjściowych są uznawane |
|    | za własność publiczną. W takim przypadku wskazane jest         |
|    | zrzeczenie się praw autorskich przez tłumaczy, co ponownie     |
|    | podyktowane jest tym, aby osoby odpowiedzialne za rozwój       |
|    | danego pakietu mogły go dalej rozpowszechniać bez obaw o       |
|    | potencjalne skutki prawne.                                     |
+----+----------------------------------------------------------------+

--package-name=schoolpress

Definiuje nazwę pakietu wymienianą w nagłówku pliku .pot. Z reguły
będzie taka sama jak nazwa domeny tekstu.

--package-version=1.0

Definiuje wersję pakietu wymienianą w nagłówku pliku .pot. Ta wartość
powinna być uaktualniana wraz z każdym wydaniem aplikacji, wtyczki lub
motywu.

--msgid-bugs-address="info@schoolpress.me"

Definiuje adres e-mail wymieniany w nagłówku pliku .pot, aby w ten
sposób umożliwić zgłaszanie wszelkich błędów w tym pliku.

--directory=.

Ta opcja nakazuje xgettext rozpoczęcie skanowania od katalogu bieżącego.

$(find . -name "*.php")

To polecenie znajduje się na końcu. Jest to polecenie systemu Linux
wyszukujące wszystkie pliki .php w katalogu bieżącym.

Utworzenie pliku .po

Warto przypomnieć, że narzędzie Poedit oferuje elegancki graficzny
interfejs użytkownika przeznaczony do generowania plików .po na
podstawie plików .pot oraz zapewnia tłumaczenie dla każdego ciągu
tekstowego. Dostosowanie narzędzia do własnych potrzeb jest dość prostym
zadaniem. Wystarczy w katalogu plików językowych utworzyć kopię pliku
.pot i zmienić jego rozszerzenie na .po (np. na es_ES.po). Kolejnym
krokiem jest edycja pliku .po i dodanie tłumaczenia dla każdego wiersza
msgstr w pliku.

Utworzenie pliku .mo

Po uaktualnieniu pliku .po dla ustawień regionalnych konieczne jest jego
skompilowanie w postać pliku .mo. Polecenia msgfmt w systemie Linux
można użyć do wygenerowania plików .mo, np. msgfmt es_ES.po
--output-file es_ES.mo.

GlotPress

GlotPress to narzędzie pozwalające tłumaczom współpracować nad
tłumaczeniem w internecie. Zamiast zarządzać poszczególnymi plikami .po
dla każdej lokalizacji, GlotPress oferuje interfejs użytkownika w
postaci witryny internetowej przeznaczony do edytowania ciągów
tekstowych dla wszystkich ustawień regionalnych. Tłumaczenia są
przechowywane w bazie danych. Gdy dla wtyczki zostanie przetłumaczona
zdefiniowana wartość procentowa ciągów tekstowych, GlotPress
automatycznie wygeneruje pliki .po i .mo. Nie ma nawet konieczności
pobierania wygenerowanych paczek językowych lub dołączania ich do
wtyczki. WordPress automatycznie je odszuka i pobierze, na podstawie
wybranych ustawień regionalnych.

Używanie narzędzia GlotPress dla wtyczek i motywów umieszczanych w repozytorium WordPress.org

Jeżeli zdecydowałeś się na hosting wtyczki lub motywu w repozytorium
WordPress.org, użycie GlotPress jest sposobem na łatwe i prawidłowe
opakowanie ciągów tekstowych przeznaczonych do tłumaczenia i
zagwarantowanie, że domena tekstu będzie odpowiadała slugowi wtyczki lub
motywu. Jeżeli zrobisz to prawidłowo, nowy projekt tłumaczenia zostanie
dla Ciebie wygenerowany w jednym z wymienionych tutaj miejsc:

-   https://translate.wordpress.org/projects/wp-plugins<your-plugins-slug>/
-   https://translate.wordpress.org/projects/wp-themes<your-themes-slug>/.

I na tym koniec. Jeżeli istniejące pliki .po w katalogu /languages/
zostały dołączone do wtyczki, powinny zostać zaimportowane do projektu
GlotPress jako ustawienia regionalne z już przetłumaczonymi ciągami
tekstowymi.

Po zintegrowaniu wtyczki lub motywu z GlotPress do projektu nie trzeba
dłużej dołączać plików językowych. WordPress będzie szukać paczek
językowych na podstawie ustawień regionalnych i automatycznie pobierze
je do użycia. Trzeba jednak zwrócić uwagę, że automatycznie są
rozpowszechniane tylko te tłumaczenia, które zostały ukończone w co
najmniej 95 procentach. Dlatego trzeba pamiętać o uzupełnianiu
tłumaczenia na bieżąco. Ewentualnie można pobrać pliki .po i .mo
niedokończonych tłumaczeń i dołączyć je do wtyczki za pomocą procedury,
którą wcześniej dokładnie przedstawiliśmy.

Utworzenie własnego serwera GlotPress

Jeżeli hosting wtyczki lub motywu odbywa się w Twoim serwerze, nadal
możesz wykorzystać zalety technologii GlotPress poprzez przygotowanie
własnego serwera tłumaczeń. Zespół tworzący GlotPress utworzył wtyczkę
WordPressa, którą można zainstalować i aktywować w dowolnej witrynie
internetowej WordPressa. Wtyczka GlotPress
(https://wordpress.org/plugins/glotpress/), bo o niej tutaj mowa,
powoduje skonfigurowanie punktu końcowego /glotpress/, który pozwala na
utworzenie nowego projektu tłumaczenia dla samodzielnie hostingowanych
wtyczek i motywów.

Po przygotowaniu serwera GlotPress można utworzyć nowy projekt dla
wtyczki nieprzechowywanej w repozytorium WordPress.org. Wprawdzie
WordPress nie będzie automatycznie pobierać tłumaczenia takiej wtyczki
dla użytkownika, ale zawsze można wyeksportować pliki .po i .mo, a
następnie umieścić je w plikach wtyczek.

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Wydaje się możliwe użycie zaczepu translations_api (https://developer.wordpress. org/reference/hooks/translations_api/) w celu uaktualnienia WordPressa, aby sprawdzał Twój serwer GlotPress i pobierał dostępne tłumaczenia. Jednak nie spotkaliśmy się jeszcze z takim rozwiązaniem. Jego wdrożenie może okazać się interesującym ćwiczeniem dla zmotywowanego czytelnika tej książki. Dołączanie plików tłumaczeń do rozpowszechnianych wtyczek wydaje się najprostszym rozwiązaniem.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

W zależności od przeznaczenia aplikacji internetowej przetłumaczenie jej
zawartości może mieć duże znaczenie dla osiągnięcia sukcesu. Podczas
tworzenia niestandardowego motywu lub wtyczki dobrą praktyką jest
tworzenie kodu w taki sposób, aby umożliwić jego lokalizację.

[1] Jeżeli tak nie jest, należy odszukać i zainstalować pakiet gettext
dla używanej dystrybucji systemu Linux.

Rozdział 14. Optymalizacja i skalowanie WordPressa

Materiał zamieszczony w tym rozdziale dotyczy wyciśnięcia maksymalnej
wydajności z WordPressa dzięki zastosowaniu optymalnej konfiguracji
serwera, buforowania i sprytnych rozwiązań programistycznych.

WordPress jest często uznawany za platformę, która nie skaluje się
równie dobrze jak inne frameworki PHP lub inne języki programowania.
Przekonanie o niewystarczająco dobrym skalowaniu WordPressa często
wynika z faktu, że ta platforma tradycyjnie była stosowana do tworzenia
małych blogów działających w środowiskach współdzielonego hostingu.
Decyzje podejmowane przez zespół tworzący WordPressa (m.in. dotyczące
obsługi funkcjonalności uznanej za przestarzałą oraz starszych wersji
PHP i MySQL) mają zapewnić, że WordPress będzie uruchamiać się łatwo w
jak największej liczbie konfiguracji hostingu, w tym także w ramach
charakteryzujących się małymi możliwościami kont w środowiskach hostingu
współdzielonego.

W internecie istnieje więc wiele naprawdę wolno działających witryn
opartych na WordPressie, z powodu których umacnia się przekonanie o jego
wolnym działaniu. Trzeba w tym miejscu koniecznie dodać, że WordPress
jest bardzo szybki po odpowiednim skonfigurowaniu platformy oraz może
być skalowany za pomocą tych samych technik, co każda inna aplikacja
oparta na PHP i MySQL. Wiele takich technik omówimy w tym rozdziale.
Poznasz również wiele narzędzi i koncepcji, które można zastosować
podczas tworzenia własnych aplikacji WordPressa.

Terminologia

W całej książce możesz natknąć się na terminy takie jak „optymalizacja”
i „skalowanie”. Duże znaczenie ma dokładne zrozumienie tych pojęć.

Optymalizacja

To słowo odwołuje się do maksymalnie szybkiego działania aplikacji i
skryptów. W niektórych przypadkach przeprowadza się optymalizację użycia
pamięci lub jeszcze innego niż szybkość aspektu. Mimo wszystko w
większości sytuacji określenie „optymalizacja” oznacza zwiększenie
szybkości działania.

Skalowanie

Ten termin oznacza budowanie aplikacji, która będzie potrafiła
obsługiwać coraz więcej zadań. Więcej odwiedzin stron. Więcej
użytkowników. Więcej postów. Więcej plików. Więcej podstron
internetowych. Więcej obliczeń.

Skalowanie oznacza również budowanie aplikacji obsługującej coraz
większe zadania. Większe posty. Większe pliki.

Prawdą jest, że czasami aplikacja lub jakaś jej część działa doskonale
pod małym obciążeniem lub gdy np. tabele bazy danych są mniejsze. Jednak
wraz ze wzrostem liczby użytkowników i obiektów, wielkości tych obiektów
itd. wydajność aplikacji dramatycznie spada lub aplikacja w ogóle
przestaje działać.

Skalowanie jest miarą subiektywną, określającą, jak dobrze kod i
aplikacja radzą sobie z coraz większą liczbą zadań, które na dodatek
stają się coraz większe. Ogólnie rzecz biorąc, na wszelki wypadek
powinno się tworzyć aplikacje, które potrafią sobie poradzić z
oczekiwanym wzrostem liczby zadań. Z drugiej strony zawsze należy brać
pod uwagę wady i zalety każdej platformy lub kodu decyzji podejmowanej
ze względu na skalowanie. Te decyzje zwykle wiążą się z pewnymi
kosztami, zarówno finansowymi, jak i technicznymi, oraz wynikającymi z
większego poziomu skomplikowania bazy kodu. Ponadto pewne techniki
zapewniające maksymalną wydajność podczas obsługi wielu ogromnych
transakcji w rzeczywistości spowalniają niektóre zadania, gdy są
stosowane do wykonywania mniejszej liczby mniejszych transakcji. Dlatego
tak ważne jest upewnienie się, że budowana aplikacja uwzględnia
rzeczywiste oczekiwania, a nie została zaprogramowana tylko z
uwzględnieniem samej skalowalności.

Skalowanie i optymalizacja są ze sobą blisko powiązane, ponieważ
aplikacje, które działają szybko, lepiej się skalują. Skalowanie to
zdecydowanie więcej niż tylko posiadanie szybkich komponentów, choć one
na pewno ułatwiają skalowanie. Z kolei wolno działająca aplikacja będzie
utrudniała skalowanie. Stąd zawsze ma sens przeprowadzanie optymalizacji
aplikacji od wewnątrz. W dokumencie The Truth About WordPress
Performance (https://mediatemple.net/blog/wp-content/uploads/
2013/09/The-Truth-About-WordPress-Performance.pdf), czyli doskonałej
pracy przygotowanej przez Cyberblogger Media i W3 Edge, autorzy odwołują
się do optymalizacji „źródła” zamiast „krawędzi”.

Źródło

Odwołuje się do aplikacji WordPressa, która jest źródłem wszystkich
danych wychodzących z aplikacji. Optymalizacja źródła oznacza, że
aplikacja WordPressa i serwer będą działały szybciej.

Krawędź

Odwołuje się do usług zewnętrznych dla aplikacji WordPressa, które
znajdują się dalej od źródła, ale potencjalnie bliżej użytkowników. Te
usługi obejmują m.in. sieci CDN (content delivery network) i buforowanie
podobne jak stosowane w przeglądarkach WWW. Optymalizacja krawędzi
obejmuje wykorzystanie tych usług w taki sposób, aby zapewnić
użytkownikowi jeszcze lepsze wrażenia podczas pracy z aplikacją.

Źródło kontra krawędź

Ponownie opowiadamy się za optymalizacją od wewnątrz, w kierunku od jej
jądra ku krawędzi. Usprawnienia wprowadzone w wydajności jądra
WordPressa zawsze, w takiej czy innej postaci, będą odczuwalne przez
użytkownika końcowego. Z drugiej strony zwiększenie wydajności działania
usługi zewnętrznej, choć poprawi wrażenia użytkownika związane z pracą z
aplikacją, czasami może oznaczać większe problemy dla jądra niż korzyści
płynące z wprowadzonej optymalizacji.

Typowym przykładem omówionej sytuacji jest ta, w której serwer proxy
taki jak Varnish (omówimy go nieco dokładniej w dalszej części
rozdziału) jest używany do skrócenia czasu wczytywania witryny
internetowej, która wolno działa. Varnish tworzy kopie w pełni
wygenerowanych stron WordPressa. Jeżeli odwiedzający witrynę wykona
żądanie dotyczące strony znajdującej się w buforze Varnisha, przekazana
zostanie kopia z bufora zamiast generowania nowej strony przez
WordPress.

Dostarczanie plików jednorodnych jest znacznie szybsze niż dynamiczne
wykonywanie kodu PHP. Dlatego Varnish może znacznie zwiększyć szybkość
działania witryny internetowej. Strona wymagająca 10 sekund na wczytanie
w wolnej konfiguracji WordPressa może być wczytana w ciągu sekundy,
jeśli jej kopia jest pobierana z bufora Varnisha. Wprawdzie 10-sekundowy
czas wczytywania strony jest nieakceptowalny, ale nadal zdarzają się
sytuacje, że trzeba czekać tak długo. Pierwsze wczytanie strony zabierze
wówczas 10 sekund. Strona wczytywana w administracyjnym panelu głównym
również będzie wymagała 10 sekund na wczytanie. Jeżeli kopia strony
zostanie z jakiegokolwiek powodu usunięta z bufora Varnisha, np. na
skutek jej uaktualnienia lub ze względu na brak wolnego miejsca w
buforze, pobranie nowej kopii tej strony będzie wymagało 10 sekund.

Varnish i podobne narzędzia sprawdzają się doskonale i mogą stanowić
cenny komponent platformy Twojej aplikacji. Trzeba jednak pamiętać, aby
takie usługi nie przykrywały problemów pojawiających się w źródle.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Zachowaj ostrożność, ponieważ większość znajdujących się w internecie wskazówek dotyczących przyśpieszenia działania witryny internetowej jest przeznaczona dla statycznych witryn. W tej książce mówimy o tworzeniu aplikacji internetowych za pomocą komponentów interaktywnych. Działanie dobrego serwera buforowania opiera się na obciążeniu serwera WWW poprzez zwolnienie zasobów procesora i pamięci, aby w ten sposób poprawić wydajność niebuforowanej strony internetowej.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Testowanie

Część procesu definiowania wydajności działania jest powiązana z
ustaleniem, jak szybko strona internetowa może być wczytana w
przeglądarce WWW. Wykorzystamy kilka różnych narzędzi do przetestowania
operacji wczytywania strony przez pojedynczego użytkownika, a także dla
wielu jednocześnie korzystających z niej użytkowników.

Do przeprowadzenia wszystkich testów w rozdziale została użyta nowa
kopia instalacji WordPressa, zawierająca jedynie motyw Twenty Thirteen i
pozbawiona wszystkich wtyczek. Gdy nie zaznaczyliśmy inaczej, serwerem
była minimalna wersja stosu zawierającego tylko Apache, MySQL i PHP.
Hosting witryny to serwer dedykowany działający pod kontrolą dystrybucji
CentOS 6 i posiadający następującą specyfikację sprzętową:

-   procesor Intel Xeon E3-1220
-   4 rdzenie o częstotliwości 3,1 GHz
-   12 GB pamięci DDR3 ECC RAM
-   dyski twarde 2 TB SATA wykorzystujące programową macierz RAID.

Co będzie testowane

Zanim przejdziemy do określenia jak testować, należy poświęcić chwilę na
ustalenie, co trzeba przetestować. Omówione w rozdziale narzędzia
testowania działają przez skierowanie przeglądarki WWW lub innego
narzędzia pod określony adres lub grupę adresów URL do przetestowania. W
tym miejscu powstaje pytanie, jak wybrać adres(y) URL do przetestowania.

Najłatwiejszą odpowiedzią byłoby przetestowanie wszystkiego, choć to nie
jest zbyt pomocne. Trzeba wiedzieć nie tylko, które strony są do
przetestowania, lecz także dlaczego dane strony powinny być
przetestowane. Mamy więc kilka kwestii, o których trzeba pamiętać
podczas testowania wydajności działania stron aplikacji.

Testowanie strony „statycznej” do jej użycia jako testu wydajności

Określenie statyczna nie oznacza tutaj statycznego pliku .html. Strona
powinna być wygenerowana przez WordPressa, przy czym należy wybrać
stronę typu „O nas” lub „Kontakt”, na której znajduje się jak najmniej
zmieniających się elementów. Wynik wczytywania strony statycznej pokaże,
jak szybko mogą być wczytywane strony w aplikacji. Jeżeli strony
statyczne są wczytywane wolno, najpierw należy poprawić wydajność tej
operacji, a dopiero później przejść do bardziej skomplikowanych stron.

Testowanie stron po wyłączeniu buforowania stron i akceleracji

W pierwszej kolejności należy potwierdzić sprawne działanie podstawowej
aplikacji WordPressa, a dopiero później przystąpić do testowania całej
platformy obejmującej CDN, odwrotne proxy i wszelkie inne mechanizmy,
które są używane w celu zapewnienia większej wydajności działania.
Jeżeli wykonasz 100 jednoczesnych żądań do strony w pełni korzystającej
z bufora, wykonanie pierwszego żądania może zabierać 10 sekund,
natomiast pozostałych 99 — tylko sekundę. Średni czas wczytywania strony
będzie wówczas wynosił 1,09 sekundy. Jednak jak wcześniej wspomnieliśmy,
10-sekundowe oczekiwanie na pierwsze wczytanie strony jest nie do
zaakceptowania i wskazuje na istnienie większego problemu w konfiguracji
rozwiązania.

Testowanie stron po włączeniu buforowania stron i akceleracji

Wyłącznie zewnętrznych mechanizmów akceleracji może pomóc w
zlokalizowaniu problemów dotyczących podstawowej aplikacji. Jednak testy
trzeba przeprowadzić również z włączonymi tego rodzaju usługami. Dzięki
temu będzie możliwe wyszukanie problemów z nimi związanych. Czasami
potrafią one spowolnić wydajność działania aplikacji.

Testowanie stron prototypowych

Niezależnie od rodzaju strony, który będzie najczęściej wykorzystywany
przez użytkowników aplikacji, należy go przetestować. Jeżeli działanie
aplikacji koncentruje się wokół niestandardowego typu postów, trzeba się
upewnić, że strony CPT działają sprawnie. Jeżeli w aplikacji duże
znaczenie ma konkretna operacja wyszukiwania, trzeba koniecznie
przetestować formularz wyszukiwania i stronę wyników.

Testowanie stron nietypowych

Wprawdzie należy poświęcić większość czasu na koncentrowanie się na
najczęstszych sposobach używania aplikacji, ale dobrym pomysłem jest
także przetestowanie nietypowych sposobów użycia aplikacji, zwłaszcza
jeśli istnieją powody do przypuszczenia, że kryją się tam pewne problemy
związane z wydajnością działania.

Testowanie grup adresów URL

Część z narzędzi omawianych w rozdziale (np. Siege i Blitz.io) pozwala
na podanie listy adresów URL. Dzięki przygotowaniu listy wszystkich
typów stron używanych przez użytkowników można znacznie lepiej zrozumieć
rodzaj ruchu sieciowego, który witryna internetowa będzie mogła
obsłużyć. Jeżeli spodziewasz się (lub wiesz na podstawie analizy), że 80
procent ruchu sieciowego dotyczy stron statycznych, a 20 procent stron
wyszukiwania, możesz przygotować listę adresów URL zawierającą osiem
stron statycznych i dwie strony wyszukiwania. W ten sposób podczas
testowania zasymulujesz podział 80/20. Jeżeli z testu wynika, że witryna
internetowa potrafi obsłużyć tysiąc odwiedzających na minutę, to jest
dość wiarygodny wskaźnik na możliwość faktycznego obsłużenia tysiąca
odwiedzających przez wdrożoną witrynę.

Testowanie adresów URL

Testowanie adresów URL w grupach pozwala na uzyskanie znacznie bardziej
rzeczywistych wyników, choć jednocześnie utrudnia wyśledzenie
określonych problemów związanych z wydajnością działania. Jeżeli czas
wczytywania strony statycznej wynosi poniżej sekundy, natomiast
wczytywanie strony wyników zabiera 10 sekund, zastosowanie omówionego
wcześniej podziału 80/20 oznacza średni czas wczytywania strony
wynoszący 2,8 sekundy. Jednak 10-sekundowe oczekiwanie na wczytanie
strony wyników może być nie do zaakceptowania. Jeżeli testujesz
pojedynczą stronę wyników wyszukiwania lub grupę podobnych stron
wyników, możesz znacznie lepiej zdiagnozować i usunąć wszelkie problemy
związane z wydajnością działania funkcji wyszukiwania w danej witrynie
internetowej.

Testowanie aplikacji z poziomu lokalizacji zewnętrznych dla serwera WWW

Omówione w rozdziale narzędzia powłoki mogą być uruchamiane z poziomu
tego samego serwera, w którym znajduje się witryna internetowa. Dobrym
rozwiązaniem jest uruchamianie tych narzędzi także z innych,
zewnętrznych serwerów, aby otrzymać w ten sposób znacznie bardziej
realne dane o czasie wczytywania strony, gdy trzeba uwzględnić ruch
sieciowy przychodzący do serwera i wychodzący z niego.

Testowanie aplikacji z poziomu lokalizacji wewnętrznych dla serwera WWW

Sensowne jest przeprowadzanie testów wydajności z wewnątrz serwera WWW.
W ten sposób można wyeliminować wszelkie efekty zewnętrznego ruchu
sieciowego, które mogą wpłynąć na wynik. Poza tym pomoże to w lepszym
zdiagnozowaniu problemów związanych z wydajnością działania, które mogą
występować w serwerze.

Każdy z wymienionych przykładów ma dobry odpowiednik, co jest kolejnym
potwierdzeniem, że każdą stronę witryny internetowej należy przetestować
w różnych sytuacjach, aby znaleźć problemy związane z wydajnością
działania. Bardzo duże znaczenie ma ustalenie, co będziesz próbował
przetestować, i podjęcie próby maksymalnego ograniczenia wpływu
czynników zewnętrznych na element, na którym się koncentrujesz.

Pasek debugowania w Chrome

Pasek debugowania w przeglądarce WWW Chrome to popularne wśród
projektantów aplikacji internetowych narzędzie, które może być używane
do analizy i debugowania kodu HTML, JavaScript i CSS w witrynach
internetowych. Karta Network pozwala również na wyświetlanie wszystkich
żądań przychodzących do witryny internetowej, udzielanych na nie
odpowiedzi i czasu potrzebnego na wykonanie każdego z tych żądań.

Podobne karty istnieją także w narzędziach dla programistów oferowanych
przez przeglądarki WWW Firefox i Microsoft Edge. W celu przetestowania
za pomocą paska debugowania w Chrome czasu wczytywania strony witryny
internetowej należy wykonać wymienione tutaj kroki:

1.  Uruchom Chrome.
2.  Kliknij menu Chrome, a następnie wybierz opcję Narzędzia/Narzędzia
    dla programistów.
3.  Kliknij kartę Network paska debugowania wyświetlanego w panelu
    dolnym.
4.  Przejdź na stronę, którą chcesz przetestować.
5.  Po otrzymaniu raportu informującego o wszystkich żądaniach
    wykonanych do serwera przewiń stronę do dołu, aby poznać całkowitą
    liczbę wszystkich żądań i ostateczny czas wczytywania strony.

Na rysunku 14.1 pokazaliśmy przykładowy pasek debugowania w Chrome po
wczytaniu witryny internetowej. Ostateczny raport ma postać komunikatu
podobnego do tutaj przedstawionego:

    19 requests | 35.7KB transferred | 1.42s (load: 1.16s, DOMContentLoaded: 1.10s)

[]

Rysunek 14.1. Karta Network paska debugowania przeglądarki WWW Chrome

W tym komunikacie mamy informacje o liczbie żądań, całkowitej liczbie
danych przekazanych do oraz z serwera, ostatecznym czasie wczytywania
strony, a także o czasie potrzebnym na wczytanie modelu DOM.

Akcja DOMContentLoaded jest wywoływana po wczytaniu całego kodu HTML
danej witryny internetowej, ale jeszcze przed zakończeniem wczytywania
obrazów, skryptów JavaScript lub arkuszy stylów. Dlatego czas podany dla
tej akcji będzie krótszy niż całkowity czas wczytania strony podany w
komunikacie wyświetlonym na pasku debugowania.

Pasek debugowania w Chrome pozwala na ustalenie jedynie przybliżonego
czasu wczytywania strony. Trzeba będzie wielokrotnie przeprowadzać wiele
ręcznych operacji wczytywania oraz zapisywać ich wyniki, aby otrzymać
dobrą średnią. Jednak pasek debugowania dostarcza użytecznych informacji
o czasie wczytywania poszczególnych plików i skryptów, co może być
użyteczne podczas wyszukiwania wąskich gardeł w obrazach i skryptach
witryny internetowej.

W trakcie testowania czasu wczytywania stron za pomocą paska debugowania
Chrome pierwsze wyświetlenie strony zwykle będzie odbywało się znacznie
wolniej niż kolejne. Ma to związek z buforowaniem przez przeglądarkę WWW
arkuszy CSS, skryptów JavaScript i obrazków. Ponadto buforowanie
stosowane po stronie serwera również będzie miało wpływ na czas
wyświetlenia strony. Pamiętaj o tym podczas testowania. O ile nie
sprawdzasz wydajności działania z włączonym buforem, powinieneś wyłączyć
buforowanie w przeglądarce WWW i na serwerze WWW.

Istnieje również możliwość użycia karty Audits paska debugowania Chrome
(lub opracowanych przez Google narzędzi PageSpeed,
https://developers.google.com/speed) w celu otrzymania podpowiedzi, jak
przyśpieszyć wydajność działania witryny internetowej. Na rysunku 14.2
pokazaliśmy przykład raportu wygenerowanego przez kartę Audits paska
debugowania przeglądarki WWW Chrome. W rozdziale omawiamy najważniejsze
narzędzia i metody związane z dostarczaniem wspomnianych podpowiedzi
przez audyt przeprowadzony za pomocą narzędzia PageSpeed.

[]

Rysunek 14.2. Karta Audits paska debugowania w przeglądarce WWW Chrome

Google oferuje również dla serwerów WWW Apache i Nginx moduły, które
automatycznie wykrywają i przeprowadzają pewne optymalizacje. Nawet
jeśli wolisz ręcznie zastosować się do pewnych zaleceń i podpowiedzi,
strona dokumentacji dla modułu PageSpeed
(https://www.modpagespeed.com/doc/) stanowi doskonałą kolekcję
najlepszych praktyk związanych z wydajnością działania witryny
internetowej.

Narzędzie Stan witryny WordPressa

W wydaniu WordPress 5.2 pojawiło się nowe narzędzie przeznaczone do
testowania i zgłaszania różnych problemów związanych z zapewnieniem
bezpieczeństwa oraz wydajnością działania. Dobrym rozwiązaniem jest
uruchamianie tego narzędzia w każdej witrynie internetowej, którą
zarządzasz. W ten sposób będzie można się upewnić, że oprogramowanie
serwera i WordPressa jest aktualne, a wszelkie moduły wymagane przez
serwer zostały włączone. Narzędzie Stan witryny (Site Health) w akcji
pokazaliśmy na rysunku 14.3.

[]

Rysunek 14.3. Narzędzie Stan witryny w WordPressie

Apache Bench

Używając przeglądarki WWW, można w przybliżeniu poznać czas wczytywania
strony internetowej dla jednego użytkownika, pod obciążeniem, jakie
występowało w serwerze w chwili przeprowadzania testu. Aby dowiedzieć
się więcej na temat sposobu działania serwera pod dużym obciążeniem,
konieczne jest wykorzystanie narzędzia testów wydajności, takiego jak
Apache Bench.

Pomimo nazwy, to narzędzie może być stosowane także w innych niż Apache
serwerach HTTP. Jego działanie polega na utworzeniu pewnej liczby
połączeń z witryną internetową i zarejestrowaniu średniego czasu
wczytania strony oraz innych informacji.

Instalacja Apache Bench

Narzędzie Apache Bench jest dostępne dla wszystkich dystrybucji systemu
Linux. W serwerach CentOS i Red Hat otrzymasz je po zainstalowaniu
pakietu httpd-tool. Jeżeli korzystasz z menedżera pakietów yum, pakiet
httpd-tool zostanie zainstalowany po wydaniu następującego polecenia:

    $ yum install httpd-tool

W serwerach Ubuntu narzędzie Apache Bench jest częścią pakietu
apache2-util. Jeżeli korzystasz z menedżera pakietów apt-get, pakiet
apache2-util zostanie zainstalowany po wydaniu następującego polecenia:

    $ apt-get install apache2-util

Narzędzie Apache Ben jest dostępne również dla Windows i powinno być
zainstalowane wraz z serwerem Apache. Dokładne informacje dotyczące
instalacji i uruchomienia Apache Bench w Windows zostały zamieszczone w
dokumentacji Apache dostępnej na stronie http://httpd.apache.
org/docs/current/platform/windows.html.

Uruchomienie Apache Bench

Pełna lista parametrów i opcji znajduje się w pliku głównym, a także w
witrynie internetowej Apache
(http://httpd.apache.org/docs/2.2/programs/ab.html). Polecenie
uruchamiające narzędzie to ab, a typowy przykład wywołania przedstawia
się następująco:

    $ ab -n 1000 -c 100 http://nazwa_domeny.pl/index.php

Dwa najważniejsze parametry polecenia ab to n i c. Wartością parametru n
jest liczba żądań, natomiast parametru c jest liczba jednoczesnych żądań
do wykonania. W przedstawionym przykładzie tysiąc całkowitych żądań
będzie wykonanych w paczkach po 100 jednoczesnych żądań.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeżeli na końcu nazwy domeny umieścisz ukośnik lub nie podasz nazwy pliku .php do wczytania, działanie Apache Bench może zakończyć się komunikatem błędu.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------

Wygenerowane przez narzędzie dane wyjściowe będą podobne do
przedstawionych poniżej (pokazują one wynik dla 100 jednoczesnych żądań
wykonanych do strony głównej domyślnej instalacji WordPressa działającej
w serwerze testowym).

    # ab -n 1000 -c 100 http://nazwa_domeny.pl/index.php

    This is ApacheBench, Version 2.3 <$Revision: 655654 $>

    Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/

    Licensed to The Apache Software Foundation, http://www.apache.org/

    Benchmarking nazwa_domeny.pl (be patient)

    Server Software:        Apache/2.2.15

    Server Hostname:        nazwa_domeny.pl

    Server Port:            80

    Document Path:          /

    Document Length:        251 bytes

    Concurrency Level:      100

    Time taken for tests:   8.167 seconds

    Complete requests:      1000

    Failed requests:        993

       (Connect: 0, Receive: 0, Length: 993, Exceptions: 0)

    Write errors:           0

    Non-2xx responses:      7

    Total transferred:      9738397 bytes

    HTML transferred:       9516683 bytes

    Requests per second:    122.44 [#/sec] (mean)

    Time per request:       816.740 [ms] (mean)

    Time per request:       8.167 [ms] (mean, across all concurrent requests)

    Transfer rate:          1164.40 [Kbytes/sec] received

    Connection Times (ms)

                  min  mean[+/-sd] median   max

    Connect:        0    0   0.4      0       2

    Processing:     3  799 127.4    826    1164

    Waiting:        2  714 113.7    729    1091

    Total:          3  799 127.4    826    1164

    Percentage of the requests served within a certain time (ms)

      50%    826

      66%    854

      75%    867

      80%    876

      90%    904

      95%    936

      98%    968

      99%    987

     100%   1164 (longest request)

Najważniejsza wartość, na którą trzeba tutaj zwrócić uwagę, to czas
wykonania żądania (Time per request). W przykładowym teście wartość ta
wyniosła 816,740 milisekund, czyli 0,817 sekundy. Oznacza ona, że jeśli
100 osób będzie jednocześnie odwiedzało witrynę internetową, serwer
będzie potrzebował 0,817 sekundy na przekazanie kodu HTML strony
głównej.

Istnieje jeszcze druga wartość Time per request oznaczona etykietą mean,
across all concurrent requests. W omawianym przykładzie jej wartość
wynosi 8,167 milisekund, czyli około 0,01 sekundy. Zwróć uwagę, że druga
wartość Time per request nie przedstawia czasu wczytywania dla jednego
żądania. Jednak na przestrzeni wielu testów ten współczynnik (średnia
czasu żądania podzielonego przez liczbę jednocześnie wykonywanych żądań)
pokazuje, jak dobrze serwer radzi sobie z obsługą ogromnej liczby
jednoczesnych użytkowników. Jeżeli ta średnia pozostaje na tym samym
poziomie pomimo zwiększania wartości parametru -c, oznacza to, że serwer
doskonale się skaluje. Natomiast znaczący wzrost wartości tej zmiennej
wskazuje na problem ze skalowaniem serwera.

Kolejna ważna wartość w wygenerowanym raporcie to liczba żądań na
sekundę (Requests per second). Czasami ta wartość jest bardziej
bezpośrednio związana z oszacowanym obciążeniem serwera. Możesz
wykorzystać rzeczywiste wartości „liczba żądań w ciągu dnia” lub „liczba
żądań na godzinę” z danych statystycznych witryny internetowej,
skonwertować je na wartość „liczba żądań na sekundę”, a następnie
porównać ją z wartością otrzymaną w raporcie. Można również zmienić
wartości parametrów n oraz c w celu dopasowania do oczekiwanych
warunków.

Testowanie za pomocą narzędzia Apache Bench

W tym miejscu przedstawiamy kilka podpowiedzi dotyczących testowania
witryny internetowej za pomocą Apache Bench.

1.  Narzędzie Apache Bench uruchamiamy z miejsca innego niż testowany
    serwer, ponieważ będzie ono korzystało z zasobów niezbędnych do
    działania serwera. Ponadto przeprowadzanie testów wydajności z
    zewnętrz dostarcza znacznie bardziej realistycznych informacji o
    czasie generowania poszczególnych stron oraz o czasie potrzebnym na
    przekazywanie danych przez sieć.

    Z drugiej strony uruchomienie Apache Bench w tym samym serwerze, w
    którym znajduje się witryna internetowa, powoduje wyeliminowanie z
    wyników wpływu opóźnienia sieci i pokazuje wydajność działania stosu
    niezależnie od większego internetu.

2.  Rozpocznij od małej liczby jednoczesnych połączeń, a następnie
    stopniowo ją zwiększaj. Jeżeli zaczniesz od testowania 100 tysięcy
    jednoczesnych połączeń, możesz usmażyć swój serwer lub testowany,
    bądź obydwa. Rozpocznij od przetestowania 100 połączeń, następnie
    200, dalej 500, później tysiąca, i stopniowo zwiększaj tę liczbę.
    Większe błędy lub wąskie gardła w serwerze i wydajności działania
    aplikacji mogą się ujawnić już przy zaledwie 100 połączeniach. Po
    zaliczeniu tych testów spróbuj przetestować aplikację z większą
    liczbą połączeń.

3.  Przeprowadź wiele testów. Wiele czynników będzie wpływało na wynik
    testów wydajności. Dwa testy nigdy nie będą dokładnie takie same,
    więc przeprowadzaj je na różnych stronach witryny internetowej, w
    różnych porach, w różnych warunkach, z poziomu różnych serwerów i
    położeń geograficznych. Dzięki temu otrzymasz znacznie bardziej
    rzeczywiste wyniki.

Użycie gnuplot do graficznego przedstawienia wyników wygenerowanych przez Apache Bench

Podczas uruchamiania narzędzia Apache Bench parametr -g może zostać
użyty do podania pliku danych wyjściowych, w których zostaną umieszczone
wyniki zapisane w formacie gnuplot. Następnie ten plik można wykorzystać
w skrypcie gnuplot do wygenerowania wykresu.

  ---- --------------------------------------------------------------------------------------------------------------
  []   Istnieje również możliwość użycia parametru -e do wskazania pliku danych wyjściowych w formacie CSV (Excel).
  ---- --------------------------------------------------------------------------------------------------------------

Wydanie przedstawionych tutaj poleceń pozwoli na przygotowanie gruntu do
przeprowadzania testów witryny internetowej i zapisywania ich wyników w
postaci formatu gnuplot.

    # mkdir benchmarks

    # mkdir benchmarks/data

    # mkdir benchmarks/graphs

    # ab -n 5000 -c 200 -g benchmarks/data/testing.tsv "http://nazwa_domeny.pl/"

Podsumowanie raportu dla tego testu wydajności zawiera m.in. następujące
dane:

    Requests per second:    95.00 [#/sec] (mean)

    Time per request:       2105.187 [ms] (mean)

Następnie trzeba zainstalować narzędzie gnuplot[1]. Po jego
zainstalowaniu można utworzyć kilka skryptów przeznaczonych do
generowania wykresów. W tym miejscu przedstawiliśmy zmodyfikowane
skrypty pochodzące z przykładów zaprezentowanych przez Brada Landersa w
poście bloga opublikowanym na stronie
http://www.bradlanders.com/2013/04/15/apache-bench-and-gnuplot-youre-probably-doing-it-wrong/.
Umieść je w katalogu /benchmark/.

Pierwszy fragment kodu powoduje wygenerowanie wykresu liniowego
pokazującego rozkład czasu wczytywania strony internetowej. Ten wykres
doskonale pokazuje liczbę żądań wczytania strony o określonych porach.
Kod wykresu możesz umieścić w pliku o nazwie plot.gp.

    # Dane wyjściowe zostaną umieszczone w pliku PNG

    set terminal png size 1024,768

    # Zdefiniowanie proporcji wykresu

    set size 1, 1

    # Nazwa pliku, w którym będzie zapisany wykres

    set output "graphs/sequence.png"

    # Tytuł wykresu

    set title "Test wydajności"

    # Miejsce umieszczenia legendy wykresu

    set key left top

    # Wyświetlenie linii wykresu na osi Y

    set grid y

    # Etykiety dla osi X

    set xlabel 'Żądania'

    # Etykiety dla osi Y

    set ylabel "Czas udzielenia odpowiedzi (ms)"

    # Jako ograniczniki mają być używane tabulatory, a nie spacje, które są stosowane domyślnie

    set datafile separator '\t'

    # Wygenerowanie wykresu

    plot "data/testing.tsv" every ::2 using 5 title 'Czas udzielenia odpowiedzi' with lines

    exit

Drugi wykres to wykres punktowy, pokazujący czas wykonywania żądania i
rozkład tego czasu w poszczególnych testach. Kod tego wykresu umieść w
pliku o nazwie plot2.gp.

    # Dane wyjściowe zostaną umieszczone w pliku PNG

    set terminal png size 1024,768

    # Zdefiniowanie proporcji wykresu

    set size 1, 1

    # Nazwa pliku, w którym będzie zapisany wykres

    set output "graphs/timeseries.png"

    # Tytuł wykresu

    set title "Test wydajności"

    # Miejsce umieszczenia legendy wykresu

    set key left top

    # Wyświetlenie linii wykresu na osi Y

    set grid y

    # Określenie, że serią danych dla osi X są informacje o czasie wykonywania żądania

    set xdata time

    # Określenie formatu *wejściowego*, informacje o czasie wykonywania żądania

    set timefmt "%s"

    # Określenie formatu *wyjściowego* dla etykiet dla osi X

    set format x "%S"

    # Etykiety dla osi X

    set xlabel 'Sekundy'

    # Etykiety dla osi Y

    set ylabel "Czas udzielenia odpowiedzi (ms)"

    # Jako ograniczniki mają być używane tabulatory, a nie spacje, które są stosowane domyślnie

    set datafile separator '\t'

    # Wygenerowanie wykresu

    plot "data/testing.tsv" every ::2 using 2:5 title 'Czas udzielenia odpowiedzi' with points

    exit

Aby dane testów wydajności zamienić na wykresy, należy wydać
przedstawione tutaj polecenia.

    # cd benchmark

    # gnuplot plot1.gp

    # gnuplot plot2.gp

Wynikiem ich wykonania będą wykresy, które przedstawiamy na rysunkach
14.4 i 14.5.

[]

Rysunek 14.4. Wykres wygenerowany przez skrypt zapisany w pliku plot1.gp

[]

Rysunek 14.5. Wykres wygenerowany przez skrypt zapisany w pliku plot2.gp

Dane w postaci graficznej mogą być bardzo pomocne. Przykładowo komunikat
podsumowania wskazuje wprawdzie na średni czas wczytywania strony
wynoszący 2105 milisekund, ale z wykresu jasno wynika, że większość
żądań została przetworzona w czasie krótszym niż sekunda, natomiast
pozostałe potrzebowały ok. 4,5 sekundy.

Możesz uznać, że dwusekundowy czas wczytywania jest akceptowalny,
natomiast czterosekundowy już nie. Opierając się na raporcie
podsumowania, można pomyśleć, że tak naprawdę ponad 30 procent
użytkowników będzie doświadczało czasu wczytywania wynoszącego ponad
cztery sekundy.

Siege

Siege to narzędzie, które podobnie jak Apache Benchmark, będzie
wykonywało jednoczesne żądania do testowanej witryny internetowej i
rejestrowało czas udzielania odpowiedzi. Raport wygenerowany przez Siege
sprawdza się doskonale podczas pokazywania najbardziej interesujących
informacji.

Omawiane narzędzie musi być zainstalowane ze źródeł. Najnowszą wersję
plików kodu źródłowego można pobrać z witryny internetowej Joe Dog
Software (https://www.joedog.org/siege-home/).

Spójrz na przykładowe polecenie wywołujące narzędzie Siegie.

    $ siege -b -c100 -d20 -t2M http://nazwa_domeny.pl

Parametr -b nakazuje przeprowadzenie testu wydajności. Z kolei parametr
-c100 wymaga 100 jednoczesnych użytkowników. Parametr -d20 określa, że
średni czas uśpienia między wczytywaniem strony dla poszczególnych
użytkowników wynosi 20 sekund. Natomiast parametr -t2M wskazuje, że test
wydajności ma być przeprowadzany przez dwie minuty. Istnieje również
możliwość wyrażenia czasu w sekundach, np. -t30S, oraz w godzinach, np.
-t1H.

Oto przykładowe dane wyjściowe wygenerowane przez narzędzie Siege.

    ** Preparing 100 concurrent users for battle.

    The server is now under siege...

    Lifting the server siege...      done.

    Transactions:             1160 hits

    Availability:                 100.00 %

    Elapsed time:                 119.29 secs

    Data transferred:               9.53 MB

    Response time:                  0.11 secs

    Transaction rate:               9.72 trans/sec

    Throughput:                     0.08 MB/sec

    Concurrency:                    1.05

    Successful transactions:        1160

    Failed transactions:               0

    Longest transaction:            0.26

    Shortest transaction:           0.09

W omawianym przykładzie 100 użytkowników wykonało 1160 żądań do serwera,
a średni czas udzielenia odpowiedzi wyniósł 0,11 sekundy. Serwer działał
przez 100 procent czasu, a udzielenie najdłuższej odpowiedzi trwało 0,26
sekundy.

W3 Total Cache

Istnieje kilka wtyczek dla WordPressa pomagających w skonfigurowaniu
narzędzi, których celem jest zwiększenie wydajności działania witryny
internetowej WordPressa. Jedną z wtyczek tego rodzaju jest W3 Total
Cache. Oferuje ona praktycznie każdą z omówionych tutaj metod
zwiększenia wydajności działania witryny internetowej.

Frederick Townes, założyciel Mashable i główny programista W3 Total
Cache, jest przekonany, że optymalizacja WordPressa powinna być
przeprowadzana jak najbliżej podstawowej aplikacji WordPressa (źródła)
na ile to możliwe.

Jedno wiemy na pewno — wrażenia odbierane przez użytkownika są równie
ważne jak treść strony internetowej; można stwierdzić, że idą w parze.
Aby witryna internetowa lub aplikacja mogły w pełni osiągnąć swój
potencjał, bardzo duże znaczenie ma zapewnienie harmonii przez stos,
aplikację i przeglądarkę WWW. W przypadku WordPressa można znacznie
ułatwić to zadanie za pomocą wtyczki W3 Total Cache.

W przypadku witryn internetowych rzadziej odwiedzanych lub zawierających
niewielką ilość treści dynamicznej zdefiniowanie najczęściej stosowanych
ustawień w W3 Total Cache to wszystko, co trzeba zrobić, aby umożliwić
skalowanie aplikacji. Natomiast w pozostałych witrynach internetowych
trzeba będzie oddzielnie zaimplementować pewne metody oferowane przez W3
Total Cache i dostosować je do potrzeb określonej aplikacji. Ogólnie
rzecz biorąc, W3 Total Cache sprawdza się doskonale, zapewniając
bezproblemowe współdziałanie wszystkich technik implementowanych przez
to narzędzie. Dlatego dobrym pomysłem jest wykorzystanie W3 Total Cache
w celu dostosowania ustawień do własnych potrzeb zamiast użycia
rozwiązania zewnętrznego dla wtyczki, które może powodować konflikty z
wtyczką. W tym podrozdziale przedstawiamy typową konfigurację W3 Total
Cache, a także pokrótce omawiamy wybrane ogólne techniki pracy.

Wtyczkę W3 Total Cache można pobrać z repozytorium wtyczek
WordPress.org. Po zainstalowaniu wtyczki w administracyjnym panelu
głównym pojawi się menu Performance. Zwykle trzeba uaktualnić
uprawnienia różnych katalogów i plików w instalacji WordPressa, aby
wtyczka W3 Total Cache mogła działać. Wyświetli ona konkretne komunikaty
pomagające w przeprowadzeniu konfiguracji, po zakończeniu której będzie
można włączyć różne narzędzia dostarczone wraz z wtyczką.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Wtyczka W3 Total Cache jest dostępna zupełnie bezpłatnie w repozytorium wtyczek WordPress.org. Jednak konieczne będzie wykupienie usługi CDN, aby móc wykorzystać jej funkcje związane z siecią CDN. Ponadto twórcy wtyczki (https://www. boldgrid.com/w3-total-cache/) oferują poprzez wymienioną witrynę internetową różne usługi w zakresie konfiguracji i pomocy technicznej.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Aby włączyć narzędzia, z których chcesz skorzystać, w menu wtyczki W3
Total Cache przejdź na stronę General Settings. Odszukaj pole wyboru
Enable w sekcjach „Page Cache”, „Minify”, „Database Cache”, „Object
Cache” i „Browser Cache”. Następnie zaznacz w nich to pole wyboru i
kliknij przycisk Save All Settings, jak pokazujemy na rysunku 14.6.

[]

Rysunek 14.6. Zaznaczenie pola wyboru Enable dla każdej techniki
wydajności działania, która ma zostać użyta

Z reguły będziesz używać domyślnych i zalecanych ustawień dla wszystkich
narzędzi oferowanych przez W3 Total Cache. Konkretne ustawienia zależą
od wymagań aplikacji, konfiguracji hostingu, a także od sposobu pracy
użytkowników z aplikacją. Dostępnych jest wiele ustawień, nie będziemy
ich tutaj omawiać, a jedynie wspomnimy o kilku najważniejszych.

Ustawienia Page Cache

Bufor strony (page cache) działa zgodnie ze swoją nazwą: buforuje całą
stronę internetową po jej wygenerowaniu. Jeśli użytkownik odwiedza
witrynę internetową, gdy w buforze znajduje się aktualnie wybrana
strona, przekazany będzie statyczny plik HTML zamiast generowania strony
za pomocą PHP i WordPressa. Natomiast jeśli bufor nie zawiera danej
strony lub jest ona nieaktualna, stronę trzeba będzie wczytać w
standardowy sposób poprzez WordPressa.

Podobnie jak w przypadku serwera WWW, takiego jak Nginx i Apache,
udostępnianie statycznego pliku HTML odbywa się znacznie szybciej niż
dynamicznego pliku PHP. Udostępnianie buforowanych plików pozwala
zupełnie uniknąć wywołań do bazy danych oraz obliczeń wymaganych podczas
wykonywania dynamicznych skryptów PHP. Takie rozwiązanie również
wzmacnia Twój stos sieciowy, który od poziomu systemu operacyjnego do
poziomu serwera WWW został zaprojektowany w celu szybkiego przekazywania
plików.

Każda wizyta użytkownika zakończona dostarczeniem statycznego pliku HTML
zamiast dynamicznego generowania strony w PHP zapewnia oszczędność
pewnej ilości pamięci RAM i czasu procesora. Gdy dostępna będzie większa
liczba zasobów, nawet niebuforowane lub niemożliwe do buforowania strony
będą wczytywane znacznie szybciej. Dlatego buforowanie może znacznie
przyśpieszyć wczytywanie stron witryny internetowej. Jest to podstawowa
technika pozwalająca na zwiększenie szybkości udostępniania treści
witryn internetowych WordPressa.

W menu Performance na stronie Page Cache zwykle będziesz włączać
wymienione tutaj opcje w sekcjach „General: Cache front page”, „Cache
feeds”, „Cache SSL (https) requests”, „Cache 404 (not found) pages” i
„Don’t cache pages for logged in users”. Spójrz na rysunek 14.7.

[]

Rysunek 14.7. Sekcja General ustawień wtyczki W3 Total Cache

Pole wyboru Don’t cache pages for logged in users jest bardzo ważną
opcją do zaznaczenia, ponieważ zalogowani użytkownicy bardzo często mają
dostęp do informacji poufnych, które nie powinny trafić do bufora. W
najlepszym przypadku będziesz mógł się pozbyć przypadkowego wyświetlania
buforowanego komunikatu w stylu „Witaj, Janek” w prawym górnym rogu
witryny internetowej, który pojawia się użytkownikom innym niż Janek. W
najgorszym przypadku ujawnisz informacje o Janku, np. jego prywatny
adres e-mail.

Dlatego pełne buforowanie strony dla zalogowanych użytkowników zwykle
będzie prowadziło do problemów. Inne techniki w zakresie buforowania,
które omawiamy w dalszej części rozdziału, wciąż mogą pomóc w
zwiększeniu szybkości wczytywania stron internetowych dla zalogowanych
użytkowników.

Kolejną opcją wartą poznania jest możliwość wykluczania z bufora
określonych stron, ścieżek dostępu i adresów URL. W polu Advanced
znajduje się pole tekstowe zatytułowane Never cache the following pages
(zobacz rysunek 14.8). Umieszczone w nim strony, ścieżki dostępu i
adresy URL będą ignorowane przez bufor stron, a tym samym generowane
podczas każdej operacji wczytywania strony. Należy umieszczać po jednym
ciągu tekstowym adresu URL w wierszu, dozwolone jest stosowanie wyrażeń
regularnych.

[]

Rysunek 14.8. Sekcja Never cache the following pages w ustawieniach
buforowania wtyczki W3 Total Cache

Przykładami stron najczęściej wykluczanych z bufora są strony
finalizacji zamówienia, logowania, nieoparte na JavaScripcie formularze
kontaktowe, adresy URI API oraz wszelkie inne, które powinny być
generowane dynamicznie podczas każdego wczytywania.

Minimalizacja

Minimalizacja to proces polegający na usunięciu niepotrzebnych białych i
innych znaków z plików kodu źródłowego, najczęściej to pliki JavaScriptu
i CSS. To pozwala na zmniejszenie wielkości tych plików przekazywanych
przeglądarce WWW. Mniejsza wielkość pliku przekłada się na krótszy czas
wczytywania strony.

Prawdopodobnie spotkałeś się już z plikiem takim jak jquery.min.js,
który jest zminimalizowaną wersją biblioteki jQuery. Wtyczka W3 Total
Cache będzie automatycznie minimalizowała dla Ciebie wszystkie pliki CSS
i JS. Istnieje również możliwość minimalizacji plików HTML (przede
wszystkim umieszczonych w buforze), co pozwala skrócić nieco czas
wczytywania strony.

Minimalizację warto stosować w produkcyjnych witrynach internetowych.
Natomiast podczas pracy nad witryną lepiej wyłączyć minimalizację,
ponieważ ułatwi to debugowanie plików CSS i JavaScript.

Buforowanie bazy danych

Wtyczka W3 Total Cache oferuje możliwość buforowania bazy danych. To
spowoduje umieszczenie wyników wykonywania zapytań SELECT w pliku bufora
(lub też w magazynie danych działającym w pamięci). W przypadku
powtarzających się zapytań bazy danych wynik będzie pobierany z bufora,
co pozwoli uniknąć konieczności faktycznego wykonania operacji w bazie
danych. Trzeba pamiętać, że dostęp do bazy danych może odbywać się za
pomocą zupełnie innej usługi, co dodatkowo przyczynia się do
zmniejszenia wydajności działania aplikacji.

Jeżeli serwer bazy danych został uruchomiony w dysku SSD (solid state
drive) lub w innym rodzaju buforowania zastosowanego w warstwie MySQL,
buforowanie bazy danych za pomocą W3 Total Cache może nie poprawić
wydajności działania, a nawet (delikatnie mówiąc) mieć na nią negatywny
wpływ. Dlatego upewnij się o przeprowadzaniu testów wydajności przed i
po włączeniu buforowania bazy danych, aby sprawdzić, czy ta technika
pomaga witrynie internetowej. Przeanalizuj też dziennik zdarzeń wolno
wykonywanych zapytań i wyszukaj te, które można zmodyfikować i poprawić
ich wydajność działania. Pamiętaj, że buforowanie skaluje serwer; nie
pomoże w magiczny sposób podczas wolno wykonywanych zapytań lub kodu.

Jeżeli odkryjesz, że wykonanie pewnych zapytań wymaga naprawdę dużo
czasu, możesz je pojedynczo buforować za pomocą WordPressa lub innych
technik buforowania fragmentów, które omówimy w dalszej części
rozdziału.

Buforowanie obiektów

Buforowanie obiektów jest podobne do buforowania bazy danych, przy czym
reprezentacje obiektów PHP są przechowywane w buforze zamiast w postaci
niezmodyfikowanych wyników MySQL. Podobnie jak w przypadku buforowania
bazy danych, buforowanie obiektów czasami może spowolnić witrynę
internetową zamiast przyśpieszyć jej działanie. Użycie trwałego obiektu
bufora (więcej informacji na jego temat przedstawiamy w dalszej części
rozdziału) prawdopodobnie pozwoli na zwiększenie wydajności działania
witryny internetowej. Upewnij się o przeprowadzeniu testów wydajności
przed i po skonfigurowaniu buforowania obiektów.

Buforowanie obiektów może prowadzić do znanych problemów z niektórymi
wtyczkami i zadaniami wykonywanymi w WordPressie. Wprawdzie jest to
potężne narzędzie pozwalające na przyśpieszenie witryny internetowej,
ale jednocześnie może wymagać czasu na modyfikację działających na
niskim poziomie skryptów, które wykorzystają buforowanie obiektów do
pracy z wtyczkami i kodem aplikacji.

Sieć CDN

Sieć CDN to usługa dostarczania plików statycznych — najczęściej są to
obrazy, skrypty JavaScript i arkusze stylów CSS — z jednego lub więcej
serwerów umieszczonych w różnych regionach geograficznych. Ma to na celu
optymalizację operacji dostarczania plików statycznych. Dlatego zamiast
je wczytywać z tego samego serwera, który zajmuje się również
generowaniem stron PHP witryny internetowej, pliki statyczne będą
pochodziły z serwera CDN znajdującego się najbliżej użytkownika. Nawet
jeśli używasz własnego serwera jako CDN, nadal możesz skrócić czas
wczytywania stron, ponieważ przeglądarka WWW będzie mogła w tym samym
czasie wczytywać stronę PHP i pliki statyczne — do tych operacji zostaną
użyte oddzielne połączenia.

Wtyczka W3 Total Cache pomaga zintegrować witrynę internetową z wieloma
najpopularniejszymi sieciami CDN. Zapewnia możliwość przekazywania do
serwera CDN wszelkich plików multimedialnych, statycznych plików
skryptów i plików buforów stron. Potrafi również automatycznie
przekierowywać adresy URL witryny do serwera CDN i, co najważniejsze,
usuwać zmodyfikowane pliki w obsługujących tę funkcjonalność serwerach
CDN.

Kompresja GZIP

Kompresja GZIP to kolejna elegancka sztuczka, która bardzo często
pozwala na zwiększenie wydajności działania witryny internetowej. W
efekcie następuje poświęcenie czasu przetwarzania (w trakcie kompresji
plików) w celu skrócenia czasu pobierania (ponieważ pliki będą
mniejsze). Przeglądarka WWW rozpakuje pliki po ich otrzymaniu. Czas
zaoszczędzony podczas pobierania mniejszych plików zwykle rekompensuje
czas potrzebny na ich kompresję i rozpakowanie. Oczywiście podczas
używania wtyczki W3 Total Cache kompresja jest przeprowadzana
jednokrotnie, tylko podczas tworzenia bufora.

Podobnie jak podczas stosowania innych technik optymalizacji, także w
przypadku kompresji bardzo duże znaczenie ma przeprowadzanie testów
wydajności przed i po włączeniu kompresji. Dzięki temu będzie można
sprawdzić, czy witryna internetowa faktycznie odnosi korzyść z tej
techniki optymalizacji.

Hosting

Zmiana usługi hostingu to zdecydowanie jedna z najlepszych rzeczy, którą
można zrobić w celu poprawienia wydajności działania aplikacji
WordPressa. Większa ilość mocy procesora i pamięci RAM potrafi zwiększyć
szybkość działania PHP, MySQL i serwera WWW. Sporo osób będzie
ekscytowało się optymalizacją kodu za pomocą technik buforowania
mających na celu zwiększenie wydajności działania aplikacji
internetowej, ignorując zupełnie fakt, że zwykła zmiana usługi hostingu
lub jej parametrów może poprawić wydajność.

Oczywiście zachęcamy do stosowania wszystkich omówionych w rozdziale
technik, o ile są one dostępne, a budżet na to pozwala. Jedną z
najwcześniej podejmowanych decyzji, prawdopodobnie jeszcze nawet przed
rozpoczęciem tworzenia kodu, jest ustalenie usługi hostingu
odpowiedzialnej za obsługę ukończonej aplikacji internetowej.

Nasze rekomendacje w tym zakresie zostały zamieszczone w towarzyszącej
książce witrynie internetowej. W tym podrozdziale przedstawiamy różne
rodzaje hostingu, które warto rozważyć.

Hosting przygotowany z myślą o WordPressie

Gdy platforma WordPress zyskała większą popularność w zakresie tworzenia
witryn internetowych, firmy oferujące usługi hostingowe zaczęły
przygotowywać rozwiązania skonfigurowane specjalnie do uruchamiania
witryn internetowych WordPressa. Pierwszymi były Page.ly, Zippykid, WP
Engine i SiteGound.

Hosting przeznaczony dla WordPressa oferuje zarządzane środowiska z
buforowaniem po stronie serwera. Pracownicy takiej firmy mają znacznie
większą wiedzę o WordPressie niż pracownicy typowej firmy oferującej
usługi hostingowe.

Panele kontrolne dla takich usług hostingowych są podobne do planów
hostingu współdzielonego, przy czym możliwości w zakresie modyfikowania
konfiguracji są ograniczone. Na plus trzeba zaliczyć to, że taki hosting
zwykle ma skonfigurowane buforowanie, doskonale radzi sobie z
zarządzaniem spamem i atakami typu DoS (denial of service), a także
pozwala na szybkie skalowanie aplikacji, gdy wzrasta obciążenie. Z kolei
wadą jest to, że ograniczone możliwości w zakresie konfiguracji
będąproblemem dla niektórych aplikacji, a koszt samego rozwiązania może
być wysoki w przypadku ogromnych witryn.

Utworzenie własnego serwera

Alternatywą dla hostingu przeznaczonego specjalnie dla aplikacji
WordPressa jest przygotowanie własnego serwera w postaci fizycznego
komputera lub usługi wykupionej w chmurze.

W przypadku rozwiązań w postaci dedykowanych serwerów fizycznych
popularnym wyborem jest Rackspace, a firma 1and1 oferuje potężny sprzęt
w atrakcyjnych cenach. Z kolei w przypadku rozwiązań w chmurze popularna
jest usługa Amazon EC2, a jej znacznie atrakcyjniejszą pod względem
kosztów alternatywą jest oferta firmy DigitalOcean.

Niezależnie od wybranego rozwiązania trzeba samodzielnie zdefiniować
serwer WWW, zainstalować PHP i MySQL, zarządzać konfiguracją DNS, a
także zajmować się innymi zadaniami wymaganymi przez serwer. W
zależności od potrzeb i sytuacji może to być dobre lub złe. Jeżeli
potrzebujesz konkretnej konfiguracji dla aplikacji, będziesz zmuszony do
przygotowania własnego serwera. Z drugiej strony czas lub pieniądze
związane z kosztami administrowania serwerem mogą być znacznie lepiej
wykorzystane.

Trzeba koniecznie poznać własne ograniczenia w zakresie administracji
serwerem. Przykładowo Jason ma ogromne doświadczenie w konfigurowaniu
serwerów WWW, takich jak Apache, a także w konfigurowaniu i
konserwowaniu PHP i MySQL. Z drugiej strony ma niewielkie doświadczenie
w zarządzaniu zaporami sieciowymi w sposób pozwalający na unikanie
ataków typu DoS, a także w konfiguracji mechanizmu równoważenia
obciążenia w wielu serwerach. Powinieneś zdecydować się na usługę
hostingu i opcję, która najlepiej współdziała z Twoimi mocnymi i słabymi
stronami.

Przygotowanie własnego serwera i uzyskanie dziesięciokrotnie większej
wydajności za 0,1 ceny serwera współdzielonego u dostawcy usług
hostingowych wydaje się dobrym rozwiązaniem. Gdy jednak będziesz musiał
o godzinie trzeciej nad ranem zmagać się z obroną serwera przed
zautomatyzowanymi atakami z zagranicy, miesięczna opłata za zarządzanie
hostingiem nie będzie się wydawać wygórowana.

  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Najlepsze praktyki związane z tworzeniem i działaniem serwerów WWW oraz konfiguracją różnych narzędzi buforowania wspomagających te serwery zmieniają się na przestrzeni czasu. Ponadto konkretne wskazówki będą zależały od użytego serwera, wersji dystrybucji systemu Linux, zainstalowanych narzędzi, a także od specyfiki samej aplikacji. Zapoznanie się z informacjami przedstawionymi w dalszej części rozdziału oraz ze wskazanymi artykułami umożliwi poznanie mechanizmów działania omawianych technik. Jeżeli zdecydujesz się na implementację danej techniki we własnym serwerze, spróbuj znaleźć w internecie wiarygodne informacje, przewodnik lub artykuł, jak najbardziej aktualne i odpowiadające Twoim potrzebom.
  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Poniżej omawiamy kilka najczęściej spotykanych konfiguracji w serwerach
działających w systemach Linux i zawierających uruchomioną platformę
WordPress. Szczegóły związane z konfiguracją poszczególnych rozwiązań
nieustannie się zmieniają. Postaraliśmy się zamieścić łącza do
najnowszych dostępnych w internecie informacji i artykułów.

Konfiguracja serwera Apache

Jest to obecnie najpopularniejsze oprogramowanie serwera WWW, którego
instalacja jest niezwykle łatwa w praktycznie każdej dystrybucji systemu
Linux.

Po zainstalowaniu oprogramowania Apache można zwykle wprowadzić kilka
zmian konfiguracyjnych, które pozwolą na optymalizację Apache do obsługi
witryn internetowych WordPressa:

-   Wyłączenie niepotrzebnych modułów wczytywanych domyślnie.
-   Skonfigurowanie Apache do użycia prefork lub współbieżności w
    zależności od potrzeb. Dobre omówienie poszczególnych opcji
    zamieszczono w poście bloga zatytułowanym Understanding Apache 2 MPM
    (worker vs prefork), który został opublikowany na stronie
    https://www.garron. me/en/blog/apache2-mpm-worker-prefork-php.html.
    Prefork (opcja domyślna) zwykle sprawdza się najlepiej w przypadku
    aplikacji WordPressa.
-   Jeżeli używasz modułu Apache Prefork Multi-Processing Module
    (domyślnie), skonfiguruj wartości StartServers, MinSpareServers,
    MaxSpareServers, ServerLimit, MaxClients i MaxRequestsPerChild.
-   Jeżeli używasz modułu Multi-Processing Module, skonfiguruj wartości
    StartServers, MaxClients, MinSpareThreads, MaxSpareThreads,
    ThreadsPerChild i MaxRequestsPerChild.

Są to ustawienia, na które trzeba zwrócić szczególną uwagę podczas
optymalizacji Apache dla używanego sprzętu i uruchomionej aplikacji.
Mają one swoje odpowiedniki w innych serwerach WWW, a stojące za nimi
koncepcje powinny być możliwe do zastosowania dla każdego serwera WWW, w
którym została uruchomiona platforma WordPress.

W przedstawionym tutaj omówieniu poszczególnych opcji przyjęliśmy
założenie, że w przypadku Apache częściej jest używany moduł Prefork
Multi-Processing Module.

MaxClients

Gdy serwer Apache przetwarza żądanie udostępnienia pliku lub skryptu
PHP, tworzy proces potomny przeznaczony do obsługi tego żądania. Wartość
MaxClinets w konfiguracji Apache wskazuje serwerowi maksymalną liczbę
procesów potomnych możliwych do utworzenia.

Po osiągnięciu tej liczby Apache będzie kolejkować następne żądania
przychodzące. Dlatego jeśli wartość MaxClients jest niska, odwiedzający
witrynę internetową będą musieli długo czekać na wczytanie strony, co ma
związek z oczekiwaniem, aż Apache uruchomi proces przeznaczony do
obsługi danego żądania.

Jeżeli wartość MaxClients będzie zbyt duża, Apache wykorzysta całą
dostępną pamięć RAM i zacznie korzystać z pamięci wirtualnej na dysku
twardym, która jest dużo, dużo wolniejsza niż fizyczna pamięć RAM. W
takiej sytuacji odwiedzający witrynę internetową będą musieli długo
czekać na wczytanie strony, co ma związek z obsługiwaniem żądań za
pomocą wolnej pamięci wirtualnej.

Pomijając aspekt szybkości działania, pamięć wirtualna wymaga również
większej mocy obliczeniowej procesora, ponieważ dane są przenoszone
między pamięcią RAM i dyskiem twardym, co prowadzi do ogólnego
zmniejszenia wydajności działania. Gdy serwer zacznie działać w takim
trybie (nosi on nazwę thrashing), sytuacja może bardzo szybko wymknąć
się spod kontroli i doprowadzić do zablokowania serwera.

Dlatego bardzo duże znaczenie ma wybranie odpowiedniej wartości
MaxClients. Aby ją ustalić dla danego serwera Apache, trzeba zacząć od
określenia ilości pamięci przeznaczonej dla serwera (zwykle to
maksymalna możliwa ilość po odjęciu pamięci niezbędnej dla serwera bazy
danych MySQL i pozostałych uruchomionych usług). Następnie tę wartość
trzeba podzielić przez ilość pamięci, którą średnio zabiera proces
Apache.

Nie istnieje dokładny sposób pozwalający na ustalenie ilości pamięci
używanej przez usługi lub zabieranej przez poszczególne procesy.
Najlepsze podejście polega na ustawieniu początkowo wartości
konserwatywnej, a następnie jej modyfikacji w czasie rzeczywistym.

Polecenie top -M powoduje wyświetlenie wielu informacji, m.in. o
pamięci: całkowita ilość pamięci w komputerze, pozostała ilość wolnej
pamięci oraz ilość pamięci używanej przez aktywne procesy. W naszym
serwerze testowym mamy dostępne 11,7 GB pamięci, z której 10,25 GB jest
wolne. Jeżeli chcemy zastosować podział pamięci „pół na pół” między
Apache i MySQL (to kolejne założenie, które należy przetestować w
aplikacji i wprowadzić odpowiednią korektę), Apache i MySQL można
przydzielić po 4,5 GB pamięci, a pozostałe 2,7 GB przeznaczyć dla
pozostałych usług uruchomionych w serwerze.

Na rysunku 14.9 pokazaliśmy przykładowe dane wyjściowe wygenerowane
przez polecenie top. W celu ustalenia ilości pamięci wymaganej przez
Apache dla poszczególnych procesów należy polecenie top -M wydać w
serwerze znajdującym się pod jego normalnym obciążeniem. Następnie
trzeba wyszukać procesy httpd. Jeżeli zauważysz, że aplikacja używa
około 20 MB dla każdego z tych procesów, możesz podzielić 4,5 GB (czyli
mniej więcej 4600 MB) przez 20 MB, a otrzymasz liczbę 230. Ta wartość
oznacza, że dany serwer, mając do dyspozycji 4,5 GB pamięci RAM,
powinien być w stanie obsłużyć 230 użytkowników.

[]

Rysunek 14.9. Użycie polecenia top do ustalenia ilości wolnej pamięci

Podczas definiowania wartości MaxClient tę samą wartość przypisz
ServerLimit. Druga z wymienionych wartości przypomina pierwszą, ale może
być zmieniona tylko podczas ponownego uruchomienia Apache. Z kolei
wartość MaxClients można zmieniać za pomocą skryptów podczas działania
Apache, choć zwykle się tego nie robi. Teoretycznie wartość ServerLimit
mogłaby być większa niż MaxClients i pewne procesy mogłyby zwiększać
bądź zmniejszać wartość MaxClients podczas działania serwera Apache.

MaxRequestPerChild

Każdy tworzony przez Apache proces potomny będzie obsługiwał żądania
jedno po drugim. Jeżeli wartością MaxRequestsPerChild jest 0, te procesy
potomne nigdy nie będą zamykane, co jest dobrym rozwiązaniem, ponieważ
zmniejsza obciążenie związane z uruchamianiem nowych procesów potomnych.
Może to być jednocześnie złym rozwiązaniem, jeśli w aplikacji znajduje
się wyciek pamięci. Przypisanie MaxRequestsPerChild bardzo dużej
wartości, np. 1000 lub 2000, jest dobrym kompromisem — nowe procesy nie
będą zbyt często zamykane i ponownie uruchamiane, a ewentualny wyciek
pamięci zostanie powstrzymany, gdy proces potomny zostanie wreszcie
zakończony.

KeepAlive

Domyślnie ustawienie KeepAlive w serwerze Apache jest wyłączone, co
oznacza zakończenie połączenia po przekazaniu pliku przeglądarce WWW
klienta. Oddzielne połączenie jest nawiązywane i zrywane dla każdego
pliku żądanego przez przeglądarkę WWW. Ponieważ pojedyncza strona
internetowa może mieć powiązanych ze sobą wiele plików (obrazki, skrypty
JavaScript i style CSS), więc zachowanie domyślne prowadzi do wielu
niepotrzebnych operacji nawiązywania i zakończenia połączenia.

Po włączeniu opcji KeepAlive serwer Apache będzie pozostawiał otwarte
pierwsze połączenie pochodzące z przeglądarki WWW, a wszystkie kolejne
żądania w tej samej sesji przeglądarki WWW będą obsługiwane przez to
połączenie. Jeżeli przez pewien czas w trakcie sesji przeglądarka WWW
nie wykona żadnych żądań, połączenie zostanie zerwane. Wykorzystanie
pojedynczego połączenia może prowadzić do znacznego wzrostu wydajności
działania niektórych witryn internetowych, zwłaszcza jeśli ich strony
zawierają wiele oddzielnych obrazów, skryptów JavaScript i stylów CSS
(skrypty JavaScript i style CSS powinieneś minimalizować do postaci
pojedynczego pliku).

Z drugiej jednak strony włączenie omawianej opcji wymaga większej ilości
pamięci RAM, ponieważ każde połączenie będzie zabierało pewną ilość
pamięci przeznaczonej do obsługi poszczególnych żądań.

Dobrze jest poeksperymentować z włączonym ustawieniem KeepAlive. Jeżeli
się na to zdecydujesz, powinieneś zmienić tę wartość z domyślnych 15
sekund na znacznie mniejszą, np. dwie, trzy sekundy, bądź jeszcze
bliższą rzeczywistej ilości czasu potrzebnej na wczytanie jednej strony
internetowej danej witryny. Dzięki temu pamięć RAM będzie zwalniana
znacznie wcześniej.

Po włączeniu opcji KeepAlive prawdopodobnie trzeba będzie zmodyfikować
wartości MaxClients i MaxRequestsPerChild. Skoro każdy proces będzie
zabierał większą ilość pamięci niezbędną dla otwartego połączenia,
konieczne może okazać się zmniejszenie wartości MaxClients, aby uniknąć
użycia całej dostępnej pamięci RAM. Ponieważ każde połączenie jest
liczone jako jedno żądanie w odniesieniu do MaxRequestsPerChild, należy
zmniejszyć tę wartość ze względu na mniejszą liczbę żądań wykonywanych w
trakcie każdej wizyty.

Oto lista dobrych artykułów dotyczących optymalizacji serwera Apache:

-   Apache Performance Tuning
    (http://httpd.apache.org/docs/2.4/misc/perf-tuning.html)
-   Apache MPM Prefork
    (http://httpd.apache.org/docs/2.4/mod/prefork.html)
-   Apache MPM Worker (http://httpd.apache.org/docs/2.4/mod/worker.html)
-   Optimize Apache for WordPress, którego autorem jest Drew Strojny
    (https://thethemefoundry. com/blog/optimize-apache-wordpress/)
-   Apache Optimization: KeepAlive On or Off? opublikowany w serwisie
    Abdussamad (https://
    abdussamad.com/archives/169-Apache-optimization:-KeepAlive-On-or-Off.html).

Konfiguracja serwera Nginx

Popularną i obecnie zyskującą coraz większe zainteresowanie alternatywą
dla serwera Apache jest Nginx. Największą zaletą Nginx jest
asynchroniczność, podczas gdy Apache to serwer WWW oparty na procesie. W
praktyce oznacza to, że gdy jednocześnie wielu klientów zacznie
wykonywać żądania do serwera Apache, dla każdego nowego połączenia jest
tworzony oddzielny wątek. Natomiast w serwerze Nginx wszystkie
połączenia są obsługiwane przez pojedynczy wątek lub ich małą grupę.
Ponieważ każdy wątek wymaga pewnej ilości pamięci, Nginx jest znacznie
efektywniejszy pod względem jej użycia, więc jest w stanie obsłużyć
większą niż Apache liczbę jednocześnie wykonywanych żądań.

Oto dwa wybrane artykuły, w których znajdziesz informacje o instalacji i
konfiguracji serwera Nginx:

-   Nginx (https://wordpress.org/support/article/nginx/)
-   How To Install Wordpress with nginx on Ubuntu 12.04
    (https://www.digitalocean.com/community/
    tutorials/how-to-install-wordpress-with-nginx-on-ubuntu-12-04).

Nginx przed Apache

Wybierając Nginx zamiast Apache, musimy liczyć się z dostępnością
mniejszej liczby modułów rozszerzających serwer. Część modułów, takich
jak mod_rewrite do obsługi „eleganckich łączy permalink”, zostało
przeniesionych do Nginx. Z kolei inne moduły Apache nie mają swoich
odpowiedników w Nginx.

Dlatego dość dużą popularność zyskało tworzenie konfiguracji podwójnego
serwera WWW, w której Nginx udostępnia strony buforowane i treść
statyczną, Apache zaś odpowiada za obsługę dynamicznie generowanej
treści. Sposób przygotowania takiej konfiguracji wyjaśnia między innymi
artykuł napisany przez Etela Sverdlowa How To Configure Nginx as a
Reverse Proxy for Apache i opublikowany na stronie
https://www.digitalocean.com/community/tutorials/how-to-configure-nginx-as-a-reverse-proxy-for-apache.

Największą zaletą takiej konfiguracji jest to, że pliki statyczne będą
udostępniane przez serwer Nginx, który został zoptymalizowany do
szybkiego dostarczania plików statycznych. W ten sposób pozostaje sporo
pamięci dostępnej dla Apache. Jeżeli stosujesz już sieć CDN w celu
udostępniania plików statycznych, wykorzystanie do tego serwera Nginx
jest zbędne. Ponadto, skoro pliki PHP są dostarczane przez Apache, nie
będzie żadnych korzyści związanych z oszczędnością pamięci przez Nginx
dla dynamicznie generowanych stron. Dlatego lepiej wykorzystać Nginx do
udostępniania plików statycznych i PHP lub Apache i CDN dla plików
statycznych.

Optymalizacja MySQL

Aby uzyskać najlepszą wydajność działania witryny internetowej
WordPressa, trzeba się upewnić o prawidłowej konfiguracji MySQL dla
używanego komputera i witryny oraz o wykorzystaniu w aplikacji
zoptymalizowanych zapytań do bazy danych.

Optymalizacja konfiguracji MySQL

Plik konfiguracyjny MySQL to najczęściej /etc/my.cnf lub
/etc/mysql/my.cnf. Zawarte w nim ustawienia można zmodyfikować, aby w
ten sposób poprawić wydajność działania witryny internetowej. Do
dyspozycji mamy wiele ustawień. Najlepszym sposobem na przygotowanie
dobrej konfiguracji dla komputera i witryny internetowej jest użycie
skryptu w języku Perl o nazwie MySQLTuner
(https://github.com/major/MySQLTuner-perl).

Do działania tego skryptu wymagany jest interpreter języka Perl w
systemie. Następnie można wydać polecenie perl mysqltuner.pl i stosować
się do wyświetlanych zaleceń. Wygenerowane dane wyjściowe będą podobne
do przedstawionych poniżej.

    -------- General Statistics ---------------------------------------------

    [--] Skipped version check for MySQLTuner script

    [OK] Currently running supported MySQL version 5.5.32

    [OK] Operating on 64-bit architecture

    -------- Storage Engine Statistics --------------------------------------

    [--] Status: +Archive -BDB -Federated +InnoDB -ISAM -NDBCluster

    [--] Data in MyISAM tables: 35M (Tables: 395)

    [--] Data in InnoDB tables: 16M (Tables: 316)

    [--] Data in PERFORMANCE_SCHEMA tables: 0B (Tables: 17)

    [!!] Total fragmented tables: 327

    -------- Security Recommendations  --------------------------------------

    [OK] All database users have passwords assigned

    -------- Performance Metrics --------------------------------------------

    [--] Up for: 26d 22h 6m 21s (8M q [3.755 qps], 393K conn, TX: 15B, RX:

    1B)

    [--] Reads / Writes: 95% / 5%

    [--] Total buffers: 168.0M global + 2.8M per thread (151 max threads)

    [OK] Maximum possible memory usage: 583.2M (7% of installed RAM)

    [OK] Slow queries: 0% (0/8M)

    [OK] Highest usage of available connections: 21% (33/151)

    [OK] Key buffer size / total MyISAM indexes: 8.0M/21.1M

    [OK] Key buffer hit rate: 100.0% (84M cached / 40K reads)

    [!!] Query cache is disabled

    [OK] Sorts requiring temporary tables: 0% (3 temp sorts / 1M sorts)

    [!!] Joins performed without indexes: 23544

    [!!] Temporary tables created on disk: 26% (359K on disk / 1M total)

    [!!] Thread cache is disabled

    [OK] Table cache hit rate: 34% (400 open / 1K opened)

    [OK] Open file limit used: 68% (697/1K)

    [OK] Table locks acquired immediately: 99% (8M immediate / 8M locks)

    [OK] InnoDB data size / buffer pool: 16.1M/128.0M

    -------- Recommendations ------------------------------------------------

    General recommendations:

        Run OPTIMIZE TABLE to defragment tables for better performance

        Enable the slow query log to troubleshoot bad queries

        Adjust your join queries to always utilize indexes

        When making adjustments, make tmp_table_size/max_heap_table_size

        equal

        Reduce your SELECT DISTINCT queries without LIMIT clauses

        Set thread_cache_size to 4 as a starting value

    Variables to adjust:

        query_cache_size (>= 8M)

        join_buffer_size (> 128.0K, or always use indexes with joins)

        tmp_table_size (> 16M)

        max_heap_table_size (> 16M)

        thread_cache_size (start at 4)

Warto pamiętać, że rekomendacje skryptu będą znacznie lepsze, jeśli
będzie miał do przetworzenia dane dziennika zdarzeń z przynajmniej
jednego dnia. Dlatego skrypt powinien być wykonany najwcześniej 24
godziny po ponownym uruchomieniu serwera MySQL. Należy zastosować się do
podanych zaleceń, odczekać 24 godziny, ponownie uruchomić skrypt itd. Tę
procedurę trzeba powtarzać przez kilka dni, zanim uda się przygotować
optymalne ustawienia dla serwera MySQL.

Optymalizacja zapytań bazy danych

Ogromnym źródłem wydłużającym czas wczytywania strony procesu jest
wykonywanie niezoptymalizowanych, niepotrzebnych oraz w inny sposób
wolnych zapytań MySQL. Wyszukanie i optymalizacja tych zapytań SQL
pozwoli na zwiększenie wydajności działania witryny internetowej.
Buforowanie zapytań bazy danych, na poziomie serwera bazy danych lub
określonych zapytań, pomoże przyśpieszyć wolno wykonywane zapytania.
Jednak ostatecznym celem powinna być optymalizacja kodu SQL.

Optymalizację zapytań bazy danych należy rozpocząć od wyszukania wolno
wykonywalnych lub niepotrzebnych zapytań. Doskonałym narzędziem
przeznaczonym do tego celu jest utworzona przez Johna Blackbourna
wtyczka Query Monitor (https://wordpress.org/plugins/query-monitor/).

Jak widać na rysunku 14.10 dodaje na dole każdej strony witryny
internetowej pasek wyświetlający informacje, takie jak wyrażony w
milisekundach czas wczytania strony, liczba wykonanych zapytań SQL, czas
ich wykonywania, komunikaty błędów i ostrzeżeń PHP itd.

[]

Rysunek 14.10. Wtyczka Query Monitor zostaje po jej aktywowaniu dodana
na dole wszystkich stron witryny internetowej

Jeżeli na pasku wtyczki klikniesz łącze Queries, zobaczysz listę
wszystkich wykonanych zapytań i oddzielny czas wykonywania każdego z
nich.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Przeglądanie ostatniego wygenerowanego zapytania SQL okazuje się szczególnie użyteczne w sytuacji, gdy to zapytanie jest tworzone przez wiele funkcji PHP lub na podstawie ogromnej ilości logiki rozgałęziania. Przykładowo ostateczne zapytanie wczytujące posty bloga na stronie głównej WordPressa jest generowane na podstawie wielu zmiennych przechowywanych w obiekcie $wp_query, w zależności od wyniku wyszukiwania, aktualnej strony archiwum itd.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Po włączeniu wtyczki Query Monitor można przeglądać witrynę internetową
w poszukiwaniu zapytań, które są wykonywane wolno lub okazują się
niepotrzebne.

Kolejnym sposobem na wyszukanie wolno wykonywanych zapytań jest
włączenie w pliku konfiguracyjnym MySQL opcji rejestrowania takich
zapytań. To pomoże w wyszukaniu wolno wykonywanych zapytań, które
pojawiły się w środowisku produkcyjnym. Nie musisz całkowicie polegać na
zawartości wymienionego dziennika zdarzeń, ale pomoże on w wychwyceniu
pewnych przypadków, które nie zostały wykryte podczas testów.

W celu włączenia w serwerze MySQL rejestrowania w dzienniku zdarzeń
wolno wykonywanych zapytań należy odszukać plik my.cnf lub my.ini, a
następnie umieścić w nim następujące polecenia:

    slow-query-log = 1;

    slow-query-log-file = /ścieżka/dostępu/do/pliku/dziennika/zdarzeń;

Po uaktualnieniu pliku konfiguracyjnego MySQL konieczne jest ponowne
uruchomienie serwera MySQL.

Gdy próbujesz zoptymalizować zapytania bazy danych, zawsze staraj się
wyszukiwać wymienione tutaj sytuacje.

-   To samo zapytanie SQL jest wykonywane więcej niż tylko jeden raz
    podczas operacji wczytywania strony. Wynik wykonania zapytania
    należy umieścić w zmiennej globalnej lub gdzieś indziej, skąd będzie
    można pobrać te dane podczas wczytywania strony.
-   To samo zapytanie może być użyte zamiast wykonania wielu zapytań.
    Przykładowo wtyczka może jednorazowo wczytać wszystkie opcje zamiast
    używać oddzielnego zapytania lub wywołania getOption() dla każdej
    opcji.
-   Zapytanie zostało wykonane, ale jego wynik nie został użyty. Część
    zapytań może być niezbędnych do wykonania jedynie w panelu
    kontrolnym lub we frontendzie określonej strony. Zmień używany
    zaczep WordPressa lub dodaj logikę PHP do takich wywołań, aby
    wspomniane zapytania było wykonywane tylko wtedy, gdy są niezbędne.

Po znalezieniu zapytania, które jest wykonywane szczególnie długo,
sposób jego optymalizacji będzie ściśle związany z samym zapytaniem. Oto
kilka rozwiązań, które możesz wypróbować:

-   Dostosowanie zapytania do użycia w klauzulach WHERE, ON, ORDER BY i
    GROUP BY jedynie indeksowanych kolumn.
-   Dodanie klauzuli WHERE do złączenia (JOIN), aby obejmowało ono
    mniejszą ilość danych.
-   Wykorzystanie różnych tabel do przechowywania danych — np.
    zastosowanie taksonomii zamiast metadanych posta (ten temat został
    omówiony w rozdziale 5.).
-   Dodanie indeksów do kolumn używanych w klauzulach WHERE, ON, ORDER
    BY i GROUP BY.

Pliki advanced-cache.php i object-cache.php

Filarami[2] pozwalającymi na stosowanie wymienionych technik
buforowania, w tym także technik wykorzystanych we wtyczce W3 Total
Cache, są pliki advanced-cache.php i object-cache.php, które można dodać
do katalogu /wp-content/.

Aby nakazać WordPressowi sprawdzenie pod kątem istnienia wymienionych
plików, w pliku wp-config.php należy umieścić polecenie
define('WP_CACHE', true).

Plik advanced-cache.php jest wczytywany przez wp-settings.php, jeszcze
zanim zostanie wczytana ogromna część plików źródłowych WordPressa.
Dlatego istnieje możliwość wykonania określonego kodu (np. sprawdzenie
dostępności pliku bufora w serwerze), a następnie wstrzymania
wykonywania kodu PHP za pomocą polecenia exit;, przed wczytaniem
pozostałej części WordPressa.

Jeżeli plik object-cache.php istnieje, będzie wykorzystany do
zdefiniowania bufora funkcji API zamiast użycia funkcji wbudowanych,
które znajdują się w pliku wp-includes/cache.php. Podczas wczytywania
strony WordPress będzie domyślnie buforować wszystkie opcje tablicy.
Elementy tymczasowe są przechowywane w bazie danych. Jeżeli utworzysz
własną wersję pliku object-cache.php, będziesz mógł nakazać WordPressowi
przechowywanie opcji i elementów tymczasowych w pamięci RAM, której
zawartość będzie zachowana między kolejnymi operacjami wczytania strony.

Wtyczki takie jak W3 Total Cache są w większości frontendem dla
generowania pliku advanced-cache.php z wybranymi przez Ciebie
ustawieniami. Masz możliwość przygotowania własnej wersji pliku
advanced-cache.php lub object-cache.php bądź wykorzystania już
skonfigurowanego dla określonego narzędzia buforowania lub techniki.
Większość przedstawionych w rozdziale technik buforowania opiera się na
użyciu konkretnego pliku advanced-cache.php lub object-cache.php w celu
współpracy z inną usługą buforowania.

Jeżeli na początku pliku .php znajdującego się w katalogu wp-content
umieścisz komentarz w postaci nagłówka o strukturze odpowiadającej
wtyczce (nazwa wtyczki, opis itd.), te informacje będą wyświetlane w
karcie Drop-ins na stronie wtyczki w panelu głównym WordPressa.

APC

APC, czyli Alternative PHP Cache, to rozszerzenie dla PHP działające
jako pamięć podręczna dla kodu operacyjnego (an opcode cache). Może być
również wykorzystane do przechowywania par klucz – wartość stosowanych
podczas buforowania obiektów.

Pamięć podręczna dla kodu operacyjnego

Gdy skrypt PHP jest uruchamiany, zostaje skompilowany na postać pamięci
podręcznej dla kodu operacyjnego, gotową do wykorzystania przez serwer.
W tej pamięci podręcznej część kodu jest buforowana aż do chwili
uaktualnienia skryptu PHP.

Bufor typu klucz – wartość

APC dodaje również funkcje apc_store() i apc_fetch() przeznaczone do
umieszczania pewnych informacji w pamięci oraz pobierania z niej pewnych
informacji. Wartość przechowywana w pamięci jest zwykle pobierana
znacznie szybciej niż z dysku twardego lub bazy danych, zwłaszcza jeśli
wymaga przeprowadzenia pewnych obliczeń. Wtyczki, takie jak W3 Total
Cache lub APC Object Cache Backend (https://wordpress.org/plugins/apc/),
mogą być za pomocą APC wykorzystane do przechowywania obiektów bufora
WordPressa w pamięci RAM.

Oto ogólna procedura skonfigurowania APC w WordPressie:

1.  Instalacja APC w serwerze, konfiguracja PHP do użycia APC i ponowne
    uruchomienie serwera WWW.
2.  Konfiguracja WordPressa do użycia APC za pomocą W3 Total Cache, APC
    Object Cache Backend lub innej wtyczki bądź samodzielne
    przygotowanie object-cache.php.

W wymienionych tutaj źródłach znajdziesz użyteczne informacje dotyczące
pracy z APC, ogólnie oraz w WordPressie:

-   Alternative PHP Cache (https://www.php.net/manual/en/book.apc.php)
-   Artykuł How To Install Alternative PHP Cache (APC) on a Cloud Server
    Running Ubuntu 12.04 napisany przez Danny’ego Siposa i opublikowany
    na stronie https://www.digitalocean.com/
    community/tutorials/how-to-install-alternative-php-cache-apc-on-a-cloud-server-running-ubuntu-12-04.

  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Język PHP w wersji 5.5 i nowszych jest skompilowany z OPCache, czyli alternatywą dla APC w zakresie obsługi pamięci podręcznej dla kodu operacyjnego. Jednak OPCache nie oferuje tej samej funkcjonalności umieszczania danych w pamięci i pobierania danych z pamięci, co znajdująca się w APC. Dlatego należy wyłączyć obsługę OPCache i używać APC do uruchomienia uaktualnionej wersji APC o nazwie APCu wraz z OPCache. APCu oferuje funkcjonalność umieszczania danych w pamięci i pobierania z niej danych natomiast obsługę pamięci podręcznej dla kodu operacyjnego pozostawia OPCache.
  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Memcached

Memcached to system pozwalający na przechowywanie w pamięci par klucz –
wartość. Ten system można wykorzystać jako backend dla buforowania
obiektów w WordPressie. Działanie Memcached można porównać do APC, choć
nie oferuje funkcjonalności pamięci podręcznej dla kodu operacyjnego.

Bufory pełnych stron można przechowywać w Memcached zamiast w postaci
plików na dysku, co gwarantuje szybki czas wczytywania, choć wydajność
działania będzie niższa niż nowoczesnych serwerów wyposażonych w szybkie
napędy SSD. Memcached może działać w serwerze zarówno Apache, jak i
Nginx,

Jedną z zalet Memcached nieoferowaną przez inne techniki buforowania
obiektów (dotyczy to również Redis i APC) jest możliwość umieszczenia
bufora Memcached w postaci rozproszonej na różnych serwerach. Dlatego
jeśli masz wiele różnych serwerów przeznaczonych do hostingu aplikacji,
wszystkie mogą używać jednego egzemplarza Memcached do przechowywania
wspólnego bufora. Nie ma potrzeby, aby każdy z nich tworzył oddzielny (i
często zbędny) bufor przechowywany w serwerze. Warto zwrócić uwagę na
jeszcze jeden interesujący fakt: korporacyjna wersja wtyczki W3 Total
Cache pozwala na bezproblemowe używanie APC między serwerami.

Oto ogólna procedura skonfigurowania Memcached w WordPressie:

1.  Instalacja usługi Memcached w serwerze, przydzielenie jej pewnej
    ilości pamięci i uruchomienie.
2.  Użycie wtyczki W3 Total Cache lub Memcached Object Cache
    (https://wordpress.org/plugins/ memcached/) w celu uaktualnienia
    obiektu bufora WordPress, aby korzystał z Memcached.

W wymienionych poniżej źródłach znajdziesz użyteczne informacje
dotyczące pracy z Memcached, ogólnie oraz w WordPressie.

-   Memcached w serwisie PHP.net
    (https://www.php.net/manual/en/book.memcached.php)
-   Oficjalna witryna internetowa Memcached (http://memcached.org/)
-   Artykuł WordPress + Memcached napisany przez Scotta Taylora i
    opublikowany na stronie
    https://scotty-t.com/2012/01/20/wordpress-memcached/.

Redis

Redis to kolejny system przeznaczony do przechowywania par klucz –
wartość w pamięci serwera WWW Apache lub Nginx. Podobnie jak w przypadku
Memcached, także Redis można wykorzystać jako backend dla buforowania
obiektów lub stron w WordPressie.

Jednak w przeciwieństwie do Memcached system Redis potrafi przechowywać
dane nie tylko w postaci par klucz – wartość, lecz także na listach, w
zbiorach oraz w posortowanych zbiorach. Te struktury danych zawsze będą
użyteczne dla aplikacji, a dojrzałość oferowana przez Memcached, który
narodził się wiele lat przed powstaniem Redis, jest doceniana przez
wielu programistów.

Oto ogólna procedura skonfigurowania Redis w WordPressie:

1.  Instalacja usługi Redis w serwerze, przydzielenie jej pewnej ilości
    pamięci i uruchomienie.
2.  Użycie zamiennika dla pliku index.php WordPressa. Zamiennik będzie
    sprawdzał bufor Redis i jeśli strona się w nim znajduje, będzie
    zwrócona z bufora, a nie generowana od początku. Popularną wersją
    takiego zamiennika jest wp-redis-cache.
3.  Uruchomienie wtyczki lub innego skryptu w celu wyczyszczenia bufora
    Redis, np. po uaktualnieniu posta.

W podanych źródłach znajdziesz użyteczne informacje dotyczące pracy z
Redis, ogólnie oraz w WordPressie:

-   Oficjalna witryna internetowa Redis (https://redis.io/)
-   Wtyczka WP-Redis-Cache
    (https://github.com/BenjaminAdams/wp-redis-cache)
-   Artykuł How to load WordPress in a few milliseconds using Redis
    autorstwa Jima Westergrena i opublikowany na stronie
    https://www.jimwestergren.com/wordpress-with-redis-as-a-frontend-cache/.

Varnish

Varnish to odwrotne proxy, które można skonfigurować do działania z
serwerem WWW Apache lub Nginx. Działanie tego proxy będzie polegało na
dostarczaniu odwiedzającym witrynę buforowanych wersji pełnych stron.
Skoro serwer WWW i PHP nigdy nie będą nawet wczytywały buforowanych
stron, wydajność działania proxy Varnish w zakresie buforowania pełnych
stron jest bez porównania znacznie większa niż wydajność oferowana przez
Memcached i Redis. Z drugiej strony proxy Varnish nie jest przeznaczone
do buforowania obiektów, więc sprawdza się jedynie w przypadku stron
statycznych witryny internetowej.

Oto ogólna procedura skonfigurowania Varnish w WordPressie:

1.  Instalacja usługi Varnish w serwerze.
2.  Skonfigurowanie Varnish do ignorowania panelu głównego pod adresem
    /wp-admin/ i innych sekcji witryny internetowej, które nie powinny
    być buforowane.
3.  Użycie wtyczki do wyczyszczenia bufora Varnish po uaktualnieniu
    postów lub wprowadzeniu innych aktualizacji w WordPressie. Do
    popularnych wtyczek przeznaczonych do pracy z proxy Varnish
    zaliczamy WP-Varnish (https://github.com/pkhamre/wp-varnish) i
    Varnish HTTP Purge
    (https://wordpress.org/plugins/varnish-http-purge/).

W wymienionych źródłach znajdziesz użyteczne informacje dotyczące pracy
z Varnish, ogólnie oraz w WordPressie:

-   Oficjalna witryna internetowa proxy Varnish
    (https://varnish-cache.org/)
-   Artykuł How to Install and Customize Varnish for WordPress napisany
    przez Austina Guntera i opublikowany na stronie
    https://www.problogdesign.com/wordpress/how-to-install-and-customize-varnish-for-wordpress/
-   Szablony konfiguracyjne Varnish
    (https://github.com/mattiasgeniar/varnish-3.0-configuration-templates).

Batcache

Batcache używa APC lub Memcached jako backendu dla buforowania pełnych
stron w WordPressie. Ostateczny efekt będzie podobny do otrzymanego po
użyciu W3 Total Cache lub innej wtyczki zintegrowanej z APC lub
Memcached w celu zapewnienia buforowania pełnych stron.

Unikatową cechą Batcache jest to, że buforowanie jest włączone wtedy,
gdy strona została wczytana dwukrotnie w ciągu ostatnich 120 sekund. W
takim przypadku następuje umieszczenie strony w buforze i jej
udostępnianie stamtąd w ciągu kolejnych 300 sekund. Te wartości można
dostosować do własnych potrzeb. Podstawową ideą kryjącą się za Batcache
jest ochrona przed nagłym wzrostem ruchu sieciowego, co się może
zdarzyć, gdy na przykład strona witryny internetowej zostanie wspomniana
na jednym z popularnych portali, takim jak Slashdot, Techcrunch, Reddit
itd., lub na innej witrynie internetowej z ogromną bazą użytkowników.
Kolejną zaletą buforowania jedynie najczęściej odwiedzanych stron jest
zmniejszenie ilości pamięci RAM niezbędnej do przechowywania bufora.
Jeżeli zmodyfikujesz ustawienia domyślne, będziesz mógł wykorzystać
Batcache do działania w charakterze zawsze włączonego systemu
buforowania pełnych stron.

Oto ogólna procedura skonfigurowania Batcache w WordPressie:

1.  Konfiguracja Memcached lub APC do użycia jako działający w pamięci
    magazyn typu klucz – wartość dla Batcache
2.  Pobranie wtyczki Batcache z repozytorium WordPressa
3.  Przeniesienie pliku advanced-cache.php do katalogu wp-content
    instalacji WordPressa.

Batcache ma interesujące korzenie, ponieważ to narzędzie zostało
opracowane specjalnie dla WordPressa. Początkowo było używane na
stronach WordPress VIP w oficjalnej witrynie platformy. Wprawdzie
pierwszą użytą nazwą była Supercache, ale ponieważ mniej więcej w tym
samym czasie pojawiała się popularna wtyczka buforowania o nazwie WP
Super Cache, autorzy Supercache/Batcache zdecydowali się na zmianę
nazwy. W wymienionych tutaj źródłach znajdziesz użyteczne informacje
dotyczące pracy z Batcache w WordPressie:

-   Wtyczka Batcache (https://wordpress.org/plugins/batcache/)
-   Oficjalne przedstawienie Batcache i ogólne omówienie możliwości
    (https://andy.wordpress. com/2008/06/22/batcache-for-wordpress/).

Buforowanie selektywne

Omówione dotychczas metody buforowania były przeznaczone do buforowania
pełnych stron lub przedstawiały zwykły bufor przechowujący każdy obiekt
WordPressa. Istnieje możliwość dodania do bufora reguł pozwalających na
unikanie buforowania treści znajdujących się pod określonym adresem URL
lub spełniających pewne warunki. Jednak w zasadzie takie rozwiązanie
sprowadza się do buforowania wszystkiego.

Czasami zachodzi potrzeba zrobienia czegoś w inny sposób. Przykładem
może być buforowanie określonych stron i obiektów. To zwykle odbywa się
poprzez przechowywanie informacji w elementach tymczasowych WordPressa.
Jeżeli masz dostępny trwały obiekt, taki jak APC, przechowywany obiekt
będzie wczytany w znacznie krótszym czasie.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   To, co tutaj nazywamy buforowaniem selektywnym, jest często określane mianem buforowania fragmentu. Niezależnie od używanego terminu koncepcja pozostaje taka sama: buforowanie fragmentów wygenerowanej strony internetowej zamiast pełnej strony.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Przykładowo może być włączone buforowanie pełnych stron, np. za pomocą
wtyczki W3 Total Cache lub proxy Varnish, ale zachodzi potrzeba
wykluczenia z bufora zalogowanych użytkowników, ponieważ informacje o
użytkownikach nie powinny być buforowane. W przypadku buforowania
zalogowanych użytkowników Maria mogłaby zobaczyć umieszczony gdzieś na
stronie komunikat typu Witaj, Bartek. Pewien fragment strony może być
taki sam dla wszystkich użytkowników lub ich pewnej grupy. Istnieje
możliwość selektywnego buforowania tych informacji, jeśli ich pobranie
wiąże się z dużymi wywołaniami do bazy danych lub innymi kosztowymi
obliczeniami.

Dobrymi kandydatami do buforowania selektywnego są raporty,
skomplikowane zapytania postów i inne informacje, których przygotowanie
i pobranie wymaga dużej ilości czasu lub zasobów komputera.

API Transient

Element tymczasowy (transient) to preferowany w WordPressie sposób na
definiowanie i pobieranie wartości z obiektu bufora. Jeżeli nie został
zainstalowany system trwałego buforowania, wszystkie elementy tymczasowe
są przechowywane w tabeli wp_options bazy danych WordPressa. Natomiast
po zainstalowaniu mechanizmu buforowania obiektów, takiego jak APC,
APCu, Mem-cached lub Redis, ten właśnie system będzie używany do
przechowywania elementów tymczasowych.

W każdej chwili można ponownie uruchomić serwer lub opróżnić pamięć
bufora obiektów, co oznacza usunięcie wszystkich elementów tymczasowych.
Dlatego podczas przechowywania tych elementów zawsze należy przyjmować
założenie, że magazyn danych jest ulotny i zawodny. Jeżeli trzeba
zachować informacje umieszczane w elementach tymczasowych, ze względu na
wydajność działania mogą się one znajdować w buforze elementów
tymczasowych, ale jednocześnie powinny być gdzieś trwale zapisane —
prawdopodobnie podczas zapisywania opcji za pomocą wywołania
update_option().

W aplikacji SchoolPress konieczne jest pobieranie średniego wyniku ze
wszystkich prac domowych oddanych przez jednego ucznia. Zapytanie
pobierające taką wartość będzie wykorzystywało funkcję obliczającą
wartość średnią kolumny meta_value tabeli wp_usermeta. Obliczenie
średniej dla jednego ucznia, który oddał na przykład 10 lub 100 prac
domowych, nie będzie zbyt dużym zadaniem. Natomiast w przypadku strony
wyświetlającej średnią dla kilkudziesięciu uczniów obliczenia konieczne
do wykonania mogą „zabrać chwilę”. W celu przyśpieszenia takiej operacji
można w elemencie tymczasowym buforować wygenerowany pełny raport, jak
to pokazujemy w kodzie na listingu 14.1.

Listing 14.1. Kod klasy SPClass

    class SPClass()

    {

        /* Konstruktor i inne metody… */

        function getStudents()

        {

            /* Pobranie wszystkich użytkowników w grupie BuddyPress dla danej klasy. */

            return $this->students; // Tablica obiektów przedstawiających uczniów

        }

        function getAssignmentAverages()

        {

            // Sprawdzenie pod kątem elementu tymczasowego

            $this->assignment_averages =

            get_transient('class_assignment_averages_' . $this->ID);

            // Nie znaleziono elementu tymczasowego? Należy go wygenerować

            if(empty($this->assignment_averages))

            {

                $this->assignment_averages = array();

                $this->getStudents();

                foreach($this->students as $student)

                {

                    $this->assignment_averages[$student->ID] =

                    $student->getAssignmentAverages();

                }

                // Zapisanie wartości w elemencie tymczasowym

                set_transient('class_assignment_averages_' .

                $this->ID, $this->assignment_averages);

            }

            // Zwrot wartości

            return $this->assignment_averages;

        }

    }

    // Po wystawieniu oceny za pracę domową następuje usunięcie elementów tymczasowych wartości średniej

    public function clear_assignment_averages_transient($assignment_id)

    {

        // Identyfikator klasy jest przechowywany w metadanych posta pracy domowej

        $assignment = new Assignment($assignment_id);

        $class_id = $assignment->class_id;

        // Usunięcie wszystkich zawierających wartość średnią elementów tymczasowych dla danej klasy

        delete_transient('class_assignment_averages_' . $class_id);

    }

    add_action('sp_update_assignment_score', array('SPClass',

    'clear_assignment_averages_transient'));

Jest to doskonały przykład użycia elementów tymczasowych, ponieważ
zapewnienie dostępu do obliczonych wartości znajdujących się w takim
elemencie może znacznie przyśpieszyć wykonywanie powtarzających się
operacji. Nie ma żadnego problemu w przypadku nagłego zniknięcia
elementu tymczasowego, ponieważ przechowywaną w nim wartość zawsze można
ponownie wygenerować na podstawie istniejących danych.

W omawianym przykładzie znalazła się spora ilość kodu i przyjęto w nim
pewne założenia dotyczące klas SPClass i Student. Jednak na jego
podstawie powinieneś ogólnie wiedzieć, jak wspomniany raport używa
elementów tymczasowych do przechowywania obliczonych wartości,
pobierania ich z bufora i usuwania po uaktualnieniu wartości.

W tym przykładzie tablica stored jest przechowywana w elemencie
tymczasowym $this->assigment_averages. Ewentualnie można przechowywać
wygenerowany kod HTML, choć w przypadku tablicy unikamy większości
skomplikowanych wywołań do bazy danych, a samo rozwiązanie jest znacznie
elastyczniejsze.

Funkcja odpowiedzialna za umieszczenie wartości w elemencie tymczasowym
to set_transient( $transient, $value, $expiration ), a jej atrybuty są
następujące:

$transient

Unikatowa nazwa elementu tymczasowego, maksymalnie 45 znaków.

$value

Wartość przeznaczona do przechowywania. Obiekty i tablice są
automatycznie serializowane i deserializowane.

$expiration

Parametr opcjonalny definiujący wyrażony w sekundach czas utraty
ważności tego elementu tymczasowego. Gdy element tymczasowy będzie
uznany za nieaktualny, zostanie usunięty przez mechanizm usuwania
nieużytków WordPressa. Domyślnie ta wartość wynosi 0 i oznacza, że
element nie utraci ważności aż do chwili jego usunięcia.

Zwróć uwagę na użycie opisowego klucza (class_assignment_averages_), po
którym znajduje się identyfikator grupy klasy. Dzięki temu wszystkie
klasy będą miały oddzielne elementy tymczasowe przechowujące obliczone
wartości średnie.

W celu pobrania elementu tymczasowego należy użyć wywołania
get_transient( $transient ) i przekazać mu parametr w postaci unikatowej
nazwy elementu tymczasowego. Jeżeli wskazany element jest dostępny i
pozostaje aktualny, zwrócona będzie jego wartość. W przeciwnym razie
wartością zwrotną jest false.

W celu usunięcia elementu tymczasowego zanim utraci on ważność, należy
wywołać metodę delete_transient( $transient ) i przekazać jej parametr w
postaci unikatowej nazwy elementu tymczasowego. Zwróć uwagę, że w
omawianym przykładzie został użyty zaczep sp_update_assigment_score
wywoływany po ocenieniu pracy domowej. Jako funkcja wywołania zwrotnego
zaczepu zostaje przekazana tablica, ponieważ wymieniona metoda jest
częścią klasy SPClass. Zaczep sp_update_assigment_score przekazuje
parametr w postaci $assigment_id. Metoda wywołania zwrotnego używa tego
identyfikatora do znalezienia pracy domowej i identyfikatora powiązanej
klasy, a następnie usuwa element tymczasowy
class_assignment_averages_{ID}.

Jeżeli elementy tymczasowe powiązane z postami lub użytkownikami będą
przechowywane, być może będziesz chciał je usuwać w trakcie wywołań
zaczepów odpowiednio save_post lub profile_update.

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Funkcje przeznaczone do obsługi elementów tymczasowych są prostymi opakowaniami dla funkcji zdefiniowanych w domyślnym pliku wp-includes/cache.php lub zamienniku object-cache.php: wp_cache_set(), wp_cache_get() i wp_cache_delete(). Jeżeli chcesz, wymienione funkcje możesz wywoływać bezpośrednio. Więcej informacji na temat tych funkcji znajdziesz w serwisie Codex na stronie https://codex.wordpress.org/Class_Reference/WP_Object_Cache.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Elementy tymczasowe dla wielu witryn internetowych

W przypadku instalacji sieciowej elementy tymczasowe utworzone za pomocą
wywołania set_transient() są przeznaczone dla bieżącej witryny
internetowej sieci. Dlatego element class_assignment_averages_1
zdefiniowany na jednej witrynie internetowej sieci będzie niedostępny w
innej witrynie tej sieci. (To ma sens w omawianym tutaj przykładzie).

Jeżeli chcesz utworzyć element tymczasowy przeznaczony dla całej sieci,
WordPress oferuje odpowiednie wersje tworzących go funkcji.

-   set_site_transient( $transient, $value, $expiration )
-   get_site_transient( $transient )
-   delete_site_transient( $transient )

Wymienione funkcje działają w dokładnie taki sam sposób, jak zwykłe
funkcje przeznaczone do tworzenia elementów tymczasowych. Jednak
elementy tworzone przez wersje _site_transients funkcji są przechowywane
w tabeli wp_site_options, a nie w wp_options.

Skoro elementy tymczasowe definiowane za pomocą set_site_transient()
mają prefiks _site dodany do nazwy, ich nazwy mogą się składać z
maksymalnie 40 znaków.

Warto również zwrócić uwagę na wywoływanie odmiennego zestawu zaczepów
przed i po utworzeniu elementu tymczasowego o zasięgu sieci. Jeżeli
utworzyłeś kod korzystający z zaczepu pre_set_transient, set_transient
lub setted_transient, może wystąpić potrzeba połączenia tego kodu z
zaczepami pre_set_site_transient, pre_set_transient i
pre_setted_site_transient.

Używanie JavaScriptu do poprawy wydajności działania

Użyteczną taktyką pozwalającą na skrócenie czasu wczytywania strony jest
pobieranie jej fragmentów za pomocą kodu JavaScript zamiast generowania
tych samych danych wyjściowych poprzez dynamicznie działający kod PHP.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeżeli aplikacja została od początku utworzona jako aplikacja JavaScriptu z wykorzystaniem API WP REST i frameworka takiego jak React, zamieszczone w tym podrozdziale sugestie są zbędne, ponieważ strony internetowe i ekrany aplikacji i tak pobierasz za pomocą żądań w technologii AJAX.
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Dzięki tej technice strony mogą pojawiać się szybciej, ponieważ
wczytanie ramki strony nastąpi w bardzo krótkim czasie. Następnie
wymagające więcej czasu operacje wczytywania pewnych fragmentów witryny
mogą odbywać się po wyświetleniu komunikatu, takiego jak Wczytywanie...,
pewnej ikony lub paska postępu. Użytkownicy od razu będą widzieli, że
treść strony jest wczytywana i że trzeba zaczekać jeszcze kilka sekund
na jej wyświetlenie.

Użycie JavaScriptu może dosłownie zwiększyć szybkość wczytywania strony
internetowej. Jeżeli cała generowana dynamicznie treść strony będzie
wczytywana za pomocą JavaScriptu, bufor strony można wykorzystać w celu
udostępniania pozostałej części strony, bez konieczności jej generowania
przez PHP.

Przykładowo w wielu blogach jedyną treścią dynamiczną są komentarze.
Użycie wbudowanego w WordPress bufora pełnego stron i komentarzy
oznacza, że ostatnio dodane komentarze nie zostaną wyświetlone aż do
chwili usunięcia zawartości bufora. Jeżeli jednak zostanie wykorzystany
oparty na JavaScripcie system obsługi komentarzy, np. oferowany przez
wtyczkę JetPack lub usługę typu Disqus bądź Facebook, sekcja komentarzy
będzie zwykłym fragmentem kodu JavaScript, który dynamicznie wczytuje
komentarze z innego serwera.

Na listingu 14.2 przedstawiamy prosty przykład, jak można za pomocą
JavaScriptu wczytywać pewną treść na statycznej stronie

Listing 14.2. Wtyczka JS Display Name

    <?php

    /*

    Nazwa wtyczki: JS Display Name

    Adres URI wtyczki: http://bwawwp.com/js-display-name/

    Opis: Prosty sposób na wyświetlanie za pomocą kodu JavaScript nazwy zalogowanego użytkownika

    Wersja: .1

    Autor: Jason Coleman

    Adres URI witryny autora: http://bwawwp.com

    */

    /*

            Użyj tej funkcji do umieszczenia kodu JavaScript w motywie

            if(function_exists("jsdn_show_display_name"))

            {

                    jsdn_show_display_name();

            }

    */

    function jsdn_show_display_name($prefix = "Witaj,&nbsp;")

    {

        ?>

        <p>

        <script src="<?php echo admin_url(

            "/admin-ajax.php?action=jsdn_show_display_name&prefix=" .

            urlencode($prefix)

        );?>"></script>

        </p>

        <?php

    }

    /*

    Ta funkcja wykrywa wywołanie JavaScript i zwraca nazwę użytkownika przeznaczoną do wyświetlenia

    */

    function jsdn_wp_ajax()

    {

        global $current_user;

        if(!empty($current_user->display_name))

        {

            $prefix = sanitize_text_field($_REQUEST['prefix']);

            $text = $prefix . $current_user->display_name;

            header('Content-Type: text/javascript');

            ?>

            document.write(<?php echo json_encode($text);?>);

            <?php

        }

        exit;

    }

    add_action('wp_ajax_jsdn_show_display_name', 'jsdn_wp_ajax');

    add_action('wp_ajax_nopriv_jsdn_show_display_name', 'jsdn_wp_ajax');

Tabele niestandardowe

Kolejnym narzędziem, które będzie potrzebne podczas tworzenia aplikacji
WordPressa, a szczególnie się przydaje w trakcie optymalizacji
wydajności działania, jest możliwość utworzenia niestandardowej tabeli
bazy danych lub widoku, za pomocą którego będzie można znacznie szybciej
przeprowadzać pewne operacje wyszukiwania i inne zapytania.

W aplikacji SchoolPress trzeba wykonywać sporo zapytań związanych z
obiektami przedstawiającymi pracę domową. Sortowanie informacji chcemy
przeprowadzać pod względem oceny, klasy, nauczyciela, ucznia, daty pracy
domowej, daty oddania pracy itd. Być może potrzebne będzie sortowanie
uwzględniające połączenie kilku z tych informacji. Jeżeli wartości są
przechowywane w tabeli wp_postmeta, zapytania będą wykonywane wolno z
dwóch powodów. Pierwszy — tabela jest ogromna, ponieważ zawiera posty i
metadane nie tylko związane z pracą domową; drugi — kolumna meta_value
nie jest indeksowana.

Indeksowanie kolumny meta_value byłoby przesadą, ponieważ oznaczałoby
indeksowanie wielu metadanych postów, które nie muszą być zindeksowane.
Wstawianie danych do tabeli wp_postmeta trwałoby wieki i wymagałoby
ogromnej ilości pamięci. Zastąpienie niektórych metadanych postów
taksonomiami nie miałoby większego sensu — takie rozwiązanie stałoby się
trudne w zarządzaniu i niekoniecznie oznaczałoby zwiększenie szybkości
działania w oczekiwanym stopniu.

Kolejny fragment kodu przedstawia nieco sztuczny przykład, ale w pewnym
momencie natkniesz się na sytuację, w której lepszym rozwiązaniem będzie
przechowywanie danych w tabeli niestandardowej zamiast pewnego rodzaju
połączeniu postów, metadanych postów i taksonomii.

Tabela przeznaczona do przechowywania pracy domowej może mieć
następującą postać.

    CREATE TABLE `wp_sp_assignments` (

      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,

      `post_id` bigint(20) unsigned,

      `class_id` bigint(20) unsigned,

      `student_id` bigint(20) unsigned,

      `score` int(10),

      `assignment_date` DATETIME,

      `due_date` DATETIME,

      `submission_date` DATETIE

      PRIMARY KEY (`id`),

      UNIQUE KEY `post_id` (`post_id`),

      KEY `class_id` (`class_id`),

      KEY `student_id` (`student_id`),

      KEY `score` (`score`),

      KEY `asignment_date` (`assignment_date`),

      KEY `due_date` (`due_date`),

      KEY `submission_date` (`submission_date`)

    );

Jest to wyjątkowy przykład, w którym każda kolumna ma indeks. Takie
rozwiązanie jest tutaj prawdopodobnie przesadą, ale pozwala na
wykonywanie szybkich zapytań względem tabeli złączonej z wp_posts lub z
wp_users.

Jeżeli miałbyś taką tabelę, wtedy konieczne byłoby wykorzystanie zaczepu
save_post lub wp_sp_assignments w pokazany tutaj sposób.

    function sp_update_assignments_table($post_id)

    {

        // Pobranie posta

        $post = get_post($post_id);

        // Interesują nas tylko prace domowe

        if($post->post_type != "assignment")

            return false;

        // Pobranie danych gotowych do wstawienia lub zastąpienia

        $assignment_data = array(

            "post_id" => $post_id,

            "student_id" => $post->post_author,

            "teacher_id" => $post->teacher_id,

            "score" => $post->score,

            "assignment_date" => $post->assignment_date,

            "due_date" => $post->due_date

            "submission_date" => $post->submission_date

          );

          // Wyszukiwanie istniejącej pracy domowej

          $assignment_id = $wpdb->get_var("SELECT id

                                           FROM wp_sp_assignments

                                           WHERE post_id = '" . $post_id . "'

                                           LIMIT 1");

        // W przypadku braku identyfikatora pracy domowej oznacza to nową pracę domową

        if(empty($assignment_id))

        {

            $assignment_id = $wpdb->insert("wp_sp_assignments", $assignment_data);

        }

        else

        {

            $assignment_data['id'] = $assignment_id;

            $wpdb->replace("wp_sp_assignments", $assignment_data);

        }

        return $assignment_id;

    }

    add_action('save_post', 'sp_update_assignments_table');

Pominięcie WordPressa

Ostatnią techniką pomagającą w skalowaniu WordPressa jest rezygnacja z
użycia WordPressa do obsługi każdego aspektu aplikacji.

W tym rozdziale miałeś już okazję poznać przykłady zastosowania tej
techniki. Gdy zdecydowałeś się na użycie Varnish, tak naprawdę pominąłeś
WordPressa i w inny sposób wczytywałeś statyczne pliki HTML. Gdy
używałeś pliku advanced-cache.php, również pomijałeś pewne fragmenty
WordPressa. Jeśli do wczytywania komentarzy z Facebooka używasz
JavaScriptu, także pomijasz WordPressa. Przechowując dane w
niestandardowej tabeli bazy danych, pomijasz w ten sposób framework
WordPress.

Do budowania aplikacji używamy WordPressa ze względu na oferowany przez
tę platformę poziom zapewnienia bezpieczeństwa, funkcjonalność, ogromną
liczbę wtyczek, a także dużą społeczność i dużą liczbę dostępnych
rozwiązań. Mając kod utworzony dla platformy WordPressa, można go bardzo
łatwo zaczepić w systemie CMS WordPressa i systemie zarządzania
użytkownikami. Ponadto dodawanie zaczepów do własnego kodu również jest
bardzo łatwe.

Jednak czasami spadek wydajności jest większy niż zalety płynące z
zastosowania pewnej funkcjonalności WordPressa. Niekoniecznie musisz
korzystać z wszystkich funkcji WordPressa, niektóre z nich możesz
pominąć.

Przykładowo wcześniejszy skrypt odpowiedzialny za wyświetlanie nazwy
użytkownika za pomocą kodu JavaScript mógłby zostać utworzony w postaci
skryptu PHP. Taki kod mógłby wykonywać proste zapytanie SELECT w celu
pobrania kolumny display_name użytkownika wymienionego w pliku cookie
WordPressa. Takie podejście pozwala na zaoszczędzenie kilku milisekund w
trakcie wczytywania każdej strony witryny internetowej. Jeżeli pomnożysz
to przez wiele dynamicznych fragmentów istniejących w aplikacji,
potencjalne oszczędności staną się pokaźne.

W większości przypadków odcięcie WordPressa w taki sposób powinno być
ostatecznością. Zwiększenie wydajności działania odbywa się kosztem
zwiększenia poziomu skomplikowania kodu. Uruchomienie takiego skryptu za
pomocą API REST lub pliku admin-ajax.php powoduje zmniejszenie
obciążenia WordPressa, ale nadal pozwala kodowi na współdziałanie z
innymi wtyczkami i używanie wbudowanych klas WordPressa oraz API, jeśli
zachodzi potrzeba.

Jeżeli w celu wyeksportowania danych w formacie CSV wczytujesz skrypt,
który będzie wykonywany przez 10 sekund, skrócenie o pół sekundy czasu
jego wczytywania nie ma znaczenia.

Podczas budowania programu zawsze powinieneś starać się zastosować jak
najprostsze rozwiązanie, oparte na tradycyjnych metodach WordPressa.
Optymalizację na tym poziomie powinieneś przeprowadzać tylko po
znalezieniu wąskiego gardła, które warto optymalizować. Przeanalizuj
wszystkie opcje omówione w tym rozdziale i spróbuj ustalić, która z nich
sprawdza się najlepiej dla optymalizowanej funkcjonalności. Uwzględnij
przy tym potrzeby zespołu oraz narzędzia dostępne do Twojej dyspozycji.

[1] W systemach CentOS i Red Hat wystarczy wydać polecenie yum install
gnuplot. Więcej informacji na temat instalacji narzędzia znajdziesz w
witrynie internetowej tego narzędzia pod adresem
http://www.gnuplot.info/.

[2] Przyjmujemy założenie, że będzie tylko jeden filar. Tym razem musisz
nam wybaczyć.

Rozdział 15. E-commerce

Być może w pewnym momencie będziesz chciał pobierać opłaty za dostęp do
swojej aplikacji lub w inny sposób akceptować płatności w swojej
witrynie. W tym rozdziale omawiamy najlepsze dostępne wtyczki e-commerce
i obsługi członkostwa oraz podajemy kilka wskazówek związanych z wyborem
odpowiedniego rozwiązania. Omawiamy również etapy konfigurowania metod
płatności w modelu oprogramowania jako usługi (software as a service).

Wybór wtyczki

W WordPressie mamy jedną wtyczkę typu e-commerce będącą niemalże
synonimem e-commerce: WooCommerce. Od czasu pierwszego wydania tej
książki w 2014 roku wtyczka WooCommerce zdominowała nie tylko platformę
e-commerce WordPressa, lecz także całą gałąź e-commerce. Dla
programistów wtyczka może okazać się niezwykle interesująca ze względu
na zaczepy i filtry, dlatego pokrótce ją tu omawiamy.

Pomimo tego, że WooCommerce jest dobrze przygotowanym i utrzymanym
produktem, zdarzają się przypadki, w których inne wtyczki typu
e-commerce okażą się bardziej odpowiednie. Należą do nich Paid
Memberships Pro (wtyczka typu e-commerce przeznaczona do obsługi
użytkowników) i Easy Digital Downloads (wtyczka typu e-commerce
przeznaczona do obsługi produktów wirtualnych).

Wtyczki omawiane w niniejszym rozdziale mają następujące cechy wspólne:

-   integracja z wieloma bramkami płatności
-   bezpieczne formularze składania zamówień
-   zapisywanie informacji o zamówieniu
-   produkty (lub poziomy członkostwa) z informacjami o cenie.

W dalszej części rozdziału przedstawiamy unikalne cechy każdego typu
wtyczki typu e-commerce.

WooCommerce

Trudno dokładnie ustalić wielkość udziału platform e-commerce w
rynku[1], ale WooCommerce prawdopodobnie jest używana na co najmniej 20
procentach wszystkich witryn internetowych typu e-commerce[2]. Z
informacji znajdujących się w WordPress.org wynika, że ta wtyczka była
pobierana ponad 47 milionów razy na ponad czterech milionach aktywnych
witryn internetowych. Jak by na to nie patrzeć, ogromna liczba witryn
internetowych korzysta z WooCommerce. Właśnie dlatego w 2015 roku firma
Automattic kupiła WooCommerce. Ogromna popularność to również powód, dla
którego właśnie tę wtyczkę omawiamy jako pierwszą.

WooCommerce i inne „wtyczki koszyków na zakupy” zapewniają obsługę
następujących funkcji:

-   niestandardowy typ postów dla produktów
-   możliwość przeglądania produktów
-   możliwość wyszukiwania produktów
-   możliwość zakupu wielu produktów jednocześnie
-   obsługa adresu wysyłki i jej kosztu
-   obsługa niestandardowych przepisów podatkowych.

Dokumentację dotyczącą konfiguracji wtyczki WooCommerce i wiele innych
cennych informacji można znaleźć w oficjalnej witrynie internetowej
WooCommerce (https://docs.woocommerce.com/).

Wtyczka i rozszerzenia WooCommerce

Wtyczka WooCommerce jest dostępna bezpłatnie w repozytorium
WordPress.org. Podstawowa wtyczka zawiera wszystko, co jest niezbędne do
zdefiniowania produktów i ich cen oraz do akceptowania płatności przez
serwis PayPal. Niedawno bezpłatnie udostępniono rozszerzenie Stripe
Payment Gateway i stało się ono najpopularniejszym sposobem akceptowania
kart kredytowych bezpośrednio w witrynie internetowej użytkownika
zbudowanej za pomocą WooCommerce. Dostępne są również rozszerzenia dla
prawie każdej bramki płatności, której klient zechce użyć.

Dla WooCommerce powstały dziesiątki zarówno bezpłatnych, jak i płatnych
rozszerzeń, które usprawniają podstawową wtyczkę, integrują się z
usługami marketingowymi firm zewnętrznych, wprowadzają nowe typy
produktów, integrują się z usługami wysyłkowymi albo usprawniają
zarządzanie sklepem. Dwa najpopularniejsze rozszerzenia to WooCommerce
Subscriptions
(https://woocommerce.com/products/woocommerce-subscriptions/)
umożliwiające pobieranie płatności cyklicznych i WooCommerce Memberships
(https://woocommerce.com/products/woocommerce-memberships/)
umożliwiające oprócz pobierania płatności cyklicznych ograniczenie
zawartości witryny na podstawie wykupionego poziomu członkostwa. Wtyczka
Paid Memberships Pro została zoptymalizowana pod kątem tego konkretnego
przypadku użycia, ale jeśli już korzystasz z Woo-Commerce lub
potrzebujesz innej funkcji obsługiwanej przez WooCommerce, wymienione
rozszerzenia również są dobrym rozwiązaniem.

Dostosowywanie WooCommerce za pomocą zaczepów

WooCommerce (jak każda dobra wtyczka WordPressa) ma niesamowitą liczbę
zaczepów akcji i filtrów, których można użyć do ustandaryzowania sposobu
działania wtyczki na Twojej witrynie internetowej. Dokładne omówienie
wszystkich oferowanych zaczepów akcji i filtrów znajdziesz na stronie
https://docs.woocommerce.com/wc-apidocs/hook-docs.html.

Poniżej prezentujemy kilka przykładów, aby pokazać, jakie możliwości
daje użycie kilku typowych zaczepów wtyczki WooCommerce.

Ustawienia hurtowej wyprzedaży

Wprawdzie istnieją wtyczki, których możesz użyć w celu przygotowania
ogólnej wyprzedaży w sklepie utworzonym za pomocą WooCommerce, ale
ponieważ jesteś świetnym programistą, możesz to zrobić samodzielnie,
korzystając z własnego kodu. W poniższym fragmencie kodu zastosowano
10-procentową zniżkę na każdy produkt, który jeszcze nie jest na
wyprzedaży.

    // Obniżenie ceny o 10%, jeżeli dany produkt jeszcze nie jest na wyprzedaży

    function my_get_sale_price($sale_price, $product) {

        if(empty($sale_price)) {

            $sale_price = $product->get_regular_price() * .9;

            $product->set_price($sale_price);

        }

        return $sale_price;

    }

    dd_filter('woocommerce_product_get_sale_price', 'my_get_sale_price',

      10, 2);

    add_filter('woocommerce_product_variation_get_sale_price',

      'my_get_sale_price', 10, 2);

Produkty WooCommerce mają zarówno cenę „normalną”, jak i „wyprzedażową”.
Cena ostateczna jest nazywana po prostu „ceną”. Zaczep, którego możesz
użyć w celu ustalenia ceny wyprzedaży, to
woocommerce_product_get_sale_price. Jednak do obsługi produktów
istniejących w różnych wariantach (np. rozmiaru podkoszulka S, M, L)
trzeba będzie użyć zaczepu commerce_product_get_variation_sale_price.

Zwróć uwagę na wiersz zawierający wywołanie
$product->set_price($sale_price). Obliczana cena nie zostanie
uaktualniona automatycznie po otrzymaniu ceny sprzedaży z funkcji
wywołania zwrotnego. Tę aktualizację trzeba będzie przeprowadzić
ręcznie. Parametr $product jest w funkcji wywołania zwrotnego
przekazywany przez referencje. Dlatego uaktualnienie obiektu produktu
spowoduje również uaktualnienie parametru na zewnątrz filtru.

Automatyczne uzupełnianie zamówień

Gdy tworzone jest nowe zamówienie „w kasie”, jego stan domyślnie zmienia
się na „w realizacji”. Administrator witryny musi następnie uruchomić
procedurę przetworzenia tego zamówienia. W przypadku produktów
fizycznych przetwarzanie zamówienia oznacza zwykle zapakowanie produktu
do pudełka i wysłanie go do zamawiającego. To pozwala zmienić stan
zamówienia na „zrealizowane”.

W przypadku produktów wirtualnych może istnieć potrzeba automatycznej
zmiany stanu zamówienia na „zrealizowane”. Wiele rozszerzeń dla wtyczki
WooCommerce oferuje usprawnienie pozwalające na ograniczenie liczby
niezbędnych kliknięć, a samo rozszerzenie jest uruchamiane w chwili
rozpoczęcia realizacji zamówienia. Im szybciej zamówienie zostanie
zrealizowane, tym sprawniej wtyczki roześlą wiadomości e-mail, użyją
dostępnego API lub wykonają inne niezbędne czynności. W kolejnym
przykładzie kodu zostanie wykorzystana pętla przeprowadzająca iterację
przez produkty znajdujące się w koszyku po sfinalizowaniu transakcji.
Jeżeli wszystkie produkty w koszyku są wirtualne, zamówienie zmieni stan
na „zrealizowane”.

    function autocomplete_virtual_orders($order_id) {

        // Pobranie istniejącego zamówienia

        $order = new WC_Order($order_id);

        // Przyjęcie założenia, że zostanie automatycznie uzupełnione

        $autocomplete = true;

        // Pobranie elementów

        if (count( $order->get_items() ) > 0) {

            foreach ($order->get_items() as $item) {

                if($item['type'] == 'line_item') {

                    $_product = $order->get_product_from_item( $item );

                    if(!$_product->is_virtual()) {

                        // W koszyku został znaleziony produkt, który nie jest wirtualny

                        $autocomplete = false;

                        break;

                    }

                }

            }

        }

        // Zmiana stanu zamówienia, gdy jest to niezbędne

        if(!empty($autocomplete)) {

            $order->update_status('completed', 'Autocompleted.');

        }

    }

    add_filter('woocommerce_thankyou', 'autocomplete_virtual_orders');

Paid Memberships Pro

Działanie Paid Memberships Pro i innych wtyczek służących do obsługi
użytkowników koncentruje się na przyjmowaniu płatności za uzyskanie
dostępu do witryny internetowej lub aplikacji WordPressa. Funkcje takich
wtyczek to m.in.:

-   płatności cykliczne w ramach subskrypcji
-   narzędzia do udostępniania treści na podstawie poziomu członkostwa.

Dokumentację związaną z konfiguracją wtyczki Paid Memberships Pro oraz
inne ważne wskazówki znajdziesz na stronie
https://www.paidmembershipspro.com/documentation/.

+----------------------------------------------------------------------+
| Dlaczego Paid Memberships Pro                                        |
|                                                                      |
| Oprócz oczywistego powodu, jakim jest opracowanie tej wtyczki przez  |
| współautora niniejszej książki, Jasona Colemana, Paid Memberships    |
| Pro jest jedyną wtyczką WordPressa dostępną w 100 procentach na      |
| licencji GPL ( general public license). Możesz ją pobrać bezpłatnie  |
| z repozytorium WordPressa. W przypadku pozostałych wtyczek dostęp do |
| wszystkich funkcjonalności wymaga zakupienia płatnych modułów lub    |
| uaktualnionych wersji oferujących całą funkcjonalność.               |
|                                                                      |
| Cały kod wtyczki Paid Memberships Pro został umieszczony w           |
| publicznym repozytorium w serwisie GitHub i jest dostępny dla        |
| każdego programisty. Podobnie jak w przypadku wtyczki WooCommerce,   |
| omawiana wtyczka również zapewnia zaczepy i filtry umożliwiające     |
| zmianę domyślnego sposobu jej działania.                             |
|                                                                      |
| Większość witryn internetowych stosujących poziomy członkostwa na    |
| różne sposoby oferuje aktualizacje lub oferty specjalne, a także     |
| używa odmiennych rozwiązań w zakresie uniemożliwiania dostępu do     |
| treści. Zamiast długiej listy ustawień Paid Membership Pro dostarcza |
| pieczołowicie zaprojektowane zaczepy i filtry ułatwiające            |
| konfigurację niemalże każdego modelu cenowego lub modelu             |
| ograniczającego dostęp do zawartości witryny za pomocą zaledwie      |
| kilku wierszy kodu .                                                 |
|                                                                      |
| Inną kluczową różnicą pomiędzy Paid Memberships Pro a innymi tego    |
| typu wtyczkami jest to, że Paid Memberships Pro używa własnej tabeli |
| do zdefiniowania poziomów członkostwa oraz relacji pomiędzy          |
| użytkownikami i zamówieniami. Część wtyczek stosuje wbudowane w      |
| WordPressie role użytkowników, więc poszczególne poziomy członkostwa |
| odpowiadają także roli użytkownika. Jak pisaliśmy w rozdziale 6.,    |
| role użytkowników mają bardzo duże znaczenie w niektórych witrynach  |
| internetowych opartych na poziomie członkostwa. Jednak, ogólnie      |
| rzecz biorąc, lepiej jest rozdzielić koncepcje poziomu członkostwa i |
| roli użytkownika, ponieważ to pozwala np. na posiadanie członków     |
| będących administratorami i członków będących subskrybentami. Jeżeli |
| zachodzi potrzeba przypisywania ról na podstawie poziomu             |
| członkostwa, można to bardzo łatwo zrobić we wtyczce Paid            |
| Memberships Pro — odpowiedni przykład pokazujemy w dalszej części    |
| rozdziału.                                                           |
+----------------------------------------------------------------------+

Przedstawiamy kilka przykładów użycia zaczepów wtyczki Paid Memberships
Pro. Zanim przejdziemy do omawiania wybranych założeń e-commerce,
zaprezentujemy jeszcze jedną, unikatową wtyczkę.

Easy Digital Downloads

Wszystkie wymienione dotychczas wtyczki typu e-commerce mogą być używane
dla produktów cyfrowych i produktów fizycznych. Jednak jeśli planujesz
sprzedaż tylko produktów cyfrowych, powinieneś rozważyć wykorzystanie
wtyczki Easy Digital Downloads (https://easydigitaldownloads. com/),
która została utworzona właśnie do takich celów. Najważniejsze funkcje
tej wtyczki:

-   pobieranie plików zarezerwowane wyłącznie dla autoryzowanych
    klientów
-   możliwość jednoczesnego zakupu wielu plików do pobrania.

Dokumentację dotyczącą konfiguracji wtyczki Easy Digital Downloads oraz
inne ważne informacje na jej temat znajdziesz na stronie
https://docs.easydigitaldownloads.com/.

+----------------------------------------------------------------------+
| Dlaczego Easy Digital Downloads                                      |
|                                                                      |
| Easy Digital Downloads zawiera rozszerzenia przydatne dla            |
| programistów, takie jak Software Licensing i Product Support.        |
| Zarówno jądro wtyczki, jak i wszystkie rozszerzenia zostały          |
| doskonale opracowane i są dobrze obsługiwane.                        |
|                                                                      |
| Podobnie jak w przypadku wtyczki WooCommerce, podstawowa wtyczka     |
| Easy Digital Downloads jest dostępna bezpłatnie w repozytorium       |
| WordPressa, natomiast rozszerzenia dla niej można zakupić na         |
| oficjalnej witrynie internetowej. Wprawdzie rozszerzenia można       |
| kupować pojedynczo, ale większość użytkowników będzie się raczej     |
| skłaniała do zakupu jednego z pakietów dających jednocześnie dostęp  |
| do większości lub do wszystkich rozszerzeń w atrakcyjnej cenie.      |
+----------------------------------------------------------------------+

Przykładowe fragmenty kodów wykorzystujących wtyczkę Easy Digital Downloads

W tym punkcie przedstawiamy kilka fragmentów kodu pokazujących, w jaki
sposób używać funkcji i zaczepów wtyczki Easy Digital Downloads (EDD) w
większych aplikacjach WordPressa. Używając wywołania funkcji
edd_has_purchased(), można sprawdzić, czy użytkownik kupił określony
produkt, pobrany później za pomocą EDD. Jeśli już korzystasz z EDD w
celu sprzedawania programów na swojej witrynie internetowej, wymienionej
funkcji możesz użyć w celu ograniczania dostępu do innych stron lub
funkcjonalności aplikacji WordPressa.

    // Ograniczenie dostępu do strony, jeśli użytkownik nie wykupił możliwości pobrania określonego pliku

    function my_template_redirect_check_edd()

    {

        global $current_user;

        // Określenie slugu chronionej strony

        $protected_page_slug = 'customers-only';

        // Zdefiniowanie identyfikatora pobrania, pod kątem którego będzie przeprowadzone sprawdzenie

        $required_download_id = 184;

        // Chroniona jest tylko jedna, konkretna strona

        if(!is_page($protected_page_slug))

            return;

        // Przekierowanie w przypadku braku użytkownika lub niezakupienia produktu

        if(!is_user_logged_in() ||

                !edd_has_user_purchased($current_user->ID, $required_download_id)) {

            wp_redirect(get_permalink($required_download_id));

            exit;

        }

    }

    add_action('template_redirect', 'my_template_redirect_check_edd');

W tym przykładzie użyliśmy zaczepu template_redirect w WordPressie.
Jeżeli użytkownik nie kupił możliwości pobrania pliku, pod kątem którego
jest przeprowadzane sprawdzenie, zostanie przekierowany na stronę
frontendu dotyczącą danego pliku. To dobry sposób na zablokowanie
dostępu do całej strony (być może strony zawierającej treść lub skrót
dla formularza kontaktowego lub inną treść, do której użytkownik
niebędący klientem firmy nie powinien mieć dostępu).

Podobne operacje sprawdzenia można stosować jako opakowanie dla
samodzielnie tworzonego kodu PHP. Jeżeli robisz to często, takie
opakowanie dobrze jest umieścić w oddzielnej funkcji. W kolejnym
fragmencie kodu zaprezentowaliśmy funkcję pomocniczą pozwalającą na
sprawdzenie, czy użytkownik wykupił dostęp do danego pliku. Następnie ta
funkcja dodaje do menu podstawowego łącze prowadzące do pomocy
technicznej.

    // Funkcja pomocnicza, która sprawdza, czy użytkownik jest klientem

    function is_plugin_customer($user_id = null)

    {

        $plugin_download_id = 184;      // Uaktualnij to polecenie

        // Domyślnie to jest bieżący użytkownik

        if(empty($user_id))

        {

            global $current_user;

            $user_id = $current_user->ID;

        }

        return edd_has_user_purchased($user_id, $plugin_download_id);

    }

    // Dodanie do menu podstawowego łącza prowadzącego do pomocy technicznej. To jest łącze tylko dla klientów

    function add_support_link_to_menu($items, $args)

    {

        if($args->theme_location == 'primary' && is_plugin_customer())

        {

            $items .= '<li class="menu-item menu-item-type-post_type

                    menu-item-object-page menu-item-support">';

            $items .= '<a href="/support/">Pomoc techniczna</a>';

            $items .= '</li>';

        }

        return $items;

    }

    add_filter('wp_nav_menu_items', 'add_support_link_to_menu', 10, 2);

Funkcja is_plugin_customer() stosuje przydatną sztuczkę z parametrem
$user_id. Istnieje możliwość przekazania konkretnej wartości $user_id do
sprawdzenia lub, opcjonalnie, pozostawienie pustego parametru. W tym
drugim przypadku funkcja domyślnie użyje identyfikatora bieżącego
użytkownika. Identyfikator pobieranego pliku (identyfikator posta
podczas edycji tej wartości w panelu głównym) został na stałe
zdefiniowany w funkcji i jest używany w zwracanym wywołaniu
edd_has_user_purchased().

W ostatnim fragmencie kodu filtr wp_nav_menu_items został użyty w celu
dodania kolejnego łącza prowadzącego na stronę pomocy technicznej
przeznaczonej dla użytkowników, którzy zakupili wtyczkę.

Przedstawiamy tutaj ogólne koncepcje typu e-commerce, a następnie
zagłębimy się w przykłady pokazujące, jak można za pomocą WordPressa
zdefiniować model sprzedaży SaaS.

Bramki płatności

Bramka płatności jest usługą, która przetwarza, a czasem nawet
przechowuje informacje o karcie kredytowej klienta i daje pewność, że
pieniądze trafią na Twoje konto bankowe[3]. Popularnymi bramkami
płatności w Stanach Zjednoczonych są Stripe, PayPal, Authorize.net i
Braintree Payments. Istnieją jeszcze dziesiątki bramek płatności w
innych regionach świata, wiele z nich specjalizuje się w obsłudze
transakcji przeprowadzanych w określonych krajach lub na konkretnych
rynkach.

Oto lista najistotniejszych kwestii, na które trzeba zwrócić uwagę przy
wyborze bramki płatności:

-   Czy bramka płatności jest obsługiwana w kraju i w walucie, w których
    chcesz pobierać opłaty.
-   Czy bramka jest zintegrowana z wtyczką, której używasz do obsługi
    działalności typu e-commerce.
-   Czy bramka współpracuje z typem prowadzonej działalności. Niektóre
    bramki nie będą działać z witrynami dla dorosłych, witrynami
    hazardowymi lub innymi działalnościami obarczonymi „wysokim
    ryzykiem”.
-   Czy bramka oferuje funkcjonalności, których potrzebujesz, takie jak
    fakturowanie cykliczne, przechowywanie informacji o kartach
    kredytowych itd.
-   W jaki sposób bramka obsługuje zgodność z PCI (payment card
    industry)[4].
-   Czy bramka płatności będzie współpracować z Twoim kontem sprzedawcy
    (ta kwestia zostanie omówiona w następnym podrozdziale).
-   I na koniec, jakie są opłaty za korzystanie z bramki płatności.
    Jeden procent od 10 milionów dolarów to jednak dużo pieniędzy i
    dlatego warto powalczyć o niższe opłaty. Ogólnie rzecz biorąc,
    opłaty są porównywalne i szukając odpowiedniej bramki płatności,
    powinno się raczej zwracać uwagę na zgodność bramki z wymaganiami
    związanymi z Twoją działalnością. Wraz z rozwojem biznesu i wzrostem
    przychodów łatwiejsze stanie się negocjowanie obniżki opłat do
    wysokości standardowego minimum przyjętego w danej branży.

Konto sprzedawcy

Konto sprzedawcy (merchant account) jest często mylone z bramką
płatności, ale ten rodzaj konta jest zupełnie odrębną kwestią, potrzebną
do przetwarzania płatności na swojej witrynie internetowej. Po części
całe zamieszanie wynika stąd, że niektóre bramki płatności używają
własnego konta sprzedawcy.

Aby zarabiać pieniądze on-line, niezbędne są zarówno bramki płatności,
jak i konta sprzedawcy, a dostawcy tych usług pomogą Ci zabezpieczać
transakcje on-line. Oznacza to, że można szukać bramki płatności
oferującej także konto sprzedawcy albo szukać konta sprzedawcy
powiązanego od razu z bramką płatności. Uważamy, że młodsze firmy zwykle
mają ustalane opłaty na korzystniejszych warunkach, jeśli rozpoczynają
działalność od znalezienia bramki płatności powiązanej z określonym
kontem sprzedawcy, niż jeśli najpierw udają się do swojego banku, by
otworzyć konto sprzedawcy.

Informacje o karcie kredytowej i pieniądze przepływają od klienta
odwiedzającego Twoją witrynę internetową na Twój rachunek bieżący w
następujący sposób: WordPress/wtyczka typu e-commerce/ bramka
płatności/konto sprzedawcy/Twój rachunek bieżący.

Jedną z różnic pomiędzy bramką płatności i kontem sprzedawcy jest to, że
bramka płatności powiązana jest z technologią, natomiast konto
sprzedawcy z rodzajem prowadzonej działalności. Bramka płatności
zapewnia obsługę weryfikacji i obciążenia karty kredytowej i pozwala na
skonfigurowanie płatności cyklicznych. Możliwe jest równie
przechowywanie informacji o klientach w celu kolejnego rozliczenia.

Konto sprzedawcy jest rodzajem konta bankowego, na którym środki
przychodzące są przechowywane do chwili, gdy będą mogły być przelane na
Twój rachunek bankowy. Dlaczego pieniądze nie są przekazywane
bezpośrednio na Twoje konto bankowe? To opóźnienie wynika z oczekiwania
na weryfikację czeku lub karty kredytowej. Jeśli z jakiegoś powodu
wydający kartę kredytową zażąda zwrotu pieniędzy (np. na skutek błędu
lub żądania klienta), możliwe będzie pobranie pieniędzy z konta
sprzedawcy.

Ważne kwestie, na które należy zwrócić uwagę przy wyborze konta
sprzedawcy:

-   Czy wybrana bramka płatności będzie działać z kontem sprzedawcy.
-   Czy konto sprzedawcy będzie pasowało do Twojego typu działalności.
    Niektórych kont sprzedawcy nie można używać, jeżeli działalność
    związana jest z witrynami internetowymi przeznaczonymi dla
    dorosłych, z hazardem albo innymi typami działalności obarczonymi
    „wysokim ryzykiem”.
-   Czy konto sprzedawcy będzie odpowiednie dla wielkości Twojego typu
    działalności. Niektórych kont sprzedawcy nie można łączyć z nowymi
    podmiotami gospodarczymi na rynku, które zajmują się dostarczaniem
    bardzo drogich produktów (o cenach sięgających tysięcy dolarów
    amerykańskich).
-   Jak wygląda kwestia opłat. Czasem są one wliczone w cenę za bramkę
    płatności, innym razem zaś są to odrębne opłaty.

Zwykle najlepszym sposobem na zaakceptowanie płatności kartami
kredytowymi w internecie jest najpierw wybranie wtyczki, później bramki
płatności, a następnie dobranie odpowiedniego konta sprzedawcy.

Konfigurowanie modelu Saas przy użyciu wtyczki Paid Memberships Pro

Model pobierania opłaty w zamian za dostęp do aplikacji nosi nazwę SaaS.
W tym podrozdziale omówimy konfigurację wtyczki Paid Memberships Pro w
naszej aplikacji SchoolPress. Dla szkoły będzie dostępna opcja płatności
w kwocie 1000 USD rocznie.

Model SaaS

Model SaaS bazuje na tym, że zamiast zakupu oprogramowania w pudełku i
instalowania go na swoim komputerze wnosisz opłatę — zwykle miesięczną
lub roczną — za dostęp do aplikacji internetowej w chmurze. Firmy
korzystające z modelu SaaS to m.in. GitHub, Dropbox, Evernote, Aplikacje
Google, a nawet Microsoft Office.

Model SaaS jest popularny ze względu na to, że generuje raczej
przewidywalne, powtarzające się zyski. Stanowi również ważny sposób
zarabiania na oprogramowaniu typu open source, takim jak WordPress.
Skoro platforma WordPress jest dostępna na licencji GPL, to gdybyś miał
sprzedawać i rozpowszechniać kod utworzonego przez siebie oprogramowania
na bazie WordPressa, Twoi klienci mieliby prawo do otrzymania go na
licencji GPL i bezpłatnego, dalszego rozpowszechniania tego kodu.
Używanie modelu SaaS umożliwia klientom korzystanie z oprogramowania bez
konieczności przekazywania im kodu źródłowego.

Informacje zamieszczone w dalszej części podrozdziału pomogą w
skonfigurowaniu płatności — jednorazowej, miesięcznej lub rocznej — za
dostęp do Twojej aplikacji.

Etap 0. — ustalenie sposobu pobierania opłaty za korzystanie z aplikacji

Czy jest to opłata jednorazowa, czy miesięczna subskrypcja? A może to
roczna subskrypcja? Czy opłata naliczana jest automatycznie co roku, czy
należy ją odnawiać?

Należy sobie odpowiedzieć na wszystkie te pytania jeszcze przed
rozpoczęciem integracji wtyczką Paid Memberships Pro lub przed
tworzeniem kodu dostosowującego ją do własnych potrzeb. Jason napisał
świetną serię artykułów poświęconych wyborowi modelu płatności za
aplikacje internetowe i treść premium w witrynie internetowej
(https://www.paidmembershipspro.com/membership-pricing-basic-methods-part-1/).

W przypadku aplikacji SchoolPress będziemy naliczać opłatę roczną w
wysokości 1000 USD za każde konto szkoły. Szkoła po zarejestrowaniu
otrzyma dostęp do utworzonej dla niej witryny w sieci WordPressa (np.
myschool.schoolpress.com). Administrator witryny szkolnej będzie miał
możliwość dodawania do niej nauczycieli, a także innych treści.

Poziom członkostwa zostanie ustawiony w taki sposób, aby coroczne opłaty
były naliczane automatycznie.

Etap 1. — instalowanie i aktywowanie wtyczki Paid Memberships Pro

Wtyczka Paid Memberships Pro jest dostępna w repozytorium wtyczek
WordPressa, dzięki czemu jej instalacja i aktywacja jest dziecinnie
prosta (zobacz rysunek 15.1).

1.  Przejdź z panelu głównego WordPressa, a następnie wybierz opcję menu
    Wtyczki/Dodaj nową (Plugins/Add New).
2.  Znajdź wtyczkę Paid Memberships Pro i kliknij przycisk Zainstaluj
    teraz (Install).
3.  Opcjonalnie wpisz informacje o serwerze FTP (w niektórych usługach
    hostingowych nie jest to wymagane).
4.  Po prawidłowym zainstalowaniu wtyczki kliknij przycisk Włącz
    (Activate).

[]

Rysunek 15.1. Dodawanie nowej wtyczki

Etap 2. — ustalenie poziomu członkostwa

Teraz musisz zdefiniować poziom członkostwa.

1.  Przejdź z panelu głównego WordPress do nowo utworzonej strony
    Memberships.
2.  Kliknij łącze lub przycisk Add new level.
3.  Wpisz we właściwe pola formularza informacje dotyczące członkostwa,
    tak jak pokazaliśmy na rysunku 15.2. W omawianym przykładzie będą to
    następujące pola:
    1.  Name: <Nazwa szkoły>
    2.  Description: w tym miejscu powinien zarejestrować się
        administrator szkoły, aby móc utworzyć witrynę SchoolPress i
        mieć do niej dostęp
    3.  Confirmation Message: (pozostaw niewypełnione)
    4.  Initial Payment: 1000
    5.  Recurring Subscription: (zaznacz tę opcję)
        1.  Billing Amount: 1000
        2.  Per: 1
        3.  Days/Weeks/Years: Years
        4.  Billing Cycle Limit: 0
        5.  Custom Trial: (nie zaznaczaj)
    6.  Disable New Signups: (nie zaznaczaj)
    7.  Membership Expiration: (nie zaznaczaj)
    8.  Categories: (nie zaznaczaj żadnej opcji)
4.  Kliknij przycisk Save Level.

[]

Rysunek 15.2. Strona Add New Membership Level we wtyczce Paid
Memberships Pro

Etap 3. — konfiguracja stron

Wtyczka Paid Memberships Pro wymaga kilku stron, aby ułatwić realizację
transakcji i zapewnić obsługę innych funkcji związanych z członkostwem.
Gdy w ustawieniach tej wtyczki klikniesz kartę Pages, zostanie
wyświetlony formularz, który pokazaliśmy na rysunku 15.3.

[]

Rysunek 15.3. Generowanie stron dla wtyczki Paid Memberships Pro

Jeżeli już masz strony przeznaczone do przedstawienia poziomów
członkostwa lub kont użytkowników, możesz je wskazać za pomocą
rozwijanych na karcie Pages menu ustawień wtyczki Paid Memberships Pro.
Jednak w większości przypadków trzeba będzie kliknąć łącze „pozwalające
na automatyczne wygenerowanie odpowiednich stron”. To spowoduje
utworzenie stron o nazwach Account, Billing Information, Cancel,
Checkout, Confirmation, Invoice i Levels. Na rysunku 15.4 pokazaliśmy
stronę Pages po wygenerowaniu wymienionych stron.

[]

Rysunek 15.4. Strony domyślne wygenerowane przez wtyczkę Paid
Memberships Pro

Etap 4. — wybór ustawień płatności

Rysunek 15.5 pokazuje kartę Paymant Gateway & SSL ustawień wtyczki Paid
Memberships Pro. W tym miejscu możesz wybrać bramkę płatności oraz podać
odpowiednie wartości dotyczące użytkownika i API. W zależności od
wybranej bramki na tej stronie będzie można zmienić walutę, rodzaje
obsługiwanych kart kredytowych, włączyć szyfrowanie SSL (w rzeczywistych
aplikacjach internetowych zawsze powinieneś stosować szyfrowanie SSL) i
zdecydować się na użycie opcji Nuclear dla SSL.

[]

Rysunek 15.5. Karta Payment Gateway & SSL Settings w ustawieniach
wtyczki Paid Memberships Pro

Na stronie ustawień płatności można również wkleić kod SSL Seal Code,
podać stawkę podatku i inne dane. Obliczenie podatku może odbyć się
również programowo za pomocą filtru pmpro_tax (wkrótce do niego
powrócimy).

Strona płatności wyświetla również URL przeznaczony do współdzielenia z
bramką płatności, co pozwala na prowadzenie w tle komunikacji między
bramką płatności i witryną internetową. Nazwa tej funkcji różni się w
zależności od bramki płatności: w PayPalu jest określana mianem IPN
handler, w Authorize.net to silent post URL, w Stripe i Braintree to
webhook.

Etap 5. — wybór ustawień wiadomości e-mail

Domyślnie WordPress wysyła wiadomości e-mail z Twojej witryny
internetowej. Nadawcą jest WordPress z adresu
wordpress@<nazwa_domeny>.com. Ten zapis nie wygląda dobrze i często nie
jest prawdziwym adresem. Karta Email ustawień wtyczki Paid Memberships
Pro (pokazana na rysunku 15.6) umożliwia zmianę tych wartości, a także
wskazanie, które wiadomości e-mail związane z członkostwem chcesz
otrzymywać.

[]

Rysunek 15.6. Ustawienia wiadomości e-mail we wtyczce Paid Memberships
Pro

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Możesz wysyłać lepiej wyglądające wiadomości e-mail niezależnie od tego, czy używasz wtyczki Paid Memberships Pro. Zapoznaj się z zamieszczonym na stronie https://github.com/strangerstudios/paid-memberships-pro/blob/dev/includes/email.php kodem związanym z wiadomościami e-mail i dostosuj go do potrzeb swojej witryny internetowej.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Etap 6. — wybór ustawień zaawansowanych

Na rysunku 15.7 przedstawiona jest karta Advanced Settings zawierająca
kilka wbudowanych opcji uruchamiania wtyczki Paid Memberships Pro.
Szczególnie interesująca może być opcja wyboru strony Terms of Service,
która będzie wyświetlana użytkownikowi podczas rejestracji jego konta.
Zobaczysz przewijane pole tekstowe z wyświetloną zawartością strony TOS.
Konieczne będzie kliknięcie przycisku oznaczającego zaakceptowanie
warunków świadczenia usług.

[]

Rysunek 15.7. Ustawienia zaawansowane wtyczki Paid Memberships Pro

  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Od maja 2008 roku wtyczka Paid Memberships Pro jest także zintegrowana z podstawową funkcjonalnością WordPressa w zakresie obsługi RODO, czyli ogólnego rozporządzenia o ochronie danych (General Data Protection Regulation, GDPR) wprowadzonego na terenie Unii Europejskiej. Jeśli Twoja aplikacja będzie miała użytkowników z Unii Europejskiej (lub w ogóle jeśli zależy Ci na prywatności), powinieneś zastanowić się, w jaki sposób RODO ma zastosowanie dla Twojej aplikacji internetowej. Na blogu wtyczki Paid Memberships Pro Jason opublikował post (https://www.paidmembershipspro.com/getting-ready-for-gdpr/), w którym zamieścił dość szczegółowe omówienie kwestii związanych z GPDR i z tym, jak uaktualnił wtyczkę Paid Memberships Pro, aby pozostała zgodna z tą dyrektywą.
  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Etap 7. — uniemożliwianie dostępu do stron

Oprócz generowania strony finalizowania zamówienia oraz integrowania jej
z bramką płatności podstawową funkcjonalnością dodaną przez wtyczkę Paid
Memberships Pro jest uniemożliwianie dostępu do poszczególnych stron lub
ich fragmentów, w zależności od poziomu członkostwa użytkownika. Można
to zrobić na kilka sposobów.

Uniemożliwianie dostępu do konkretnej strony

Wtyczka Paid Memberships Pro dodaje pole wyboru Require Membership
(zobacz rysunek 15.8) do paska bocznego stron edycji posta i formularza
edycji stron w panelu głównym WordPressa. Aby zablokować stronę na danym
poziomie członkostwa, zaznacz pole wyboru obok nazwy pola tego poziomu.

[]

Rysunek 15.8. Wybór poziomów wymaganych do wyświetlenia danej strony

W przypadku wybrania więcej niż jednego poziomu członkowie każdego z
nich będą mogli wyświetlić daną stronę. Jeśli nie wybrano żadnego
poziomu, każdy odwiedzający witrynę internetową (nawet nie będąc
użytkownikiem) może przeglądać daną stronę.

Blokowanie dostępu do strony na podstawie adresu URL

Czasem łatwiej jest ograniczyć dostęp do strony lub grupy stron poprzez
sprawdzanie adresu URL strony. Na przykład, aby uniemożliwić dostęp do
strony użytkownikom nienależącym do grupy BuddyPress, należy dodać do
wtyczki poniższy fragment kodu.

    // Blokowanie dostępu do stron dla członków grupy

    function my_buddy_press_members_group()

    {

        $uri = $_SERVER['REQUEST_URI'];

        if(strtolower(substr($uri, 0, 16)) == "/groups/members/")

        {

            // Upewnienie się, że mamy do czynienia z członkiem grupy

            if(!pmpro_hasMembershipLevel())

            {

                wp_redirect(pmpro_url("levels"));

                exit;

            }

        }

    }

    add_action("init", "my_buddy_press_members_group");

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Od czasu wydania pierwszej edycji tej książki dla wtyczki Paid Memberships Pro powstał dodatek pozwalający na jej integrację z BuddyPress. W celu zablokowania BuddyPress użyj dodatku PMPro BuddyPress Add-on (https://www.paidmember shipspro.com/add-ons/buddypress-integration/). Zdecydowaliśmy się na pozostawienie tego przykładu w książce, ponieważ on dobrze pokazuje, w jaki sposób można ograniczyć każdy ogólny adres na podstawie poziomu członkostwa użytkownika.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

W tym przypadku podstawowym motorem napędowym jest funkcja
pmpro_hasMembershipLevel(). Może ona przyjmować dwa parametry. Pierwszym
jest identyfikator lub nazwa poziomu członkostwa, pod kątem którego ma
być przeprowadzone sprawdzenie. Drugim jest identyfikator użytkownika,
którego chcesz sprawdzić. Jeśli parametry nie zostaną przekazane,
funkcja będzie sprawdzać, czy bieżący użytkownik ma przypisany
jakikolwiek poziom członkostwa.

Istnieje możliwość sprawdzenia odwrotnego np. przez przekazanie wartości
-1 jako identyfikatora poziomu członkostwa. Jeśli bieżący użytkownik nie
ma przypisanego poziomu członkostwa 1, wynikiem wywołania
pmpro_hasMembershipLevel(-1) jest true. W przypadku przekazania
wymienionej funkcji parametru 0, sprawdzi ona, czy użytkownik nie ma
żadnego poziomu członkostwa. Dlatego wartością zwrotną wywołania
pmpro_hasMembershipLevel(0) będzie true, jeśli bieżący użytkownik nie ma
przypisanego poziomu członkostwa. (Można również użyć wywołania
!pmpro_hasMembershipLevel()).

Wiele identyfikatorów lub nazw poziomów członkostwa przekazuje się w
tablicy. Przykładowo, jeśli chcesz sprawdzić pod kątem poziomów
członkostwa 1 i 2, użyj następującego fragmentu kodu:

    if(pmpro_hasMembershipLevel(array(1,2)))

    {

        // Pewne operacje na poziomach członkostwa 1 i 2

    }

Ograniczanie dostępu do części strony na podstawie skrótu

Innym sposobem ograniczenia dostępu do treści jest użycie skrótu w
treści posta. Kolejny przykład przedstawia stronę, na której wyświetlona
treść będzie zależała od poziomu członkostwa.

    Witamy w aplikacji SchoolPress!

    [membership level="1"]Dziękujemy, że wciąż z nami jesteś.[/membership]

    [membership level="-1"]Zarejestruj szkołę![/membership]

Skrót [membership] jest dość prosty. Przyjmuje parametr w postaci
poziomu członkostwa. Podobnie jak w przypadku funkcji
pmpro_hasMembershipLevel(), może pobrać identyfikator lub nazwę poziomu
członkostwa, a także wartość 0 lub ujemną dla poziomu członkostwa. Treść
umieszczona w skrócie będzie wyświetlona na podstawie poziomu
członkostwa. Jeżeli chcesz przekazać więcej identyfikatorów, musisz je
rozdzielić przecinkami.

Ograniczanie dostępu do fragmentu strony za pomocą kodu PHP przy użyciu funkcji pmpro_hasMembershipLevel()

Blokując dostęp członkom grupy BuddyPress, użyliśmy funkcji
pmpro_hasMember shipLevel(). Tę funkcję można wywoływać również w
szablonach strony lub w innym fragmencie kodu, aby ograniczyć dostęp do
treści lub fragmentu kodu. Na przykład w nagłówku możesz znaleźć
następujący fragment kodu.

    <?php if(is_user_logged_in()) { ?>

    <div class="user-welcome">

      Witamy

    <?php if(function_exists("pmpro_hasMembershipLevel")

    && pmpro_hasMembershipLevel()) { ?>

            <a href="<?php echo pmpro_url("account"); ?>">

    <?php echo $current_user->display_name;?>

        </a>

    <?php } else { ?>

            <a href="<?php echo home_url("/wp-admin/profile.php"); ?>">

    <?php echo $current_user->display_name;?>

        </a>

    <?php } ?>

    </div> <!-- Koniec sekcji user-welcome -->

    <?php } ?>

Ten fragment kodu wyświetli członkom łącze do strony konta wtyczki Paid
Memberships Pro. Niezarejestrowanym użytkownikom wyświetli się łącze do
strony w repozytorium wtyczek WordPressa zawierającej informacje o tej
wtyczce .

Etap 8. — dostosowanie wtyczki Paid Memberships Pro do własnych potrzeb

W tym miejscu przedstawiamy kilka typowych modyfikacji wtyczki Paid
Memberships Pro. Zwykle proces dostosowywania wtyczki do własnych
potrzeb wygląda następująco:

1.  Zastanów się, co chcesz zmienić.
2.  Dowiedz się, gdzie jest domyślnie zdefiniowany sposób zachowania
    zmiany, którą chcesz wprowadzić.
3.  Odszukaj lub dodaj zaczep zapewniający obsługę wprowadzanej
    modyfikacji.
4.  Utwórz akcję lub filtr pozwalający na użycie zaczepu.

Ograniczanie dostępu do strony głównej użytkownikom, którzy nie są członkami

Domyślnie wtyczka Paid Memberships Pro nie ogranicza dostępu do żadnej
części witryny, o ile nie zostaną wprowadzone odpowiednie ustawienia. W
przypadku niektórych witryn internetowych konieczne będzie zapewnienie
jedynie bardzo ograniczonego dostępu publicznego (strony dotyczące
produktów, informacje o firmie i dane kontaktowe). Takie rozwiązanie
można zastosować przez przekierowanie niezarejestrowanych użytkowników
ze stron, do których nie powinni mieć dostępu. W tym celu użyj
następującego fragmentu kodu.

    function my_template_redirect()

    {

        $okay_pages = array(

            pmpro_getOption('billing_page_id'),

            pmpro_getOption('account_page_id'),

            pmpro_getOption('levels_page_id'),

            pmpro_getOption('checkout_page_id'),

            pmpro_getOption('confirmation_page_id')

        );

        // Niezarejestrowany użytkownik powinien zostać przekierowany na stronę główną witryny

        if(!is_user_logged_in()

            && !is_home()

            && !is_page($okay_pages)

            && !strpos($_SERVER['REQUEST_URI'], "login"))

        {

            wp_redirect(home_url('wp-login.php?redirect_to='.

                urlencode($_SERVER['REQUEST_URI'])));

        }

        elseif(is_page()

            && !is_home()

            && !is_page($okay_pages)

            && !pmpro_hasMembershipLevel()

        {

            wp_redirect(home_url());

        }

    }

    add_action('template_redirect', 'my_template_redirect');

W poprzednim fragmencie kodu skonfigurowaliśmy tablicę identyfikatorów
postów dla stron widocznych dla niezarejestrowanych użytkowników.
Funkcja pmpro_getOption() została użyta do pobrania identyfikatorów
stron wygenerowanych przez wtyczkę PMPro i jednocześnie do umożliwienia
dostępu do strony głównej za pomocą funkcji WordPressa is_home().
Zapewniony będzie również dostęp do każdej strony zawierającej w adresie
URL słowo login; w omawianym przykładzie będzie to tylko strona
logowania.

Ograniczanie dostępu do plików

Część stron, do których ograniczasz dostęp, może zawierać obrazy lub
łącza do innych plików. Jeśli ograniczysz dostęp do takiej strony, wtedy
łącze lub obraz nie będą widoczne dla użytkowników. Jednak użytkownicy
znający bezpośredni adres URL pliku będą mogli je pobrać bez
wcześniejszego logowania się. Jest to możliwe, ponieważ gdy serwer
Apache przetwarza adres URL w postaci
http://schoolpress.me/wp-content/uploads/logo.png, udostępnia ten plik
bezpośrednio, bez wcześniejszego sprawdzenia w PHP lub w WordPressie.

Możesz to zmienić przez modyfikację reguł dostępu w pliku .htaccess,
którego reguły pozwalają na przekierowanie dowolnego adres URL za pomocą
specjalnego skryptu dołączonego do wtyczki Paid Memberships Pro. Na
początku pliku .htaccess, przed innymi regułami przepisywania adresów,
dodaj przedstawiony tutaj fragment kodu.

    RewriteEngine On

    RewriteBase /

    RewriteRule ^wp-content/uploads/(.*)$ \

        /wp-content/plugins/paid-memberships-pro/services/getfile.php [L]

Na czym polega działanie tego kodu? W WordPressie obrazy i pliki mogą
być umieszczane w poście lub na stronie. Pliki te, nazywane w
WordPressie załącznikami (attachments), są umieszczane w katalogu
/wp-content/uploads/, choć za pomocą rekordów tabeli wp_post są
powiązane z postami, do których zostały dodane.

Załączniki są przechowywane w tabeli wp_posts, w której wartością
kolumny post_status jest attachment, a wartością kolumny post_parent
jest identyfikator posta, do którego załącznik został dodany.

Skrypt getfile.php wyszukuje w tabeli wp_posts odpowiedni rekord dla
żądanego pliku. Jeżeli element nadrzędny załącznika będzie wymagał
członkostwa, przed udostępnieniem tego pliku zostanie przeprowadzona
operacja sprawdzenia, czy zalogowany użytkownik ma odpowiednie
uprawnienia.

Zmiana roli użytkownika na podstawie poziomu członkostwa

W większości przykładów w tym podrozdziale przyjęliśmy założenie, że
użytkownik ma dostęp tylko do aplikacji frontendu witryny internetowej.
Jednak czasami zachodzi potrzeba umożliwienia użytkownikowi dostępu do
panelu głównego, przypisania mu roli author, aby mógł opublikować post
na blogu, bądź przypisania mu roli innej niż subscriber.

Przedstawiony tutaj fragment kodu przypisuje rolę author każdemu nowemu
użytkownikowi na danym poziomie członkostwa. Jeżeli użytkownik nie
będzie już na danym poziomie członkostwa, zostanie mu przypisana rola
subscriber.

    function my_pmpro_after_change_membership_level($level_id, $user_id)

    {

        if($level_id == 1)

        {

            // Nowy członek na poziomie 1

            // Jeżeli jest w roli subscriber, powinien otrzymać rolę author

            $wp_user_object = new WP_User($user_id);

            if(in_array('subscriber', $wp_user_object->roles))

                $wp_user_object->set_role('author');

        }

        else

        {

            // To nie jest poziom członkostwa 1

            // Jeżeli jest w roli author, powinien otrzymać rolę subscriber

            $wp_user_object = new WP_User($user_id);

            if(in_array('author', $wp_user_object->roles))

                $wp_user_object->set_role('subscriber');

        }

    }

    add_action(

        'pmpro_after_change_membership_level',

        'my_pmpro_after_change_membership_level',

        10,

        2

    );

Więcej informacji na temat użytkowników i ról zamieściliśmy w rozdziale
6.

Formularz adresu

Domyślnie oferowany przez wtyczkę Paid Memberships Pro formularz
składania zamówienia zawiera w oddzielnych wierszach pola adresu nazwę
miejscowości nazwę stanu w USA i kod pocztowy. Rozwijane menu
pozwalające na wybór kraju jest wyświetlane na końcu formularza, jak
pokazujemy na poniższym rysunku.

[]

Rysunek 15.9. Pola adresu w formularzu składania zamówienia wtyczki Paid
Memberships Pro

Masz możliwość zmiany domyślnie wybranego kraju, listy krajów lub
oznaczenia wybranych pól jako tych, które nie są wymagane. Spójrz na
przykład kodu, w którym zastosowano takie rozwiązanie.

    /*

        Zmiana kraju domyślnego z USA na PL (Polska)

    */

    function my_pmpro_default_country($default)

    {

        return 'PL';

    }

    add_filter('pmpro_default_country', 'my_pmpro_default_country');

    /*

            Usunięcie i dodanie pewnych krajów na liście domyślnej

    */

    function my_pmpro_countries($countries)

    {

        // Usunięcie USA

        unset($countries['US']);

        // Dodanie Księżyca (KS to skrót od słowa księżyc)

        $countries['KS'] = 'Księżyc';

        // Tablicę krajów można utworzyć od zera

        //$countries = array('CA' => 'Kanada', 'GB' => 'Wielka Brytania',

        // 'PL' => 'Polska');

        return $countries;

    }

    add_filter('pmpro_countries', 'my_pmpro_countries');

    /*

            (Opcjonalnie) Określone kraje można usunąć z listy lub dopisać je na nią

        Na to pozwala filtr pmpro_countries

            Tablica jest sformatowana w następującej postaci:

        array('PL'=>'Polska', 'GB'=>'Wielka Brytania');

        w której skrót jest kluczem, wartością natomiast

            jest nazwa kraju

    */

    function my_pmpro_countries($countries)

    {

        // Usunięcie USA

        unset($countries['US']);

        // Dodanie Księżyca (KS to skrót od słowa księżyc)

        $countries['KS'] = 'Księżyc';

        // Tablicę krajów można utworzyć od zera

        //$countries = array('CA' => 'Kanada', 'GB' => 'Wielka Brytania',

        // 'PL' => 'Polska');

        return $countries;

    }

    add_filter('pmpro_countries', 'my_pmpro_countries');

    /*

            Zmiana pól płatnika może nie być wymagana

            Domyślne pola to: bfirstname, blastname, baddress1, bcity, bstate,

        bzipcode, bphone, bemail, bcountry, CardType, AccountNumber,

        ExpirationMonth, ExpirationYear i CVV

    */

    function my_pmpro_required_billing_fields($fields)

    {

        // Usunięcie pól nazwy stanu i kodu pocztowego

        unset($fields['bstate']);

        unset($fields['bzipcode']);

        return $fields;

    }

    add_filter('pmpro_required_billing_fields', 'my_pmpro_required_billing_fields');

[1] Co należy uznać za „platformę typu e-commerce”? Czy wielkość udziału
w rynku powinna być określana na podstawie liczby witryn internetowych,
czy może na podstawie wielkości sprzedaży? Jak można obliczyć udział
w rynku w przypadku rozwiązań e-commerce, takich jak Shopify lub Amazon?

[2] W chwili pisania tej książki, według informacji opublikowanych w
witrynie BuiltWith (https://trends.builtwith.com/shop), około 21 procent
witryn internetowych typu e-commerce z listy miliona największych używa
wtyczki WooCommerce.

[3] Oczywiście kwota zostanie pomniejszona o wymagane opłaty.

[4] Na wysokim poziomie zgodność z PCI wymaga znacznie bardziej
kosztownej konfiguracji serwera i wielu zasobów niezbędnych do jej
prawidłowej obsługi i dokumentacji. W przypadku części bramek płatności
istnieje technologia i procesy pomagające w uniknięciu tych kosztów i
jednoczesnym zapewnieniu bezpieczeństwa danych klientów.

Rozdział 16. Aplikacje mobilne na bazie WordPressa

Aplikacje mobilne na bazie WordPressa działające na platformach iOS i
Android? Pewnie, dlaczego nie? Możesz wykorzystywać na wiele sposobów
możliwości WordPressa w zakresie tworzenia zarówno natywnych, jak i
hybrydowych aplikacji mobilnych.

Zanim zagłębimy się w ten temat, zastanówmy się nad przykładowym
zastosowaniem takich aplikacji. Chociaż możliwości są nieograniczone,
mamy tutaj na myśli aplikacje oparte na treści. Omówimy także kilka
kwestii, o których powinieneś wiedzieć, tworząc hybrydowe aplikacje
mobilne.

Przypadki użycia aplikacji mobilnych

OK, mamy zatem aplikacje mobilne, które mogą wyświetlać treść pochodzącą
z aplikacji internetowej. Na ile to jest proces interaktywny? Hybrydowe
aplikacje mobilne na bazie WordPressa mogą być tak interaktywne, jak im
pozwolisz! Wszystko to, co możesz zrobić w WordPressie, okazuje się
również możliwe w hybrydowej aplikacji mobilnej.

-   Użytkownicy mogą się logować do Twojej aplikacji za pomocą konta w
    serwisie Facebook, Twitter lub w innym portalu społecznościowym,
    który umożliwia pojedyncze logowanie (single sign-on, SSO).
-   Możliwe, że Twoja aplikacja jest sklepem internetowym obsługiwanym
    przez wtyczkę Woo-Commerce, więc umożliwia klientom przeglądanie i
    kupowanie produktów bezpośrednio z poziomu aplikacji. Być może Twoja
    aplikacja pozwala także wielu sprzedawcom na otwieranie sklepów w
    Twojej sieci, dzięki której mogą zarządzać oferowanymi produktami i
    usługami oraz przesyłać zdjęcia tych produktów w czasie
    rzeczywistym, bezpośrednio ze swojego urządzenia.
-   Może się także zdarzyć, że zbudowałeś serwis randkowy dzięki
    BuddyPress. Utworzenie markowej aplikacji mobilnej dla tego serwisu
    może przyczynić się do wzrostu jego popularności i tym samym do
    zwiększenia bazy członków. Dzięki funkcjom urządzenia mobilnego
    takim jak aparat członkowie mediów społecznościowych mogą wykonywać
    selfie i przesyłać bezpośrednio do swojego profilu.
-   Możesz też zbudować witrynę internetową przeznaczoną do handlu
    nieruchomościami, aby agenci mogli tworzyć nowe posty za pomocą
    niestandardowego typu postów (np. o nazwie Domy) dla nieruchomości
    przeznaczonych na sprzedaż. Dzięki aplikacji internetowej
    użytkownicy mogą robić zdjęcia i publikować je, podając długość i
    szerokość geograficzną, aby oferta została zamieszczona w serwisie
    Mapy Google.
-   Możesz utworzyć aplikację mobilną dla firm budowlanych, firm
    świadczących usługi hydrauliczne, architektoniczne, elektryczne,
    medyczne, stomatologiczne, księgowe lub jakiekolwiek inne usługi
    fizyczne. Aplikacja mobilna pomoże tym firmom śledzić zlecenia,
    uzyskiwać dostęp do danych klienta, przesyłać zdjęcia i filmy,
    monitorować za pomocą GPS miejsce kolejnych zleceń, współpracować z
    kontrahentami oraz zaoferować wiele innych funkcjonalności.
-   Być może już zainwestowałeś czas i pieniądze w system oparty na
    bazie WordPressa, który chcesz udostępnić za pośrednictwem aplikacji
    umieszczonej w sklepach aplikacji dla urządzeń mobilnych.

Możliwości tworzenia są nieograniczone i możesz wbudować praktycznie
dowolną ilość funkcjonalności natywnej w hybrydową aplikację mobilną. W
razie potrzeby zawsze możesz utworzyć w pełni natywną aplikację mobilną
i nadal zapewnić w niej dostęp do aplikacji internetowej WordPressa, aby
treść i baza użytkownika pozostały takie same na wszystkich platformach.

Natywne i hybrydowe aplikacje mobilne

Użycie interfejsu API REST WordPressa w pełni natywnej lub hybrydowej
aplikacji mobilnej byłoby preferowanym sposobem integracji z WordPressem
i optymalizacji wydajności działania aplikacji. Jeśli jesteś programistą
aplikacji natywnych lub dopiero zamierzasz nim zostać, powinieneś się
zainteresować taką właśnie metodą. Jeśli natomiast jesteś programistą i
nie masz zamiaru uczyć się języka Objective-C, Swift, Kotlin lub Java,
hybrydowa aplikacja mobilna jest tą, której potrzebujesz, więc trafiłeś
na odpowiednią książkę.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   W zależności od określonych potrzeb danego projektu oraz umiejętności zarówno Twoich, jak i całego zespołu programistów, hybrydowa aplikacja mobilna nie zawsze musi być najlepszym rozwiązaniem.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Co to jest natywna aplikacja mobilna

Natywna aplikacja mobilna to przeznaczona dla smartfona i/lub tabletu
aplikacja, która została utworzona w określonym języku programowania dla
konkretnego systemu operacyjnego:

-   Swift = iOS
-   Java = Android.

Oto wybrane korzyści płynące z tworzenia natywnej aplikacji mobilnej.

Wydajność

Aplikacje natywne są tworzone i optymalizowane z myślą o określonych
platformach wykorzystujących podstawowe języki programowania, biblioteki
oraz interfejsy API, dzięki którym są bardzo szybkie i responsywne.

Biblioteki natywne

Wykorzystywanie i bezpośredni dostęp do wszystkich bibliotek natywnych
ma ogromną przewagę nad zapewnieniem dostępu tylko do samych funkcji
biblioteki natywnej za pośrednictwem wtyczek opakowujących tę
funkcjonalność.

Bezpieczeństwo

Aplikacje natywne mogą być bezpieczniejsze niż hybrydowe, ponieważ
zależą tylko od platformy, na której zostały utworzone. Aplikacje
hybrydowe natomiast uzależnione są od wielu technologii, takich jak
JavaScript, HTML i CSS.

Oto niektóre wady tworzenia natywnej aplikacji mobilnej.

Czasochłonność

Aby umieścić aplikację w więcej niż jednym sklepie z aplikacjami
mobilnymi, trzeba czasem coś utworzyć więcej niż tylko raz.

Konieczność wydania większej sumy pieniędzy

Pomijając już kwestię konieczności poświęcania czasu na tworzenie tych
samych rozwiązań na różnych platformach, zatrudnienie programistów
zajmujących się tworzeniem kodu dla platform iOS i Androida zwyczajnie
kosztuje więcej.

Mniejsza liczba fachowców

Na rynku jest o wiele więcej programistów aplikacji internetowych niż
programistów natywnych aplikacji mobilnych.

Co to jest hybrydowa aplikacja mobilna

Aplikacja hybrydowa, podobnie jak natywna, działa na smartfonach i
tabletach, jednak została utworzona przy użyciu technologii
internetowych, takich jak JavaScript, HTML5 i CSS. Aplikacja hybrydowa
działa w natywnym kontenerze albo w opakowaniu aplikacji; używa silnika
przeglądarki WWW urządzenia do wygenerowania kodu znaczników HTML i
lokalnego przetworzenia skryptu JavaScript. Aby mieć dostęp do natywnych
funkcji urządzeń, takich jak akcelerometr, aparat, GPS i pamięć lokalna,
możesz za pomocą JavaScriptu tworzyć i używać natywnych wtyczek. Ogólnie
rzecz biorąc, aplikacja hybrydowa to umieszczona wewnątrz aplikacji
natywnej witryna internetowa, która ma wyglądać i działać jak pełna
aplikacja natywna.

Dlaczego lepiej wybrać aplikację hybrydową zamiast natywnej

Obecnie ponad dwie trzecie programistów aplikacji mobilnych częściej
decyduje się na tworzenie aplikacji hybrydowych niż natywnych.
Najczęstszym powodem takiej decyzji i coraz większej popularności
hybrydowych aplikacji mobilnych jest oszczędność czasu i pieniędzy.
Wyobraź sobie, ile czasu musicie poświęcić — zarówno Ty, jak i Twoja
firma — na tworzenie, obsługiwanie i konserwowanie zupełnie nowej
witryny internetowej, natywnej aplikacji iOS i natywnej aplikacji
Android. Jeżeli trzykrotnie tworzysz podobny interfejs użytkownika i
powielasz tę samą funkcjonalność, będziesz zmuszony do obsługi trzech
baz kodu. Opracowanie aplikacji hybrydowej będzie wymagało poświęcenia
ułamka czasu, który byłby potrzebny na opracowanie odpowiadających jej
aplikacji natywnych. Jest to możliwe, ponieważ pojedynczą bazę kodu,
podobnie jak w przypadku WordPressa, można wykorzystać do przygotowania
funkcji i funkcjonalności udostępnianych później przez aplikację na
różnych platformach, np. iOS i Android. To prawda, że w niektórych
przypadkach w zasadzie oznacza to wczytanie witryny internetowej w
elemencie iframe aplikacji. Jeżeli jednak aplikacja działa zgodnie z
oczekiwaniami lub wymaganiami klienta sklepu z aplikacjami dla urządzeń
mobilnych, może być to najefektywniejsze pod względem kosztów
rozwiązanie.

Oto wybrane zalety tworzenia hybrydowych aplikacji mobilnych na bazie
WordPressa.

Rób to, na czym się znasz

Zarówno Ty, jak i członkowie Twojego zespołu pracujecie już w
WordPressie. Poświęć więc czas na tworzenie ciekawych funkcjonalności
dla Twojej aplikacji zamiast na poznawanie zagadnień związanych z
tworzeniem aplikacji.

Wspólna baza kodu

Nie ma potrzeby odkrywania Ameryki po raz drugi. Aby dodać
niestandardową funkcjonalność do aplikacji mobilnej, wystarczy przejść
do repozytorium wtyczek WordPressa i znaleźć odpowiednią, która zawiera
wymaganą funkcjonalność, lub utworzyć nową wtyczkę zupełnie od początku.
Witryna internetowa, aplikacja iOS i aplikacja Android mogą korzystać a
tej samej bazy kodu.

Spójny UX

Skoro korzystasz z technologii internetowych, takich jak JavaScript,
HTML i CSS, bardzo łatwo możesz uaktualniać i zarządzać UX, aby zapewnić
jego spójność na wszystkich platformach, na których jest uruchamiana
aplikacja.

Zabezpieczenie na przyszłość

Korzystaj z zaawansowanych technologii internetowych i stosów
programistycznych ułatwiających tworzenie aplikacji mobilnych oraz ich
wdrażanie i aktualizowanie. Platforma internetowa pozwala na łatwe
rozszerzenie zasięgu aplikacji na wiele platform, które istnieją
obecnie, a także tych, które dopiero powstaną w przyszłości.

Cordova

Apache Cordowa to framework internetowy typu open source przeznaczony do
tworzenia hybrydowych aplikacji mobilnych z wykorzystaniem technologii
HTML, CSS i JavaScript.

PhoneGap

PhoneGap będący własnością Adobe jest komercyjną wersją frameworka
Cordova. Podobnie jak w przypadku WordPress.com i WordPress.org, Cordova
współdzieli z PhoneGap tę samą bazę kodu. PhoneGap w rzeczywistości jest
frameworkiem Cordova, ale wyposażonym w łatwy w obsłudze kompilator oraz
posiadającym dostępne opcje w zakresie pomocy technicznej.

Instalowanie frameworka Cordova

Utwórz katalog dla projektów aplikacji i przejdź do niego w powłoce. Aby
zainstalować framework Cordova, zainstaluj najpierw Node.js
(https://nodejs.org/en/), czyli środowisko uruchomieniowe JavaScript
dostępne w postaci oprogramowania typu open source. Następnie w powłoce
wydaj polecenie node -v. Wyświetli ono bieżącą wersję Node.js i tym
samym potwierdzisz, że masz zainstalowaną i działającą platformę
Node.js.

Do instalacji frameworka Cordova używamy menedżera pakietów npm. Wydaj w
powłoce polecenie sudo npm install cordova -g, zwróć uwagę na parametr
-g oznaczający globalną instalację frameworka. Po zakończeniu instalacji
w powłoce powinien zostać wyświetlony komunikat zawierający m.in.
bieżącą wersję frameworka Cordova.

W celu utworzenia nowego projektu aplikacji, wydaj odpowiednie polecenie
cordova create TestApp com.apppresser.apps.testapp TestApp w katalogu, w
którym chcesz przechowywać projekt aplikacji. W wymienionym poleceniu
użyj wartości odpowiednich dla tworzonego projektu. Polecenie cordova
create przyjmuje trzy parametry:

-   Katalog projektu aplikacji: TestApp
-   Nazwa pakietu aplikacji: com.apppresser.apps.testapp (zwykle jest
    stosowana odwrotna nazwa domeny)
-   Nazwa aplikacji: TestApp.

Przejrzyjmy pokrótce pliki i katalogi utworzone w projekcie Cordova.

config.xml

Plik ustawień domyślnych stosowany w wersjach frameworka Cordova
wcześniejszych niż wersja 7.

package.json

Plik ustawień domyślnych stosowany począwszy od wersji 7. frameworka.

hooks

Zaczepy Cordova to niestandardowe skrypty przeznaczone do dostosowywania
do własnych potrzeb poleceń frameworka Cordova.

platforms

Domyślnie ten katalog platformy jest pusty. Został przeznaczony dla
plików i kodu używanego podczas integracji frameworka Cordova z każdym
SDK (software development kit), np. dla platform Android i iOS.

plugins

Wtyczki Cordova używane przez Twoje aplikacje. Są to wszystkie wtyczki
współdziałające z funkcjami natywnymi.

www

Wszystkie zasoby internetowe, które zostaną opakowane widokiem
internetowym aplikacji.

Nadszedł najwyższy czas, aby dodać platformy do projektu nowej
aplikacji. Jednak wcześniej warto zapoznać w oficjalnej witrynie
internetowej frameworka Cordova z obsługiwanymi przez niego platformami.
Pozwoli to upewnić się, że Twoje środowisko pracy spełnia wszystkie
wymagania platformy, dla której będzie tworzona aplikacja.

-   Android Platform Guide
    (https://cordova.apache.org/docs/en/latest/guide/platforms/android/
    index.html)
-   iOS Platform Guide
    (https://cordova.apache.org/docs/en/latest/guide/platforms/ios/index.html)
      ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
      []   Pełną listę dostępnych poleceń można znaleźć na stronie Cordova Command-line-interface (CLI) Reference pod adresem https://cordova.apache.org/docs/en/latest/ reference/cordova-cli/.
      ---- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Cordova i Android

Przed dodaniem wszystkich niezbędnych plików frameworka Cordova
potrzebnych do korzystania z Android SDK upewnij się, że masz dostęp do
Android SDK za pomocą Android Studio
(https://developer.android.com/studio). Jeśli nie masz jeszcze
oprogramowania Android Studio, koniecznie je zainstaluj.

  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeśli zamierzasz korzystać z emulatora, upewnij się, że masz zainstalowane oprogramowanie Android Emulator z menedżera Android SDK (https://developer.android. com/studio/command-line/sdkmanager).
  ---- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Po zainstalowaniu Android Studio wydaj następujące polecenie w powłoce z
poziomu katalogu projektu nowej aplikacji.

    $ cordova platform add android

W powłoce powinny zostać wygenerowane następujące dane wyjściowe.

    Brians-MBP:TestApp bmess$ cordova platform add android

    Using cordova-fetch for cordova-android@^8.0.0

    Adding android project...

    Creating Cordova project for the Android platform:

            Path: platforms/android

            Package: com.apppresser.apps.testapp

            Name: TestApp

            Activity: MainActivity

            Android target: android-28

    Subproject Path: CordovaLib

    Subproject Path: app

    Android project created with cordova-android@8.1.0

    Plugin 'cordova-plugin-whitelist' found in config.xml... Migrating it to

    package.json

    Discovered saved plugin "cordova-plugin-whitelist". Adding it to the project

    Installing "cordova-plugin-whitelist" for android

    Adding cordova-plugin-whitelist to package.json

Jeśli zajrzysz do katalogu platforms w projekcie aplikacji, zobaczysz w
nim nowy podkatalog android zawierający wszystkie domyślne zasoby Twojej
aplikacji, potrzebne do jej uruchomienia na platformie Android.

Jeśli chcesz skompilować projekt nowej aplikacji w celu jego
przetestowania, musisz w powłoce wydać polecenie cordova build. To
polecenie utworzy Twoją aplikację dla wszystkich dostępnych platform.
Istnieje również możliwość utworzenia aplikacji jedynie dla określonej
platformy, wymaga to wydania w powłoce polecenia takiego jak cordova
build android.

Po wyświetleniu w powłoce komunikatu zawierającego wyrażenie BUILD
SUCCESSFUL zobaczysz ścieżkę dostępu do katalogu zawierającego nowo
utworzony plik .apk. Plik ten to skompilowana aplikacja dla systemu
Android, którą możesz zainstalować i przetestować na dowolnym urządzeniu
działającym pod kontrolą Androida. W celu podłączenia urządzenia z
Androidem bezpośrednio do komputera i skonfigurowania go do testowania
należy uruchomić aplikację bezpośrednio na urządzeniu, wydając w powłoce
polecenie cordova run android.

Jeśli nie masz urządzenia z Androidem, a chcesz przetestować swoją
aplikację w emulatorze Android, w powłoce wydaj polecenie cordova
emulate android.

Cordova i iOS

Podobnie jak potrzebny był dostęp do plików SDK Android za pomocą
Android Studio, tak samo potrzebny jest dostęp do plików iOS SDK za
pomocą Xcode. Jeśli nie masz zainstalowanego programu Xcode, musisz to
zrobić teraz (w przeciwnym wypadku nie będzie możliwości tworzenia
aplikacji iOS).

Aby do nowego projektu Cordova dodać iOS jako obsługiwaną platformę,
należy w powłoce wydać polecenie cordova platform add ios. Spowoduje ono
wyświetlenie następujących danych wyjściowych:

    Brians-MBP:TestApp bmess$ cordova platform add ios

    Using cordova-fetch for cordova-ios@^5.0.0

    Adding ios project...

    Creating Cordova project for the iOS platform:

            Path: platforms/ios

            Package: com.apppresser.apps.testapp

            Name: TestApp

    iOS project created with cordova-ios@5.0.1

    Installing "cordova-plugin-whitelist" for ios

    Brians-MBP:TestApp bmess$

Polecenia powłoki frameworka Cordova służące do tworzenia, uruchamiania
i emulacji aplikacji iOS odpowiadają poleceniom używanym podczas
tworzenia aplikacji dla platformy Android. Różnią się jedynie dodawanym
na końcu przyrostkiem ios.

cordova build ios

Kompiluje projekt na postać aplikacji gotowej do uruchomienia.

cordova run ios

Uruchamia aplikację bezpośrednio w urządzeniu iOS, skonfigurowanym do
testowania i podłączonym do komputera.

cordova emulate ios

Uruchamia aplikację iOS w emulatorze iOS.

Wtyczki Cordova

Podobnie jak WordPress posiada wtyczki mogące poprawić funkcjonalność
Twojej witryny internetowej, tak samo Cordova ma wtyczki rozszerzające
funkcjonalność aplikacji. Wtyczki frameworka Cordova poprzez JavaScript
współpracują z natywnymi funkcjami urządzenia.

Dostępne są wbudowane wtyczki Cordova oraz wtyczki opracowane przez inne
firmy, możliwe do zainstalowania i używania w Twojej aplikacji. Masz
również możliwość samodzielnego tworzenia wtyczek. Do wbudowanych
wtyczek Cordova zaliczamy m.in.:

BatteryStatus

Zapewnia interfejs API z dostępem do zdarzeń batterystatus,
batterycritical oraz batterylow.

Camera

Zapewnia interfejs API do robienia zdjęć i wybierania zdjęć z biblioteki
obrazów urządzenia.

Capture

Zapewnia dostęp do funkcji przechwytywania dźwięku, obrazu i wideo.

Connection

Dostarcza informacje o połączeniach komórkowym i WiFi, a także
informuje, czy urządzenie posiada dostęp do internetu.

Device

Dostarcza informacje o sprzęcie i oprogramowaniu urządzenia.

Events

Dostarcza różne komponenty nasłuchujące zdarzenia, które mogą być
wykorzystywane w aplikacji, m.in.: deviceready, pause, resume,
backbutton, menubutton, searchbutton, startcallbutton, endcallbutton,
volumedownbutton, volumeupbutton i activated.

File

Implementuje interfejs API plików umożliwiający dostęp na poziomie
odczytywania i zapisywania plików znajdujących się w urządzeniu.

Geolocation

Dostarcza informacje o położeniu urządzenia, takich jak szerokość i
długość geograficzna.

Globalization

Dostarcza informacje i wykonuje operacje specyficzne dla ustawień
regionalnych urządzenia, języka i strefy czasowej.

InAppBrowser

Umożliwia wyświetlanie stron internetowych z poziomu aplikacji, bez
konieczności jej opuszczania.

Media

Zapewnia możliwość nagrywania i odtwarzania plików audio na urządzeniu.

Notification

Umożliwia dostęp do elementów natywnego interfejsu użytkownika, takich
jak alert, confirm, prompt i beep.

Splashscreen

Wyświetla i ukrywa winietkę aplikacji podczas jej uruchamiania.

Status bar

Zapewnia funkcję dostosowywania do własnych potrzeb elementu StatusBar w
aplikacjach na platformach iOS i Android.

Storage

Zapewnia funkcję lokalnego przechowywania danych w urządzeniu.

Vibration

Umożliwia użycie funkcji alarmu wibracyjnego w urządzeniu.

Listę pozostałych wtyczek niebędących wbudowanymi wtyczkami Cordova
znajdziesz na stronie https://cordova.apache.org/plugins/.

W celu dodania wtyczki Cordova do Twojego projektu użyj polecenia
cordova plugin add z nazwą wtyczki. Przykładowo, aby dodać wtyczkę
camera do projektu, należy użyć pełnej nazwy wtyczki na końcu polecenia:

    $ cordova plugin add cordova-plugin-camera

Można także dodać wtyczkę, używając adresu URL repozytorium Git, np.:

    $ cordova plugin add https://github.com/apache/cordova-plugin-camera.git

W dowolnym momencie w katalogu projektu możesz wyświetlić listę
zainstalowanych wtyczek, wystarczy wydać polecenie cordova plugin ls.

Framework Ionic

Framework Ionic jest dostępną jako open source platformą służącą do
tworzenia aplikacji mobilnych, ułatwiającą budowanie natywnych aplikacji
zarówno w systemie iOS, jak i Android. Pozwala również na tworzenie
progresywnych aplikacji internetowych przy użyciu JavaScriptu, HTML-u i
CSS-a.

Ionic współdziała z frameworkiem Cordova i oferuje obszerną bibliotekę
narzędzi powłoki, dzięki której możliwe jest wydawanie praktycznie
wszystkich poleceń zaprezentowanych w tej sekcji.

1.  Zainstaluj Ionic CLI ze strony
    https://ionicframework.com/docs/intro/cli. Po zainstalowaniu
    platformy Node.js i menedżera pakietów npm wydaj następujące
    polecenie:

        $  sudo npm install -g ionic

    -   Sprawdź zainstalowaną wersję Ionic za pomocą polecenia ionic -v.
    -   Sprawdź zainstalowaną wersję Node.js za pomocą polecenia node
        -v.
    -   W celu zainstalowania frameworków Cordova i Ionic, użyj
        polecenia sudo npm install -g cordova ionic.

2.  Po zainstalowaniu Ionic, rozpocznij pracę nad nową aplikacją przez
    wydanie polecenia start frameworka Ionic z przekazaną mu nazwę
    aplikacji, typem szablonu i nazwą używanego frameworka (w omawianym
    przykładzie zdecydowaliśmy się na szablon tabs, do dyspozycji masz
    jeszcze wiele innych szablonów).

        $ ionic start SchoolApp tabs angular

3.  Przejdź do katalogu nowego projektu Ionic i wyświetl listę plików:

        $ cd SchoolApp

        $ ls

4.  Z poziomu katalogu projektu nowej aplikacji wydaj polecenie ionic
    serve, aby w ten sposób udostępnić tę aplikację w przeglądarce WWW.
    Bum! Natychmiast otrzymałeś progresywną aplikację internetową.

5.  W celu dodania natywnych możliwości w projekcie aplikacji opartej na
    Ionic i Cordova należy wydać następujące polecenia:

        $ ionic cordova platform add android

        $ ionic cordova platform add ios

    W ten sposób do nowego pliku Ionic zostaną dodane odpowiednie pliki
    platformy Cordova.

    Wydanie polecenia ionic cordova build android spowoduje kompilację
    aplikacji i wygenerowanie pliku .apk.

6.  Wydaj polecenie ionic cordova emulate android w celu uruchomienia
    nowej aplikacji w emulatorze urządzenia Android.

    Aplikację można uruchomić również w emulatorze urządzenia iOS.

        $ ionic cordova emulate ios --no-native-run

Jeśli nie masz wyraźnie zdefiniowanego celu w emulatorze, będziesz
musiał mieć uruchomiony emulator, w którym ma zostać wypróbowana
aplikacja.

Teraz możesz rozpocząć tworzenie progresywnych, opartych na WordPressie
aplikacji na platformy iOS i Android! Masz kilka możliwości. Przede
wszystkim możesz budować lokalne strony aplikacji mobilnych, które za
pomocą JavaScriptu pobierają treść z API REST WordPressa. Ewentualnie
możesz wczytać strony WordPressa w widoku internetowym i zastosować
specjalny, responsywny motyw dla aplikacji mobilnej, jeśli go kupiłeś
lub opracowałeś samodzielnie. Obie metody mają swoje zalety; w projekcie
aplikacji możesz używać ich obydwu w zależności od tego, co chcesz
zrobić.

Opakowanie aplikacji

Czy już masz (lub planujesz dodać) w WordPressie funkcje niestandardowe
i funkcjonalność, które można powielić w aplikacji mobilnej?
Najprostszym i najszybszym sposobem na upieczenie dwóch pieczeni przy
jednym ogniu jest zastosowanie tzw. opakowania dla już istniejącej
witryny internetowej WordPressa.

Opakowanie aplikacji to w zasadzie natywna aplikacja mobilna z widokiem
internetowym lub elementem iframe. Oznacza to, że aplikacja mobilna jest
tak naprawdę tylko przeglądarką WWW osadzoną w samej aplikacji. Adres
URL tej przeglądarki WWW prowadzi do aplikacji WordPressa,
prawdopodobnie używającej niestandardowego, responsywnego motywu
mobilnego, dzięki któremu witryna internetowa wygląda i działa jak
aplikacja mobilna. Istnieje możliwość rozszerzenia aplikacji hybrydowej
o więcej funkcji natywnych, takich jak dostęp do aparatu, GPS, książki
adresowej i wielu innych danych. Jeśli jednak chcesz pobrać aplikację z
różnych serwisów, a nie masz wystarczająco dużo czasu, pieniędzy i
zasobów na utworzenie w pełni rozbudowanych aplikacji natywnych lub
hybrydowych opartych na interfejsie API WordPressa, zastosowanie
podstawowego opakowania aplikacji może okazać się najlepszym
rozwiązaniem. Prawie wszystko to, co można zrobić za pomocą WordPressa
lub odpowiedniej wtyczki bądź motywu, można również zrobić w aplikacjach
mobilnych działających w systemie zarówno iOS, jak i Android. Wyobraź
sobie tylko te wszystkie możliwości!

AppPresser

AppPresser (https://apppresser.com/) oferuje jeden z najprostszych
sposobów na tworzenie aplikacji mobilnej wykorzystującej wtyczki i
motywy WordPressa. Przy użyciu AppPresser możliwe jest wizualne
tworzenie aplikacji mobilnych na platformy iOS i Android, nie trzeba
przy tym napisać ani jednego wiersza kodu. Jeżeli jednak zagłębisz się w
kod AppPresser wygenerowany przez App Builder, będziesz mógł dostosować
aplikację do własnych potrzeb i dowolnie rozbudować.

AppPresser to znacznie więcej niż tylko mobilny motyw i kilka wtyczek
dla WordPressa. Skoro AppPresser korzysta z frameworków Cordova i Ionic,
może integrować się z komponentami urządzenia, takimi jak aparat,
geolokalizator i przyśpieszeniomierz. Aplikacje utworzone za pomocą
AppPressera mogą być umieszczane w sklepach iTunes App Store i Google
Play, podobnie jak aplikacje natywne dla danej platformy.

Konfiguracja aplikacji opartej na AppPresser jest łatwa. Taka aplikacja
składa się z dwóch części: witryny internetowej WordPressa i panelu
głównego My AppPresser.

Instalowanie i konfigurowanie w WordPressie

Po zarejestrowaniu się w AppPresser otrzymasz dostęp do motywu
AppPresser Ionic, wtyczek AppPresser oraz konta panelu głównego.
Pierwszą rzeczą, którą musisz zrobić, jest zainstalowanie i aktywowanie
podstawowej wtyczki AppPresser. Zaloguj się do witryny WordPressa,
przejdź do menu Wtyczki/Dodaj nową (Plugins/Add New) i wyszukaj
AppPresser. Zainstaluj i aktywuj tę wtyczkę, a następnie pobierz motyw
AP3 Ion Theme ze strony konta AppPresser.Te same czynności wykonuj także
podczas instalowania innych wtyczek AppPresser, których będziesz chciał
używać w witrynie internetowej WordPressa.

Kolejnym krokiem jest zainstalowanie motywu AppPresser AP3 WordPress w
Twoim katalogu motywów. Przejdź do menu Wygląd/Motywy/Dodaj nowy/Wyślij
motyw na serwer (Appearance/ Themes/Add New/Upload), a następnie przekaż
do serwera archiwum ZIP zawierające motyw. Trzeba w tym miejscu dodać,
że motyw AppPresser nie może zostać przekazany do serwera jako wtyczka.
Nie aktywuj motywu AppPresser — musi on pozostać w Twoim katalogu
motywów. Gdy witryna internetowa otrzyma żądanie z aplikacji mobilnej,
automatycznie wykorzysta motyw AppPresser zamiast domyślnie aktywnego
motywu.

  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Jeśli kiedykolwiek podczas logowania zobaczysz aktywny motyw AP3 Ion Theme, oznacza to, że prawdopodobnie przeglądasz aplikacje i masz ustawiony plik cookies. To nie jest błąd, a nikt inny nie widzi tego motywu. Wystarczy usunąć plik cookies, a wszystko wróci do normy.
  ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

W celu skonfigurowania AppPresser i jego wtyczek zajrzyj na stronę
ustawień w panelu głównym WordPressa. Dodaj slug i identyfikator witryny
internetowej, które ustalisz po zalogowaniu się w witrynie
https://myapppresser.com/ i przejściu na stronę <nazwa aplikacji>/Ogólne
(<nazwa aplikacji>/General). Skonfiguruj odpowiednie ustawienia i zapisz
je.

Dla każdej zainstalowanej i aktywowanej wtyczki dostępna jest oddzielna
zakładka z opcjami konfiguracyjnymi. Niektóre wtyczki AppPresser w
zasadzie stanowią połączenie wtyczek frameworków WordPress i Cordova,
np. w zakresie dostęp do aparatu, urządzenia GPS itd. Z kolei inne
wtyczki AppPresser oferują niestandardową integrację z zewnętrznymi
wtyczkami WordPressa, takimi jak WooCommerce, LearnDash i BuddyPress, za
pośrednictwem interfejsu API REST zapewniającymi możliwość
dostosowywania do własnych potrzeb stron aplikacji mobilnych. Poniżej
przedstawiamymy aktualnie dostępne wtyczki AppPresser:

-   AppBuddy
-   AppCamera
-   AppCommerce
-   AppCommunity
-   AppGeolocation
-   AppPush
-   AppShare
-   AppWoo
-   App Facebook Connect
-   LearnDash
-   In App Purchases.

App Builder

Po skonfigurowaniu wtyczek AppPresser w swojej witrynie internetowej
zaloguj się do panelu głównego pod adresem https://myapppresser.com/. W
panelu głównym wyświetlana jest lista wszystkich Twoich aplikacji. Po
kliknięciu pomarańczowego przycisku New App należy nadać tytuł aplikacji
i następnie kliknąć przycisk create app.

Po utworzeniu aplikacji zostaniesz przeniesiony do jej panelu głównego.
W tym miejscu możesz dostosować aplikację do własnych potrzeb,
zdefiniować sposób obsługi powiadomień w niej itd. Kliknij przycisk
Customize and Build App, aby przejść do ekranu pozwalającego na
dostosowanie aplikacji do własnych potrzeb przez zmianę jej kolorów,
dodanie stron, menu itd. Na tym etapie pracy wszystko powinno wyglądać
znajomo, ponieważ w zasadzie masz do czynienia z komponentem modyfikacji
motywu WordPressa, ale bez możliwości wyświetlenia aktywnego motywu
WordPressa jako motywu aplikacji mobilnej (zobacz rysunek 16.1).

[]

Rysunek 16.1. Dostosowanie aplikacji do własnych potrzeb w AppPreser

  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   MyAppPresser to właściwie sieć witryn internetowych WordPressa, która jako App Builder używa komponentu pozwalającego na dostosowanie motywu WordPressa do własnych potrzeb.
  ---- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

W App Builder zarówno utworzysz, jak i dostosujesz aplikację do swoich
potrzeb. Korzystanie z App Builder i dostosowywanie ustawień aplikacji
pozwala zachować praktycznie pełną kontrolę nad wyglądem i sposobem
działania aplikacji. Oto sześć elementów menu głównego App Builder.

Sekcja „Colors”

Umożliwia wizualną zmianę domyślnych kolorów dowolnego elementu
aplikacji. Domyślne elementy to m.in.: Body Background, Text Color,
Button Background, Button Text, Left Menu Background, Left Menu Text,
Left Menu Icon Color, Link Color, Headings Color i Android Status Bar
Background.

Sekcja „Design”

Pozwala na dostosowanie do potrzeb aplikacji niektórych jej elementów,
takich jak czcionka nagłówka, czcionka tekstu i wszelkie niestandardowe
czcionki, których chcesz użyć. Możesz również zastosować tutaj dowolny
niestandardowy kod CSS, aby w ten sposób całkowicie dostosować projekt
aplikacji do własnych potrzeb.

Sekcja „Settings”

W tym miejscu znajdują się ogólne informacje dotyczące aplikacji —
wymagane do jej utworzenia oraz dostosowujące ją za pomocą dodatkowych
ustawień. Wyboru dokonuje się za pomocą menu bocznego, kart menu albo
korzysta się z obu. Możliwe jest włączenie dostępu do aparatu, wysyłanie
powiadomień, używanie funkcjonalności geolokalizacji. Masz też możliwość
dodania ikony aplikacji, winietki, logo umieszczanego w nagłówku oraz
wszelkich innych zasobów offline, np. lokalnych obrazów i klipów wideo
do wyświetlenia. Kolejna możliwość to przekazanie skryptu JavaScript,
który będzie wykonany w aplikacji. Można wybrać język domyślny używany w
aplikacji, a także kierunek tekstu, np. od prawej do lewej, jeśli
zachodzi potrzeba.

Sekcja „Build and Preview”

Ta sekcja zawiera ustawienia stosowane podczas kompilowania aplikacji
już po jej dostosowaniu do własnych potrzeb. Kliknięcie przycisku Build
App spowoduje skompilowanie aplikacji na potrzeby testów lub
przygotowanie wersji aplikacji mobilnych, gotowej do umieszczenia w
sklepie. Jeżeli chcesz przeprowadzić kompilację dla fizycznego
urządzenia, musisz podać token autoryzacji PhoneGap Build. Dzięki temu
będzie można użyć kodu QR w celu umieszczenia aplikacji w urządzeniu.
Trzeba w tym miejscu dodać, że na platformie iOS konieczne jest
posiadanie certyfikatu, którym podpisuje się aplikacje. Jeśli za pomocą
App Builder chciałbyś rozbudować aplikację lub dalej dostosowywać ją do
własnych potrzeb, pliki paczki można pobrać w postaci archiwum ZIP.

Sekcja „Menu”

Umożliwia kontrolowanie, które strony będą dostępne w Twojej aplikacji.
Możesz dodawać niestandardowe łącza lub strony. Możliwe jest również
dodanie tytułu strony i niestandardowego łącza z pełnym adresem URL do
znajdującej się w witrynie internetowej WordPressa strony, którą chcesz
dołączyć do swojej aplikacji. W ten sposób zyskujesz możliwość
wyświetlania w aplikacji dowolnych stron WordPress za pomocą motywu
AppPresser. Jeśli posiadasz jakieś niestandardowe strony aplikacji,
także możesz je tutaj dodać.

Sekcja „Custom Pages”

Umożliwia tworzenie niestandardowych stron w aplikacji. Nie są to zwykłe
strony WordPressa wczytywane w aplikacji, ale lokalne strony aplikacji,
które w dużym stopniu można dostosowywać do własnych potrzeb.

  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   Słowo wyjaśnienia odnośnie do niestandardowych stron AppPresser: mogą to być statyczne pliki HTML działające w trybie offline lub lista stron pobierających dane za pomocą interfejsu API. Niestandardowe strony HTML nie są ściśle związane z Word-Pressem i mogą mieć dowolną treść. Na przykład, jeśli utworzysz stronę typu O firmie, na której znajdują się obraz i tekst, zostanie ona osadzona w aplikacji i dzięki temu pozostanie dostępna nawet w przypadku braku połączenia z internetem. Możesz także utworzyć listę stron zawierających pobieraną za pomocą interfejsu API REST treść, taką jak posty lub strony. Pracę nad utworzeniem niestandardowej strony możesz zacząć od wyboru szablonu spośród wielu dostępnych. Każdy z nich zawiera różne pola danych wejściowych, takie jak tytuł strony, niestandardowy adres URL trasy interfejsu API REST i/lub pola tekstowe oferujące kod znaczników Iconic/HTML5.
  ---- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Kiedy używasz App Builder w połączeniu z motywami i wtyczkami
AppPresser, możesz na podstawie dowolnej witryny internetowej WordPressa
szybko tworzyć aplikacje dla systemów iOS i Android. Załóżmy, że Twoja
witryna internetowa ma zainstalowaną wtyczkę przeznaczoną do obsługi
członkostwa i wtyczkę LearnDash, Ty zaś chcesz zapewnić integrację
aplikacji z różnymi postami WordPressa. Najpierw zainstaluj w swojej
witrynie internetowej podstawową wtyczkę AppPresser, wtyczki dodatkowe i
motyw. Witryna internetowa nie uległa zmianie, ponieważ AppPresser jest
aktywowany tylko w aplikacji mobilnej.

Następnie zaloguj się do Visual App Builder i utwórz nową aplikację.
Wybierz z witryny internetowej strony, które chcesz umieścić w
aplikacji. Na przykład, jeżeli chcesz, aby tam był kanał aktywności
BuddyPress, możesz dodać w menu aplikacji adres URL prowadzący na
wspomnianą stronę kanału. Gdy chcesz udostępnić możliwości oferowane
przez LearnDash, musisz do tego celu utworzyć niestandardową stronę
korzystającą z API REST.

Możesz zdecydować się na dodanie przycisku logowania do menu, aby
użytkownicy mogli się w Twojej witrynie internetowej zalogować,
wylogować i zarejestrować. Następnie możesz zmienić kolory, dodać ikonę
i winietkę, a następnie skompilować aplikację. Powstałą aplikację można
podejrzeć w przeglądarce WWW lub w aplikacji AppPresser Preview na
platformach iOS i Android bądź też użyć PhoneGap Build do przetestowania
aplikacji w swoim urządzeniu.

Kompilowanie i testowanie aplikacji

Na karcie Build i Preview komponentu pozwalającego na dostosowanie
motywu do własnych potrzeb konieczne będzie zintegrowanie aplikacji z
API PhoneGap Build za pomocą tokena uwierzytelniania, wygenerowanego w
koncie PhoneGap Build podczas przekazywania aplikacji w celu jej
skompilowania. Jeżeli jeszcze nie masz konta, możesz je utworzyć
bezpłatnie. Następnie przejdź do sekcji „Account/Client applications”, a
uzyskasz dostęp do tokena uwierzytelniania. Zapisz go w polu PhoneGap
Build Auth Token i kliknij przycisk Build App. To spowoduje zapakowanie
wszystkich plików aplikacji i przekazanie ich do PhoneGap Build w celu
kompilacji. Po zakończeniu kompilacji zostaną wyświetlone kod QR i łącze
— pozwalają one na pobranie i zainstalowanie pliku APK w urządzeniu
Android lub aplikacji iOS, o ile posiadasz odpowiedni klucz i hasło
potrzebne w celu podpisania aplikacji. Jeżeli jeszcze nie masz konta
programisty Apple lub klucza pozwalającego na podpisywanie aplikacji
iOS, aplikację będziesz mógł przetestować za pomocą AppPresser Preview
(https://apps.apple.com/app/id1200503566). Dokładnie ta sama aplikacja
może być wykorzystywanarównież podczas testowania utworzonej aplikacji w
urządzeniu Android
(https://play.google.com/store/apps/details?id=com.apppresser.preview3).

Szczerze mówiąc, AppPresser Preview pozwala na zalogowanie się do
swojego konta AppPresser, a więc na przetestowanie kodu w urządzeniu
podczas kompilowania aplikacji lub wprowadzania uaktualnień. Na karcie
Build and Preview znajduje się przycisk zatytułowany Update Live App.
Jego kliknięcie spowoduje przekazanie zmian (np. niestandardowego kodu
CSS lub elementów menu zmienionych w App Builder) do istniejącej,
zainstalowanej aplikacji. W zasadzie oznacza to, że aplikacja otrzymuje
polecenie pobrania nowych danych z API.

Przykładowo przyjmujemy założenie, że w sklepie aplikacji mobilnych masz
aplikację, której tło jest w kolorze niebieskim. Chcesz rozpocząć
eksperymenty ze zmianą tła na czerwone, choć jednocześnie nie chcesz,
aby bieżący użytkownicy aplikacji widzieli tę zmianę. Wprowadź więc
zmiany w App Customizer i sprawdź je. Gdy będziesz zadowolony z nowych
zmian, kliknij przycisk Go Live, a tło aplikacji zostanie zmienione na
czerwone. Wszelkie lokalnie wprowadzone uaktualnienia, np. dodanie
treści offline (nowa winietka, nowe strony HTML itd.), muszą zostać
ponownie skompilowane. Następnie aplikację trzeba przekazać
użytkownikom, a dopiero po zainstalowaniu uaktualnionej aplikacji w
urządzeniach widoczne będą wprowadzone w niej zmiany.

  ---- ----------------------------------------------------------------------------------------------------------------
  []   Użytkownicy aplikacji muszą ją zamknąć i ponownie uruchomić, aby móc zobaczyć jakiekolwiek wprowadzone zmiany.
  ---- ----------------------------------------------------------------------------------------------------------------

Łącza między stronami aplikacji

Ponieważ istnieje kilka różnych stron aplikacji, łączenie jednej strony
aplikacji z inną może przybierać różne formy.

Aby utworzyć łącze ze strony WordPressa do strony aplikacji, dodaj na
stronie WordPressa w elemencie iframe odpowiednie łącze prowadzące do
strony aplikacji. Użyj dowolnego z poniższych fragmentów kodu w dowolnie
wybranym poście WordPressa, stronie lub CPT.

-   Łącze do strony umieszczone w menu witryny internetowej:

    <a href="#" data-applink="2">Menu 2</a>

-   Łącze do strony na karcie:

    <button data-apptablink="1">Karta menu 1</button>

Liczba na karcie odnosi się do pozycji elementu, która jest liczona,
począwszy od 0. Na przykład pierwsza strona w menu będzie oznaczona
liczbą 0, druga liczbą 1 itd. Łącze prowadzi z niestandardowej strony
HTML do innej (musi znajdować się w menu). W takim przypadku zaczynasz
od utworzenia niestandardowej strony HTML, a następnie dodajesz łącze
prowadzące do innej strony aplikacji.

-   Dodawanie przycisku do strony:

    <button ion-button>Odwiedź stronę</button>

-   Dodawanie funkcji obsługi kliknięć, w tym przyciski:

    <button ion-button (click)="pushPage( pages.menus.items[0] )">

     Odwiedź stronę

    </button>

W zależności od menu zmieni się strona, do której prowadzi łącze.

W przypadku menu bocznego należy skorzystać z wywołania
pages.menus.items[].W przypadku menu kart natomiast należy skorzystać z
wywołania pages.tab_menu.items[], jak prezentujemy to w kolejnym
fragmencie kodu.

    <button ion-button (click)="pushPage( pages.tab_menu.items[1] )">

     Odwiedź stronę

    </button>

Liczba odnosi się do elementów menu, które są liczone od 0. Dlatego
pierwszy element będzie oznaczony liczbą 0, drugi liczbą 1 itd.

Jeżeli nie chcesz przycisku pozwalającego na powrót do strony, zamiast
pushPage() użyj wywołania openPage().

    <button ion-button (click)="openPage( pages.menus.items[3] )">

     Odwiedź stronę

    </button>

Wtyczka AppCamera

Rozszerzenie AppCamera umożliwia użytkownikom aplikacji wykonywanie
zdjęć, które są przesyłane bezpośrednio do Twojej witryny WordPressa.
Następnie te zdjęcia mogą być wyświetlone bezpośrednio w aplikacji.
Wtyczka AppCamera również integruje się bezpośrednio z wtyczkami
WooCommerce, BuddyPress i skrótem, którego można używać w dowolnym
poście lub na dowolnej stronie. Po zainstalowaniu i aktywowaniu wtyczki
AppCamera w ustawieniach AppPresser znajdziesz nową kartę zatytułowaną
AppPresser Camera. Kliknij ją, aby skonfigurować ustawienia omawianego
rozszerzenia obsługi aparatu.

Rozszerzenie wtyczki oferuje wiele ustawień, które pomagają w jej
skonfigurowaniu.

Camera license key

Dodaj otrzymany przy zakupie klucz licencyjny. Umożliwi to otrzymywanie
aktualizacji wtyczki w momencie jej wydania.

Uploaded photos must be moderated

Użyj tego ustawienia, jeśli chcesz zachować możliwość przeglądania,
zatwierdzania i odrzucania wszystkich przesłanych zdjęć przed ich
opublikowaniem.

Email new photos to admin email

Skorzystaj z tego ustawienia, jeśli chcesz otrzymywać e-mail z
powiadomieniem na adres administratora WordPressa, gdy użytkownik
prześle zdjęcie. Te powiadomienia będziesz otrzymywać niezależnie od
tego, czy zdjęcie wymaga moderowania.

Save photos to featured image

Jeśli włączysz tę opcję i skonfigurujesz przesyłanie w celu tworzenia
nowych postów, przesłane zdjęcie zostanie również ustawione jako
wyróżnione na stronie posta.

Photo upload description

Tekst, który będzie wyświetlany jako opis w wygenerowanym formularzu do
przesyłania zdjęć.

Text to display if logged out

Tekst, który będzie wyświetlany wylogowanym użytkownikom.

Kiedy będziesz już zadowolony z ustawień, kliknij przycisk Save Settings
zapisujący ustawienia.

AppCamera automatycznie dodaje przycisk przesyłania zdjęć do galerii
zdjęć produktów we wtyczce WooCommerce i modalne okno aktywności wtyczki
BuddyPress (wymaga to zainstalowania wtyczek AppBuddy i AppWoo).

Do strony lub posta można także ręcznie dodać skrót (powrócimy do tego
za chwilę), który spowoduje wyświetlenie w aplikacji przycisku
przesyłania zdjęć. Przyciski Take Photo oraz Upload Image pojawiają się
tylko wtedy, gdy użytkownik jest zalogowany. W przeciwnym wypadku
zostanie wyświetlony komunikat informujący o konieczności zalogowania
się. Zezwolenie niezalogowanym użytkownikom na przesyłanie zdjęć do
witryny internetowej nie jest bezpieczne, zatem nie ma takiej opcji w
omawianej wtyczce. Istnieje wiele sposobów wyświetlania obrazów
przesłanych z aplikacji do aplikacji lub witryny (zobacz rysunek 16.2).

[]

Rysunek 16.2. Skrót AppPhoto

Gallery shortcode

Możesz dodać skrót [gallery] do galerii WordPressa na tej samej stronie,
na której znajduje się skrót [app-camera]. To pozwoli na wyświetlanie
zdjęć. Pamiętaj, że strona nie jest odświeżana dynamicznie w celu
wyświetlenia najnowszych przesłanych obrazów, ale w razie potrzeby
możesz użyć do tego kodu JavaScript.

Action="this"

Jeśli używasz [app-camera action="this"], każde zdjęcie z aplikacji
zostanie przesłane do biblioteki multimediów i dołączone do bieżącego
posta lub strony, na której znajduje się ten skrót.

Action="new"

Jeśli korzystasz z [app-camera action="new"], każde zdjęcie utworzy nowy
post. Następnie możesz wyświetlać te posty w dowolny sposób, np. jako
niestandardowy szablon w motywie lub za pomocą wtyczki Display Posts
Shortcode.

Możesz użyć atrybutu post_type w celu określenia typu posta, który już
zarejestrowałeś, lub atrybutu app_photos, aby wyświetlać tylko te
zdjęcia, a nie inne posty. Ta metoda zapewnia również obsługę
moderowania.

Rozszerzenie AppCamera często jest stosowane razem z następującymi
skrótami:

-   [app-camera action="new"]
-   [app-camera post_type="page"]
-   [app-camera post_title="true"]
-   [app-camera not_logged_in="Musisz się zalogować"]
-   [app-camera description="Możesz zacząć przekazywać zdjęcia!"].

+----+----------------------------------------------------------------+
| [] | Masz możliwość użycia tylko jednego skrótu w danej chwili i    |
|    | możesz łączyć wiele parametrów, np.:                           |
|    |                                                                |
|    |                                                                |
|    | [app-camera post_type="page" force_login="false" action="new"] |
+----+----------------------------------------------------------------+

Możesz moderować obrazy przed ich wyświetleniem w witrynie internetowej.
Aby moderować zdjęcia, przejdź do strony ustawień AppPresser, kliknij
kartę Camera, wybierz pole wyboru Uploaded photos must be moderated?, a
następnie zapisz zmiany. Jeśli została wybrana opcja oznaczająca
konieczność moderowana zdjęć przed ich opublikowaniem, ta sekcja nie
pojawi się, dopóki nie zostaną przekazane zdjęcia do moderowania. Gdy
dostępne będą zdjęcia oczekujące na zatwierdzenie przez moderatora,
zobaczysz nowy element podmenu, Moderate Photos, w menu AppPresser. Obok
będzie informacja o liczbie zdjęć oczekujących na zatwierdzenie. Możliwe
jest też uzyskanie dostępu do tej strony za pomocą łącza Photo
Moderation Panel, które pojawi się obok przycisku Save Settings w karcie
AppCamera.

Przeglądając stronę przeznaczoną do moderowania (spójrz na rysunek
16.3), zwróć uwagę na listę zdjęć oczekujących na moderowanie; można je
przeglądać, zatwierdzać lub odrzucać. Dostępne są również podgląd
zdjęcia w postaci miniatury, nazwa pliku i jego typ, nazwa programu w
celu przekazania zdjęcia, post do którego zdjęcie zostało przekazane
oraz data. Pola wyboru po lewej stronie pozwalają na masowe
zatwierdzenie lub odrzucenie, a każde zdjęcie ma swoje własne łącze
pozwalające na odrzucenie lub zatwierdzenie danego zdjęcia. Kiedy nie ma
żadnego zdjęcia oczekującego na zatwierdzenie lub odrzucenie, element
menu i łącze nie będą wyświetlone, aż do momentu pojawienia się nowego
zdjęcia do moderowania.

[]

Rysunek 16.3. Moderowanie przekazywanych zdjęć

Wtyczka AppCamera jest też wyposażona w wiele zaczepów WordPress, które
można dostosować do potrzeb budowanej aplikacji.

appp_after_camera_buttons

Ten zaczep jest wykonywany natychmiast po wyświetleniu formularza
pozwalającego na przekazanie zdjęcia.

appp_after_process_uploads

Ten zaczep jest wykonywany natychmiast po zakończeniu operacji
przekazywania zdjęcia. Zawiera tyko identyfikatory posta i załącznika
pochodzące z przekazanych danych. Dzięki temu można później
przeprowadzić dalsze przetwarzania posta lub załącznika.

appp_before_camera_buttons

Ten zaczep jest wykonywany tuż przed wyświetleniem formularza
pozwalającego na przekazanie zdjęcia.

active_plugins

Ten zaczep pozwala na przechwycenie wywołania get_option(
aktywne_wtyczki ), zanim rozszerzenie ustali, czy wymagane wtyczki są
aktualnie aktywne. Wartością domyślną jest get_option( aktywne_wtyczki
).

appp_camera_description

Pozwala na przechwycenie i zmodyfikowanie, o ile to niezbędne, tekstu
wyświetlanego jako opis. Ta wartość jest definiowana w sekcji „Camera”
na stronie ustawień AppSettings. Wartością domyślną jest ciąg tekstowy
oznaczający Możesz przekazywać zdjęcia!.

appp_camera_not_logged_in_text

Pozwala na przechwycenie i zmodyfikowanie, o ile to niezbędne, tekstu
wyświetlanego niezalogowanym użytkownikom. Ta wartość jest definiowana w
sekcji „Camera” na stronie ustawień AppSettings. Wartością domyślną jest
ciąg tekstowy oznaczający Możesz przekazywać swoje zdjęcie!.

appp_camera_post_title_label

Pozwala na przechwycenie i zmodyfikowanie etykiety dla pola post_tile
wyświetlanej za pomocą skrótu [app-camera]. Wartością domyślną jest
<label> . __( Title:, appp ) . </label>.

appp_upload_email_message

Pozwala na przechwycenie i zmodyfikowanie komunikatu domyślnego, który
jest definiowany dla wysyłanych w formie wiadomości e-mail powiadomień o
przekazaniu nowych zdjęć.

appp_upload_email_subject

Pozwala na przechwycenie i zmodyfikowanie domyślnego tytułu wiadomości
e-mail, która jest wysyłana po przekazaniu do witryny nowych zdjęć.
Wartością domyślną jest tekst oznaczający Przekazano nowe zdjęcie.

appp_upload_email_to

Pozwala na przechwycenie i zmodyfikowanie domyślnego odbiorcy wiadomości
e-mail, który otrzymuje powiadomienia o przekazaniu nowych zdjęć.
Wartością domyślną jest get_settings ( admin_email ).

appp_camera_photo_blog_embedded_img_size

Pozwala na przechwycenie i zmodyfikowanie domyślnej wielkości zdjęcia,
które może być osadzone w blogu. Wartością domyślną jest array( 768,
2500, false ). Pierwszy parametr to szerokość wyrażona w pikselach,
drugi to wysokość wyrażona w pikselach, trzeci parametr określa
natomiast, czy zdjęcie ma zostać przycięte.

appp_moderate_maybe_publish

Pozwala na przechwycenie i zmodyfikowanie, jeśli zachodzi potrzeba,
tablicy argumentów używanych do publikacji posta po uzyskaniu zgody na
publikację zdjęcia. Wartością domyślną jest array( ID ⇒
absint( $parent[0] ), post_status ⇒ publish );.

appp_insert_photo_post

Umieszcza przekazane zdjęcie w obszarze treści posta, jeśli użytkownik
nie zdecydował, że dane zdjęcie ma zostać wyróżnione.

Wtyczki WooCommerce

Wtyczka AppWoo została opracowana specjalnie w celu zintegrowania
WooCommerce z Twoją aplikacją oraz z motywem AppPresser. W celu
utworzenia strony WooCommerce w aplikacji zajrzyj do menu narzędzia
dostosowania aplikacji do własnych potrzeb. Kliknij add items, wybierz
WordPress/external links, a następnie dodaj adres URL strony sklepu i
zapisz zmiany. Możesz także dodać inne strony, takie jak niestandardowe
strony kategorii produktów.

Wtyczka AppWoo jest w zasadzie samowystarczalna i nie oferuje żadnych
ustawień dokonywanych przez użytkownika. Jednakże w tle wykonuje
wymienione tutaj zadania i tym samym pomaga w optymalizacji AppTheme i
WooCommerce dla aplikacji natywnej.

-   Definiuje układ strony pojedynczego produktu, aby elegancko
    wkomponował się w strukturę przypominającą aplikację. Odbywa się to
    przez usunięcie różnych wywołań zwrotnych zaczepów WooCommerce, a
    także przez zarejestrowanie nowych dla AppTheme, aby osiągnąć
    zamierzony efekt.
-   Zapewnia integrację z AppSwiper oraz pomaga z żądaniami w
    technologii AJAX i suwakami dla obrazów produktów. Dzięki temu można
    znacznie łatwiej wyświetlać różne obrazy produktów i różnicować je
    klientom.
-   Jeżeli aktywne jest rozszerzenie AppCamera, użytkownik automatycznie
    otrzyma możliwość przekazywania i przesyłania obrazów poszczególnych
    produktów.
-   Powracającym klientom dostarcza profil użytkownika w lewym menu
    panelu. Kliknięcie tego menu spowoduje wyświetlenie nazwy
    użytkownika i obrazka profilu.
-   W lewym menu panelu dostarcza klientowi informacje o koszyku na
    zakupy i wartości całkowitej zamówienia. Bezpośrednio z poziomu menu
    zapewnia również dostęp do informacji o kliencie i zamówieniach.

Mamy kilka zaczepów AppWoo gotowych do wykorzystania z własną wtyczką
WordPressa.

appp_after_product_images

Ten zaczep jest wykonywany natychmiast po wyświetleniu galerii produktu.

active_plugins

Ten zaczep pozwala na przechwycenie wywołania get_option(
aktywne_wtyczki ), zanim rozszerzenie ustali, czy wymagana wtyczka
WooCommerce jest w danej chwili aktywna. Wartością domyślną jest
get_option( aktywne_wtyczki ).

apppresser_woocom_gallery_ids

Ten zaczep pozwala na przechwycenie i zmodyfikowanie, jeśli zachodzi
potrzeba, tablicy identyfikatorów obrazów użytych w wyświetlonej
galerii. Wartością domyślną jest $gallery_ids.

apppresser_disable_woo_styles

Ten zaczep pozwala na przechwycenie i uniemożliwia wyłączenia stylów
WooCommerce. Wartością domyślną jest true // Style zostaną wyłączone.

Jeśli używasz wtyczki WooCommerce w aplikacji, ikonka koszyka pojawi się
automatycznie na stronach wyświetlających tylko jeden produkt. Jeśli
chcesz, aby koszyk pojawiał się na każdej stronie, możesz dodać poniższy
fragment kodu do niestandardowego pliku JavaScript we wtyczce lub w
motywie potomnym witryny internetowej WordPressa.

    jQuery(document).ready(function($) {

        if( $('body').hasClass('woocommerce-page') ) {

            var message_array = {};

            message_array['post_title'] = window.appp.post_title;

            message_array['cart_link'] = window.apppwoo.cart_url;

            parent.postMessage( JSON.stringify( message_array ), '*');

        }

    });

(Pamiętaj, że to tylko przykład. Ten skrypt być może będzie wymagał
modyfikacji, aby mógł działać poprawnie w Twojej witrynie internetowej).

Dzięki ogromnym aktualizacjom WordPressa i WooCommerce, które zostały
przeprowadzone w ciągu kilku ostatnich lat, AppPresser udostępnił nową
integrację z aplikacjami mobilnymi o nazwie AppCommerce. Ta wersja jest
szybsza, czytelniejsza i bardziej skoncentrowana na zapewnieniu jak
najlepszych wrażeń klientom utworzonego sklepu. AppCommerce łączy się ze
sklepem Woo-Commerce poprzez interfejs API REST. Klienci mogą dodawać
produkty do koszyka, logować się, przeglądać poprzednie zamówienia i
szczegóły konta, tworzyć listę życzeń itd. Finalizacja zamówienia odbywa
się w Twojej witrynie internetowej za pośrednictwem przeglądarki WWW
osadzonej w aplikacji. Zapewnia to płynność działania i umożliwia
korzystanie z bieżących bramek płatności, adresu wysyłkowego i
określania wysokości podatku — to wszystko bez konieczności stosowania
dodatkowej konfiguracji. Jeśli chcesz, proces składania zamówienia
możesz w pełni dostosować do własnych potrzeb, aby był unikatowy dla
danej witryny internetowej. Po dokonaniu płatności klient zostanie
przekierowany z powrotem na stronę sklepu. Rozwiązanie oparte na
AppCommerce można za pomocą aplikacji AppPresser w pełni dostosować do
własnych potrzeb. Sam wybierasz, które strony mają zostać wyświetlone,
które produkty, jakie kolory zostaną użyte itd.

Aby dodać do aplikacji sklep WooCommerce, koszyk i strony konta, przejdź
do komponentu pozwalającego na dostosowanie aplikacji do własnych
potrzeb, a następnie na stronę Custom Pages. Teraz musisz kliknąć Add
New Page, a później wybrać AppCommerce.

W przypadku strony sklepu lub dowolnej strony aplikacji, do której
chcesz dodać listę produktów, Twoje zadanie sprowadza się do użycia
znacznika woo-list i wybrania opcji Shop w komponencie. Do wyświetlenia
listy produktów na własnej stronie w aplikacji skorzystaj z
przedstawionego tutaj kodu.

    <woo-list route="products" infiniteScroll="true"></woo-list>

Aby dostosować do własnych potrzeb wyświetlane produkty lub kategorie
produktów, należy skorzystać z parametrów adresu URL omówionych w
dokumentacji API REST WooCommerce
(https://woocommerce.github.io/woocommerce-rest-api-docs/#list-all-products).
Na przykład możesz dodać products?type=simple w celu wyświetlenia
jedynie prostych produktów lub products?stock_status=outofstock w celu
wyświetlenia aktualnie niedostępnych produktów.

    <woo-list route="products?stock_status=outofstock" infiniteScroll="true">

    </woo-list>

  ---- ----------------------------------------------------------------------------------------------------------------------------
  []   Jeżeli skorzystałeś z szablonu AppCommerce, prawdopodobnie masz już wymienione strony. Jeżeli tak, nie musisz ich tworzyć.
  ---- ----------------------------------------------------------------------------------------------------------------------------

W przypadku dedykowanej strony koszyka na zakupy w aplikacji konieczne
będzie umieszczenie gdzieś na stronie znacznika woo-cart i wybrania
opcji Cart w komponencie.

    <woo-cart></woo-cart>

Dla strony konta użytkownika natomiast trzeba skorzystać z następującego
znacznika.

    <woo-account></woo-account>

  ---- -------------------------------------------------------------------------------------------------------
  []   Pamiętaj, że strony sklepu, koszyka na zakupy i konta użytkownika są wymaganymi stronami w aplikacji.
  ---- -------------------------------------------------------------------------------------------------------

Do aplikacji można dodać także inne strony WooCommerce, np. listę
życzeń. Na stronie produktu klient może kliknąć przycisk typu Dodaj do
listy i tym samym zapisać dany produkt na liście. Aby utworzyć stronę
listy, zacznij od przygotowania nowej strony niestandardowej i wybierz
AppCommerce. Jako komponent wybierz None, a następnie na stronie umieść
następujący znacznik.

    <woo-list wishlist="true"></woo-list>

Finalizacja zamówienia odbywa się za pomocą witryny internetowej
wyświetlonej w przeglądarce WWW osadzonej w aplikacji. W celu
osiągnięcia jak najlepszego wrażenia przez użytkownika zalecamy
skorzystanie z wtyczki WooCommerce Smart Checkout.

  ---- -------------------------------------------------------------------------------------------------------------------------------------
  []   Prawie 40 procent wszystkich transakcji e-commerce w sezonie świątecznym w 2018 roku zostało przeprowadzonych za pomocą smartfonów.
  ---- -------------------------------------------------------------------------------------------------------------------------------------

LearnDash i AppLMS

Integracja z LearnDash pozwala na dodawanie kursów, tematów, lekcji i
quizów do aplikacji. Istnieje możliwość ograniczenia dostępu do treści
na podstawie stanu logowania oraz wykorzystanie wtyczki członkostwa,
BuddyPress, gamifikacji itd. W celu dodania LearnDash do aplikacji
wystarczy po prostu utworzyć stronę wyświetlającą kursy. Reszta zostanie
wygenerowana automatycznie. Aby dodać kursy do aplikacji, utwórz nową
niestandardową stronę w komponencie pozwalającym na dostosowanie
aplikacji do własnych potrzeb (Custom pages/Add new page), a następnie
umieść na niej następujący fragment kodu.

    <ap-list wp="true" card="true" class="col-2"

         route="https://mysite.com/wp-json/wp/v2/sfwd-courses?per_page=10">

           </ap-list>

Zmodyfikuj parametr per_page w celu wyświetlenia dowolnej liczby kursów.
To spowoduje wyświetlenie kursów w układzie składającym się z dwóch
kolumn. Jeżeli chcesz skorzystać z układu jednokolumnowego, zmodyfikuj
komponent ap-list, jak to pokazujemy w kolejnym fragmencie kodu.

    <ap-list wp="true" route="https://mysite.com/wp-json/wp/

         v2/sfwd-courses" infiniteScroll="true"></ap-list>

Dodaj dowolny tekst lub kod HTML i zapisz zmiany. Następnym krokiem jest
dodanie tej strony do menu i ponowna kompilacja aplikacji (zobacz
rysunek 16.4).

[]

Rysunek 16.4. Dodawanie kursów do aplikacji

Jeżeli nie lubisz takiego podejścia opartego na API lub potrzebujesz
większych możliwości w zakresie dostosowania do własnych potrzeb, możesz
skorzystać z podejścia opartego na WordPressie. Utwórz nową stronę w
witrynie internetowej WordPressa, a następnie umieść na niej skrót w
postaci listy kursów LearnDash. Jeżeli jesteś programistą lub osobą,
która chce pójść dalej w zakresie dostosowania do własnych potrzeb,
możesz zbudować własną wtyczkę w celu rozszerzenia niezbędnej
funkcjonalności.

AppPush

Mechanizm push notifications powoduje przekazywanie komunikatów do
dowolnego urządzenia, w którym zainstalowano Twoją aplikację, i
umożliwia przekazywanie powiadomień. AppPresser jest dostarczany wraz z
tym mechanizmem. Wprawdzie przygotowanie opartego na nim rozwiązania
wymaga nieco konfiguracji, ale nie powinno to okazać się trudne, o ile
starannie przeprowadzisz wymaganą procedurę. Warto przy tym pamiętać o
kilku kwestiach:

-   Przekazywania powiadomień nie można przetestować w symulatorze ani w
    aplikacji AppPresser Preview, konieczne jest użycie fizycznego
    urządzenia.
-   Większość problemów związanych jest z certyfikatami iOS. Dlatego
    ściśle przestrzegaj instrukcji.
-   Konieczne jest ważne konto programisty Apple. Więcej informacji na
    temat takiego konta znajdziesz na stronie
    (https://developer.apple.com/).
-   Android wymaga bezpłatnego projektu Firebase i klucza API.

Po zdefiniowaniu certyfikatów iOS i projektu Firebase informacje te
można dodać w witrynie https://myapppresser.com/ oraz w PhoneGap, aby
przekazywanie powiadomień było możliwe w My AppPresser lub za pomocą
wtyczki AppPush zainstalowanej i zintegrowanej z Twoją witryną
internetową.

  ---- ---------------------------------------------------------------------------------------------------------------------------------------
  []   Jeżeli chciałbyś dowiedzieć się więcej na temat AppPresser i dostępnych wtyczek, odwiedź witrynę internetową https://apppresser.com/.
  ---- ---------------------------------------------------------------------------------------------------------------------------------------

Rozdział 17. Biblioteki PHP, integracje usług sieciowych, migracje platform

Czasem może być konieczne zintegrowanie funkcji, funkcjonalności oraz
danych z WordPressa, które nie są specyficzne dla tej platformy.

W rozdziale omawiamy wybrane najpopularniejsze biblioteki PHP, usługi
sieciowe oraz interfejsy API, które można łatwo zintegrować z
WordPressem. Ponadto zajmiemy się ustrukturyzowanym procesem, który
można wykorzystać do całkowitego przeniesienia treści i danych z niemal
dowolnego oprogramowania firmy zewnętrznej do WordPressa, co powszechnie
nazywa się migracją platformy. Przenieś wszystkie elementy do
WordPressa!

Biblioteki PHP

Większość języków programowania, włączając PHP, ma modułowe kolekcje
kodu, klas i funkcji. Te kolekcje zwykle nazywane są biblioteką kodu lub
rozszerzeniem.

Nie wyważaj otwartych drzwi! Istnieją biblioteki PHP zapewniające ściśle
określoną funkcjonalność, której można bardzo łatwo użyć do rozszerzenia
możliwości budowanych aplikacji.

Spora część kodu platformy WordPressa została utworzona w języku PHP, co
oznacza, że jako programista WordPressa możesz korzystać z dowolnych
dostępnych bibliotek PHP, a nawet tworzyć własne. Uporządkowana lista
wybranych popularnych bibliotek PHP została zamieszczona na stronie
PHP.net Function Reference pod adresem
https://www.php.net/manual/en/funcref.php.

Repozytorium wtyczek WordPressa zawiera sporo wtyczek współpracujących z
różnymi bibliotekami i usługami zewnętrznymi. Zatem zawsze gdy szukasz
niestandardowej funkcjonalności WordPressa, możesz zacząć od przejrzenia
repozytorium wtyczek. Oczywiście, jeśli nie znajdziesz tego, czego
szukasz, być może będziesz musiał zająć się samodzielnie utworzeniem
wtyczki lub po prostu dostosować do własnych potrzeb już istniejącą.

Wielokrotnie wspominaliśmy o serwisie GitHub, ponieważ jest to świetne
miejsce do znalezienia poszukiwanej funkcjonalności. Innym bardzo dobrym
źródłem kodu mogą być oparte na PHP projekty typu open source, takie jak
Drupal, Laravel, Joomla! i/lub Magento. Może się zdarzyć, że dokładnie
taka funkcjonalność, jakiej poszukujesz, jeszcze nie istnieje w postaci
wtyczki WordPressa, ale jest dostępna jako moduł Drupal — zatem utwórz
kod w taki sposób, aby działał w WordPressie.

Przedstawiamy kilka ciekawych bibliotek PHP, które oferują rozszerzoną
funkcjonalność i można je łatwo zintegrować z WordPressem.

  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  []   W zależności od środowiska hostingu korzystanie z wybranych bibliotek PHP może okazać się niemożliwe. Niektóre biblioteki PHP są opakowaniami do oprogramowania bazowego, które należy zainstalować na serwerze WWW. Jeśli nie masz możliwości zmiany konfiguracji serwera WWW, nie będziesz mógł korzystać ze wspomnianych wtyczek.
  ---- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Generowanie i przetwarzanie obrazów

Pomyśl o oprogramowaniu takim jak Photoshop, ale przeznaczonym do
tworzenia kodu. Mogłoby być ono używane do budowania m.in. generatorów
memów (http://www.quickmeme.com/). Zadania związane z generowaniem
obrazów i przeprowadzaniem na nich operacji mogą być użyteczne pod
wieloma względami:

-   zmiana wielkości i skalowanie obrazów
-   porównywanie obrazów
-   kopiowanie obrazów
-   konwertowanie obrazów do różnych formatów
-   zmiana kolorów w obrazie
-   konwertowanie tekstu na obrazy i nakładanie tekstu na obrazy
-   łączenie wielu obrazów
-   tworzenie animowanych obrazów,
-   stosowanie niestandardowych filtrów obrazów (jak np. w serwisie
    Instagram)
-   rozmycie i wyostrzenie obrazów
-   dodawanie krawędzi i ramek do obrazów
-   dynamiczne tworzenie wykresów i innej grafiki na podstawie danych
-   generowanie grafiki trójwymiarowej (3D).

Jak zapewne się domyślasz, wszystkie te możliwości użytkownik jest w
stanie wykorzystać na wiele sposobów, zważywszy, że z danym obrazem
można zrobić praktycznie wszystko. W zależności od oczekiwanego efektu
końcowego niektóre biblioteki PHP przeznaczone do przetwarzania obrazów
są lepsze od innych.

Domyślnie WordPress używa jednej z dwóch najpopularniejszych bibliotek
PHP służących do przetwarzania obrazów w celu zapewnienia
funkcjonalności przetwarzania obrazów w WordPressie i obsługi biblioteki
multimediów. Najpierw WordPress sprawdza, czy biblioteka Imagick jest
dostępna; jeśli nie, to sprawdza, czy dostępna jest biblioteka GD. Gdy
żadna z wymienionych bibliotek nie jest dostępna, próba uruchomienia
funkcji przetwarzania obrazów w WordPressie zakończy się wyświetleniem
komunikatu błędu. Kiedy w WordPressie przycinamy, obracamy lub w
jakikolwiek inny sposób przetwarzamy obraz, w tle zawsze używamy jednej
z dwóch wspomnianych wcześniej bibliotek.

Możesz łatwo sprawdzić, czy biblioteki Imagick albo GD zostały
zainstalowane na Twojej platformie WordPressa. Wymaga to użycia
następującego fragmentu kodu w pliku functions.php motywu.

    <?php

    // Nie używaj tego fragmentu kodu w produkcyjnej witrynie internetowej

    function bwawwp_image_library_check(){

        if( extension_loaded('imagick') ) {

            $imagick = new Imagick();

            print_r( $imagick->queryFormats() );

        } else {

            echo 'Brak biblioteki ImageMagick!';

        }

        if( extension_loaded('gd') ) {

            print_r( gd_info() );

        } else {

            echo 'Brak biblioteki GD!';

        }

        exit();

    }

    add_action("init", "bwawwp_image_library_check");

W zależności od tego, która biblioteka jest używana, możesz łatwo zacząć
tworzyć kod przeznaczony do wykorzystania możliwości tej biblioteki.

GD

GD jest prawdopodobnie najpopularniejszą biblioteką PHP służącą do
przetwarzania obrazów i zwykle jest kompilowana z domyślnymi
instalacjami PHP. Biblioteka GD (https://www.php.net/
manual/en/book.image.php) zazwyczaj jest nieco szybsza od biblioteki
Imagick, szczególnie podczas przetwarzania większych obrazów, oraz
stanowi mniejsze obciążenie dla zasobów serwera. Wprawdzie biblioteka GD
jest świetnym narzędziem do wykonywania wielu operacji na obrazach, ale
biblioteka Imagick oferuje więcej funkcji i funkcjonalności.

Imagick

Imagick (https://imagemagick.org/), jedno z najpotężniejszych narzędzi
służących do przetwarzania obrazów i jednocześnie nasze ulubione — choć
chcielibyśmy, aby ktoś przygotował jego witrynę internetową opartą na
WordPressie —pozwala na programowe przetwarzanie praktycznie w dowolny
sposób wszelkich plików graficznych. Wystarczy zainstalować Imagick w
serwerze WWW, a następnie uruchomić to narzędzie za pomocą polecenia
powłoki zdefiniowanego w wywołaniu funkcji PHP shell_exec() lub exec().
Ewentualnie można skorzystać z biblioteki PHP dla Imagick
(https://www.php.net/manual/en/book.imagick.php) jako opakowania dla
oprogramowania wspomagającego jej działanie. Biblioteka Imagick nie jest
domyślnie dołączona do PHP i należy ją zainstalować osobno wraz z samym
oprogramowaniem Imagick.

Justin Sternberg opracował kilka naprawdę prostych w użyciu metod,
używając Imagick do nakładania dowolnego tekstu na obraz i zapisywania
go w postaci osobnego obrazu, który później staje się załącznikiem do
posta WordPressa. Może to okazać się wyjątkowo przydatne szczególnie
wtedy, gdy wymagasz, aby wszystkie obrazy w aplikacji internetowej były
oznaczone znakiem wodnym zawierającym adres URL. Zatem jeśli ktoś bez
Twojej zgody wykorzysta należące do Ciebie obrazy, będą one opatrzone
adresem URL prowadzącym na Twoją witrynę internetową. Metody opracowane
przez Justina znajdziesz na stronie wtyczki WordPress-Image-WaterMark
(https://github.com/ jtsternberg/WordPress-Image-Watermark).

Zebra_Image

Zebra_Image (https://github.com/stefangabos/Zebra_Image) to superlekka i
łatwa w użyciu biblioteka PHP służąca do przetwarzania obrazów. Stanowi
świetną alternatywę dla Imagick, szczególnie jeśli wykorzystujesz tylko
ułamek możliwości biblioteki Imagick, nie możesz jej zainstalować na
swoim serwerze WWW lub potrzebujesz jedynie podstawowej funkcjonalności
związanej z przetwarzaniem obrazów: zmiany wielkości, przycinania,
obracania, odwracania i/lub wyostrzania obrazu. Ta składająca się z
tylko jednego pliku biblioteka PHP wymaga jedynie rozszerzenia GD, które
zwykle jest dostarczane wraz z PHP.

Imagine

Gdzieś pomiędzy bibliotekami Imagick i Zebra_Image znajduje się Imagine
(https://imagine.readthedocs.io/en/stable/). Ta zorientowana obiektowo
biblioteka PHP oferuje bardzo potężne możliwości i można jej używać do
niemal wszystkich rodzajów przetwarzania obrazów. Podobnie jak
w przypadku biblioteki Zebra_Image, Imagine także jest opartą na GD
biblioteką PHP.

Dynamic Dummy Image Generator

Wprawdzie Dynamic Dummy Image Generator (https://dummyimage.com/) nie
jest biblioteką PHP, ale to świetne małe narzędzie, o którym
chcielibyśmy wspomnieć, ponieważ pomaga podczas pracy na witryną
internetową WordPressa. Na pewno znalazłeś się w sytuacji, w której
klient nie dostarczył Ci obiecanych obrazów na czas. Używając Dummy
Image (https://dummyimage.com/
1024x600&text=Building+Web+Apps+with+WordPress) możesz na podstawie
adresu URL dynamicznie tworzyć obrazy o różnych rozmiarach.

Snappy

A teraz najlepsze! Dzięki Snappy (https://github.com/KnpLabs/snappy)
możesz automatycznie tworzyć obraz i/lub plik PDF na podstawie dowolnego
adresu URL lub strony HTML. Pomyśl o tych wszystkich niesamowitych
rzeczach, które możesz robić, generując obraz z dowolnej witryny
internetowej.

Generowanie dokumentu PDF

Programowe generowanie dokumentów PDF oraz ich przetwarzanie może być
niezwykle użyteczne. Przykładowo możesz odwiedzić szkolną lub miejską
witrynę internetową zawierającą mnóstwo dokumentów w formacie PDF (menu
posiłków, kalendarz, nadchodzące wydarzenia, rejestracja wydarzeń, listy
lektur, plany spotkań, podręczniki, raporty, przewodniki itd.), które
prawdopodobnie powinny znajdować się na aktualnej witrynie internetowej,
ale nie w formie dokumentu PDF. Jednym z głównych powodów, dla których
szkoły i wszelkiego rodzaju instytucje używają plików PDF (oprócz
argumentu w stylu „zawsze tak robiliśmy”), jest fakt, że pliki PDF można
łatwo rozpowszechniać za pośrednictwem wiadomości e-mail lub w formie
papierowej po uprzednim wydrukowaniu. Wprawdzie są to ważne argumenty,
istnieje też jednak kilka wad dostarczania treści jedynie w formie PDF.

-   Pliki PDF nie są zgodne z ADA, co może narażać organizacje na
    związane z tym konsekwencje prawe.
-   Pliki PDF nie są dostosowane do urządzeń mobilnych. Mimo że są
    możliwe do wyświetlenia w urządzeniu mobilnym, to podczas
    korzystania z nieresponsywnej witryny internetowej trzeba będzie
    nieustannie zmieniać poziom powiększenia treści.
-   Jeśli pewna treść znajduje się zarówno na stronie internetowej, jak
    i w pliku PDF, uaktualnienia trzeba będzie wprowadzać w obydwóch
    wymienionych miejscach.

Co się stanie, jeśli każda strona witryny internetowej będzie musiała
mieć dostępny plik PDF do pobrania? Co zrobić w sytuacji, gdy masz kilka
danych statystycznych dostępnych on-line oraz innych danych, na
podstawie których musisz wygenerować dokumenty w formacie PDF? Co się
stanie, jeśli kalendarz jest ciągle aktualizowany, a po każdej jego
zmianie musisz ręcznie przeprowadzać aktualizację pliku PDF i ponownie
udostępniać go użytkownikom? Te i podobne problemy możemy rozwiązać za
pomocą kodu automatyzującego wymieniony proces i tym samym zaoszczędzić
mnóstwo czasu i pieniędzy. Omówimy teraz wybrane biblioteki PHP
pozwalające na automatyczne generowanie plików w formacie PDF.

Snappy

Wspominaliśmy już o Snappy (https://github.com/KnpLabs/snappy), a teraz
chcielibyśmy raz jeszcze powtórzyć, jak wspaniałą sprawą jest możliwość
łatwego generowania plików PDF na podstawie strony internetowej,
podanego adresu URL lub pliku HTML. Po przekazaniu wielu adresów URL
istnieje nawet możliwość wygenerowania wielostronicowego dokumentu PDF.
Chcesz wygenerować szczegółowy dokument PDF dla całej witryny? Wystarczy
przeprowadzić iterację przez wszystkie strony dokumentu i przekazać je
do narzędzia Snappy!

Snappy używa dwóch popularnych narzędzi powłoki typu open source
pozwalających konwertować kod HTML do formatu PDF lub graficznego:
wkhtmltopdf i wkhtmltoimage. Niezbędne pliki binarne możesz łatwo pobrać
i zainstalować w serwerze za pomocą Composer, czyli menedżera zależności
dla PHP (https://getcomposer.org/).

FPDF

Litera F w skrócie FPDF (http://fpdf.org/) pochodzi od angielskiego
słowa free oznaczającego „bezpłatny”! FPDF to lekka alternatywa dla
PDFlib, szczególnie użyteczna, jeśli nie generujesz zbyt wielu
skomplikowanych dokumentów w formacie PDF. Bibliotekę FPDF można
wykorzystać w celu dynamicznego generowania dokumentów PDF tylko za
pomocą kodu PHP: ta biblioteka nie ma praktycznie żadnych innych
zależności PHP poza Zlib (w celu zapewnienia obsługi kompresji) i GD (w
celu zapewnienia obsługi formatu GIF), które zwykle są już wkompilowane
w PHP. Zapoznaj się z kilkoma wybranymi, najważniejszymi funkcjami FPDF.

__construct

To jest konstruktor.

AcceptPageBreak

Wskazuje, czy ma być zastosowany automatyczny podział strony.

AddFont

Dodaje nową czcionkę.

AddLink

Tworzy łącze wewnętrzne.

AddPage

Dodaje nową stronę.

AliasNbPages

Definiuje alias do liczby stron.

Cell

Wyświetla komórkę.

Close

Zamyka dokument.

Error

To jest błąd krytyczny.

Footer

To jest stopka strony.

GetPageHeight

Pobranie wysokości bieżącej strony.

GetPageWidth

Pobranie szerokości bieżącej strony.

GetStringWidth

Ustala długość ciągu tekstowego.

GetX

Pobiera bieżące położenie na osi X.

GetY

Pobiera bieżące położenie na osi Y.

Header

To jest nagłówek strony.

Image

Umieszcza obraz w dokumencie.

Line

Rysuje linię.

Link

Umieszcza łącze w dokumencie.

Ln

To jest podział wiersza.

MultiCell

Umieszcza w dokumencie tekst ze znakami nowego wiersza.

Output

Zapisuje lub przekazuje dokument.

PageNo

To jest numer strony.

Rect

Rysuje prostokąt.

SetAuthor

Umieszcza w dokumencie informacje o autorze.

SetAutoPageBreak

Ustala tryb automatycznego podziału na strony.

SetCompression

Włącza lub wyłącza kompresję.

SetCreator

Umieszcza informację o twórcy dokumentu.

SetDisplayMode

Ustawia tryb wyświetlania.

SetDrawColor

Ustawia kolor rysunku.

SetFillColor

Ustawia kolor wypełnienia.

SetFont

Ustawia czcionkę.

SetFontSize

Ustawia rozmiar czcionki.

SetKeywords

Powiązuje słowa kluczowe z dokumentem.

SetLeftMargin

Ustawia lewy margines.

SetLineWidth

Ustawia szerokość linii.

SetLink

Ustawia cel łącza wewnętrznego.

SetMargins

Ustawia marginesy.

SetRightMargin

Ustawia prawy margines.

SetSubject

Ustawia temat dokumentu.

SetTextColor

Ustawia kolor tekstu.

SetTitle

Ustawia kolor tekstu.

SetTopMargin

Ustawia górny margines.

SetX

Ustawia bieżące położenie na osi X.

SetXY

Ustawia bieżące położenie na osiach X i Y.

SetY

Ustawia bieżące położenie na osi Y i opcjonalnie zeruje położenie na osi
X.

Text

Wyświetla ciąg tekstowy.

Write

Wyświetla tekt pływający.

Inne biblioteki PHP do generowania dokumentów PDF

W zależności od konkretnych potrzeb za pomocą ulubionej wyszukiwarki
internetowej możesz wyszukać więcej informacji szczegółowych o
wymienionych tutaj bibliotekach:

-   wkhtmltopdf
-   mPDF
-   Dompdf
-   TCPDF
-   HTML2PdF.

Geolokalizacja i geotargetowanie

Istnieje wiele dostępnych usług geolokalizacyjnych wykonujących
określone zadania, np. podawanie przybliżonego położenia urządzenia o
danym adresie IP bądź przybliżonej długości i szerokości geograficznej
na podstawie danych z GPS lub sieci wi-fi. Jeśli masz dostęp do
informacji o położeniu geograficznym użytkowników odwiedzających stronę,
możesz je wykorzystać na przykład do:

-   ograniczania dostępu do witryn internetowych lub konkretnych stron
-   udostępniania treści witryny internetowej, np. geotargetowane
    reklamy
-   śledzenia położenia użytkownika lub przedmiotu w czasie niemal
    rzeczywistym
-   znajdowania najbliższej lokalizacji obiektu.

Przyjmujemy założenie, że szkoła chce zastosować dodatkowe
zabezpieczenie w aplikacji internetowej i zapewnić dostęp do strony
logowania tylko osobom z miasta lub województwa, w którym się znajduje.
Ten rodzaj funkcji bezpieczeństwa może być konieczny tylko wtedy, gdy
chcesz ograniczyć dostępność aplikacji do jedynie określonego położenia
geograficznego, choć takie rozwiązanie znacznie zmniejsza liczbę
potencjalnych ataków. Zamiast tylko zapewnić dostęp do aplikacji
internetowej, można ją blokować przed użytkownikami z określonych
regionów, np. z Chin. Być może w zależności od aplikacji będzie wiadomo,
że odwiedzający ją użytkownicy z Chin nie mają do niej dostępu.

Być może urzędowa witryna internetowa zbudowana na podstawie WordPressa
ma wyświetlać użytkownikom szkoły znajdujące się w regionie, z którego
pochodzi użytkownik wczytujący tę witrynę. Przyjmujemy założenie, że
informacje o danej szkole są zamieszczone za pomocą niestandardowego
typu postów i zawierają adres przechowywany w postaci metadanych posta.
W omawianym przykładzie rozwiązaniem jest ustalenie położenia
użytkownika, a następnie wykonanie zapytania pobierającego metadane o
szkołach, które znajdują się w regionie odpowiadającym temu, z którego
pochodzi użytkownik odwiedzający daną witrynę internetową.

MaxMind GeoIP

MaxMind GeoIP (https://www.maxmind.com/en/geoip2-services-and-databases)
pobiera dane z adresu IP użytkownika, takie jak jego położenie, oraz
informacje o dostawcy internetu. MaxMind to świetna usługa, ponieważ ma
bardzo rozbudowany interfejs API i bezpłatną bazę danych do pobrania.

Z witryny internetowej MaxMind możesz pobrać bibliotekę PHP wraz z całą
funkcjonalnością oferowaną przez usługę. Aby skorzystać z interfejsu
API, pobierz i zainstaluj kod z serwisu GitHub
(https://github.com/maxmind/GeoIP2-php).

Geocoder PHP

Geocoder PHP (https://geocoder-php.org/) to biblioteka PHP, która ułatwi
Ci tworzenie aplikacji internetowych i mobilnych wykorzystujących dane
geolokalizacji. W odróżnieniu od biblioteki MaxMind będącej własnym
dostawcą geolokalizacji Geocoder PHP umożliwia wybór spośród wielu
dostawców geolokalizacji, w tym także MaxMind. Dzięki tej bibliotece PHP
wywoływanie i pobieranie danych od różnych dostawców geolokalizacji jest
łatwe i spójne. Aby skorzystać z biblioteki Geocoder PHP, należy wybrać
dostawcę geolokalizacji i klienta HTTP. Oto lista aktualnie
obsługiwanych dostawców:

-   Algolia Places
-   ArcGIS Online
-   Bing Maps
-   FreeGeoIp
-   Geocode Earth
-   GeoIP
-   GeoIP2
-   Geonames
-   GeoPlugin
-   Mapy Google
-   Miejsca w Mapach Google
-   GraphHopper
-   Here
-   HostIp
-   IpInfo
-   IpInfoDB
-   ipstack
-   LocationIQ
-   Mapbox
-   MapQuest
-   MaxMind
-   MaxMind Binary
-   Nominatim
-   OpenCage
-   Pelias
-   Photon
-   PickPoint
-   TomTom
-   Yandex.

Hosting z usługami geolokalizacji

Niektórzy dostawcy usług hostingowych oferują usługi geolokalizacji
zintegrowane bezpośrednio z platformami hostingowymi. W takich
sytuacjach oferowane są informacje takie jak kontynent odwiedzającego
witrynę internetową, kraj, województwo lub region, miejscowość. Te dane
można następnie wykorzystać do wyświetlania użytkownikowi odpowiedniej
treści na podstawie jego położenia geograficznego.

Przykładowo usługi hostingu WP Engine korzystają z dodatkowej usługi
geolokalizacji (https://wpengine.com/support/geotarget/) zintegrowanej z
przygotowanym dla tej platformy rozwiązaniem w zakresie buforowania
WordPressa, dostępnym za pomocą własnej wtyczki WordPressa. Buforowane
informacje o odwiedzającym są przechowywane w kubełkach, które mogą być
dostępne za pomocą zmiennych PHP i skrótów WordPressa. To jest
prawdopodobnie jeden z najszybszych sposobów na zintegrowanie danych
geolokalizacji z witryną internetową, choć trzeba skorzystać z hostingu
WP Engine.

Kompresja i archiwizowanie plików

Można wyobrazić sobie wiele sytuacji, w których w sposób programowy
przeprowadzane jest kompresowanie i dekompresowanie plików. W większości
przypadków wykonuje się jedną z dwóch wymienionych tutaj operacji:

-   automatyczne rozpakowywanie archiwum ZIP na postać wielu plików
    zasobów
-   automatyczne kompresowanie wielu plików zasobów na postać
    pojedynczego archiwum ZIP.

Podczas instalowania wtyczki WordPress przeprowadza operację
rozpakowania archiwum. Gdy opracowaną przez siebie wtyczkę przekazujesz
do serwera lub instalujesz wtyczkę pochodzącą z repozytorium WordPressa,
WordPress odszukuje archiwum ZIP i rozpakowuje jego zawartość do
katalogu wp-content/plugins instalacji WordPressa.

W przypadku witryny AppPresser.com kompresowanie i rozpakowywanie plików
odbywa się programowo na platformie, natomiast w przypadku interfejsu
użytkownika App Builder dostępne jest pole pozwalające na przekazanie
archiwum ZIP zawierającego wszystkie zasoby aplikacji mobilnej. Te
zasoby mogą być również używane lokalnie w aplikacji mobilnej.
Działający po stronie serwera kod PHP otrzymuje archiwum ZIP,
rozpakowuje je, a następnie przenosi wszystkie pliki do katalogu
lokalnego w katalogu projektu aplikacji. Gdy aplikacja jest gotowa do
kompilacji, przeprowadzana jest automatyczna kompresja wszystkich plików
zasobów w katalogu projektu aplikacji, a następnie archiwum zostaje
przekazane do PhoneGap Build w celu kompilacji. Ostatecznie wszystkie
obrazy źródłowe przekazane w postaci pojedynczego archiwum ZIP są w
skompilowanej aplikacji mobilnej pobierane lokalnie.

Mieliśmy kiedyś okazję pracować nad migracją ogromnej platformy z
własnościowego systemu CMS (content management system) do sieci witryn
internetowych WordPressa. Migrowana witryna internetowa korzystała z
własnej bazy danych MySQL. Otrzymaliśmy dostęp w postaci konta SFTP,
w którym wszystkie witryny internetowe przeznaczone do migracji
znajdowały się w postaci oddzielnych archiwów ZIP. Każdy plik ZIP
zawierał plik .sql, którego treścią była zawartość bazy danych
z wszystkimi plikami kodu źródłowego i zasobami dla poszczególnych
witryn. Trzeba było przeprowadzić migrację ponad ośmiu tysięcy witryn,
co oznaczało ponad osiem tysiecy plików ZIP, które należało rozpakować,
a następnie uruchomić niestandardowe skrypty migracji w celu
przeniesienia wszystkich danych do WordPressa. Byliśmy w stanie
zautomatyzować ten proces przez zastosowanie programowej iteracji przez
pliki ZIP znajdujące się na koncie SFTP, a następnie ich rozpakowanie za
pomocą narzędzia PHP ZipArchive
(https://www.php.net/manual/en/book.zip.php).

Klasa PHP ZipArchive oferuje wiele funkcjonalności pomagających w
kompresowaniu i rozpakowywaniu plików. Wymieniona klasa zwykle jest
standardowo dostępna w PHP. Masz możliwość kompresowania plików
pojedynczo lub wskazania katalogu, którego cała zawartość będzie
skompresowana. Metoda ZipArchive::open zapewnia podstawową funkcję
przeznaczoną do otwierania nowego archiwum ZIP w celu odczytywanialub
zmodyfikowania jego zawartości. Wymieniona metoda akceptuje parametr
filename będący ścieżką dostępu w postaci nazwy katalogu i pliku
archiwum ZIP do otworzenia. Jest to parametr opcjonalny, flag,
akceptujący jedną z czterech wymienionych wartości określających tryb
działania.

OVERWRITE

Nadpisuje pliki w podanym archiwum, o ile istnieją w nim już dodawane
pliki.

CREATE

Tworzy nowe archiwum, jeśli archiwum o podanej nazwie jeszcze nie
istnieje.

EXCL

Pozwala na sprawdzenie, czy podane archiwum już istnieje.

CHECKONS

Pozwala na dodatkowe sprawdzenie spójności archiwum. Jeśli ta operacja
zakończy się niepowodzeniem, metoda generuje komunikat błędu.

Kompresja poszczególnych plików na postać archiwum

Poniżej znajduje się prosty fragment kodu pokazujący, jak można dodawać
pliki do archiwum ZIP — w danej chwili tworzony jest tylko jeden plik.
Jak można sobie wyobrazić, istnieje możliwość utworzenia kodu
przeprowadzającego iterację przez wskazane pliki, a następnie dodającego
je do nowego archiwum ZIP.

    <?php

    // Zaczynamy od utworzenia egzemplarza ZipArchive

    $zip = new ZipArchive();

    // Za pomocą metody open() tworzymy archiwum ZIP w serwerze

    $zip->open( 'compressed-dir-path/messenlehner-kids.zip', ZipArchive::CREATE );

    // Metoda addFile() pozwala na dodanie pliku do archiwum ZIP

    $zip->addFile( 'dowolna-ścieżka-dostępu/index.html', 'index.html' );

    // Istnieje również możliwość dodawania plików do podkatalogów w archiwum ZIP

    $zip->addFile( 'dowolna-ścieżka-dostępu/dalya.png', 'images/dalya.png' );

    $zip->addFile( 'dowolna-ścieżka-dostępu/brian.png', 'images/brian.png' );

    $zip->addFile( 'dowolna-ścieżka-dostępu/nina.mp4', 'videos/nina.png' );

    // Można zmienić nazwę pliku podczas jego dodawania do archiwum

    $zip->addFile( 'dowolna-ścieżka-dostępu/CWM.png', 'images/cam.png' );

    $zip->addFile( 'dowolna-ścieżka-dostępu/babyA.png', 'images/aksel.png' );

    // Wywołanie metody close() kończy operację i zapisuje nowe archiwum

    $zip->close();

    ?>

Kompresja wielu plików

ZipArchive zawiera funkcje pozwalające na pobieranie różnych plików z
podanych ścieżek dostępu. Dzięki temu pliki można dodawać do archiwum
ZIP zbiorczo zamiast pojedynczo.

addGlob()

Ta metoda umożliwia identyfikację plików zdefiniowanych typów.

addPattern()

Ta metoda pozwala na używanie wyrażeń regularnych do identyfikowania
plików w katalogu na podstawie dowolnego wzorca w nazwach plików.

W kolejnym fragmencie kodu znajduje się przykład użycia metod addGlob()
i addPattern() w celu dodania wszystkich plików obrazów .png i .jpg oraz
plików wideo .mp4 do tworzonego archiwum ZIP.

    <?php

    // Zaczynamy od utworzenia egzemplarza ZipArchive

    $zip = new ZipArchive();

    // Za pomocą metody open() tworzymy archiwum ZIP w serwerze

    $zip->open( 'compressed-dir-path/messenlehner-kids.zip', ZipArchive::CREATE );

    // Zdefiniowanie tablicy opcji pozwalającej na dodanie katalogu 'videos' do archiwum ZIP

    $options = array( 'add_path' => 'videos/', 'remove_all_path' => TRUE );

    // Dodanie plików 'mp4' z podanego katalogu do katalogu 'videos' w archiwum ZIP

    $zip->addGlob( 'dowolna-ścieżka-dostępu/*.mp4', 0, $options );

    // Zdefiniowanie tablicy opcji pozwalającej na dodanie katalogu 'images' do archiwum ZIP

    $options = array( 'add_path' => 'images/', 'remove_all_path' => TRUE );

    // Dodanie plików 'jpg' i 'png' z podanego katalogu do katalogu 'images' w archiwum ZIP

    $zip->addGlob( 'some-other-dir-path/*.{jpg, png}', GLOB_BRACE, $options );

    // Istnieje możliwość użycia wyrażeń regularnych w celu pobrania dowolnie wskazanych plików z podanego katalogu

    $zip->addPattern( '/\.(?:jpg|png)$/', 'another-dir-path', $options );

    // Wywołanie metody close() kończy operację i zapisuje nowe archiwum

    $zip->close();

    ?>

Wyodrębnianie plików z archiwum

Aby automatycznie rozpakować skompresowane archiwum ZIP, możesz użyć
metody extractTo(), która przyjmuje dwa parametry.

destination

Wskazuje miejsce, w którym zostaną rozpakowane i zapisane pliki z
archiwum ZIP.

entries

Wskazuje pliki, które mają być wyodrębnione z archiwum ZIP. Możesz
pobierać po jednym pliku, tablicę plików lub, jeśli chcesz wyodrębnić
wszystkie pliki z archiwum ZIP, możesz wykluczyć ten parametr.

    <?php

    // Sposób wyodrębnienia plików z archiwum ZIP w serwerze

    $zip = new ZipArchive();

    $zip->open( 'compressed-dir-path/messenlehner-kids.zip',

    ZipArchive::CREATE );

    // Użycie metody extractTo() w celu wyodrębnienia plików z archiwum ZIP w serwerze

    // Wyodrębniony będzie jeden plik

    $zip->extractTo( 'uncompressed-dir-path/', 'images/aksel.png' );

    // Wyodrębnione będą wszystkie pliki z tablicy

    $zip->extractTo( 'uncompressed-dir-path/',

    array( 'images/cam.png', 'images/nina.png' ) );

    // Wyodrębnione będą wszystkie pliki z archiwum

    $zip->extractTo( 'uncompressed-dir-path/' );

    $zip->close();

    ?>

Inne biblioteki PHP do kompresji

Do kompresji i rozpakowywania plików w WordPressie używana jest
biblioteka ZipArchive. W rzeczywistości WordPress najpierw sprawdza, czy
wymieniona biblioteka jest dostępna. Jeśli nie, wtedy jako rozwiązania
awaryjnego używa innej popularnej biblioteki służącej do kompresji
plików PclZip. Poza wymienionymi istnieją również inne biblioteki PHP,
których można używać do kompresji i rozpakowywania plików:

-   PclZip (https://github.com/ivanlanin/pclzip)
-   Bzip2 (https://www.sourceware.org/bzip2/)
-   LZF (https://www.php.net/manual/en/book.lzf.php)
-   Phar (https://www.php.net/manual/en/book.phar.php)
-   Rar (https://www.php.net/manual/en/book.rar.php)
-   Zlib (https://www.php.net/manual/en/book.zlib.php).

Narzędzia programistyczne

Oto kilka bibliotek PHP ułatwiających pracę programistom. Oczywiście
dostępnych jest wiele doskonałych narzędzi, tutaj wymieniliśmy jedynie
kilka wybranych godnych uwagi.

PHPUnit

Jeśli jeszcze nie słyszałeś o testach jednostkowych, powinieneś jak
najszybciej zapoznać się z tym tematem. Jest to świetna metoda do
sprawdzenia kodu pod kątem regresji oraz do automatycznego wyszukiwania
błędów w kodzie. Potraktuj tę bibliotekę jako rozwiązanie pozwalające na
tworzenie kodu automatyzującego testowanie kodu aplikacji. Dzięki
PHPUnit (https://phpunit.de/) można zdefiniować określone testy
jednostkowe, które będą wykonywane dla określonych funkcji w kodzie w
celu potwierdzenia, że działanie sprawdzanych funkcji jest zgodne z
oczekiwaniami. Nie jesteśmy w stanie wystarczająco mocno podkreślić wagi
testów jednostkowych, gdy wielu programistów pracuje nad danym kodem.
Zapewnij swoim klientom i sobie spokój dzięki przeprowadzaniu testów
jednostkowych przed wdrożeniem w środowisku produkcyjnym jakichkolwiek
uaktualnień kodu źródłowego.

  ---- -----------------------------------------------------------------------------------------------------------------------------
  []   Możesz, a nawet powinieneś pobierać dodatkowe wynagrodzenie za stosowanie testów jednostkowych podczas tworzenia aplikacji.
  ---- -----------------------------------------------------------------------------------------------------------------------------

phpDocumentor

Każdy dobry programista wie o tym, jak ważne jest umieszczanie w
tworzonym kodzie rzetelnych komentarzy i dodatkowej dokumentacji. Dzięki
temu inni programiści przeglądający ten kod od razu mogą się
zorientować, o co w nim chodzi. Taka praktyka sprawdza się również
wtedy, gdy po jakimś czasie, np. po kilku latach, powracasz do
utworzonego przez siebie kodu. Dlatego zawsze powinieneś pamiętać o
dodawaniu dobrych komentarzy. Doskonałym narzędziem pozwalającym na
automatyczne generowanie dokumentacji na podstawie komentarzy
umieszczonych w kodzie jest phpDocumentor
(https://github.com/phpDocumentor/phpDocumentor).

Faker

Faker (https://github.com/fzaninotto/Faker) jest świetną biblioteką PHP
do automatycznego generowania przykładych treści, których można używać
do zapełniania bazy danych, tworzenia przykładowych użytkowników
WordPressa, wyświetlania przykładowych treści na tworzonej stronie,
zanim zostanie zapełniona treścią docelową, do generowanie kanału XML,
do wypełniania punktów końcowych API, do przeprowadzania testów
jednostkowych itd. Podczas tworzenia przykładowej treści można
skorzystać z wymienionych tutaj komponentów formatowania bądź też
opracować własne za pomocą funkcji zdefiniowanych w klasie Base:

-   Base
-   Lorem Ipsum Text
-   Person
-   Address
-   Phone Number
-   Company Real
-   Text Date and Time
-   Internet User Agent
-   Payment
-   Color
-   File
-   Image
-   Uuid
-   Barcode
-   Miscellaneous Biased
-   Html Lorem.

Goutte a PHP-based website scraper

Nie masz dostępu do danych źródłowych witryny internetowej i musisz
przeprowadzić migrację do WordPressa? Potrzebujesz danych produktu z
wielu witryn internetowych, które nie oferują kanału danych. Doskonałym
rozwiązaniem w takich sytuacjach może okazać się ekstrakcja danych (web
scraping). Jednak bardzo czasochłonne może być programowe znalezienie
pewnych szukanych wzorców na stronach internetowych (o ile istnieje
pewna spójność), a następnie przetworzenie kodu znaczników strony HTML
na podstawie wzorców pozwalających na ekstrakcję żądanych danych. Jeżeli
przeprowadzasz ekstrakcję danych z wielu stron internetowych, może to
być niezwykle żmudna operacja.

Goutte (https://github.com/FriendsOfPHP/Goutte) to doskonałe narzędzie
pozwalające na ekstrakcję praktycznie dowolnych danych z dostarczonego
kodu znaczników HTML, choć możliwe jest również przetwarzanie danych w
formacie XML. Goutte niezwykle ułatwia przetwarzanie i analizowanie
danych zwróconych przez żądanie HTTP. Używa do tego predefiniowanych
metod, które pomagają programiście w identyfikowaniu i wyodrębnianiu
wszelkich elementów HTML. Oto kilka ciekawych zadań, które można wykonać
dość łatwo za pomocą Goutte:

-   wyodrębnianie łączy z treści
-   wyodrębnianie obrazów z treści
-   wyodrębnianie nagłówków ze znaczników nagłówków
-   wyodrębnianie treści znaczników <div> na podstawie ich
    identyfikatorów lub nazw klas
-   wyodrębnianie elementów równorzędnych, nadrzędnych i potomnych z
    list uporządkowanych i nieuporządkowanych
-   wyodrębnianie dowolnej treści z dowolnych znaczników HTML
-   wyodrębnianie określonych węzłów z danych XML
-   automatyczne klikanie łączy
-   automatyczne wysyłanie formularzy internetowych
-   automatyczne logowanie do witryn internetowych (o ile zostaną podane
    prawidłowe dane uwierzytelniające, czyli nazwa użytkownika i hasło).

Whoops, czyli przyjazne użytkownikowi komunikaty błędów PHP

Whoops (https://github.com/filp/whoops) to dostępna jako pakiet Composer
biblioteka PHP pozwalająca na obsługę błędów i wyjątków w kodzie w
znacznie bardziej elegancki sposób. Masz możliwość całkowitego
dostosowania do własnych potrzeb komunikatów błędów PHP, aby zawierały
więcej użytecznych informacji niż w standardowych komunikatach, które
czasami są naprawdę trudne do zrozumienia. Jest to doskonałe narzędzie
do zarządzania i wyświetlania błędów; pomoże Ci w znacznie łatwiejszym
rozwiązywaniu problemów z kodem źródłowym.

Zewnętrzne API i usługi sieciowe

Interfejs API może być częścią aplikacji, w której masz dostęp do kodu
źródłowego. Mamy więc do czynienia z sytuacją podobną, jak w przypadku
innych API WordPressa omówionych w tej książce. Interfejs API może też
umożliwiać korzystanie z aplikacji lub usługi, w których nie masz
bezpośredniego dostępu do kodu źródłowego. Wiele aplikacji i usług
internetowych oferuje pewnego rodzaju interfejs API pozwalający na
uzyskanie dostępu do danych lub przeprowadzanie na nich operacji z
poziomu innej aplikacji.

W kolejnych sekcjach przedstawiamy nasze ulubione API usług sieciowych,
które można bardzo łatwo zintegrować z WordPressem.

Elasticsearch

To jest Elasticsearch (https://www.elastic.co/elastic-stack), Logstash,
Kibana i Beats, które razem tworzą tzw. stos ELK. Rozwiązanie pozwala na
niezawodne i bezpieczne pobieranie danych z dowolnego źródła, w dowolnym
formacie, a następnie ich formatowanie, przeszukiwanie, analizowanie i
wizualizowanie w czasie rzeczywistym.

ElasticPress firmy 10up

Wtyczka ElasticPress firmy 10up
(https://wordpress.org/plugins/elasticpress/) automatycznie integruje
aplikację z Elasticsearch, aby indeksować bazę danych Twojej aplikacji
WordPressa oraz umożliwić użycie w aplikacji internetowej rozbudowanej
funkcjonalności wyszukiwania w WordPressie.

Google Vision

To rozwiązanie jest jednocześnie świetne i nieco przerażające. API
Google Vision (https://cloud. google.com/vision/) wykorzystuje techniki
uczenia maszynowego do analizy dostarczonych obrazów i próbuje ocenić
prawdopodobieństwo przedstawienia czegoś na danym obrazie.

Mapy Google

Praktycznie każdy zna Mapy Google i jesteśmy przekonani, że każdy
programista WordPressa natknął się na wtyczki WordPressa zapewniające
integrację z Mapami Google. Firma Google oferuje oparte na JavaScripcie
API
(https://developers.google.com/maps/documentation/javascript/tutorial)
przeznaczone do pracy z mapami. Na podstawie mapy określonego położenia,
niestandardowej mapy z własnymi znacznikami itd. można przedstawić
niemalże wszystko w poście WordPressa, wykorzystując do tego
niestandardowe typy postów. Jedynym ograniczeniem jest tutaj tylko
wyobraźnia programisty. Właściwie powinniśmy napisać, że jedynym
ograniczeniem jest wielkość kuli ziemskiej.

Poza całą funkcjonalnością dostępną za pomocą API JavaScriptu Map Google
dostępne są jeszcze inne API usług związanych z mapami.

Directions

Tę usługę można wykorzystać do wyznaczenia trasy między różnymi
położeniami i podania informacji, krok po kroku, jak pokonać tę trasę.
Podczas generowania tych danych przekazuje się położenia początkowe i
końcowe. Istnieje również możliwość określenia trybu podróżowania:
samochodem (domyślnie), rowerem, transportem publicznym lub pieszo.

Distance Matrix

API Distance Matrix firmy Google to usługa oferująca informacje o
długości trasy i czasie potrzebnym na jej pokonanie, od punktu
początkowego do końcowego. Zwrócone informacje są oparte na zalecanej
trasie między punktami początkowym i końcowym, wyznaczonej przez API Map
Google, i zawiera rekordy z wartościami czasu podróży i odległości dla
każdej pary.

Elevation

To API zapewnia możliwość wykonywania zapytań dotyczących danych o
wskazanych punktach.

Geocoding

To API pozwala na pobieranie danych geolokalizacji, np. szerokości i
długości geograficznej, dla podanego adresu. Istnieje możliwość
skorzystania z odwrotnej geolokalizacji, aby w ten sposób znaleźć
najbliższy adres dla podanych współrzędnych geograficznych.

Street View

To API pozwala na pracę z funkcjonalnością Street View w Mapach Google.
Doskonałą jego cechą jest możliwość uzyskania dostępu do wszystkich
obrazów i lokalizacji, które są dostępne za pomocą Map Google.

Wtyczki Map Google dla WordPressa

Wymienione tutaj wtyczki WordPressa pozwalają na wykorzystanie usługi
Map Google.

WP Google Maps (https://wordpress.org/plugins/wp-google-maps/)

Jest to jedna z najpopularniejszych wtyczek WordPressa używająca Map
Google i pozwalająca na łatwe umieszczanie tych map w postach WordPressa
za pomocą skrótów.

Gutenberg Map Block for Google Maps
(https://wordpress.org/plugins/map-block-gutenberg/)

Jeżeli korzystasz z projektu Gutenberg i chcesz zaoferować użytkownikom
łatwe w użyciu rozwiązanie do zarządzania Mapami Google, wypróbuj tę
wtyczkę.

gPano (https://wordpress.org/plugins/gpano/)

Łatwa w użyciu wtyczka przeznaczona do osadzania obrazu panoram Google
Street View w postach lub na stronach.

WP Store Locator (https://wordpress.org/plugins/wp-store-locator/)

Łatwa w użyciu wtyczka WordPressa pozwalająca na umieszczanie na mapach
fizycznych miejsc z niestandardowymi znacznikami i informacjami. Te
miejsca można wyszukiwać po nazwie i za pomocą metadanych, a także
określić promień względem danego miejsca. Omawiana wtyczka używa również
usługi Directions Map Google, aby zapewnić informacje pozwalające na
dotarcie do wskazanego miejsca.

Tłumacz Google

Co można zrobić w sytuacji, gdy fragment treści będziesz chciał
przetłumaczyć na inne języki? Do tego celu można wykorzystać API
Tłumacza Google (https://cloud.google.com/translate/docs/). Dostępnych
jest sporo wtyczek WordPressa używających tego API, ale w zależności od
sytuacji pewne fragmenty tekstu chciałbyś tłumaczyć w locie, na co
pozwala omawiane tutaj API. W tej usłudze Google korzysta z uczenia
maszynowego, co zostało nazwane AutoML Translation. To API nie jest
bezpłatne, ale w zależności od wagi automatycznego tłumaczenia treści
ten koszt może być warty poniesienia.

Translate WordPress with GTranslate
(https://wordpress.org/plugins/gtranslate/) to doskonała wtyczka
pokazująca wybrane możliwości usługi Tłumacza Google zintegrowanej z
WordPressem.

Twilio

Czy w aplikacji masz potrzebę wysyłania dostosowanych do własnych
potrzeb wiadomości SMS dla członków aplikacji internetowej? Być może
aplikacja wymaga dodatkowego poziomu zabezpieczeń i weryfikacji kont
użytkowników za pomocą losowo wybranych kodów weryfikacyjnych, które są
przekazywane użytkownikom poprzez wiadomości SMS. Twilio
(https://www.twilio.com/ sms/api) oferuje doskonałą usługę sieciową
pozwalającą na wysyłanie i otrzymywanie wiadomości SMS między telefonami
komórkowymi i kontami użytkowników.

Być może szkoła musi zweryfikować numery telefonów rodziców, aby później
móc wysyłać wiadomości SMS zawierające ważne komunikaty dotyczące
dzieci, na przykład o niedozwolonym zachowaniu w placówce. W takich
przypadkach powinieneś pobrać z serwisu GitHub bibliotekę PHP Twilio
(https://github.com/twilio/twilio-php/). Jeżeli tworzysz własną wtyczkę,
plik Twilio.php i katalog Twilio umieść w podkatalogu lib wtyczki.
Struktura katalogu powinna więc przedstawiać się następująco
/wp-content/plugins/<nazwa-wtyczki>/lib/Twilio.

  ---- -----------------------------------------------------------------
  []   Podczas pracy z API Twilio zalecamy stosowanie szyfrowania SSL.
  ---- -----------------------------------------------------------------

Inne popularne interfejsy API

Wspomnieliśmy już o kilku dostępnych bibliotekach PHP, usługach
internetowych i interfejsach API, których możesz używać w zależności od
tego, co próbujesz osiągnąć. Wymieniliśmy tutaj jedynie
najpopularniejsze z możliwości, jakie oferuje internet, a to tylko
wierzchołek góry lodowej możliwości.

Pamiętaj, nie musisz odkrywać Ameryki na nowo. Zanim zaczniesz cokolwiek
robić, sprawdź, czy wcześniej nie zostało już utworzone i udostępnione
odpowiednie rozwiązanie. Używaj danych ze źródeł zewnętrznych oraz
integruj swoje dane z zewnętrznymi sieciami społecznościowymi i
katalogami. Pracuj mądrzej, nie ciężej!

Oto kilka popularnych usług internetowych, z którymi warto
poeksperymentować.

Google APIs Explorer (https://developers.google.com/apis-explorer/)

Lista usług internetowych Google z interfejsami API obejmującymi między
innymi YouTube, Dysk Google, Kalendarz Google, Gmail, Google Analytics,
Google Hangouts, Google Firebase.

Instagram Graph API (https://developers.facebook.com/docs/instagram-api)

Interfejs API używany do tworzenia aplikacji, które umożliwiają kontom
typu Business i Creator na programowe zarządzanie zdjęciami, filmami,
historiami, albumami, komentarzami i hashtagami.

Salesforce API Explorer
(https://developer.salesforce.com/docs/api-explorer )

Lista dostępnych usług Salesforce z interfejsami API dla m.in.:
Marketing Cloud, Einstein Prediction, Force.com i Data.com.

Flickr API (https://www.flickr.com/services/api/)

Interfejs API do programowego zarządzania zdjęciami i zawartością konta
w serwisie Flickr.

eBay API
(https://developer.ebay.com/api-docs/developer/static/developer-landing.html)

eBay posiada kilka dostępnych interfejsów API, które pozwalają na
programowe wyszukiwanie, kupowanie, sprzedawanie i negocjowanie, a także
na wykonywanie wszelkich innych czynności związanych z kupnem i
sprzedażą.

Dropbox API (https://www.dropbox.com/developers)

Umożliwia programowe zarządzanie kontami Dropbox. Dodaje do aplikacji
internetowych obsługę funkcji Dropbox, takich jak przechowywanie,
udostępnianie, wyświetlanie i wyszukiwanie plików oraz wiele innych
zadań.

LinkedIn API (https://www.linkedin.com/developers/)

Używa interfejsu API LinkedIn do programowego wyszukiwania i
udostępniania treści platformy.

MailChimp API (https://mailchimp.com/developer/)

Wykorzystuje interfejs API MailChimp do synchronizowania operacji
związanych z wiadomościami e-mail, organizowania danych kampanii,
zarządzania odbiorcami i automatyzacji sposobu pracy.

Constant Contact API (https://developer.constantcontact.com/)

Możliwe jest programowe zarządzanie kontami Constant Contact, w tym
pobieranie, tworzenie i aktualizowanie elementów książki adresowej.

Prawie każda duża usługa sieciowa oferuje pewnego rodzaju interfejs API,
który umożliwia pracę z danymi tej usługi.

Migracje

Migracje, migracje, migracje… od czego zacząć? Najlepiej zacznę od
początku, czyli od pierwszej dużej migracji, nad którą miałem okazję
pracować. Zanim jeszcze zająłem się WordPressem, byłem całkiem zielony i
pracowałem dla dowództwa logistyki morskiej w Camp Lejeune w Północnej
Karolinie. Służąc w Korpusie Piechoty Morskiej Stanów Zjednoczonych, w
ramach szkolenia nauczyłem się, jak budować, aktualizować i konserwować
relacyjne bazy danych na dużą skalę. Poznałem wady i zalety języka SQL (
structured query language) i różnice w składni pomiędzy różnymi bazami
danych. Korzystaliśmy głównie z Microsoft SQL Server, w przypadku
większych projektów natomiast używaliśmy produktów firmy Oracle.
Większość baz danych, które utworzyłem lub nad którymi pracowałem, miała
frontendy internetowe zbudowane za pomocą ColdFusion, Lassic ASP lub
ASP.NET. Na przestrzeni czasu stałem się bardzo wydajny w tworzeniu kodu
właśnie w tych językach programowania. Mogłem używać kodu do
przekazywania dowolnych informacji z baz danych, z których chciałem, i
dodawać dane do wybranych przeze mnie baz danych. Jedną z największych
baz danych, z którą pracowałem podczas mojej służby w wojsku jak również
w trakcie obecnej kariery, jest system internetowy zdolny do śledzenia
wszelkiego rodzaju sprzętu, od zbiorników po szczoteczki do zębów. Ten
system logistyczny został zbudowany we współpracy z kontrahentami
cywilnymi, aby zastąpić używany wtedy przez Korpus Piechoty Morskiej
Stanów Zjednoczonych system mainframe do obsługi zadań związanych z
zaopatrzeniem jednostek. Zajmowałem się wtedy umieszczaniem ogromnej
ilości danych w bazie danych Oracle używanej przez nową aplikację
internetową. Otrzymałem rozkaz jedzenia, spania i oddychania tą ogromną
migracją danych, więc przez kilka miesięcy zajmowałem się tylko tym, aż
do chwili gdy wszystkie dane zostały prawidłowo zaimportowane. W owym
czasie WordPress jeszcze nie istniał. Mimo to wszystko, czego nauczyłem
się podczas tej migracji przeprowadzanej kilkanaście lat temu, kiedy
służyłem w wojsku, nadal ma zastosowanie w obecnych projektach.

Skoncentrujmy się teraz na migracjach WordPress i tym, jak można
przenieść wszystkie dane do WordPressa. Gdy ktoś używa sformułowania
„migracja WordPressa” bez podawania dalszych szczegółów, automatycznie
przychodzą nam na myśl dwie kwestie: migracja hosta i migracja
platformy. W zależności od zadania do wykonania trzeba będzie znać jedno
z tych zagadnień. Niezależnie od tego, co musisz zrobić, istnieją pewne
narzędzia i istniejące wtyczki WordPressa, dzięki którym wykonanie
zadania może stać się nieco łatwiejsze. W kolejnych sekcjach
przeanalizujemy różne typy migracji, z którymi możesz się spotkać.

Migracja hosta

Z migracją hosta mamy do czynienia, gdy instalacja WordPressa jest
przenoszona do innego serwera lub środowiska hostingu. Taka sytuacja
zdarza się, gdy na przykład jesteś programistą uruchamiającym nowe
witryny internetowe dla klientów lub podczas przenoszenia witryny
internetowej do innej firmy świadczącej usługi hostingowe. Najważniejszą
kwestią jest przeniesienie, inaczej „migracja”, istniejącej witryny
internetowej w inne miejsce. Ten proces niemal zawsze odbywa się w taki
sam sposób.

1.  Utwórz kopię zapasową!
2.  Wszystkie pliki kodu źródłowego przenieś do nowego serwera.
3.  Wyeksportuj i zaimportuj bazę danych.
4.  Zmień ustawienia DNS, jeśli zachodzi potrzeba.
5.  Uaktualnij adresy URL w bazie danych, jeśli zachodzi potrzeba.
6.  Upewnij się, że w trakcie tego procesu nic nie zostało uszkodzone.

Dostępne wtyczki migracji

Duplicator — WordPress Migration Plugin
(https://wordpress.org/plugins/duplicator/) to niezawodnie działająca
wtyczka przeznaczona do przenoszenia instalacji WordPressa.

WP Migrate DB Pro (https://deliciousbrains.com/wp-migrate-db-pro/) to
jedna z naszych ulubionych wtyczek migracji przeznaczona do przenoszenia
danych z WordPressa oraz do niego, do przeprowadzania prostych i
skomplikowanych migracji. Dzięki tej wtyczce można wyeksportować
i zaimportować dowolną tabelę bazy danych WordPressa z jednej witryny do
drugiej. Wtyczka ta sprawdza się doskonale podczas pracy w środowiskach
produkcyjnym, roboczym, programistycznym i lokalnym — do aktywacji i
skonfigurowania każdego z nich oraz do łatwego przekazywania danych
służy interfejs użytkownika. Dla omawianej wtyczki powstało kilka
rozszerzeń, można również tworzyć własne. Do wyróżniających się
rozszerzeń zaliczamy CLI Add-on i Multisite Tools Add-on.

Narzędzie migracji witryny internetowej WP Engine

Niektóre firmy oferujące usługi hostingowe, np. WP Engine, oferują
narzędzia migracji, dzięki którym przeniesienie witryny internetowej do
nowej platformy hostingowej jest bardzo łatwe. Twórcy takiego
rozwiązanie dołożyli starań, aby cały proces przeniesienia witryny lub
aplikacji internetowej nie wymagał działań ze strony użytkownika.

Migracja platformy

Przejście do WordPressa z innej platformy to dość popularne rozwiązanie,
choć może okazać się pracochłonne, w zależności od ilości danych i ich
struktury. Czy mamy do czynienia z procesem przejścia z innej platformy
typu open source, takich jak Drupal lub Joomla!, do WordPressa? Czy może
następuje przejście z niestandardowej platformy własnościowej?
Niezależnie od sytuacji konieczne będzie automatyczne zaimportowanie
danych, które mają trafić do WordPressa. Zastosowanie się do
przedstawionej tutaj procedury zagwarantuje nie tylko przeniesienie
wszystkich danych do WordPressa, lecz także pozwoli uniknąć wielu
problemów w trakcie tej operacji.

Zrozumienie docelowej struktury danych

Przekazanie treści do WordPressa to jedynie połowa zadania! Od zawsze
jesteśmy fanami tworzenia skryptów automatyzujących proces wstawiania
informacji do bazy danych. Niezależnie od tego, czy mamy do czynienia z
przygotowaniem prostego formularza internetowego w celu ręcznego
wstawienia informacji do bazy danych, czy też z pobieraniem milionów
rekordów z jednej bazy danych, a następnie ich importowanie w drugiej
bazie danych, najważniejsze jest otrzymanie danych w oczekiwanym
formacie. Bardzo ważne jest tutaj dokładne zrozumienie, jak dane są
ułożone i przechowywane w schemacie docelowej bazy danych. Dokładne
poznanie schematu bazy danych WordPressa i funkcji pomocniczych
platformy przeznaczonych do pracy z bazami danych ma istotne znaczenie
podczas migracji treści do WordPressa. Jeżeli baza danych WordPressa ma
przed Tobą tajemnice lub jej dokładnie nie poznałeś, być może nie
powinieneś był pomijać rozdziału 2.

Zrozumienie struktury danych źródłowych

Zakładamy, że znasz docelową strukturę danych w WordPressie, jednak dane
źródłowe mogą znajdować się w dowolnej postaci. To może być inna witryna
internetowa WordPressa. To może być inna platforma PHP i MySQL, np.
Drupal lub Joomla!. To może być niestandardowy, własnościowy schemat
bazy danych w MS SQL Server, Oracle lub w innego typu bazie danych. To
mogą być dane w formacie XML lub JSON pobierane za pomocą API. To może
być seria plików CSV lub nawet statycznych plików HTML. Tę listę można
kontynuować jeszcze długo, dane źródłowe mogą mieć praktycznie dowolną
postać, a Twoim celem jest ich umieszczenie w WordPressie. Niezależnie
od rodzaju danych źródłowych trzeba koniecznie znać ich strukturę i
wiedzieć, jak ją mapować na strukturę danych w WordPressie. Mieliśmy
okazję widzieć i pracować praktycznie z każdym rodzajem danych
przenoszonych do WordPressa. W tym podrozdziale przedstawiamy krótką
listę pewnych źródeł danych, w pracy z którymi mamy spore doświadczenie.

Dane pochodzące z bazy danych

Większość naszego doświadczenia związanego z migracjami platformy z
zewnętrznego źródła danych do WordPressa dotyczy przenoszenia informacji
z innych baz danych SQL. W zależności od silnika, schematu i wielkości
bazy danych podczas migracji być może trzeba będzie się zmierzyć z
poważnymi wyzwaniami.

Schematy baz danych MySQL

MySQL jest bezpłatna, bardzo popularna i najczęściej używana z opartymi
na PHP systemami zarządzania treścią lub systemami publikacji, takimi
jak WordPress, Drupal, Joomla!, Magento, ExpressionEngine, SilverStripe,
MediaWiki itd.

Schematy baz danych serwera Microsoft SQL Sever

SQL Server firmy Microsoft to nie jest produkt bezpłatny, ale bardzo
popularny i używany w różnych zastosowaniach, od prostych witryn
internetowych po korporacyjne aplikacje internetowe. W większości
przypadków baza danych SQL Server ma frontend utworzony za pomocą .NET.

Schematy baz danych Oracle

Jeżeli używasz bazy danych Oracle, prawdopodobnie masz ku temu powody.
Jeżeli dysponujesz ogromną ilością danych (liczonych w milionach
rekordów), może to być całkowicie uzasadnione. Mieliśmy okazję pracować
z klientami, którzy używali baz danych Oracle, choć było to zupełnie
niepotrzebne. Nowy interfejs użytkownika dla połączenia WordPress i
MySQL to eleganckie, wystarczające i skalowalne rozwiązanie, z którego
ci klienci powinni byli skorzystać.

Inne silniki baz danych

Istnieją jeszcze inne silniki baz danych, z którymi mieliśmy okazję
pracować. Oto kilka wybranych: PostgreSQL, DB2, MongoDB, Microsoft
Access SQLite i Sybase.

Dane pochodzące z plików

Czasami możesz nie mieć bezpośredniego dostępu do bazy danych. Być może
cała aplikacja internetowa została uruchomiona z plików w serwerze WWW
lub masz możliwość jedynie wygenerowania w aplikacji eksportowanych
plików. Niezależnie od tego, w jaki sposób pliki danych do Ciebie
trafią, musisz poznać strukturę danych w tych plikach. Istnieje kilka
typowych formatów pliku zawierających dane.

CSV (comma-separated values)

Możesz się spotkać z dowolnym typem pliku zawierającym wartości
rozdzielone pewnymi znakami. Najczęściej spotykanym plikiem tego rodzaju
jest CSV.

XML (extensible markup language)

Ten format jest najczęściej używany do wymiany danych w sieci. XML ma
kilka odmian, do najpopularniejszych zaliczamy RSS, Atom, SOAP i XHTML.

JSON ( javascript object notation)

Jeżeli dane w tym formacie są umieszczone w pliku, zwykle ma on
rozszerzenie .json. Jest to bardzo popularny format do wymiany danych,
który bardzo często zastępuje XML.

HTML (hypertext markup language)

Jeżeli dotarłeś aż do tego miejsca, to raczej nie musimy Ci wyjaśniać,
czym jest ten format.

Dane pochodzące z zewnętrznego API

API to bardzo popularna metoda przekazywania danych do systemu
internetowego i pobierania ich stamtąd lub do przekazywania danych
między systemami internetowymi. Wcześniej wspomnieliśmy o kilku
popularnych usługach internetowych i ich API.

Ekstrakcja danych ze stron internetowych

Jeżeli wszystkie inne rozwiązania zawiodą i nie możesz uzyskać dostępu
do żadnych danych, zawsze możesz je wyodrębnić z działającej witryny
internetowej. Stopień skomplikowania operacji wyodrębniania treści
witryny internetowej zależy od tego, jak dobrą strukturę ma kod HTML tej
witryny internetowej. Powinieneś się skoncentrować na znalezieniu pewnej
spójności między stronami, z których będą pobierane dane.

Niezależnie od źródła danych ogólna idea zawsze pozostaje taka sama:
przetworzenie danych, iteracja przez dane i ich umieszczenie w
odpowiednim miejscu. To wydaje się bardzo prostym zadaniem i w
rzeczywistości najczęściej tak jest, ale znaczenie kluczowe ma dokładne
zrozumienie danych źródłowych i WordPressa.

Utworzenie przewodnika mapowania danych

Jest to jeden z najważniejszych kroków w każdej migracji niezależnie od
jej wielkości. Mapowanie danych źródłowych na docelowe pozwoli na
dłuższą metę zaoszczędzić sporo czasu. Przeprowadzamy ten krok dla
każdego projektu niezależnie od wielkości danych, i Ty również
powinieneś tak robić. Opracowanie przewodnika mapowania danych to w
rzeczywistości dość proste zadanie. Zachęcamy do skorzystania z arkusza
kalkulacyjnego Google, aby Twoi współpracownicy mogli nad tym pracować w
czasie rzeczywistym. Pracę należy rozpocząć od identyfikacji typów
treści w danych źródłowych, np. postów, komentarzy, użytkowników itd. Na
liście powinien znaleźć się każdy typ treści z wszystkimi dołączanymi
metadanymi — te informacje umieść pionowo po lewej stronie arkusza. Obok
nazwy każdej kolumny umieść typ danych (np. ciąg tekstowy, liczba
całkowita, wartość boolowska itd.). Następnie obok typu możesz umieścić
przykład rzeczywistych danych, a dalej informacje dodatkowe lub inne
komentarze związane z tym polem. Zalecamy przygotowanie pól dla każdego
typu treści i dla wszystkich danych, które są przenoszone do WordPressa.

Po prawej strony arkusza kalkulacyjnego utwórz nową kolumnę, w której
będziesz wpisywać nazwy kolumn bazy danych WordPressa, i rozpocznij
mapowanie kolumn źródłowych na docelowe. Niektóre kolumny będą
oczywiste, np. tytuł posta. Część metadanych w danych źródłowych będzie
użyta jako metadane w WordPressie. Jeżeli jesteś w trakcie tworzenia
nowego motywu lub korzystasz z istniejącej wtyczki WordPressa
zawierającej predefiniowane klucze meta, upewnij się o odwołaniu do
właściwych kluczy metadanych. Jeżeli pracujesz nad migracją dla klienta,
dobrze jest przenalizować wraz z nim przygotowany przewodnik mapowania
danych, który następnie powinien zostać przez niego podpisany. Upewnij
się, że Ty, klient i każda inna osoba zaangażowana w migrację znajduje
się na tej samej stronie, na którą mają trafić dane. Jeżeli zrezygnujesz
z przygotowania przewodnika mapowania danych, być może będziesz musiał
wielokrotnie konsultować się z klientem odnośnie do miejsca, do którego
mają trafić dane, a następnie będziesz tworzyć kolejne skrypty
poprawiające dane lub będziesz poprawiać główny skrypt migracji i
ponownie go uruchamiać. W zależności od ilości importowanych danych
ponowne przeprowadzanie migracji zupełnie od początku może zabierać dużo
czasu, którego wciąż brakuje. Dlatego podczas migracji przygotowuj
przewodnik mapowania danych, a później będziesz mógł nam podziękować.

Rozdział 18. Przyszłość

Pierwsze wydanie książki zostało opublikowane w 2014 roku. W trakcie
tych kilku lat między pierwszą a drugą edycją wiele się zmieniło; wiele
się również zmieni w ciągu kilku lat po opublikowaniu drugiego wydania.

W tym rozdziale przedstawiamy pokrótce największe zmiany wprowadzone w
WordPressie w ciągu ostatnich kilku lat. Jeżeli dotarłeś do tego
rozdziału, powinieneś już wiedzieć nieco na ten temat.

Spróbujemy również przewidzieć przyszłość WordPressa. Wprawdzie część z
tych przewidywań może okazać się zupełnie chybiona, ale część zagadnień
będzie warta uwagi w ciągu kilku najbliższych lat.

Jak to było wcześniej

WordPress 3.0, który pojawił się w 2010 roku, był pierwszą wersją
zapewniającą obsługę niestandardowych typów postów (custom post types,
CPT). Więcej informacji na temat CPT zamieściliśmy w rozdziale 5.
Dodanie obsługi CPT było ostatnim krokiem podczas przejścia WordPressa
z oprogramowania bloga do systemu zarządzania treścią. Dodanie obsługi
CPT pozwoliło programistom rozpocząć używanie WordPressa jako frameworka
aplikacji.

WordPress 4.7 wydany w grudniu 2016 roku zawierał punkty końcowe API
REST dla postów, komentarzy, użytkowników, metadanych i ustawień
(dokładne omówienie API REST znalazło się w rozdziale 10.). Wprawdzie
wtyczka zapewniająca obsługę API REST istniała już kilka lat wcześniej,
ale dopiero pojawienie się API REST w podstawowej wtyczce WordPressa
„zatwierdziło” używanie API REST i zachęciło programistów do tworzenia
opartych na nim rozwiązań.

Wydana w grudniu 2018 roku wersja WordPress 5.0 zaoferowała nowy edytor
bloków Gutenberg (dokładne omówienie edytora Gutenberg, bloków i CPT
zamieściliśmy w rozdziale 11.). Edytor bloków jest nowością i upłynie
nieco czasu, zanim witryny internetowe, wtyczki i motywy zaczną w pełni
korzystać z oferowanych przez niego możliwości. Edytor bloków oznacza
nowy sposób na zarządzanie treścią, układem i innymi ustawieniami
witryny internetowej. Projekt Gutenberg pokazuje również przykłady
użycia nowoczesnego stosu programistycznego JavaScriptu, w którym są
wykorzystywane narzędzia, np. Node.js, npm, React, webpack i Git. Pod
wieloma względami projekt Gutenberg i wtyczki ustalili ogólne standardy
dla programowania z użyciem WordPressa.

API REST

Choć API REST zostało w pełni dodane do wydania WordPress 4.7, musiało
upłynąć kilka lat, zanim programiści i stosy programistyczne zaczęli w
pełni używać i obsługiwać aplikacje wykorzystujące API REST. Obecnie API
REST znajduje zastosowanie w wielu podstawowych komponentach WordPressa
i w wielu jego wtyczkach. W przyszłości powinniśmy być świadkami
zyskiwania przez API REST coraz większego znaczenia na platformie
WordPress.

Wtyczki WordPressa będą bardziej skoncentrowane na API

API odgrywa teraz ważną rolę w wielu projektach. Opracowane API
aplikacji będzie musiało być oddzielne od frontendu. Następnie należy
określić, który stos sprawdzi się najlepiej dla frontendu aplikacji. To
znacznie ułatwia obsługę warstwy danych aplikacji, a także pozwala na
dodanie kolejnych warstw do aplikacji. Ta sama treść WordPressa może być
udostępniana za pomocą witryny internetowej bloga, aplikacji mobilnej,
kampanii mailowej lub poprzez każdą inną aplikację wymagającą tych
danych.

Takie wtyczki jak WooCommerce i BuddyPress oferują API niemal w 100
procentach pokrywające całą ich funkcjonalność. Dzięki temu można
znacznie łatwiej zintegrować dane pochodzące z tych wtyczek z
aplikacjami powiązanymi z witryną internetową WordPressa.

Headless WordPress

Coraz częściej można zauważyć, że WordPress jest używany jedynie jako
magazyn treści przeznaczony dla większych aplikacji internetowych, które
dostęp do tych danych uzyskują za pomocą API REST. Korzystanie z
WordPressa w sposób, w którym administracyjny panel główny jest używany
bez wbudowanych motywów i frontendu, jest określane mianem trybu
headless WordPress.

Generatory statycznych witryn internetowych, np. GatsbyJS, oferują
możliwość hostingu tych witryn internetowych. Hosting ten jest
bezpieczny, wydajny i stosunkowo tani. Można skonfigurować GatsbyJS do
użycia WordPressa w charakterze źródła danych. Instalacja WordPressa
przeznaczona do zarządzania treścią nie musi nawet używać hostingu w
internecie, z powodzeniem może być uruchamiana w środowisku lokalnym.

Nawet dynamiczna witryna internetowa może korzystać z trybu headless
WordPress, o ile jej fragmenty zostały utworzone w kodzie JavaScript
działającym po stronie klienta i używającym usług zewnętrznych lub API
działającego w oddzielnych serwerach.

Taki rodzaj wdrożenia opartego na komponentach jest obecnie popularny.
Istnieją wady i zalety rozproszenia aplikacji między różnymi serwerami i
usługami.

Używanie oddzielnych usług do uruchamiania aplikacji powoduje, że każda
z nich zostaje zoptymalizowana do wykonywania swojego zadania. Jeżeli
któryś z komponentów ulegnie awarii, pozostała część aplikacji być może
będzie w stanie działać bez niego przez jakiś czas. Jeżeli jeden z
komponentów zawiera lukę w zabezpieczeniach, nie spowoduje narażenia
całej aplikacji na niebezpieczeństwo. Jeżeli zachodzi potrzeba
zastąpienia komponentu, znacznie łatwiejsze będzie zastąpienie go niż
przeprowadzanie zmiany całej platformy. To niewątpliwie są zalety
rozproszenia aplikacji między serwerami i usługami.

Używanie różnych usług do uruchomienia aplikacji oznacza konieczność
poświęcenia większej ilości czasu na poznawanie nowych platform i
rozwiązywanie problemów związanych z ich integracją. Czasami współpraca
między poszczególnymi usługami wcale nie przebiega gładko i trzeba
włożyć więcej wysiłku, aby rozwiązanie funkcjonowało zgodnie z
oczekiwaniami. To są oczywiste wady rozproszenia aplikacji między
serwerami i usługami.

Wydaje się istnieć wiele najlepszych praktyk programistycznych
dotyczących całej gamy aplikacji, począwszy od tych samodzielnie
działających aż po rozproszone między wieloma usługami. Na przestrzeni
czasu kolekcja poszczególnych narzędzi współpracujących ze sobą została
zgrupowana w postaci pakietów hostingu, zintegrowanych środowisk
wdrożenia lub zarządzanych kontenerów. Pakiety te pozwalają na
złagodzenie skutków niektórych problemów związanych z integracją,
a także ułatwiają używanie określonych kolekcji narzędzi. Z upływem
czasu zaczną być one postrzegane jako pojedyncza platforma. Obecnie, gdy
rejestrujesz konto w usłudze zarządzanego hostingu WordPressa, nie
musisz zastanawiać się nad serwerem WWW, bazą danych, modułami PHP lub
innymi narzędziami działającymi w komputerze i umożliwiającymi
funkcjonowanie WordPressa. W przyszłości funkcjonować będą podobne,
wymagające tylko jednego kliknięcia, procedury instalacji aplikacji
WordPressa za pomocą różnych technologii i rozproszone między różnymi
serwerami.

GraphQL

GraphQL to język zapytań dla API, który prawdopodobnie zastąpi API REST
wszędzie, także w WordPressie. Na omówienie API REST poświęciliśmy sporo
miejsca — cały rozdział 10. Co więc powoduje, że GraphQL to znacznie
lepsza technologia?

W tradycyjnym API REST to API musi definiować punkty końcowe oraz dane,
które muszą być przekazywane do żądań i przez te żądania. W przypadku
GraphQL usługa wykonująca żądania definiuje zapytanie i format, w którym
chce otrzymać dane. To oznacza mniejszą ilość pracy koniecznej do
wykonania w celu publikacji i konserwacji API, a jednocześnie daje
usługom korzystającym z tego API większą elastyczność w zakresie jego
użycia.

Używanie API REST przypomina wywołanie funkcji w PHP. Istnieją
predefiniowane parametry (część z nich jest opcjonalna), a dane są
ogólnie zwracane w tym samym formacie. GraphQL przypomina wykonywanie
zapytania SQL. Masz możliwość wykonania zapytania dotyczącego dowolnych
dostępnych danych, złączania danych i definiowania wartości, które mają
zostać zwrócone.

Jeżeli chcesz dowiedzieć się więcej na temat GraphQL, odwiedź oficjalną
witrynę internetową https://graphql.org/ lub sięgnij po książkę Learning
GraphQL autorstwa Aleksa Banksa i Eve Porcello (O’Reilly Media). WP
GraphQL to wtyczka dla WordPressa pozwalająca na wykonywanie zapytań
GraphQL do witryny internetowej WordPressa. Więcej informacji na temat
tej wtyczki znajdziesz pod adresem https://www.wpgraphql.com/.

Projekt Gutenberg

Od chwili wprowadzenia nowego edytora bloków w WordPressie 5.0 jesteśmy
świadkami coraz częstszego ich stosowania i definiowania nowych
zastosowań dla edytora bloków zarówno w samym WordPressie, jak i w
innych projektach. W tym podrozdziale przedstawiamy nasze przewidywania
dotyczące projektu Gutenberg i edytora bloków.

Interfejs administracyjny zostanie przeniesiony do rozwiązania opartego na React i Gutenberg

Każde ustawienie związane z wizualnym sposobem wyświetlania treści we
frontendzie witryny internetowej jest doskonałym kandydatem do jego
przeniesienia do bloków. W trakcie drugiej realizacji projektu Guenberg
widżety i menu nawigacyjne zostaną przeniesione do bloków.

Przeniesienie pozostałych ekranów nawigacyjnych do wersji opartych na
React i wywołaniach API może znacznie zwiększyć wydajność działania i
użyteczność panelu głównego WordPressa. Pewne prototypy związane z
przeniesieniem do React widoku List Table w WordPressie znajdują się w
repozytorium New List Table w serwisie GitHub
(https://github.com/WP-API/new-list-tables).

Gutenberg zapewni obsługę edycji we frontendzie WordPressa

Programiści tworzący WordPressa i bloki dokładają starań, aby edytor
bloków w możliwie najdokładniejszy sposób pokazywał, jak treść zostanie
wyświetlona we frontendzie. Gdy części tworzące układ strony
internetowej — takie jak menu, paski boczne i inne — zostaną
przeniesione do edytora blokowego, będziesz miał możliwość modyfikacji
dowolnego elementu wyglądu witryny internetowej poprzez zmianę ułożenia
i edycję bloków.

Mogą istnieć pewne różnice w postrzeganiu tego, co tak faktycznie
oznacza możliwość edycji we frontendzie w WordPressie. Wprawdzie
zastąpienie panelu głównego innym rozwiązaniem może być szybkie i
bezproblemowe, ale obecnie dostępny edytor jest uznawany przez wielu
programistów, którzy chcą zająć się edycją we frontendzie, za
„wystarczająco dobry”. Faktyczne wprowadzenie „edycji we frontendzie”
może zostać opóźnione, a ta luka może zostać wypełniona przez wtyczki
lub rozwiązanie podobne do edycji we frontendzie.

Szablon bloku zastąpi motyw

Motyw WordPressa definiuje wygląd i sposób działania witryny
internetowej. Odbywa się to poprzez wybór koloru, czcionki i układu.
Większość motywów zapewnia elastyczność w zakresie kolorów i czcionek, a
teraz układ strony będzie mógł być kontrolowany za pomocą szablonu
bloku.

Jest to nadmierne uproszczenie projektu witryny internetowej, a dobry
projekt, poza kolorami, czcionkami i układem strony, składa się z wielu
drobiazgów. Trzeba w tym miejscu koniecznie wspomnieć, że taki poziom
kontroli jest oczekiwany przez użytkowników wybierających motyw w
WordPressie.

Zadaniem dobrego motywu będzie zagwarantowanie, że popularne bloki i
szablony bloków będą się świetnie prezentowały w jego projekcie.

Od jakiegoś czasu motywy zawierają skomplikowane funkcje, które
właściwie kwalifikują się do ich umieszczenia we wtyczkach, w tzw.
terytorium wtyczek. Podstawowa idea stojąca za nowym podejściem jest
taka, że użytkownik powinien mieć możliwość zmiany motywu bez obawy o
utratę jakiejkolwiek treści lub funkcjonalności w witrynie internetowej.
Wszystko, co powoduje złamanie tej reguły, powinno znaleźć się we
wtyczce. W motywach znajdujących się w repozytorium WordPress.org
zastosowano się do tej reguły. W przypadku wielu motywów dostępnych poza
wymienionym repozytorium ich autorzy dołożyli starań, aby dostosować się
do tej reguły, a jednocześnie zapewnić możliwość wyróżnienia się motywów
spośród innych i spełniania wymagań użytkowników.

Wiele sklepów oferujących motywy WordPressa w praktyce stało się
sklepami wtyczek. Oferują one wtyczki typu premium pozwalające motywom
na osiągnięcie pełni możliwości. Wspomniane „terytorium wtyczek” wielu
tych motywów stało się obecnie „terytorium bloków”.

Motywy nie odejdą w zapomnienie. Wybrany motyw będzie nadawał wygląd
witrynie internetowej, choć wraz z upływem czasu obsługa nagłówka,
stopki, pasków bocznych i innych komponentów układu zostanie
przeniesiona do edytora blokowego.

Bloki zastąpią wtyczki

Często spotykany zwrot w społeczności WordPressa to „do tego celu jest
wtyczka”. Skoro repozytorium WordPress.org zawiera ponad 50 tysięcy
wtyczek, istnieje duże prawdopodobieństwo, że istnieje wtyczka dla
każdej funkcjonalności lub rodzaju integracji, którego szukasz. Trzeba
ją jedynie znaleźć.

Gdy edytor bloków będzie kontrolował coraz większą liczbę
funkcjonalności i będzie coraz częściej używany podczas tworzenia witryn
internetowych WordPressa, użytkownicy nauczą się najpierw sprawdzać, czy
którykolwiek z bloków nie oferuje niezbędnej funkcjonalności. Wiele z
tych bloków będzie dostarczanych przez wtyczki. Mimo tego bloki mogą być
dodawane również za pomocą pliku JavaScript wczytywanego ze
współdzielonego serwera.

Wtyczki nie znikną z WordPressa, ale użytkownicy będą musieli coraz
częściej myśleć o nich w kategoriach powiązanych z blokami. Zamiast
wtyczki obsługi członkostwa użytkownik będzie szukał bloku
zapewniającego obsługę członkostwa. Wprawdzie istniejące wtyczki mogą
dodawać bloki[1], ale wtyczki tworzone zupełnie od początku jako bloki
będą znacznie odpowiedniejsze dla użytkowników i lepiej się sprawdzą w
nowym stosie technologii oraz paradygmatów programowania
ustandaryzowanych za pomocą projektu Gutenberg.

Udział WordPressa w rynku będzie się zmieniał

Obecnie WordPress jest używany do obsługi mniej więcej jednej trzeciej
witryn internetowych opublikowanych w internecie. Od 2011 do 2019 roku
udział WordPressa w rynku wzrósł z 13,1% do 34% i nadal się zwiększa.

Z perspektywy użytkownika końcowego WordPress konkuruje z usługami
samodzielnego hostingu, takimi jak Squarespace i Shopify. Hosty oparte
na WordPressie usprawniły proces tworzenia nowej witryny internetowej, a
nowy edytor oparty na bloku usprawnił proces układania treści. Oznacza
to, że WordPress wciąż będzie konkurował ze wspomnianymi usługami w
zakresie samodzielnego hostingu.

Konsolidacja pionowa firm WordPressa, gdy firmy hostingowe kupują firmy
tworzące wtyczki i motywy, jeszcze bardziej ułatwi proces tworzenia
witryn internetowych opartych na WordPressie.

Wprawdzie liczba witryn internetowych w pełni opartych na WordPressie
może ulegać zmianie, ale zwiększa się trend tworzenia stosów aplikacji w
postaci oddzielnych witryn internetowych opartych na WordPressie.

WordPress stanie się znacznie popularniejszą platformą do tworzenia aplikacji mobilnych

API REST, standardy progresywnych aplikacji internetowych i narzędzia
takie jak AppPresser powodują, że utworzenie aplikacji mobilnej za
pomocą WordPressa jest znacznie łatwiejsze niż kiedykolwiek wcześniej.
Jeżeli tworzysz aplikację internetową z wykorzystaniem technologii React
lub trybu headless WordPress, sensowne jest użycie tego samego
egzemplarza WordPressa do obsługi frontendu aplikacji mobilnej
opracowanej za pomocą React Native.

WordPress wciąż będzie użyteczny podczas tworzenia różnych aplikacji internetowych

W ciągu pięciu kolejnych lat WordPress nadal będzie stanowił podstawę
dla jeszcze większej liczby witryn internetowych. Platforma stanie się
lepsza. API będzie usprawnione. Narzędzia zostaną rozbudowane. Hosting i
inne usługi poprawią się. Pojawi się kolejne (a może nawet dwa) wydanie
tej książki.

Jesteśmy podekscytowani całą doskonałą pracą, jaką wykonujecie Ty i inni
programiści WordPressa. Jeżeli zbudowałeś coś ciekawego w oparciu o tę
platformę, podziel się tym z nami za pośrednictwem serwisu Twitter
(https://twitter.com/bwawwp) lub witryny internetowej poświęconej tej
książce (https://bwawwp.com/).

[1] W przypadku wtyczki Paid Memberships Pro nastąpiło to wkrótce po
wydaniu edytora bloków.

O autorach

Brian Messenlehner rozpoczął karierę programisty podczas służby w
Korpusie Piechoty Morskiej Stanów Zjednoczonych w 2000 roku. Jest
współzałożycielem AlphaWeb.com, AppPresser.com i SchoolPresser.com —
firm internetowych specjalizujących się w programowaniu aplikacji
mobilnych i opartych na WordPressie. Brian profesjonalnie zajmuje się
WordPressem już od 2008 roku. Tworzył niestandardowe rozwiązania
internetowe i mobilne dla wielu klientów; są wśród nich: magazyn „The
Time”, NBC, Microsoft, Discovery Channel, Constant Contact, Uber,
Campbell’s Soup, HEB, Starbucks, YMCA, Newark New Jersey Public Schools
oraz National Park Services. Można się z nim skontaktować za
pośrednictwem serwisu Twitter (https://twitter.com/bmess).

Jason Coleman jest szefem Stranger Studios i głównym programistą Paid
Memberships Pro — platformy obsługi członkostwa w WordPressie. Od ponad
pięciu lat zajmuje się tworzeniem aplikacji PHP opartych na WordPressie.
Jason pomaga klientom zarabiać pieniądze za pomocą wtyczki Paid
Memberships Pro poprzez otwieranie nowych firm i rozwijanie już
istniejących. Można się z nim skontaktować poprzez oficjalną witrynę
internetową (https://therealjasoncoleman.com/) oraz za pośrednictwem
serwisu Twitter (https://twitter.com/jason_coleman).

Kolofon

Zwierzę znajdujące się na okładce książki to legwan zielony (Iguana
iguana). Zamieszkuje Ameryki Środkową i Południową oraz Wyspy
Karaibskie, a zasięg jego występowania na lądzie rozciąga się od Meksyku
aż po południową Brazylię. Kolejne populacje zamieszkują południową
Florydę, Hawaje i dolinę rzeki Rio Grande. Gdy Hiszpanie dotarli do
archipelagu Bahamy w 1492 roku, pierwsza wyspa, na którą zeszli, znana
była mieszkańcom Taino jako Guanahani, „wyspa iguana”, a miejscowa nazwa
tych zwierząt została przyjęta przez język hiszpański jako iguana.

Legwany to duże jaszczurki dorastające zwykle do 1,5 metra długości (od
głowy do ogona) i ważące ponad 20 kilogramów. Samice kopią głębokie
dziury, w których składają około 40 jaj. Następnie pozostawiają je aż do
wyklucia młodych jaszczurek, które od urodzenia są samodzielne. Legwany
odżywiają się owocami i różnego rodzaju substancjami roślinnymi. Pomimo
wspólnej nazwy, legwan zielony, osobniki tego gatunku mogą mieć odmienne
kolory w zależności od miejsca pochodzenia. W południowej części zasięgu
legwany mają niebieskawy odcień z jasnoniebieskimi plamkami. Na wyspach,
takich jak Aruba i Grenada, ich ubarwienie może być lawendowe lub
czarne. Osobniki z zachodniego wybrzeża Kostaryki są czerwone, a legwany
meksykańskie mogą być jasnopomarańczowe.

Legwany zielone wspaniale wspinają się po drzewach i są odporne na
upadki — mogą spaść z naprawdę dużej wysokości, nawet z 15 metrów, nie
doznając obrażeń. Pazurami i mocnymi tylnymi kończynami bezpiecznie
chwytają gałęzie i wykonują długie skoki z drzewa na drzewo. Oprócz
tego, że świetnie czują się na lądzie, są również znakomitymi pływakami.
Używają silnego ogona do napędzania i sprawnego poruszania się w wodzie.
Służy on również do obrony przed drapieżnikami i do obezwładniania
rywala. Szczególną cechą ogona legwanów (charakterystyczną również dla
innych jaszczurek) jest zdolność do odrastania. Zjawisko to nosi nazwę
autotomii: w chwili zagrożenia zraniona lub zaatakowana przez
drapieżnika jaszczurka odrzuca ogon, który oddziela się od reszty ciała.
Z czasem w miejscu starego ogona odrasta nowy. Odrzucona część, wciąż
poruszana impulsami elektrycznymi, przykuwa uwagę atakującego
drapieżnika i tym samym daje jaszczurce szansę na ucieczkę.

Ze względu na swój intrygujący wygląd i dość łagodną naturę legwany
zielone są często zwierzętami domowymi. Wymagają jednak szczególnie
troskliwej opieki i, co niestety zdarza się dość często, są porzucane,
gdy okazuje się, że właściciel nie jest w stanie zapewnić im
odpowiednich warunków bytowych. Legwany mają dość specyficzne wymagania
żywieniowe, potrzebują dostępu do świeżej wody, stałej temperatury
wynoszącej około 26 – 27 stopni Celsjusza i codziennego wystawienia na
promieniowanie UVA i UVB. Mogą żyć nawet 20 lat, więc decyzja o
posiadaniu takiego zwierzęcia powinna być naprawdę dobrze przemyślana.

Wiele zwierząt przedstawianych na okładkach wydawnictwa O’Reilly Media
jest zagrożonych wyginięciem. Wszystkie są dla świata niezwykle ważne.

Autorką rysunku legwana na okładce jest Karen Montgomery, która
stworzyła go na podstawie czarno-białej ryciny pochodzącej ze zbiorów
Dover.

[Okładka]

[Okładka]

Spis treści

Opinie o książce WordPress. Tworzenie aplikacji internetowych. Wydanie
II

Przedmowa

Wprowadzenie

Dla kogo jest przeznaczona ta książka

Dla kogo nie jest to odpowiednia książka

Co znajdziesz w książce

Fragmenty kodu

Konwencje zastosowane w książce

Użycie przykładowych kodów

Podziękowania

Rozdział 1. Tworzenie aplikacji internetowych w WordPressie

Czym jest witryna internetowa?

Czym jest aplikacja?

Czym jest aplikacja internetowa?

Funkcje aplikacji internetowej

Aplikacje mobilne

Progresywne aplikacje internetowe

Dlaczego WordPress?

Jesteś już użytkownikiem WordPressa

Zarządzanie treścią w WordPressie jest łatwe

Łatwe i bezpieczne zarządzanie użytkownikami w WordPressie

Wtyczki

Elastyczność ma duże znaczenie

Częste uaktualnienia zabezpieczeń

Koszt

Odpowiedź na często pojawiającą się krytykę wybranych aspektów
WordPressa

WordPress jest przeznaczony tylko do tworzenia blogów

WordPress jest przeznaczony tylko dla stron z treściami

WordPress się nie skaluje

WordPress nie zapewnia bezpieczeństwa

Wtyczki WordPressa są beznadziejne

Kiedy nie używać WordPressa?

Planujesz licencjonować lub sprzedawać technologię witryny internetowej

Inna platforma szybciej doprowadzi Cię do celu

Elastyczność jest bez znaczenia

Aplikacja musi działać w czasie rzeczywistym

WordPress jako framework aplikacji

WordPress kontra frameworki MVC

Modele = wtyczki

Widoki = motywy

Kontrolery = procedury wczytujące szablony

Anatomia aplikacji internetowej WordPressa

Czym jest SchoolPress?

SchoolPress działa w sieci zawierającej wiele witryn WordPressa

Model biznesowy SchoolPressa

Poziomy członkostwa i role użytkowników

Klasy są grupami BuddyPress

Zadanie to przykład CPT

Rozwiązania zadań są podtypami CPT zadań

Semestry to taksonomie dla CPT klasy

Wydział to taksonomia dla CPT klasy

Aplikacja SchoolPress ma jedną główną niestandardową wtyczkę

Aplikacja SchoolPress używa kilku innych niestandardowych wtyczek

Aplikacja SchoolPress używa motywu Memberlite

Rozdział 2. Podstawy WordPressa

Struktura katalogu WordPressa

Katalog główny

/wp-admin

/wp-includes

/wp-content

/wp-content/plugins

/wp-content/themes

/wp-content/uploads

/wp-content/mu-plugins

Struktura bazy danych WordPressa

wp_options

Funkcje zdefiniowane w /wp-includes/option.php

add_option( string $option, mixed $value = '', string $deprecated = '',
string|bool $autoload = 'yes' )

update_option( $option, $newvalue )

get_option( $option, $default = false )

delete_option( $option )

wp_users

Funkcje zdefiniowane w plikach /wp-includes/pluggable.php i
/wp-includes/user.php

wp_insert_user( $userdata )

wp_create_user( $username, $password, $email )

wp_update_user( $userdata )

get_user_by( $field, $value )

get_userdata( $userid )

wp_delete_user( $id, $reassign = 'brak wartości' )

wp_usermeta

get_user_meta( $user_id, $key = '', $single = false )

update_user_meta( $user_id, $meta_key, $meta_value, $prev_value = '' )

add_user_meta( $user_id, $meta_key, $meta_value, $unique = false )

delete_user_meta( $user_id, $meta_key, $meta_value = '' )

wp_posts

Funkcje zdefiniowane w /wp-includes/post.php

wp_insert_post( $postarr, $wp_error = false )

wp_update_post( $postarr = array(), $wp_error = false )

get_post( $post = null, $output = OBJECT, $filter = 'raw' )

get_posts( $args = null )

wp_delete_post( $postid = 0, $force_delete = false )

wp_postmeta

Funkcje zdefiniowane w /wp-includes/post.php

get_post_meta( $post_id, $key = '', $single = false )

update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' )

add_post_meta( $post_id, $meta_key, $meta_value, $unique = false )

delete_post_meta( $post_id, $meta_key, $meta_value = '' )

wp_comments

Funkcje zdefiniowane w /wp-includes/comment.php

get_comment( $comment, $output = OBJECT )

get_comments( $args = '' )

wp_insert_comment( $commentdata )

wp_update_comment( $commentarr )

wp_delete_comment( $comment_id, $force_delete = false )

wp_commentsmeta

Funkcje zdefiniowane w /wp-includes/comment.php

get_comment_meta( $comment_id, $key = '', $single = false )

add_comment_meta( $comment_id, $meta_key, $meta_value, $unique = false )

update_comment_meta( $comment_id, $meta_key, $meta_value, $prev_value =
'' )

delete_comment_meta( $comment_id, $meta_key, $meta_value = '' )

wp_terms

Funkcje zdefiniowane w /wp-includes/taxonomy.php

get_terms( $taxonomies, $args = '' )

get_term( $term, $taxonomy, $output = OBJECT, $filter = 'raw' )

wp_insert_term( $term, $taxonomy, $args = array() )

wp_update_term( $term_id, $taxonomy, $args = array() )

wp_delete_term( $term, $taxonomy, $args = array() )

wp_termmeta

get_term_meta( $term_id, $key = '', $single = false )

update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' )

add_term_meta( $term_id, $meta_key, $meta_value, $unique = false )

delete_term_meta( $term_id, $meta_key, $meta_value = '' )

wp_term_taxonomy

Funkcje zdefiniowane w /wp-includes/taxonomy.php

get_taxonomies( $args = array(), $output = 'names', $operator = 'and' )

get_taxonomy( $taxonomy )

register_taxonomy( $taxonomy, $object_type, $args = array() )

wp_term_relationships

get_object_taxonomies( $object, $output = 'names' )

wp_get_object_terms( $object_ids, $taxonomies, $args = array() )

wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false )

Zaczepy — akcje i filtry

Akcje

Filtry

Środowiska programistyczne i hostingowe

Praca lokalna

Wybór hostingu

Środowiska robocze i produkcyjne

Rozszerzanie WordPressa

Rozdział 3. Stosowanie wtyczek WordPressa

Licencja GPLv2

Instalowanie wtyczek WordPressa

Utworzenie własnej wtyczki

Struktura plików we wtyczce

/adminpages/

/classes/

/css/

/js/

/images/

/includes/

/includes/lib/

/pages/

/services/

/scheduled/

/schoolpress.php

Dodatki dla istniejących wtyczek

Przypadki użycia i przykłady

Pętla WordPressa

Zmienne globalne WordPressa

$wpdb

Używanie niestandardowych tabel bazy danych

Wykonywanie zapytań

Znaki sterujące w zapytaniu bazy danych

Zapytania SELECT wraz z $wpdb

Wtyczki bezpłatne

Admin Columns

Advanced Custom Fields

BadgeOS

Posts 2 Posts

Members

W3 Total Cache

Yoast SEO

Wtyczki premium

Gravity Forms

BackupBuddy

WP All Import

Wtyczki społecznościowe

BuddyPress

Tabele bazy danych

Panel Komponenty

Panel Strony

Panel Opcje

Sekcja Pola profilu

Wtyczki BuddyPressa

Rozdział 4. Motywy

Motyw kontra wtyczka

Gdzie umieścić kod podczas tworzenia aplikacji?

Kiedy opracować wtyczkę?

Gdzie umieszczać kod podczas tworzenia motywu?

Hierarchia szablonu

Szablony strony

Przykładowy szablon strony

Stosowanie zaczepów do kopiowania szablonów

Kiedy należy używać szablonu motywu?

Funkcje WordPressa powiązane z motywem

Stosowanie funkcji locate_template() w motywach

Plik style.css

Wersjonowanie plików CSS motywu

Plik functions.php

Motywy i niestandardowe typy postów

Popularne frameworki motywów

Frameworki motywów WordPressa

_s

Memberlite

Genesis

Frameworki motywów przeznaczone nie tylko dla WordPressa

Tworzenie motywu potomnego dla Memberlite

Wykorzystanie frameworka Bootstrap w motywie aplikacji

Menu

Menu nawigacyjne

Menu dynamiczne

Responsywny układ strony

Wykrywanie urządzenia i ekranu za pomocą CSS

Wykrywanie urządzeń i funkcji za pomocą kodu JavaScript

Określanie wielkości okna i ekranu za pomocą kodu JavaScript i jQuery

Wykrywanie funkcji w JavaScripcie

Wykrywanie urządzenia w PHP

Wykrywanie funkcjonalności w WordPressie

Wykrywanie funkcjonalności za pomocą wywołania get_browser() w PHP

Słowo końcowe na temat wykrywania przeglądarki WWW

Rozdział 5. Niestandardowe typy postów, metadane postów i taksonomie

Domyślne i niestandardowe typy postów

Strona

Post

Załącznik

Wersja

Element menu nawigacyjnego

Niestandardowe style CSS

Changeset

Bufor oEmbed

Żądania użytkowników

Bloki kodu wielokrotnego użycia

Definiowanie i rejestrowanie niestandardowych typów postów

register_post_type( $post_type, $args );

Co to jest taksonomia i jak należy z niej korzystać?

Taksonomie kontra metadane posta

Tworzenie niestandardowych taksonomii

register_taxonomy( $taxonomy, $object_type, $args )

register_taxonomy_for_object_type( $taxonomy, $object_type )

Stosowanie niestandardowych typów postów i taksonomii we własnych
motywach i wtyczkach

Szablony stron archiwum i pojedynczego posta w motywie

Stare dobre komponenty WP_Query i get_posts()

Metadane w niestandardowych typach postów

add_meta_box( $id, $title, $callback, $screen, $context, $priority,
$callback_args )

Stosowanie elementów obsługi metadanych w edytorze bloków

Czy metadane muszą być definiowane dla każdego posta tego typu?

Czy kontrolki metadanych zmieszczą się w pasku bocznym?

Czy metadane muszą być umieszczone w treści posta?

Czy użytkownicy mogą dodawać do posta kopie metadanych?

Opakowania klas dla niestandardowych typów postów

Rozszerzanie klasy WP_Post kontra opakowanie obiektu tej klasy

Po co używać klasy opakowania?

CTP i taksonomie będą w jednym miejscu

Definiowanie kodu w klasie opakowania

Klasa opakowania jest czytelniejsza

Rozdział 6. Użytkownicy, role i uprawnienia

Pobieranie danych użytkownika

Dodawanie, uaktualnianie i usuwanie użytkowników

Zaczepy i filtry

Czym są role i uprawnienia?

Sprawdzanie ról i uprawnień użytkownika

Tworzenie niestandardowych ról i uprawnień

Rozszerzanie klasy WP_User

Dodanie właściwości rejestracji i profilu

Dostosowanie do własnych potrzeb tabeli użytkowników w panelu głównym

Wtyczki

Theme My Login

Ukrycie paska administracyjnego przed użytkownikami niebędącymi
administratorami

Paid Memberships Pro

Paid Memberships Pro Register Helper

Members

WP User Fields

Rozdział 7. Praca z API WordPressa, obiektami i funkcjami pomocniczymi

API skrótów

Atrybuty skrótu

Skróty zagnieżdżone

Usunięcie skrótu

Inne użyteczne funkcje powiązane ze skrótami

API widżetów

Zanim zaczniesz dodawać własny widżet

Dodawanie widżetu

Definiowanie obszaru widżetu

Osadzanie widżetu poza dynamicznym paskiem bocznym

API widżetów w panelu głównym WordPressa

Usunięcie widżetu panelu głównego

Dodawanie własnego widżetu panelu głównego

API ustawień

Czy naprawdę potrzebna jest strona ustawień?

Czy zamiast ustawień można użyć zaczepu lub filtru?

Stosowanie standardów podczas dodawania ustawień

Ignorowanie standardów podczas dodawania ustawień

API przepisywania adresów URL

Dodawanie reguły przepisywania adresu URL

Usuwanie reguły przepisywania adresu URL

Inne funkcje przepisywania adresów URL

WP-Cron

Definiowanie niestandardowego odstępu czasu

Tworzenie harmonogramu dla pojedynczych zdarzeń

Wywoływanie zadań mechanizmu cron z serwera

Stosowanie zadań mechanizmu cron jedynie po stronie serwera

WP Mail

Wysyłanie ładniejszych wiadomości e-mail za pomocą WordPressa

API nagłówka pliku

Dodawanie nagłówków plików do własnych plików

Dodawanie nowych nagłówków do wtyczek i motywów

API Heartbeat

Rozdział 8. Bezpieczny WordPress

Dlaczego bezpieczeństwo jest ważne?

Podstawy zapewnienia bezpieczeństwa

Regularnie uaktualniaj oprogramowanie

Nie używaj nazwy użytkownika admin

Używaj silnych haseł

Przykłady beznadziejnych haseł

Przykłady dobrych haseł

Zabezpieczenie WordPressa

Nie zezwalaj administratorowi na edycję wtyczek lub motywów

Zmień domyślny prefiks tabel bazy danych

Przenieś wp-config.php

Ukryj komunikaty błędów logowania

Ukryj numer wersji WordPressa

Uniemożliw logowanie poprzez stronę wp-login.php

Dodaj niestandardowe reguły .htaccess w celu zabezpieczenia strony
wp-admin

Certyfikaty SSL i HTTPS

Instalacja certyfikatu SSL w serwerze

Użycie jednego katalogu dla ruchu sieciowego HTTPS i HTTP

Stosowanie szyfrowania SSL na stronach logowania i administracyjnych

Debugowanie problemów związanych z HTTPS

Zapobieganie błędom dzięki „opcji nuklearnej”

Twórz kopię zapasową całości!

Skanuj, skanuj i skanuj!

Użyteczne wtyczki zapewnienia bezpieczeństwa

Wtyczki związane z blokowaniem spamu

Akismet

Bad Behavior

Wtyczki związane z tworzeniem kopii zapasowej

BackupBuddy

VaultPress

Wtyczki związane z zaporą sieciową i skanowaniem

WordFence

All In One WP Security & Firewall

Exploit Scanner

Wtyczki związane z logowaniem i hasłami

Limit Login Attempts

AskApache Password Protect

Tworzenie bezpiecznego kodu

Sprawdzenie uprawnień użytkownika

user_can( $user, $capability )

current_user_can( $capability )

current_user_can_for_blog( $blog_id, $capability )

Niestandardowe zapytania SQL

Weryfikacja danych, ich oczyszczanie i stosowanie znaków sterujących

esc_url( $url, $protocols = null, $_context = 'display' )

esc_url_raw( $url, $protocols = null )

esc_html( $text )

esc_js( $text )

esc_attr( $text )

esc_textarea( $text )

sanitize_option( $option, $value )

sanitize_text_field( $str )

sanitize_user( $username, $strict = false )

sanitize_title( $title, $fallback_title = '' )

sanitize_email( $email )

sanitize_file_name( $filename )

wp_kses( $string, $allowed_html, $allowed_protocols = array () )

wp_kses_post( $data )

Jednokrotnie używana liczba

wp_create_nonce( $action = -1 )

wp_verify_nonce( $nonce, $action = -1 )

check_admin_referer( $action = -1, $query_arg = '_wpnonce’ )

wp_nonce_url( $actionurl, $action = -1 )

wp_nonce_field( $action = -1, $name = ''_wpnonce'', $referer = true ,
$echo = true )

check_ajax_referer( $action = -1, $query_arg = false, $die = true )

Rozdział 9. Frameworki JavaScript

Co to jest ECMAScript

Co to jest ES6

Co to jest ES9

Co to jest ESNext

Co to jest AJAX

Co to jest JSON

jQuery i WordPress

Dodawanie innych bibliotek JavaScript

Gdzie umieszczać niestandardowy kod JavaScript

Wywołania AJAX za pomocą WordPressa i jQuery

Zarządzanie wieloma żądaniami AJAX

API Heartbeat

Inicjalizacja

Wykonanie kodu JavaScript po stronie klienta

Wykonywanie kodu PHP po stronie serwera

Inicjalizacja

Wykonanie kodu JavaScript po stronie klienta

Wykonywanie kodu PHP po stronie serwera

Ograniczenia WordPressa związane z przetwarzaniem asynchronicznym

Frameworki JavaScript

Backbone.js

React

Rozdział 10. API REST WordPressa

Czym jest API REST?

API

REST

JSON

HTTP

Żądanie

Nagłówki

Treść

Dlaczego warto używać API REST WordPressa

Używanie wersji drugiej API REST WordPressa

Odkrycie

Uwierzytelnianie

Uwierzytelnianie na podstawie cookie

Uwierzytelnianie proste

Token JWT

Uwierzytelnianie OAuth

Trasy i punkty końcowe

Czym jest trasa?

Czym jest punkt końcowy?

Czym jest przestrzeń nazw

Żądania

Odpowiedź

Dodawanie własnych tras i punktów końcowych

register_rest_route( $namespace, $route, $args, $override );

Konfiguracja wtyczki Single Sign-On w WordPressie

Dodanie trasy /wp-sso/v1/check

Stosowanie uwierzytelniania prostego w omawianej wtyczce

Używanie zdefiniowanego punktu końcowego do sprawdzenia danych
uwierzytelniających użytkownika

Popularne wtyczki używające API REST WordPressa

WooCommerce

Przykład — niewyświetlanie banerów zarejestrowanym klientom

BuddyPress

Przykład — podkreślenie aktywności określonych użytkowników

Paid Memberships Pro

Przykład — sprawdzenie, czy dany adres należy do klienta

Rozdział 11. Projekt Gutenberg, bloki i niestandardowe typy postów

Edytor WordPressa

Wtyczka Classic Editor

Używanie bloków podczas tworzenia treści i projektu

Używanie bloków do tworzenia funkcjonalności

Tworzenie własnego bloku

Przykład minimalnego bloku

Używanie bloków niestandardowych do tworzenia aplikacji

Włączenie edytora bloków w niestandardowych typach postów

Kategorie bloków

Bloki Homework

Ograniczenie bloków do określonych CPT

Ograniczenie CPT do określonych bloków

Szablon bloku

Zapisywanie danych bloku w metadanych posta

Podpowiedzi

Włączenie WP_SCRIPT_DEBUG

Używanie wywołania filemtime() dla wersji skryptu

Więcej podpowiedzi

Poznaj dokładnie JavaScript, Node.js i React

Rozdział 12. Sieć witryn internetowych WordPressa

Dlaczego sieć witryn internetowych

Dlaczego nie należy korzystać z sieci witryn

Alternatywy dla sieci witryn

Wielu autorów lub kategorii w tej samej witrynie WordPressa

Niestandardowe typy postów

Oddzielne witryny internetowe

Używanie usługi konserwacji WordPressa

Wielodostępność

Przygotowanie sieci witryn

Zarządzanie siecią witryn WordPressa

Panel główny

Witryny internetowe

Użytkownicy

Motywy

Wtyczki

Ustawienia

Uaktualnienia

Struktura bazy danych sieci witryn

Tabele o zasięgu sieci

wp_site

wp_sitemeta

wp_blogs

wp_blog_versions

wp_signups

wp_registration_log

Tabele poszczególnych witryn

Współdzielone tabele witryny internetowej

Mapowanie domeny

Wtyczki użyteczne w sieci witryn internetowych

Gravity Forms User Registration Add-On

Dodatek Member Network Sites dla wtyczki Paid Memberships Pro

Multisite Global Media

Multisite Plugin Manager

Multisite Robots.txt Manager

NS Cloner — Site Copier

WP Multi Network

Podstawowa funkcjonalność sieci witryn WordPressa

$blog_id

is_multisite()

get_current_blog_id()

switch_to_blog( $new_blog )

restore_current_blog()

get_blog_details( $fields = null, $get_all = true )

update_blog_details( $blog_id, $details = array() )

get_blog_status( $id, $pref )

update_blog_status( $blog_id, $pref, $value )

get_blog_option( $id, $option, $default = false )

update_blog_option( $id, $option, $value )

delete_blog_option( $id, $option )

get_blog_post( $blog_id, $post_id )

add_user_to_blog( $blog_id, $user_id, $role )

wpmu_delete_user( $user_id )

create_empty_blog( $domain, $path, $weblog_title, $site_id = 1 )

Funkcje niewymienione w tym podrozdziale

Rozdział 13. Lokalizacja aplikacji WordPressa

Czy w ogóle zachodzi potrzeba lokalizacji aplikacji

Jak lokalizacja jest przeprowadzana w WordPressie

Definiowanie lokalizacji w WordPressie

Domeny tekstu

Definiowanie domeny tekstu

Przygotowanie ciągów tekstowych za pomocą funkcji tłumaczeń

__( $text, $domain = "default" )

_e( $text, $domain = "default" )

_x( $text, $context, $domain = "default" )

_ex( $title, $context, $domain = "default" )

Jednoczesne tłumaczenie tekstu i stosowanie znaków sterujących

Tworzenie i wczytywanie plików tłumaczeń

Struktura pliku do lokalizacji

Generowanie pliku .pot

Utworzenie pliku .po

Utworzenie pliku .mo

GlotPress

Używanie narzędzia GlotPress dla wtyczek i motywów umieszczanych w
repozytorium WordPress.org

Utworzenie własnego serwera GlotPress

Rozdział 14. Optymalizacja i skalowanie WordPressa

Terminologia

Źródło kontra krawędź

Testowanie

Co będzie testowane

Pasek debugowania w Chrome

Narzędzie Stan witryny WordPressa

Apache Bench

Instalacja Apache Bench

Uruchomienie Apache Bench

Testowanie za pomocą narzędzia Apache Bench

Użycie gnuplot do graficznego przedstawienia wyników wygenerowanych
przez Apache Bench

Siege

W3 Total Cache

Ustawienia Page Cache

Minimalizacja

Buforowanie bazy danych

Buforowanie obiektów

Sieć CDN

Kompresja GZIP

Hosting

Hosting przygotowany z myślą o WordPressie

Utworzenie własnego serwera

Konfiguracja serwera Apache

Konfiguracja serwera Nginx

Nginx przed Apache

Optymalizacja MySQL

Pliki advanced-cache.php i object-cache.php

APC

Memcached

Redis

Varnish

Batcache

Buforowanie selektywne

API Transient

Elementy tymczasowe dla wielu witryn internetowych

Używanie JavaScriptu do poprawy wydajności działania

Tabele niestandardowe

Pominięcie WordPressa

Rozdział 15. E-commerce

Wybór wtyczki

WooCommerce

Wtyczka i rozszerzenia WooCommerce

Dostosowywanie WooCommerce za pomocą zaczepów

Paid Memberships Pro

Easy Digital Downloads

Przykładowe fragmenty kodów wykorzystujących wtyczkę Easy Digital
Downloads

Bramki płatności

Konto sprzedawcy

Konfigurowanie modelu Saas przy użyciu wtyczki Paid Memberships Pro

Model SaaS

Etap 0. — ustalenie sposobu pobierania opłaty za korzystanie z aplikacji

Etap 1. — instalowanie i aktywowanie wtyczki Paid Memberships Pro

Etap 2. — ustalenie poziomu członkostwa

Etap 3. — konfiguracja stron

Etap 4. — wybór ustawień płatności

Etap 5. — wybór ustawień wiadomości e-mail

Etap 6. — wybór ustawień zaawansowanych

Etap 7. — uniemożliwianie dostępu do stron

Uniemożliwianie dostępu do konkretnej strony

Blokowanie dostępu do strony na podstawie adresu URL

Ograniczanie dostępu do części strony na podstawie skrótu

Ograniczanie dostępu do fragmentu strony za pomocą kodu PHP przy użyciu
funkcji pmpro_hasMembershipLevel()

Etap 8. — dostosowanie wtyczki Paid Memberships Pro do własnych potrzeb

Ograniczanie dostępu do strony głównej użytkownikom, którzy nie są
członkami

Ograniczanie dostępu do plików

Zmiana roli użytkownika na podstawie poziomu członkostwa

Formularz adresu

Rozdział 16. Aplikacje mobilne na bazie WordPressa

Przypadki użycia aplikacji mobilnych

Natywne i hybrydowe aplikacje mobilne

Co to jest natywna aplikacja mobilna

Co to jest hybrydowa aplikacja mobilna

Dlaczego lepiej wybrać aplikację hybrydową zamiast natywnej

Cordova

PhoneGap

Instalowanie frameworka Cordova

Cordova i Android

Cordova i iOS

Wtyczki Cordova

Framework Ionic

Opakowanie aplikacji

AppPresser

Instalowanie i konfigurowanie w WordPressie

App Builder

Kompilowanie i testowanie aplikacji

Łącza między stronami aplikacji

Wtyczka AppCamera

Wtyczki WooCommerce

LearnDash i AppLMS

AppPush

Rozdział 17. Biblioteki PHP, integracje usług sieciowych, migracje
platform

Biblioteki PHP

Generowanie i przetwarzanie obrazów

GD

Imagick

Zebra_Image

Imagine

Dynamic Dummy Image Generator

Snappy

Generowanie dokumentu PDF

Snappy

FPDF

Inne biblioteki PHP do generowania dokumentów PDF

Geolokalizacja i geotargetowanie

MaxMind GeoIP

Geocoder PHP

Hosting z usługami geolokalizacji

Kompresja i archiwizowanie plików

Kompresja poszczególnych plików na postać archiwum

Kompresja wielu plików

Wyodrębnianie plików z archiwum

Inne biblioteki PHP do kompresji

Narzędzia programistyczne

PHPUnit

phpDocumentor

Faker

Goutte a PHP-based website scraper

Whoops, czyli przyjazne użytkownikowi komunikaty błędów PHP

Zewnętrzne API i usługi sieciowe

Elasticsearch

ElasticPress firmy 10up

Google Vision

Mapy Google

Directions

Distance Matrix

Elevation

Geocoding

Street View

Wtyczki Map Google dla WordPressa

Tłumacz Google

Twilio

Inne popularne interfejsy API

Migracje

Migracja hosta

Dostępne wtyczki migracji

Narzędzie migracji witryny internetowej WP Engine

Migracja platformy

Zrozumienie docelowej struktury danych

Zrozumienie struktury danych źródłowych

Dane pochodzące z bazy danych

Dane pochodzące z plików

Dane pochodzące z zewnętrznego API

Ekstrakcja danych ze stron internetowych

Utworzenie przewodnika mapowania danych

Rozdział 18. Przyszłość

Jak to było wcześniej

API REST

Wtyczki WordPressa będą bardziej skoncentrowane na API

Headless WordPress

GraphQL

Projekt Gutenberg

Interfejs administracyjny zostanie przeniesiony do rozwiązania opartego
na React i Gutenberg

Gutenberg zapewni obsługę edycji we frontendzie WordPressa

Szablon bloku zastąpi motyw

Bloki zastąpią wtyczki

Udział WordPressa w rynku będzie się zmieniał

WordPress stanie się znacznie popularniejszą platformą do tworzenia
aplikacji mobilnych

WordPress wciąż będzie użyteczny podczas tworzenia różnych aplikacji
internetowych

O autorach

Kolofon
