[]

[]

Ten ebook jest chroniony znakiem wodnym

Kopia pliku przygotowana specjalnie dla:

Pawel Domanski
pawel@dexterteam.eu

Ebookpoint.pl

Brad Williams, Ozh Richard, Justin Tadlock

Wtyczki do WordPressa

Programowanie dla profesjonalistów

Tytuł oryginału: Professional WordPress Plugin Development

Tłumaczenie: Robert Górczyński

ISBN: ePub: 978-83-246-5044-6, Mobi: 978-83-246-5045-3

© 2011 by Wiley Publishing, Inc., Indianapolis, Indiana

All Rights Reserved. Authorized translation from the English language
edition published by John Wiley & Sons Limited. Responsibility for the
accuracy of the translation rests solely with Helion S. A. and is
not the responsibility of John Wiley & Sons Limited. No part of this
book may be reproduced in any form without the written permission of the
original copyright holder, John Wiley & Sons Limited.

Wiley, the Wiley logo, Wrox, the Wrox logo, Wrox Programmer to
Programmer, and related trade dress are trademarks or registered
trademarks of John Wiley & Sons, Inc. and/or its affiliates, in the
United States and other countries, and may not be used without written
permission. WordPress is a registered trademark of Automattic, Inc. All
other trademarks are the property of their respective owners.

Wiley Publishing, Inc. is not associated with any product or vendor
mentioned in the book.

Translation copyright © 2012 by Wydawnictwo Helion.

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.

Autor oraz Wydawnictwo HELION 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. Autor oraz
Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za
ewentualne szkody wynikłe z wykorzystania informacji zawartych
w książce.

Wydawnictwo HELION

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)

Pliki z przykładami omawianymi w książce można znaleźć pod adresem:
ftp://ftp.helion.pl/przyklady/wtywor.zip

Drogi Czytelniku!

Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres

http://helion.pl/user/opinie/wtywor_ebook

Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję.

Konwersja do epub Agencja A3M

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

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

Dla mojego ojca Roberta "Basket Boba" Williamsa za inspirację,
która pozwoliła mi stać się tym człowiekiem, jakim jestem dzisiaj.

— Brad Williams

Dla mojej żony Ariane za wsparcie okazywane mi,
gdy uchylałem się od obowiązków domowych,
a także dla moich synów Oskara i Cyrusa,
którzy w ciągu dziesięciu lat staną się hakerami na platformie
WordPress.

— Ozh Richard

Dla mojej rodziny, która pozwoliła mi na poznanie internetu
i uczynienie z niego ścieżki kariery zawodowej,
a także dla społeczności WordPress za zaproszenie mnie.

— Justin Tadlock

Podziękowania

April, miłości mojego życia! Dziękuję Ci za nieustające wsparcie,
przyjaźń oraz pogodzenie się z moim stylem życia. Dziękuję moim
niesamowitym siostrzenicom Indianie Brooke i Austin Margaret. Dziękuję
Carol Long za wiarę w powodzenie tej książki i pomoc w jej powstaniu.
Książka nie powstałaby bez pomocy Ozha i Justina, dwóch wspaniałych
współautorów dysponujących ogromną wiedzą o platformie WordPress.
Dziękuję całej społeczności WordPress za okazane wsparcie, przyjaźń,
motywację i pomoc. Dziękuję fizzypop za konferencję WordCamp. I na końcu
dziękuję mojemu śmiesznemu zoo: Lecterowi, Clarice i Squeaks the Cat
(znanej także jako Kitty Galore). Wasze uśmiechnięte pyski i faliste
grzbiety zawsze wywołują uśmiech na mojej twarzy.

— Brad Williams

W społeczności WordPress minęło sporo czasu od chwili, gdy około roku
2004 zacząłem szczegółowo analizować kilka wtyczek, aby poznać sposób
ich działania. Nie jestem w stanie w pełni wyrazić, jak bardzo cenię
wszystkich programistów, którzy utworzyli kod pozwalający mi na poznanie
wnętrza platformy WordPress. Podziękowania za nieocenione oddanie
składam wszystkim członkom społeczności WordPress, którzy wprawdzie nie
tworzą kodu, ale rozwijają kreatywność i pchają społeczność do przodu.
Dziękuję Bradowi za szaloną propozycję napisania książki o wtyczkach dla
platformy WordPress — mam nadzieję, że pewnego dnia przekroczę ocean,
aby wypić z Tobą kilka piw. Podziękowania składam również muzykom —
Ronniemu Jamesowi Dio, Tomowi Arayi, Bruce'owi Dickinsonowi, Blaze'owi
Bayleyowi, Lemmy'emu Kilmisterowi, Dave'owi Mustaine'owi, Robowi
Zombiemu, Tilliemu Lindemannowi i Mike'owi Muiriemu — Wasze szlachetne
głosy uspokajały mnie i inspirowały, gdy pracowałem do późna w nocy.

— Ozh Richard

Społeczność platformy WordPress przygarnęła mnie jak zagubionego
dzieciaka, gdy próbowałem zdecydować, co zrobić ze swoim życiem, i
zaoferowała mi możliwości, o jakich nigdy nie śniłem. Proste "dziękuję"
tutaj nie wystarcza. Podziękowania składam użytkownikom opracowanych
przeze mnie wtyczek i motywów, którzy nieustannie inspirują mnie,
pozwalają utrzymać w dobrej formie, dostarczają nieoceniony odzew i
pozostają lojalni. Bradowi dziękuję za przypadkową wiadomość e-mail i
informację o pisaniu książki o wtyczkach dla WordPress. Ozhowi dziękuję
za utworzenie tych wszystkich wspaniałych wtyczek, które poznałem, zanim
sam stałem się programistą. Dziękuję także babci za pozwolenie
opuszczenia wielu obiadów podczas pracy nad tą książką. Mojej rodzinie i
przyjaciołom dziękuję za wsparcie i anielską cierpliwość w czasie
trwających godzinami rozmów (np. szalonych tyrad) dotyczących tworzenia
wtyczek. I najważniejsze: podziękowania składam mojemu ojcu, który
wprawdzie nie ma pojęcia o programowaniu sieciowym, ale nauczył mnie,
jak osiągnąć sukces, i uczy mnie po dziś dzień.

— Justin Tadlock

O autorach

Brad Williams to dyrektor oraz współzałożyciel witryny
WebDevStudios.com, a także współprowadzący podcast SitePoint i
współautor książki Professional WordPress. Brad już od ponad czternastu
lat zajmuje się tworzeniem witryn internetowych, a ostatnie cztery lata
poświęcił na technologie open source, takie jak Word Press. Udziela się
jako wykładowca na wielu konferencjach WordCamp odbywających się w USA,
a ponadto organizuje spotkania WordPress Meetup i WordCamp Philly w New
Jersey oraz Filadelfii. W roku 2010 założył firmę Pluginize.com
zajmującą się tworzeniem własnych wtyczek dla platformy WordPress.

Ozh Richard to programista sieciowy, który korzysta z platformy
WordPress od wersji 1.0.1; w maju 2004 roku opublikował pierwszą witrynę
internetową bazującą na WordPress, a trzy miesiące później wydał
pierwszą wtyczkę dla WordPress. Od tamtej chwili opracował wiele
popularnych wtyczek i wygrał konkurs Annual WordPress Plugin
Competition, którego stał się oficjalnym jurorem. Kiedy nie tworzy
wtyczek WordPress lub samouczków, angażuje się w inne projekty open
source, np. YOURLS (skracanie adresów URL), lub gra w Quake'a. Jego
strona domowa to http://ozh.org/.

Justin Tadlock to programista sieciowy i projektant, który w roku 2003 —
mając osiemnaście lat — w kilka miesięcy po otrzymaniu pierwszego
komputera utworzył swoją pierwszą stronę internetową. Platformę
WordPress odkrył w roku 2005 i od tamtej chwili angażuje się w ten
projekt. Opracował wiele popularnych wtyczek i motywów WordPress, a
także wypróbował kilka pomysłów biznesowych bazujących na technologiach
open source.

Wstęp

Na początku była prostym systemem obsługi blogów, ale na przestrzeni
ostatnich lat platforma WordPress stała się w pełni wyposażonym i
szeroko używanym systemem zarządzania treścią. Zarówno użytkownikom
indywidualnym, jak i firmom oferuje dostępną na całym świecie i
bezpłatną alternatywę typu open source dla zamkniętych i często bardzo
drogich systemów.

Określenie "w pełni wyposażony" jest jak najbardziej prawdziwe dzięki
możliwości dodawania kolejnych funkcji w postaci wtyczek. Jądro
platformy WordPress jest bardzo proste: niezbędne funkcje użytkownik
dodaje, instalując odpowiednie wtyczki. Samodzielne opracowywanie
wtyczek pozwala użytkownikowi na pokazanie swoich szczególnych
umiejętności w danym zakresie i udzielenie innym użytkownikom pomocy bez
konieczności zajmowania się innymi aspektami WordPress.

Utworzyłem dziesiątki wtyczek, które w sumie były pobrane miliony razy.
To zmieniło moje życie — pozwoliło na zbudowanie firmy, opracowywanie
wtyczek i rozpoczęcie pracy w charakterze konsultanta. Przed Tobą, Drogi
Czytelniku, również otwierają się takie możliwości!

Żałuję, że kiedy pięć lat temu rozpoczynałem tworzenie wtyczek dla
WordPress, traktując to jako hobby, książki tej jeszcze nie było na
rynku. Dzięki niej mógłbym zaoszczędzić niezliczoną ilość godzin
poświęconych na przeglądanie kodu i niepełnej dokumentacji. Praktycznie
zawsze wielokrotnie wykonywałem te same zadania w celu znalezienia
innego rozwiązania lub po prostu łatwiejszego sposobu wykonania danego
zadania.

Kiedy książka ta jeszcze nie istniała, jej autorzy od zawsze byli dla
mnie źródłem użytecznych informacji, gdy pracowałem nad swoimi
wtyczkami. Każdy z nich jest niezależnym ekspertem, natomiast razem
tworzą jeden z najlepszych zespołów, jaki można było zebrać do pracy nad
książką.

Platforma WordPress znacznie ułatwia pracę osobom, które chcą wyrazić
swoje myśli, przekazać dźwięki itd. Ludziom tworzącym kod platforma
WordPress od zawsze pozwalała na wyrażanie siebie właśnie poprzez kod.
To jest naprawdę bardzo proste, praktycznie każdy może opracować wtyczkę
dla WordPress. Korzystając z tej książki, możesz samodzielnie zbudować
wtyczkę i tym samym prawdziwie wyrazić pierwotne motto platformy
WordPress: kod to poezja.

Udanego tworzenia kodu!

Joost De Valk
Yoast.com

Wprowadzenie

Drogi Czytelniku, dziękujemy za zakup tej książki! Prawdopodobnie już
słyszałeś o platformie WordPress, czyli najpopularniejszym obecnie
systemie zarządzania treścią (CMS, ang. Content Management System) i
oprogramowaniu, które służy do prowadzenia bloga. Na bazie platformy
WordPress zbudowano dosłownie miliony witryn internetowych dostępnych w
internecie, łącznie z takimi jak TechCrunch i blog CNN. Bezpłatne
rozwiązanie, technologia typu open source i ogromne możliwości rozbudowy
to najważniejsze czynniki wpływające na tak oszałamiającą popularność
platformy WordPress. Oferujący ogromne możliwości i łatwy w użyciu
system wtyczek sprawia, że użytkownik może dowolnie dostosować platformę
WordPress do swoich wymagań i rozbudować ją, dodając potrzebne funkcje.
Wprawdzie w oficjalnym, dostępnym bezpłatnie repozytorium wtyczek
znajduje się ich ponad dziesięć tysięcy, ale one niekoniecznie muszą
spełniać wymagania użytkownika lub jego klientów. W takiej sytuacji
przyda się ta książka.

W czasie pisania tej książki autorzy (Brad, Ozh i Justin) publicznie
wydali ponad pięćdziesiąt wtyczek, które były pobrane niemal milion
razy. To — oczywiście — nie obejmuje wtyczek prywatnych opracowanych dla
konkretnych klientów. To cenne doświadczenie zostanie wykorzystane w
celu pokazania sposobów tworzenia własnych wtyczek dla WordPress na
podstawie praktycznych przykładów i rzeczywistych sytuacji, które mogą
wystąpić podczas pracy z klientami.

Podstawowym powodem, dla którego chcieliśmy napisać tę książkę, było
utworzenie trwałego zasobu dla programistów wtyczek WordPress. Podczas
tworzenia wtyczek WordPress znalezienie pojedynczego miejsca
zawierającego wiele niezbędnych zasobów może być prawdziwym wyzwaniem.
Wiele dostępnych w internecie przewodników i samouczków to pozycje
przestarzałe, które na dodatek zalecają stosowanie niewłaściwych metod
budowania wtyczek. Książka to jedna z największych kolekcji informacji
dotyczących tworzenia wtyczek i powinna być uznana za lekturę
obowiązkową dla każdego, kto chce od podstaw poznać temat opracowywania
wtyczek dla WordPress.

Dla kogo jest przeznaczona ta książka?

Książka jest przeznaczona dla profesjonalnych programistów sieciowych,
którzy chcą, aby instalacja WordPress działała dokładnie w taki sposób,
jak życzy sobie tego klient. WordPress sprawdził się w charakterze
wyjątkowej platformy służącej do tworzenia dowolnego rodzaju witryny
internetowej, od zawierającej proste strony statyczne po w pełni
wyposażone sieci obsługujące społeczności. Zrozumienie sposobu tworzenia
wtyczek pozwoli na wykorzystanie większości możliwości drzemiących w
WordPress przy jednoczesnym zachowaniu efektywnego, pod względem kosztów
na jednego klienta, podejścia podczas implementacji wymaganych funkcji.

Książka przeznaczona jest także dla wolnych strzelców piszących kod,
którzy chcą zdobyć nowe umiejętności (i tym samym wzbogacić swoje
portfolio), zrozumieć wewnętrzny sposób działania platformy WordPress i
tworzyć rozwiązania na jej bazie. Ponieważ WordPress to
najpopularniejsze oprogramowanie do budowania kodu, a także oferujących
potężne możliwości witryn internetowych, bardzo ważne jest zrozumienie
sposobu jego wewnętrznego działania, co pozwoli na dostosowanie systemu
do własnych potrzeb. Poznanie tajników tworzenia wtyczek może być
bezcennym dodatkiem do CV i wizytówki.

Wreszcie, książka jest przeznaczona dla traktujących programowanie jako
hobby programistów PHP, którzy chcą poznać sposób działania swoich
blogów WordPress, odkryć nieskończone możliwości oferowane przez zwięzły
i elastyczny kod źródłowy oraz dowiedzieć się, jak przeprowadzać
interakcję z przepływem zdarzeń. Piękno rozwiązań open source polega na
tym, że są łatwe do zrozumienia oraz można je bez problemów porzucić.
Książka pomoże w wykonaniu pierwszego kroku do społeczności, która z
radością powita Twoją, Drogi Czytelniku, kreatywność i wkład.

Ujmując rzecz najprościej, książka jest przeznaczona dla każdego, kto
chce w pełni wykorzystać możliwości platformy WordPress, bez względu na
to, czy dla zabawy, czy w celach zarobkowych.

Co jest potrzebne, by dobrze wykorzystać tę książkę?

W książce przyjęto założenie, że masz już działający serwer WWW wraz z
zainstalowaną platformą WordPress. Dla wygody preferowane jest użycie
serwera WWW działającego lokalnie, ponieważ to znacznie ułatwia
modyfikację plików wtyczek podczas lektury książki. Jednak równie dobrze
można wykorzystać serwer WWW działający w internecie.

Fragmenty kodu utworzone w języku PHP to podstawa książki: wskazana jest
umiejętność odczytu i tworzenia prostych skryptów PHP oraz wykorzystania
dokumentacji w celu uzupełnienia wszelkich braków dotyczących używanych
funkcji PHP. Zaawansowane sztuczki w PHP zostały objaśnione w książce,
więc bez obaw — nie musisz być ekspertem z zakresu PHP.

Wymagana jest również podstawowa znajomość języka HTML, co pozwoli na
pełne zrozumienie prezentowanego kodu. Znajomość podstawowych poleceń i
składni MySQL pomoże w zrozumieniu bardziej złożonych zagadnień. Aby
maksymalnie wykorzystać rozdział poświęcony technologiom JavaScript i
AJAX, przyda się umiejętność odczytu kodu JavaScript i jQuery.

Jaki materiał przedstawiono w książce?

W czasie pisania książki dostępna była wersja 3.1 platformy WordPress,
więc książka została przygotowana na jej bazie. Stosowanie najlepszych
praktyk z zakresu tworzenia kodu oraz używanie wbudowanych API platformy
WordPress to podstawa gwarantująca uzyskanie kodu, który nie stanie się
przestarzały po wydaniu nowszej wersji WordPress. Jesteśmy przekonani,
że każdy fragment kodu przedstawiony w książce pozostanie odpowiedni i
aktualny przez wiele lat, podobnie jak opracowane przez nas wiele lat
temu wtyczki, które nadal pozostają w pełni funkcjonalne.

W jaki sposób zorganizowana jest ta książka?

Książka to jedno z oferujących największe możliwości i jednocześnie
bardzo wyczerpujące źródło informacji o wtyczkach WordPress. Omówiono
tutaj wiele zaawansowanych zagadnień platformy WordPress, np. API
Rewrite, zadania mechanizmu cron oraz własne rodzaje wpisów bloga. Sama
książka została podzielona na trzy części. Lektura trzech pierwszych
rozdziałów ("Wprowadzenie", "Podstawy dotyczące wtyczek" i "Zaczepy")
jest obowiązkowa, gdy chcesz wykonać pierwsze kroki w cudownym świecie
wtyczek WordPress. W rozdziałach od 4. do 7. poruszono większość tematów
najczęściej spotykanych podczas tworzenia wtyczek. Zrozumienie tych
zagadnień będzie pomocne w trakcie lektury kolejnych rozdziałów.
Natomiast w pozostałych rozdziałach przedstawiono zaawansowane API i
funkcje. Te rozdziały można czytać w dowolnej kolejności; czasami
zawierają odniesienia do innych rozdziałów, w których znajdują się
informacje szczegółowe dotyczące danej funkcji.

Konwencje

Aby maksymalnie ułatwić lekturę i śledzenie omawianych zagadnień, w
książce zastosowano różne konwencje typograficzne.

------------------------------------------------------------------------

Ostrzeżenie

Ta ikona oznacza bardzo ważną informację bezpośrednio powiązaną z
tekstem, którą należy zapamiętać.

------------------------------------------------------------------------

------------------------------------------------------------------------

Uwaga

Ta ikona oznacza notatkę, wskazówkę, podpowiedź itp., związaną z
aktualnie omawianym zagadnieniem.

------------------------------------------------------------------------

W tekście również zastosowano pewne style:

-   Nowe pojęcia są zapisane czcionką pogrubioną.
-   Skróty klawiaturowe, ważne słowa, nazwy plików i adresy URL są
    zapisane kursywą.
-   Kod w tekście jest przedstawiony czcionką o stałej szerokości, np.
    persistence.properties.
-   Kod źródłowy jest przedstawiany na dwa różne sposoby:

    W większości przykładów zastosowano czcionkę o stałej szerokości.
    Pogrubiona czcionka o stałej szerokości jest stosowana w celu podkreślenia szczególnie ważnych fragmentów kodu w danym kontekście lub do przedstawienia zmian w porównaniu z poprzednim fragmentem kodu.

Kod źródłowy

Podczas lektury książki możesz zdecydować się na ręczne wprowadzanie
przedstawianego kodu źródłowego lub wykorzystać gotowe pliki kodu
źródłowego dostępne pod adresem
ftp://ftp.helion.pl/przyklady/wtywor.zip. Z wymienionej strony wystarczy
pobrać archiwum, w którym znajdują się pliki kodu źródłowego. Kod
umieszczony w tym archiwum jest na stronach książki oznaczony poniższą
ikoną:

[]

Listingi zawierają nazwę pliku w tytule. Jeżeli to po prostu fragment
kodu źródłowego, nazwa pliku zostanie podana w następujący sposób:

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku nazwa_pliku.

------------------------------------------------------------------------

Po pobraniu archiwum kodu źródłowego wystarczy je rozpakować za pomocą
ulubionego narzędzia obsługi archiwów.

Errata

Dołożyliśmy wszelkich starań, aby zarówno tekst, jak i kod źródłowy były
pozbawione błędów. Jednak nikt nie jest doskonały i pomyłki się
zdarzają. Jeżeli znajdziesz błąd w tekście, np. literówkę lub
niedziałający fragment kodu, będziemy wdzięczni za informacje o błędzie.
Zgłaszając erratę, oszczędzasz innym godzin niepotrzebnej frustracji
oraz pomagasz nam w dostarczaniu książki o jeszcze lepiej jakości.

Aby znaleźć erratę dla tej książki, przejdź na witrynę helion.pl i w
polu wyszukiwania podaj tytuł książki. Następnie na stronie książki
kliknij łącze Erraty. W przeglądarce zostanie wyświetlona strona
zawierająca erraty zgłoszone dla danej książki i zatwierdzone przez
redaktorów Helionu. Pełny katalog książek znajduje się na witrynie
helion.pl.

Jeżeli znaleziony błąd nie znajduje się na stronie erraty, kliknij łącze
Zgłoś erratę i wypełnij wyświetlony formularz informacjami o wykrytym
błędzie. Po sprawdzeniu przekazanej informacji strona erraty zostanie
uaktualniona, a błąd usunięty z kolejnych wydań książki.

Rozdział 1 Wprowadzenie do wtyczek

W tym rozdziale:

-   Zrozumienie wtyczki
-   Używanie dostępnego API WordPress
-   Kolejność wczytywania wtyczek
-   Przykłady popularnych wtyczek
-   Rozdzielenie funkcji wtyczki i motywu
-   Zarządzanie wtyczkami i ich instalacja
-   Rozróżnianie typów wtyczek platformy WordPress

Platforma WordPress to obecnie najpopularniejszy system zarządzania
treścią dostępny jako oprogramowanie typu open source. Jednym z
podstawowych powodów tak dużej popularności platformy WordPress jest
łatwość, z jaką można dostosować ją do własnych potrzeb za pomocą
wtyczek. WordPress oferuje programistom niesamowitą strukturę służącą do
tworzenia wtyczek oraz narzędzia wymagane do przeprowadzenia rozbudowy
WordPress w niemal dowolny sposób.

Zrozumienie sposobu działania wtyczek oraz narzędzi oferowanych przez
WordPress ma znaczenie krytyczne podczas opracowywania profesjonalnych
wtyczek dla tej platformy.

Co to jest wtyczka?

Wtyczka WordPress to skrypt PHP rozszerzający bądź modyfikujący
podstawowe funkcje platformy WordPress. Proste wtyczki to pliki
instalowane na platformie WordPress, których zadaniem jest dodanie
pojedynczej funkcji lub całego ich zestawu. Dostępne wtyczki różnią się
poziomem skomplikowania — od prostych dostarczających obsługę funkcji
portali społecznościowych aż po całkiem skomplikowane pakiety typu
e-commerce. Nie ma ograniczenia w zakresie funkcji, które może
dostarczać wtyczka WordPress, więc liczba dostępnych do pobrania wtyczek
jest ogromna.

W jaki sposób wtyczki współdziałają z platformą WordPress?

Platforma WordPress oferuje wiele różnych API (ang. Application
Programming Interface, czyli interfejs programowania aplikacji), które
mogą być wykorzystywane przez tworzone wtyczki. Każde API pomaga we
współpracy z WordPress w inny sposób. Poniżej wymieniono listę
najważniejszych API dostępnych dla WordPress oraz opisano ich
przeznaczenie.

-   Wtyczka (ang. Plugin) — dostarcza zestaw zaczepów pozwalających
    wtyczkom na uzyskanie dostępu do określonych części WordPress. Na
    platformie WordPress dostępne są dwa różne typy zaczepów; są to
    akcje i filtry. Zaczep akcji powoduje wywołanie kodu wtyczki w
    określonym momencie. Przykładowo własna funkcja może być wywołana po
    zarejestrowaniu przez użytkownika konta w WordPress. Z kolei zaczep
    filtru modyfikuje tekst przed jego dodaniem lub po jego pobraniu z
    bazy danych.
-   Widgety (ang. Widgets) — API tworzy widgety i zarządza nimi we
    wtyczce. Widgety są wyświetlane na stronie Wygląd/Widgety i możliwe
    do dodania na dowolnym zarejestrowanym panelu bocznym w motywie. To
    API pozwala na używanie wielu egzemplarzy tego samego widgetu we
    wszystkich panelach bocznych.
-   Skrót (ang. Shortcode) — to API zapewnia obsługę skrótów we wtyczce.
    Skrót to prosty zaczep pozwalający na wywołanie funkcji PHP poprzez
    umieszczenie na stronie polecenia [skrót].
-   HTTP — to API pozwala na wysyłanie z wtyczki żądań HTTP. Pobiera
    treść z zewnętrznego adresu URL lub wysyła treść na wskazany adres
    URL. Obecnie istnieje pięć różnych sposobów wysyłania żądania HTTP.
    Dzięki temu API następuje standaryzacja procesu wysyłania żądania
    HTTP i sprawdzenie każdej metody przed jej wykonaniem. Na podstawie
    konfiguracji serwera API wybierze odpowiednią metodę i wykona
    żądanie HTTP.
-   Ustawienia (ang. Settings) — to API pozwala na umieszczenie we
    wtyczce ustawień lub sekcji ustawień. Podstawową zaletą używania
    tego API jest bezpieczeństwo. Wszystkie dane ustawień są dokładnie
    sprawdzane, więc podczas zapisywania ustawień wtyczki nie trzeba
    zwracać uwagi na niebezpieczeństwo ataku typu CSRF (ang. Cross Site
    Request Forgery) lub XSS (ang. Cross Site Scripting).
-   Opcje (ang. Options) — to API jest odpowiedzialne za przechowywanie
    i pobieranie opcji wtyczki. Oferuje możliwość utworzenia nowej
    opcji, uaktualnienia istniejącej, usunięcia opcji oraz pobrania
    dowolnej, już zdefiniowanej.
-   Widgety kokpitu (ang. Dashboard Widgets) — za pomocą tego API można
    tworzyć widgety kokpitu administratora. Widgety automatycznie
    pojawiają się w kokpicie WordPress i zawierają wszystkie standardowe
    funkcje dostosowania do własnych potrzeb, czyli m.in. opcje
    minimalizacji, przeciągania i upuszczania, a także możliwość
    ukrycia.
-   Rewrite — to API pozwala na tworzenie we wtyczkach własnych reguł
    Rewrite. Za pomocą tego API można dodawać statyczne punkty końcowe
    (/własna_strona/), tagi strukturalne (%postname%) oraz dodatkowe
    łącza kanałów RSS (/feed/json/).
-   Transients — to API tworzy we wtyczkach opcje tymczasowe (buforowane
    dane). Jest podobne do API opcji, ale wszystkie opcje są zapisywane
    wraz z datą i godziną utraty ważności.
-   Baza danych (ang. Database) — to API jest odpowiedzialne za
    udzielenie dostępu do bazy danych WordPress. Obejmuje operacje
    tworzenia, uaktualniania, usuwania i pobierania rekordów bazy danych
    w celu ich użycia we wtyczce.

Platforma WordPress oferuje także funkcje zastępowalne (ang. pluggable
functions). Dzięki wspomnianym funkcjom można nadpisać określone funkcje
podstawowe platformy nowymi, udostępnianymi przez wtyczkę. Przykładem
tego rodzaju funkcji jest wp_mail(). Użytkownik może bardzo łatwo
zdefiniować tę funkcję we własnej wtyczce i wysyłać wiadomości e-mail za
pomocą SMTP zamiast metody domyślnej. Wszystkie funkcje zastępowalne
zostały zdefiniowane w pliku /wp-includes/pluggable.php platformy
WordPress.

Pewne predefiniowane funkcje można wykorzystać podczas określonych
operacji wykonywanych przez wtyczkę, takich jak aktywacja lub
dezaktywacja wtyczki, lub nawet w trakcie usuwania wtyczki. Szczegółowe
omówienie tych funkcji znajduje się w rozdziale 2.

Kiedy wtyczki są wczytywane?

Wtyczki są wczytywane we wczesnym procesie wywołania strony utworzonej
na bazie WordPress. Na rysunku 1.1 pokazano przebieg standardowego
procesu wczytywania strony bazującej na platformie WordPress.

[]

Rysunek 1.1. Przebieg standardowego procesu wczytywania strony
utworzonej na bazie WordPress

Pokazany przebieg jest nieco inny podczas wczytywania strony
administracyjnej. Różnice są minimalne i sprowadzają się do wczytywanego
motywu, czyli administratora zamiast motywu witryny internetowej.

Dostępne wtyczki

Podczas wyszukiwania dostępnych wtyczek WordPress trzeba wiedzieć, gdzie
ich szukać. Wtyczki można pobierać z dowolnej strony dostępnej w
internecie, ale to nie jest najlepszy pomysł.

------------------------------------------------------------------------

Ostrzeżenie

Podobnie jak w przypadku każdego oprogramowania, pobieranie wtyczek z
niezaufanego źródła może doprowadzić do pobrania złośliwego kodu i
przerobionych plików wtyczek. Najlepszym rozwiązaniem jest pobieranie
wtyczek jedynie z zaufanych witryn internetowych oraz oficjalnych
źródeł, takich jak oficjalny katalog wtyczek.

------------------------------------------------------------------------

Oficjalny katalog wtyczek

Poszukiwanie wtyczek należy zacząć od oficjalnego katalogu wtyczek
znajdującego się na witrynie WordPress.org. Katalog wtyczek jest
dostępny na stronie http://wordpress.org/extend/plugins/. Zawiera ponad
dziesięć tysięcy wtyczek, które zostały pobrane ponad sto milionów razy,
co świadczy o ważnej roli odgrywanej przez wtyczki na każdej witrynie
internetowej bazującej na WordPress. Wszystkie wtyczki znajdujące się
oficjalnym katalogu są w 100% na licencji GPL i bezpłatne do użytku
zarówno osobistego, jak i komercyjnego.

Przykłady popularnych wtyczek

Warto zapoznać się z pięcioma najczęściej pobieranymi wtyczkami
WordPress, co pozwoli na przekonanie się o ich różnorodności.

-   All in One SEO Pack — dodaje do WordPress zaawansowane funkcje
    silnika wyszukiwania. Dostępne funkcje to m.in. własne metadane dla
    całej treści, adresy URL w postaci kanonicznej, obsługa własnych
    typów przekazywania stron i wiele innych.

        http://wordpress.org/extend/​plugins/all-in-one-seo-pack/

-   Google XML Sitemaps — powoduje wygenerowanie pliku XML z mapą
    witryny obejmującą całą treść. Tak przygotowany plik można później
    przekazać popularnym silnikom wyszukiwania, np. Google, Bing lub
    Ask.com.

        http://wordpress.org/extend/​plugins/google-sitemap-generator/

-   Akismet — popularny filtr spamu w komentarzach na stronie WordPress.
    Wszystkie komentarze są sprawdzane przez usługę sieciową Akismet w
    celu sprawdzenia, czy zawierają spam.

        http://wordpress.org/extend/​plugins/akismet/

-   NextGEN Gallery — umożliwia witrynie bazującej na WordPress obsługę
    zaawansowanej galerii obrazów. Użytkownik może bardzo łatwo tworzyć
    galerię obrazów i zarządzać nią oraz pokazami slajdów. Galerie mogą
    być osadzone w postach lub na stronach.

        http://wordpress.org/extend/plugins/nextgen-gallery/

-   Contact Form 7 — wtyczka pozwala na dodanie formularza kontaktowego
    w dowolnym wpisie lub na dowolnej stronie WordPress. Zapewnia
    obsługę wielu formularzy kontaktowych, filtrowanie spamu za pomocą
    Akismet oraz obsługę techniki CAPTCHA.

        http://wordpress.org/extend/plugins/contact-form-7/

Jak można się przekonać, wymienione powyżej wtyczki mogą obsługiwać
różnorodne zadania. Oferowane przez nie funkcje są uniwersalne i
praktycznie powinny znajdować się na większości witryn internetowych.

Popularne tagi wtyczek

Teraz warto się zapoznać z kilkoma popularnymi tagami przypisywanymi
wtyczkom. Tagi wtyczek to, podobnie jak tagi wpisów bloga, proste słowa
kluczowe opisujące wtyczkę w katalogu. W ten sposób użytkownik, podając
tag, może łatwo znaleźć istniejącą wtyczkę. Poniżej wymieniono kilka
popularnych przykładów.

-   Twitter — każdy kocha Twitter za możliwość prowadzenia mikrobloga i
    dzielenia się odnośnikami do stron internetowych. Dzięki tagowi o
    nazwie twitter można znaleźć wiele powiązanych z Twitterem wtyczek
    dla WordPress.

        http://wordpress.org/extend/plugins/tags/twitter

-   Google — przy tak dużej liczbie wielu różnych usług i API Google to
    popularny tag przypisywany wtyczkom. Wszystko, począwszy od reklam
    Google aż po mapy Google, może zostać zintegrowane we wtyczce
    WordPress.

        http://wordpress.org/extend/plugins/tags/google

-   Widget — większość wtyczek zawierających widget ma przypisany także
    tag widget. W ten sposób użytkownik może przeglądać wiele rodzajów
    widgetów dostępnych dla WordPress.

        http://wordpress.org/extend/plugins/tags/widget

Przeglądanie popularnych tagów wtyczek to doskonały sposób inspiracji
podczas opracowywania nowych wtyczek dla platformy WordPress.

Zalety wtyczek

Używanie wtyczek WordPress wiąże się z wieloma zaletami. Poznanie
wspomnianych zalet tworzenia wtyczek jest konieczne do prawdziwego
zrozumienia powodów, dla których warto budować wtyczki. W ten sposób
można także określić potrzebę opracowania określonej wtyczki dla
platformy WordPress.

Brak konieczności modyfikacji jądra platformy

Jedną z podstawowych zalet wtyczek jest możliwość zmiany zachowania
platformy WordPress bez konieczności modyfikacji jakichkolwiek plików
tworzących jej jądro. Wspomniane pliki tworzące jądro platformy to po
prostu pliki dostarczane w standardowej instalacji WordPress.

Modyfikacja plików tworzących jądro platformy może znacznie utrudnić
uaktualnienie WordPress po wydaniu nowszej wersji. Jeżeli użytkownik
przeprowadzi jakąkolwiek modyfikację pliku tworzącego jądro WordPress,
wówczas podczas uaktualnienia platformy ta modyfikacja zostanie
nadpisana. Utrzymywanie platformy WordPress w najnowszej dostępnej
wersji ma znaczenie krytyczne dla zapewnienia bezpieczeństwa witryny
internetowej.

Ponadto modyfikacja plików wchodzących w skład jądra platformy może
doprowadzić do niestabilnego działania witryny internetowej. Różne
komponenty WordPress wzajemnie na sobie polegają w celu prawidłowego
funkcjonowania. Gdy przeprowadzimy modyfikację pliku tworzącego jądro
platformy, będzie on działać niezgodnie z założeniami, a to może
doprowadzić do niestabilności i uszkodzić funkcje WordPress niezwiązane
z wprowadzoną modyfikacją.

Nie trzeba wyważać otwartych drzwi

Inną zaletą tworzenia wtyczek jest istniejąca już struktura przeznaczona
do obsługi wtyczek. Wiele często stosowanych funkcji zostało już
opracowanych i są gotowe do użycia w postaci wtyczki. Przykładowo
użytkownik może wykorzystać zalety płynące z używania ról wbudowanych na
platformie WordPress. Za pomocą ról można bardzo łatwo wprowadzić
ograniczenie polegające na tym, że dany kod będzie wykonywany jedynie
przez użytkownika z uprawnieniami administratora. Spójrzmy na przykład:

    <?php
    if ( current_user_can( 'manage_options' ) ) {
       // Cały znajdujący się tutaj kod będzie wykonany tylko wtedy,
       // JEŻELI użytkownik jest administratorem.
    }
    ?>   

Jak można się przekonać, sprawdzenie uprawnień użytkownika przed
wykonaniem jakiegokolwiek kodu we wtyczce jest bardzo proste. Więcej
informacji dotyczących kont użytkowników i ról znajduje się w rozdziale
8.

Poniżej przedstawiono kolejny przykład, tym razem wysyłanie wiadomości
e-mail na platformie WordPress. Oczywiście, we własnej wtyczce można
utworzyć nową funkcję przeznaczoną do tego celu, ale po co? WordPress
oferuje użyteczną funkcję o nazwie wp_mail() służącą do wysyłania
wiadomości e-mail. Warto spojrzeć na przykład jej użycia:

    <?php
    $email_to = 'uzytkownik@przyklad.pl';
    $email_subject = 'Przykład wtyczki wysyłającej e-mail';
    $email_message = 'Jak ci się podoba moja nowa wtyczka?';
    wp_mail( $email_to, $email_subject, $email_message );
    ?>

Jak można się przekonać na podstawie powyższego kodu, wysyłanie
wiadomości e-mail w WordPress nie może być prostsze. Jeśli tylko wtyczka
nie wymaga użycia pewnych dostosowanych do własnych potrzeb funkcji
obsługujących wiadomości e-mail, nie należy tworzyć tej funkcji zupełnie
od początku. Zastosowanie funkcji wp_mail() gwarantuje także brak
problemów podczas wysyłania wiadomości e-mail w WordPress, ponieważ
używana jest funkcja wbudowana i standardowo dostarczana przez
platformę.

Stosowanie na platformie WordPress dostępnych funkcji wbudowanych może
znacznie zmniejszyć ilość czasu koniecznego na opracowanie wtyczki. Inna
zaleta niewyważania otwartych drzwi polega na tym, że taka wtyczka,
dzięki maksymalnemu zachowaniu zgodności, będzie prawdopodobnie działała
w większej liczbie serwerów i konfiguracji. Nie wyważaj otwartych drzwi,
jeśli potrzebne funkcje są już dostępne w WordPress.

Oddzielenie wtyczek i motywów

Wtyczka może przejąć kontrolę nad procesem generowania strony, a tym
samym staje się "motywem". Podobnie motyw może zawierać funkcje wtyczki.
Ponieważ różnica między wtyczką i motywem czasami się zaciera, rodzi się
pytanie o możliwość umieszczenia kodu wtyczki bezpośrednio w motywie. To
bardzo często pojawiające się pytanie, na które można udzielić wielu
różnych odpowiedzi.

Czy motyw powinien zawierać funkcje wtyczki? Nie. Podstawowym powodem
jest fakt, że zadanie wtyczki to dostarczenie platformie WordPress
dodatkowych funkcji, niezależnie od używanego motywu. W ten sposób
następuje zachowanie rozdzielności między projektem graficznym witryny
internetowej a jej funkcjonalnością. Dlatego też w celu zachowania
wspomnianej rozdzielności motyw nie może być bezpośrednio powiązany z
funkcjami wymaganymi do prawidłowego działania witryny. Platforma
WordPress została zbudowana tak, aby w dowolnej chwili za pomocą kilku
kliknięć myszą maksymalnie ułatwić zmianę projektu graficznego (czyli
motywu). Kiedy wszystkie funkcje wtyczki zostaną zawarte w motywie,
zmiana motywu będzie wiązała się z utratą funkcji wymaganych do
prawidłowego działania witryny internetowej.

Istnieje również ważny argument przemawiający za tym, aby określone
funkcje były umieszczane w motywie. Motywy bardzo często oferują funkcję
nawigacyjną "jesteś tutaj". Wymieniona funkcja na pewno może istnieć we
wtyczce, ale ponieważ jest powiązana z nawigacją, to rozsądne będzie jej
umieszczenie w motywie. Funkcje optymalizacji silników wyszukiwania
także są często spotykane w motywach.

Łatwe uaktualnienia

Platforma WordPress bardzo ułatwia uaktualnienie wtyczki do najnowszej
wersji. Każda wtyczka zainstalowana bezpośrednio z katalogu wtyczek
znajdującego się na witrynie WordPress.org informuje użytkownika o
dostępności nowszej wersji. Proces uaktualnienia wtyczki jest bardzo
prosty i sprowadza się do kliknięcia komunikatu powiadomienia
wyświetlanego tuż pod opisem wtyczki na stronie administracyjnej
Wtyczki.

Wtyczki, które nie zostały zainstalowane z oficjalnego katalogu wtyczek,
również mogą być uaktualniane za pomocą oferowanej przez WordPress
funkcji automatycznego uaktualniania. Autor wtyczki musi zdefiniować
miejsce, z którego WordPress może pobrać najnowszą wersję wtyczki, a
platforma zajmie się resztą. Jeżeli autor nie zdefiniuje wspomnianej
lokalizacji, użytkownik musi ręcznie uaktualnić wtyczkę.

Aktualizacja wtyczek jest bardzo ważna ze względu na zapewnienie
witrynie internetowej bezpieczeństwa poprzez eliminację znalezionych luk
i błędów.

Łatwiejsze dzielenie się wtyczkami i ich ponowne używanie

Wtyczkami można bardzo łatwo dzielić się z innymi użytkownikami.
Znacznie łatwiej udostępnić wtyczkę, niż nakazać innemu użytkownikowi
przeprowadzenie modyfikacji określonych wierszy kodu w motywie bądź w
plikach tworzących platformę WordPress. Stosowanie wtyczek jednocześnie
bardzo ułatwia używanie tych samych funkcji na wielu witrynach
internetowych. Kiedy użytkownik znajdzie zestaw wtyczek, które polubi,
bardzo łatwo może je zainstalować na każdej utworzonej przez siebie
witrynie internetowej bazującej na WordPress.

Wtyczki są oddzielone od siebie

Uruchomienie uszkodzonej wtyczki na platformie WordPress nie powoduje
uszkodzenia witryny internetowej. Jeżeli wtyczka spowoduje wystąpienie
błędu krytycznego, platforma WordPress automatycznie ją dezaktywuje,
zanim wtyczka zdąży narobić strat. Dzięki takiej możliwości aktywacja i
testowanie nowych wtyczek są obarczone znacznie mniejszym ryzykiem.
Jeśli nawet wtyczka spowoduje wyświetlenie białego ekranu śmierci
(komunikat błędu), można bardzo łatwo zmienić nazwę katalogu wtyczek, a
WordPress dezaktywuje wtyczkę. Ten mechanizm uniemożliwia uszkodzonej
wtyczce zablokowanie użytkownika na jego własnej witrynie internetowej z
powodu błędu w samej wtyczce.

Jeśli natomiast użytkownik spróbuje zmodyfikować pliki tworzące jądro
WordPress, może doprowadzić do wystąpienia błędów krytycznych, które
uniemożliwią działanie witryny internetowej. To może się wiązać z
wprowadzeniem nieodwracalnych uszkodzeń w WordPress.

Społeczność tworząca wtyczki

Opracowywaniem wtyczek zajmuje się ogromna społeczność, która dzieli się
wiedzą i kodem oraz tworzy doskonałe wtyczki. Zaangażowanie się w prace
tej społeczności to doskonały sposób wzbogacenia własnej wiedzy z
zakresu budowania wtyczek. W rozdziale 18. przedstawiono wiele
związanych z tym zasobów.

Instalacja wtyczek i zarządzanie nimi

Wszystkie operacje zarządzania wtyczkami na platformie WordPress są
przeprowadzane na stronie administracyjnej Wtyczki (zobacz rysunek 1.2).

[]

Rysunek 1.2. Operacje na wtyczkach są przeprowadzane na stronie
administracyjnej Wtyczki

Menu pokazane na rysunku 1.2 jest wyświetlane jedynie administratorom,
natomiast zwykli użytkownicy go nie widzą. Podczas używania funkcji
Multisite (czyli sieci blogów) platformy WordPress menu Wtyczki jest
domyślnie ukryte. Wymienione menu należy włączyć na stronie
Administracja siecią/Ustawienia.

Instalacja wtyczki

Platforma WordPress oferuje trzy różne metody instalacji nowej wtyczki.
Wybór najlepszej metody jest uzależniony od konfiguracji serwera.

Pierwsza metoda polega na użyciu wbudowanego automatycznego instalatora.
Dzięki tej metodzie użytkownik może przeszukiwać oficjalny katalog
wtyczek na witrynie WordPress.org bezpośrednio z poziomu kokpitu
administracyjnego witryny internetowej. Po znalezieniu odpowiedniej
wtyczki wystarczy kliknąć łącze Zainstaluj, a wtyczka zostanie
automatycznie pobrana i zainstalowana.

Druga metoda polega na przekazaniu do serwera pliku wtyczki w postaci
archiwum .zip. Wtyczki dostarczane jako archiwa .zip mogą być
przekazywane do serwera, a następnie są rozpakowywane i instalowane
przez WordPress. Aby użyć tej metody, należy kliknąć łącze Wyślij na
serwer wyświetlane na górze strony Zainstaluj wtyczki. Kliknięcie
przycisku Przeglądaj… pozwala na wybór wtyczki przeznaczonej do
instalacji. Po jej wybraniu trzeba nacisnąć przycisk Zainstaluj (zobacz
rysunek 1.3).

[]

Rysunek 1.3. Instalacja wtyczki z archiwum zip

Trzecia i ostatnia metoda instalacji wtyczki na platformie WordPress
polega na użyciu protokołu FTP (ang. File Transfer Protocol). Użycie FTP
jest bardzo proste i sprowadza się do połączenia z serwerem poprzez
klienta FTP i ręcznego skopiowania wtyczki do instalacji WordPress. Aby
użyć tej metody, należy nieskompresowaną wtyczkę skopiować do katalogu
wp-content/plugins znajdującego się na serwerze WWW.

Zarządzanie wtyczkami

Po instalacji wtyczki w WordPress można zarządzać nią (oraz innymi) za
pomocą strony administracyjnej Wtyczki. Na stronie znajduje się lista
wtyczek zarówno aktywnych, jak i nieaktywnych w danej instalacji
WordPress. Przy użyciu tej strony użytkownik może więc bardzo łatwo
aktywować, dezaktywować, edytować, uaktualniać i usuwać wtyczki.

Strona administracyjna Wtyczki oferuje również funkcje grupowego
aktywowania, dezaktywowania, uaktualniania i usuwania wtyczek. Wystarczy
zaznaczyć wszystkie wtyczki, których będzie dotyczyła akcja, a następnie
z rozwijanego menu wybrać odpowiednią operację. W ten sposób proces
zarządzania wieloma wtyczkami jest łatwy.

Edycja wtyczek

Na stronie Wtyczki/Edytor platforma WordPress oferuje wbudowany edytor
wtyczek. Za jego pomocą użytkownik może wyświetlić oraz edytować kod
źródłowy dowolnej zainstalowanej wtyczki. Warto pamiętać, że edytować
kod źródłowy wtyczki można jedynie wtedy, gdy użytkownik ma uprawnienia
zapisu jej pliku na serwerze WWW. W przeciwnym razie można jedynie
wyświetlić kod źródłowy wtyczki.

Aby użyć edytora, trzeba z rozwijanego menu wyświetlanego w lewej górnej
części okna edytora wybrać wtyczkę. Edytor wyświetla wszystkie pliki
powiązane z wybraną wtyczką. Ponadto istnieje możliwość przejrzenia
dokumentacji, co pozwala na łatwe wyszukanie informacji o przeznaczeniu
określonej funkcji przeglądanej wtyczki.

------------------------------------------------------------------------

Ostrzeżenie

Oto ostrzeżenie dotyczące używania wbudowanego edytora wtyczek:
przeglądarka nie oferuje przycisku Cofnij. Nie ma również możliwości
przeglądania wcześniejszych wersji kodu. Dlatego też wprowadzenie błędu
w kodzie może doprowadzić do awarii całej witryny internetowej bez
możliwości cofnięcia zmian. Wbudowany edytor najlepiej więc
wykorzystywać jedynie do przeglądania kodu wtyczek i nigdy nie
przeprowadzać za jego pomocą edycji plików wtyczek.

------------------------------------------------------------------------

Katalog wtyczek

WordPress w rzeczywistości oferuje dwa katalogi wtyczek, ale to mało
znany fakt. Podstawowy katalog wtyczek w standardowej instalacji
WordPress to wp-content/plugins. Natomiast drugi, mniej znany, katalog
wtyczek to wp-content/mu-plugins. Katalog mu-plugins (skrót mu pochodzi
od Must-Use, czyli konieczne do użycia) nie jest automatycznie tworzony
przez WordPress i musi być wykreowany ręcznie.

Główna różnica pomiędzy wymienionymi katalogami polega na tym, że
katalog mu-plugins jest przeznaczony dla wtyczek, które zawsze są
wykonywane. Tak więc każda wtyczka umieszczona w katalogu mu-plugins
będzie automatycznie wczytywana przez WordPress na wszystkich witrynach
w sieci, jeśli używana jest funkcja Multisite.

------------------------------------------------------------------------

Uwaga

Katalog mu-plugins nie odczytuje wtyczek umieszczonych w podkatalogach,
więc wszystkie wtyczki muszą być w postaci pojedynczych plików lub muszą
dołączać pliki istniejące w podkatalogu. Każdy plik wtyczki znajdujący
się w podkatalogu zostanie zignorowany, o ile nie zostanie dołączony
(wczytany) w podstawowym pliku wtyczki.

------------------------------------------------------------------------

Typy wtyczek

Platforma WordPress oferuje kilka różnych typów i stanów wtyczek (zobacz
rysunek 1.4). Podczas administrowania i zarządzania wtyczkami WordPress
musisz więc rozumieć różnice między nimi.

-   Włączone — to wtyczki aktywne i działające na platformie WordPress.
-   Wyłączone — to wtyczki zainstalowane, ale nieaktywne. Na platformie
    WordPress nie jest wykonywany żaden kod nieaktywnych wtyczek.
-   Wymuszane — to wtyczki znajdujące się w katalogu
    wp-content/mu-plugins. Wtyczki z wymienionego katalogu są wczytywane
    automatycznie. Jedynym sposobem dezaktywacji takiej wtyczki jest
    zupełne usunięcie jej z tego katalogu.
-   Zamienniki — podstawowe funkcje WordPress mogą być zastępowane
    wtyczkami zamienników. Te wtyczki to pliki PHP o specjalnych
    nazwach, znajdujące się w katalogu wp-content. Gdy WordPress wykryje
    dowolny z tych plików, automatycznie go wczyta i umieści na liście
    zamienników wyświetlanej na stronie administracyjnej Wtyczki.
    Dostępne obecnie wtyczki zamienników to:
-   advanced-cache.php — zaawansowana wtyczka buforowania;
-   db.php — własna klasa współpracy z bazą danych;
-   db-error.php — własne komunikaty błędów podczas współpracy z bazą
    danych;
-   install.php — własny skrypt instalacyjny;
-   maintenance.php — własne komunikaty obsługi;
-   object-cache.php — zewnętrzny obiekt buforowania;
-   sunrise.php — zaawansowane mapowanie domeny;
-   blog-deleted.php — własny komunikat po usunięciu bloga;
-   blog-inactive.php — własny komunikat po dezaktywowaniu bloga;
-   blog-suspended.php — własny komunikat po zawieszeniu bloga.

[]

Rysunek 1.4. Różne typy i stany wtyczek na platformie WordPress

Ostatnie cztery wymienione wtyczki są charakterystyczne dla funkcji
Multisite na platformie WordPress. Standardowa instalacja WordPress nie
wykorzystuje żadnej z czterech ostatnich wtyczek wymienionych na
powyższej liście.

Podczas opracowywania nowej wtyczki, a jeszcze przed rozpoczęciem pracy,
należy określić jej rodzaj. Większość wtyczek będzie standardowymi
wtyczkami WordPress, ale czasami może wystąpić konieczność utworzenia
wtyczki wymuszonej lub zamiennika.

Testowanie funkcji wtyczek

Czasami trzeba przetestować funkcje pewnej wtyczki bez rzeczywistego jej
utworzenia. W tym celu większość programistów umieszcza sprawdzany kod
bezpośrednio w pliku wp-config.php. To jest zła technika i nie powinna
być stosowana, bo kiedy wymieniony plik jest przetwarzany i wczytywany,
platforma WordPress nie jest jeszcze w pełni ustanowiona.

Zamiast modyfikować plik wp-config.php, warto utworzyć plik test.php
wraz z przedstawionym poniżej kodem, a następnie umieścić go w katalogu
głównym WordPress:

    <?php
    // Wczytanie środowiska WordPress.
    // define( 'WP_DEBUG', true ); /* usuń znacznik komentarza podczas debugowania */
    require('./wp-load.php');
    // require_once ('./wp-admin/admin.php'); /* usuń znacznik komentarza dla is_admin() */
    ?> 
    <pre> 
    <?php
    /* to jest miejsce na testowany kod */
    var_dump( is_admin() );
    ?> 
    </pre>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku test.php.

------------------------------------------------------------------------

Jest to sposób pozwalający na szybkie wczytanie wszystkich wymaganych
funkcji WordPress w celu przetestowania funkcji wtyczki bez faktycznego
jej tworzenia. Jak można zobaczyć, plik wp-load.php jest dołączany na
początku pliku. Podczas testowania w środowisku administratora należy
dołączyć także plik wp-admin/admin.php. Po dołączeniu wymaganych plików
fabrycznych platformy WordPress można przystąpić do testowania kodu,
który w innym przypadku musiałby zostać umieszczony we wtyczce. Po
zakończeniu testów nie wolno zapomnieć o usunięciu pliku test.php.

Podsumowanie

W tym rozdziale przedstawiono ogólne informacje dotyczące wtyczek oraz
sposobów ich współpracy z platformą WordPress za pomocą dostępnego API.
Omówiono podstawowe zalety używania wtyczek oraz powody, dla których ich
funkcje nie powinny być umieszczane w motywach. Ponadto poruszono temat
instalacji wtyczek i zarządzania nimi w kokpicie administracyjnym
platformy WordPress.

Po zrozumieniu sposobu działania wtyczek na platformie WordPress warto
przystąpić do rozpoczęcia tworzenia wtyczek!

Rozdział 2 Podstawy wtyczek

W tym rozdziale:

-   Utworzenie solidnych podstaw dla wtyczek
-   Określenie ścieżek dostępu do katalogów i plików
-   Używanie funkcji aktywacji i dezaktywacji
-   Zrozumienie dostępnych metod dezinstalacji wtyczek
-   Stosowanie rozsądnych praktyk i standardy tworzenia kodu
-   Zrozumienie potrzeby tworzenia poprawnej dokumentacji kodu
-   Używanie listy rzeczy do sprawdzenia podczas prac nad wtyczkami

Podczas opracowywania wtyczek dla platformy WordPress bardzo ważne jest
rozpoczęcie pracy od przygotowania solidnych podstaw dla wtyczek. W
trakcie prac nad wtyczkami solidne podstawy pomagają w eliminacji wielu
problemów. Techniki omówione w tym rozdziale będą nieustannie stosowane
w kolejnych rozdziałach książki i stanowią przykład dobrego podejścia.

Utworzenie pliku wtyczki

Wtyczka WordPress może mieć postać pojedynczego pliku PHP bądź składać
się z grupy plików umieszczonych we własnym katalogu. Podczas tworzenia
nowej wtyczki dla WordPress pod uwagę trzeba wziąć kilka czynników,
m.in. nazwę wtyczki oraz prawidłowy sposób używania katalogu.

Nadanie nazwy wtyczce

Podczas wyboru nazwy dla wtyczki dobrą praktyką jest rozważenie nazwy
bazującej na rzeczywistej funkcji wtyczki. Przykładowo, tworząc wtyczkę
działającą na obszarze SEO, nie należy jej nadawać nazwy Wtyczka Bartka,
ponieważ na jej podstawie użytkownicy nie będą wiedzieli, jakie jest
przeznaczenie tej wtyczki. Nazwa powinna być więc zarówno unikalna, jak
i wskazywać przeznaczenie wtyczki.

Dobrym pomysłem jest również przeszukanie oficjalnego katalogu wtyczek
na witrynie WordPress.org (http://wordpress.org/extend/plugins/) pod
kątem istnienia podobnych wtyczek, aby uniknąć zamieszania. Jeżeli
zdecydujesz się na nadanie wtyczce nazwy SEO Gold, a w katalogu istnieje
już wtyczka SEO Silver, może powstać pewne zamieszanie — użytkownicy
mogą sądzić, że to nowa lub nowsza wersja starej wtyczki. Nie warto
doprowadzać do sytuacji, w której pierwszym skojarzeniem dotyczącym
danej wtyczki będzie zamieszanie. Więcej informacji na ten temat
przedstawiono w rozdziale 17.

Używanie katalogu

Gorąco zalecamy przechowywanie wszystkich plików wtyczki w podkatalogu
umieszczonym w katalogu plugins platformy WordPress. Wszystkie wtyczki
pobierane z oficjalnego katalogu wtyczek są automatycznie umieszczane w
podkatalogach. W ten sposób wtyczka może składać się z wielu plików, np.
obrazów. W katalogu wtyczki można stosować nawet podkatalogi, co ułatwia
zarządzanie plikami wtyczki. Nazwa katalogu powinna być taka sama jak
głównego pliku wtyczki. W nazwie katalogu nie należy umieszczać żadnych
spacji lub znaków podkreślenia; jeśli trzeba, można użyć myślnika.
Podkatalogi i hierarchiczną strukturę katalogów przeznaczonych do
przechowywania plików wtyczki omówiono w kolejnym podrozdziale.

Stosowanie rozsądnych praktyk

Poniżej przedstawiono zestaw rozsądnych praktyk wykorzystywanych podczas
opracowywania wtyczek dla platformy WordPress. Omówione tutaj
rozwiązania warto stosować w trakcie pracy nad każdą wtyczką. W ten
sposób można uniknąć wielu najczęstszych błędów na platformie WordPress.
Ponadto przedstawione poniżej rozwiązania powodują otrzymanie znacznie
czytelniejszej struktury wtyczek.

Stosowanie prefiksu w każdej sytuacji

Podczas tworzenia własnej wtyczki warto w każdej sytuacji stosować
unikalny prefiks. To dotyczy wszystkich plików wtyczki, nazw funkcji i
zmiennych oraz wszelkich innych komponentów wtyczki. Dlaczego? To
proste, jednym z najczęściej występujących błędów dotyczących wtyczek
jest używanie powszechnie stosowanych nazw funkcji i zmiennych. Jeśli
przykładowo we wtyczce znajduje się funkcja update_options() i
użytkownik zainstaluje inną wtyczkę posiadającą funkcję o takiej samej
nazwie, wówczas witryna internetowa nie będzie działała, ponieważ PHP
nie zezwala na istnienie dwóch funkcji o takiej samej nazwie.

Dobrym rozwiązaniem jest stosowanie w każdej sytuacji prefiksu
utworzonego z pierwszych liter imienia i nazwiska programisty oraz nazwy
wtyczki. Jeśli przykładowo programista to Adam Nowak, a utworzona przez
niego wtyczka nosi nazwę Superwtyczka, wówczas wymieniona wcześniej
funkcja może mieć nazwę an_sw_update_options(). W takim przypadku
występuje znikome prawdopodobieństwo, że na świecie istnieje inna
funkcja o takiej samej nazwie, a tym samym zmniejsza się ryzyko
konfliktu nazw z innymi wtyczkami.

To samo rozwiązanie warto stosować także w nazwach zmiennych; nie należy
używać ogólnych nazw zmiennych. Jeżeli np. wtyczka tworzy zmienną o
nazwie $post i używa jej, można spodziewać się wystąpienia problemów,
ponieważ $post w WordPress to zmienna globalna zawierająca dane wpisu
bloga. Gdy wtyczka nadpisze dane przechowywane w wymienionej zmiennej, a
inny komponent WordPress będzie zakładał istnienie tych danych w
zmiennej $post, wtedy powstaje poważny problem. Zamiast tego warto więc
stosować taki sam prefiks jak wcześniej, czyli w przypadku tej zmiennej
będzie to $an_sw_post. W ten sposób powstaje unikalna nazwa zmiennej,
która prawdopodobnie jest używana w innych wtyczkach.

W kodzie przedstawionym w książce zastosowano prefiks boj_ (od
pierwszych liter imion autorów) i myplugin_ (od fikcyjnej wtyczki o
nazwie My Plugin), np. boj_myplugin_nazwa_funkcji().

Organizacja pliku

Zapewnienie właściwej organizacji plików wtyczki to podstawowy krok
podczas tworzenia profesjonalnej wtyczki. Ogólnie rzecz biorąc, katalog
wtyczki powinien zawierać tylko dwa pliki. Pierwszy z nich to podstawowy
plik PHP wtyczki, natomiast drugi to uninstall.php. Z powodów
organizacyjnych wszystkie pozostałe pliki powinny znajdować się w
podkatalogach.

Ponadto zaleca się podział wtyczki na kilka mniejszych plików.
Podstawowym powodem takiego zalecenia są kwestie wydajności. Przykładowo
wszystkie funkcje interfejsu administratora powinny znaleźć się w
oddzielnym pliku. W ten sposób można warunkowo dołączyć kod
administratora wtedy, gdy użytkownik działa po stronie administracyjnej
WordPress:

    <?php
    if ( is_admin() ) {
        // Znajdujemy się w katalogu wp-admin.
        require_once( dirname(__FILE__).'/includes/admin.php' );
    }
    ?> 

Powyższy fragment kodu za pomocą funkcji is_admin()sprawdza, czy
użytkownik znajduje się w administracyjnym kokpicie WordPress. Jeżeli
tak, wówczas do wtyczki zostanie dołączony plik /includes/admin.php,
który następnie będzie przetworzony.

Struktura katalogów

Inny ważny krok podczas tworzenia profesjonalnej wtyczki to zachowanie
przejrzystej struktury katalogów, która pozwala na przechowywanie
podobnych plików razem. Jeśli przykładowo we wtyczce skorzystano ze
skryptów JavaScript, warto utworzyć katalog /js przeznaczony dla
wszystkich plików JavaScript. Gdy używane są własne pliki arkuszy
stylów, dla nich należy utworzyć katalog /css. Wszystkie pliki graficzne
powinny trafić do katalogu /images.

Warto teraz zapoznać się ze standardową strukturą katalogów wtyczki:

-   /unikalna-nazwa-wtyczki — (bez spacji lub innych znaków
    specjalnych);
-   unikalna-nazwa-wtyczki.php — podstawowy plik PHP wtyczki;
-   uninstall.php — plik pozwalający na usunięcie wtyczki;
-   /js — katalog przeznaczony do przechowywania skryptów JavaScript;
-   /css — katalog przeznaczony do przechowywania arkuszy stylów;
-   /includes — katalog przeznaczony do przechowywania innych
    dołączanych plików PHP;
-   /images — katalog przeznaczony do przechowywania plików graficznych.

Jak można zobaczyć, przechowywanie plików w uporządkowanej strukturze
pozwala na bardzo łatwą obsługę wtyczki na przestrzeni czasu. Ponadto
inni programiści wtyczek, gdy przeglądają kod źródłowy wtyczki, mogą
znacznie łatwiej podążać za stosowaną logiką.

Wymagania dotyczące nagłówka

Nagłówek wtyczki to jedyne wymaganie stawiane wtyczce na platformie
WordPress. Wspomniany nagłówek wtyczki to blok komentarza PHP
umieszczony na samym początku podstawowego pliku PHP wtyczki. Komentarz
informuje platformę WordPress, że dany plik jest poprawną wtyczką.

Utworzenie nagłówka

Poniżej przedstawiono przykład nagłówka wtyczki:

    <?php
    /*
    Plugin Name: Superwtyczka
    Plugin URI: http://przyklad.pl/wtyczki-wordpresss/superwtyczka
    Description: To jest opis wtyczki.
    Version: 1.0
    Author: Adam Nowak
    Author URI: http://przyklad.pl
    License: GPLv2
    */
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku header-example.php.

------------------------------------------------------------------------

Jak można się przekonać, nagłówek wtyczki jest bardzo prosty. Jedyny
wymagany przez platformę WordPress wiersz to nazwa wtyczki (Plugin
Name), ale dobrym rozwiązaniem będzie stosowanie całego przedstawionego
powyżej nagłówka.

Wiersz Plugin URI to bezpośrednie łącze prowadzące do strony
internetowej z informacjami szczegółowymi o danej wtyczce. W wierszu
Description znajduje się krótki opis wtyczki wyświetlany na stronie
administracyjnej Wtyczki platformy WordPress. Z kolei wiersz Version
zawiera informacje o bieżącej wersji wtyczki, których platforma
WordPress używa w celu sprawdzenia, czy na witrynie WordPress.org jest
dostępne uaktualnienie dla danej wtyczki. Kolejne dwa wiersze zawierają
informacje o autorze i jego stronie domowej. Obydwie informacje są
wyświetlane na stronie administracyjnej Wtyczki platformy WordPress.
Ostatni wiersz wskazuje na licencję, na której została udostępniona dana
wtyczka.

Na rysunku 2.1 pokazano powyższy nagłówek wtyczki wygenerowany na
stronie administracyjnej Wtyczki platformy WordPress.

[]

Rysunek 2.1. Nagłówek wtyczki wyświetlony na stronie administracyjnej

Kliknięcie danych autora wtyczki (w omawianym przykładzie to Adam Nowak)
prowadzi bezpośrednio na stronę domową autora. Z kolei odnośnik Odwiedź
witrynę wtyczki prowadzi na stronę internetową zdefiniowaną w wierszu
Plugin URI nagłówka. Jak można się przekonać, obydwa odnośniki pomagają
użytkownikom wtyczki w uzyskaniu informacji dodatkowych o wtyczce i jej
autorze.

Licencja wtyczki

Dobrym pomysłem jest umieszczenie poniżej bloku nagłówka wtyczki
informacji o licencji, na której została udostępniona wtyczka. Wprawdzie
podawanie informacji o licencji nie jest wymagane, ale za każdym razem,
gdy udostępniasz kod publicznie, warto jasno określić licencję, na
której dany kod został udostępniony. W ten sposób użytkownicy mają
całkowitą jasność, na jakiej licencji jest dostępny kod i jak można go
używać. Więcej informacji na ten temat przedstawiono w rozdziale 17.

Platforma WordPress jest dostępna na licencji GPL (Powszechna Licencja
Publiczna GNU) i każda wtyczka przygotowana dla WordPress również
powinna być rozpowszechniania na tej licencji. Poniżej przedstawiono
przykład standardowego bloku licencji GPL:

    <?php
    /* Copyright ROK NAZWISKO AUTORA WTYCZKI (e-mail: E-MAIL AUTORA WTYCZKI)
       Niniejszy program jest wolnym oprogramowaniem; możesz go 
       rozprowadzać dalej i (lub) modyfikować na warunkach Powszechnej
       Licencji Publicznej GNU, wydanej przez Fundację Wolnego
       Oprogramowania - według wersji 2.  tej licencji lub którejś
       z późniejszych wersji. 
       Niniejszy program rozpowszechniany jest z nadzieją, iż będzie 
       użyteczny - jednak BEZ JAKIEJKOLWIEK GWARANCJI, nawet domyślnej 
       gwarancji PRZYDATNOŚCI HANDLOWEJ albo PRZYDATNOŚCI DO OKREŚLONYCH 
       ZASTOSOWAŃ. W celu uzyskania bliższych informacji - patrz Powszechna 
       Licencja Publiczna GNU. 
       Z pewnością wraz z niniejszym programem otrzymałeś też egzemplarz 
       Powszechnej Licencji Publicznej GNU (GNU General Public License);
       jeśli nie - napisz do Free Software Foundation, Inc., 51 Franklin St,
       Fifth Floor, Boston, MA 02110-1301 USA.
    */
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku license-example.php.

------------------------------------------------------------------------

W powyższym bloku wystarczy podać rok, nazwisko i adres e-mail autora
wtyczki, a następnie cały blok umieścić tuż pod nagłówkiem wtyczki.
Umieszczenie powyższego bloku sprawia, że wtyczka jest dostępna na
licencji GPL.

Określanie ścieżek dostępu

We wtyczce bardzo często trzeba określić ścieżkę dostępu do pliku lub
katalogu. Przykładowo w katalogu wtyczki może znajdować się plik
graficzny przeznaczony do wyświetlenia. Ogólnie rzecz biorąc, nie zaleca
się umieszczania w kodzie na stałe zapisanych ścieżek dostępu. Platforma
WordPress może być skonfigurowana na milion różnych sposobów i
założenie, że autor wtyczki zna prawidłowe ścieżki dostępu do katalogów,
jest błędne. W podrozdziale zostaną omówione poprawne sposoby określania
we wtyczce ścieżek dostępu do plików i katalogów.

Ścieżki dostępu wtyczki

Zadaniem dość często wykonywanym w niemal każdej wtyczce jest
odniesienie się do plików i katalogów w instalacji platformy WordPress.
W kodzie do pliku można się odnieść na dwa sposoby: poprzez użycie
ścieżki dostępu serwera lokalnego lub poprzez standardowy adres URL.
Wspomniana ścieżka dostępu serwera lokalnego to ścieżka dostępu do
katalogu w komputerze. Lokalne ścieżki dostępu są najczęściej używane,
gdy trzeba pobrać zasób znajdujący się w serwerze lokalnym. Natomiast
adres URL jest zwykle stosowany do pobrania zasobu zewnętrznego względem
serwera. Oczywiście, nie ma przeciwwskazań, aby np. pliki graficzne
dołączać za pomocą adresu URL.

Platforma WordPress oferuje funkcję przeniesienia katalogu wp-content w
inne miejsce. Z tego powodu w kodzie nie należy na stałe podawać ścieżek
dostępu do katalogów WordPress, ale zamiast tego stosować dostępne
funkcje, które pozwalają na określenie poprawnych ścieżek dostępu.

Lokalne ścieżki dostępu

Oto jedno z pytań najczęściej zadawanych podczas prac nad wtyczką: "Jaki
jest prawidłowy sposób określenia lokalnej ścieżki dostępu do plików
wtyczki?". W celu ustalenia lokalnej ścieżki dostępu do wtyczki
konieczne jest użycie funkcji plugin_dir_path(). Wymieniona funkcja
powoduje wyodrębnienie fizycznej lokalizacji pliku względem katalogu
wtyczek.

    <?php plugin_dir_path( $file ); ?> 

Parametry:

-   $file — (ciąg tekstowy, wymagany) — nazwa pliku wtyczki.

Teraz warto spojrzeć na przykład sposobu określenia lokalnej ścieżki
dostępu do katalogu wtyczki:

    <?php
    echo plugin_dir_path( __FILE__ );
    ?> 

Do funkcji plugin_dir_path() jest przekazywana stała PHP o nazwie
__FILE__. Dane wyjściowe powyższego fragmentu kodu to pełna ścieżka
dostępu w serwerze lokalnym prowadząca do katalogu wtyczki, np.:

/public_html/wp-content/plugins/moja-superwtyczka/

Co zrobić w sytuacji, gdy konieczne będzie pobranie lokalnej ścieżki
dostępu do pliku znajdującego się w podkatalogu katalogu wtyczki?
Rozwiązaniem jest również użycie funkcji plugin_dir_path() wraz z nazwą
podkatalogu i potrzebnego pliku:

    <?php
    echo plugin_dir_path( __FILE__ ) .'js/scripts.js';
    ?> 

Powyższy kod może wygenerować następującą ścieżkę dostępu:

/public_html/wp-content/plugins/moja-superwtyczka/js/scripts.js

Jak widać, funkcja plugin_dir_path() jest bardzo pomocna podczas
tworzenia wtyczek dla WordPress. Stosowanie poprawnych metod uzyskiwania
dostępu do plików i katalogów wtyczki może zapewnić maksymalną zgodność
ze wszystkimi instalacjami WordPress, niezależnie od poziomu ich
modyfikacji.

Adresy URL

Poniżej wymieniono dostępne na platformie WordPress funkcje pomagające w
określaniu adresów URL.

-   plugins_url() — pełny adres URL katalogu wtyczek (np.
    http://przyklad.pl/wp-content/
    plugins);
-   includes_url() — pełny adres URL katalogu dołączanych plików (np.
    http://przyklad.pl/wp-includes);
-   content_url() — pełny adres URL katalogu z treścią (np.
    http://przyklad.pl/wp-content);
-   admin_url() — pełny adres URL katalogu administracyjnego (np.
    http://przyklad.pl/wp-admin/);
-   site_url() — pełny adres URL bieżącej witryny (np.
    http://przyklad.pl);
-   home_url() — pełny adres URL strony głównej bieżącej witryny (np.
    http://przyklad.pl).

Funkcje site_url() i home_url() są bardzo podobne, co może prowadzić do
pewnych niejasności dotyczących ich sposobu działania. Funkcja
site_url() pobiera wartość siteurl ustawioną w tabeli wp-options bazy
danych. To jest adres URL prowadzący do plików tworzących standardową
instalację WordPress. Jeżeli pliki tworzące platformę znajdują się w
podkatalogu /wordpress serwera WWW, wówczas wartością zwrotną będzie
http://przyklad.pl/wordpress.

Z kolei funkcja home_url() pobiera wartość home ustawioną w tabeli
wp-options bazy danych. To jest adres URL, który użytkownicy muszą
wprowadzić w pasku adresu przeglądarki internetowej, aby wyświetlić daną
witrynę bazującą na WordPress. Jeżeli pliki tworzące platformę znajdują
się w podkatalogu /wordpress serwera WWW, ale adres URL witryny ma mieć
postać http://przyklad.pl, wówczas wartością home musi być
http://przyklad.pl.

Podczas tworzenia wtyczek dla WordPress funkcja plugins_url() stanie się
jednym z Twoich najlepszych przyjaciół. Za pomocą tej funkcji można
bardzo łatwo ustalić pełny adres URL dowolnego pliku znajdującego się w
katalogu wtyczek.

    <?php plugins_url( $path, $plugin ); ?> 

Parametry:

-   $path — (ciąg tekstowy, opcjonalny) — ścieżka dostępu względem
    adresu URL katalogu wtyczek;
-   $plugin — (ciąg tekstowy, opcjonalny) — względny plik wtyczki (tzn.
    przekazywany w stałej __FILE__).

Przykładowo trzeba ustalić ścieżkę dostępu do pliku graficznego, który
będzie użyty jako ikona wtyczki. To zadanie można bardzo łatwo wykonać
za pomocą poniższego fragmentu kodu:

    <?php
    echo '<img src="' .plugins_url( 'images/ikona.png' , __FILE__ ). '">';
    ?> 

Wartość pierwszego parametru przekazywanego funkcji to względna ścieżka
dostępu do pliku graficznego, który ma zostać użyty. Natomiast drugi
parametr to względny plik wtyczki, który w omawianym przypadku można
przekazać poprzez stałą PHP o nazwie __FILE__. Powyższy fragment kodu
wygeneruje przedstawiony poniżej znacznik img języka HTML:

    <img src="http://przyklad.pl/wp-content/plugins/moja-superwtyczka/images/ikona.png">

Poniżej wymieniono niektóre zalety stosowania funkcji plugins_url()
podczas ustalania adresów URL plików wtyczki:

-   obsługa katalogu wtyczek mu-plugins;
-   automatyczne wykrywanie SSL, więc po włączeniu obsługi SSL na
    platformie WordPress zwracane adresy URL będą zawierały protokół
    https;
-   używanie stałej WP_PLUGIN_URL, co oznacza możliwość wykrycia
    położenia wtyczki nawet wtedy, kiedy użytkownik przeniósł ją w inne
    miejsce;
-   obsługa funkcji Multisite poprzez użycie stałej WPMU_PLUGIN_URL.

Aktywacja i dezaktywacja funkcji

Platforma WordPress oferuje pewne funkcje, które można wykorzystywać we
wszystkich samodzielnie opracowywanych wtyczkach. W tym podrozdziale
omówiono aktywację i dezaktywację funkcji.

Funkcja aktywacji wtyczki

Funkcja aktywacji wtyczki jest wywoływana (jak można odgadnąć) podczas
aktywacji danej wtyczki na platformie WordPress. Do tego celu służy
funkcja register_activation_hook(). Za pomocą wymienionej funkcji można
skonfigurować pewne opcje domyślne wtyczki. Ponadto funkcja przeprowadza
sprawdzenie, czy używana wersja WordPress jest zgodna z daną wtyczką.
Jak pokazano poniżej, funkcja akceptuje dwa parametry:

    <?php register_activation_hook( $file, $function ); ?> 

Parametry:

-   $file — (ciąg tekstowy, wymagany) — ścieżka dostępu do podstawowego
    pliku wtyczki;
-   $function — (ciąg tekstowy, wymagany) — funkcja, która ma zostać
    wykonana po aktywacji wtyczki.

Poniżej pokazano przykład użycia omawianej funkcji:

    <?php
    register_activation_hook( __FILE__, 'boj_myplugin_install' );
    function boj_myplugin_install() {
        // właściwy kod funkcji
    }
    ?> 

Pierwszy przekazywany funkcji parametr to ścieżka dostępu do pliku
wtyczki — w tym celu używana jest stała __FILE__. Ta stała PHP zawsze
zawiera bezwzględną ścieżkę dostępu do pliku, z którego została
wywołana. Natomiast drugi parametr to unikalna funkcja, która ma zostać
wywołana podczas aktywacji wtyczki.

Po zrozumieniu sposobu działania funkcji register_activation_hook()
warto zobaczyć przykład jej praktycznego użycia. Przedstawiony poniżej
fragment kodu przeprowadza sprawdzenie, czy bieżąca instalacja WordPress
jest zgodna z daną wtyczką.

    <?php
    register_activation_hook( __FILE__, 'boj_install' );
    function boj_install() {
        If ( version_compare( get_bloginfo( 'version' ), '3.1', ' < ' ) ) {
            deactivate_plugins( basename( __FILE__ ) ); // Dezaktywacja wtyczki.
        }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku version-requirement.php.

------------------------------------------------------------------------

Funkcja instalacyjna boj_install() wykorzystuje funkcję get_bloginfo() w
celu pobrania informacji o wersji WordPress wykorzystywanej przez
użytkownika. Następnie za pomocą funkcji PHP o nazwie version_compare()
przeprowadzane jest sprawdzenie, czy zainstalowana jest platforma
WordPress w wersji minimum 3.1. Jeżeli stosowana jest platforma
WordPress w wersji starszej niż 3.1, wtyczka będzie dezaktywowana za
pomocą funkcji deactivate_plugins().

Utworzenie ustawień domyślnych podczas aktywacji

Inne często stosowane rozwiązanie polega na ustawieniu pewnych wartości
domyślnych w trakcie aktywacji wtyczki. Wyobraź sobie, że wtyczka
udostępnia całą stronę opcji. Istnieje więc prawdopodobieństwo, że w
celu zapewnienia prawidłowego działania wtyczki niektóre z dostępnych
opcji muszą być zdefiniowane. Zamiast zmuszać użytkownika do przejścia
na stronę opcji i ich ustawiania, można podczas aktywacji wtyczki
automatycznie skonfigurować opcje domyślne.

    <?php
    register_activation_hook( __FILE__, 'boj_install' );
    function boj_install() {
        $boj_myplugin_options = array(
            'view' => 'grid',
            'food' => 'bacon',
            'mode' => 'zombie'
        );
        update_option( 'boj_myplugin_options', $boj_myplugin_options );
    }
    ?> 

Powyższy przykładowy fragment kodu w trakcie aktywacji wtyczki tworzy
tabelę opcji domyślnych, a następnie przechowuje ją na platformie
WordPress. Temat tworzenia i zapisywania opcji na platformie WordPress
został szczegółowo przedstawiony w rozdziale 7.

Funkcja dezaktywacji wtyczki

Istnieje również możliwość dezaktywacji wtyczki. Do tego celu służy
funkcja register_ deactivation_hook(), która jest wywoływana, gdy
wtyczka zostaje wyłączona na stronie administracyjnej Wtyczki platformy
WordPress. Także i ta funkcja akceptuje dwa parametry, takie same jak w
przypadku aktywacji funkcji.

    <?php register_deactivation_hook( $file, $function ); ?> 

Parametry:

-   $file — (ciąg tekstowy, wymagany) — ścieżka dostępu do podstawowego
    pliku wtyczki;
-   $function — (ciąg tekstowy, wymagany) — funkcja, która ma zostać
    wykonana po dezaktywacji wtyczki.

Poniżej pokazano przykład użycia omawianej funkcji:

    <?php
    register_deactivation_hook( __FILE__, 'boj_myplugin_uninstall' );
    function boj_myplugin_uninstall() {
        // właściwy kod funkcji
    }
    ?> 

Powyższy fragment kodu powoduje wykonanie funkcji
boj_myplugin_uninstall() podczas dezaktywacji wtyczki na platformie
WordPress.

Dezaktywacja to nie dezinstalacja wtyczki

W funkcji dezaktywacji nie należy umieszczać kodu powodującego
dezinstalację wtyczki w trakcie dezaktywacji. Wyobraź sobie następującą
sytuację: po przypadkowej dezaktywacji wtyczki i jej ponownej aktywacji
okazuje się, że wszystkie ustawienia wtyczki zostały usunięte. Warto
również pamiętać, że oferowana przez WordPress funkcja automatycznego
uaktualnienia powoduje dezaktywację wszystkich wtyczek przed
rozpoczęciem instalacji nowej wersji platformy WordPress.

Metody dezinstalacji

Umieszczenie we wtyczce funkcji dezinstalacji jest łatwym sposobem
usunięcia wszystkich danych, które zostały dodane do platformy WordPress
przez daną wtyczkę. Dodanie tego rodzaju funkcji powinno być
obowiązkowym krokiem podczas tworzenia każdej wtyczki. Nie wymaga to
zbyt dużej ilości pracy, a użytkownicy zyskują pewność, że mogą
całkowicie usunąć wtyczkę z instalacji WordPress, jeśli będą tego
chcieli.

Dlaczego dezinstalacja wtyczki jest konieczna?

Wtyczkę należy traktować jak rodzaj oprogramowania zainstalowanego w
komputerze. Użytkownik może więc oczekiwać, że oprogramowanie oferuje
łatwy sposób usunięcia z komputera zarówno samego oprogramowania, jak i
wszystkich związanych z nim komponentów. Wtyczka WordPress niczym się
tutaj nie wyróżnia — to po prostu oprogramowanie zainstalowane na
platformie WordPress. Jeżeli użytkownik chce pozbyć się wtyczki, należy
dostarczyć mu wszelkie funkcje niezbędne do usunięcia wtyczki z witryny
internetowej zbudowanej na bazie WordPress.

Warto w tym miejscu wziąć pod uwagę dane utworzone przez wtyczkę. Jeśli
przykładowo wtyczka tworzy zdarzenia, takie jak własne rodzaje wpisów
bloga, istnieje prawdopodobieństwo, że użytkownik nie chce usunięcia
tych wszystkich zdarzeń wraz z wtyczką. W takim przypadku należy
wcześniej zapytać użytkownika, czy chce usunąć wszystkie dane powiązane
z wtyczką.

Platforma WordPress oferuje dwie różne metody dezinstalacji wtyczki:
plik uninstall.php oraz zaczep uninstall.

Plik uninstall.php

Pierwsza metoda polega na użyciu pliku uninstall.php. Ta metoda jest
również preferowana, ponieważ kod odpowiedzialny za dezinstalację
wtyczki znajduje się w oddzielnym pliku. Aby skorzystać z tej metody,
należy utworzyć plik o nazwie uninstall.php i umieścić go w katalogu
głównym wtyczki. Jeżeli wymieniony plik istnieje, po wybraniu na stronie
administracyjnej Wtyczki opcji usunięcia danej wtyczki, zawartość pliku
uninstall.php zostanie wykonana. Warto spojrzeć na zawartość
przykładowego pliku uninstall.php:

    <?php
    // Jeżeli plik nie został wywołany z poziomu WordPress, zakończ działanie.
    if( !defined( 'WP_UNINSTALL_PLUGIN' ) )
        exit ();
    // Usunięcie opcji z tabeli opcji.
    delete_option( 'boj_myplugin_options' );
    // Usunięcie wszelkich dodatkowych opcji i własnych tabel.
    ?> 

Pierwszym zadaniem jest sprawdzenie, czy plik uninstall.php został
faktycznie wywołany przez platformę WordPress. W tym celu następuje
weryfikacja stałej WP_UNINSTALL_PLUGIN. Jeżeli plik nie jest wywołany
przez WordPress, następuje natychmiastowe zakończenie jego
przetwarzania. To stanowi rodzaj środka bezpieczeństwa i ma
zagwarantować, że plik uninstall.php będzie wykonany tylko po
zainicjowaniu przez użytkownika procesu usunięcia wtyczki.

Po potwierdzeniu wywołania pliku uninstall.php przez platformę można
przystąpić do usuwania opcji wtyczki z bazy danych. Celem skryptu
powodującego dezinstalację wtyczki jest usunięcie wszelkich śladów
wtyczki z bazy danych WordPress. To obejmuje usunięcie wszystkich opcji
oraz własnych tabel, które ewentualnie mogły zostać utworzone. W tym
pliku nie trzeba umieszczać kodu odpowiedzialnego za rzeczywiste
usunięcie plików lub katalogów wtyczki — tym zajmie się platforma
WordPress po wykonaniu skryptu uninstall.php.

Zaczep uninstall

Druga dostępna metoda dezinstalacji wtyczki polega na użyciu zaczepu
uninstall. Po usunięciu wtyczki w WordPress, jeżeli nie został
dostarczony plik uninstall.php, platforma uruchomi zaczep uninstall (o
ile taki istnieje).

    <?php register_uninstall_hook( $file, $function ); ?> 

Parametry:

-   $file — (ciąg tekstowy, wymagany) — ścieżka dostępu do podstawowego
    pliku wtyczki;
-   $function — (ciąg tekstowy, wymagany) — funkcja, która ma zostać
    wykonana po dezinstalacji wtyczki.

Poniżej pokazano praktyczny przykład użycia funkcji dezinstalacji
wtyczki:

    <?php
    register_activation_hook( __FILE__, 'boj_myplugin_activate' );
    function boj_myplugin_activate() {
        // Rejestracja funkcji odinstalowania.
        register_uninstall_hook( __FILE__, 'boj_myplugin_uninstaller' );
    }
    function boj_myplugin_uninstaller() {
        // Usunięcie wszelkich opcji, tabel itd. utworzonych przez wtyczkę.
        delete_option( 'boj_myplugin_options' );
    }
    ?> 

Jak można zobaczyć, funkcja register_uninstall_hook() powinna być
wywołana podczas aktywacji, a nie w trakcie każdego wczytania wtyczki. W
ten sposób podczas aktywacji wtyczki za pomocą funkcji
register_activation_hook() zostaje dołączony zaczep uninstall. Następnie
w kodzie znajduje się funkcja dezinstalacji wtyczki. Ponownie pierwszy
przekazywany jej parametr to zawartość stałej __FILE__. Natomiast drugi
parametr to funkcja dezinstalacji, która ma być wywołana.

Rzeczywiste procedury dezinstalacji wtyczki zachodzą wewnątrz funkcji
boj_myplugin_ uninstaller(). Trzeba pamiętać, że jeśli w katalogu
głównym wtyczki istnieje plik uninstall.php, to zaczep uninstall nie
zostanie wykonany.

------------------------------------------------------------------------

Uwaga

Warto zwrócić uwagę na użycie metody klasy jako funkcji wywołania
zwrotnego dla zaczepu uninstall. Jest to spowodowane przechowywaniem
przez zaczep odniesienia do zmiennej $this w bazie danych, której
wartość będzie unikalna dla aktualnie wczytanej strony.

------------------------------------------------------------------------

Jak już zasugerowano w tym podrozdziale, używanie zaczepu uninstall
wiąże się z wieloma trudnościami. W celu usunięcia ustawień i opcji
wtyczki podczas jej usuwania z platformy WordPress znacznie lepszym i
łatwiejszym rozwiązaniem jest zastosowanie metody z wykorzystaniem pliku
uninstall.php.

Standardy tworzenia kodu

Podczas tworzenia jakiegokolwiek kodu dla platformy WordPress zalecane
jest stosowanie pewnych zdefiniowanych standardów. To pozwala na
zachowanie spójnego i czytelnego stylu kodu na platformie WordPress,
który dodatkowo będzie łatwy w odczycie.

Oficjalne standardy dotyczące tworzenia kodu na platformie WordPress
zostały przedstawione na stronie
http://codex.wordpress.org/WordPress_Coding_Standards.

Twórz dokumentację kodu

Jednym z najbardziej oczywistych i jednocześnie najczęściej pomijanych
kroków jest umieszczanie komentarzy w kodzie. Umieszczanie komentarzy w
kodzie źródłowym wtyczki jest szybkim i łatwym sposobem udokumentowania
zasady działania danej wtyczki. Komentarze umieszczone w kodzie
źródłowym przynoszą wiele korzyści, a największą z nich jest objaśnienie
prostym językiem przeznaczenia i rzeczywistego sposobu działania danego
fragmentu kodu.

Wyobraź sobie utworzenie wyjątkowo skomplikowanej wtyczki bez
umieszczenia jakiegokolwiek komentarza w jej kodzie źródłowym. Po
upływie kilku miesięcy zrozumienie faktycznego działania kodu może
wymagać sporego wysiłku i dłuższego okresu czasu. Gdy inny programista
będzie przeglądał kod źródłowy pozbawiony komentarzy, zrozumienie jego
logiki i sposobu funkcjonowania zabierze znacznie więcej czasu niż
zrozumienie dobrze udokumentowanego kodu. Komentarze pomogą każdemu, kto
pracuje z kodem źródłowym. Warto więc zawsze umieszczać je w kodzie!

Niemal wszystkie funkcje fabryczne platformy WordPress mają dokumentację
w postaci PHPDoc. PHPDoc to standardowa metoda opisywania w komentarzu
PHP sposobu działania danej funkcji. Poniżej przedstawiono prosty
przykład umieszczonego w komentarzu opisu funkcji w postaci PHPDoc:

    <?php
    /**
     * Krótki opis funkcji.
     *
     * Znacznie dłuższy i dokładniejszy opis funkcji.
     *
     * @param   typ    $zmienna1   Opis
     * @param   typ    $zmienna2   Opis
     * @return  typ    Opis
    */
    function boj_super_function( $varname1, $varname2 ) {
        // Właściwy kod funkcji.
    }
    ?> 

Jak można zobaczyć w powyższym przykładzie, komentarz w postaci PHPDoc
pomaga w opisaniu działania funkcji. Dzięki temu każdy programista
przeglądający tak opisany kod źródłowy wtyczki nie będzie miał żadnych
problemów z szybkim określeniem sposobu działania funkcji, akceptowanych
przez nią parametrów i oczekiwanej wartości zwrotnej. W tym celu nie
będzie nawet musiał analizować kodu funkcji. Tego rodzaju komentarze są
również wykorzystywane przez pewne narzędzia graficzne, np.
PHPDocumentor i PHPXref.

Nazwy zmiennych, funkcji i plików

Nazwy zmiennych i funkcji zawsze powinny być zapisywane małymi literami,
a jako separatora należy używać znaku podkreślenia. Poniżej pokazano
przykład prawidłowego nadania nazw funkcji i zmiennej:

    <?php
    function boj_myplugin_function_name ( $boj_myplugin_variable ) {
        // Właściwy kod funkcji.
    }
    ?> 

W nazwach plików także powinny być stosowane jedynie małe litery. Jednak
w charakterze separatora należy stosować myślnik, a nie znak
podkreślenia. Przykładowo plik wtyczki może mieć nazwę
an-superwtyczka.php.

Apostrof i cudzysłów

Język PHP pozwala na zdefiniowanie ciągu tekstowego za pomocą znaków
apostrofu bądź cudzysłowu. Na platformie WordPress, gdzie tylko istnieje
możliwość, zaleca się stosowanie apostrofów. Jedną z zalet używania
apostrofów jest rzadsza konieczność obsługi w ciągu tekstowych znaków
cudzysłowu stosowanych przez kod HTML. Poniżej pokazano przykład
wyświetlenia odnośnika za pomocą metody wykorzystującej apostrofy:

    <?php
    echo '<a href="http://przyklad.pl/">Odwiedź witrynę przyklad.pl</a>';
    ?> 

Podczas łączenia ciągów tekstowych w PHP można wykorzystać znaki
cudzysłowu. Poniżej przedstawiono prosty przykład wstawienia zmiennej do
adresu URL witryny internetowej:

    <?php
    $boj_myplugin_website = 'http://przyklad.pl/';
    echo "<a href='$boj_myplugin_website'>Odwiedź witrynę przyklad.pl</a> ";?> 

W zmiennej $boj_myplugin_website należy podać adres URL, który ma zostać
umieszczony w odnośniku HTML. Kolejny krok to przygotowywanie ciągu
tekstowego zawierającego adres URL i jego wyświetlenie przez polecenie
echo.

Wcięcia

Wcięcia zawsze powinny odzwierciedlać logiczną strukturę kodu. Oznacza
to używanie tabulacji, a nie spacji podczas tworzenia kodu. Poniżej
pokazano przykład kiepskiego sposobu stosowania wcięć w poleceniu if:

    if ( warunek ) {
    echo 'Tak';
    } elseif ( warunek2 ) {
    echo 'Nie';
    } 

Logika w powyższym fragmencie kodu jest trudna do wychwycenia, ponieważ
brakuje wcięć, które logicznie odzwierciedlałyby strukturę polecenia if.
Teraz warto spojrzeć na ten sam przykład kodu, ale z zastosowaniem
prawidłowych wcięć:

    <?php
    if ( warunek ) {
        echo 'Tak';
    } elseif ( warunek2 ) {
        echo 'Nie';
    }
    ?> 

Zauważ, jak prawidłowe stosowanie wcięć znacznie ułatwia odczyt
powyższego bloku kodu zawierającego polecenie if. Wystarczy po prostu
spojrzeć na kod, aby go w pełni zrozumieć. Z tego powodu prawidłowe
stosowanie wcięć jest niezbędne podczas tworzenia kodu.

Styl stosowania nawiasów

Bloki kodu składające się z więcej niż jednego wiersza zawsze powinny
być umieszczane w nawiasach. Sam nawias otwierający należy umieszczać w
tym samym wierszu, w którym znajduje się dane polecenie warunkowe. Warto
spojrzeć na przykład prawidłowego stosowania nawiasów:

    <?php
    if ( warunek ) {
        akcja1();
        akcja2();
    } elseif ( warunek2 || warunek3 ) {
        akcja3();
        akcja4();
    } else {
       akcja_domyslna();
    }
    ?> 

W wyjątkowo długim bloku kodu dobrym rozwiązaniem jest umieszczenie
krótkiego komentarza za nawiasem zamykającym ten blok, aby od razu było
wiadomo, który blok kodu jest zamykany przez dany nawias:

    <?php
    if ( warunek ) {
        akcja1();
        akcja2();
    } elseif ( warunek2 || warunek3 ) {
        akcja3();
        akcja4();
    } else {
       akcja_domyslna();
    } // Koniec bloku polecenia warunkowego.
    ?> 

Używanie spacji

Spacje zawsze powinny być używane po przecinku oraz po obu stronach
operatorów logicznych i przypisania. Poniżej pokazano kilka różnych
przykładów prawidłowego stosowania spacji:

    <?php
    if ( $foo == 34 ) {
        // Właściwy kod.
    }
    foreach ( $foo as $bar ) {
        // Właściwy kod.
    }
    $foo = array( 34, 16, 8 );
    function super_function( $param1 = 'foo', $param2 = 'bar' ) {
        // Właściwy kod.
    }
    ?> 

Warto zwrócić uwagę na spacje użyte w każdym z powyższych przykładów.
Dzięki nim odczyt i zrozumienie kodu staje się łatwiejsze, ponieważ kod
jest czytelny i spójny.

Skrócone znaczniki PHP

W kodzie nie należy korzystać ze skróconych znaczników PHP (<? i ?>),
ponieważ do poprawnego funkcjonowania wymagane jest ich włączenie w
serwerze. W wielu usługach hostingowych są domyślnie wyłączone, co
oznacza, że po aktywacji wykorzystującej je wtyczki witryna internetowa
bazująca na WordPress przestanie działać. Dlatego też kod powinien być
ujęty w standardowe znaczniki PHP, czyli <?php i ?>.

Polecenia SQL

Podczas wykonywania zapytań do bazy danych na platformie WordPress może
wystąpić konieczność samodzielnego tworzenia własnych poleceń SQL w celu
pobierania danych z bazy danych. Polecenia SQL mogą obejmować wiele
wierszy, jeśli wymaga tego poziom skomplikowania polecenia. Choć
polecenia SQL nie rozróżniają wielkości liter, to i tak warto je
zapisywać dużymi literami:

    SELECT uzytkownik FROM tabela1 WHERE stan = 'wlaczony' 

Prawidłowy sposób używania poleceń SQL na platformie WordPress omówiono
w rozdziale 6.

Lista rzeczy do sprawdzenia podczas prac nad wtyczkami

Podczas prac nad nową wtyczką dla platformy WordPress trzeba pamiętać o
wielu rzeczach, aby utworzyć prawidłowe podstawy dla wtyczki.
Wykorzystanie przedstawionej poniżej listy może ułatwić ten proces i
daje pewność opracowania solidnych i prawidłowych fundamentów dla
wtyczki.

-   Ustalenie unikalnej i znaczącej nazwy wtyczki.
    -   Czy nazwa wystarczająco dokładnie oddaje funkcjonalność wtyczki?
    -   Czy potwierdziłeś, że wtyczka o wybranej nazwie nie istnieje w
        oficjalnym katalogu wtyczek?
-   Ustalenie unikalnego prefiksu.
    -   Czy prefiks jest dostatecznie unikalny, aby uniknąć konfliktu z
        innymi wtyczkami?
-   Utworzenie struktury katalogu wtyczki.
    -   Czy wtyczka potrzebuje katalogu dla plików PHP?
    -   Czy wtyczka potrzebuje katalogu dla plików JavaScript?
    -   Czy wtyczka potrzebuje katalogu dla plików CSS?
    -   Czy wtyczka potrzebuje katalogu dla plików graficznych?
-   Utworzenie domyślnych plików wtyczki.
    -   Utwórz podstawowy plik wtyczki o takiej samej nazwie jak nazwa
        katalogu wtyczki.
    -   Utwórz plik uninstall.php przeznaczony dla kodu wykonywanego
        podczas dezinstalacji wtyczki.
-   Utworzenie kodu nagłówka wtyczki.
    -   Określ wyświetlaną nazwę wtyczki.
    -   Dodaj szczegółowy opis przeznaczenia wtyczki.
    -   Umieść poprawne informacje dotyczące wersji wtyczki.
    -   Upewnij się, że podałeś wartości w wierszach Plugin URI i Author
        URI.
-   Dołączenie licencji, na której wtyczka jest dostępna.
    -   Kod zawierający licencję umieść bezpośrednio pod nagłówkiem
        wtyczki.
-   Utworzenie funkcji aktywacji wtyczki.
    -   Czy do prawidłowego działania wtyczka wymaga określonej wersji
        WordPress?
    -   Czy podczas aktywacji wtyczka wymaga ustawionych pewnych opcji
        domyślnych?
-   Utworzenie funkcji dezaktywacji wtyczki.
    -   Czy wtyczka musi przeprowadzić jakiekolwiek operacje w trakcie
        jej dezaktywacji?
-   Utworzenie skryptu uninstall.php wtyczki.
    -   Utwórz plik uninstall.php.
    -   W utworzonym pliku umieść kod wykonywany podczas dezinstalacji
        wtyczki.
-   Odniesienia do plików.
    -   Stosuj poprawne stałe katalogów i funkcje pozwalające na
        określenie ścieżek dostępu do komponentów wtyczki i platformy
        WordPress.

Podsumowanie

W rozdziale omówiono ustanowienie prawidłowych podstaw podczas
opracowywania wtyczek dla platformy WordPress. Stosowanie
przedstawionych tutaj technik ma istotne znaczenie, aby utworzone
wtyczki działały z wszelkimi konfiguracjami WordPress. Umieszczanie
komentarzy w kodzie to również ważny krok, za pomocą komentarzy można
dokładnie opisać funkcję i sposób jej działania. To może w przyszłości
zaoszczędzić programiście wiele czasu, gdy np. po wielu miesiącach
powróci do kodu źródłowego w celu jego uaktualnienia. Ponadto komentarze
ułatwiają odczyt kodu źródłowego innym programistom.

Rozdział 3 Zaczepy

W tym rozdziale:

-   Tworzenie akcji dla zaczepów akcji
-   Tworzenie filtrów dla zaczepów filtrów
-   Używanie zaczepów wewnątrz klas PHP
-   Dodawanie własnych zaczepów do wtyczek
-   Wyszukiwanie zaczepów platformy WordPress

Zaczepy to podstawa platformy WordPress. Umożliwiają twórcom wtyczek
"zaczepienie się" na platformie i zmianę jej sposobu działania bez
konieczności wprowadzania modyfikacji w kodzie tworzącym jądro
platformy. W ten sposób użytkownicy mogą bardzo łatwo przeprowadzać
uaktualnienia do nowszych wersji WordPress, nie tracąc przy tym
modyfikacji oferowanych przez wtyczki.

Jeżeli programista zmodyfikowałby kod tworzący jądro platformy
WordPress, wówczas tak wprowadzone zmiany byłyby utracone po kolejnym
uaktualnieniu platformy — podczas uaktualnienia zmodyfikowane pliki
zostałyby nadpisane ich wersjami ze standardowej instalacji WordPress.
Dzięki zaczepom wtyczki mogą być oddzielone od plików tworzących jądro
WordPress, a tym samym pozostają bezpieczne w trakcie procesu
uaktualniania platformy.

Bez zaczepów wtyczki byłyby pozbawione możliwości modyfikacji sposobu
działania WordPress. Przedstawiony w tym rozdziale system zaczepów
będzie używany w całej książce oraz w niemal w każdej opracowanej przez
Ciebie wtyczce. Po zapoznaniu się z mechanizmem używania zaczepów
będziesz już wiedział, dlaczego WordPress to platforma oferująca tak
potężne możliwości i dlaczego utworzono dla niej tysiące wtyczek
używanych przez miliony użytkowników.

Na platformie WordPress znajdują się dwa podstawowe typy zaczepów, czyli
akcje i filtry. Akcje pozwalają na wykonywanie funkcji w określonym
czasie, natomiast przy użyciu filtrów można manipulować danymi
wyjściowymi przekazywanymi za pomocą zaczepu.

------------------------------------------------------------------------

Uwaga

Zaczepy nie są przeznaczone jedynie dla wtyczek — na platformie
WordPress używa się ich wewnętrznie. Przeglądając dokładnie kod źródłowy
WordPress, znajdziemy wiele przykładów wykorzystywania zaczepów przez
platformę.

------------------------------------------------------------------------

Akcje

Zaczepy akcji pozwalają na wywołanie funkcji w określonym momencie
procesu wczytywania WordPress lub po wystąpieniu zdefiniowanego
zdarzenia. Przykładowo użytkownik może chcieć wywołania pewnej funkcji,
gdy platforma WordPress po raz pierwszy wczyta stronę lub po zapisaniu
wpisu bloga.

Konieczne jest zrozumienie sposobu działania funkcji do_action().
Podczas stosowania zaczepów WordPress wtyczka nie wywołuje wymienionej
funkcji bezpośrednio, ale niemal zawsze będzie ją wywoływała pośrednio.

    <?php
    do_action( $tag, $arg = '' );
    ?> 

Parametry:

-   $tag — nazwa zaczepu akcji.
-   $arg — wartość (lub wartości) przekazywana zarejestrowanej akcji.
    Wygląda to na pojedynczy parametr, ale nie zawsze tak jest. Zaczepy
    akcji mają możliwość przekazania dowolnej liczby parametrów lub
    żadnego. Trzeba sprawdzić kod źródłowy WordPress dla danego zaczepu,
    ponieważ liczba parametrów zależy od konkretnego zaczepu.

Poniżej przedstawiono przykład zaczepu akcji wraz z kilkoma parametrami.

    <?php
    do_action( $tag, $arg_1, $arg_2, $arg_3 );
    ?> 

Teraz warto spojrzeć na zaczep akcji WordPress o nazwie wp_head i sposób
jego używania na tej platformie. Wymieniony zaczep jest wywoływany w
obszarze <head> strony. Platforma WordPress i wtyczki zwykle
wykorzystują wymieniony zaczep w celu dodania informacji metadanych,
arkuszy stylów i skryptów.

    <?php
    do_action( 'wp_head' );
    ?> 

Kiedy powyższy fragment kodu jest wykonywany przez WordPress, najpierw
są wyszukiwane wszystkie akcje zarejestrowane dla zaczepu akcji wp_head.
Następnie znalezione akcje są wykonywane w określonej kolejności. Jak
można zobaczyć w powyższym kodzie, zaczep ma nazwę wp_head, ale nie
przekazuje żadnych dodatkowych parametrów. To sytuacja często spotykana
w przypadku zaczepów akcji.

Poniżej przedstawiono przykład zaczepu akcji przekazującego dwa
dodatkowe parametry.

    <?php
     do_action('save_post', $post_id, $post);
    ?> 

W powyższym fragmencie kodu nazwa zaczepu to save_post, natomiast
przekazywane przez niego parametry to $post_id i $post.

Czym jest akcja?

Z technicznego punktu widzenia akcja jest funkcją PHP. Aby funkcja mogła
zostać uznana za akcję, musi być zarejestrowana dla zaczepu akcji. W
poprzedniej sekcji dowiedziałeś się, czym jest zaczep akcji. Jednak by
zaczep akcji służył do wielu zadań, konieczne jest zarejestrowanie
akcji.

Tutaj z pomocą przychodzą wtyczki. Programista przygotowuje własne
funkcje (akcje), które będą wykonywały określone zadania po wywołaniu
zaczepu akcji. W tym celu używa się funkcji add_action().

    <?php
    add_action( $tag, $function, $priority, $accepted_args );
    ?> 

Parametry:

-   $tag — nazwa zaczepu akcji wykonującego funkcję opracowaną przez
    programistę.
-   $function — nazwa Twojej funkcji wywoływanej przez WordPress.
-   $priority — liczba całkowita określająca kolejność, w jakiej jest
    wywoływana akcja. Gdy nie będzie podana żadna wartość, domyślnie
    zostanie użyta wartość 10. Im wartość niższa, tym wcześniej funkcja
    zostanie wywołana. Analogicznie, im wyższa wartość, tym późniejsze
    wywołanie akcji.
-   $accepted_args — liczba parametrów, które zaczep akcji przekaże
    Twojej funkcji. Domyślnie przekazywany jest tylko jeden parametr.

Zaczepy akcji nie są ograniczone jedynie do pojedynczej akcji. Wtyczka
może więc dodać wiele funkcji do pojedynczego zaczepu akcji. Inne
wtyczki, a nawet kod samej platformy WordPress, bardzo często dodają
funkcje do tego samego zaczepu.

Warto teraz spojrzeć na praktyczny przykład użycia zaczepu akcji. Jednym
z częściej używanych jest wp_footer wywoływany na końcu strony przez
motyw WordPress wybrany przez użytkownika. Ogólnie rzecz biorąc,
wymieniony zaczep jest wywoływany tuż przed zamykającym znacznikiem
</body> w kodzie HTML. W przedstawionym poniżej fragmencie kodu
następuje zarejestrowanie dla zaczepu wp_footer akcji, która powoduje
umieszczenie w stopce komunikatu zdefiniowanego przez użytkownika.

    <?php
    add_action( 'wp_footer', 'boj_example_footer_message', 100 );
    function boj_example_footer_message() {
        echo 'Ta witryna została zbudowana na bazie <a href="http://pl.wordpress.org"
        title="WordPress - platforma do publikacji bloga">WordPress</a>.';
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-example-footer-message.php.

------------------------------------------------------------------------

Należy dokładnie przyjrzeć się sposobowi użycia funkcji add_action() w
powyższym fragmencie kodu.

    <?php
    add_action( 'wp_footer', 'boj_example_footer_message', 100 );
    ?> 

Pierwszy parametr to nazwa zaczepu (wp_footer). Drugim jest wywołanie
zwrotne własnej funkcji (boj_example_footer_message()). Natomiast trzeci
parametr to priorytet (100). Ta funkcja będzie prawdopodobnie wywołana
znacznie później niż inne zarejestrowane dla wp_footer, ponieważ jej
priorytet wynosi 100. Po zmianie wartości priorytetu na 1 byłaby
wywołana znacznie wcześniej.

------------------------------------------------------------------------

Uwaga

Warto zwrócić uwagę na fakt, że z wielu różnych powodów dany zaczep może
być wywołany więcej niż tylko jednokrotnie. Wszystkie akcje
zarejestrowane dla takiego zaczepu będą wywoływane podczas każdego
wywołania zaczepu.

------------------------------------------------------------------------

Funkcje zaczepu akcji

Dotychczas przedstawiono dwie podstawowe funkcje zaczepu akcji:
do_action() i add_action(). Do pracy z zaczepami akcji platforma
WordPress oferuje także inne funkcje, które mogą być użyteczne w
tworzonych wtyczkach.

do_action_ref_array()

Funkcja do_action_ref_array() działa podobnie jak do_action(), a różnica
polega na sposobie przekazywania argumentów. Zamiast przekazywać wiele
wartości opcjonalnych w postaci parametrów dodatkowych, funkcja ta
przekazuje tablicę argumentów. Wymieniona tablica argumentów jest
jednocześnie parametrem wymaganym. Celem tej funkcji jest przekazanie
obiektu przez referencję do akcji dodanej do określonego zaczepu.
Oznacza to, że akcja może zmienić sam obiekt bez jego zwracania.

    <?php
    do_action_ref_array( $tag, $args );
    ?> 

Parametry:

-   $tag — nazwa zaczepu akcji.
-   $arg — tablica argumentów przekazywana akcjom zarejestrowanym dla
    danego zaczepu. Ogólnie rzecz biorąc, będzie to obiekt, który może
    być zmieniony przez akcję.

Warto teraz spojrzeć na przykład wywoływania przez WordPress funkcji
do_action_ref_array(). Przedstawiony poniżej fragment kodu pokazuje
zaczep akcji pre_get_posts. Ten zaczep jest wywoływany przez platformę
WordPress przed wczytaniem postów z bazy danych i pozwala wtyczkom na
zmianę sposobu pobierania postów.

    <?php
    do_action_ref_array( 'pre_get_posts', array( &$this ) );
    ?> 

Jak można zobaczyć, nazwa zaczepu pre_get_posts jest pierwszym
parametrem. Natomiast drugi parametr to tablica argumentów używanych
podczas pobierania wpisów bloga z bazy danych. Zaczep ten pozwala na
wykonywanie kodu na podstawie przekazanej tablicy argumentów.

Przypuśćmy, że chcesz na stronie głównej bloga umieścić losowo wybrane
wpisy, zamiast stosować domyślną kolejność według daty ich publikacji. W
takim przypadku należy zarejestrować akcję dla wymienionego zaczepu
akcji, a następnie zmienić kolejność wyświetlania wpisów bloga.

    <?php
    add_action( 'pre_get_posts', 'boj_randomly_order_blog_posts' );
    function boj_randomly_order_blog_posts( $query ) {
        if ( $query->is_home && empty( $query->query_vars['suppress_filters'] ) )
            $query->set( 'orderby', 'rand' );
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-random-blog-posts.php.

------------------------------------------------------------------------

remove_action()

Funkcja remove_action() pozwala na usunięcie akcji wcześniej dodanej do
zaczepu. Zazwyczaj usuwane są akcje domyślnie dodane przez platformę
WordPress. W celu usunięcia akcji musiała ona wcześniej zostać dodana za
pomocą funkcji add_action(). Jeżeli kod zostanie uruchomiony przed
zarejestrowaniem akcji, wskazana akcja nie zostanie usunięta z zaczepu.

Wartością zwrotną funkcji jest true, gdy akcja zostanie usunięta z
zaczepu, lub false, jeśli nie udało się usunąć akcji z zaczepu.

    <?php
    remove_action( $tag, $function_to_remove, $priority, $accepted_args );
    ?> 

Parametry:

-   $tag — nazwa zaczepu akcji, z którego ma zostać usunięta
    zarejestrowana dla niego akcja.
-   $function_to_remove — nazwa funkcji dodanej wcześniej do zaczepu i
    teraz przeznaczonej do usunięcia.
-   $priority — priorytet ustalony podczas wywołania funkcji
    add_action(). Wartością domyślną jest 10.
-   $accepted_args — liczba parametrów, które zaczep akcji przekazuje
    funkcji. Domyślnie przekazywany jest tylko jeden parametr.

Aby operacja usunięcia akcji z zaczepu zakończyła się powodzeniem,
parametry $tag, $function_ to_remove i $priority muszą dokładnie
odpowiadać wartościom tych parametrów użytych w funkcji do_action(). W
przeciwnym razie akcja nie zostanie usunięta, a wartością zwrotną
funkcji remove_action() będzie false.

Warto przyjrzeć się jednej z domyślnych akcji platformy WordPress o
nazwie rel_canonical. Wymieniona akcja powoduje dodanie kanonicznego
łącza między znacznikiem otwierającym <head> i zamykającym </head> na
stronie.

    <?php
    add_action( 'wp_head', 'rel_canonical' );
    ?> 

W celu usunięcia akcji funkcji remove_action() trzeba użyć we wtyczce.
Konieczne jest zdefiniowanie parametrów $tag i $function_to_remove. W
omawianym przykładzie nie trzeba dodawać parametru $priority, ponieważ
podczas definiowania akcji priorytet nie został podany.

    <?php
    remove_action( 'wp_head', 'rel_canonical' );
    ?> 

Istnieje możliwość usunięcia dowolnej akcji dodanej przez platformę
WordPress, wtyczkę lub motyw we wtyczce. Ogólnie rzecz biorąc,
najczęściej usuwane będą akcje w WordPress. Wiele akcji domyślnych
zdefiniowano w pliku wp-includes/default-filters.php. Przejrzenie tego
pliku pozwala programiście na poznanie ogólnego sposobu używania
zaczepów na platformie WordPress.

remove_all_actions()

W niektórych wtyczkach może wystąpić konieczność usunięcia wszystkich
akcji dla danej wartości tag lub wszystkich akcji dla danej wartości tag
i priorytetu. Funkcja remove_all_actions() pozwala na wykonanie takiego
zadania za pomocą pojedynczego wiersza kodu zamiast używania wielu
wywołań funkcji remove_action().

    <?php
    remove_all_actions( $tag, $priority );
    ?> 

Parametry:

-   $tag — nazwa zaczepu akcji, z którego mają zostać usunięte
    zarejestrowane dla niego akcje.
-   $priority — priorytet akcji przeznaczonych do usunięcia. To parametr
    opcjonalny i jego wartością domyślną jest false. Po ustawieniu tego
    parametru usunięte zostaną tylko akcje o wskazanym priorytecie.

W przedstawionym poniżej fragmencie kodu następuje usunięcie wszystkich
akcji z zaczepu wp_head niezależnie od ich priorytetu.

    <?php
    remove_all_actions( 'wp_head' );
    ?> 

Jeżeli usunięte mają być jedynie akcje o wskazanym priorytecie, trzeba
podać wartość drugiego parametru ($priority). W celu usunięcia z zaczepu
wp_head wszystkich akcji o priorytecie 1 trzeba użyć poniższego
fragmentu kodu:

    <?php
    remove_all_actions( 'wp_head', 1 );
    ?> 

------------------------------------------------------------------------

Ostrzeżenie

Podczas korzystania z tej funkcji należy zachować ostrożność. Inne
wtyczki lub motywy mogły dodać akcje, o których możesz nawet nie
wiedzieć. W takim przypadku użycie funkcji remove_all_actions() przez
Twoją wtyczkę doprowadzi do sytuacji, że funkcje oczekiwane przez
użytkowników nie będą działały. Najlepszym rozwiązaniem jest zachowanie
maksymalnej dokładności w kodzie, co w większości przypadków oznacza
użycie funkcji remove_action().

------------------------------------------------------------------------

has_action()

Czasami przed wykonaniem kodu może wystąpić konieczność sprawdzenia, czy
zaczep ma jakiekolwiek akcje lub czy określone akcje zostały
zarejestrowane dla danego zaczepu. Funkcja has_action() to funkcja
warunkowa pozwalająca na sprawdzenie obu wymienionych wcześniej
sytuacji.

    <?php
    has_action( $tag, $function_to_check );
    ?> 

Parametry:

-   $tag — nazwa zaczepu akcji, który ma być sprawdzony pod kątem
    zarejestrowanych dla niego akcji.
-   $function_to_check — nazwa sprawdzanej funkcji. To parametr
    opcjonalny i jego wartością domyślną jest false.

Wartością zwrotną funkcji has_action() może być wartość boolowska lub
liczba całkowita. Jeżeli funkcja wymieniona w parametrze
$function_to_check nie została ustawiona, wartością zwrotną będzie true,
o ile do zaczepu zostały dodane akcje, lub false w przeciwnym razie.
Jeżeli natomiast funkcja wymieniona w parametrze $function_to_check
została ustawiona i dodana do zaczepu, wartością zwrotną będzie
priorytet (liczba całkowita). W przeciwnym razie wartością zwrotną
będzie false.

W poniższym fragmencie kodu następuje wyświetlenie komunikatu na
podstawie tego, czy zaczep akcji wp_footer ma jakiekolwiek
zarejestrowane dla niego akcje.

    <?php
    if ( has_action( 'wp_footer' ) )
        echo '<p>Dla zaczepu została zarejestrowana akcja.</p>';
    else
        echo '<p>Dla zaczepu nie została zarejestrowana żadna akcja.</p>';
    ?> 

Teraz warto spojrzeć na akcję dodawaną do zaczepu wp_footer przez
platformę WordPress. Podana funkcja wp_print_footer_scripts() jest
domyślnie rejestrowana dla wymienionego zaczepu.

    <?php
    add_action( 'wp_footer', 'wp_print_footer_scripts' );
    ?> 

W przypadku gdy komunikat ma być wyświetlony na podstawie rejestracji
określonej akcji dla zaczepu, należy użyć poniższego fragmentu kodu.

    <?php
    if ( has_action( 'wp_footer', 'wp_print_footer_scripts' ) )
        echo '<p> Funkcja wp_print_footer_scripts jest zarejestrowana
          dla zaczepu wp_footer.</p>';
    ?> 

did_action()

Funkcja did_action() pozwala wtyczce na sprawdzenie, czy zaczep akcji
został już wykonany, oraz na zliczenie liczby jego wykonań. To również
oznacza, że pewne zaczepy akcji są wywoływane kilkakrotnie podczas
wczytywania pojedynczej strony.

    <?php
    did_action( $tag );
    ?> 

Parametry:

-   $tag — nazwa zaczepu akcji, który ma być sprawdzony.

Wartością zwrotną funkcji jest liczba informująca o ilości wywołań
danego zaczepu bądź wartość false, jeśli zaczep nie został jeszcze
wywołany. Najczęstszym sposobem użycia tej funkcji jest sprawdzenie, czy
zaczep został wywołany, a następnie wykonanie kodu na podstawie wartości
zwrotnej did_action().

W poniższym fragmencie kodu następuje zdefiniowanie stałej PHP, jeśli
zaczep plugins_loaded został już wywołany.

    <?php
    if ( did_action( 'plugins_loaded' ) )
        define( 'BOJ_MYPLUGIN_READY', true );
    ?> 

register_activation_hook i register_deactivation_hook

W platformie WordPress umieszczono dwie funkcje służące do rejestracji
zaczepów akcji podczas aktywacji i dezaktywacji poszczególnych wtyczek.
Pod względem technicznym obie funkcje są przeznaczone do tworzenia
własnych zaczepów i zostały dokładnie omówione w rozdziale 2. książki.

Najczęściej używane zaczepy akcji

Platforma WordPress oferuje wiele zaczepów akcji, ale niektóre z nich są
używane częściej od pozostałych. Znajomość tych zaczepów może pomóc w
przygotowaniu solidnych podstaw dla tworzonych wtyczek.

plugins_loaded

Dla twórcy wtyczek zaczep akcji plugins_loaded będzie prawdopodobnie
najważniejszy. Jest on wywoływany po wczytaniu większości plików
WordPress, ale jeszcze przed rozpoczęciem wykonywania dołączanych
funkcji. W większości wtyczek żaden kod nie powinien być wykonany przez
wywołaniem wymienionego zaczepu. Zaczep plugins_loaded jest wykonywany
po wczytaniu przez WordPress wszystkich wtyczek aktywowanych przez
użytkownika. To także najwcześniejszy zaczep wtyczki, który może być
użyty przez programistę w trakcie procesu wczytywania.

Wtyczka WordPress powinna przeprowadzać swoją konfigurację w zaczepie
plugins_loaded. Inne akcje również powinny być dodane przez funkcję
wywołania zwrotnego użytą w wymienionym zaczepie.

W przedstawionym poniżej fragmencie kodu używana jest akcja
boj_example_footer_message() utworzona wcześniej w tym rozdziale.
Zamiast wywoływać ją oddzielnie, należy ją dodać do akcji
konfiguracyjnej, która jest zarejestrowana dla zaczepu plugins_loaded.

    <?php
    add_action( 'plugins_loaded', 'boj_footer_message_plugin_setup' );
    function boj_footer_message_plugin_setup() {
        /* Dodanie akcji wyświetlającej komunikat w stopce. */
        add_action( 'wp_footer', 'boj_example_footer_message', 100 );
    }
    function boj_example_footer_message() {
        echo 'Ta witryna została zbudowana na bazie <a href="http://pl.wordpress.org"
        title="WordPress - platforma do publikacji bloga ">WordPress</a> .';
    }
    ?> 

------------------------------------------------------------------------

Uwaga

Dobrą praktyką jest utworzenie funkcji konfiguracyjnej i zarejestrowanie
jej dla zaczepu plugins_loaded. W ten sposób można zagwarantować, że na
skutek niewczytania określonych funkcji WordPress nie zostaną
wprowadzone żadne błędy.

------------------------------------------------------------------------

init

Zaczep init jest wywoływany tuż po przeprowadzeniu większości
konfiguracji WordPress. W wymienionym zaczepie platforma WordPress
dodaje ogromną ilość funkcji, m.in. rejestruje typy wpisów bloga oraz
inicjalizuje widgety domyślne.

Ponieważ na tym etapie prawie wszystko na platformie WordPress jest już
skonfigurowane, tworzona przez Ciebie wtyczka może wykorzystać ten
zaczep do przeprowadzania wszelkich zadań, które musi wykonać, gdy będą
już dostępne wszystkie informacje WordPress.

W przedstawionym poniżej fragmencie kodu użytkownicy otrzymują możliwość
tworzenia fragmentów stron. Odbywa się to w zaczepie init, ponieważ typ
wpisu bloga "page" jest na tym etapie utworzony za pomocą funkcji
add_post_type_support(). Więcej informacji na ten temat można znaleźć w
rozdziale 11.

    <?php
    add_action( 'init', 'boj_add_excerpts_to_pages' );
    function boj_add_excerpts_to_pages() {
        add_post_type_support( 'page', array( 'excerpt' ) );
    }
    ?> 

admin_menu

Zaczep admin_menu jest wywoływany jedynie podczas wczytywania stron
administracyjnych. Kiedy opracowywana przez Ciebie wtyczka działa
bezpośrednio na stronach administracyjnych, do wykonywania kodu należy
używać właśnie tego zaczepu.

Przedstawiony poniżej fragment kodu powoduje dodanie podmenu o nazwie
Ustawienia BOJ do menu Ustawienia w kokpicie administracyjnym WordPress
(więcej informacji na ten temat można znaleźć w rozdziale 7.).

    <?php
    add_action( 'admin_menu', 'boj_admin_settings_page' );
    function boj_admin_settings_page() {
        add_options_page(
            'Ustawienia BOJ',
            'Ustawienia BOJ',
            'manage_options',
            'boj_admin_settings',
            'boj_admin_settings_page'
        );
    }
    ?> 

template_redirect()

Zaczep akcji template_redirect jest bardzo ważny, ponieważ wskazuje
punkt, w którym platforma WordPress zna już stronę wyświetlaną przez
użytkownika. Jest wywoływany tuż przed wybraniem szablonu motywu dla
określonej strony. Ten zaczep jest wywoływany jedynie na stronach
witryny dostępnych publicznie, ale nie na stronach administracyjnych. To
odpowiedni zaczep do wykorzystania, gdy trzeba wczytać kod przeznaczony
jedynie dla określonych stron.

W poniższym fragmencie kodu następuje wczytanie pliku arkusza stylów
tylko dla pojedynczego wpisu bloga.

    <?php
    add_action( 'template_redirect', 'boj_singular_post_css' );
    function boj_singular_post_css() {
        if ( is_singular( 'post' ) ) {
            wp_enqueue_style(
                'boj-singular-post',
                'boj-example.css',
                false,
                0.1,
                'screen'
            );
        }
    }
    ?> 

wp_head

Na wyświetlanych stronach witryny motyw WordPress wywołuje funkcję
wp_head(), która z kolei wywołuje zaczep wp_head. Wtyczki wykorzystują
zaczep do umieszczania kodu HTML między znacznikami otwierającym <head>
i zamykającym </head>.

W przedstawionym poniżej fragmencie kodu na stronie zostaje umieszczony
znacznik <meta> wraz z opisem strony.

    <?php
    add_action( 'wp_head', 'boj_front_page_meta_description' );
    function boj_front_page_meta_description() {
        /* Pobranie opisu witryny. */
        $description = esc_attr( get_bloginfo( 'description' ) );
        /* Jeżeli opis został podany, wówczas należy wyświetlić znacznik <meta>. */
        if ( !empty( $description ) )
            echo '<meta name="description" content="' . $description . '" />';
    }
    ?> 

------------------------------------------------------------------------

Ostrzeżenie

Wiele wtyczek nieprawidłowo wykorzystuje zaczep akcji wp_head w celu
dodania skryptu JavaScript do nagłówka, zamiast używać funkcji
wp_enqueue_script() (więcej informacji na ten temat znajduje się w
rozdziale 12.). Jedyna sytuacja, w której skrypt JavaScript może zostać
dodany za pomocą wymienionego zaczepu, zachodzi wtedy, gdy skrypt nie
znajduje się w oddzielnym pliku.

------------------------------------------------------------------------

Filtry

Filtry znacznie różnią się od zaczepów akcji i pozwalają na manipulację
danymi wyjściowymi kodu. Zaczepy akcji są odpowiedzialne za wstawianie
kodu, natomiast zaczepy filtrów umożliwiają nadpisywanie kodu
przekazywanego zaczepom przez platformę WordPress. Można więc
powiedzieć, że funkcja "filtruje" dane wyjściowe.

W celu przyswojenia sobie koncepcji zaczepu filtru trzeba najpierw
zrozumieć zasadę działania funkcji WordPress o nazwie apply_filters().

    <?php
    apply_filters( $tag, $value );
    ?> 

Parametry:

-   $tag — nazwa zaczepu akcji filtru.
-   $value — parametr przekazywany wszystkim filtrom zarejestrowanym dla
    zaczepu. Funkcja może również pobrać dowolną liczbę dodatkowych
    parametrów $value w celu ich przekazania filtrom.

Podczas tworzenia filtru trzeba zwrócić uwagę na konieczność zwrócenia
platformie WordPress wartości $value.

Poniżej przedstawiono przykład zaczepu filtru stosowanego przez kod
tworzący jądro WordPress.

    <?php
    apply_filters( 'template_include', $template );
    ?> 

W powyższym fragmencie kodu template_include oznacza nazwę zaczepu
filtru, natomiast $template to nazwa pliku, który może być zmieniony
przez filtry zarejestrowane dla danego zaczepu filtru.

Czym jest filtr?

Filtr to funkcja zarejestrowana dla zaczepu filtru. Sama funkcja pobiera
przynajmniej jeden parametr i zwraca ten parametr po wykonaniu kodu
funkcji. Bez filtru zaczep filtru nie wykonuje żadnego zadania. Istnieje
więc po to, aby programista wtyczek mógł wprowadzać różne zmienne. Tutaj
możliwości jest bardzo wiele, od prostych ciągów tekstowych aż po
tablice wielowymiarowe.

Kiedy zaczep filtru jest wywoływany przez funkcję apply_filters(),
następuje wykonanie wszystkich zarejestrowanych dla niego filtrów. W
celu dodania filtru należy użyć funkcji add_filter():

    <?php
    add_filter( $tag, $function, $priority, $accepted_args );
    ?> 

Parametry:

-   $tag — nazwa zaczepu filtru wykonującego filtry.
-   $function — nazwa tworzonej funkcji filtru przeznaczonej do
    modyfikowania danych wyjściowych.
-   $priority — liczba całkowita określająca kolejność, w jakiej będą
    stosowane filtry. Gdy nie będzie podana żadna wartość, domyślnie
    zostanie użyta wartość 10.
-   $accepted_args — liczba parametrów akceptowanych przez funkcję
    filtru. Wartością domyślną jest 1. Funkcja musi akceptować
    przynajmniej jeden parametr, który będzie zwracany.

Do pojedynczego zaczepu filtru można dodać większą liczbę filtrów. Inne
wtyczki, a nawet kod samej platformy WordPress, bardzo często dodają
filtry do tego samego zaczepu. Zaczepy filtrów nie są ograniczone do
pojedynczego filtru. Warto na to zwrócić uwagę, ponieważ każdy filtr
zawsze musi zwrócić wartość, która będzie użyta przez inne filtry.
Jeżeli funkcja nie zwróci wartości, istnieje niebezpieczeństwo
uszkodzenia funkcji oferowanych zarówno przez platformę WordPress, jak i
inne wtyczki.

Warto teraz spojrzeć na zaczep filtru wp_title na platformie WordPress,
który jest odpowiedzialny za element <title> na stronie.

    <?php
    apply_filters( 'wp_title', $title, $sep, $seplocation );
    ?> 

Parametry:

-   $wp_title — nazwa zaczepu.
-   $title — filtrowany ciąg tekstowy i wartość, która zostanie zwrócona
    platformie WordPress.
-   $sep — ciąg tekstowy wskazujący separator, jaki powinien być
    zastosowany pomiędzy elementami znajdującymi się w <title>.
-   $seplocation — położenie separatora. W przedstawionym poniżej
    przykładzie nie będzie używany.

Poniższy fragment kodu zawiera funkcję filtrującą dane wyjściowe $title
poprzez dołączenie nazwy witryny na końcu nazwy strony.

    <?php
    add_filter( 'wp_title', 'boj_add_site_name_to_title', 10, 2 );
    function boj_add_site_name_to_title( $title, $sep ) {
        /* Pobranie nazwy witryny. */
        $name = get_bloginfo( 'name' );
        /* Dołączenie nazwy do zmiennej $title. */
        $title .= $sep . ' ' . $name;
        /* Zwrot przygotowanego tytułu. */
        return $title;
    }
    ?> 

Oto wiersz kodu odpowiedzialny na platformie WordPress za dodanie filtru
do zaczepu wp_title.

    <?php
    add_filter( 'wp_title', 'boj_add_site_name_to_title', 10, 2 );
    ?> 

Powyższy kod powoduje dodanie filtru o nazwie boj_add_site_name_to_title
do zaczepu filtru wp_title. Priorytet otrzymał wartość 10, a filtr
akceptuje dwa parametry.

Funkcja boj_add_site_name_to_title() manipuluje parametrem $title i
zwraca go z powrotem platformie WordPress. Parametr $sep może być użyty
wewnątrz funkcji, ale nie jest zwracany.

Funkcje zaczepu filtru

Oprócz omówionych wcześniej apply_filters() i add_filter(), platforma
WordPress oferuje znacznie więcej funkcji przeznaczonych do pracy z
zaczepami filtrów.

apply_filters_ref_array()

Funkcja apply_filters_ref_array() działa podobnie do apply_filters(), a
podstawowa różnica polega na sposobie przekazywania argumentów. Zamiast
przekazywać wiele wartości, funkcja ta przekazuje tablicę argumentów.
Obydwa parametry są wymagane. Warto pamiętać, że parametr $args powinien
być przekazywany poprzez referencję, a nie wartość.

    <?php
    apply_filters_ref_array( $tag, $args );
    ?> 

Parametry:

-   $tag — nazwa zaczepu filtru.
-   $args — tablica argumentów przekazywana filtrom zarejestrowanym dla
    danego zaczepu.

Przypuśćmy, że masz do bazy danych skomplikowane zapytanie, którego
zadaniem jest wczytanie wpisów bloga na stronie głównej witryny, a tego
nie umożliwiają standardowe funkcje WordPress. Platforma oferuje jednak
filtr o nazwie posts_results pozwalający na realizację tego zadania.
Poniżej przedstawiono użycie tego filtru w kodzie tworzącym jądro
WordPress.

    <?php
    $this->posts =  apply_filters_ref_array( 
        'posts_results', array( $this->posts, &$this )
    );
    ?> 

Zaczep filtru przekazuje wszystkim zarejestrowanym dla niego filtrom
tablicę obiektów post. Używając przedstawionego poniżej kodu, można
całkowicie nadpisać tę tablicę i zastąpić jej zawartość własnych zbiorem
danych. Platforma WordPress domyślnie pobiera wpisy bloga typu post. W
kodzie pobierane są wpisy bloga typu page, które następnie zostają
umieszczone na stronie głównej witryny.

W poniższym fragmencie kodu użyto klasy wpdb, która dokładniej została
omówiona w rozdziale 6.

    <?php
    add_filter( 'posts_results', 'boj_custom_home_page_posts' );
    function boj_custom_home_page_posts( $results ) {
        global $wpdb, $wp_query;
        /* Sprawdzenie, czy wyświetlana jest strona główna. */
        if ( is_home() ) {
            /* Posty na stronie. */
            $per_page = get_option( 'posts_per_page' );
            /* Pobranie bieżącej strony */
            $paged = get_query_var( 'paged' );
            /* Ustawienie zmiennej $page. */
            $page = ( ( 0 == $paged || 1 == $paged ) ? 1 : absint( $paged ) );
            /* Określenie liczby postów. */
            $offset = ( $page - 1 ) * $per_page . ', ';
            /* Określenie ograniczenia zmiennej $offset oraz liczby wyświetlanych postów. */
            $limits = 'LIMIT '. $offset . $per_page;
            /* Pobranie wyników z bazy danych. */
            $results = $wpdb->get_results( "
                SELECT SQL_CALC_FOUND_ROWS $wpdb->posts.*
                FROM $wpdb->posts
                WHERE 1=1
                AND post_type = 'page'
                AND post_status = 'publish'
                ORDER BY post_title ASC
                $limits
            " );
        }
        return $results;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-custom-home-page.php.

------------------------------------------------------------------------

remove_filter()

Funkcja remove_filter() pozwala wtyczkom na usuwanie filtrów wcześniej
zarejestrowanych dla danego zaczepu filtru. Aby usunięcie filtru
zakończyło się powodzeniem, wymieniona funkcja musi być wywołana po
zarejestrowaniu filtru za pomocą funkcji add_filter().

    <?php
    remove_filter( $tag, $filter_to_remove, $priority, $accepted_args );
    ?> 

Parametry:

-   $tag — nazwa zaczepu filtru, z którego ma zostać usunięty
    zarejestrowany dla niego filtr.
-   $function_to_remove — nazwa filtru dodanego wcześniej do zaczepu i
    teraz przeznaczonego do usunięcia.
-   $priority — priorytet ustalony podczas wywołania funkcji
    add_filter() rejestrującej filtr. Wartością domyślną jest 10.
-   $accepted_args — liczba zaakceptowanych parametrów poprzednio
    zdefiniowanych w wywołaniu funkcji add_filter() rejestrującej filtr.
    Wartością domyślną jest jeden parametr.

Wartością zwrotną funkcji jest true, gdy filtr zostanie usunięty z
zaczepu, lub false, jeśli filtru nie udało się usunąć. Aby operacja
usunięcia filtru z zaczepu zakończyła się powodzeniem, wartości
parametrów $tag, $function_to_remove i $priority muszą dokładnie
odpowiadać wartościom tych parametrów, które zostały użyte w funkcji
add_filter(). W przeciwnym razie filtr nie zostanie usunięty.

Wiele filtrów domyślnych zdefiniowano w pliku
wp-includes/default-filters.php. Jednym z interesujących filtrów jest
funkcja o nazwie wpautop(), która konwertuje dwa znaki nowego wiersza na
akapity w kodzie HTML. Wymieniona funkcja jest wywoływana przez wiele
zaczepów w kodzie tworzącym jądro platformy. Poniżej przedstawiono
przykład wywołania funkcji wpautop() w kodzie tworzącym jądro WordPress.

    <?php
    add_filter( 'the_content', 'wpautop' );
    ?> 

W powyższym fragmencie kodu funkcja wpautop() zostaje zastosowana
względem treści wpisu bloga i konwertuje wszystkie podwójne znaki nowego
wiersza na akapity. Możesz pracować nad projektem klienta wymagającym
zastosowania określonego języka i reguł formatowania. Przykładowo klient
może wymagać, aby treść zawierała automatycznie formatowane akapity.
Usunięcie filtru z zaczepu the_content jest możliwe za pomocą funkcji
remove_filter().

    <?php
    remove_filter( 'the_content', 'wpautop' );
    ?> 

W poprzednim fragmencie kodu zdefiniowano parametry $tag i
$function_to_remove w celu zagwarantowania usunięcia właściwego filtru z
odpowiedniej funkcji. Ponieważ początkowa definicja filtru nie zawierała
podanego parametru, a jego wartością domyślną jest 10, nie ma więc
konieczności używania parametru $priority.

remove_all_filters()

W niektórych wtyczkach może wystąpić konieczność usunięcia wszystkich
filtrów z określonego zaczepu filtru lub wszystkich filtrów
posiadających zdefiniowaną konkretną wartość priorytetu. Funkcja
remove_all_filters() pozwala na wykonanie takiego zadania za pomocą
pojedynczego wiersza kodu.

    <?php
    remove_all_filters( $tag, $priority );
    ?> 

Parametry:

-   $tag — nazwa zaczepu filtru, z którego mają zostać usunięte
    wszystkie zarejestrowane dla niego filtry.
-   $priority — priorytet filtrów przeznaczonych do usunięcia. To
    parametr opcjonalny. Jeżeli nie zostanie podany, z zaczepu zostaną
    usunięte wszystkie filtry.

Załóżmy, że w treści wpisu bloga chcesz usunąć całe formatowanie
domyślne (takie jak automatycznie formatowane akapity) oraz
przeprowadzić konwersję określonych znaków na odpowiadające im encje.
Platforma WordPress dodała do zaczepu the_content kilka filtrów, które
automatycznie się tym zajmują. W celu usunięcia tych filtrów należy użyć
funkcji remove_all_filters() z pojedynczym parametrem w postaci wartości
the_content.

    <?php
    remove_all_filters( 'the_content' );
    ?> 

Jeżeli usunięte mają być jedynie filtry o określonym priorytecie, trzeba
użyć drugiego parametru. W przedstawionym poniżej przykładzie następuje
usunięcie z zaczepu the_content wszystkich filtrów o priorytecie 11.

    <?php
    remove_all_filters( 'the_content', 11 );
    ?> 

has_filter()

Funkcja has_filter() pozwala wtyczkom na sprawdzenie, czy dla zaczepu
zarejestrowano jakiekolwiek filtry lub czy określone filtry zostały
zarejestrowane dla danego zaczepu.

    <?php
    has_filter( $tag, $function_to_check );
    ?> 

Parametry:

-   $tag — nazwa zaczepu filtru, który ma być sprawdzony pod kątem
    zarejestrowanych dla niego filtrów.
-   $function_to_check — nazwa sprawdzanego filtru. To parametr
    opcjonalny.

Wartością zwrotną funkcji has_filter() jest false, jeśli dla zaczepu nie
znaleziono zarejestrowanego wskazanego filtru. Natomiast po znalezieniu
filtru wartością zwrotną będzie true. Gdy parametr $function_to_check
będzie podany, wartością zwrotną będzie priorytet filtru.

W poniższym fragmencie kodu następuje sprawdzenie, czy wskazany filtr
został zarejestrowany dla zaczepu the_content. Następnie na podstawie
wartości zwrotnej funkcji kod wyświetla odpowiedni komunikat.

    <?php
    if ( has_filter( 'the_content' ) )
        echo 'Dla tego zaczepu zarejestrowano przynajmniej jeden filtr.';
    else
        echo 'Dla tego zaczepu nie zarejestrowano żadnych filtrów.';
    ?> 

Jeżeli chcesz sprawdzić, czy dla danego zaczepu został zarejestrowany
konkretny filtr, wtedy musisz podać parametr $function_to_check.
Załóżmy, że chcesz sprawdzić, czy na platformie WordPress włączono
funkcję automatycznego formatowania akapitów w treści postu. Poniższy
fragment kodu wyświetli komunikat, gdy wymieniona funkcja jest włączona.

    <?php
    if ( has_filter( 'the_content', 'wpautop' ) )
        echo 'Treść posiada automatycznie formatowane akapity.';
    ?> 

current_filter()

Funkcja current_filter() podaje nazwę aktualnie wykonanego zaczepu
filtru. Jednak funkcja nie działa po prostu z zaczepami filtrów, może
być stosowana również dla zaczepów akcji i wówczas zwraca nazwę
aktualnego zaczepu akcji lub filtru. Funkcja jest szczególnie użyteczna,
kiedy chcesz używać pojedynczej funkcji do obsługi wielu zaczepów, ale z
zastrzeżeniem, że jej wykonanie zależy od aktualnie wywoływanego
zaczepu.

Załóżmy, że klient wymaga usunięcia określonych słów z tytułów wpisów
bloga oraz ich treści. Ponadto klient zezwala na użycie pewnych słów w
tytule wpisu bloga, ale zestaw tych dozwolonych słów jest nieco inny od
zestawu dla treści postu. W takiej sytuacji można użyć pojedynczej
funkcji do filtrowania zaczepów the_content i the_title — na podstawie
aktualnie wykonywanego zaczepu funkcja current_filter() będzie ustawiała
odpowiedni zestaw słów.

Za pomocą poniższego kodu można zdefiniować tablicę zawierającą
niepożądane słowa, a następnie, w zależności od sytuacji, zastępować je
słowem "Ups!" w tekście.

    <?php
    add_filter( 'the_content', 'boj_replace_unwanted_words' );
    add_filter( 'the_title', 'boj_replace_unwanted_words' );
    function boj_replace_unwanted_words( $text ) {
        /* Jeżeli aktualny zaczep to the_content, ustawiamy dla niego odpowiedni zestaw niepożądanych 
          słów. */
        if ( 'the_content' == current_filter() )
            $words = array( 'bluźnierstwo', 'klątwa', 'diabeł' );
        /* Jeżeli aktualny zaczep to the_title, ustawiamy dla niego odpowiedni zestaw niepożądanych 
          słów. */
        elseif ( 'the_title' == current_filter() )
            $words = array( 'bluźnierstwo', 'klątwa' );
        /* Niepożądane słowo zostaje zastąpione przez "Ups!". */
        $text = str_replace( $words, 'Ups!', $text );
        /* Zwrot zmodyfikowanego tekstu. */
        return $text;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-replace-unwanted-words.php.

------------------------------------------------------------------------

Funkcje szybko zwracające wartość

Bardzo często trzeba utworzyć funkcję przekazującą zaczepowi filtru
często stosowaną wartość, np. true, false lub pustą tablicę. W celu
szybkiego zwrócenia wartości możesz pokusić się o użycie funkcji PHP o
nazwie create_function().

Platforma WordPress zawiera kilka funkcji wykorzystywanych w takich
sytuacjach. W przedstawionym poniżej fragmencie kodu wyłączono metody
kontaktu z użytkownikiem, które są po prostu polami tekstowymi
utworzonymi za pomocą znaczników HTML <input> i wyświetlanymi na
poszczególnych stronach administracyjnych WordPress. W celu wyłączenia
wymienionych pól konieczne jest użycie wartości zwrotnej w postaci
pustej tablicy. Zwykle trzeba dodać wywołanie zaczepu filtru i kod
funkcji.

    <?php
    add_filter( 'user_contactmethods', 'boj_return_empty_array' );
    function boj_return_empty_array() {
        return array();
    }
    ?> 

Tworzenie służącego do tego kodu nie stanowi problemu, jeśli trzeba to
zrobić raz lub dwa. Jednak wydaje się bezsensowne pisanie całej funkcji
w celu zwrócenia pustej tablicy. Dzięki platformie WordPress można to
zrobić łatwiej. Ponieważ zadaniem jest wyłączenie pól, można użyć
funkcji WordPress o nazwie __return_empty_array() w charakterze filtru
szybko zwracającego pustą tablicę. Dlatego też powyższy fragment kodu
można zastąpić poniższym:

    <?php
    add_filter( 'user_contactmethods', '__return_empty_array' );
    ?> 

W tym miejscu ważne jest użycie __return_empty_array(). Platforma
WordPress oczekuje wartości zwrotnej w postaci tablicy, więc zwrócenie
danych w postaci innej niż tablica spowoduje wygenerowanie błędu PHP.

Funkcje WordPress służące do szybkiego zwracania wartości mogą być
użyteczne podczas tworzenia wtyczek. Bardzo ważne jest, aby zawsze
sprawdzić kod tworzący jądro platformy i przekonać się, jaka jest
oczekiwana wartość po zastosowaniu filtru. W każdej sytuacji oczekiwany
jest określony typ wartości zwrotnej:

-   __return_false — zwracana jest wartość boolowska false;
-   __return_true — zwracana jest wartość boolowska true;
-   __return_empty_array — zwracana jest pusta tablica PHP;
-   __return_zero — zwracana jest liczba całkowita 0.

To po prostu kilka funkcji WordPress dostępnych z poziomu wtyczek.
Jeżeli wcześniej tworzyłeś jednowierszowe funkcje przeznaczone jedynie
do zwrócenia pojedynczej wartości zaczepowi filtru, nadal masz możliwość
tworzenia własnych funkcji obsługujących tego rodzaju sytuacje, o ile
wymienione powyżej nie spełniają Twoich potrzeb.

Najczęściej używane zaczepy filtru

Platforma WordPress oferuje programistom setki zaczepów filtrów do
wykorzystania we wtyczkach. Zawężenie tej grupy do jedynie niewielkiej
listy najczęściej używanych nawet w przybliżeniu nie pokazuje
możliwości, jakie mają wtyczki podczas stosowania systemu zaczepów. W
tym punkcie omówiono używanie pewnych najczęściej stosowanych zaczepów
filtrów we własnych wtyczkach.

the_content

Jednym z zaczepów filtru najczęściej używanych przez programistów jest
niewątpliwie the_content. Bez treści witryna internetowa byłaby przecież
bezużyteczna. Najważniejsze jest wyświetlanie treści w witrynie, a w
wielu wtyczkach wykorzystano ten zaczep w celu dodawania różnorodnych
funkcji.

Zaczep the_content przekazuje treść postu wszystkim zarejestrowanym dla
niego filtrom. Następnie filtry manipulują treścią, zwykle dodając do
wpisu bloga formatowanie lub informacje dodatkowe.

Kod przedstawiony poniżej powoduje dodanie listy wpisów bloga
powiązanych z bieżącym na podstawie kategorii wpisu bloga. Wspomniana
lista jest wyświetlana czytelnikowi danego wpisu bloga.

    <?php
    add_filter( 'the_content', 'boj_add_related_posts_to_content' );
    function boj_add_related_posts_to_content( $content ) {
        /* Jeżeli nie jest wyświetlany pojedynczy wpis bloga, wystarczy po prostu zwrócić treść. */
        if ( !is_singular( 'post' ) )
            return $content;
        /* Pobranie kategorii bieżącego wpisu bloga. */
        $terms = get_the_terms( get_the_ID(), 'category' );
        /* Iteracja przez kategorie i umieszczenie ich identyfikatorów w tablicy. */
        $categories = array();
        foreach ( $terms as $term )
            $categories[] = $term->term_id;
        /* Wyszukanie w bazie danych wpisów bloga zaliczanych do tych samych kategorii. */
        $loop = new WP_Query(
            array(
                'cat__in' => $categories,
                'posts_per_page' => 5,
                'post__not_in' => array( get_the_ID() ),
                'orderby' => 'rand'
            )
        );
        /* Sprawdzenie istnienia wpisów bloga powiązanych z aktualnie wyświetlanym. */
        if ( $loop->have_posts() ) {
            /* Początek nieuporządkowanej listy. */
            $content .= '<ul class="related-posts">';
            while ( $loop->have_posts() ) {
                $loop->the_post();
                /* Dodanie tytułu wpisu bloga wraz z odnośnikiem do niego. */
                $content .= the_title(
                    '<li><a href="' . get_permalink() . '">',
                    '</a></li>',
                    false
                );
            }
            /* Koniec nieuporządkowanej listy. */
            $content .= '</ul>';
            /* Wyzerowanie zapytania. */
            wp_reset_query();
        }
        /* Zwrot treści. */
        return $content;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-releated-posts.php.

------------------------------------------------------------------------

the_title

Tytuł wpisu bloga jest niemal tak samo ważny jak jego treść. Z tego
powodu the_title jest popularnym zaczepem filtru. Za pomocą tego zaczepu
można dodać lub całkowicie nadpisać informacje.

Jednym z bardziej użytecznych filtrów stosowanych wraz z the_title jest
funkcja powodująca usunięcie znaczników HTML z tytułu. Użytkownicy
czasami dodają znaczniki, które mogą namieszać w formatowaniu tytułu. Za
pomocą przedstawionego poniżej kodu można usunąć wszystkie znaczniki
dodane przez użytkownika podczas tworzenia tytułu wpisu bloga.

    <?php
    add_filter( 'the_title', 'boj_strip_tags_from_titles' );
    function boj_strip_tags_from_titles( $title ) {
        $title = strip_tags( $title );
        return $title;
    }
    ?> 

comment_text

Zaczep comment_text także się przydaje, ponieważ komentarze najczęściej
odgrywają ważną rolę zarówno na blogu, jak i wielu innych typach witryn.

Za pomocą przedstawionego poniżej fragmentu kodu można sprawdzić, czy
komentarz został dodany przez użytkownika zarejestrowanego w danej
witrynie. Jeżeli użytkownik jest zarejestrowany, można dodać akapit
informujący o roli użytkownika w danej witrynie. (Więcej informacji na
ten temat znajduje się w rozdziale 8.).

    <?php
    add_filter( 'comment_text', 'boj_add_role_to_comment_text' );
    function boj_add_role_to_comment_text( $text ) {
        global $comment;
        /* Sprawdzenie, czy komentarz został dodany przez użytkownika zarejestrowanego w danej witrynie. */
        if ( $comment->user_id > 0 ) {
            /* Utworzenie nowego obiektu użytkownika. */
            $user = new WP_User( $comment->user_id );
            /* Jeżeli użytkownik ma rolę, należy ją również wyświetlić w komentarzu.  */
            if ( is_array( $user->roles ) )
                $text .= '<p>Rola użytkownika: ' . $user->roles[0] .'</p>';
        }
        return $text;
    }
    ?> 

template_include

template_include to rodzaj pojemnika zaczepów filtrów przeznaczonego dla
wielu innych, znacznie dokładniejszych zaczepów filtrów, takich jak:

-   front_page_template,
-   home_template,
-   single_template,
-   page_template,
-   attachment_template,
-   archive_template,
-   category_template,
-   tag_template,
-   author_template,
-   date_template,
-   archive_template,
-   search_template,
-   404_template,
-   index_template.

Jest wywoływany po wybraniu pliku szablonu motywu dla bieżącej strony.
Platforma WordPress wybiera szablon na podstawie strony aktualnie
czytanej przez czytelnika bloga. Istnieje możliwość dodawania filtrów do
każdego poszczególnego zaczepu filtru bądź przeprowadzenia całego
filtrowania jednocześnie na końcu za pomocą zaczepu template_include.

Załóżmy, że chcesz zbudować własny szablon hierarchii w celu
umożliwienia motywom korzystania z szablonów na podstawie kryteriów
zdefiniowanych we wtyczce zamiast stosowania zwykłej hierarchii
szablonów WordPress. To zadanie można wykonać przy użyciu zaczepu
template_include oraz innych wymienionych na powyższej liście.

W przedstawionym poniżej kodzie następuje sprawdzenie, czy istnieje
szablon dla danego wpisu bloga. Domyślnie platforma WordPress najpierw
szuka pliku single.php, a jeśli go nie znajdzie, wtedy poszukuje pliku
index.php. Zdefiniowana w kodzie funkcja szuka pliku o nazwie
single-category-$slug.php ($slug oznacza nazwę kategorii). Jeżeli
użytkownik ma kategorię "art" i w motywie istnieje plik o nazwie
single-category-art.php, wówczas ten plik zostanie użyty zamiast
single.php.

    <?php
    add_filter( 'single_template', 'boj_single_template' );
    function boj_single_template( $template ) {
        global $wp_query;
        /* Sprawdzenie, czy wyświetlany jest pojedynczy wpis bloga. */
        if ( is_singular( 'post' ) ) {
            /* Pobranie identyfikatora wpisu bloga. */
            $post_id = $wp_query->get_queried_object_id();
            /* Pobranie kategorii wpisu bloga. */
            $terms = get_the_terms( $post_id, 'category' );
            /* Iteracja przez kategorie i ich dodanie jako części nazwy pliku. */
            $templates = array();
            foreach ( $terms as $term )
                $templates[] = "single-category-{$term->slug}.php";
            /* Sprawdzenie, czy szablon istnieje. */
            $locate = locate_template( $templates );
            /* Jeżeli szablon został znaleziony, wówczas będzie użyty. */
            if ( !empty( $locate ) )
                $template = $locate;
        }
        /* Zwrot nazwy pliku szablonu. */
        return $template;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-single-template.php.

------------------------------------------------------------------------

Używanie zaczepów z poziomu klasy

W rozdziale przedstawiono wiele przykładów wykorzystania w funkcjach PHP
zaczepów akcji i filtrów. Podczas dodawania metody klasy jako akcji lub
filtru sposób wywołania add_action() i add_filter() jest nieco odmienny.

Ogólnie rzecz biorąc, we wtyczkach zamiast metod klasy najczęściej
stosuje się funkcje jako akcje lub filtry. Jednak zdarzają się sytuacje,
w których użycie klasy przyniesie wtyczce więcej korzyści. Dlatego też
warto wiedzieć, w jaki sposób zarejestrować w klasie metody dla
zaczepów.

Warto spojrzeć na podstawowy sposób rejestracji funkcji dla zaczepu
akcji, który szczegółowo został omówiony we wcześniejszej części
rozdziału.

    <?php
    add_action( $tag, $function_to_add );
    ?> 

Używając w klasie metody, takiej jak $function_to_add, wymieniony
parametr trzeba zmienić w taki sposób, aby był tablicą. Pierwszy
argument tablicy powinien mieć postać &$this, natomiast drugim powinna
być nazwa metody.

    <?php
    add_action( $tag, array(  &$this, $method_to_add ) );
    ?> 

To samo dotyczy również zaczepu filtru. Zwykły sposób dodawania funkcji
do zaczepu filtru jest następujący:

    <?php
    add_filter( $tag, $function_to_add );
    ?> 

Kiedy filtrem jest metoda klasy, trzeba zmodyfikować parametr
$function_to_add.

    <?php
    add_filter( $tag, array(  &$this, $method_to_add ) );
    ?> 

W przedstawionym poniżej kodzie tworzona jest klasa wyposażona w
konstruktor, metodę używaną jako akcję oraz metodę używaną jako filtr.
Metoda add_filters() sprawdza, czy czytelnik bloga aktualnie wyświetla
pojedynczy wpis bloga. Jeżeli tak jest, metoda content() dołącza do
treści wpisu bloga datę jego ostatniej modyfikacji.

    <?php
    class BOJ_My_Plugin_Loader {
        /* Metoda konstruktora dla klasy. */
        function BOJ_My_Plugin_Loader() {
            /* Dodanie metody 'singular_check' do zaczepu 'template_redirect'. */
            add_action( 'template_redirect', array(  &$this, 'singular_check' ) );
        }
        /* Metoda używana w charakterze akcji. */
        function singular_check() {
            /* Jeżeli wyświetlany jest pojedynczy wpis bloga, wówczas można filtrować jego treść. */
            if ( is_singular() )
                add_filter( 'the_content', array(  &$this, 'content' ) );
        }
        /* Metoda używana w charakterze filtru. */
        function content( $content ) {
            /* Pobranie daty ostatniej modyfikacji wpisu bloga. */
            $date = get_the_modified_time( get_option( 'date_format' ) );
            /* Dodanie do treści daty ostatniej modyfikacji wpisu bloga. */
            $content .= '<p>Data ostatniej modyfikacji wpisu bloga: ' . $date . '</p>';
            /* Zwrot treści. */
            return $content;
        }
    }
    $boj_myplugin_loader = new BOJ_My_Plugin_Loader();
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-class-hooks.php.

------------------------------------------------------------------------

Tworzenie własnych zaczepów

Wtyczki mogą wykorzystywać nie tylko fabrycznie wbudowane zaczepy, ale
również umożliwiają budowanie własnych przeznaczonych do używania przez
inne wtyczki i motywy. Utworzenie własnego zaczepu jest szczególnie
użyteczne w kodzie, którego dane wyjściowe można modyfikować.

Do opracowania własnego zaczepu w Twojej wtyczce wykorzystasz jedną z
czterech dostępnych funkcji:

-   do_action(),
-   do_action_ref_array(),
-   apply_filters(),
-   apply_filters_ref_array().

Dwie pierwsze funkcje służą do tworzenia własnych zaczepów akcji,
natomiast dwie kolejne — do tworzenia własnych zaczepów filtrów.

Zalety utworzenia własnego zaczepu

Własne zaczepy zwiększają elastyczność wtyczki i pozwalają na jej dalszą
rozbudowę przez innych programistów. Ponadto własny zaczep umożliwia
podpięcie się do różnych procesów wewnątrz samej wtyczki.

Używanie własnego zaczepu chroni także wtyczkę przed bezpośrednią
modyfikacją przez innych użytkowników. Jest to szczególnie ważne podczas
dostarczania uaktualnień wtyczki — użytkownicy nie tracą samodzielnie
wprowadzonych modyfikacji.

Przykład utworzenia własnego zaczepu akcji

W tym punkcie omówiony zostanie przykład własnego zaczepu akcji:
powstanie funkcja konfiguracyjna wtyczki. Wspomniana funkcja definiuje
stałą, którą będzie można zmodyfikować. W pewnym momencie inne wtyczki
również mogą wykonywać dowolny kod, korzystając z oferowanego zaczepu.

    <?php
    add_action( 'plugins_loaded', 'boj_myplugin_setup' );
    function boj_myplugin_setup() {
        /* Zezwolenie na wywołanie akcji przed innymi funkcjami. */
        do_action( 'boj_myplugin_setup_pre' );
        /* Sprawdzenie, czy zdefiniowano root. */
        if ( !defined( 'BOJ_MYPLUGIN_ROOT_SLUG' ) )
            define( 'BOJ_MYPLUGIN_ROOT_SLUG', 'articles' );
    }
    ?> 

Inne wtyczki lub motywy mogą się podłączyć do boj_myplugin_setup_pre i
wywołać dowolną funkcję. Załóżmy, że trzeba zmienić wartość stałej
BOJ_MYPLUGIN_ROOT_SLUG z articles na papers. W tym celu można utworzyć
własną akcję i zarejestrować ją dla zaczepu.

    <?php
    add_action( 'boj_myplugin_setup_pre', 'boj_define_myplugin_constants' );
    function boj_define_myplugin_constants() {
        define( 'BOJ_MYPLUGIN_ROOT_SLUG', 'papers' );
    }
    ?> 

Przykład własnego zaczepu filtru

Załóżmy, że masz funkcję wyświetlającą listę wpisów bloga na podstawie
przekazanego jej określonego zestawu argumentów. Możesz jednak pozwolić,
by inni użytkownicy mogli filtrować argumenty, a tym samym wyświetlać
wpisy bloga.

W tym przykładzie została utworzona funkcja wyświetlająca dziesięć
najpopularniejszych wpisów bloga wybranych na podstawie liczby
otrzymanych przez nie komentarzy. Funkcja pozwala użytkownikom na
filtrowanie argumentów wpływających na wybór wpisów bloga pobieranych z
bazy danych. W ten sposób filtrowana jest ostatecznie otrzymywana lista
wpisów bloga.

    <?php
    function boj_posts_by_comments() {
        /* Argumenty domyślne. */
        $args = array(
            'post_type' => 'post',
            'posts_per_page' => 10,
            'order' => 'DESC',
            'orderby' => 'comment_count'
        );
        /* Zastosowanie filtrów względem argumentów. */
        $args = apply_filters( 'boj_posts_by_comments_args', $args );
        /* Ustawienie zmiennej danych wyjściowych. */
        $out = '';
        /* Pobranie wpisów bloga z bazy danych na podstawie użytych argumentów. */
        $loop = new WP_Query( $args );
        /* Sprawdzenie, czy wpisy bloga zostały znalezione. */
        if ( $loop->have_posts() ) {
            /* Początek nieuporządkowanej listy. */
            $out .= '<ul class="posts-by-comments">';
            /* Iteracja przez pobrane wpisy bloga. */
            while ( $loop->have_posts() ) {
                $loop->the_post();
                /* Dodanie tytułu wpisu bloga do listy. */
                $out .= the_title( '<li>', '</li>', false );
            }
            /* Koniec nieuporządkowanej listy. */
            $out .= '</ul>';
        }
        /* Zastosowanie filtrów względem ostatecznych danych wyjściowych. */
        $out = apply_filters( 'boj_posts_by_comments', $out );
        /* Wyświetlenie kodu HTML. */
        echo $out;
    }
    ?> 

W celu filtrowania argumentów należy do funkcji
boj_posts_by_comments_args dodać filtr. Jeżeli wartość domyślna liczby
wpisów bloga ma być zmieniona z 10 na 15, można w tym celu wykorzystać
filtr.

    <?php
    add_filter( 'boj_posts_by_comments_args', 'boj_change_posts_by_comments_args' );
    function boj_change_posts_by_comments_args( $args ) {
        /* Zmiana wartości klucza posts_per_page w tablicy. */
        $args['posts_per_page'] = 15;
        /* Zwrot parametru $args. */
        return $args;
    }
    ?> 

Aby filtrować kod HTML ostatecznych danych wyjściowych, należy do
funkcji boj_posts_by_comments dodać filtr. Przykładowo za pomocą
własnego filtru można listę nieuporządkowaną zmienić na uporządkowaną.

    <?php
    add_filter( 'boj_posts_by_comments', 'boj_change_posts_by_comments' );
    function boj_change_posts_by_comments( $out ) {
        /* Zmiana znacznika otwierającego z  < ul >  na  < ol > . */
        $out = str_replace( '<ul', '<ol', $out );
        /* Zmiana znacznika zamykającego z  < /ul >  na  < /ol > . */
        $out = str_replace( '</ul>', '</ol>', $out );
        /* Zwrot przefiltrowanego kodu HTML. */
        return $out;
    }
    ?> 

W jaki sposób wyszukiwać zaczepy?

Przedstawienie pełnej listy wszystkich zaczepów udostępnianych przez
platformę WordPress jest niemal niemożliwe. We wcześniejszej części
rozdziału wymieniono niektóre z najczęściej używanych zaczepów akcji i
filtrów. To była jednak tylko niewielka próbka zaczepów oferowanych
przez platformę WordPress.

Wraz z nowymi wersjami WordPress pojawiają się nowe zaczepy. Śledzenie
zmian wprowadzonych w kodzie tworzącym jądro platformy z wersji na
wersję pomaga w wychwyceniu nowych zaczepów, które można wykorzystywać
we własnych wtyczkach.

Wyszukiwanie zaczepów w kodzie tworzącym jądro WordPress

Jako twórca wtyczek powinieneś zapoznać się z kodem budującym jądro
platformy WordPress. Wyszukiwanie zaczepów jest doskonałym sposobem
analizowania działania platformy. Nie ma lepszego sposobu zrozumienia
działania kodu PHP od rzeczywistej analizy kodu i jego kolejnych
poleceń.

Łatwą techniką wyszukania zaczepów jest otworzenie w ulubionym edytorze
tekstów pliku z katalogu wordpress, a następnie przeprowadzenie operacji
wyszukiwania jednej z czterech wymienionych poniżej nazw funkcji:

-   do_action(),
-   do_action_ref_array(),
-   apply_filters(),
-   apply_filters_ref_array().

Funkcje te zostały omówione wcześniej w tym rozdziale. Każda z nich
tworzy zaczep, więc wyszukując ich nazwy, można znaleźć nowe zaczepy na
platformie WordPress.

Zaczepy zmienne

Szukając zaczepów w kodzie tworzącym jądro platformy WordPress, można
się natknąć na tzw. "zaczepy zmienne". Z reguły nazwą zaczepu jest
statyczny ciąg tekstowy. Jednak nazwa zaczepu zmiennego ulega zmianie na
podstawie określonej zmiennej.

Dobrym przykładem jest tutaj zaczep akcji load-$pagenow. Wartość
zmiennej $pagenow ulega zmianie w zależności od aktualnie wyświetlanej
strony administracyjnej platformy WordPress. Sam zaczep wygląda tak, jak
przedstawiono w poniższym fragmencie kodu.

    <?php
    do_action( "load-$pagenow" );
    ?> 

Wartością zmiennej $pagenow jest nazwa aktualnie wyświetlanej strony.
Przykładowo zaczep nowo opublikowanej strony w sekcji administracyjnej
to load-post-new.php, natomiast zaczep na stronie edycji wpisu bloga to
load-post.php. W ten sposób wtyczki mogą uruchamiać kod jedynie w
przypadku wyświetlania wskazanej strony w sekcji administracyjnej.

W platformie WordPress istnieje kilka zaczepów akcji i filtrów o
zmiennych nazwach. Ogólnie rzecz ujmując, nazwy tych zaczepów ulegają
zmianie i dostarczają programistom kontekstu, co pozwala na wykonanie
kodu jedynie po spełnieniu określonych warunków. Warto o tym pamiętać
podczas wyszukiwania właściwego zaczepu do użycia we własnej wtyczce.

Listy zaczepów

Choć wyszukiwanie zaczepów w kodzie tworzącym jądro platformy może być
bardzo pouczające dla programisty, to czasami znacznie łatwiejsze będzie
sprawdzenie jednej z list zaczepów dostępnych publicznie w internecie.
Listy te w pewnych sytuacjach pozwalają na zaoszczędzenie dużych ilości
czasu oraz mogą dostarczać także opisy zaczepów.

Platforma WordPress oferuje oficjalne listy zaczepów zarówno akcji, jak
i filtrów dostępne na stronach Codex:

-   http://codex.wordpress.org/Plugin_API/Action_Reference,
-   http://codex.wordpress.org/Plugin_API/Filter_Reference.

W rozdziale 18. przedstawiono więcej informacji oraz omówiono narzędzia
przydatne twórcom wtyczek.

Podsumowanie

Zaczep to najważniejszy aspekt budowania wtyczek dla platformy
WordPress. Gdy rozpoczynasz każdy nowy projekt wtyczki, funkcje
oferowane przez wtyczkę są dołączane do WordPress za pomocą zaczepów
akcji i filtrów. To wszystko, czego się nauczyłeś w tym rozdziale,
będziesz mógł wykorzystać w pozostałych rozdziałach książki, ponieważ
zaczepy stanowią integralną część procesu tworzenia wtyczek.

Po poznaniu sposobu działania zaczepów możesz przystąpić do tworzenia
wtyczek.

Rozdział 4 Integracja z platformą WordPress

W tym rozdziale:

-   Tworzenie menu i podmenu
-   Tworzenie widgetów oraz widgetów kokpitu
-   Definiowanie pól metadanych dla treści
-   Projektowanie i nadawanie stylu wtyczce

Integracja wtyczki z platformą WordPress to krok o znaczeniu krytycznym
w procesie tworzenia profesjonalnej wtyczki. Platforma WordPress oferuje
wiele różnych sposobów integracji z wtyczkami, m.in. za pomocą elementów
menu i podmenu, przy użyciu widgetów i widgetów kokpitu, a także z
wykorzystaniem dodanych pól użytkownika na ekranach z treścią.

W tym rozdziale zostanie omówiony temat prawidłowej integracji wtyczki
na wielu obszarach platformy WordPress. Zaprezentowane będą również
dostępne dla wtyczek właściwe projekty i style, których wykorzystanie
gwarantuje, że wtyczki zapewnią użytkownikom spójny wygląd interfejsu
użytkownika.

Dodawanie menu i podmenu

Wiele wtyczek wymaga użycia pewnego rodzaju elementów menu, będących —
ogólnie rzecz biorąc — odnośnikami prowadzącymi na strony ustawień
wtyczki, na których użytkownik może skonfigurować opcje. Platforma
WordPress oferuje dwa sposoby dodawania menu wtyczki: jako menu
najwyższego poziomu oraz jako element podmenu.

Utworzenie menu najwyższego poziomu

Pierwszą omówioną metodą oferowaną przez WordPress będzie menu
najwyższego poziomu, które jest dodawane do listy menu kokpitu
administracyjnego. Przykładem tego rodzaju jest menu Ustawienia. Menu
najwyższego poziomu to rozwiązanie bardzo często stosowane dla wtyczek,
których opcje znajdują się na wielu stronach. W celu zarejestrowania
menu najwyższego poziomu należy użyć funkcji add_menu_page().

    <?php add_menu_page( page_title, menu_title, capability, menu_slug, function,
     icon_url, position ); ?> 

Funkcja add_menu_page() akceptuje wymienione poniżej parametry:

-   page_title — tytuł strony zdefiniowany w znacznikach <title>;
-   menu_title — nazwa menu wyświetlana w kokpicie;
-   capability — minimalne wymagania umożliwiające wyświetlenie menu;
-   menu_slug — nazwa odwołująca się do menu, powinna być unikalna;
-   function — funkcja wywoływana w celu wyświetlenia strony z treścią
    dla wybranego elementu;
-   icon_url — adres URL prowadzący do grafiki używanej w charakterze
    ikony menu;
-   position — położenie, w którym menu powinno zostać wyświetlone.

Warto teraz spojrzeć na przykład utworzenia menu dla wtyczki i zobaczyć,
jak działa cały proces. Kod menu będzie wywołany przez zaczep
admin_menu. To odpowiedni zaczep do wykorzystania podczas tworzenia menu
i podmenu we wtyczce.

    <?php
    add_action( 'admin_menu', 'boj_menuexample_create_menu' );
    function boj_menuexample_create_menu() {
    // Utworzenie własnego menu najwyższego poziomu.
     add_menu_page( 'Strona ustawień wtyczki', 'Przykład menu ustawień',
     'manage_options', __FILE__, 'boj_menuexample_settings_page',
     plugins_url( '/images/wp-icon.png', __FILE__ ) );
    }
    ?> 

Jak można zobaczyć, zaczep admin_menu wywołuje funkcję
boj_menuexample_create_menu(). Kolejnym krokiem jest wywołanie funkcji
add_menu_page() odpowiedzialnej za zarejestrowanie własnego menu na
platformie WordPress. Jako nazwę menu podano Przykład menu ustawień,
minimalne wymagania zdefiniowano jako manage_options (czyli użytkownik
musi być administratorem), a nawet wskazano ikonę dla menu w postaci
pliku graficznego znajdującego się w katalogu /images. Wyświetlone menu
pokazano na rysunku 4.1.

------------------------------------------------------------------------

Uwaga

Menu to funkcja często używana we wtyczkach WordPress; ogólnie rzecz
biorąc, stosowanie menu jest oczekiwane przez użytkowników. Ponadto
dobrym pomysłem jest umieszczenie w opisie wtyczki oraz w dokumentacji
informacji o tym, gdzie można znaleźć ustawienia wtyczki.

------------------------------------------------------------------------

Dodawanie podmenu

Po utworzeniu menu najwyższego poziomu można przystąpić do budowania
kilku podmenu, które są po prostu elementami wyświetlanymi przez menu
najwyższego poziomu. Przykładowo Ustawienia to menu najwyższego poziomu,
podczas gdy element Ogólne wyświetlany w grupie Ustawienia to podmenu. W
celu zarejestrowania podmenu należy użyć funkcji add_submenu_page().

    <?php add_submenu_page( parent_slug, page_title, menu_title, capability,
     menu_slug, function ); ?> 

[]

Rysunek 4.1. Własne menu wyświetlone w kokpicie WordPress

Funkcja add_submenu_page() akceptuje wymienione poniżej parametry:

-   parent_slug — nazwa menu nadrzędnego (poprzednio zdefiniowana w
    parametrze menu_slug);
-   page_title — tytuł strony zdefiniowany w znacznikach <title>;
-   menu_title — nazwa podmenu wyświetlana w kokpicie;
-   capability — minimalne wymagania umożliwiające wyświetlenie podmenu;
-   menu_slug — nazwa odwołująca się do podmenu, powinna być unikalna;
-   function — funkcja wywoływana w celu wyświetlenia strony z treścią
    dla wybranego elementu.

Po poznaniu sposobu definiowania podmenu można do utworzonego wcześniej
menu najwyższego poziomu dodać elementy podmenu.

    <?php
    add_action( 'admin_menu', 'boj_menuexample_create_menu' );
    function boj_menuexample_create_menu() {
    // Utworzenie własnego menu najwyższego poziomu.
     add_menu_page( 'Strona ustawień wtyczki', 'Przykład menu ustawień',
     'manage_options', __FILE__, 'boj_menuexample_settings_page',
     plugins_url( '/images/wp-icon.png', __FILE__ ) );
    // Utworzenie elementów podmenu.
     add_submenu_page( __FILE__, 'Informacje o wtyczce', 'O wtyczce', 'manage_options',
     __FILE__.'_about', boj_menuexample_about_page );
     add_submenu_page( __FILE__, 'Pomoc dla wtyczki', 'Pomoc', 'manage_options',
     __FILE__.'_help', boj_menuexample_help_page );
     add_submenu_page( __FILE__, 'Dezinstalacja wtyczki', 'Dezinstalacja', 
     'manage_options', __FILE__.'_uninstall', boj_menuexample_uninstall_page );
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-custom-menu-plugin.php.

------------------------------------------------------------------------

W powyższym fragmencie kodu następuje utworzenie trzech podmenu dla
przygotowanego wcześniej menu najwyższego poziomu: O wtyczce, Pomoc i
Dezinstalacja (zobacz rysunek 4.2). Każdy z utworzonych elementów
podmenu powoduje wywołanie innej funkcji, która może zawierać kod
przeznaczony do użycia na stronie danego podmenu.

[]

Rysunek 4.2. Elementy podmenu dodane do menu najwyższego poziomu

Dodawanie elementu menu do już istniejącego menu

Jeżeli wtyczka wymaga tylko pojedynczej strony opcji, nie ma
konieczności tworzenia menu najwyższego poziomu. Zamiast tego można po
prostu dodać podmenu do istniejącego już menu, np. do menu Ustawienia.

Platforma WordPress oferuje wiele różnych funkcji służących do dodawania
podmenu do istniejących, domyślnych menu WordPress. Jedną z nich jest
add_options_page(). Poniżej przedstawiono sposób działania tej funkcji
na przykładzie dodania elementu podmenu do menu Ustawienia.

    <?php add_options_page( page_title, menu_title, capability, menu_slug, function);?> 

Funkcja add_options_page() akceptuje wymienione poniżej parametry:

-   page_title — tytuł strony zdefiniowany w znacznikach <title>;
-   menu_title — nazwa podmenu wyświetlana w kokpicie;
-   capability — minimalne wymagania umożliwiające wyświetlenie podmenu;
-   menu_slug — nazwa odwołująca się do podmenu, powinna być unikalna;
-   function — funkcja wywoływana w celu wyświetlenia strony z treścią
    dla wybranego elementu.

W przedstawionym poniżej fragmencie kodu pokazano, jak dodać element
podmenu do menu Ustawienia:

    <?php
    add_action( 'admin_menu', 'boj_menuexample_create_menu' );
    function boj_menuexample_create_menu() {
    // Utworzenie elementu podmenu w menu Ustawienia.
     add_options_page('Strona ustawień wtyczki', 'Przykład menu ustawień',
     'manage_options', __FILE__, 'boj_menuexample_settings_page' );
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-options-page-plugin.php.

------------------------------------------------------------------------

Przedstawiony powyżej kod powoduje dodanie do menu Ustawienia elementu
podmenu o nazwie Przykład menu ustawień (zobacz rysunek 4.3). Jako tytuł
strony podano Strona ustawień wtyczki, minimalne wymagania zdefiniowano
jako manage_options (czyli użytkownik musi być administratorem). Ponadto
zdefiniowano funkcję boj_menuexample_settings_page(), która będzie
wywoływana po kliknięciu tego podmenu.

[]

Rysunek 4.3. Własny element podmenu dodany do menu domyślnego platformy
WordPress

Poniżej wymieniono listę wszystkich dostępnych funkcji dotyczących
podmenu na platformie WordPress:

-   add_dashboard_page() — dodaje podmenu do menu Kokpit;
-   add_posts_page() — dodaje podmenu do menu Wpisy;
-   add_media_page() — dodaje podmenu do menu Media;
-   add_links_page() — dodaje podmenu do menu Odnośniki;
-   add_pages_page() — dodaje podmenu do menu Strony;
-   add_comments_page() — dodaje podmenu do menu Komentarze;
-   add_theme_page() — dodaje podmenu do menu Wygląd;
-   add_plugins_page() — dodaje podmenu do menu Wtyczki;
-   add_users_page() — dodaje podmenu do menu Użytkownicy;
-   add_management_page() — dodaje podmenu do menu Narzędzia;
-   add_options_page() — dodaje podmenu do menu Ustawienia.

W celu użycia dowolnej z wymienionych powyżej funkcji wystarczy jej
nazwę wstawić do przedstawionego wcześniej kodu.

------------------------------------------------------------------------

Uwaga

Jeżeli wtyczka wymaga użycia tylko pojedynczej strony opcji, najlepszym
rozwiązaniem jest dodanie podmenu do już istniejącego menu. Gdy
natomiast wtyczka musi korzystać z więcej niż tylko pojedynczej strony
opcji, wtedy należy utworzyć dla niej menu najwyższego poziomu.

------------------------------------------------------------------------

Tworzenie widgetów

Widgety to doskonały sposób na dostarczenie użytkownikom wtyczki łatwej
metody wyświetlenia informacji bądź danych wtyczki. Platforma WordPress
oferuje API Widget przeznaczone do tworzenia i interakcji z widgetami. W
tym podrozdziale omówiono tworzenie widgetów, dodawanie i zapisywanie
ich opcji, a także wyświetlanie w widgecie informacji dotyczących
wtyczki.

Utworzenie widgetu

Na platformie WordPress wszystkie widgety są budowane za pomocą klasy
WP_Widget. W celu zrozumienia sposobu działania tej klasy warto spojrzeć
na jej ogólny schemat:

    <?php
    class My_Widget extends WP_Widget {
     function My_Widget() {
    // Przetworzenie widgetu.
     }
     function form($instance) {
    // Wyświetlenie formularza widgetu w kokpicie administracyjnym.
     }
     function update($new_instance, $old_instance) {
    // Przetworzenie opcji widgetu, które mają być zapisane.
     }
     function widget($args, $instance) {
    // Wyświetlenie widgetu.
     }
    }
    ?> 

Jak można zobaczyć, klasa WP_Widget zawiera wiele funkcji przeznaczonych
do obsługi widgetu, a każda z nich ma określone przeznaczenie.

Warto teraz przystąpić do utworzenia widgetu dla wtyczki. Ponieważ to
pierwszy widget, pozostaniemy przy prostym tekstowym widgecie, który
zapisze i wyświetli informacje o ulubionej piosence oraz filmie. Ten
prosty przykład ma na celu zademonstrowanie sposobu, w jaki można
zapisywać dane tekstowe w widgecie platformy WordPress.

Na początku użyty będzie zaczep akcji o nazwie widgets_init. Zaczep jest
wywoływany po zarejestrowaniu przez platformę WordPress widgetów
domyślnych.

    <?php
    // Użycie zaczepu akcji widgets_init w celu wykonania własnej funkcji.
    add_action( 'widgets_init', 'boj_widgetexample_register_widgets' );
    // Rejestracja widgetu.
    function boj_widgetexample_register_widgets() {
     register_widget( 'boj_widgetexample_widget_my_info' );
    }
    ?> 

Zaczep widgets_init wywołuje własną funkcję zarejestrowaną dla widgetu;
w omawianym przykładzie to boj_widgetexample_register_widgets().
Kolejnym krokiem jest użycie funkcji register_widget() w celu
rejestracji nowego widgetu. W omawianym przykładzie rejestrowana jest
nazwa klasy boj_widgetexample_widget_my_info(). Wymieniona funkcja
akceptuje pojedynczy parametr, a sama klasa jest rozszerzeniem klasy
WP_Widget. Nazwa klasy może być dowolna, ale powinna być unikalna i
zawsze zawierać opis widgetu. Za pomocą tej funkcji można zarejestrować
dowolną liczbę widgetów.

Po zarejestrowaniu widgetu można przystąpić do konfiguracji jego klasy.

    <?php
    //boj_widgetexample_widget_my_info class
    class boj_widgetexample_widget_my_info extends WP_Widget {
    ?> 

Klasa WP_Widget jest rozszerzana poprzez utworzenie nowej klasy o
unikalnej nazwie zdefiniowanej wcześniej podczas rejestracji widgetu. Po
zdefiniowaniu klasy kolejnym etapem jest rozpoczęcie tworzenia widgetu.

    <?php
    // Przetworzenie widgetu.
     function boj_widgetexample_widget_my_info() {
     $widget_ops = array(
     'classname' => 'boj_widgetexample_widget_class',
     'description' => 'Wyświetla ulubioną piosenkę i film użytkownika.'
     );
     $this->WP_Widget( 'boj_widgetexample_widget_my_info', 'Widget informacyjny',
     $widget_ops );
     }
    ?> 

Najpierw następuje utworzenie nowej tablicy o nazwie $widget_ops
przeznaczonej do przechowywania opcji widgetu. W tablicy tej będą
przechowywane opcje classname i description. Opcja classname to nazwa
klasy dodana do elementu <li> widgetu. Panele boczne domyślnie
wyświetlają wszystkie widgety za pomocą nieuporządkowanej listy. Każdy
poszczególny widget jest elementem wspomnianej listy, więc dodanie opcji
classname i identyfikatora (ID) powoduje, że dla widgetu bardzo łatwo
można utworzyć i zastosować własne style. Opcja description zawiera opis
wyświetlany na ekranie Wygląd/Widgety i jest używana w celu dostarczenia
opisu przeznaczenia widgetu.

Po zbudowaniu tablicy opcji następuje przekazanie jej wartości klasie
WP_Widget. Pierwsza przekazywana wartość to identyfikator elementu listy
zawierającego widget; w omawianym przykładzie to
boj_widgetexample_widget_my_info(). Druga przekazywana wartość to nazwa
widgetu wyświetlana na stronie Widgety. Nazwa widgetu powinna być krótka
i w miarę możliwości dokładnie opisywać widget. Ostatnią przekazywaną
wartością jest zdefiniowana wcześniej tablica opcji.

Kolejnym krokiem jest utworzenie formularza ustawień widgetu. Omawiany
tutaj widget akceptuje trzy wartości: Tytuł, Ulubiony film i Ulubiona
piosenka.

    <?php
    // Zbudowanie formularza ustawień widgetu.
     function form($instance) {
     $defaults = array( 'title' => 'Moje informacje', 'movie' => '', 'song' => '' );
     $instance = wp_parse_args( (array) $instance, $defaults );
     $title = $instance['title'];
     $movie = $instance['movie'];
     $song = $instance['song'];
     ?> 
    <p>Tytuł: <input class="widefat" name="
     <?php echo $this->get_field_name( 'title' ); ?>" type="text"
     value="<?php echo esc_attr( $title ); ?> " /></p> 
    <p>Ulubiony film: <input class="widefat" name="
     <?php echo $this->get_field_name( 'movie' ); ?>" type="text"
     value="<?php echo esc_attr( $movie ); ?>" /></p> 
    <p>Ulubiona piosenka: <textarea class="widefat" name="
     <?php echo $this->get_field_name( 'song' ); ?>" /> 
     <?php echo esc_attr( $song ); ?></textarea></p> 
    <?php
     }
    ?> 

Na początku tworzona jest zmienna $defaults zawierająca wartości
domyślne każdej opcji. W omawianym przykładzie ustawiony zostaje jedynie
domyślny tytuł. Następnie zmienne egzemplarza otrzymują swoje wartości,
tzn. zapisane wcześniej ustawienia widgetu. Jeżeli dany widget został
dopiero dodany do panelu bocznego, nie ma dla niego żadnych zapisanych
ustawień, zatem wartości nie istnieją.

Ostatni fragment kodu ustawień widgetu powoduje wyświetlenie formularza,
który pozwala na pobranie informacji. Dla wszystkich trzech pól
zastosowano standardowe znaczniki pola tekstowego w HTML. Warto zwrócić
uwagę na brak konieczności stosowania znaczników <form> i przycisku
wysyłającego formularz — tym zajmuje się klasa widgetu. Ponadto tekst
wprowadzony w polach zostaje oczyszczony z niebezpiecznych znaków za
pomocą funkcji esc_attr().

Kolejnym krokiem jest zapisanie ustawień widgetu za pomocą funkcji
update() klasy widgetu.

    <?php
    // Zapis ustawień widgetu.
     function update($new_instance, $old_instance) {
     $instance = $old_instance;
     $instance['title'] = strip_tags( $new_instance['title'] );
     $instance['movie'] = strip_tags( $new_instance['movie'] );
     $instance['song'] = strip_tags( $new_instance['song'] );
     return $instance;
     }
    ?> 

Jak można zobaczyć, klasa widgetu zajmuje się zapisem wszystkich danych.
Twoim zadaniem jest po prostu przekazanie nowych wartości dla wszystkich
opcji widgetu. Zawsze trzeba się upewnić o usunięciu niebezpiecznych
znaków z danych podanych przez użytkownika. W omawianym przykładzie do
tego celu użyto funkcji PHP o nazwie strip_tags().

Ostatni fragment kodu jest odpowiedzialny za wyświetlenie gotowego
widgetu. Odbywa się to za pomocą funkcji widget() klasy widgetu.

    <?php
    // Wyświetlenie widgetu.
     function widget($args, $instance) {
     extract($args);
     echo $before_widget;
     $title = apply_filters( 'widget_title', $instance['title'] );
     $movie = empty( $instance['movie'] ) ? ' &nbsp;' : $instance['movie'];
     $song = empty( $instance['song'] ) ? ' &nbsp;' : $instance['song'];
     if ( !empty( $title ) ) { echo $before_title . $title . $after_title; };
     echo '<p>Ulubiony film: ' . $movie . '</p>';
     echo '<p>Ulubiona piosenka: ' . $song . '</p>';
     echo $after_widget;
     }
    ?> 

Pierwszym krokiem jest wyodrębnienie parametru $args. Ta zmienna
przechowuje globalne wartości motywu, takie jak $before_widget i
$after_widget. Wartości mogą być zdefiniowane podczas rejestracji panelu
bocznego oraz w celu dostosowania do własnych potrzeb kodu opakowującego
widget, np. przez dodanie znacznika <div>.

Kolejny krok to ustawienie zmiennej $title przechowującej tytuł widgetu.
Ustawienie tytułu wymaga użycia zaczepu filtru o nazwie widget_title. W
ten sposób inni programiści mogą modyfikować wyświetlany tytuł widgetu,
jeśli będzie trzeba. Ustawienie zmiennych $movie i $song następuje przy
użyciu operatorów trójargumentowych PHP. Innymi słowy, jeśli zmienna
$movie jest pusta, otrzymuje wartość '&nbsp;', w przeciwnym razie
wartością będzie $instance['movie'].

Warto zwrócić uwagę, że kodzie zdefiniowano wszystkie zmienne ustawień
widgetu oraz przypisano im wartości, więc można przystąpić do ich
wyświetlenia. Najpierw wyświetlana jest wartość zmiennej $title. Bardzo
ważne jest, aby zawsze opakowywać tę wartość zmiennymi before_widget i
$after_widget. Wymienione zmienne globalne również mogą być ustawione
przez programistów podczas rejestracji panelu bocznego. Po wyświetleniu
wartości zmiennej $title następuje wyświetlenie tytułu ulubionego filmu
i ulubionej piosenki. Na końcu blok informacji pokazywanych przez widget
trzeba zamknąć wartością zmiennej globalnej $after_widget.

Gratulacje! Właśnie utworzyłeś widget platformy WordPress. Teraz nowo
utworzony widget można umieścić na stronie i wypełnić go ustawieniami,
co pokazano na rysunku 4.4.

Następnie widget można już wyświetlić w panelu bocznym, tak jak pokazano
na rysunku 4.5.

Poniżej przedstawiono pełny kod źródłowy omówionego powyżej widgetu.

    <?php
    /*
    Plugin Name: Przykład wtyczki tworzącej widget
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka tworząca widget na platformie WordPress.
    Version: 1.0
    Author: Brad Williams

[]

Rysunek 4.4. Formularz ustawień omawianego widgetu

[]

Rysunek 4.5. Widget wyświetlony w panelu bocznym

    Author URI: http://wrox.com
    License: GPLv2
    */
    // Użycie zaczepu akcji widgets_init w celu wykonania własnej funkcji.
    add_action( 'widgets_init', 'boj_widgetexample_register_widgets' );
    // Rejestracja widgetu.
    function boj_widgetexample_register_widgets() {
     register_widget( 'boj_widgetexample_widget_my_info' );
    }
    class boj_widgetexample_widget_my_info extends WP_Widget {
    // Przetworzenie widgetu.
     function boj_widgetexample_widget_my_info() {
     $widget_ops = array(
     'classname' => 'boj_widgetexample_widget_class',
     'description' => 'Wyświetla ulubioną piosenkę i film użytkownika.'
     );
     $this->WP_Widget( 'boj_widgetexample_widget_my_info', 'Widget informacyjny',
     $widget_ops );
     }
    // Zbudowanie formularza ustawień widgetu.
     function form($instance) {
     $defaults = array( 'title' => 'Moje informacje', 'movie' => '', 'song' => '' );
     $instance = wp_parse_args( (array) $instance, $defaults );
     $title = $instance['title'];
     $movie = $instance['movie'];
     $song = $instance['song'];
     ?> 
    <p>Tytuł: <input class="widefat" name="
     <?php echo $this->get_field_name( 'title' ); ?>"
     type="text" value="<?php echo esc_attr( $title ); ?>" /></p> 
    <p>Ulubiony film: <input class="widefat" name="
     <?php echo $this->get_field_name( 'movie' ); ?>"
     type="text" value="<?php echo esc_attr( $movie ); ?>" /></p> 
    <p>Ulubiona piosenka: <textarea class="widefat" name="
     <?php echo $this->get_field_name( 'song' ); ?>" /> 
     <?php echo esc_attr( $song ); ?></textarea></p> 
    <?php
     }
    // Zapis ustawień widgetu.
     function update($new_instance, $old_instance) {
     $instance = $old_instance;
     $instance['title'] = strip_tags( $new_instance['title'] );
     $instance['movie'] = strip_tags( $new_instance['movie'] );
     $instance['song'] = strip_tags( $new_instance['song'] );
     return $instance;
     }
    // Wyświetlenie widgetu.
     function widget($args, $instance) {
     extract($args);
     echo $before_widget;
     $title = apply_filters( 'widget_title', $instance['title'] );
     $movie = empty( $instance['movie'] ) ? ' &nbsp;' : $instance['movie'];
     $song = empty( $instance['song'] ) ? ' &nbsp;' : $instance['song'];
     if ( !empty( $title ) ) { echo $before_title . $title . $after_title; };
     echo '<p>Ulubiony film: ' . $movie . '</p>';
     echo '<p>Ulubiona piosenka: ' . $song . '</p>';
     echo $after_widget;
     }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-widget-plugin.php.

------------------------------------------------------------------------

Widget zaawansowany

Po zapoznaniu się z podstawowym sposobem działania widgetów można
przystąpić do utworzenia widgetu znacznie bardziej zaawansowanego. W
przedstawionym poniżej przykładzie powstanie widget pobierający i
wyświetlający wiadomości z kanału RSS. Podczas budowy formularza z
opcjami widgetu można wykorzystać elementy różnego typu. Pierwszym
krokiem jest rejestracja nowego widgetu.

    <?php
    // Użycie zaczepu akcji widgets_init w celu wykonania własnej funkcji.
    add_action( 'widgets_init', 'boj_awe_register_widgets' );
    // Rejestracja widgetu.
    function boj_awe_register_widgets() {
     register_widget( 'boj_awe_widget' );
    }
    ?> 

Nowy widget zostanie zarejestrowany jako boj_awe_widget. Po rejestracji
można zająć się utworzeniem dla widgetu nowej klasy będącej
rozszerzeniem klasy WP_Widget.

    <?php
    class boj_awe_widget extends WP_Widget {
    // Przetworzenie nowego widgetu.
     function boj_awe_widget() {
     $widget_ops = array(
     'classname' => 'boj_awe_widget_class',
     'description' => 'Wyświetla wiadomości RSS wraz z opcjami.'
     );
     $this->WP_Widget( 'boj_awe_widget', 'Zaawansowany widget RSS', $widget_ops );
     }
    ?> 

Podobnie jak we wcześniejszym przykładzie, ustawiona zostaje nazwa i
opis dla nowego widgetu. Nowo tworzony widget nosi nazwę Zaawansowany
widget RSS. Kolejnym krokiem jest utworzenie formularza dla opcji
widgetu.

    <?php
    // Zbudowanie formularza ustawień widgetu.
     function form($instance) {
     $defaults = array(
     'title' => 'Wiadomości RSS',
     'rss_feed' => 'http://strangework.com/feed',
     'rss_items' => '2'
     );
     $instance = wp_parse_args( (array) $instance, $defaults );
     $title = $instance['title'];
     $rss_feed = $instance['rss_feed'];
     $rss_items = $instance['rss_items'];
     $rss_date = $instance['rss_date'];
     $rss_summary = $instance['rss_summary'];
     ?> 
    <p>Tytuł: <input class="widefat" name="
     <?php echo $this->get_field_name( 'title' ); ?>"
     type="text" value="<?php echo esc_attr( $title ); ?>" /></p> 
    <p>Wiadomość RSS: <input class="widefat" name="
     <?php echo $this->get_field_name( 'rss_feed' ); ?>"
     type="text" value="<?php echo esc_attr( $rss_feed ); ?>" /></p> 
    <p>Elementy do wyświetlenia:
    <select name="<?php echo $this->get_field_name( 'rss_items' ); ?>" > 
    <option value="1" <?php selected( $rss_items, 1 ); ?>>1</option> 
    <option value="2" <?php selected( $rss_items, 2 ); ?>>2</option> 
    <option value="3" <?php selected( $rss_items, 3 ); ?>>3</option> 
    <option value="4" <?php selected( $rss_items, 4 ); ?>>4</option> 
    <option value="5" <?php selected( $rss_items, 5 ); ?>>5</option> 
    </select> 
    </p> 
    <p>Wyświetlić datę?: <input name="
     <?php echo $this->get_field_name( 'rss_date' ); ?>"
     type="checkbox" <?php checked( $rss_date, 'on' ); ?> /></p> 
    <p>Wyświetlić podsumowanie?: <input name="
     <?php echo $this->get_field_name( 'rss_summary' ); ?>"
     type="checkbox" <?php checked( $rss_summary, 'on' ); ?> /></p> 
    <?php
     }
    ?> 

Omawiany widget ma pięć opcji pozwalających użytkownikowi na ustawienie
tytułu, kanału wiadomości RSS, liczby elementów do pokazania oraz
ewentualne wyświetlanie daty i podsumowania. Opcje dotyczące tytułu i
kanału wiadomości RSS są standardowymi polami tekstowymi.

Liczba elementów do wyświetlenia to standardowa lista wyboru utworzona w
języku HTML. Warto zwrócić uwagę na użycie funkcji selected()
niezmiernie użytecznej podczas porównywania dwóch wartości w wybranym
polu w celu określenia, czy dana opcja została wybrana. Jeżeli
porównywana wartość jest taka sama jak wcześniej zapisana opcja,
WordPress umieszcza w polu selected='selected', co powoduje, że dana
opcja jest oznaczona jako wybrana.

Opcje pozwalające na wyświetlenie daty i podsumowania to zwykłe pola
wyboru. W tym miejscu użyto funkcji WordPress o nazwie checked().
Wymieniona funkcja działa podobnie do funkcji selected() pod tym
względem, że porównuje dwie wartości w celu sprawdzenia, czy są
identyczne. Różnica między tymi funkcjami polega na tym, że checked()
powoduje dodanie zapisu checked='checked' oznaczającego wybranie danego
pola opcji.

Po zakończeniu konfiguracji widgetu można zapisać jego opcje.

    <?php
    // Zapis ustawień widgetu.
     function update($new_instance, $old_instance) {
     $instance = $old_instance;
     $instance['title'] = strip_tags( $new_instance['title'] );
     $instance['rss_feed'] = strip_tags( $new_instance['rss_feed'] );
     $instance['rss_items'] = strip_tags( $new_instance['rss_items'] );
     $instance['rss_date'] = strip_tags( $new_instance['rss_date'] );
     $instance['rss_summary'] = strip_tags( $new_instance['rss_summary'] );
     return $instance;
     }
    ?> 

Jak zwykle, trzeba się upewnić o usunięciu niebezpiecznych znaków z
danych wprowadzonych przez użytkownika. W omawianym przykładzie odbywa
się to przy użyciu funkcji strip_tags(). Po zapisaniu opcji widgetu
można przystąpić do jego wyświetlenia na podstawie wybranych opcji.

    <?php
    // Wyświetlenie widgetu.
     function widget($args, $instance) {
     extract($args);
     echo $before_widget;
    // Wczytanie ustawień widgetu.
     $title = apply_filters( 'widget_title', $instance['title'] );
     $rss_feed = empty( $instance['rss_feed'] ) ? '' : $instance['rss_feed'];
     $rss_items = empty( $instance['rss_items'] ) ? 2 : $instance['rss_items'];
     $rss_date = empty( $instance['rss_date'] ) ? 0 : 1;
     $rss_summary = empty( $instance['rss_summary'] ) ? 0 : 1;
     if ( !empty( $title ) ) { echo $before_title . $title . $after_title; };
     if ( $rss_feed ) {
    // Wyświetlenie wiadomości RSS.
     wp_widget_rss_output( array(
     'url' => $rss_feed,
     'title' => $title,
     'items' => $rss_items,
     'show_summary' => $rss_summary,
     'show_author' => 0,
     'show_date' => $rss_date
     ) );
     }
     echo $after_widget;
     }
    ?> 

Najpierw trzeba wczytać wszystkie opcje widgetu w celu ustalenia sposobu
wyświetlania wiadomości z kanału RSS. Opcje domyślne są konfigurowane za
pomocą operatora trójargumentowego. Jeśli przykładowo użytkownik włączył
wyświetlanie daty w wiadomości RSS, wartością zmiennej $rss_date będzie
1, natomiast w przeciwnym razie wartością będzie 0.

W ten sposób zakończyłeś tworzenie zaawansowanego widgetu WordPress.
Zbudowany tutaj widget to doskonały przykład pokazujący, jak tworzyć i
ustawiać wiele różnych typów opcji oraz odpowiednio ich używać podczas
wyświetlania widgetu. Poniżej przedstawiono pełny kod źródłowy
omówionego widgetu.

    <?php
    /*
    Plugin Name: Przykład zaawansowanej wtyczki tworzącej widget
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka tworząca widget na platformie WordPress.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    // Użycie zaczepu akcji widgets_init w celu wykonania własnej funkcji.
    add_action( 'widgets_init', 'boj_awe_register_widgets' );
    // Rejestracja widgetu.
    function boj_awe_register_widgets() {
     register_widget( 'boj_awe_widget' );
    }
    class boj_awe_widget extends WP_Widget {
    // Przetworzenie nowego widgetu.
     function boj_awe_widget() {
     $widget_ops = array(
     'classname' => 'boj_awe_widget_class',
     'description' => 'Wyświetla wiadomości RSS wraz z opcjami.'
     );
     $this->WP_Widget( 'boj_awe_widget', 'Zaawansowany widget RSS', $widget_ops );
     }
    // Zbudowanie formularza ustawień widgetu.
     function form($instance) {
     $defaults = array(
     'title' => 'Wiadomości RSS',
     'rss_feed' => 'http://strangework.com/feed',
     'rss_items' => '2'
     );
     $instance = wp_parse_args( (array) $instance, $defaults );
     $title = $instance['title'];
     $rss_feed = $instance['rss_feed'];
     $rss_items = $instance['rss_items'];
     $rss_date = $instance['rss_date'];
     $rss_summary = $instance['rss_summary'];
     ?> 
    <p>Tytuł: <input class="widefat" name="
     <?php echo $this->get_field_name( 'title' ); ?>"
     type="text" value=" <?php echo esc_attr( $title ); ?>" /></p> 
    <p>Wiadomość RSS: <input class="widefat" name="
     <?php echo $this->get_field_name( 'rss_feed' ); ?> "
     type="text" value=" <?php echo esc_attr( $rss_feed ); ?>" /></p> 
    <p>Elementy do wyświetlenia:
    <select name=" <?php echo $this->get_field_name( 'rss_items' ); ?> " > 
    <option value="1" <?php selected( $rss_items, 1 ); ?>>1</option> 
    <option value="2" <?php selected( $rss_items, 2 ); ?>>2</option> 
    <option value="3" <?php selected( $rss_items, 3 ); ?>>3</option> 
    <option value="4" <?php selected( $rss_items, 4 ); ?>>4</option> 
    <option value="5" <?php selected( $rss_items, 5 ); ?>>5</option> 
    </select> 
    </p> 
    <p>Wyświetlić datę?: <input name="
     <?php echo $this->get_field_name( 'rss_date' ); ?> 
     type="checkbox" <?php checked( $rss_date, 'on' ); ?> /></p> 
    <p>Wyświetlić podsumowanie?: <input name="
     <?php echo $this->get_field_name( 'rss_summary' ); ?>"
     type="checkbox" <?php checked( $rss_summary, 'on' ); ?> /></p> 
    <?php
     }
    // Zapis ustawień widgetu.
     function update($new_instance, $old_instance) {
     $instance = $old_instance;
     $instance['title'] = strip_tags( $new_instance['title'] );
     $instance['rss_feed'] = strip_tags( $new_instance['rss_feed'] );
     $instance['rss_items'] = strip_tags( $new_instance['rss_items'] );
     $instance['rss_date'] = strip_tags( $new_instance['rss_date'] );
     $instance['rss_summary'] = strip_tags( $new_instance['rss_summary'] );
     return $instance;
     }
    // Wyświetlenie widgetu.
     function widget($args, $instance) {
     extract($args);
     echo $before_widget;
    // Wczytanie ustawień widgetu.
     $title = apply_filters( 'widget_title', $instance['title'] );
     $rss_feed = empty( $instance['rss_feed'] ) ? '' : $instance['rss_feed'];
     $rss_items = empty( $instance['rss_items'] ) ? 2 : $instance['rss_items'];
     $rss_date = empty( $instance['rss_date'] ) ? 0 : 1;
     $rss_summary = empty( $instance['rss_summary'] ) ? 0 : 1;
     if ( !empty( $title ) ) { echo $before_title . $title . $after_title; };
     if ( $rss_feed ) {
    // Wyświetlenie wiadomości RSS.
     wp_widget_rss_output( array(
     'url' => $rss_feed,
     'title' => $title,
     'items' => $rss_items,
     'show_summary' => $rss_summary,
     'show_author' => 0,
     'show_date' => $rss_date
     ) );
     }
     echo $after_widget;
     }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-advanced-rss-widget.php.

------------------------------------------------------------------------

Tworzenie widgetów kokpitu

Platforma WordPress oferuje również API pozwalające na tworzenie
widgetów kokpitu. Za pomocą wspomnianego API można budować własne
widgety, które będą wyświetlane na ekranie kokpitu WordPress.

W celu utworzenia widgetu kokpitu należy użyć funkcji
wp_add_dashboard_widget(). Poniżej przedstawiono sposób użycia tej
funkcji do utworzenia przykładowego widgetu kokpitu.

    <?php wp_add_dashboard_widget( widget_id, widget_name, callback, control_callback ); ?> 

Funkcja wp_add_dashboard_widget() akceptuje następujące parametry:

-   widget_id — identyfikator CSS dodawany do znacznika <div> widgetu;
-   widget_name — nazwa widgetu wyświetlana w jego nagłówku;
-   callback — funkcja, która będzie wywołana w celu wyświetlenia
    widgetu;
-   control_callback — funkcja, która będzie wywołana w celu obsługi
    elementów i wysyłania.

Poniżej przedstawiono kilka różnych przykładów. Najpierw następuje
utworzenie prostego widgetu kokpitu wyświetlającego użytkownikowi pewne
informacje.

Do utworzenia widgetu kokpitu wykorzystywany jest zaczep akcji o nazwie
wp_dashboard_setup. Zaczep jest wywoływany po zainicjalizowaniu
domyślnych widgetów kokpitu, ale jeszcze przed ich wyświetleniem.

    <?php
    add_action( 'wp_dashboard_setup', 'boj_dashboard_example_widgets' );
    function boj_dashboard_example_widgets() {
    // Utworzenie własnego widgetu kokpitu.
     wp_add_dashboard_widget( 'dashboard_custom_feed',
     'Informacje o wtyczce', 'boj_dashboard_example_display' );
    }
    ?> 

Zaczep wp_dashboard_setup wywołuje funkcję
boj_dashboard_example_widgets(). Następnie użyta została funkcja
wp_add_dashboard_widget() w celu rejestracji nowego widgetu kokpitu.
Widget otrzymuje tytuł Informacje o wtyczce i następuje wywołanie
funkcji boj_dashboard_example_display(). Na tym etapie widget kokpitu
jest już zarejestrowany i można przystąpić do konfiguracji funkcji,
której zadaniem jest wyświetlenie komunikatu użytkownikowi.

    <?php
    function boj_dashboard_example_display()
    {
     echo '<p>Błędy proszę zgłaszać na adres pomoc@przyklad.pl.</p>';
    }
    ?> 

W ten sposób powstał własny widget kokpitu wyświetlający użytkownikowi
prosty komunikat (zobacz rysunek 4.6). API umożliwiające tworzenie
widgetów kokpitu automatycznie dodaje funkcje odpowiedzialne za ich
przeciąganie, rozwijanie, a nawet umieszcza widget na ekranie opcji, co
pozwala użytkownikom na łatwe ukrywanie widgetu.

Poniżej przedstawiono pełny kod źródłowy omówionego widgetu:

    <?php
    /*
    Plugin Name: Przykład wtyczki tworzącej widget kokpitu

[]

Rysunek 4.6. Gotowy widget kokpitu w działaniu

    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka tworząca widget kokpitu na platformie WordPress.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    add_action( 'wp_dashboard_setup', 'boj_dashboard_example_widgets' );
    function boj_dashboard_example_widgets() {
    // Utworzenie własnego widgetu kokpitu.
     wp_add_dashboard_widget( 'dashboard_custom_feed',
     'Informacje o wtyczce', 'boj_dashboard_example_display' );
    }
    function boj_dashboard_example_display()
    {
     echo '<p>Błędy proszę zgłaszać na adres pomoc@przyklad.pl.</p>';
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-dashboard-widget.php.

------------------------------------------------------------------------

Utworzenie widgetu kokpitu wraz z opcjami

Po zapoznaniu się z podstawowym sposobem działania widgetów kokpitu
można przystąpić do opracowania znacznie bardziej zaawansowanego
widgetu, który przechowuje wartości opcji. Widgety kokpitu mogą
przechowywać opcje, co powoduje, że użytkownik ma możliwość łatwego
dostosowania ich do własnych potrzeb. Jeżeli widget kokpitu zawiera
jakiekolwiek opcje, umieszczenie kursora myszy nad jego tytułem
spowoduje wyświetlenie odnośnika Konfiguracja.

Widget omówiony w tym przykładzie pozwala na podanie własnego adresu URL
kanału wiadomości RSS, a następnie wyświetla treść pobranych wiadomości.

    <?php
    add_action( 'wp_dashboard_setup', 'boj_dashboard_example_widgets' );
    function boj_dashboard_example_widgets() {
    // Utworzenie własnego widgetu kokpitu.
     wp_add_dashboard_widget( 'dashboard_custom_feed',
     'Informacje o wtyczce', 'boj_dashboard_example_display',
     'boj_dashboard_example_setup' );
    }
    ?> 

Warto zwrócić uwagę na pojawienie się czwartego parametru funkcji
wp_add_dashboard_widget(). W omawianym przykładzie ma on wartość
boj_dashboard_example_setup() i wskazuje funkcję, która będzie wywołana
w celu obsługi elementów widgetu. Funkcja ta wyświetla pole tekstowe i
zapisuje wprowadzone w nim dane jako opcje widgetu. Kolejnym krokiem
jest utworzenie funkcji boj_dashboard_example_display() odpowiedzialnej
za wyświetlanie przez widget wiadomości RSS.

    <?php
    function boj_dashboard_example_display()
    {
    // Wczytanie opcji widgetu.
     $boj_option = get_option( 'boj_dashboard_widget_rss ');
    // Jeżeli opcje nie zostały ustawione, wówczas należy użyć domyślnych.
     $boj_rss_feed = ( $boj_option ) ? $boj_option : 'http://wordpress.org/news/feed/';
    // Pobranie wiadomości RSS i ich wyświetlenie.
     echo '<div class="rss-widget">';
     wp_widget_rss_output( array(
     'url' => $boj_rss_feed,
     'title' => 'Wiadomości RSS',
     'items' => 2,
     'show_summary' => 1,
     'show_author' => 0,
     'show_date' => 1
     ) );
     echo '</div>';
    }
    ?> 

Pierwsze dwa wiersze powodują wczytanie wiadomości z kanału RSS
zapisanego jako opcja w widgecie. W rozdziale 7. dokładniej omówiono
temat opcji oraz ustawień wtyczek. Następnie widget używa funkcji
wp_widget_rss_output() w celu pobrania wiadomości RSS oraz ich
wyświetlenia. Ta niewielka funkcja jest bardzo przydatna do pobierania i
wyświetlania wiadomości RSS na platformie WordPress. Widget definiuje
adres URL kanału wiadomości RSS, ustawia tytuł widgetu jako Wiadomości
RSS, określa liczbę pobranych wiadomości (dwie) oraz zawiera inne opcje.

Teraz można przystąpić do wyświetlenia widgetu, w tym celu trzeba
utworzyć funkcję boj_dashboard_example_setup(). Zadaniem funkcji jest
dodanie do widgetu pól formularza oraz zapisanie wartości wprowadzonych
przez użytkownika.

    <?php
    function boj_dashboard_example_setup() {
    // Sprawdzenie przed zapisaniem, czy opcja została ustawiona.
     if ( isset( $_POST['boj_rss_feed'] ) ) {
    // Pobranie wartości opcji z formularza.
     $boj_rss_feed = esc_url_raw( $_POST['boj_rss_feed'] );
    // Zapisanie wartości jako opcji.
     update_option( 'boj_dashboard_widget_rss', $boj_rss_feed );
     }
    // Wczytanie i zapisanie wiadomości RSS, o ile istnieją.
     $boj_rss_feed = get_option( 'boj_dashboard_widget_rss ');
     ?> 
    <label for="feed"> 
     Adres URL kanału RSS: <input type="text" name="boj_rss_feed" id="boj_rss_feed"
     value="<?php echo esc_url( $boj_rss_feed ); ?>" size="50" /> 
    </label> 
    <?php
    }
    ?> 

Pierwszym zadaniem funkcji jest zapewnienie obsługi zapisu opcji
widgetu. Przed przeprowadzeniem operacji zapisu zawsze należy sprawdzić
istnienie wartości POST przy użyciu funkcji PHP o nazwie isset().
Kolejnym krokiem jest przypisanie zmiennej $boj_rss_feed wartości
$_POST['boj_rss_feed']. Warto zwrócić uwagę na użycie funkcji
esc_url_raw() do usunięcia niebezpiecznych znaków z wartości POST. W ten
sposób przed zapisaniem danych następuje weryfikacja poprawności formatu
adresu URL i usunięcie z niego niedozwolonych znaków. Na końcu opcje
widgetu są zapisywane za pomocą funkcji update_option().

Po zapisaniu opcji widgetu trzeba wyświetlić pole formularza, to pozwoli
użytkownikowi na podanie adresu URL, z którego mają zostać pobrane
wiadomości RSS. W pierwszej kolejności opcje widgetu są pobierane z bazy
danych, o ile w niej istnieją, co pozwala na wyświetlenie w polu
zapisanego wcześniej adresu URL. Następnie utworzone zostaje proste pole
tekstowe o nazwie boj_rss_feed. Warto zwrócić uwagę na fakt, że jego
wartość pochodzi ze zmiennej $boj_rss_feed przechowującej podany przez
użytkownika adres URL kanału z wiadomościami RSS.

W ten sposób zbudowaliśmy własny widget kokpitu przechowujący adres URL
kanału z wiadomości RSS oraz wyświetlający użytkownikowi dwie ostatnie
wiadomości (zobacz rysunek 4.7).

[]

Rysunek 4.7. Własny widget kokpitu z opcjami w działaniu

Poniżej przedstawiono pełny kod źródłowy omówionego widgetu:

    <?php
    /*
    Plugin Name: Przykład wtyczki tworzącej widget RSS kokpitu
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka tworząca widget kokpitu na platformie WordPress.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    add_action( 'wp_dashboard_setup', 'boj_dashboard_example_widgets' );
    function boj_dashboard_example_widgets() {
    // Utworzenie własnego widgetu kokpitu.
     wp_add_dashboard_widget( 'dashboard_custom_feed', 'Informacje o wtyczce',
     'boj_dashboard_example_display', 'boj_dashboard_example_setup' );
    }
    function boj_dashboard_example_setup() {
    // Sprawdzenie przed zapisaniem, czy opcja została ustawiona.
     if ( isset( $_POST['boj_rss_feed'] ) ) {
    // Pobranie wartości opcji z formularza.
     $boj_rss_feed = esc_url_raw( $_POST['boj_rss_feed'] );
    // Zapisanie wartości jako opcji.
     update_option( 'boj_dashboard_widget_rss', $boj_rss_feed );
     }
     // Wczytanie i zapisanie wiadomości RSS, o ile istnieją.
     $boj_rss_feed = get_option( 'boj_dashboard_widget_rss ');
     ?> 
    <label for="feed"> 
     Adres URL kanału RSS: <input type="text" name="boj_rss_feed" id="boj_rss_feed"
     value="<?php echo esc_url( $boj_rss_feed ); ?>" size="50" /> 
    </label> 
    <?php
    }
    function boj_dashboard_example_display()
    {
    // Wczytanie opcji widgetu.
     $boj_option = get_option( 'boj_dashboard_widget_rss ');
    // Jeżeli opcje nie zostały ustawione, wówczas należy użyć domyślnych.
     $boj_rss_feed = ( $boj_option ) ? $boj_option : 'http://wordpress.org/news/feed/';
    // Pobranie wiadomości RSS i ich wyświetlenie.
     echo '<div class="rss-widget">';
     wp_widget_rss_output( array(
     'url' => $boj_rss_feed,
     'title' => 'Wiadomości RSS',
     'items' => 2,
     'show_summary' => 1,
     'show_author' => 0,
     'show_date' => 1
     ) );
     echo '</div>';
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-rss-dashboard-widget.php.

------------------------------------------------------------------------

------------------------------------------------------------------------

Uwaga

Widgety kokpitu to doskonały sposób umieszczania ważnych dla użytkownika
informacji w widocznym dla niego miejscu. Większość użytkowników
WordPress loguje się bezpośrednio do kokpitu administracyjnego, więc czy
może być lepszy sposób dostarczania im ważnych informacji dotyczących
wtyczki?

------------------------------------------------------------------------

Pola użytkowników

Platforma WordPress zawiera wiele sekcji, czyli pól użytkownika na
stronie wpisu bloga, oraz odnośniki do stron konfiguracyjnych. Za pomocą
wspomnianych pól użytkownika można bardzo łatwo umieszczać w treści
wpisu bloga dodatkowe informacje. Przykładowo pole tagów umożliwia
nadanie tagów danemu artykułowi.

Dodawanie własnego pola użytkownika

W celu utworzenia własnego pola użytkownika w WordPress należy użyć
funkcji add_meta_box(). Funkcja pozwala na zdefiniowanie wszystkich
aspektów pola użytkownika. Poniżej przedstawiono przykład użycia tej
funkcji:

    <?php add_meta_box( id, title, callback, page, context, priority, callback_args ); ?> 

Funkcja add_meta_box() akceptuje następujące parametry:

-   id — identyfikator CSS dodawany do znacznika <div> opakowującego
    pole użytkownika;
-   title — nazwa pola użytkownika wyświetlana w jego nagłówku;
-   callback — funkcja wywoływana w celu wyświetlenia pola użytkownika;
-   page — strona, na której powinno zostać wyświetlone pole
    użytkownika;
-   context — miejsce na stronie, w którym powinno znaleźć się pole
    użytkownika;
-   priority — priorytet, z jakim powinno być wyświetlone pole
    użytkownika;
-   callback_args — argumenty przekazywane funkcji wywoływanej w celu
    wyświetlenia pola użytkownika.

Teraz można przystąpić do opracowania własnego pola użytkownika
przeznaczonego do umieszczenia na stronie.

    <?php
    add_action( 'add_meta_boxes', 'boj_mbe_create' );
    function boj_mbe_create() {
     add_meta_box( 'boj-meta', 'Własne pole użytkownika', 'boj_mbe_function', 'post',
     'normal', 'high' );
    }
    function boj_mbe_function() {
     echo 'Witaj w polu użytkownika!';
    }
    ?> 

W powyższym fragmencie kodu utworzono pole użytkownika, które będzie
wyświetlone na stronie. Do wywołania funkcji boj_mbe_create()
odpowiedzialnej za dodanie pola użytkownika wykorzystano zaczep akcji
meta_boxes. Tytuł pola został ustalony jako Własne pole użytkownika i
jest wyświetlany w wywołaniu funkcji boj_mbe_function(). Warto zwrócić
uwagę na użycie wartości normal dla parametru context oraz high dla
parametru priority. To powoduje, że pole użytkownika zostaje wyświetlone
bezpośrednio pod edytorem wizualnym na stronie dodawania wpisu bloga
(zobacz rysunek 4.8).

------------------------------------------------------------------------

Uwaga

Własne pole użytkownika można dodać do dowolnego typu wpisu bloga na
platformie WordPress poprzez podanie w parametrze page nazwy własnego
typu wpisu bloga.

------------------------------------------------------------------------

Zapis danych pola użytkownika

Prawdziwa potęga pól użytkownika wynika z możliwości zapisu danych na
stronie wpisu bloga lub dowolnego typu treści platformy WordPress.
Wszystkie dane zapisywane i dotyczące treści noszą nazwę metadanych. Na
stronach konfiguracyjnych platformy WordPress domyślnie znajdują się
pola użytkownika, które po prostu pozwalają na szybki zapis metadanych
dotyczących treści.

[]

Rysunek 4.8. Własne pole użytkownika wyświetlone na stronie

Dokładniejsze omówienie metadanych przedstawiono w rozdziale 11., ale
teraz należy zrozumieć koncepcję zapisu danych w polu użytkownika.

W omówionym poniżej przykładzie na stronie wpisu bloga zostanie
utworzone pole użytkownika, które będzie pozwalało na zapis dwóch pól
danych dotyczących treści.

    <?php
    add_action( 'add_meta_boxes', 'boj_mbe_create' );
    function boj_mbe_create() {
    // Utworzenie własnego pola użytkownika.
     add_meta_box( 'boj-meta', 'Własne pole użytkownika', 'boj_mbe_function', 'post',
     'normal', 'high' );
    }
    ?> 

Kolejnym krokiem jest inicjalizacja i utworzenie pola użytkownika,
podobnie jak w poprzednim przykładzie. Ponadto trzeba napisać funkcję
odpowiedzialną za wyświetlenie pól formularza.

    <?php
    function boj_mbe_function( $post ) {
    // Pobranie wartości metadanych, o ile istnieją.
     $boj_mbe_name = get_post_meta( $post->ID, '_boj_mbe_name', true );
     $boj_mbe_costume = get_post_meta( $post->ID, '_boj_mbe_costume', true );
     echo 'Proszę wypełnić poniższe pola';
     ?> 
    <p>Imię: <input type="text" name="boj_mbe_name" value="
    <?php echo esc_attr( $boj_mbe_name ); ?> " /></p> 
    <p>Kostium:
    <select name="boj_mbe_costume"> 
    <option value="vampire" <?php selected( $boj_mbe_costume, 'vampire' ); ?>> 
     Wampir
    </option> 
    <option value="zombie" <?php selected( $boj_mbe_costume, 'zombie' ); ?>> 
     Zombie
    </option> 
    <option value="smurf" <?php selected( $boj_mbe_costume, 'smurf' ); ?>> 
     Smerf
    </option> 
    </select> 
    </p> 
    <?php
    }
    ?> 

Pierwszą rzeczą, na którą trzeba zwrócić uwagę, jest przekazanie własnej
funkcji obiektu $post jako parametru. W ten sposób uzyskujemy dostęp do
wszystkich danych znajdujących się w obiekcie, których następnie można
użyć w polu użytkownika; w omawianym przykładzie jest to identyfikator
wpisu bloga.

Kolejnym krokiem jest pobranie z platformy WordPress dwóch wartości
metadanych, jeśli istnieją. Do tego wykorzystano funkcję
get_post_meta(), która akceptuje trzy parametry:

-   post_id — identyfikator wpisu bloga, z którego mają zostać wczytane
    dane;
-   key — unikalna nazwa pola metadanych, które ma być wczytane;
-   single — wskazanie wartości zwrotnej ciągu tekstowego: jako tablica
    (false) lub pojedynczy ciąg tekstowy (true).

Jeżeli tworzony jest nowy wpis bloga, wartości metadanych nie istnieją,
ponieważ nie zostały jeszcze utworzone. Kolejnym krokiem w kodzie jest
wyświetlenie pól formularza. Pierwsze jest przeznaczone do podania
imienia. Warto zwrócić uwagę na fakt, że tekst tego pola jest
przypisywany $boj_mbe_name, czyli zmiennej przechowującej pobieraną
wartość metadanych. Ze względów bezpieczeństwa dane wprowadzane przez
użytkownika są poddawane działaniu funkcji esc_attr().

Drugie pole formularza to zwykłe pole HTML <select>. Oferuje ono trzy
możliwości do wyboru; w omawianym przykładzie to kostiumy wampira,
zombie i smerfa. Wybrany element zostaje określony za pomocą funkcji
selected(). Formularz pola użytkownika na tym etapie jest ukończony. Jak
można zobaczyć, nie trzeba dodawać przycisku wysyłającego formularz do
serwera. Za pomocą zaczepu akcji save_post wartości są przekazywane do
przedstawionej poniżej funkcji boj_mbe_save_meta().

    <?php
    // Zaczep pozwalający na zapis danych pola użytkownika.
    add_action( 'save_post', 'boj_mbe_save_meta' );
    function boj_mbe_save_meta( $post_id ) {
    // Sprawdzenie, czy metadane zostały podane.
     if ( isset( $_POST['boj_mbe_name'] ) ) {
    // Zapis metadanych.
     update_post_meta( $post_id, '_boj_mbe_name',
     strip_tags( $_POST['boj_mbe_name'] ) );
     update_post_meta( $post_id, '_boj_mbe_costume',
     strip_tags( $_POST['boj_mbe_costume'] ) );
     }
    }
    ?> 

Za pomocą funkcji add_action() do zaczepu save_post zostaje dodana
funkcja boj_mbe_save_ meta() wywoływana podczas zapisywania nowego wpisu
bloga. Funkcja powoduje zapisanie danych, które podano w polu
użytkownika. Warto zwrócić uwagę na przekazanie funkcji parametru w
postaci zmiennej $post_id. Ten identyfikator wpisu jest używany podczas
zapisywania metadanych. Dobrym pomysłem jest, aby przed rozpoczęciem
pracy z polem formularza zawsze sprawdzić, czy pole w ogóle zostało
użyte. Tutaj odbywa się to poprzez wywołanie funkcji PHP o nazwie
isset(). Na koniec funkcja update_post_meta() powoduje dodanie lub
uaktualnienie metadanych wpisu na podstawie informacji podanych w polu
użytkownika. Funkcja update_post_meta() akceptuje cztery parametry:

-   post_id — identyfikator wpisu bloga, dla którego mają zostać
    zapisane metadane;
-   meta_key — unikalna nazwa pola metadanych, które ma zostać zapisane;
-   meta_value — wartość pola metadanych, które ma zostać zapisane;
-   prev_value — poprzednia wartość pola metadanych; pozwala ona na
    rozróżnienie wielu pól o takiej samej nazwie.

W omawianym przykładzie użyto tylko trzech pierwszych parametrów,
ponieważ ostatni, czwarty jest opcjonalny. Używane są więc identyfikator
wpisu bloga, nazwa pola metadanych oraz wartość wprowadzona we własnym
polu użytkownika. Wartości wprowadzane przez użytkownika są oczyszczane
z niebezpiecznych znaków za pomocą funkcji strip_tags().

------------------------------------------------------------------------

Uwaga

Jeżeli nazwa metadanych rozpoczyna się znakiem podkreślenia, nie będzie
wyświetlona w domyślnym polu użytkownika platformy WordPress. To pomaga
w uniknięciu wszelkich niejasności podczas wprowadzania metadanych.

------------------------------------------------------------------------

Powyżej utworzyłeś własne pole użytkownika, które przechowuje dane na
platformie WordPress! Warto teraz spojrzeć na pełny kod źródłowy
wtyczki.

    <?php
    /*
    Plugin Name: Przykład wtyczki tworzącej pole użytkownika
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka służąca do tworzenia pola użytkownika na platformie WordPress.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    add_action( 'add_meta_box', 'boj_mbe_create' );
    function boj_mbe_create() {
    // Utworzenie własnego pola użytkownika.
     add_meta_box( 'boj-meta', 'Własne pole użytkownika', 'boj_mbe_function',
     'post', 'normal', 'high' );
    }
    function boj_mbe_function( $post ) {
    // Pobranie wartości metadanych, o ile istnieją.
     $boj_mbe_name = get_post_meta( $post->ID, '_boj_mbe_name', true );
     $boj_mbe_costume = get_post_meta( $post->ID, '_boj_mbe_costume', true );
     echo 'Proszę wypełnić poniższe pola';
     ?> 
    <p>Imię: <input type="text" name="boj_mbe_name" value="
    <?php echo esc_attr( $boj_mbe_name ); ?>" /></p> 
    <p>Kostium:
    <select name="boj_mbe_costume"> 
    <option value="vampire" <?php selected( $boj_mbe_costume, 'vampire' ); ?>> 
     Wampir
    </option> 
    <option value="zombie" <?php selected( $boj_mbe_costume, 'zombie' ); ?>> 
     Zombie
    </option> 
    <option value="smurf" <?php selected( $boj_mbe_costume, 'smurf' ); ?>> 
     Smerf
    </option> 
    </select> 
    </p> 
    <?php
    }
    // Zaczep pozwalający na zapis danych pola użytkownika.
    add_action( 'save_post', 'boj_mbe_save_meta' );
    function boj_mbe_save_meta( $post_id ) {
    // Sprawdzenie, czy metadane zostały podane.
     if ( isset( $_POST['boj_mbe_name'] ) ) {
    // Zapis metadanych.
     update_post_meta( $post_id, '_boj_mbe_name',
     strip_tags( $_POST['boj_mbe_name'] ) );
     update_post_meta( $post_id, '_boj_mbe_costume',
     strip_tags( $_POST['boj_mbe_costume'] ) );
     }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-meta-box.php.

------------------------------------------------------------------------

Zaawansowane pole użytkownika

Po zapoznaniu się ze sposobem działania pola użytkownika można
przystąpić do budowy pola bardziej skomplikowanego. W tym przykładzie
przedstawiono utworzenie własnego pola użytkownika pozwalającego mu na
wybór pliku graficznego z biblioteki multimediów platformy WordPress
oraz na zapis adresu URL w polu.

Najpierw, podobnie jak wcześniej, trzeba użyć zaczepu akcji
add_meta_boxes w celu wywołania własnej funkcji tworzącej pole
użytkownika.

    <?php
    add_action( 'add_meta_boxes', 'boj_mbe_image_create' );
    function boj_mbe_image_create() {
    // Utworzenie własnego pola użytkownika.
     add_meta_box( 'boj-image-meta', 'Wybierz obraz', 'boj_mbe_image_function',
     'post', 'normal', 'high' );
    }
    ?> 

Za pomocą funkcji add_meta_box() można zdefiniować ustawienia własnego
pola użytkownika. W omawianym przykładzie pole otrzymało tytuł Wybierz
obraz, a wywoływaną funkcją jest boj_mbe_image_function().

Po utworzeniu pola użytkownika można przystąpić do budowy funkcji
odpowiedzialnej za wyświetlenie jego treści.

    <?php
    function boj_mbe_image_function( $post ) {
    // Pobranie wartości metadanych, o ile istnieją.
     $boj_mbe_image = get_post_meta( $post->ID, '_boj_mbe_image', true );
     ?> 
     Obraz <input id="boj_mbe_image" type="text" size="75"
     name="boj_mbe_image" value="<?php echo esc_url( $boj_mbe_image ); ?>" /> 
    <input id="upload_image_button" type="button"
     value="Obraz z biblioteki multimediów" class="button-secondary" /> 
    <br />Podaj adres URL obrazu lub użyj obrazu z biblioteki multimediów
    <?php
    }
    ?> 

Pierwszym krokiem jest wczytanie do zmiennej $boj_mbe_image wartości
metadanych, jeśli istnieją. Jeżeli metadane nie zostały jeszcze
zapisane, zmienna będzie pusta. Kolejny krok to wyświetlenie pola
formularza pozwalającego na podanie adresu URL obrazu. Ponadto trzeba
dodać przycisk umożliwiający użytkownikowi wybór obrazu z biblioteki
multimediów (zobacz rysunek 4.9).

[]

Rysunek 4.9. Zaawansowane pole użytkownika

Pozostało już wywołanie zaczepu akcji save_post w celu wywołania własnej
funkcji boj_mbe_image_save_meta(), która spowoduje zapisanie danych pola
użytkownika.

    <?php
    // Zaczep pozwalający na zapis danych pola użytkownika.
    add_action( 'save_post', 'boj_mbe_image_save_meta' );
    function boj_mbe_image_save_meta( $post_id ) {
    // Sprawdzenie, czy metadane zostały podane.
     if ( isset( $_POST['boj_mbe_image'] ) ) {
    // Zapis metadanych.
     update_post_meta( $post_id, '_boj_mbe_image',
     esc_url_raw( $_POST['boj_mbe_image'] ) );
     }
    }
    ?> 

Dobrą praktyką jest sprawdzenie pola formularza przed pobraniem z niego
wartości. Jeżeli w polu została podana wartość, można wykorzystać
funkcję update_post_meta() do zapisania metadanych wpisu. Warto zwrócić
uwagę na użycie funkcji esc_url_raw() odpowiedzialnej za usunięcie
niebezpiecznych znaków z adresu URL. W ten sposób następuje
wyeliminowanie niepoprawnych i niebezpiecznych znaków, a także
sprawdzenie, czy użyty został prawidłowy typ protokołu (http, https, ftp
itd.).

Aż do tego etapu była to zupełnie zwykła wtyczka dodająca pole
użytkownika. Prawdziwa zabawa zaczyna się dopiero tutaj! W celu
skorzystania z biblioteki multimediów trzeba użyć kodu JavaScript.
Kolejnym krokiem jest więc utworzenie pliku o nazwie boj-meta-image.js.
W pliku tym znajdzie się kod JavaScript odpowiedzialny za wstawienie w
polu tekstowym pola użytkownika adresu URL obrazu po wybraniu obrazu z
biblioteki multimediów. Kod JavaScript przedstawiono poniżej.

    jQuery(document).ready(function($) {
     var formfield = null;
     $('#upload_image_button').click(function() {
     $('html').addClass('Image');
     formfield = $('#boj_mbe_image').attr('name');
     tb_show('', 'media-upload.php?type=image & TB_iframe=true');
     return false;
     });
    // Użytkownik wstawia plik do wpisu.
    // Wykonanie w sposób inny niż standardowy następuje tylko wtedy, gdy użytkownik rozpocznie przetwarzanie przy
    // użyciu powyższego procesu. window.send_to_editor(html) to zwykły sposób 
    // obsługi otrzymanych danych przez WordPress.
     window.original_send_to_editor = window.send_to_editor;
     window.send_to_editor = function(html){
     var fileurl;
     if (formfield != null) {
     fileurl = $('img',html).attr('src');
     $('#boj_mbe_image').val(fileurl);
     tb_remove();
     $('html').removeClass('Image');
     formfield = null;
     } else {
     window.original_send_to_editor(html);
     }
     };
    }); 

Należy pamiętać, że to jest kod JavaScript i nie może być umieszczony
między znacznikami <?php ?>. Kod po kliknięciu przycisku
upload_image_button najpierw otwiera bibliotekę multimedialną — to po
prostu nazwa przycisku wysyłania formularza, który znajduje się w polu
użytkownika. Druga część kodu pobiera adres URL obrazu i umieszcza go w
polu tekstowym formularza (boj_mbe_image).

Po przygotowaniu pliku z kodem JavaScript trzeba się do niego odwołać z
poziomu wtyczki.

    <?php
    // Zaczep do dodawania skryptu wraz z wykrywaniem strony.
    add_action('admin_print_scripts-post.php', 'boj_mbe_image_admin_scripts');
    add_action('admin_print_scripts-post-new.php', 'boj_mbe_image_admin_scripts');
    function boj_mbe_image_admin_scripts() {
     wp_enqueue_script( 'boj-image-upload',
     plugins_url( '/boj-meta-box/boj-meta-image.js' ),
     array( 'jquery','media-upload','thickbox' )
     );
    }
    ?> 

Do wykonania własnej funkcji dołączającej plik skryptu JavaScript
zostanie użyty zaczep akcji admin_print_scripts. Warto zwrócić uwagę,
jak ten zaczep akcji dołączył fragmenty -post.php i -post-new.php do
nazwy zaczepu. Proces nosi nazwę wykrywania strony, więc zaczep wywołuje
funkcję boj_mbe_image_admin_scripts() tylko wtedy, gdy użytkownik
znajduje się na stronie post.php lub post-new.php na platformie
WordPress.

Do wstawienia kodu JavaScript do nagłówka strony stosowana jest funkcja
wp_enqueue_script(). To prawidłowy sposób dołączania plików JavaScript
do nagłówka strony w WordPress. Więcej informacji na ten temat
przedstawiono w rozdziale 12.

Ostatnim krokiem jest dodanie za pomocą funkcji wp_enqueue_styles()stylu
thickbox.

    <?php
    // Zaczep do dodawania stylów wraz z wykrywaniem strony.
    add_action('admin_print_styles-post.php', 'boj_mbe_image_admin_styles');
    add_action('admin_print_styles-post-new.php', 'boj_mbe_image_admin_styles');
    function boj_mbe_image_admin_styles() {
     wp_enqueue_style( 'thickbox' );
    }
    ?> 

Powyższy fragment kodu powoduje dodanie stylu thickbox w nagłówku
strony.

W celu wybrania obrazu w polu użytkownika wystarczy kliknąć przycisk
Obraz z biblioteki multimediów. Następnie należy wybrać obraz i kliknąć
przycisk Wstaw. W polu tekstowym pola użytkownika zostanie wstawiony
adres URL obrazu. Nastąpi to tylko wtedy, gdy użytkownik w polu
użytkownika kliknie przycisk Obraz z biblioteki multimediów.

Poniżej przedstawiono pełny kod źródłowy wtyczki.

Plik boj-meta-box.php:

    <?php
    /*
    Plugin Name: Przykład wtyczki używającej biblioteki multimedialnej
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka umożliwia wybór obrazu z biblioteki multimedialnej.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    add_action( 'admin_init', 'boj_mbe_image_create' );
    function boj_mbe_image_create() {
    // Utworzenie własnego pola użytkownika.
     add_meta_box( 'boj-image-meta', 'Wybierz obraz', 'boj_mbe_image_function', 'post',
     'normal', 'high' );
    }
    function boj_mbe_image_function( $post ) {
    // Pobranie wartości metadanych, o ile istnieją.
     $boj_mbe_image = get_post_meta( $post->ID, '_boj_mbe_image', true );
     ?> 
     Obraz <input id="boj_mbe_image" type="text" size="75" name="boj_mbe_image"
     value="<?php echo esc_url( $boj_mbe_image ); ?>" /> 
     <input id="upload_image_button" type="button"
     value="Obraz z biblioteki multimediów" class="button-secondary" /> 
     <p>Podaj adres URL obrazu lub użyj obrazu z biblioteki multimediów</p> 
     <?php
    }
    // Zaczep do dodawania skryptu wraz z wykrywaniem strony.
    add_action('admin_print_scripts-post.php', 'boj_mbe_image_admin_scripts');
    add_action('admin_print_scripts-post-new.php', 'boj_mbe_image_admin_scripts');
    function boj_mbe_image_admin_scripts() {
     wp_enqueue_script( 'boj-image-upload',
     plugins_url( '/boj-meta-box/boj-meta-image.js' ),
     array( 'jquery','media-upload','thickbox' ) );
    }
    // Zaczep do dodawania stylów wraz z wykrywaniem strony.
    add_action('admin_print_styles-post.php', 'boj_mbe_image_admin_styles');
    add_action('admin_print_styles-post-new.php', 'boj_mbe_image_admin_styles');
    function boj_mbe_image_admin_styles() {
     wp_enqueue_style( 'thickbox' );
    }
    // Zaczep pozwalający na zapis danych pola użytkownika.
    add_action( 'save_post', 'boj_mbe_image_save_meta' );
    function boj_mbe_image_save_meta( $post_id ) {
    // Sprawdzenie, czy metadane zostały podane.
     if ( isset( $_POST['boj_mbe_image'] ) ) {
    // Zapis metadanych.
     update_post_meta( $post_id, '_boj_mbe_image',
     esc_url( $_POST['boj_mbe_image'] ) );
     }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-meta-box.php znajdującego
się w archiwum boj-meta-box.zip.

------------------------------------------------------------------------

Plik boj-meta-image.js:

    jQuery(document).ready(function($) {
     var formfield = null;
     $('#upload_image_button').click(function() {
     $('html').addClass('Image');
     formfield = $('#boj_mbe_image').attr('name');
     tb_show('', 'media-upload.php?type=image & TB_iframe=true');
     return false;
     });
    // Użytkownik wstawia plik do wpisu.
    // Wykonanie w sposób inny niż standardowy następuje tylko wtedy, gdy użytkownik rozpocznie 
     // przetwarzanie przy użyciu powyższego procesu. window.send_to_editor(html) to zwykły sposób
     // obsługi otrzymanych danych przez WordPress.
     window.original_send_to_editor = window.send_to_editor;
     window.send_to_editor = function(html){
     var fileurl;
     if (formfield != null) {
     fileurl = $('img',html).attr('src');
     $('#boj_mbe_image').val(fileurl);
     tb_remove();
     $('html').removeClass('Image');
     formfield = null;
     } else {
     window.original_send_to_editor(html);
     }
     };
    }); 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-meta-image.js znajdującego
się w archiwum boj-meta-box.zip.

------------------------------------------------------------------------

Zachowanie spójności

Zachowanie spójności to jedna z cech charakteryzujących dobry interfejs
użytkownika. Tworzenie wtyczek dla platformy WordPress nie jest pod tym
względem inne. Najlepszym rozwiązaniem jest maksymalne dopasowanie
interfejsu użytkownika wtyczki do stosowanego przez WordPress. W ten
sposób następuje zachowanie spójności interfejsu użytkownika, a sama
wtyczka prezentuje się jeszcze bardziej profesjonalnie i od samego
początku robi na użytkownikach korzystne wrażenie.

W platformie WordPress możemy wykorzystać wiele różnych stylów, które
bardzo łatwo stosuje się we wtyczkach. W tym podrozdziale omówiono
używanie we własnych wtyczkach stylów udostępnianych przez WordPress. W
tym celu trzeba wcześniej utworzyć prostą wtyczkę wraz ze stroną
ustawień:

    <?php
    add_action( 'admin_menu', 'boj_styling_create_menu' );
    function boj_styling_create_menu() {
    // Utworzenie menu najwyższego poziomu.
     add_menu_page( 'Ustawienia wtyczki', 'Styl wtyczki',
     'manage_options', __FILE__, 'boj_styling_settings' );
    }
    ?> 

W tym podrozdziale zostanie zmodyfikowany kod funkcji
boj_styling_settings().

Korzystanie z interfejsu użytkownika platformy WordPress

Najważniejszą kwestią podczas używania stylów WordPress jest opakowanie
wtyczki klasą wrap elementu <div>.

    <div class="wrap"> 
     Strona wtyczki
    </div> 

Klasa jest podstawą dla wszystkich stylów administracyjnych.

Nagłówki

Platformę WordPress wyposażono we własne style dla wszystkich znaczników
nagłówków. Warto przekonać się, w jaki sposób są wyświetlane znaczniki
nagłówków:

    <?php
    function boj_styling_settings() {
     ?> 
     <div class="wrap"> 
     <h2>Moja wtyczka</h2> 
     <h3>Moja wtyczka</h3> 
     <h4>Moja wtyczka</h4> 
     <h5>Moja wtyczka</h5> 
     <h6>Moja wtyczka</h6> 
     </div> 
     <?php
    }
    ?> 

Jak pokazano na rysunku 4.10, każdy kolejny nagłówek jest nieco mniejszy
od poprzedniego. Warto zwrócić uwagę na brak zdefiniowanego nagłówka
<h1>. Nagłówek <h1> jest zarezerwowany do wyświetlania nazwy witryny na
górze kokpitu administracyjnego. Z tego powodu jako nagłówka
podstawowego zawsze należy używać <h2>.

[]

Rysunek 4.10. Style nagłówków stosowane na platformie WordPress

Ikony

Dla każdej sekcji nagłówka na platformie WordPress mamy do dyspozycji
wiele różnych ikon, które można wykorzystać również we własnych
wtyczkach. Przykładowo ikoną nagłówka kokpitu jest ikona domu.

    <div id="icon-index" class="icon32"></div> 
    <div id="icon-edit" class="icon32"></div>
    <div id="icon-upload" class="icon32"></div> 
    <div id="icon-link-manager" class="icon32"></div> 
    <div id="icon-edit-pages" class="icon32"></div> 
    <div id="icon-edit-comments" class="icon32"></div> 
    <div id="icon-themes" class="icon32"></div> 
    <div id="icon-plugins" class="icon32"></div> 
    <div id="icon-users" class="icon32"></div> 
    <div id="icon-tools" class="icon32"></div> 
    <div id="icon-options-general" class="icon32"></div> 

Powyższe znaczniki <div> powodują wygenerowanie ikon pokazanych na
rysunku 4.11.

[]

Rysunek 4.11. Ikony, które można wykorzystać w nagłówkach platformy
WordPress

Nie musimy na stałe umieszczać powyższych poleceń w kodzie, WordPress
oferuje funkcję o nazwie screen_icon(), która generuje odpowiedni
znacznik <div> z ikoną. Funkcja akceptuje pojedynczy parametr, czyli
ikonę przeznaczoną do wygenerowania.

Teraz można zmodyfikować funkcję boj_styling_settings() w taki sposób,
aby wyświetlała ikonę i nagłówek.

    <?php
    function boj_styling_settings() {
     ?> 
     <div class="wrap"> 
     <?php screen_icon( 'plugins' ); ?> 
     <h2>Moja wtyczka</h2> 
     </div> 
     <?php
    }
    ?> 

Po użyciu powyższego kodu wtyczka ma nagłówek oraz ikonę.

Wiadomości

Po wystąpieniu we wtyczce zdarzenia, takiego jak zapis ustawień, bardzo
ważne jest wyświetlenie użytkownikowi odpowiedniego komunikatu
informującego o przebiegu zdarzenia. Platforma WordPress oferuje różne
style służące do wyświetlania tego rodzaju komunikatów.

    <?php
    function boj_styling_settings() {
     ?> 
     <div class="wrap" > 
     <h2>Moja wtyczka</h2> 
     <div id="message" class="updated">Pomyślnie zapisano ustawienia</div> 
     <div id="message" class="error">Wystąpił błąd podczas zapisu ustawień</div> 
     </div > 
    <?php
    }
    ?> 

Style komunikatów wygenerowane przez powyższy kod pokazano na rysunku
4.12.

[]

Rysunek 4.12. Różne style komunikatów oferowane przez platformę
WordPress

Przyciski

Podczas dodawania przycisków do formularza można wykorzystać wiele klas.
Dwie najczęściej używane to button-primary i button-secondary. Oferowane
przez nie style pasują do interfejsu użytkownika platformy WordPress.

    <p> 
    <input type="submit" name="Save" value="Zapisz opcje" /> 
    <input type="submit" name="Save" value="Zapisz opcje" class="button-primary" /> 
    </p><p> 
    <input type="submit" name="Secondary" value="Inny rodzaj przycisku" /> 
    <input type="submit" name="Secondary" value="Inny rodzaj przycisku"
     class="button-secondary" /> 
    </p> 

Powyższy fragment kodu powoduje utworzenie standardowego przycisku bez
zastosowanych stylów oraz przycisku, w którym użyto stylu WordPress. Jak
można zauważyć, przycisk w stylu WordPress wygląda znajomo i zastosowano
w nim prawidłowy styl interfejsu użytkownika (zobacz rysunek 4.13).

[]

Rysunek 4.13. Różne style przycisków platformy WordPress

Istnieje również możliwość użycia klasy button-highlighted w celu
położenia nacisku na konkretny przycisk.

    <input type="submit" name="secondary" value="Inny rodzaj przycisku"
     class="button-secondary" /> 
    <input type="submit" name="highlighted" value="Przycisk wyróżniony"
     class="button-highlighted" /> 

Teraz czcionka przycisku jest pogrubiona, a sam przycisk bardziej się
różni od standardowego (zobacz rysunek 4.14). To użyteczna możliwość,
gdy uwagę użytkownika trzeba zwrócić na konkretny przycisk.

[]

Rysunek 4.14. Wyróżnienie przycisku na platformie WordPress

Odnośniki także mogą przyjąć postać przycisków, uzyskamy to przy użyciu
odpowiedniej klasy.

    <a href="#">Szukaj</a> 
    <a href='#' class='button-secondary'>Szukaj</a> 
    <a href='#' class='button-highlighted'>Szukaj</a> 
    <a href='#' class='button-primary'>Szukaj</a> 

Powyższy fragment kodu pokazuje, w jaki sposób standardowe odnośniki
<a href> mogą mieć nadany styl, który powoduje, że wyglądają jak
przyciski (zobacz rysunek 4.15). Użytkownicy mogą nie wiedzieć, że to
zwykłe odnośniki tekstowe z zastosowanym stylem nadającym im wygląd
przycisku.

[]

Rysunek 4.15. Odnośniki tekstowe z zastosowanym stylem nadającym im
wygląd przycisku

Odnośniki

Odnośniki umieszczone w klasie wrap automatycznie otrzymują styl
odnośników administracyjnych platformy WordPress. Jednak styl domyślny
można zmodyfikować na wiele różnych sposobów.

    <div class="wrap"> 
     <?php screen_icon( 'plugins' ); ?>
     <h2>Moja wtyczka</h2> 
     <h2> <a href="#">Odnośnik testowy</a></h2> 
     <h3> <a href="#">Odnośnik testowy</a></h3> 
     <h4> <a href="#">Odnośnik testowy</a></h4> 
     <h5> <a href="#">Odnośnik testowy</a></h5> 
     <a href="#">Odnośnik testowy</a> 
    </div> 

Opakowanie odnośnika znacznikiem nagłówka pozwala na dostosowanie
wielkości czcionki odnośnika, tak jak pokazano na rysunku 4.16.

[]

Rysunek 4.16. Różna wielkość czcionki odnośników uzyskana po opakowaniu
ich znacznikami nagłówków

Pola formularza

W platformie WordPress zaimplementowano specjalną klasę tabeli o nazwie
form-table przeznaczoną dla formularzy. Klasa jest używana we wszystkich
formularzach kokpitu administracyjnego WordPress, w tym także na każdej
stronie menu Ustawienia. Klasa ta jest użyteczna podczas tworzenia
dowolnego typu opcji dla wtyczki.

    <div class="wrap"> 
     <?php screen_icon( 'plugins' ); ?> 
     <h2>Moja wtyczka</h2> 
     <form method="POST" action=""> 
     <table class="form-table"> 
     <tr valign="top"> 
     <th scope="row"><label for="fname">Imię</label></th> 
     <td><input maxlength="45" size="25" name="fname" /></td> 
     </tr> 
     <tr valign="top"> 
     <th scope="row"><label for="lname">Nazwisko</label></th> 
     <td><input id="lname" maxlength="45" size="25" name="lname" /></td> 
     </tr> 
     <tr valign="top"> 
     <th scope="row"><label for="color">Ulubiony kolor</label></th> 
     <td> 
     <select name="color"> 
     <option value="orange">Pomarańczowy</option> 
     <option value="black">Czarny</option> 
     </select> 
     </td> 
     </tr> 
     <tr valign="top"> 
     <th scope="row"><label for="featured">Wyróżniony?</label></th> 
     <td><input type="checkbox" name="favorite" /></td> 
     </tr> 
     <tr valign="top"> 
     <th scope="row"><label for="gender">Płeć</label></th> 
     <td> 
     <input type="radio" name="gender" value="male" /> Mężczyzna
     <input type="radio" name="gender" value="female" /> Kobieta
     </td> 
     </tr> 
     <tr valign="top"> 
     <th scope="row"><label for="bio">Bio</label></th> 
     <td> <textarea name="bio"></textarea></td> 
     </tr> 
     <tr valign="top"> 
     <td> 
     <input type="submit" name="save" value="Zapisz opcje"
     class="button-primary" /> 
     <input type="submit" name="reset" value="Wyczyść"
     class="button-secondary" /> 
     </td> 
     </tr> 
     </table> 
     </form> 
    </div> 

Użycie stylu form-table powoduje, że opcje przedstawiają się w sposób
znany użytkownikom (zobacz rysunek 4.17). Dzięki temu wtyczka sprawia
lepsze wrażenie.

[]

Rysunek 4.17. Strona opcji zbudowana na podstawie formularza, w którym
użyto stylu form-table

Tabele

Tabele HTML to doskonały sposób wyświetlania wierszy i kolumn danych w
łatwym do odczytu układzie. Tabelom na platformie WordPress można bardzo
łatwo nadać styl, korzystając z klasy widefat.

    <table class="widefat"> 
    <thead> 
     <tr> 
     <th>Imię</th> 
     <th>Ulubione święto</th> 
     </tr> 
    </thead> 
    <tfoot> 
     <tr> 
     <th>Imię</th> 
     <th>Ulubione święto</th> 
     </tr> 
    </tfoot> 
    <tbody> 
     <tr> 
     <td>Joanna Kowalska</td> 
     <td>Walentynki</td> 
     </tr> 
     <tr> 
     <td>Adam Nowak</td> 
     <td>Narodowe Święto Niepodległości</td> 
     </tr> 
     <tr> 
     <td>Jan Malinowski</td> 
     <td>Boże Narodzenie</td> 
     </tr> 
    </tbody> 
    </table> 

Klasa widefat zawiera specjalny zestaw stylów przeznaczonych dla
znaczników HTML <thead> i <tfoot>. W ten sposób style nagłówka i stopki
tabeli odpowiadają stylom pozostałych tabel kokpitu administracyjnego.
Ponadto klasa zawiera również style dla pozostałych danych tabeli, co
pokazano na rysunku 4.18.

[]

Rysunek 4.18. Style oferowane przez platformę WordPress dla danych w
tabeli

Stronicowanie

Jeżeli wtyczka zawiera listę rekordów, wówczas może wystąpić konieczność
zastosowania stronicowania. Wspomniane stronicowanie to metoda podziału
listy danych na wiele stron wraz z odnośnikami pozwalającymi na
wczytanie poszczególnych stron. W ten sposób skraca się czas wczytania i
ułatwia użytkownikom poruszanie po wyświetlonych danych. Odpowiedz sobie
na pytanie, czy wolisz otrzymać stronę z wyświetlonymi rekordami w
ilości pięciuset czy raczej dziesięć stron z pięćdziesięcioma rekordami
każda?

Platforma WordPress oferuje kilka różnych klas przeznaczonych do obsługi
stronicowania. Poniżej przedstawiono przykład.

    <div class="tablenav"> 
     <div class="tablenav-pages"> 
     <span class="displaying-num">Wyświetlanie 1-20 z 69</span> 
     <span class="page-numbers current">1</span> 
     <a href="#" class="page-numbers">2</a> 
     <a href="#" class="page-numbers">3</a> 
     <a href="#" class="page-numbers">4</a> 
     <a href="#" class="next page-numbers">&raquo;</a> 
     </div> 
    </div> 

Na początek odnośniki stronicowania muszą być opakowane klasami tablenav
i tablenav-pages znaczników <div>. Klasa displaying-num nadaje styl
wyświetlanym rekordom. Z kolei klasa page-numbers nadaje odnośnikom
stron styl znany z platformy WordPress. Dodanie odnośnikowi klasy
current lub next powoduje zastosowanie w danych elementach pewnych
unikalnych stylów (zobacz rysunek 4.19).

[]

Rysunek 4.19. Style stronicowania oferowane przez platformę WordPress

Zachowanie wyglądu wtyczki spójnego z interfejsem użytkownika platformy
WordPress powoduje, że wtyczka zostanie szybciej zaakceptowana, ponieważ
oferowany przez nią projekt będzie dla odbiorców komfortowy i dobrze im
znany. Dzięki temu zapewnia się również dłuższą trwałość wtyczki. Jeżeli
w pewnym momencie style fabryczne platformy WordPress zostaną zmienione,
projekt wtyczki automatycznie uwzględni te zmiany i dostosuje ją do
nowego wyglądu interfejsu użytkownika platformy. W tym przypadku
programista nie będzie musiał napisać ani jednego wiersza kodu!

Podsumowanie

W tym rozdziale przedstawiono wiele różnych metod integracji wtyczki z
platformą WordPress. Nie wszystkie omówione tutaj metody będziesz
stosował w każdej tworzonej wtyczce, ale istotne jest, by wiedzieć, co
platforma domyślnie oferuje programiście.

Rozdział 5 Internacjonalizacja

W tym rozdziale:

-   Zrozumienie pojęć internacjonalizacji i tłumaczenia wtyczek na inne
    języki
-   Określenie korzyści płynących z internacjonalizacji wtyczek
-   Przygotowanie wtyczek do tłumaczenia na inne języki
-   Używanie oferowanych przez WordPress funkcji internacjonalizacji
-   Internacjonalizacja kodu JavaScript
-   Używanie narzędzi służących do tłumaczenia na inne języki

Internacjonalizacja to akt przygotowania wtyczki do stosowania w wielu
różnych językach. Domyślnym językiem WordPress jest angielski, ale dla
sporej części użytkowników to nie jest język rodzimy. Ta społeczność
przygotowała tłumaczenia platformy WordPress na wiele innych języków
używanych na całym świecie.

Jednym z celów platformy WordPress jest ułatwienie publikowania treści
użytkownikom na całym świecie. Jako twórca wtyczki możesz im ten proces
ułatwić. Z kolei Tobie platforma WordPress ułatwia internacjonalizację
wtyczek, zatem zadanie to nie wiąże się ze szczególnie uciążliwym
wysiłkiem.

Internacjonalizacja i tłumaczenie na inne języki

Dzięki wbudowanym na platformie WordPress funkcjom tłumaczenia na inne
języki tworzoną wtyczkę można w bardzo prosty sposób udostępnić wielu
innym użytkownikom, nawet nie wiedząc, jakimi językami się posługują.
Sam proces tłumaczenia jest obsługiwany przez platformę WordPress, pod
warunkiem że podczas tworzenia wtyczki programista wykonał kilka
prostych kroków.

Internacjonalizacja bazuje na tym, że ciągi tekstowe są opakowane
określonymi wywołaniami funkcji. Dzięki stosowaniu takiej praktyki tekst
jest gotowy do przeprowadzenia internacjonalizacji. Skrótem terminu
internacjonalizacja jest wyrażenie "i18n", z którym można się spotkać w
wielu sytuacjach.

Tłumaczenie to proces przełożenia tekstu na określony język. Platforma
WordPress obsługuje tłumaczenie przy użyciu sprawdzania, czy istnieją
określone pliki tłumaczenia, a następnie na ich podstawie przeprowadza
właściwe tłumaczenie. Zadaniem wtyczki jest obsługa internacjonalizacji,
co pozwoli później na przeprowadzenie tłumaczenia na inne języki.
Skrótem terminu tłumaczenia jest "l10n".

------------------------------------------------------------------------

Ostrzeżenie

Możesz zauważyć, że w tej książce nie wykorzystaliśmy naszych wskazówek
i nie przygotowaliśmy przedstawionych fragmentów kodu do tłumaczenia na
inne języki. Powodem tego jest chęć dostarczenia krótkich i konkretnych
przykładowych fragmentów kodu przy zachowaniu maksymalnej czytelności.
Podczas prac nad wtyczką zawsze należy brać pod uwagę jej
internacjonalizację.

------------------------------------------------------------------------

Dlaczego warto przeprowadzać internacjonalizację?

Internacjonalizacja wtyczki może przynieść korzyści zarówno jej twórcy,
jak i samym użytkownikom wtyczki. W porównaniu do bardziej
skomplikowanych funkcji, których będziesz prawdopodobnie używał podczas
tworzenia wtyczki, internacjonalizacja wydaje się znacznie łatwiejsza,
jeśli stosowane są reguły przedstawione w tym rozdziale.

-   Korzyścią dla programisty jest znacznie większa baza użytkowników
    używających danej wtyczki.
-   Korzyścią dla użytkowników jest możliwość używania wtyczki w
    rodzimym języku.

Po zakończeniu pracy nad wtyczką niektórzy programiści utrzymują ścisłe
kontakty z tłumaczami, aby zagwarantować przygotowanie tłumaczenia
wtyczki. Podczas pracy nad projektami typu open source nawiązywanie
kontaktów z nowymi osobami zawsze jest korzystne. Dzięki
internacjonalizacji otwierasz przed wtyczką jeszcze większe możliwości,
niż w przypadku, gdy wtyczka nie jest tłumaczona na inne języki.

------------------------------------------------------------------------

Uwaga

Jednym z przyjemniejszych zadań jest utworzenie własnego tłumaczenia na
podstawie używanego języka i miejsca zamieszkania. Przykładowo
programista pochodzący z gór może przygotować tłumaczenie wtyczki
zawierające zwroty stosowane w gwarze góralskiej. W ten sposób można
poznać ten sam proces, przez który przechodzą tłumacze wtyczek.

------------------------------------------------------------------------

Zrozumienie zagadnienia internacjonalizacji w profesjonalnej pracy

Ogólnie rzecz biorąc, przygotowywanie wtyczki do tłumaczenia następuje,
jeśli ma być ona dostępna publicznie, ponieważ wielu użytkowników może
mieć witryny internetowe utworzone w innym języku niż używany przez
twórcę wtyczki.

Nie wszystkie wtyczki są przeznaczone do publicznego używania. W trakcie
budowania wtyczki dla klienta nie zawsze trzeba stosować wszystkie
reguły przedstawione w rozdziale. Jeżeli witryna klienta jest tylko w
jednym języku, wówczas potrzeba tłumaczenia wtyczki może w ogóle nie
istnieć. Jednak niektórzy klienci mogą posiadać witryny w wielu
językach, a tym samym chcą, aby wtyczka również była w wielu językach w
celu dostarczania treści we wszystkich językach obsługiwanych przez
witrynę. W takim przypadku trzeba się zatroszczyć o internacjonalizację
wtyczki. Zawsze należy zapytać klienta, czy internacjonalizacja jest
wymagana.

Wprawdzie podczas wykonywania projektów dla klientów nie zawsze
występuje konieczność internacjonalizacji wtyczki, ale zapewnienie
internacjonalizacji całemu tekstowi uznaje się za dobrą praktykę. Dzięki
temu można uniknąć w przyszłości konieczności modyfikacji kodu, gdy
klient zmieni zdanie dotyczące tłumaczenia projektu na inne języki.
Ponadto podczas tworzenia kodu zawsze warto stosować najlepsze praktyki.

Dodatkową potencjalną korzyścią jest poznanie narzędzi przedstawionych w
rozdziale, co stanowi kolejny punkt w CV, na który mogą zwrócić uwagę
klienci wymagający od Ciebie takich umiejętności.

Przygotowanie wtyczki do tłumaczenia na inne języki

Pierwszym krokiem w przygotowaniu wtyczki do tłumaczenia na inne języki
jest użycie funkcji load_plugin_textdomain(). Wymieniona funkcja
nakazuje platformie WordPress wczytanie pliku tłumaczenia w języku
użytkownika, o ile taki plik istnieje.

    <?php
    load_plugin_textdomain( $domain, $abs_rel_path, $plugin_rel_path );
    ?>

Parametry:

-   $domain — unikalny ciąg tekstowy identyfikujący tekst we wtyczce,
    który jest przygotowany do tłumaczenia. Ze względów organizacyjnych
    tutaj powinna być użyta wartość będąca nazwą katalogu wtyczki.
-   $abs_rel_path — ten parametr został porzucony i nie powinien być
    dłużej używany. Najlepszym rozwiązaniem będzie ustawienie mu
    wartości false.
-   $plugin_rel_path — względna ścieżka dostępu do plików tłumaczeń
    wtyczki znajdujących się w katalogu wtyczki (WP_PLUGIN_DIR).

Jeżeli tworzona wtyczka znajduje się w katalogu o nazwie boj-plugin, kod
będzie miał następującą postać:

    <?php
    load_plugin_textdomain('boj-plugin', false, 'boj-plugin/languages');
    ?> 

W powyższym fragmencie kodu parametr $domain ma wartość boj-plugin
odpowiadającą nazwie katalogu, parametr $abs_rel_path ma wartość false,
ponieważ jest niepotrzebny, natomiast parametr $plugin_rel_path ma
wartość boj-plugin/languages, gdyż w wymienionym podkatalogu są
przechowywane pliki z tłumaczeniami.

Ostatni parametr wskazuje katalog wtyczki (boj-plugin) oraz jego
podkatalog (languages). Dobrą praktyką jest utworzenie w katalogu
wtyczki dodatkowego podkatalogu o nazwie languages przeznaczonego do
przechowywania wszystkich plików tłumaczeń. Jeżeli kiedykolwiek wtyczka
będzie przetłumaczona na więcej niż kilka języków, podkatalog okaże się
użyteczny, ponieważ w przeciwnym razie wszystkie pliki tłumaczeń
musiałyby znaleźć się w katalogu głównym wtyczki, a to spowoduje
zaśmiecenie go.

Wyświetlanie i zwracanie ciągów tekstowych

Platforma WordPress ma wiele użytecznych funkcji ułatwiających proces
internacjonalizacji. Za każdym razem, gdy do wtyczki jest dodawana treść
w postaci tekstu, powinna być ona opakowana jedną z funkcji WordPress
obsługujących tłumaczenie.

Niemal każda z tego rodzaju funkcji ma przynajmniej jedną zmienną, która
będzie używana, jest to $domain. Ta unikalna zmienna została
wykorzystana w poprzednim punkcie. Wartość zmiennej pozwala platformie
WordPress na rozpoznanie jej jako części plików tłumaczenia wtyczki.

Podczas wyświetlania plików tworzących jądro WordPress można zauważyć,
że zmienna $domain nigdy nie jest ustawiania. Platforma używa wartości
domyślnej, więc wtyczka powinna posiadać unikalny ciąg tekstowy
odróżniający go od stosowanego przez WordPress.

Funkcja __()

Działanie funkcji __() sprowadza się do oznaczenia tekstu jako gotowego
do przetłumaczenia i zwrócenia go do użycia w PHP. W przedstawionym
poniżej przykładzie wartość zwrotna funkcji __() zostaje przypisana
zmiennej PHP. Warto zwrócić uwagę, że wymieniona funkcja ma w nazwie dwa
znaki podkreślenia, a nie jeden.

    <?php
    $text = __( 'WordPress to wspaniała platforma publikacji bloga.',
       'boj-plugin/languages' );
    ?> 

Funkcja _e()

Funkcja _e() powoduje, że tekst jest gotowy do przetłumaczenia. Działa
podobnie do funkcji echo() w PHP, wyświetlając tekst na ekranie. Zmienna
$text zawiera treść przeznaczoną do przetłumaczenia. Poniższy przykład
powoduje dodanie komunikatu do stopki witryny przy użyciu zaczepu akcji
(zaczepy zostały omówione w rozdziale 3.).

    <?php
    /* Rejestracja w zaczepie funkcji wyświetlającej komunikat. */
    add_action( 'wp_footer', 'boj_footer_message' );
    /* Funkcja powoduje wyświetlenie komunikatu w stopce witryny. */
    function boj_footer_message() {
        /* Wyświetlenie przetłumaczonego tekstu. */
        _e( 'Ta witryna działa na bazie najlepszej platformy &mdash; WordPress.',
        'boj-plugin' );
    }
    ?> 

Funkcja esc_attr__()

Funkcja esc_attr__() to obsługujący internacjonalizację odpowiednik
funkcji esc_attr(), która dokładnie została omówiona w rozdziale 6.
Zadaniem tej funkcji jest unieszkodliwianie niebezpiecznych znaków w
atrybutach HTML. W ten sposób kod spełnia standardy, a witryna staje się
mniej narażona na potencjalne luki w zabezpieczeniach.

Wartością zwrotną funkcji esc_attr__() jest przetłumaczony tekst możliwy
do użycia w PHP. W poniższym przykładzie pokazano utworzenie funkcji,
która zwraca odnośnik do strony zawierającej regulamin korzystania z
witryny i wyświetla tę stronę.

    <?php
    /* Funkcja zwraca odnośnik do strony zawierającej regulamin korzystania z witryny. */
    function boj_terms_of_service_link() {
        return '<a href="http://przyklad.pl/tos" title="' .
        esc_attr__( 'Wyświetl stronę z regulaminem korzystania z witryny',
           'boj-plugin' ) . '">' .  __( 'Regulamin korzystania z witryny',
           'boj-plugin' ) . '</a>';
    }
    /* Wyświetlenie danych wyjściowych funkcji boj_terms_of_service_link(). */
    echo boj_terms_of_service_link();
    ?> 

Funkcja esc_attr_e()

Funkcja esc_attr_e() działa w taki sam sposób jak esc_attr__() z
wyjątkiem tego, że tłumaczenie wyświetla na ekranie. Jeżeli przykładowo
chcesz wyświetlić odnośnik do strony administracyjnej kokpitu platformy
WordPress, musisz się upewnić o prawidłowym działaniu atrybutu title w
odnośniku. Można również użyć przedstawionej wcześniej funkcji _e().

    <a href="<?php echo admin_url('dashboard.php ); ?>"
    title="<?php esc_attr_e( 'Wyświetl kokpit platformy WordPress',
       'boj-plugin' ); ?>" > <?php _e( 'Dashboard', 'boj-plugin' ); ?></a> 

Funkcja esc_html__()

Funkcja esc_html__() to obsługujący tłumaczenie odpowiednik omówionej w
rozdziale 6. funkcji WordPress o nazwie esc_html(). Ta funkcja przydaje
się w sytuacjach, gdy użycie kodu HTML jest niewskazane. Wartość zwrotna
funkcji jest przeznaczona do użycia w PHP.

Przypuśćmy, że formularz został wysłany wraz z zawartością pola
<textarea>, w którym znajdował się komunikat domyślny. W takim przypadku
trzeba sprawdzić wprowadzone przez użytkownika dane wejściowe lub
komunikat domyślny dostarczony przez tłumacza.

    <?php
    function boj_get_text_message() {
        /* Jeżeli użytkownik wprowadził jakiekolwiek dane wejściowe, trzeba je sprawdzić. */
        if ( !empty( $_POST['boj-text'] ) )
            $message = esc_html( $_POST['boj-text'] );
        /* Jeżeli użytkownik nie wprowadził żadnych danych wejściowych, trzeba użyć domyślnego
            przetłumaczonego komunikatu. */
        else
            $message = esc_html__( 'Użytkownik nie podał żadnych danych.', 'boj-plugin' );
        return $message;
    }
    ?> 

Funkcja esc_html_e()

Funkcja esc_html_e() zachowuje się w taki sam sposób jak esc_html__() z
wyjątkiem faktu, że przetłumaczony tekst wyświetla na ekranie, zamiast
go zwracać do użycia w PHP. Przykładowo możesz użyć formularza
sieciowego wraz z tekstem domyślnym w elemencie <textarea>, ale chcesz
mieć pewność, że nie będzie wyświetlony żaden kod HTML.

    <textarea name="boj-text" id="boj-text"> 
    <?php esc_html_e( 'Proszę podać opis.', 'boj-plugin' ); ?> 
    </textarea> 

Funkcja _x()

Czasami trzeba zapewnić kontekst tłumaczenia. Funkcja _x() umożliwia
twórcy wtyczki wielokrotne użycie we wtyczce tego samego ciągu
tekstowego. Przeznaczeniem tej funkcji jest dostarczenie kontekstu, w
którym ma być użyty dany ciąg tekstowy.

Załóżmy, że pracujesz nad wtyczką SEO, w której wielokrotnie występuje
ciąg tekstowy SEO. W przedstawionym poniżej przykładzie na stronie
administracyjnej wpisu bloga dodawane jest pole użytkownika (pola
użytkownika zostały omówione w rozdziale 4.) z ustawieniami SEO. Dla
tego konkretnego wystąpienia SEO można dostarczyć dodatkowy kontekst.

    <?php
    add_action( 'admin_menu', 'boj_add_seo_meta_box' );
    function boj_add_seo_meta_box() {
        add_meta_box(
            'boj_seo_meta_box',
            _x( 'SEO', 'pole użytkownika', 'boj-plugin' ),
            'boj_seo_meta_box_callback',
            'post',
            'advanced'
        );
    }
    function boj_seo_meta_box_callback() {
        _e( 'Przykład pola użytkownika.', 'boj-plugin' );
    }
    ?> 

Funkcja _ex()

Funkcja _ex() jest używana, gdy trzeba podkreślić określony kontekst dla
ciągu tekstowego. Działa na takiej samej zasadzie jak funkcja _x() z
wyjątkiem faktu, że wyświetla dane wyjściowe, zamiast zwracać je do
dalszego przetwarzania w PHP.

Ten sam komunikat może być użyty w wielu miejscach wtyczki, ale każde
wystąpienie może mieć zupełnie inne znaczenie. W systemach blogów słowo
Post jest często używane i jako rzeczownik, i jako czasownik. Podczas
internacjonalizacji trzeba zaznaczyć między nimi różnicę poprzez podanie
kontekstu.

Wykorzystanie drugiego parametru $context dostarcza tłumaczom kontekstu
dotyczącego danego użycia terminu.

Przedstawiony poniżej fragment kodu pokazuje użycie terminu Post oraz
oznaczenie jego użycia jako zarówno rzeczownika, jak i czasownika.

    <?php
    /* Użycie terminu "Post" jako rzeczownika. */
    _ex( 'Post', 'rzeczownik', 'boj-plugin' );
    /* Użycie terminu "Post" jako czasownika. */
    _ex( 'Post', 'czasownik', 'boj-plugin' );
    ?> 

Dobrze napisany tekst ma ogromne znaczenie. Przed użyciem funkcji
kontekstu tłumaczenia zadaj sobie pytanie, czy sam tekst można napisać w
jeszcze jaśniejszy sposób. Wówczas zamiast używania ogólnych terminów
można zastosować te, które są łatwiejsze do zrozumienia dla tłumaczy i
użytkowników wtyczki.

Słowo Post jako rzeczownik można lepiej zapisać jako Select a post,
natomiast w przypadku czasownika lepsze może być określenie Submit post.
W takiej sytuacji nie będzie konieczności użycia funkcji _ex(), zamiast
tego wystarczy skorzystać z funkcji _e().

    <?php
    _e( 'Select a post', 'boj-plugin' );
    _e( 'Submit post', 'boj-plugin' );
    ?> 

Funkcja esc_attr_x()

Funkcja esc_attr_x() to połączenie dwóch wcześniej przedstawionych
funkcji tłumaczenia: esc_attr__() i _x(). Pozwala ona na tłumaczenie
tekstu, zapewnia kontekst dla tłumaczenia oraz ma możliwość
unieszkodliwienia niebezpiecznych znaków z atrybutów HTML. Wartością
zwrotną funkcji jest przetłumaczony tekst gotowy do użycia w PHP.
Funkcja nie ma jednak odpowiednika powodującego wyświetlenie tekstu na
ekranie.

W przedstawionym poniżej fragmencie kodu funkcja wyświetla odnośnik do
strony administracyjnej WordPress. Użycie funkcji esc_attr_x() w
atrybucie title odnośnika powoduje unieszkodliwienie niebezpiecznych
znaków oraz zapewnia kontekst dla ciągu tekstowego "Admin".

    <?php
    function boj_plugin_display_post_link( $post_id ) {
        /* Tekst odnośnika. */
        $boj_link_text = _x(
            'Admin',
            'odnośnik administracyjny',
            'boj-plugin'
        );
        /* Tekst dla atrybutu "title" odnośnika. */
        $boj_link_title = esc_attr_x(
            'Admin',
            'odnośnik administracyjny',
            'boj-plugin'
        );
        /* Wyświetlenie odnośnika na ekranie. */
        echo '<a href="' . admin_url( 'dashboard.php' ) . '"
        title="' . $boj_link_title . '"> ' . $boj_link_text . '</a>';
    }
    ?> 

Funkcja esc_html_x()

Funkcja esc_html_x() łączy esc_html() i _x() w pojedynczą funkcję
pozwalającą na tłumaczenie tekstu, unieszkodliwianie niebezpiecznego
kodu HTML oraz dostarczenie kontekstu tłumaczom.

Załóżmy, że utworzyłeś wtyczkę pozwalającą użytkownikom na wypełnienie
formularza dotyczącego ulubionych zadań, który następnie jest
przekazywany właścicielowi witryny w celu analizy. Zakładamy także
istnienie opcjonalnego pola tekstowego o nazwie boj-favorite-food,
którego wartość domyślna powinna być przetłumaczona. W omawianym
przykładzie wartością domyślną jest słowo "Brak", które może być
wykorzystywane w różnych sytuacjach. Aby określić prawidłowe użycie
słowa "Brak", trzeba podać kontekst, np. "ulubione jedzenie" lub
"ulubione zadanie".

    <?php
    function boj_get_favorite_food() {
        /* Jeżeli użytkownik wprowadził wartość w tym polu. */
        if ( !empty( $_POST['favorite-food'] ) )
            $boj_favorite_food = esc_html( $_POST['favorite-food'] );
        /* Jeżeli użytkownik nie wprowadził wartości w polu, wówczas użyta będzie domyślna. */
        else {
            $boj_favorite_food = esc_html_x(
                'Brak',
                'ulubione jedzenie',
                'boj-plugin'
            );
        }
        return $boj_favorite_food;
    }
    ?> 

Funkcja _n()

Jako programista nie zawsze będziesz znał liczbę elementów zwracanych do
użycia w Twoim kodzie PHP. W takich sytuacjach zawsze można użyć funkcji
_n() w celu rozróżnienia tekstów w liczbie pojedynczej i mnogiej.
Tytułowa funkcja nie tylko określi formę, która powinna być użyta, ale
również spowoduje, że każda forma będzie możliwa do tłumaczenia.
Internacjonalizacji trzeba poddać tekst zarówno w liczbie pojedynczej,
jak i mnogiej, ponieważ w wielu językach podczas stosowania formy liczby
pojedynczej i mnogiej zmienia się kolejność słów.

Parametry wymienionej funkcji są odmienne od stosowanych w pozostałych
funkcjach obsługujących tłumaczenie. Parametr $single przedstawia tekst
w liczbie pojedynczej, $plural — tekst w liczbie mnogiej. Z kolei
wartość parametru $number może nie być znana w czasie tworzenia kodu. To
po prostu nieznana liczba całkowita, która może przyjąć różne wartości.

Nie wszystkie języki używają tylko dwóch form (liczby pojedynczej i
mnogiej). Jednak podczas tworzenia wtyczki trzeba zapewnić obsługę
jedynie dwóch wymienionych form. Jeżeli język wymaga większej liczby
form, wówczas tłumacze dostarczą je w plikach tłumaczenia, a odpowiednia
forma będzie użyta podczas procesu tłumaczenia na platformie WordPress.

Poniżej przedstawiono przykład funkcji obliczającej liczbę wpisów bloga
opublikowanych na witrynie, a następnie wyświetlającej tę wartość w
zdaniu. Do wyświetlenia zdania użyta jest funkcja printf(). (Więcej
informacji na ten temat przedstawiono w podrozdziale "Używanie miejsc
zarezerwowanych", który znajduje się dalej w tym rozdziale).

    <?php
    function boj_count_published_posts() {
        /* Obliczenie liczby wpisów bloga. */
        $boj_count_posts = wp_count_posts();
        /* Pobranie liczby wpisów bloga, dla których stan post_status ma wartość 'publish'. */
        $count = $boj_count_posts->publish;
        /* Wyświetlenie zdania zawierającego liczbę opublikowanych wpisów bloga. */
        printf( _n(
            'Opublikowałeś %s wpis bloga.', 'Opublikowałeś %s wpisów bloga.',
            $count,
            'boj-plugin' ),
        $count );
    }
    ?> 

Dwa zdania w funkcji printf() wyglądają podobnie i większość
programistów może sądzić, że łatwiejszym podejściem będzie użycie
pojedynczego zdania "Opublikowałeś %s wpis(ów) bloga." Wprawdzie takie
rozwiązanie sprawdzi się w wielu językach, to jednak nie we wszystkich.

Przykładowo taka metoda nie sprawdzi się podczas zapisu powyższego
zdania w języku francuskim z użyciem słowa journal. W tym przypadku nie
można zastosować wyrażenia "journal(ów)", ponieważ liczba mnoga od
journal brzmi journaux.

Funkcja _nx()

Funkcja _nx() do połączenie funkcji tłumaczeń _n() i _x(). Pozwala ona
na rozróżnienie liczby pojedynczej i mnogiej oraz zapewnia kontekst dla
tłumaczonego tekstu.

W przedstawionym poniżej kodzie pokazano utworzenie funkcji
przechwytującej wszystkie tagi wpisów bloga na witrynie oraz
wyświetlającej liczbę wpisów bloga, które mają przypisany konkretny tag.
Funkcja _nx() umożliwia wyświetlenie tekstu na podstawie liczby wpisów
bloga dla każdego tagu oraz zapewnia kontekst dla tłumaczonego tekstu.

    <?php
    function boj_list_post_tag_counts() {
        /* Pobranie wszystkich tagów wpisów bloga i umieszczenie w liście ułożonej alfabetycznie. */
        $tags = get_terms( 'post_tag', array( 'orderby' => 'name', 'order' => 'ASC' ) );
        /* Początek znacznika nieuporządkowanej listy. */
        echo '<ul>';
        /* Iteracja przez wszystkie tagi wpisów bloga i wyświetlenie liczby wpisów bloga oraz nazwy tagu. */
        foreach ( $tags as $tag ) {
            echo '<li>';
            printf(
                _nx(
                    '%s wpis bloga',
                    '%s wpisów bloga',
                    $tag->count,
                    'liczba wpisów bloga',
                    'boj-plugin'
                ),
                $tag->count
            );
            echo '</li>';
        }
        /* Zamknięcie znacznika nieuporządkowanej listy. */
        echo '</ul>';
    }
    ?> 

Funkcja _n_noop()

Zdarzają się sytuacje, w których liczby pojedyncza i mnoga tekstu nie
powinny być tłumaczone w danym miejscu, ale powinny być przetłumaczone
dopiero później. Jest to użyteczne w przypadku posiadania ogromnych list
komunikatów, które mają być wyświetlane dopiero po ustawieniu
odpowiedniej zmiennej.

Funkcja _n_noop() dodaje te wartości do plików tłumaczeń. Zamiast,
podobnie jak inne funkcje tłumaczenia, zwracać przetłumaczony ciąg
tekstowy, wartością zwrotną funkcji jest tablica zawierająca obie
wartości.

Załóżmy, że utworzyłeś dwa własne rodzaje wpisów bloga (więcej
informacji na ten temat znajduje się w rozdziale 11.) o nazwach video i
music, aby udostępnić użytkownikom wtyczki pewne ciekawe funkcje do
użycia na ich witrynach. Wtyczka zawiera komunikaty, które powinny w
niej być, ale chcesz maksymalnie skrócić kod i ułatwić sobie jego
ponowne wykorzystanie. W przedstawionym poniżej przykładzie utworzono
funkcję pobierającą parametr $post_type. Funkcja powoduje wyświetlenie
odpowiedniego komunikatu na podstawie wartości wymienionego parametru.

    <?php
    function boj_count_posts_of_cusboj_types( $post_type = 'video' ) {
        /* Obliczenie liczby wszystkich wpisów bloga dla wskazanego rodzaju wpisu. */
        $all_posts = wp_count_posts( $post_type );
        /* Pobranie liczby opublikowanych wpisów bloga. */
        $count = $all_posts->publish;
        /* Przygotowanie tablicy komunikatów. */
        $boj_messages = array(
            'video' => _n_noop( 'Masz %s wpis z tagiem video.',
               'Masz %s wpisów z tagiem video.' ),
            'music' => _n_noop( 'Masz %s wpis z tagiem music.',
               'Masz %s wpisów z tagiem.' )
        );
        /* Pobranie komunikatu dla wskazanego typu wpisu bloga. */
        $boj_message = $boj_messages[$post_type];
        /* Wyświetlenie komunikatu dotyczącego własnego typu wpisu bloga oraz liczby wpisów. */
        printf( _n(
            $boj_message['singular'],
            $boj_message['plural'],
            $count
        ), $count );
    }
    ?> 

Funkcja _n_noop() została użyta do utworzenia tablicy komunikatów,
natomiast wyświetlenie przetłumaczonych komunikatów odbywa się za pomocą
funkcji _n(). W ten sposób tłumaczenie jest stosowane jedynie przy
wymagających tego komunikatach, a nie we wszystkich.

Funkcja _nx_noop()

Funkcja _nx_noop() to połączenie funkcji _n_noop() i _x(). Pozwala na
późniejsze przetłumaczenie tekstu oraz dostarcza tłumaczom kontekst
dotyczący użycia danego tekstu we wtyczce. Działa na takiej samej
zasadzie jak funkcja _n_noop(): dodaje tekst do plików tłumaczenia, ale
nie tłumaczy ich podczas używania w PHP.

Przedstawiony powyżej przykład został zmodyfikowany w celu wyświetlenia
liczby opublikowanych wpisów bloga z uwzględnieniem ich typu. Funkcji
_nx_noop() użyto w celu dostarczenia kontekstu.

    <?php
    function boj_count_posts_of_custom_types( $post_type = 'video' ) {
        /* Obliczenie liczby wszystkich wpisów bloga dla wskazanego rodzaju wpisu. */
        $all_posts = wp_count_posts( $post_type );
        /* Pobranie liczby opublikowanych wpisów bloga. */
        $count = $all_posts->publish;
        /* Przygotowanie tablicy komunikatów. */
        $boj_messages = array(
            'video' => _n_noop(
                '%s wpis z tagiem video',
                '%s wpisów z tagiem video',
                'liczba wpisów bloga'
            ),
            'music' => _n_noop(
                '%s wpis z tagiem music',
                '%s wpisów z tagiem music',
                'liczba wpisów bloga'
            )
        );
        /* Pobranie komunikatu dla wskazanego typu wpisu bloga. */
        $boj_message = $boj_messages[$post_type];
        /* Wyświetlenie komunikatu dotyczącego własnego typu wpisu bloga oraz liczby wpisów. */
        printf( _n(
            $boj_message['singular'],
            $boj_message['plural'],
            $count
        ), $count );
    }
    ?> 

Używanie miejsc zarezerwowanych

W przedstawionych wcześniej przykładach mogłeś zauważyć użycie symboli,
takich jak %s i %1$s. Symbole te są miejscami zarezerwowanymi dla
zmiennych. Miejsca zarezerwowane są użyteczne, ponieważ pozwalają na
tłumaczenie ciągów tekstowych bez ich rozkładania na części.

Funkcje tłumaczenia na platformie WordPress nie mogą umieszczać miejsc
zarezerwowanych w danych wyjściowych. Miejsca zarezerwowane są
przeznaczone jedynie dla tłumaczy w celu prawidłowego umieszczania
tekstu w plikach tłumaczeń. Muszą być wypełnione przez daną zmienną w
PHP.

Funkcje PHP printf() i sprintf() są bardzo użyteczne podczas stosowania
miejsc zarezerwowanych. Obie mogą zastąpić miejsce zarezerwowane
wskazaną zmienną. Do wyświetlania tekstu na ekranie używana jest funkcja
printf(), natomiast do zwrócenia tekstu stosowana jest funkcja
sprintf(). Pierwszym parametrem obu wymienionych funkcji jest $text,
czyli tekst przeznaczony do przetłumaczenia. Obydwie funkcje mogą
otrzymać dowolną liczbę parametrów dodatkowych przedstawiających miejsca
zarezerwowane w zmiennej $text.

Warto spojrzeć na przykład przetłumaczonego zdania, które jest poprawne
w języku polskim, ale już niekoniecznie w innych językach.

    <?php
    function boj_display_blog_name() {
        _e( 'Tytuł Twojego bloga brzmi ', 'boj-plugin' );
        echo get_bloginfo( 'name' );
        _e( '.', 'boj-plugin' );
    }
    ?> 

Wprawdzie tekst w powyższej funkcji jest poddawany internacjonalizacji,
ale nie odbywa się to w sposób ułatwiający jego tłumaczenie. Tutaj z
pomocą przychodzą miejsca zarezerwowane. Pozwalają na umieszczenie
zmiennej w tekście i zachowanie całości w pojedynczym zdaniu.

Poniżej przedstawiono zmodyfikowaną wersję powyższej funkcji, ale tym
razem ułatwiającej tłumaczom przetłumaczenie tekstu. Do wyświetlenia
zdania na ekranie i wypełnienia miejsc zarezerwowanych użyto funkcji
printf().

    <?php
    function boj_display_blog_name() {
        printf(
            __( 'Tytuł Twojego bloga brzmi %s.', 'boj-plugin' ),
            get_bloginfo( 'name' )
        );
    }?> 

Teraz można utworzyć funkcję zwracającą slogan wykorzystany na witrynie.
Odbywa się to poprzez wyświetlenie za pomocą funkcji sprintf() zdania
zawierającego wspomniany slogan.

    <?php
    function boj_get_blog_tagline() {
        return sprint(
            __( 'Slogan Twojej witryny to %s.', 'boj-plugin' ),
            get_bloginfo('description' )
        );
    }
    ?> 

Czasami w pojedynczym ciągu tekstowym trzeba umieścić kilka miejsc
zarezerwowanych. Na szczęście, zarówno funkcja printf(), jak i sprintf()
doskonale radzą sobie z taką sytuacją. Największa różnica polega na tym,
aby nie używać symbolu %s. W takim przypadku najlepiej stosować
ponumerowane miejsca zarezerwowane, ponieważ kolejność słów w innych
językach może być różna.

W przedstawionym poniżej przykładzie wykorzystano kilka miejsc
zarezerwowanych; zdanie jest wyświetlane na podstawie liczby
opublikowanych wpisów bloga oraz zawiera tytuł witryny.

    <?php
    function boj_display_blog_name_and_post_count() {
        /* Pobranie liczby wpisów bloga. */
        $count_posts = wp_count_posts();
        /* Pobranie liczby opublikowanych wpisów bloga. */
        $count = $count_posts->publish;
        /* Pobranie tytułu witryny. */
        $site_name = get_bloginfo( 'name' );
        /* Wyświetlenie zdania na podstawie liczby opublikowanych wpisów bloga. */
        printf(
            _n(
                'Opublikowano %1$s wpis bloga na witrynie %2$s.',
                'Opublikowano %1$s wpisów bloga na witrynie %2$s.',
                $count,
                'boj-plugin'
            ),
            $count, $site_name
        );
    }
    ?> 

W powyższym przykładzie miejsce zarezerwowane %1$s przedstawia zmienną
$count, która zwraca liczbę opublikowanych wpisów bloga. Natomiast
miejsce zarezerwowane %2s przedstawia wartość zmiennej $site_name
zawierającej tytuł witryny.

Internacjonalizacja kodu JavaScript

Niektóre wtyczki do prawidłowego działania wymagają skryptów JavaScript.
(Więcej informacji na temat skryptów JavaScript i technologii Ajax
znajduje się w rozdziale 12.). Ponieważ funkcje internacjonalizacji na
platformie WordPress są utworzone w PHP, nie można ich używać w plikach
JavaScript. Z tego powodu tłumaczenie skryptów JavaScript jest nieco
trudniejsze, ale możliwe do zrobienia.

Platforma WordPress oferuje funkcję o nazwie wp_localize_script()
pozwalającą na przekazanie przetłumaczonego ciągu tekstowego do
zewnętrznego pliku. W ten sposób przetłumaczone ciągi tekstowe można
stosować w skryptach JavaScript. Warto spojrzeć na wymienioną funkcję.

    <?php
    wp_localize_script( $handle, $object_name, $l10n );
    ?> 

Parametry:

-   $handle — wartość tego parametru musi odpowiadać parametrowi $handle
    użytemu podczas rejestracji skryptu na platformie WordPress (więcej
    informacji na ten temat znajduje się w rozdziale 12.).
-   $object_name — to unikalny identyfikator przedstawiający dany zbiór
    tłumaczenia.
-   $l10n — to tablica tłumaczeń, w której kluczom są przypisane
    wartości w postaci pojedynczych ciągów tekstowych tłumaczeń.

W celu zrozumienia sposobu działania całości konieczne jest utworzenia
wtyczki korzystającej ze skryptów JavaScript. W tym miejscu utworzono
zatem prosty skrypt. Aby dowiedzieć się więcej na temat korzystania ze
skryptów JavaScript, warto zapoznać się z rozdziałem 12. Zbudowana tutaj
wtyczka umieści w stopce witryny dwa przyciski. Po kliknięciu
któregokolwiek z nich nastąpi wyświetlenie przetłumaczonego komunikatu.

Pierwszym krokiem jest otwarcie nowego katalogu wtyczki o nazwie
boj-alert-box i umieszczenie w nim nowego pliku PHP o nazwie
boj-alert-box.php. Do tego pliku należy dodać informacje dotyczące
wtyczki (zobacz rozdział 2.).

    <?php
    /**
     * Plugin Name: Okno komunikatu
     * Plugin URI: http://przyklad.pl
     * Description: Przykład wtyczki umieszczającej dwa przyciski w stopce witryny internetowej. Po kliknięciu dowolnego z nich następuje wyświetlenie okna z komunikatem.
     * Version: 0.1
     * Author: WROX
     * Author URI: http://wrox.com
     */ 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-alert-box.php.

------------------------------------------------------------------------

Kolejnym krokiem jest wczytanie tłumaczenia zgodnie z opisem
przedstawionym w podrozdziale "Przygotowanie wtyczki do tłumaczenia"
znajdującym się we wcześniejszej części rozdziału.

    /* Dodanie funkcji tłumaczenia po wczytaniu zaczepu wtyczki. */
    add_action( 'plugins_loaded', 'boj_alert_box_load_translation' );
    /**
     * Wczytanie pliku tłumaczenia, jeśli wyświetlana strona nie jest administracyjna.
     *
     * @since 0.1
     */
    function boj_alert_box_load_translation() {
        /* Jeżeli to nie jest strona administracyjna, można wczytać tłumaczenie wtyczki. */
        if ( !is_admin() )
           load_plugin_textdomain( 'boj-alert-box', false, 'boj-alert-box/languages' );
    } 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-alert-box.php.

------------------------------------------------------------------------

Na tym etapie skrypt trzeba wczytać za pomocą funkcji
wp_enqueue_script(). Po wywołaniu wymienionej funkcji można przystąpić
do tłumaczenia skryptu przy użyciu funkcji wp_localize_script(). Bardzo
ważne jest wywołanie tej funkcji dopiero po zarejestrowaniu skryptu,
ponieważ wówczas będzie dostępna zmienna $handle.

    /* Dodanie funkcji skryptu do zaczepu akcji. */
    add_action( 'wp_print_scripts', 'boj_alert_box_load_script' );
    /**
     * Wczytanie skryptu i przetłumaczenie ciągów tekstowych.
     *
     * @since 0.1
     */
    function boj_alert_box_load_script() {
        /* Jeżeli to strony administracyjne WordPress, nie ma potrzeby dalszego wykonywania funkcji. */
        if ( is_admin() )
            return;
        /* Pobranie ścieżki dostępu i nazwy pliku skryptu. */
        $script = trailingslashit( plugins_url( 'boj-alert-box' ) ) .
        'boj-alert-box-script.js';
        /* Zakolejkowanie skryptu do użycia. */
        wp_enqueue_script( 'boj-alert-box', $script, false, 0.1 );
        /* Przetłumaczenie ciągów tekstowych używanych w skrypcie JavaScript. */
        wp_localize_script( 'boj-alert-box', 'boj_alert_box_l10n', array(
            'boj_box_1' => __( 'Te okna są irytujące!', 'boj-alert-box' ),
            'boj_box_2' => __( 'Te okna naprawdę są irytujące!', 'boj-alert-box' ),
        ) );
    } 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-alert-box.php.

------------------------------------------------------------------------

Teraz w stopce witryny można umieścić dodatkowe przyciski. Warto zwrócić
uwagę na użycie funkcji esc_attr__() omówionej wcześniej w tym rozdziale
i służącej do tłumaczenia oraz unieszkodliwiania niebezpiecznych znaków
z atrybutów value przycisków.

    /* Umieszczenie w stopce witryny przycisków powodujących wyświetlenie komunikatu. */
    add_action( 'wp_footer', 'boj_alert_box_display_buttons' );
    /**
     * Wyświetla dwa przyciski w znaczniku akapitu. Każdy przycisk ma zdefiniowane zdarzenie onClick()
     * powodujące wyświetlenie okna komunikatu JavaScript.
     *
     * @since 0.1
     */
    function boj_alert_box_display_buttons() {
        /* Przygotowanie kodu HTML dla pierwszego przycisku. */
        $boj_alert_box_buttons = '<input type="button" onclick="boj_show_alert_box_1()"
        value="' . esc_attr__( 'Naciśnij mnie!', 'boj-alert-box' ) . '" />';
        /* Przygotowanie kodu HTML dla drugiego przycisku. */
        $boj_alert_box_buttons .= '<input type="button" onclick="boj_show_alert_box_2()"
        value="' . esc_attr__( 'Teraz naciśnij mnie!', 'boj-alert-box' ) . '" />';
        /* Opakowanie przycisków znacznikiem akapitu. */
        echo '<p>' . $boj_alert_box_buttons . '</p>';
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-alert-box.php.

------------------------------------------------------------------------

Plik PHP wtyczki jest już kompletny. Kolejnym krokiem jest dodanie do
katalogu wtyczki pliku JavaScript o nazwie boj-alert-box-script.js. Po
utworzeniu pliku trzeba w nim umieścić dwie funkcje odpowiedzialne za
wyświetlanie komunikatów. W tym celu do pliku boj-alert-box-script.js
należy dodać przedstawiony poniżej kod.

    /**
     * Po wywołaniu funkcja wyświetla pierwszy przetłumaczony komunikat.
     */
    function boj_show_alert_box_1() {
        alert( boj_alert_box_l10n.boj_box_1 );
    }
    /**
     * Po wywołaniu funkcja wyświetla drugi przetłumaczony komunikat.
     */
    function boj_show_alert_box_2() {
        alert( boj_alert_box_l10n.boj_box_2 );
    } 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-alert-box-script.js.

------------------------------------------------------------------------

Ponieważ wtyczka składa się z więcej niż jednego pliku, wzajemne
interakcje pomiędzy nimi mogą być trudne do wychwycenia.

Dwa najważniejsze parametry z wywołania funkcji wp_localize_script() to
$object_name i $l10n. W przykładowej wtyczce parametr $object_name ma
wartość boj_alert_box_l10n, natomiast wartością parametru $l10n jest
tablica par klucz-wartość.

Gdy trzeba było przetłumaczyć ciąg tekstowy w skrypcie JavaScript, użyto
wywołania $object_name.$l10n[$key]. W funkcji JavaScript odpowiedzialnej
za wyświetlenie pierwszego komunikatu to wywołanie miało postać:

    alert( boj_alert_box_l10n.boj_box_2 );

Tworzenie plików tłumaczenia

Po wykonaniu najtrudniejszej pracy związanej z internacjonalizacją
ciągów tekstowych we wtyczce do zrobienia pozostał jeszcze jeden krok.
Ten krok wymaga znacznie mniejszego nakładu pracy niż poprzednie.
Konieczne jest utworzenie domyślnego pliku tłumaczenia w celu
rozpoczęcia procesu tłumaczenia przez potencjalnych tłumaczy.

W celu dostarczenia spójnego opisu przebiegu tego procesu pracę warto
kontynuować na przykładzie wtyczki opracowanej w poprzednim
podrozdziale.

Pliki MO i PO

Kiedy tłumacze przygotowują tłumaczenie wtyczki, na podstawie pliku POT
wtyczki tworzą dwa kolejne pliki: boj-alert-box-$locale.mo i
boj-alert-box-$locale.po.

boj-alert-box to parametr $domain używany w funkcjach tłumaczenia w
całej wtyczce. $locale to zmienna przedstawiająca język oraz dialekt
regionalny. Przykładowo językiem domyślnym WordPress jest en_US, gdzie
en oznacza język angielski, natomiast US to region.

Plik PO jest używany przez narzędzia służące do tłumaczenia i pozwala na
utworzenie tekstu czytelnego dla człowieka. Tłumacze pracują na tym
pliku i przygotowują odpowiednie tłumaczenie. Plik PO nie jest wymagany
do użycia przygotowanego tłumaczenia wtyczki, ale zawsze warto go
umieszczać wraz z wtyczką. W ten sposób inni użytkownicy mogą uaktualnić
ten plik i dostosować do własnych wymagań.

Plik MO powstaje na podstawie ukończonego tłumaczenia. Platforma
WordPress używa tego pliku w celu przeprowadzenia internacjonalizacji
ciągów tekstowych w przetłumaczonej wtyczce.

Ustawienia lokalne na platformie WordPress są zdefiniowane w pliku
wp-config.php. Wspomniane ustawienia powodują, że platforma WordPress
szuka tłumaczeń, a następnie je wczytuje. Jeżeli ustawienia lokalne
użytkownika to fr_FR (Francja), wówczas dla omówionej wtyczki platforma
WordPress wczyta plik boj-alert-box-fr_FR.mo, jeśli taki istnieje.

Narzędzia służące do tłumaczenia

W internecie można znaleźć wiele narzędzi typu open source służących do
tłumaczenia. Narzędzia te nie będą szczegółowo omówione w rozdziale,
ponieważ podczas przygotowywania tłumaczenia każde z nich działa na
innej zasadzie. Jednak niżej przedstawiono listę narzędzi służących do
tłumaczenia, które są obsługiwane na platformie WordPress.

Do dyspozycji tłumacza są dostępne następujące narzędzia:

-   Poedit — http://www.poedit.net/,
-   GlotPress — http://blog.glotpress.org/,
-   Launchpad — https://translations.launchpad.net/,
-   Pootle — http://pootle.locamotion.org/,
-   KBabel — http://i18n.kde.org/,
-   GNU Gettext — http://www.gnu.org/software/gettext/.

Jednym z narzędzi najczęściej używanych przez twórców wtyczek jest
Poedit. Jest proste, ma graficzny interfejs użytkownika obsługiwany
myszą, który pozwala programistom na tworzenie pliku POT na podstawie
wtyczki.

GlotPress to narzędzie bazujące na przeglądarce internetowej zbudowane
przez twórców platformy WordPress. Obietnicą składaną przez twórców
narzędzia jest możliwość pracy nad tłumaczeniem oprogramowania przez
pojedyncze osoby lub zespoły. Obecnie jest wykorzystywane do tłumaczenia
oprogramowania platformy WordPress
(http://translate.wordpress.org/projects).

W jaki sposób utworzyć plik POT?

Plik POT można utworzyć za pomocą narzędzia Poedit wymienionego na
wcześniejszej liście. Musisz podać jedynie kilka informacji, resztą
zajmie się już narzędzie Poedit.

1.  W menu głównym należy kliknąć Plik.

2.  Kolejny krok to kliknięcie opcji Nowy katalog z menu Plik. Na
    ekranie zostanie wyświetlone okno dialogowe z trzema kartami (zobacz
    rysunek 5.1).

    []

    Rysunek 5.1. Narzędzie Poedit w działaniu

3.  Na karcie Informacje o projekcie należy podać te informacje, które
    są istotne dla Twojej wtyczki. W rozwijanym menu Kodowanie powinna
    być wybrana opcja UTF-8.

4.  Na karcie Ścieżki trzeba zmienić wartość pola Ścieżka podstawowa na
    ../ oraz dodać dodatkową ścieżkę dostępu dla ., o ile pliki z
    tłumaczeniami są umieszczane w podkatalogu languages katalogu
    wtyczki. W przeciwnym razie należy pozostawić wartość domyślną.

5.  Na karcie Słowa kluczowe trzeba jako słowo kluczowe podać nazwy
    wszystkich funkcji, które zostały omówione w punkcie "Wyświetlanie i
    zwracanie ciągów tekstowych". Przykładowo nazwę funkcji esc_attr_e()
    należy podać jako esc_attr_e.

6.  Kliknięcie przycisku OK spowoduje zapis ustawień pliku POT.

7.  Plik trzeba zapisać w podkatalogu languages pod nazwą
    nazwa-wtyczki.pot. Przykładowo dla wtyczki BOJ Alert Box to będzie
    boj-alert-box.pot.

Po zakończeniu procesu narzędzie Poedit synchronizuje plik POT z
wtyczką. Na tym kończy się proces przygotowania wtyczki do
przetłumaczenia.

Gdzie przechowywać pliki tłumaczeń?

Wiele wtyczek umieszcza pliki tłumaczeń w katalogu głównym wtyczki.
Wprawdzie po zastosowaniu takiej metody tłumaczenie będzie
funkcjonowało, ale wprowadza ona bałagan i jej stosowanie jest
niezalecane. W przypadku posiadania wtyczki wykorzystującej wiele innych
plików podążanie tą drogą bardzo szybko okaże się zgubne dla twórcy.

W celu zachowania przejrzystego, doskonale zorganizowanego systemu
najlepszym rozwiązaniem jest utworzenie w katalogu wtyczki podkatalogu o
nazwie languages. Po wydaniu wtyczki domyślne pliki tłumaczeń można
przechowywać w wymienionym podkatalogu. Kiedy tłumacze przekażą
przetłumaczone pliki wtyczki, wystarczy je po prostu przekopiować do
podkatalogu languages. Trzeba się upewnić o kopiowaniu zarówno pliku PO
(od tłumacza), jak i MO (dla platformy WordPress) dla każdego
tłumaczenia.

Podsumowanie

Najważniejszą lekcją, którą powinieneś wynieść z tego rozdziału, jest
fakt, że platforma WordPress jest używana na całym świecie. Aby zbudować
dobrą wtyczkę, warto ją przygotować do przetłumaczenia. Dzięki temu
Twoja wtyczka może być oceniona nieco lepiej niż tysiące innych wtyczek
nieprzygotowanych do internacjonalizacji. Po rozpoczęciu stosowania w
praktyce narzędzi omówionych w rozdziale przekonasz się, jak łatwo można
zwiększyć możliwości wtyczki i wykreować wokół swojej pracy pewną
społeczność.

Rozdział 6 Bezpieczeństwo wtyczki

W tym rozdziale:

-   Zrozumienie kwestii bezpieczeństwa
-   Sposoby odkrywania słabych punktów w kodzie
-   Uniemożliwienie przeprowadzania złośliwych ataków, takich jak XSS i
    CSRF
-   Sprawdzanie uprawnień użytkownika
-   Weryfikacja i oczyszczanie danych
-   Tworzenie solidnych i bezpiecznych zapytań SQL
-   Pamiętanie o dobrych praktykach

W języku komputerowym pojęcie "bezpieczeństwo" bardzo często odnosi się
do groźnie brzmiących nazw, takich jak Cross Site Scripting (XSS), Cross
Site Request Forgery (CSRF), SQL Injection, nadużycie uprawnień, luki w
zabezpieczeniach i dziury.

Czy już jesteś przerażony?

Powinieneś być przerażony, ponieważ te wyrażenia to nazwy prawdziwych
zagrożeń, które — jak się wkrótce przekonasz — mogą bardzo łatwo powstać
w przypadku kiepsko utworzonego kodu. Na szczęście, po lekturze tego
rozdziału powinieneś się uspokoić. Platforma WordPress została
wyposażona w narzędzia niezbędne do zabezpieczenia tworzonego kodu.

Zabezpieczenie wtyczki

Kiepsko utworzony kod może być wykorzystany do złamania zabezpieczeń
serwera lub nieuprawnionego pobrania poufnych danych Twoich
użytkowników. To najgorsza z możliwych sytuacji.

Musisz chronić swój kod i umożliwić internetowym piratom przeglądanie
Twoich plików i katalogów. Kiepsko utworzony kod nie przeprowadza
sprawdzenia danych wprowadzanych przez użytkownika w celu wychwycenia
niebezpiecznych. Jak się przekonasz podczas lektury rozdziału,
niepoprawnie przygotowany kod formularza może np. obciąć dane wejściowe
użytkownika, a tym samym przetworzyć tylko ich część.

Czym jest zapewnienie bezpieczeństwa wtyczce?

Zapewnienie bezpieczeństwa wtyczce polega na usunięciu wszelkich luk w
zabezpieczeniach i zapewnieniu spójności danych oraz ich niezawodności.
Oznacza to zarówno uniemożliwienie przeprowadzenia złośliwych ataków,
jak i zagwarantowanie, że poprawne użycie wtyczki nie doprowadzi do jej
nieoczekiwanego zachowania.

Czym nie jest zapewnienie bezpieczeństwa wtyczce?

Na platformie WordPress zabezpieczenie wtyczki nie jest trudnym,
nieporęcznym bądź długotrwałym zadaniem: platforma oferuje wiele funkcji
przeznaczonych do rozwiązywania potencjalnych problemów.

Uprawnienia użytkownika

Prawdopodobnie już zauważyłeś, że podczas próby uzyskania dostępu do
strony administracyjnej platformy WordPress, jeśli nie jesteś zalogowany
jako użytkownik z uprawnieniami administratora, otrzymasz komunikat
błędu informujący o posiadaniu niewystarczających uprawnień (zobacz
rysunek 6.1).

[]

Rysunek 6.1. Komunikat błędu WordPress informujący o niewystarczających
uprawnieniach

W ten sposób jest zagwarantowane, że określone zadania (takie jak
zarządzanie wtyczkami bądź zmiana opcji dotyczących witryny) są
zarezerwowane tylko dla pewnej grupy osób z odpowiednimi uprawnieniami.
Innymi słowy, aby uniemożliwić ataki związane z nadużyciem uprawnień,
platforma WordPress intensywnie korzysta z funkcji o nazwie
current_user_can(). Funkcję tę możesz i powinieneś stosować w tworzonych
wtyczkach.

W jaki sposób używać funkcji current_user_can()?

Stosowanie funkcji current_user_can() jest bardzo proste: przed
przeprowadzeniem ważnej operacji sprawdzasz, czy użytkownik ma
odpowiednie uprawnienia lub przyznano mu uprawnioną rolę. W przeciwnym
razie operacja nie będzie wykonana, a użytkownik otrzyma odpowiedni
komunikat. Oto przykład:

    <?php
    // Uprawnienia:
    if ( !current_user_can('install_plugins') )
        wp_die( 'Niewystarczające uprawnienia' );
    // Rola:
    if( !current_user_can('editor') )
        wp_die( 'Nie możesz zmienić tych ustawień' );
    ?> 

Istnieje możliwość wykorzystywania ról domyślnych bądź utworzenia
własnych. To zagadnienie zostanie omówione w rozdziale 8., który jest
poświęcony tematowi zarządzania użytkownikami.

Nie sprawdzaj zbyt wcześnie

Działanie funkcji current_user_can() zależy od get_currentuserinfo(),
która jest funkcją zastępowalną. Funkcje zastępowalne mogą być
zastąpione wtyczkami: znajdują się w pliku wp-includes/
pluggable.php, który jest wczytywany po aktywacji wtyczek.

Z tego powodu uprawnień użytkownika nie można sprawdzić podczas
wczytywania wtyczki i trzeba z tym poczekać aż do pełnego uruchomienia
platformy WordPress (np. sprawdzenie przeprowadzić po akcji init).

Przykładowo weźmy pod uwagę wtyczkę wyświetlającą informacje procesu
usuwania błędów po dodaniu wyrażenia ?debug=1 do dowolnego adresu URL
bloga, ale tylko wtedy, gdy użytkownik jest administratorem.

Przedstawiona poniżej funkcja wyświetlająca informacje procesu usuwania
błędów dostarczy informacje dotyczące wszystkich zapytań SQL wykonanych
przez WordPress, o ile stała SAVEQUERIES ma ustawioną wartość true:

    <?php
    // Wyświetlenie informacji procesu usuwania błędów.
    function boj_debug_output() {
        global $wpdb;
        echo "<pre>";
        print_r($wpdb->queries);
        echo "</pre>";
    }
    ?> 

Powstaje pytanie o sposób powiązania powyższej funkcji z parametrem
debug=1.

Poniżej przedstawiono najgorsze rozwiązanie tego problemu:

    <?php
    if( isset( $_GET['debug'] ) )
        boj_debug_output();
    ?> 

To jest zła praktyka, ponieważ informacje procesu usuwania błędów mogą
zawierać poufne dane, takie jak fizyczne ścieżki dostępu bądź nazwy
tabel. W wyniku użycia powyższego polecenia warunkowego każdy będzie
mógł uzyskać dostęp do tych danych po dołączeniu wyrażenia ?debug=1 do
dowolnego adresu URL witryny.

Ponieważ informacje procesu usuwania błędów mają być dostępne tylko dla
administratora, trzeba zastosować nieco bardziej złożone polecenie
warunkowe:

    <?php
    if( isset( $_GET['debug'] )  &&  current_user_can( 'manage_options' ) )
        boj_debug_output();
    ?> 

Jednak powyższe polecenie nie działa. Jak zapewne pamiętasz, gdy wtyczka
jest wczytywana, a serwer przetwarza i kompiluje jej kod, funkcje
zastępowalne nie znajdują się jeszcze w pamięci. Rozwiązaniem jest
podpięcie operacji sprawdzenia do zaczepu akcji wywoływanego po pełnym
uruchomieniu platformy.

Poniżej przedstawiono pełny kod wtyczki:

    <?php
    /*
    Plugin Name: Prosty przykład procesu usuwania błędów
    Plugin URI: http://przyklad.pl/
    Description: Dołączenie wyrażenia ?debug=1 powoduje wyświetlenie informacji procesu usuwania błędów, o ile użytkownik jest administratorem.
    Author: WROX
    Author URI: http://wrox.com
    */
    add_action( 'init', 'boj_debug_check' );
    function boj_debug_check() {
        if( isset( $_GET['debug'] )  &&  current_user_can( 'manage_options' ) ) {
            if( !defined( 'SAVEQUERIES' ) )
                define( 'SAVEQUERIES', true );
            add_action( 'wp_footer', 'boj_debug_output' );
        }
    }
    // Wyświetlenie informacji procesu usuwania błędów.
    function boj_debug_output() {
        global $wpdb;
        echo "<pre>";
        print_r($wpdb->queries);
        echo "</pre>";
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin-simple-debug.php.

------------------------------------------------------------------------

------------------------------------------------------------------------

Uwaga

W tworzonych wtyczkach zawsze należy podpinać wywołania funkcji do
odpowiednich zaczepów akcji, takich jak init lub plugins_loaded. W ten
sposób można zagwarantować, że wszystkie funkcje platformy WordPress
zostały zadeklarowane, a funkcja wtyczki nie będzie wywołana zbyt
wcześnie.

------------------------------------------------------------------------

Unikalne identyfikatory

W poprzednim podrozdziale dotyczącym uprawnień użytkownika dowiedziałeś
się, w jaki sposób sprawdzić, czy użytkownik ma odpowiednie uprawnienia
potrzebne do wykonania danej operacji. W ten sposób blog jest chroniony
przed użytkownikami nieposiadającymi odpowiednich uprawnień. Jednak blog
trzeba chronić także przed... samymi użytkownikami.

Uprawnienia kontra zamiary

Kiedy jesteś zalogowany do danej instalacji platformy WordPress, możesz
klikać różne odnośniki powodujące wykonanie określonych operacji, takich
jak usunięcie wpisu, uaktualnienie ustawień wtyczki bądź utworzenie
kategorii. Przed wykonaniem tego typu operacji należy za pomocą funkcji
current_user_can() sprawdzić, czy użytkownik faktycznie jest zalogowany
i ma wystarczające uprawnienia. W ten sposób następuje potwierdzenie
uprawnień.

Teraz wyobraź sobie człowieka preparującego odnośnik powodujący
usunięcie wpisu na Twoim blogu. Oczywiście, wspomniany człowiek nie może
sam użyć tego typu odnośnika, ponieważ nie posiada konta administratora
w Twoim blogu, a tym samym odpowiednich uprawnień. Co jednak się stanie,
jeśli podstępnie przekona Cię do kliknięcia tego odnośnika? Ponieważ
jesteś zalogowany, operacja zostanie wykonana, a tym samym wpis bloga
będzie usunięty. Tak więc masz uprawnienia, ale nie miałeś zamiaru
usunięcia wpisu bloga. Natomiast złośliwy osobnik po prostu
przeprowadził atak typu CSRF (ang. Cross Site Request Forgery).

------------------------------------------------------------------------

Uwaga

Podstępne przekonanie użytkownika do kliknięcia odnośnika na jego
własnej witrynie nie jest trudne. Przykładowo odnośnik można ukryć,
korzystając z usługi skracania adresów URL, takich jak bit.ly, a
następnie za pomocą komunikatora przekazać odnośnik wraz z zachęcającym
komunikatem typu "zobacz, jakie zabawne zdjęcie". W erze Twittera i
Facebooka ataki CSRF przeżywają prawdziwy rozkwit.

------------------------------------------------------------------------

Oczywiście, platforma WordPress oferuje wbudowane rozwiązanie chroniące
przed tego typu atakami.

Czym jest unikalny identyfikator?

W języku komputerowym słowo nonce to skrót od number used once, czyli
liczba użyta jednokrotnie. Na platformie WordPress to krótki i losowo
wygenerowany ciąg tekstowy, taki jak hasło, który spełnia wymienione
poniżej założenia:

-   jeden użytkownik WordPress;
-   jedna operacja (usunięcie, uaktualnienie, zapisanie itd.);
-   jeden obiekt (wpis bloga, odnośnik, ustawienie wtyczki itd.);
-   jeden przedział czasu, 24 godziny.

Przykładowo odnośnik powodujący usunięcie wpisu bloga o numerze 43
mógłby mieć postać
http://przyklad.pl/wp-admin/​post.php?post=43&action​=trash&_wpnonce=83a08fcbc2.
Zastosowany w nim unikalny identyfikator 83a08fcbc2 jest ważny przez
jedynie 24 godziny i tylko do usunięcia wpisu bloga o numerze 43. Po
kliknięciu odnośnika, ale jeszcze przed faktycznym usunięciem wpisu
bloga, platforma WordPress upewni się, że identyfikator spełnia
wymienione powyżej kryteria.

Co ważniejsze, identyfikator nie może być odgadnięty przez złośliwego
użytkownika, a odnośnik bez prawidłowego identyfikatora prowadzi donikąd
(zobacz rysunek 6.2). Na rysunku pokazano komunikat wyświetlany podczas
próby aktywacji wtyczki bez podania prawidłowej wartości unikalnego
identyfikatora.

Jak tworzyć i weryfikować unikalne identyfikatory?

Platforma WordPress używa dwóch różnych funkcji do tworzenia unikalnych
identyfikatorów w formularzach: jako ukryte pola formularza lub w
adresach URL jako parametr GET.

W celu oswojenia się z unikalnymi identyfikatorami można utworzyć
użyteczną wtyczkę usprawniającą zarządzanie tagami na platformie
WordPress. Wtyczka określi tagi wpisów bloga, które nie zostały użyte w
żadnym wpisie, a następnie pozwoli na zmianę ich nazw bądź usunięcie.
Wtyczka będzie nosiła nazwę Nieużywane tagi i używała prefiksu
boj_utags.

[]

Rysunek 6.2. Bez podania poprawnej wartości unikalnego identyfikatora
nie można przeprowadzić żądanej operacji

Utworzenie unikalnego identyfikatora dla adresu URL

W celu dodania unikalnego identyfikatora do adresu URL, jak pokazano we
wcześniejszym przykładzie dotyczącym usunięcia wpisu bloga, należy użyć
funkcji wp_nonce_url() w następujący sposób:

    <?php
    $url = wp_nonce_url( $url, $action );
    ?> 

Pierwszy parametr, czyli $url, to ciąg tekstowy adresu URL, do którego
ma zostać dodany unikalny identyfikator w ciągu tekstowym zapytania.
Odnośniki we wtyczce Nieużywane tagi przeznaczone do usuwania tagu będą
miały postać
http://przyklad.pl/wp-admin/​edit.php?page=boj_utags&boj_​action=delete&id=6.
W wymienionym adresie URL należy zwrócić uwagę na parametr boj_action
oraz identyfikator tagu.

Drugi parametr — $action — to ciąg tekstowy, za pomocą którego unikalny
identyfikator zostaje przeznaczony dla jedynej operacji i jednego
obiektu. Odnośnik chroniony za pomocą unikalnego identyfikatora jest
powiązany z operacją delete, a identyfikator tagu wynosi 6, więc
parametr $action może mieć postać boj_utags-delete_tag6.

------------------------------------------------------------------------

Uwaga

Unikalnym identyfikatorem może być dowolny ciąg tekstowy. W celu
zagwarantowania jego unikalności dla wtyczki i użycia tylko z
pojedynczym działaniem i obiektem (nie licząc aktualnego użytkownika i
przedziału czasu 24 godzin) dobrym rozwiązaniem jest stosowanie modelu
wtyczka-akcja_obiekt.

------------------------------------------------------------------------

Jeśli zatem we wtyczce mamy identyfikator tagu $id, kod powodujący
wygenerowanie chronionego unikalnym identyfikatorem adresu URL
powodującego usunięcie tagu będzie miał następującą postać:

    <?php
    $delete_url = add_query_arg( array('boj_action'=> 'delete','id'=> $id) );
    $nonced_url = wp_nonce_url( $delete_url, 'boj_utags-delete_tag'.$id );
    ?> 
    <a href="<?php echo $nonced_url; ?>">usuń</a> ten tag 

Do utworzenia odnośnika usuwającego tag wykorzystano użyteczną funkcję
add_query_arg(), która do bieżącego adresu URL dodaje parametry
zapytania zdefiniowane w jej tablicy parametrów. Innymi słowy, dodawany
jest ciąg tekstowy ?boj_action=delete&id=6 lub &boj_action=delete&id=6,
jeżeli bieżący adres URL ma już ciąg tekstowy zapytania.

Utworzenie unikalnego identyfikatora dla formularza

Za pomocą funkcji wp_nonce_field() unikalne identyfikatory mogą chronić
także formularze. Funkcja pobiera parametr w postaci pojedynczego ciągu
tekstowego dołączonego do wtyczka-akcja_obiekt.

Gdy mamy wartości $name i $id tagu wpisu bloga, poprawny formularz
pozwalający na zmianę nazwy tagu będzie miał postać:

    <form action="" method="post"> 
        <?php wp_nonce_field( 'boj_utags-rename_tag'.$id ); ?> 
        <input type="hidden" name="boj_action" value="rename" /> 
        <input type="hidden" name="id" value=" <?php echo $id; ?> " /> 
        <input type="text" name="name" value=" <?php echo esc_attr($name); ?> " /> 
        <input type="submit" value="Zmień nazwę" /> 
    </form> 

Warto w tym miejscu zwrócić uwagę na użycie nowej funkcji o nazwie
esc_attr(). Gwarantuje ona, że formularz zostanie wyświetlony
prawidłowo, nawet jeśli wartość $name zawiera apostrofy. Weryfikacja
danych jest tematem kolejnego podpunktu.

Weryfikacja unikalnego identyfikatora

Dodanie unikalnego identyfikatora do adresu URL lub formularza to
dopiero połowa zadania. Pozostało jeszcze przygotowanie funkcji
wykonującej określone operacje, ale dopiero po potwierdzeniu poprawności
unikalnego identyfikatora i jego powiązaniu z operacją.

Używana do tego celu funkcja nosi nazwę check_admin_referer().
Wymieniona funkcja powoduje uwierzytelnienie unikalnego identyfikatora.
Jeżeli jest prawidłowy, nie podejmuje żadnych działań, natomiast w
przeciwnym razie wyświetla pokazany na rysunku 6.2 komunikat błędu.
Funkcja ta musi być wywołana przed wyświetleniem na ekranie
jakichkolwiek danych wyjściowych.

W tworzonej tutaj wtyczce parametry, takie jak operacja i identyfikator
tagu, są przekazywane przez metody GET (ciąg zapytania adresu URL) lub
POST (wysłany formularz). Zamiast sprawdzania obu tablic $_GET i $_POST
wystarczy sprawdzić tablicę $_REQUEST i pobrać z niej wartości
parametrów.

Pełny fragment kodu odpowiedzialny za sprawdzenie unikalnego
identyfikatora tagu wpisu bloga, a następnie umożliwienie zmiany jego
nazwy lub usunięcia przedstawia się następująco:

    <?php
    if( !current_user_can( 'manage_options' ) )
        wp_die( 'Niewystarczające uprawnienia!' );
    $id     = $_REQUEST['id'];
    $action = $_REQUEST['boj_action'];
    check_admin_referer( 'boj_utags-'.$action.'_tag'.$id );
    switch( $action ) {
        case 'rename':
            $newtag = array( 'name' => $_POST['name'], 'slug' => $_POST['name'] );
            wp_update_term( $id, 'post_tag', $newtag );
            break;
        case 'delete':
            wp_delete_term( $id, 'post_tag' );
            break;
    }
    ?> 

Warto zwrócić uwagę na sprawdzenie w pierwszej kolejności uprawnień
użytkownika. Za pomocą unikalnego identyfikatora można weryfikować
intencje, jednak nadal trzeba sprawdzić uprawnienia użytkownika do
wykonania danej operacji.

Przygotowanie całości: pełny kod wtyczki Nieużywane tagi

Aby wtyczka była w pełni funkcjonalna, wymaga użycia poprawnego nagłówka
wtyczki, pełnej strony administracyjnej wraz z nowym wpisem w menu oraz
— oczywiście — funkcji wyświetlającej nieużywane tagi.

    <?php
    /* 
    Plugin Name: Nieużywane tagi
    Plugin URI: http://przykład.pl/
    Description: Wyszukuje nieużywane tagi i pozwala na ich usunięcie bądź zmianę nazwy.
    Author: WROX
    Author URI: http://wrox.com
    */
    // Dodanie w menu Post elementu pozwalającego na przejście do strony opcji.
    add_action('admin_menu', 'boj_utags_add_page');
    function boj_utags_add_page() {
        add_posts_page( 'Nieużywane tagi', 'Nieużywane tagi', 'manage_options',
            'boj_utags', 'boj_utags_option_page' );
    }
    // Przechwycenie każdego parametru boj_action w ciągu tekstowym zapytania.
    add_action( 'admin_init', 'boj_utags_do_action' );
    // Przejście do żądanego parametru boj_action, o ile jest taka możliwość.
    function boj_utags_do_action() {
        if( !isset( $_REQUEST['boj_action'] ) )
            return;
        if( !current_user_can( 'manage_options' ) )
            wp_die( 'Niewystarczające uprawnienia!' );
        $id     = $_REQUEST['id'];
        $action = $_REQUEST['boj_action'];
        if( $action == 'done' ) {
            add_action( 'admin_notices', 'boj_utags_message' );
            return;
        }
        check_admin_referer( 'boj_utags-'.$action.'_tag'.$id );
        switch( $action ) {
            case 'rename':
                $newtag = array( 'name' => $_POST['name'], 'slug' => $_POST['name'] );
                wp_update_term( $id, 'post_tag', $newtag );
                break;
            case 'delete':
                wp_delete_term( $id, 'post_tag' );
                break;
        }
        wp_redirect( add_query_arg( array( 'boj_action' => 'done' ) ) );
    }
    // Komunikat dla administratora.
    function boj_utags_message() {
        echo "<div class='updated'><p>Operacja została wykonana</p></div>";
    }
    // Wyświetlenie strony zarządzania tagami.
    function boj_utags_option_page() {
        ?>
        <div class="wrap">
            <?php screen_icon(); ?>
            <h2>Nieużywane tagi</h2>
            <?php
            if( $tags = boj_utags_find_orphans() ):
            echo '<p>W tej chwili masz '.count( $tags ). ' nieużywanych tagów:</p>';
            echo '<ol>';
            
            foreach( $tags as $tag ) {
                $id   = $tag->term_id;
                $name = esc_attr( $tag->name );
                $delete_url= add_query_arg( array('boj_action'=>'delete','id'=>$id) );
                $nonced_url= wp_nonce_url( $delete_url, 'boj_utags-delete_tag'.$id );
                ?>
                <li>
                <form action="" method="post">
                <?php wp_nonce_field( 'boj_utags-rename_tag'.$id ); ?>
                <input type="hidden" name="boj_action" value="rename" />
                <input type="hidden" name="id" value="<?php echo $id; ?>" />
                <input type="text" name="name" value="<?php echo $name; ?>" />
                <input type="submit" value="Zmień nazwę" /> lub
                <a href="<?php echo $nonced_url; ?>">usuń</a> ten tag
                </form>
                </li>
            <?php }
            else: ?>
            <p>Nie znaleziono nieużywanych tagów.</p>
            <?php endif; ?>
            </ol>
        </div>
        <?php
    }
    // Wyszukanie nieużywanych tagów i ich zwrot w tablicy.
    function boj_utags_find_orphans() {
        global $wpdb;
        $sql = "SELECT terms.term_id, terms.name FROM {$wpdb->terms} terms
                INNER JOIN {$wpdb->term_taxonomy} taxo
                ON terms.term_id=taxo.term_id
                WHERE taxo.taxonomy = 'post_tag'
                AND taxo.count=0";
        return $wpdb->get_results( $sql );
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin-unused-tags.php.

------------------------------------------------------------------------

Po utworzeniu bądź pobraniu gotowej wtyczki, aktywacji, a następnie
uruchomieniu uzyskasz dostęp do nowej strony w menu Wpisy (zobacz
rysunek 6.3).

[]

Rysunek 6.3. Działająca wtyczka Nieużywane tagi

W przedstawionym powyżej kodzie wtyczki można zauważyć, że zastosowano
kilka dodatkowych dobrych praktyk. Oto one.

1.  Funkcja boj_utags_do_action() odpowiedzialna za sprawdzenie
    istnienia parametru boj_action w ciągu tekstowym zapytania bądź
    danych POST została zarejestrowana dla zaczepu akcji admin_init. W
    ten sposób wtyczka będzie działała jedynie wtedy, gdy użytkownik
    jest administratorem. Podczas wyświetlania części publicznej (czyli
    samego bloga) żadne zdarzenie nie jest wywoływane. W przypadku
    takiej prostej wtyczki zysk będzie niewielki, ale przy bardziej
    skomplikowanych wtyczkach ta technika może przyśpieszyć wczytywanie.
2.  Kiedy tag zostanie usunięty lub będzie miał zmienioną nazwę, wtyczka
    spowoduje przekierowanie użytkownika na bieżącą stronę, do adresu
    URL której zostanie dodany ciąg tekstowy boj_action=done. W ten
    sposób unika się niechcianego powtórzenia operacji, jeśli użytkownik
    przypadkowo naciśnie przycisk odświeżenia strony i ponownie wyśle
    dane do serwera. Funkcja zostaje zarezerwowana dla zaczepu
    admin_notices i powoduje po prostu wyświetlenie komunikatu.

Unikalne identyfikatory w skryptach Ajax

Skrypty Ajax (specjalny typ skryptów JavaScript) pozwalają na
uaktualnienie fragmentów okna przeglądarki internetowej bez konieczności
odświeżania całej strony. Skrypty Ajax mogą składać się z formularzy lub
odnośników i jako takie również powinny być chronione za pomocą
unikalnych identyfikatorów.

Temat dodawania do tych skryptów unikalnych identyfikatorów został
omówiony w rozdziale 12., który jest w całości poświęcony technologiom
JavaScript i Ajax.

Weryfikacja i oczyszczenie danych

Jak mogłeś przeczytać na początku tego rozdziału, złota reguła
filtrowania mówi, że wszystkie dane należy uznawać za niepoprawne aż do
chwili, gdy będzie można udowodnić ich poprawność. Innymi słowy, pod tym
względem warto być bardziej podejrzliwym, a nawet trochę paranoikiem.

Z lektury tego podrozdziału dowiesz się, dlaczego filtrowanie danych
jest tak ważne, jak weryfikować różne typy danych w procesach wtyczek
platformy WordPress (zwykłe ciągi tekstowe, adresy e-mail, liczby
całkowite itd.) oraz które wbudowane funkcje WordPress mogą Ci w tym
pomóc.

Potrzeba weryfikacji i oczyszczania danych

Warto przeanalizować kilka wierszy prostego i niewinnie wyglądającego
kodu HTML i PHP:

    <?php $name = $_POST['fullname']; ?> 
    <form action="" method="POST" > 
        Imię i nazwisko:
    <input type="text" name="fullname" value=" <?php echo $name; ?> " /> 
    <input type="submit" value="Zapisz" /> 
    </form> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku bad_form.php.

------------------------------------------------------------------------

Ten minimalny formularz ma tylko jedno pole, w którym będzie umieszczana
poprzednio wprowadzona wartość. Później ten formularz będziemy określać
mianem nieprawidłowego formularza.

Przykładowo po podaniu w polu wartości Jan Kowalski i naciśnięciu
przycisku Zapisz wszystko wydaje się być w porządku (zobacz rysunek
6.4).

[]

Rysunek 6.4. Nieprawidłowy formularz wyświetlony w przeglądarce
internetowej

Powstaje więc pytanie, co jest nieprawidłowego w tym prostym formularzu?

Potencjalny problem wiąże się z tym, że dane wejściowe nie są
sprawdzane, a dane wyjściowe nie są oczyszczone. Innymi słowy, warto
rozważyć taką sytuację:

-   skrypt nie sprawdza, czy wprowadzony ciąg tekstowy wygląda jak imię
    i nazwisko;
-   skrypt nie upewnia się, że wprowadzony ciąg tekstowy może być
    wyświetlony bez uszkodzenia formularza.

Aby zilustrować brak bezpieczeństwa w przedstawionym formularzu, w jego
polu należy wprowadzić następujące wartości (zobacz rysunek 6.5):

1.  Niezłośliwe dane wejściowe: Jan "Zabawny Facet" Kowalski.
2.  Złośliwe dane wejściowe:
    Jan" />Hasło:<input name="password" value="123456".
3.  Złośliwe dane wejściowe: Jan" /><script>alert('XSS');</script>.

Co się stało?

W pierwszym przypadku podano w formularzu poprawne, niezłośliwe dane.
Wprawdzie dane są poprawne, ale z powodu braku ich weryfikacji i
oczyszczenia danych wyjściowych zostają one

[]

Rysunek 6.5. Wynik wprowadzenia w polu formularz różnych wartości

obcięte ze względu na użycie znaków cudzysłowu. Prawidłowym sposobem
wygenerowania formularza w tym przypadku będzie konwersja wymienionych
znaków cudzysłowu na odpowiadające im encje HTML.

W drugim przypadku użytkownik przeszedł na ciemną stronę i bez wątpienia
próbował wykorzystać lukę w formularzu. Także i tutaj znak cudzysłowu
spowodował obcięcie wprowadzonych danych i wygenerowanie w danych
wyjściowych kolejnego pola formularza. Nie tylko dane wyjściowe nie
zostały oczyszczone (konieczna jest zamiana znaków cudzysłowu na
odpowiadające im encje HTML), ale również dane wejściowe wydają się
wątpliwe, np. imię i nazwisko użytkownika. Powinny być najpierw
zweryfikowane, np. poprzez usunięcie znaków innych niż alfanumeryczne
oraz wszelkich znaczników HTML.

Trzeci przypadek jest podobny. Zamiast wprowadzić odpowiednie dane
wejściowe, użytkownik wstawił kod JavaScript, który np. mógłby
przechwycić wartość cookie sesji z witryny i przekazać ją na inną
witrynę.

Trzeci przypadek to przykład ataku typu XSS (ang. Cross Site Scripting)
wykorzystującego lukę w zabezpieczeniach aplikacji sieciowych, która
pozwala atakującemu na wstawienie do strony wyświetlanej przez innych
użytkowników skryptu działającego po stronie klienta. Przy użyciu ataku
typu XSS atakujący może zyskać uprawnienia do strony z poufną treścią,
plików cookies sesji, a także przechowywanych przez przeglądarkę
internetową wielu innych informacji o zachowaniu użytkownika.

Omówione sytuacje pokazują, że brak weryfikacji danych w najlepszym
razie oznacza ich uszkodzenie, natomiast w najgorszym wykorzystanie luk
w zabezpieczeniach Twojej aplikacji sieciowej.

------------------------------------------------------------------------

Uwaga

Dane wyjściowe również powinny być sprawdzone przed ich umieszczeniem na
ekranie przeglądarki internetowej użytkownika. Dane wejściowe trzeba
zweryfikować (upewnić się, że są prawidłowe) lub oczyścić (zagwarantować
ich prawidłowość).

------------------------------------------------------------------------

Dobra praktyka: identyfikacja potencjalnie niebezpiecznych danych

Przyjmijmy założenie, że tworzysz wtyczkę wraz z interfejsem, w którym
użytkownik ma podać wiek oraz wybrać jeden kolor z dostępnych, czyli
czerwony, zielony lub niebieski.

Warto przeanalizować poniższy fragment kodu:

    <?php
    $clean = array();
    // Wiek: tylko dodatnia liczba całkowita.
    $clean['age'] = absint( $_POST['age'] );
    // Kolor: tylko czerwony, zielony lub niebieski.
    switch( $_POST['color'] ) {
        case 'red':
        case 'green':
        case 'blue':
            $clean['color'] = $_POST['color'];
            break;
    }
    ?> 

Warto zwrócić uwagę na weryfikację powyższego fragmentu kodu poprzez
użycie tablicy o nazwie $clean. To dobra praktyka, która pomaga
programistom w identyfikacji danych potencjalnie niebezpiecznych, a
także możliwych do uznania za bezpieczne. Ponieważ nie można do końca
przewidzieć zawartości przekazanej tablicy $_POST, nie należy jej
weryfikować. Zamiast tego trzeba po prostu pobrać z niej oczekiwane
wartości.

W powyższym fragmencie kodu zaprezentowano funkcję platformy WordPress,
która stanowi wygodne opakowanie dla funkcji intval() i abs() używanych
do zwracania dodatniej wartości całkowitej.

------------------------------------------------------------------------

Uwaga

Nigdy nie należy weryfikować danych i pozostawiać ich w tablicach
$_POST, $_GET lub $_REQUEST, ponieważ programiści zawsze powinni
zachowywać maksymalną ostrożność względem danych znajdujących się w
wymienionych tablicach superglobalnych.

------------------------------------------------------------------------

Inicjalizacja zmiennych, takich jak $clean, na początku przedstawionego
tutaj fragmentu kodu to kolejna dobra praktyka. Dzięki temu zyskujesz
pewność, że wynik procedury weryfikacyjnej będzie zawierał jedynie
oczekiwane wartości.

Używając funkcji PHP error_reporting() oraz ustawiając wartość true
stałej WordPress o nazwie WP_DEBUG, można pomóc w wymuszeniu
inicjalizacji zmiennych, ponieważ odniesienia do niezdefiniowanych
zmiennych spowodują wygenerowanie odpowiednich komunikatów na ekranie.
Więcej informacji na ten temat znajduje się w rozdziale 16.

Przedstawiony powyżej skrypt przeprowadzał weryfikację jedynie danych —
dane użytkownika będą zaakceptowane, jeśli są prawidłowe, i odrzucone w
pozostałych przypadkach. Jednak skrypt nie przeprowadzał ich
oczyszczenia — gdy przekazane będą niepoprawne dane (np. zamiast wieku
użytkownik wprowadzi ciąg tekstowy), wówczas tablica $clean po prostu je
zignoruje.

Można utworzyć podobny blok kodu, ale przeznaczony do oczyszczania
danych zamiast jedynie do ich prostej weryfikacji.

    <?php
    $clean = array();
    // Wiek: tylko dodatnia liczba całkowita.
    $clean['age'] = absint( $_POST['age'] );
    // Kolor: tylko czerwony, zielony lub niebieski. Domyślnie wybranym jest niebieski.
    switch( $_POST['color'] ) {
        case 'red':
        case 'green':
            $clean['color'] = $_POST['color'];
            break;
        case 'blue':
            default:
            $clean['color'] = 'blue';
            break;
    }
    ?> 

Teraz jeśli użytkownik poda nieprawidłowy wiek (np. abc) wynikiem będzie
0. W przypadku podania nieprawidłowego koloru (np. purpurowego)
zastosowany będzie kolor domyślny, czyli w omawianym przykładzie
niebieski.

Zastosowana tutaj metoda weryfikacji nosi nazwę białej listy —
akceptowane są dane pochodzące jedynie z ograniczonej listy znanych i
zaufanych wartości. Zupełnie przeciwna metoda weryfikacji, czyli
odrzucanie danych umieszczonych na ograniczonej liście niezaufanych
wartości, nosi nazwę metody czarnej listy, która sama w sobie rzadko
jest dobrym pomysłem. Nie zawsze istnieje możliwość zastosowania białej
listy, ale jeśli tylko można użyć tego rodzaju polityki, należy to
zrobić.

Weryfikacja czy oczyszczanie danych wejściowych?

Weryfikować czy oczyszczać dane wejściowe użytkownika? To jest decyzja
projektowa i zależy przede wszystkim od oczekiwanego rodzaju danych.
Wyobraź sobie formularz zawierający pole do podania liczby całkowitej
(np. wieku), adresu e-mail oraz dłuższego akapitu zwykłego tekstu bez
znaczników HTML (np. informacji o sobie).

Przed podjęciem decyzji, czy wystarczy jedynie weryfikować, czy trzeba
również oczyszczać dane, najpierw należy rozważyć potencjalne problemy
wynikające jedynie z weryfikacji danych i odrzucania niepoprawnych.

-   W polu wieku użytkownik będzie musiał ponownie podać wiek. To nie
    jest duży problem, a podanie danych zajmie chwilę.
-   W polu informacji o sobie cały tekst zostanie zignorowany, ponieważ
    użytkownik użył znacznika HTML. Konieczność ponownego napisania
    tekstu może być irytująca. W tym przypadku oczyszczenie danych
    wejściowych (usunięcie znaczników HTML) prawdopodobnie będzie miało
    znacznie większy sens.

Drugim czynnikiem, który trzeba wziąć pod uwagę, jest możliwość
interpretacji i odgadnięcia, jaką wartość powinny mieć oczyszczone dane.

-   Jeżeli w polu wieku użytkownik podał ABC, co to może oznaczać? W tym
    przypadku nie można zastosować oczyszczania, ponieważ na podstawie
    tych danych nie ma możliwości odgadnięcia poprawnej informacji o
    wieku użytkownika. Jedyną opcją jest więc weryfikacja danych i
    odrzucenie nieprawidłowych.
-   Z drugiej strony, jeżeli w informacjach o sobie użytkownik użył
    niedozwolonych znaczników HTML, wówczas można je usunąć i przyjąć
    założenie, że tak oczyszczone dane są bliskie temu, co użytkownik
    chciał przekazać.

Trzeci czynnik odzwierciedla zachowanie, jakie będzie podjęte względem
danych wejściowych po ich oczyszczeniu, a tym samym po ewentualnej
modyfikacji.

-   Jeżeli dane wyglądają nieco dziwnie lub są niepoprawnie sformatowane
    na stronie profilu, to nie jest poważny problem (oczywiście, jeśli
    użytkownik będzie miał później możliwość ich edycji i poprawienia).
-   Jeżeli użytkownik wprowadzi niepoprawny adres e-mail, np.
    jan@poczta,przyklad.pl, wówczas wysłana wiadomość potwierdzenia na
    oczyszczony adres jan@pocztaprzyklad.pl nigdy nie dotrze do
    użytkownika. W takim przypadku lepszym rozwiązaniem jest weryfikacja
    jedynie pola adresu e-mail, a tym samym odrzucenie nieprawidłowych
    danych i poproszenie użytkownika o ich ponowne wprowadzenie.

Przykłady weryfikacji i oczyszczania danych

W tym punkcie dowiesz się, jak weryfikować i oczyszczać różnego rodzaju
dane, a także poznasz funkcje udostępniane do tego celu przez platformę
WordPress.

Liczby całkowite

W większości przypadków funkcje PHP, takie jak intval() i is_int(),
sprawdzają się doskonale:

    <?php
    $data = 43;
    // Weryfikacja liczby całkowitej.
    return( intval( $data ) == $data );
    // Oczyszczenie liczby całkowitej.
    return( intval( $data ) );
    ?> 

Tutaj wykorzystać można również funkcję WordPress o nazwie absint(),
która może także sprawdzić, czy liczba (np. wiek) jest dodatnia.

Potencjalny problem może dotyczyć obsługi ogromnych liczb. W systemach
32-bitowych zakres liczb całkowitych ze znakiem mieści się od –2 147 483
648 do 2 147 483 647. Tak więc w systemie 32-bitowym wywołanie funkcji
intval('1000000000000') zwróci wartość 2147483647. Z kolei w systemach
64-bitowych maksymalna wartość liczby całkowitej ze znakiem wynosi 9 223
372 036 854 775 807.

Kiedy trzeba obsłużyć ogromne liczby, najlepszym rozwiązaniem jest
uznanie danych za ciąg tekstowy, a nie liczbę, i upewnienie się, że ciąg
zawiera jedynie cyfry:

    <?php
    $num = '100000000000000000';
    // Weryfikacja ogromnych liczb całkowitych.
    return( ctype_digit( $num ) );
    ?> 

Warto pamiętać, że biblioteka ctype może być niedostępna w niektórych
serwerach. Przed użyciem powyższego kodu we wtyczce dla określonego
klienta należy sprawdzić, czy jego serwer obsługuje bibliotekę ctype.

Zwykłe ciągi tekstowe

Bardzo trzeba weryfikować ciągi tekstowe o dowolnej długości, takie jak
nazwa użytkownika bądź miejsce urodzenia. Ich weryfikację można
przeprowadzić za pomocą funkcji PHP z rodziny ctype_. Wartością zwrotną
tego typu funkcji jest true lub false.

Jeżeli oczekiwane jest otrzymanie jedynie liter, wówczas można użyć
wywołania:

    <?php
    // Weryfikacja ciągów tekstowych składających się tylko z liter.
    return( ctype_alpha( $num ) );
    ?> 

W przypadku oczekiwania alfanumerycznych ciągów tekstowych, np. nazwy
użytkownika, takiej jak "Bartek43", można użyć wywołania:

    <?php
    // Weryfikacja ciągów tekstowych składających się z liter i cyfr.
    return( ctype_alnum( $num ) );
    ?> 

------------------------------------------------------------------------

Uwaga

W PHP w wersji 5.2 i nowszej dostępne są funkcje filtrowania
przeznaczone do weryfikacji różnego rodzaju danych: liczb całkowitych,
wartości boolowskich, adresów e-mail, ciągów tekstowych itd. Więcej
informacji na temat tych funkcji można znaleźć na stronie
http://pl.php.net/filter. Jednak platforma WordPress nie korzysta z tych
funkcji, ponieważ prace nad nimi nadal trwają.

------------------------------------------------------------------------

Mieszane ciągi tekstowe

Ciągi tekstowe mogą zawierać także różne znaki specjalne, np. znaki
przestankowe. Platforma WordPress oferuje funkcję sanitize_text_field(),
która jest użyteczna podczas oczyszczania ogólnych ciągów tekstowych
będących danymi wejściowymi użytkownika. Funkcja usuwa nieprawidłowe
znaki UTF-8, konwertuje pojedyncze nawiasy ostre < na encje HTML oraz
usuwa wszystkie znaczniki HTML, znaki nowego wiersza i inne nadmiarowe
znaki odstępu.

    <?php
    var_dump( sanitize_text_field( "Jestem sympatyczny.\n Bardzo <em>sympatyczny</em>!  " ) );
    // Wynik:
    // string(24) "Jestem sympatyczny. Bardzo sympatyczny!"
    ?> 

Znacznie mniej destrukcyjnym rozwiązaniem jest usunięcie po prostu
jedynie znaczników HTML, ale pozostawienie innego formatowania, np.
znaków nowego wiersza. Platforma WordPress oferuje funkcję
wp_strip_all_tags(), ponieważ wbudowana funkcja PHP strip_tags() nie
działa prawidłowo podczas filtrowania skomplikowanych znaczników, takich
jak <script></script>, które można zobaczyć w przedstawionym poniżej
fragmencie kodu:

    <?php
    $test = '<a href="xx">witryna</a><b>pogrubienie<b><script>alert("nieudane")</script>';
    // Wynik działania wbudowanej funkcji PHP o nazwie strip_tags():
    var_dump( htmlentities( strip_tags( $test ) ) );
    // Wynik: string(41) "witryna pogrubienie alert("nieudane")"
    // Wynik działania funkcji WordPress o nazwie wp_strip_all_tags():
    var_dump( htmlentities( wp_strip_all_tags( $test ) ) );
    // Wynik: string(19) "witryna pogrubienie"
    ?> 

Wewnętrzne ciągi tekstowe identyfikatorów

Platforma WordPress zawiera funkcję o nazwie sanitize_key() przeznaczoną
do oczyszczania wewnętrznych identyfikatorów, takich jak nazwy opcji.
Akceptowane są małe litery, myślniki i znaki podkreślenia.

    <?php
    $data = 'option_43;';
    // Weryfikacja:
    return( preg_match('/^[a-z0-9-_]+$/', $data ) );
    // Oczyszczenie:
    return( sanitize_key( $data ) );
    ?> 

Polecenie weryfikacji pokazuje użycie narzędzia o potężnych
możliwościach — dopasowania wzorca za pomocą wyrażeń regularnych.
Ogólnie rzecz biorąc, wspomniany wiersz oznacza "zwróć wartość true,
jeżeli wartość zmiennej $data zostanie dopasowana do podanego wzorca".
Zastosowany w poleceniu wzorzec został pokazany na rysunku 6.6.

[]

Rysunek 6.6. Wzorzec wyrażeń regularnych użyty w poleceniu

Poniżej przedstawiono wyjaśnienie czterech części tego konkretnego
wyrażenia regularnego:

1.  Ograniczniki wzorca. To może być dowolny znak, choć najczęściej
    stosuje się ukośnik /.
2.  Kiedy znak ^ jest używany jako pierwszy po ograniczniku początkowym,
    wówczas oznacza początek ciągu tekstowego. Podobnie, gdy znak $
    zostanie użyty na końcu tuż przed ogranicznikiem zamykającym, wtedy
    oznacza koniec ciągu tekstowego.
3.  Znak + oznacza "jeden lub więcej znaków dopasowanych do
    przedstawionego wcześniej wzorca".
4.  Wreszcie mamy sam wzorzec umieszczony w nawiasach kwadratowych.
    Powoduje on dopasowanie dowolnej małej litery z zakresu od a do z,
    cyfry od 0 do 9 oraz znaków - i _.

W kolejnych przykładach będą stosowane znacznie bardziej skomplikowane
wyrażenia regularne.

Wzorce ciągu tekstowego

Od czasu do czasu występuje konieczność weryfikacji bądź oczyszczenia
ciągu tekstowego, który pasuje do predefiniowanego i znanego wzorca, np.
daty urodzenia, numeru karty kredytowej, kodu pocztowego lub numeru
telefonu.

Przykład 1.: numer telefonu

Twoim zadaniem może być utworzenie funkcji weryfikującej numery
telefonów zapisane w następującej postaci: 123-456-7890 (trzy cyfry,
myślnik, trzy cyfry, myślnik, cztery cyfry).

W świecie wyrażeń regularnych \d oznacza cyfrę (to krótszy odpowiednik
[0-9]). Jeżeli oczekiwane są dokładnie trzy cyfry, to takie wymaganie
można zapisać jako \d{3}.

Na podstawie powyższych informacji można już zdefiniować i przetestować
następującą funkcję:

    <?php
    // Weryfikacja numeru telefonu w postaci 123-456-7890.
    function boj_validate_phone( $num ) {
        return preg_match( '/^\d{3}-\d{3}-\d{4}$/', $num );
    }
    // Przetestowanie utworzonej funkcji:
    var_dump( boj_validate_phone( '132-456-7890' ) );
    // Dane wyjściowe: int(1)
    var_dump( boj_validate_phone( '555-8882' ) );
    // Dane wyjściowe: int(0)
    ?> 

Przykład 2.: numer seryjny produktu

Jakiego wzorca trzeba użyć, aby przeprowadzić weryfikację numeru
seryjnego produktu, np. zapisanego w postaci A145-B3D5-KK43?

    <?php
    // Weryfikacja numeru seryjnego produktu, np. zapisanego w postaci A145-B3D5-KK43
    function boj_validate_serial( $string ) {
        return preg_match( '/^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/', $string );
    }
    ?> 

Przykład 3.: daty

W 3. przykładzie utworzymy funkcję przeznaczoną do weryfikacji daty
zbliżającego się zdarzenia. To zadanie jest nieco trudniejsze: data musi
być dopasowana do wzorca mm/dd/rrrr, a ponadto musi być datą rzeczywistą
i wskazującą dzień w przyszłości. Oznacza to, że nie można zaakceptować
daty, np. takiej jak 30/30/2010.

Wzorzec użyty do dopasowania danych wejściowych będzie miał postać
\d{2}/\d{2}/\d{4}. Ponieważ data sama w sobie zawiera ukośniki, to
ogranicznikami w wyrażeniu regularnym musi być inny znak, np. !.
(Wprawdzie ukośniki w dacie można poprzedzić dodatkowymi ukośnikami, ale
ten sposób wzorzec staje się jeszcze mniej czytelny:
\d{2}\/\d{2}\/\d{4}).

W celu sprawdzenia, czy dana data istnieje, można użyć funkcji PHP o
nazwie strtotime(), która konwertuje datę w postaci ciągu tekstowego na
znacznik czasu UNIX. Jeśli podana data nie istnieje, funkcja zwraca
wartość -1.

Pełny kod funkcji weryfikacji daty jest przedstawiony poniżej:

    <?php
    // Weryfikacja przyszłej daty zapisanej w postaci mm/dd/rrrr.
    // Wartością zwrotną jest true lub komunikat błędu.
    function boj_validate_date( $date ) {
        // Pierwszy test: dopasowanie wzorca.
        if( !preg_match( '!\d{2}/\d{2}/\d{4}!', $date ) )
            return 'nieprawidłowy wzorzec';
        // Drugi test: czy data jest prawidłowa?
        $timestamp = strtotime( $date );
        if( !$timestamp )
            return 'data jest nieprawidłowa';
        // Trzeci test: czy data wskazuje dzień w przyszłości?
        if( $timestamp <= time() )
            return 'data wskazuje dzień z przeszłości';
        // Jak dotąd wszystko dobrze.
        return true;
    }
    // Sprawdzenie działania funkcji:
    var_dump( boj_validate_date( '12/12/99' ) );
    // string(22) "nieprawidłowy wzorzec"
    var_dump( boj_validate_date( '35/30/1980' ) );
    // string(24) "data jest nieprawidłowa"
    var_dump( boj_validate_date( '03/30/1980' ) );
    // string(36) "data wskazuje dzień z przeszłości"
    var_dump( boj_validate_date( '03/30/2020' ) );
    // bool(true)
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku validate_date.php.

------------------------------------------------------------------------

Ponieważ funkcja zwraca wartość true w przypadku sukcesu lub komunikat
błędu w pozostałych przypadkach, w celu weryfikacji daty trzeba
przeprowadzić ścisłe porównanie zweryfikowanej daty z wartością true za
pomocą potrójnego znaku równości:

    <?php
    $date = '30/30/3030';
    if( boj_validate_date( $date ) === true ) {
        // Data jest prawidłowa.
    } else {
        // Data jest nieprawidłowa.
    }
    ?> 

Wyrażenia regularne to narzędzie oferujące naprawdę potężne możliwości,
a zaprojektowane zostały w celu dopasowywania każdego strukturalnego
wzorca. Więcej informacji na ten temat można znaleźć na stronie
http://pl.php.net/pcre.

Ciąg tekstowy adresu e-mail

Adres e-mail to przykład wzorca ciągu tekstowego, który można łatwo
zweryfikować lub oczyścić na platformie WordPress za pomocą dostępnych
funkcji is_email() i sanitize_email():

    <?php
    $email = 'przyklad@przyklad.pl';
    // Weryfikacja:
    return( is_email( $email ) );
    // Oczyszczenie:
    return( sanitize_email( $email ) );
    ?> 

Wartością zwrotną funkcji is_email() jest false lub poprawny adres
e-mail. Warto przeanalizować poniższe przykłady:

    <?php
    var_dump( is_email( 'przyklad@przyklad' ) );
    // bool(false)
    var_dump( is_email( 'przyklad@przyklad.pl' ) );
    // string(20) "przyklad@przyklad.pl"
    ?> 

W celu użycia tej funkcji trzeba przeprowadzić ścisłe porównanie adresu
e-mail oraz danych wyjściowych funkcji is_email():

    <?php
    if( is_email( $email ) === email ) {
        // Adres e-mail wydaje się prawidłowy.
    } else {
        // Adres e-mail jest nieprawidłowy.
    }
    ?> 

Warto jednak pamiętać, że w środowiskach sieci lokalnych (LAN) i pewnych
sieciach firmowych poprawne oraz funkcjonujące adresy e-mail w postaci
admin@localhost lub webmaster@serwer będą uznane za nieprawidłowe. W
takim przypadku można po prostu sprawdzić istnienie znaku @ lub
przeprowadzić sprawdzenie względem pewnej określonej listy poprawnych
adresów e-mail.

Wartością zwrotną funkcji sanitize_email() jest pusty ciąg tekstowy lub
oczyszczony adres e-mail, w zależności od podanych danych wejściowych.
Warto rozważyć przedstawione poniżej przykłady:

    <?php
    var_dump( sanitize_email( 'ozh@ozh' ) );
    // string(0) ""
    var_dump( sanitize_email( 'ozh@ozh..org' ) );
    // string(0) ""
    var_dump( sanitize_email( '(ozh)@(ozh).org' ) );
    // string(11) "ozh@ozh.org"
    var_dump( sanitize_email( 'ozh@ozh.org' ) );
    // string(11) "ozh@ozh.org"
    ?> 

W każdym przypadku oczyszczone adresy e-mail trzeba porównać z
początkowymi danymi wejściowymi; w przypadku wystąpienia różnic należy
poprosić użytkownika o potwierdzenie adresu e-mail.

Warto zwrócić uwagę na fakt, że wymienione funkcje nie sprawdzają, czy
podane adresy e-mail faktycznie istnieją, a jedynie czy są zgodne ze
zdefiniowanym wzorcem — jeden lub więcej dozwolonych znaków, znak @,
więcej znaków, kropka, kilka znaków domeny najwyższego poziomu. Rażąco
fałszywe adresy e-mail, takie jak kk@kk.kk, przejdą ten test.

------------------------------------------------------------------------

Uwaga

Jedynym sposobem sprawdzenia istnienia adresu e-mail jest wysłanie
wiadomości na ten adres i poproszenie odbiorcy o potwierdzenie jej
otrzymania poprzez podjęcie pewnego działania (najczęściej kliknięcie
łącza zawierającego unikalny identyfikator).

------------------------------------------------------------------------

HTML (lub XML)

HTML w tym podpunkcie może oznaczać fragment kodu HTML (np. komentarz na
stronie wpisu bloga) lub pojedynczy węzeł, tzn. element HTML wraz z
tekstem i atrybutami.

Fragment kodu HTML

Fragmenty kodu HTML mogą być oczyszczane za pomocą funkcji WordPress o
nazwie force_balance_tags(). Funkcja ta jednak nie jest uznawana za
przeprowadzającą weryfikację kodu HTML, a jedynie za funkcję pomocniczą
podczas sprawdzania poprawności. Funkcja wyszukuje nieprawidłowo
zagnieżdżone lub brakujące znaczniki zamykające i poprawia je:

    <?php
    // 1. Uzupełnienie brakujących znaczników zamykających:
    $html = '<p>Proszę zamknąć moje <strong>znaczniki!';
    var_dump( force_balance_tags( $html ) );
    // string(58) "<p>Proszę zamknąć moje <strong>znaczniki!</strong></p>"
    // 2. Poprawienie nieprawidłowo zagnieżdżonych znaczników:
    $html = '<p>Proszę <strong><em>poprawić</strong></em> zagnieżdżenie!</p>';
    var_dump( force_balance_tags( $html ) );
    // string(69) "<p>Proszę <strong><em>poprawić</em></strong> zagnieżdżenie!</p>"
    ?> 

Platforma WordPress jest dostarczana wraz ze skryptem o nazwie KSES
(akronim rekurencyjny od wyrażenia KSES Strips Evil Scripts), którego
zadaniem jest przetworzenie i oczyszczenie całego niezaufanego kodu
HTML, zarówno w danych wejściowych, jak i wyjściowych. Funkcja
opakowująca o nazwie wp_kses() pozwala na przeprowadzenie zaawansowanego
filtrowania fragmentów kodu HTML, np. własnego zbioru znaczników.

Możesz więc utworzyć funkcję przeznaczoną do usuwania wszystkich
znaczników HTML poza <strong> i <a href='' title=''>. Wszystkie
pozostałe znaczniki (<em>, <b>, …) i atrybuty (class='', style='', …)
zostaną usunięte.

Na początek trzeba zdefiniować tablicę dozwolonych znaczników i
atrybutów:

    <?php
    $allowed = array(
        'strong' => array(),
        'a'      => array(
            'href'  => array(),
            'title' => array()
        )
    );
    ?> 

Teraz można przystąpić do filtrowania i oczyszczania fragmentów kodu
HTML:

    <?php
    $html = '<a href="#" class="external" >witryna</a> 
    <b>pogrubienie?</b> <strong>pogrubienie!</strong>';
    var_dump( wp_kses( $html, $allowed ) );
    // string(68) "<a href="#" >witryna</a>pogrubienie?<strong>pogrubienie!</strong>"
    ?> 

Warto zwrócić uwagę, jak selektywnie utworzona funkcja usuwa znaczniki i
atrybuty zgodnie ze zdefiniowaną tablicą elementów dozwolonych. Funkcję
tę można wykorzystać np. do filtrowania komentarzy i zezwolenia na
używanie jedynie minimalnej ilości znaczników HTML.

Trzeba również zwrócić uwagę na fakt, że biblioteka KSES na platformie
WordPress ma zdefiniowany zestaw znaczników i atrybutów HTML, o czym
można się przekonać, przeglądając początek pliku wp-includes/kses.php.
Zmienna globalna $allowedtags zawiera dość restrykcyjnie dobrany zbiór
znaczników, które zwykle można zaakceptować w komentarzach i danych
wejściowych użytkowników.

Używając funkcji wp_kses_data() i przekazując jej pojedynczy argument w
postaci fragmentu kodu HTML przeznaczonego do oczyszczenia, korzystasz z
wspomnianej domyślnej listy dozwolonych elementów:

    <?php
    $html = '<a href="http://przyklad.pl">witryna</a> 
       <script src="script.js"></script> 
       <img src="image.png" /> 
       <junk>przypadkowy</junk>';
    var_dump( wp_kses_data( $html ) );
    // string(61) "<a href="http://przyklad.pl">witryna</a> przypadkowy"
    ?> 

Węzeł HTML

Węzeł to część dokumentu HTML (lub ponownie XML). Składa się z trzech
części pokazanych na rysunku 6.7.

[]

Rysunek 6.7. Trzy części składowe węzła HTML (lub XML)

1.  Element węzła (span, h1, em, … lub inny dowolny element XML).
2.  Atrybut węzła (class, style, title, alt, …).
3.  Tekst węzła (dowolny tekst znajdujący się poza atrybutami i
    elementami).

W przypadku węzła HTML trzeba w danych wyjściowych przeprowadzić
operację oczyszczenia atrybutu i tekstu węzła oraz upewnić się, że są
prawidłowe i nie spowodują zniszczenia wyświetlanego dokumentu.

Zanim zaczniesz czytać dalej, przeanalizuj przedstawiony poniżej
fragment kodu i spróbuj odnaleźć jego słabe strony.

    <h1><?php echo $page_title; ?></h1> 
    <a href="#anchor" title="<?php echo $link_title; ?>" >odnośnik</a> 

Podobnie jak w przypadku przedstawionego wcześniej nieprawidłowego
formularza, także tutaj problemem jest brak oczyszczenia tekstu węzła (w
zmiennej $page_title) oraz atrybutu węzła (w zmiennej $link_title) przed
ich wyświetleniem. To może doprowadzić do otrzymania nieoczekiwanych i
potencjalnie szkodliwych danych wyjściowych, np. z poniższymi
wartościami:

    <?php
    $page_title = 'uszkodzenie</h1><h1>znacznika';
    $link_title = '" onmouseover="alert(\'XSS\');';
    ?> 

Platforma WordPresss oferuje dwie funkcje specjalnie przeznaczone do
oczyszczania atrybutów i tekstu węzła HTML, usuwania niedozwolonych
znaków i konwersji znaków na encje HTML — esc_attr() i esc_html(). Ten
sam blok kodu, ale już zabezpieczony, przedstawia się następująco:

    <h1><?php echo esc_html( $page_title; ) ?></h1> 
    <a href="#anchor" title="<?php echo esc_attr( $link_title; ) ?>" >odnośnik</a> 

W środowisku uwzględniającym tłumaczenie wtyczki funkcje esc_attr() i
esc_html() mają odpowiedniki, które dodatkowo przeprowadzają tłumaczenie
(np. esc_html_e()). Więcej informacji na temat tych funkcji znajduje się
w rozdziale 5. poświęconym tłumaczeniu wtyczki na inne języki.

Adresy URL

Niezależnie od tego, czy są używane jako dane wyjściowe w atrybucie HTML
węzła (<a href="">), czy jako samodzielne fragmenty informacji (np. w
polu formularza, w którym trzeba podać adres URL witryny), adresy URL
zawsze powinny być oczyszczane za pomocą funkcji WordPress o nazwie
esc_url(). Wymieniona funkcja sprawdza i oczyszcza adres URL poprzez
usunięcie niedozwolonych znaków i opcjonalnie może również filtrować
protokół.

W danych wyjściowych funkcji esc_url() można użyć w następujący sposób:

    <?php
    // Niebezpieczny adres URL.
    $url = 'javascript:alert("XSS");';
    ?> 
    <a href="<?php echo esc_url( $url ); ?> ">Odnośnik tekstowy</a> 

W powyższym przykładzie odnośnik będzie bezpiecznie wyświetlony wraz z
pustym atrybutem href. Natomiast w przypadku danych wejściowych trzeba
przekazać albo jeden (adres URL), albo dwa parametry (adres URL i
tablicę dozwolonych protokołów) w celu przeprowadzenia oczyszczenia
danych przed ich przechowaniem lub zwróceniem do dalszego przetwarzania.

Zwróć uwagę na sposób oczyszczania różnych adresów URL:

    <?php
    $url1 = 'http://przyklad.pl/"<script> alert(\'XSS\')</script>';
    var_dump( esc_url( $url1 ) );
    // string(54) "http://przyklad.pl/scriptalert('XSS')/script"
    $url2 = 'http://przyklad.pl/" & lt;script & gt;alert(\'XSS\') & lt;/script & gt;';
    var_dump( esc_url( $url2 ) );
    // string(70) "http://przyklad.pl/ & lt;script & gt;alert('XSS') & lt;/script & gt;"
    $url3 = 'onmouseover="alert(\'XSS\')';
    var_dump( esc_url( $url3 ) );
    // string(41) "http://onmouseover=alert('XSS')"
    $url4 = 'c:\dir\dir\dir\dir';
    var_dump( esc_url( $url4 ) );
    // string(0) ""
    $url5 = 'http://prz[]ykl[]ad.p[]l/';
    var_dump( esc_url( $url5 ) );
    // string(19) "http://przyklad.pl/"
    ?> 

Jak można się przekonać, przeznaczeniem funkcji esc_url() nie jest
sprawdzenie poprawności adresu URL (np. http://onmouseover=alert('XSS')
nie wydaje się być poprawnym adresem URL), ale jego oczyszczenie, by w
trakcie użycia zminimalizować jego ewentualną szkodliwość.

Dzięki możliwości użycia drugiego parametru funkcja doskonale sprawdza
się w ograniczeniu dozwolonych protokołów:

    <?php
    $allowed = array( 'http', 'https', 'ftp' );
    $url1 = 'https://przyklad.pl';
    var_dump( esc_url( $url1, $allowed ) );
    // string(19) "https://przyklad.pl"
    $url2 = 'irc://przyklad.pl';
    var_dump( esc_url( $url2, $allowed ) );
    // string(0) ""
    $url3 = 'xyz123://przyklad.pl';
    var_dump( esc_url( $url3, $allowed ) );
    // string(0) ""
    ?> 

Adresy URL w bazie danych

Funkcja esc_url() konwertuje znaki ampersand i apostrof na odpowiadające
im encje HTML i upewnia się, że wyświetlenie adresu URL nie spowoduje
zniszczenia danych wyjściowych. Aby oczyścić adres URL w celu jego
przechowania w bazie danych, należy użyć funkcji esc_url_raw(), która
przeprowadza oczyszczanie, ale bez konwersji znaków na encje:

    <?php
    $url = "http://prz[y]klad.pl/?q=1&s=2'";
    var_dump( esc_url( $url ) );
    // string(38) "http://przyklad.pl/?q=1&#038;s=2&#039;"
    var_dump( esc_url_raw( $url ) );
    // string(28) "http://przyklad.pl/?q=1&s=2'"
    ?> 

Adresy URL w przekierowaniach

Czasami zdarza się przekierowanie użytkowników na stronę, której
położenie zależy od wartości wygenerowanej dla użytkownika, np.
http://przyklad.pl/​profile.php?user=$user. Błędnym rozwiązaniem
wykonania tego zadania na platformie WordPress będzie zastosowanie po
prostu przekierowania za pomocą nagłówka:

    <?php
    header( "Location: http://przyklad.pl/profile.php?user=$user" );
    ?> 

Pominięcie oczyszczenia zmiennej $user może doprowadzić do
przeprowadzenia niechcianego przekierowania na inny serwer (w zależności
od zainstalowanej wersji PHP) z wartościami, takimi jak
"Jan\nLocation:http://wrogawitryna/".

Prawidłowym sposobem obsługi przekierowania na platformie WordPress jest
użycie jej funkcji o nazwie wp_redirect(), która najpierw oczyszcza dane
przekierowania:

    <?php
    wp_redirect( "http://przyklad.pl/profile.php?user=$user" );
    ?> 

JavaScript

Osadzony kod JavaScript (np. taki jak onclick="doSomething();") to inny
rodzaj atrybutu węzła HTML, wymagający specjalnego traktowania i własnej
funkcji oczyszczania, czyli esc_js().

Funkcji można użyć w celu upewnienia się, że kod JavaScript
wykorzystujący zmienne dynamiczne PHP nie spowoduje szkód. Oto przykład:

    <?php
    $user = 'Jan';
    ?> 
    <script type="text/javascript"> 
    var user = '<?php echo esc_js( $user ); ?>';
    function confirm_delete() {
        return confirm('Czy naprawdę usunąć użytkownika '+user+'?');
    }
    </script> 
    <a href="<?php echo esc_url( "delete.php?user=$user" ); ?>"
       onclick="javascript:return( confirm_delete() )"
       title="Usuń">Usuń użytkownika<?php echo esc_html( $user ) ?></a> 

Warto zwrócić uwagę, że w powyższym przykładzie wykorzystano różne
funkcje esc_ w celu oczyszczania poszczególnych fragmentów odnośnika
"usuń".

Zmienne serwera lub środowiska

Tablica superglobalna $_SERVER, choć nazwa na to nie wskazuje, zawiera
informacje otrzymane przez serwer od klienta, tzn. z przeglądarki
internetowej użytkownika. Z tego powodu otrzymane wartości należy
uznawać za niebezpieczne. Zawsze należy upewnić się o oczyszczeniu
zmiennej, której trzeba użyć, za pomocą odpowiednich funkcji.

Jeśli przykładowo na stronie ma być wyświetlony adres URL strony
poprzednio odwiedzonej przez użytkownika, nie należy używać poniższego
rozwiązania:

    <?php if( isset( $_SERVER['HTTP_REFERER'] ) ) { ?> 
    Witamy użytkownika przychodzącego ze strony <?php echo $_SERVER['HTTP_REFERER']; ?> !
    <?php } ?> 

Ponieważ adres URL można bardzo łatwo sfałszować, a ponadto może
zawierać podejrzany kod umieszczony przez złośliwego użytkownika, warto
stosować funkcję esc_url():

    <?php if( isset( $_SERVER['HTTP_REFERER'] ) ) { ?> 
    Witamy użytkownika przychodzącego ze strony <?php echo esc_url( $_SERVER['HTTP_REFERER'] ); ?> !
    <?php } ?> 

Analogicznie, nie należy ufać wartości user-agent przechowywanej w
elemencie tablicy $_SERVER['HTTP_USER_AGENT']. Jeżeli chcesz wyświetlić
tego rodzaju dane, warto je potraktować jako niebezpieczny kod HTML i
najpierw oczyścić za pomocą funkcji wp_kses().

Inne często używane zmienne serwera to $_SERVER['REQUEST_URI'] i
$_SERVER['PHP_SELF']; zawierają one położenie aktualnie wczytanej strony
oraz wykonywanego skryptu. Kiedy ich wartości nie zostaną oczyszczone,
wymienione zmienne serwera można bardzo łatwo wykorzystać w złośliwych
celach. Przykładowo po wysłaniu poniższy formularz jest przetwarzany
przez ten sam plik.

    <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" > 
    <input type="text" name="fullname" / > 
    <input type="submit" value="Zapisz" / > 
    </form> 

Zapisz ten formularz w pliku pod nazwą self_form.php, a następnie w
pasku adresu przeglądarki internetowej podaj adres
http://localhost/self_form.php/"><script>alert(1337)</script> i
przekonaj się, jaki będzie skutek (zobacz rysunek 6.8).

[]

Rysunek 6.8. Wynik wysłania przedstawionego wcześniej formularza

Najlepszym rozwiązaniem jest zawsze określenie w kodzie wartości
parametru action "na stałe" lub pozostawienie pustej wartości parametru
(<form action="" method="post">), co spowoduje przesłanie danych z
powrotem w to samo miejsce. Jeżeli wartość parametru action ma być
podawana dynamicznie lub podczas używania zmiennej serwerowej, jej
wartość należy zawsze oczyścić za pomocą funkcji esc_url().

Pliki cookies

Podobnie jak nie wolno ufać tablicom $_GET i $_POST, tak samo należy
postępować z tablicą $_COOKIE. Pliki cookie to zwykłe pliki tekstowe
przechowywane w komputerze klienta, a zatem mogą być łatwo poddane
edycji za pomocą np. rozszerzenia Firebug przeglądarki Firefox. Dlatego
też pliki cookie trzeba traktować tak samo jak dane przekazane z
formularza, czyli weryfikować i oczyszczać.

------------------------------------------------------------------------

Uwaga

W PHP tablica $_REQUEST zwykle zawiera dane pochodzące z tablic $_GET,
$_POST i $_COOKIE. Warto pamiętać, że po uruchomieniu platforma
WordPress usuwa tablicę $_COOKIE z tablicy $_REQUEST. Dlatego też, jeśli
musisz sprawdzić wartość cookie, nie polegaj na tablicy $_REQUEST w
środowisku WordPress, ale bezpośrednio sprawdź tablicę $_COOKIE.

------------------------------------------------------------------------

Tablice danych

Tablicę podobnych danych można bardzo łatwo zweryfikować i oczyścić za
pomocą funkcji PHP o nazwie array_map().

Wyobraź sobie sytuację, w której użytkownik ma podać kilka dodatnich
liczb całkowitych (wiek, liczbę dzieci i dochód gospodarstwa domowego).
W celu oczyszczenia tych danych trzeba użyć funkcji absint(). Dane można
przetworzyć pojedynczo lub użyć krótszego i efektywniejszego kodu:

    <?php
    // Oczyszczenie całej tablicy $_POST.
    $_POST = array_map( 'absint', $_POST );
    // Wyodrębnienie jedynie oczekiwanych wartości.
    $clean = array();
    $clean['age'] = $_POST['age'];
    $clean['numchild'] = $_POST['numchild'];
    $clean['income'] = $_POST['income'];
    ?> 

Technika ta jest szczególnie użyteczna, kiedy nie znana jest liczba
elementów wymagających oczyszczenia. Weź pod uwagę pole <textarea>, w
którym użytkownik ma podać listę adresów URL, takich jak ulubione adresy
witryn, po jednym w każdym wierszu.

Aby oczyścić tego rodzaju listę, można ją podzielić na poszczególne
adresy URL, a następnie otrzymaną tablicę w całości przekazać funkcji
esc_url():

    <?php
    $clean_urls = array();
    // Podział wartości pola <textarea> na tablicę adresów URL.
    $urls = split( "\n", $_POST['urls'] );
    // Oczyszczenie całej tablicy.
    $clean_urls = array_map( 'esc_url', $urls );
    ?> 

Dane pochodzące ze zdefiniowanego zbioru

Jeśli nawet wydaje się, że formularz może przyjąć tylko pewne określone
wartości dla danego pola, np. TAK lub NIE w przycisku opcji, to
otrzymane wartości i tak zawsze należy weryfikować. Ogólnie rzecz
biorąc, w każdym formularzu bardzo łatwo można przekazać do serwera
dowolne dane, co zostanie pokazane poniżej.

Na początek trzeba utworzyć skrypt wyświetlający prosty formularz z
przyciskami opcji, polami wyboru i rozwijaną listą (zobacz rysunek 6.9).
Aby zasymulować zachowanie wprowadzonych informacji, skrypt może je
zapisać w lokalnym pliku tekstowym.

[]

Rysunek 6.9. Formularz używany w omawianym przykładzie

    <?php
    if( $_POST ) {
        $post = print_r( $_POST, true );
        error_log( $post, 3, dirname( __FILE__ ).'/post.log' );
    }
    ?> 
    <form action="" method="post" > 
        Płeć:
        <input type="radio" name="gender" value="mężczyzna" />mężczyzna
        <input type="radio" name="gender" value="kobieta" />kobieta
        Nielubiane potrawy:
        <input type="checkbox" name="food[]" value="szpinak" />szpinak
        <input type="checkbox" name="food[]" value="sardela" />sardela
        <input type="checkbox" name="food[]" value="wątróbka" />wątróbka
        Kraj zamieszkania:
        <select name="country" > 
        <option value="polska">Polska</option> 
        <option value="kanada">Kanada</option> 
        <option value="uk">Wielka Brytania</option> 
        <option value="inny">Inny</option> 
        </select> 
        <input type="submit" value="Zapisz" /> 
    </form> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku locked_form.php.

------------------------------------------------------------------------

Na początku skryptu, jeśli tablica $_POST została zdefiniowana,
zawartość zostaje zapisana w pliku o nazwie post.log w tym samym
katalogu. Więcej informacji na temat błędów oraz rejestrowania
komunikatów znajduje się w rozdziale 16., który poświęcony został
tematom usuwania błędów i optymalizacji kodu.

Pokazany formularz wydaje się bezpieczny: każde pole ma ograniczony
zbiór akceptowanych wartości. Na początku prawdopodobnie zakładasz, że
przekazane do serwera dane zawsze będą składały się z wierszy, które
można znaleźć w tablicy zapisanej w pliku post.log:

    Array
    (
        [gender] => mężczyzna
        [food] => Array
            (
                [0] => sardela
                [1] => wątróbka
            )
        [country] => inny
    ) 

Jeśli pola tekstowe wymuszają użycie określonych wartości, to i tak
formularz może przekazać do serwera dowolne wartości. Możesz się teraz
wczuć w rolę złośliwego użytkownika i wykorzystać przedstawiony powyżej
formularz w celu przekazania do serwera zupełnie innych danych:

    <form action="locked_form.php" method="post"> 
       <input name="gender" value="hello" /> 
       <input name="food[]" value="<script>alert('hello');</script>" /> 
       <input name="country" value="bleh" /> 
       <input name="random" value="1337" /> 
       <input type="submit" /> 
    </form> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku locked_form_abuse.php.

------------------------------------------------------------------------

Zwróć uwagę, że wartości przekazane do skryptu wymienionego w parametrze
action są zupełnie przypadkowe i nie mogą być wygenerowane przez
przedstawiony wcześniej formularz.

------------------------------------------------------------------------

Uwaga

Przekazanie skryptowi dowolnych informacji odbywa się za pomocą zwykłego
pliku HTML znajdującego się w dowolnym położeniu, nawet w komputerze
biurkowym pozbawionym serwera WWW. Nigdy nie zakładaj, że wszyscy
użytkownicy zawsze przekazują do serwera jedynie oczekiwane dane.

------------------------------------------------------------------------

Powróćmy jeszcze do pierwszego formularza locked_form.php: teraz możesz
go zabezpieczyć i oczyścić wartości przed ich przechowaniem. Ponieważ
wiadomo, że poszczególne pola pobierają różne wartości, możesz utworzyć
efektywny kod i proste filtry, używając techniki białej listy. Blok kodu
odpowiedzialny za przechowywanie wartości będzie miał postać:

    <?php
    if( $_POST ) {
        $clean = array();
        // Płeć: dwie możliwe wartości, domyślna 'mężczyzna'.
        $clean['gender'] = ( $_POST['gender'] == 'kobieta' ? 'kobieta' : 'mężczyzna' );
        // Jedzenie: zmienna liczba możliwych wartości, stąd brak wartości domyślnej.
        $foods = array( 'szpinak', 'sardela', 'wątróbka' );
        if( in_array( $_POST['food'], $foods ) )
            $clean['food'] = $_POST['food'];
        // Kraj: zmienna liczba możliwych wartości, więc wartością domyślną jest 'inny'.
        switch( $_POST['country'] ) {
            case 'kanada':
            case 'uk':
            case 'polska':
                $clean['country'] = $_POST['country'];
                break;
            default:
                $clean['country'] = 'inny';
        }
        $post = print_r( $clean, true );
        error_log( $post, 3, dirname( __FILE__ ).'/post.log' );
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku locked_form_secure.php.

------------------------------------------------------------------------

Warto zwrócić uwagę na użycie różnych metod sprawdzania składni.
Pierwsze porównanie i oczyszczenie wartości dla pola płci jest
przeprowadzane za pomocą operatora trójargumentowego PHP. Ten wiersz
oznacza: "czy wartość elementu tablica $_POST['gender'] wynosi
kobieta?". Jeśli tak, wówczas wartością elementu $clean['gender']
faktycznie będzie kobieta, natomiast w przeciwnym razie wartością będzie
mężczyzna.

Zapytania do bazy danych

Zapytania do bazy danych to — z punktu widzenia bezpieczeństwa — ciągi
tekstowe o znaczeniu krytycznym. Rozważ np. aplikację sieciową, w której
przedstawione poniżej zapytanie jest używane do uwierzytelnienia
użytkownika po podaniu przez niego nazwy użytkownika i hasła:

    <?php
    $sql = "SELECT * FROM users
            WHERE `user_login` = '$login' AND `user_pass`= '$password'";
    ?> 

Ponieważ to polecenie SQL nie jest oczyszczone, złośliwy użytkownik może
zalogować się, podając poniższe dane uwierzytelniające:

    <?php
    $login = 'cokolwiek';
    $password = "123456' OR 1='1";
    ?> 

Gdy ustawisz wartości zmiennych w taki sposób, polecenie SQL staje się
prostym warunkiem 1=1, który — oczywiście — zawsze jest prawdziwy:

    SELECT * FROM users
    WHERE `user_login` = 'adminzzz'
    AND `user_pass`= '123456'
    OR 1='1' 

Ten przykład to zakończony powodzeniem atak typu SQL Injection —
użytkownik manipuluje poleceniem wykonywanym przez bazę danych. W
zabawny sposób zostało to pokazane na rysunku 6.10 utworzonym przez
Randalla Munroe'a. Ten rysunek został umieszczony w książce za jego
zgodą (adres URL opublikowanego rysunku to: http://xkcd.com/327/).

[]

Rysunek 6.10. Atak typu SQL Injection przedstawiony w zabawny sposób

Na szczęście, platforma WordPress jest dostarczana wraz z funkcjami
pomagającymi w prawidłowym oczyszczaniu zapytań do bazy danych.

Funkcja esc_sql() oczyszcza zawartość przeznaczoną do umieszczenia w
bazie danych, co oznacza dodawanie ukośników przed znakami, które tego
wymagają (czyli apostrofami i ukośnikami). Zaletą funkcji esc_sql() jest
możliwość przetwarzania zarówno ciągu tekstowego zapytania, jak również
tablicy ciągów tekstowych.

    <?php
    $login = 'back\slash';
    $sql = 'SELECT * FROM `users` WHERE `login` = "'. esc_sql( $login ) .'"';
    var_dump( $sql );
    // string(55) "SELECT * FROM `users` WHERE `login` = "back\\slash""
    ?> 

Funkcja like_escape() zajmuje się oczyszczaniem tekstu stosowanego w
klauzulach LIKE, w których używane są znaki specjalne, takie jak % i &:

    <?php
    $pattern = 'jan';
    $like = like_escape( 'LIKE "%'.$pattern.'%"' );
    $sql = 'SELECT * FROM `users` WHERE `username` '.$like;
    var_dump( $sql );
    // string(53) "SELECT * FROM `users` WHERE `username` LIKE "\%jan\%""
    ?> 

Z kolei funkcja sanitize_sql_orderby() zajmuje się oczyszczaniem klauzul
ORDER BY przed ich umieszczeniem w ciągu tekstowym SQL:

    <?php
    $order_by   = 'last_name';
    $order_sort = 'DESC';
    $order = sanitize_sql_orderby( "$order_by $order_sort" );
    $sql = 'SELECT * FROM `users` ORDER BY '. $order;
    var_dump( $sql );
    // string(45) "SELECT * FROM `users` ORDER BY last_name DESC"
    ?> 

Do oczyszczania zapytań WordPress oferuje znacznie więcej niż wymienione
proste funkcje — wyposażony został w pełny zestaw funkcji przeznaczonych
do bezpiecznego formatowania poleceń SQL.

Formatowanie poleceń SQL

W platformie WordPress zaimplementowano wiele funkcji służących do
pobierania informacji z bazy danych. Funkcje te zostaną przedstawione w
tym podrozdziale.

Obiekt $wpdb

Cała współpraca bazy danych z platformą WordPress może się odbywać za
pomocą klasy o nazwie wpdb, która wywodzi się z popularnej klasy ezSQL
(możesz to dostrzec, jeśli masz jakieś doświadczenie z PHP).

Zapytań SQL nie powinieneś wykonywać za pomocą funkcji PHP, takich jak
mysql_query() lub mysql_fetch_array(), z dwóch powodów.

-   Klasa wpdb platformy WordPress oferuje znacznie większy poziom
    bezpieczeństwa i znacznie bardziej chroni zapytania przed atakami
    typu SQL Injection.
-   Właściciel bloga może zastąpić bazę danych MySQL innym produktem
    (np. PostgreSQL), w takim przypadku funkcje opierające się na MySQL
    nie będą działały.

Metody wymienionej klasy, które zostaną przedstawione w tym
podrozdziale, nie powinny być wywoływane bezpośrednio. Zawsze należy
używać obiektu $wpdb utworzonego przez platformę WordPress na każdej
stronie.

------------------------------------------------------------------------

Uwaga

Nie zapomnij o "zglobalizowaniu" zmiennej $wpdb (tzn. o dodaniu wiersza
global $wpdb) przed jej zastosowaniem we własnych funkcjach.

------------------------------------------------------------------------

Obiekt $wpdb może być wykorzystywany w celu uzyskania dostępu do danych
znajdujących się w dowolnej tabeli bazy danych używanej przez platformę
WordPress. To obejmuje zarówno wszystkie standardowe tabele utworzone po
instalacji bądź uaktualnieniu bloga, jak również własne tabele zbudowane
przez wtyczkę. Tworzenie własnych tabel przez wtyczkę zostało dokładnie
omówione w rozdziale 7.

Dlaczego metody obiektu wpdb są lepsze?

Obiekt $wpdb zawiera wiele metod, które można wykorzystać do odczytu,
wstawiania, uaktualniania lub usuwania informacji z tabel. W
przedstawionych poniżej przykładach otrzymamy ten sam wynik, ale warto
zwrócić uwagę na ich czytelność i niezawodność:

    <?php
    // Przykład 1.
    mysql_connect( DB_HOST, DB_USER, DB_PASSWORD ) or
       die("Nie można nawiązać połączenia: " . mysql_error());
    mysql_select_db( DB_NAME );
    mysql_query( "UPDATE wp_posts SET post_title= '$newtitle' WHERE ID= $id" );
    // Przykład 2.
    $newtitle = esc_sql( $newtitle );
    $my_id = absint( $my_id );
    $wpdb->query( "UPDATE $wpdb->posts SET post_title='$newtitle' WHERE ID=$id");
    // Przykład 3.
    $new_values = array( 'post_title' => $newtitle );
    $where = array( 'ID' => $my_id );
    $wpdb->update( $wpdb->posts, $new_values, $where );
    ?> 

Co można powiedzieć na podstawie tych trzech przykładów?

-   W przykładzie pierwszym pokazano stary, ręczny sposób nawiązania
    połączenia z bazą danych i wykonania zapytania. Ten sposób jest
    niewygodny. Samo zapytanie także nie jest najlepsze: nazwa tabeli
    została na stałe zapisana w kodzie, choć właściciel bloga ma
    przecież możliwość zmiany prefiksu tabeli. Zmienne $newtitle i $id
    nie są oczyszczane.

-   Przykład drugi jest dobry: zmienne zostały oczyszczone za pomocą
    funkcji przedstawionych we wcześniejszej części rozdziału, nazwa
    tabeli zgadza się z lokalnym prefiksem tabeli, a samo zapytanie jest
    wykonywane przy użyciu obiektu $wpdb i jego metody update().

-   Przykład trzeci jest dobry i jeszcze łatwiejszy: zdefiniowano
    tablicę wartości do uaktualnienia w postaci par wartości,
    zdefiniowano tablicę klauzul WHERE o tej samej strukturze, a
    oczyszczeniem zapytania zajmuje się odpowiednia metoda. Nie musisz
    pamiętać dokładnej składni SQL, nie musisz pamiętać o oczyszczaniu
    danych — po prostu w całości polegasz na API oferowanym przez
    platformę WordPress.

-   

    ------------------------------------------------------------------------

    Uwaga

    Zawsze korzystaj z metod obiektu $wpdb: dzięki tym funkcjom tworzony
    przez Ciebie kod jest łatwiejszy w odczycie, obsłudze oraz
    bezpieczniejszy w działaniu.

    ------------------------------------------------------------------------

Metody typu "wszystko w jednym"

Jak pokazano w powyższym przykładzie nr 3, metody typu "wszystko w
jednym" są niezawodnymi funkcjami, które nie zmuszają do zapamiętywania
najnudniejszych fragmentów (składnia SQL, funkcje oczyszczania) i
zajmują się zarządzaniem całością. Do tych funkcji zaliczamy update() i
insert().

$wpdb->update()

Ta metoda wymaga trzech parametrów:

-   nazwy tabeli (pamiętaj o użyciu $wpdb->prefix);
-   tablicy danych do uaktualnienia w postaci nieoczyszczonych par
    wartości;
-   tablicy klauzul WHERE w postaci nieoczyszczonych par wartości.
    Jeżeli istnieje wiele klauzul, zostaną połączone za pomocą AND.

Opcjonalnie można przekazać jeszcze dwa parametry:

-   Tablicę formatów, które mają być zastosowane względem uaktualnianych
    danych (lub ciąg tekstowy zamiast tablicy, jeśli względem wszystkich
    wartości ma być użyty ten sam format). Format może mieć postać '%d'
    dla liczb dziesiętnych, '%s' dla ciągu tekstowego lub '%f' dla
    liczby zmiennoprzecinkowej. Brak wyraźnie wskazanego formatu
    oznacza, że wartość jest traktowana jak ciąg tekstowy, chyba że w
    standardowej tabeli definicji WordPress zapisano inaczej.
-   Tablicę formatów (lub ciąg tekstowy, jeśli ma być zastosowany tylko
    jeden format) przeznaczonych do użycia względem wartości klauzul
    WHERE. Brak wyraźnie wskazanego formatu oznacza, że wartość jest
    traktowana jak ciąg tekstowy.

Aby zaprezentować przykład użycia omawianej funkcji, skorzystamy z
tabeli o nazwie wp_custom o prostej strukturze przedstawionej w tabeli
6.1.

Tabela 6.1. Struktura tabeli wp_custom

  --------------------------------- ----------------------- -------------
  COL_ID                            COL_STRING              COL_INTEGER
  int(11) NOT NULL AUTO_INCREMENT   varchar(100) NOT NULL   int(11)
  --------------------------------- ----------------------- -------------

Teraz możesz uaktualnić rekord tabeli wp_custom, dla którego
identyfikator ma wartość 1, wartością w drugiej kolumnie jest ciąg
tekstowy, natomiast w trzeciej — liczba całkowita:

    <?php
    $values = array(
        'column1' => 'dowolny ciąg tekstowy',
        'column2' => 43
    );
    $where = array(
        'ID' => 1
    );
    $formats_values = array( '%s', '%d' );
    $formats_where = array( '%d' );
    $wpdb->update( $wpdb->custom, $values, $where, $formats_values, $formats_where );
    ?> 

Jak możesz zobaczyć, omawiana metoda pozwala na deklarację zapytania SQL
w zorganizowany sposób, z uwzględnieniem formatu danych do oczyszczenia.
Wartością zwrotną metody jest false w przypadku błędu lub liczba
całkowita wskazująca liczbę rekordów, których dotyczyło zapytanie.

------------------------------------------------------------------------

Uwaga

Nie umieszczaj w kodzie wtyczki zapisanego na stałe prefiksu tabeli bazy
danych WordPress (zwykle wp_). Zamiast tego upewnij się o użyciu
zmiennej $wpdb->prefix. W ten sposób nie tylko zostanie użyty prawidłowy
prefiks, ale również poprawny identyfikator wpisu bloga w środowisku
sieci blogów.

------------------------------------------------------------------------

$wpdb->insert()

Metodę tę można wykorzystać do wstawiania danych w podobnej operacji.
Metoda wymaga podania trzech parametrów:

-   nazwy tabeli;
-   tablicy danych do wstawienia w postaci nieoczyszczonych par
    wartości;
-   opcjonalnej tablicy formatów, które mają być zastosowane względem
    wstawianych wartości; w przeciwnym razie są traktowane i oczyszczane
    jak ciągi tekstowe.

Za pomocą metody insert() można wstawić rekord do tej samej tabeli
$wpdb->custom, pierwsza kolumna zawiera ciąg tekstowy, natomiast druga —
liczbę całkowitą:

    <?php
    $values = array(
        'column1' => 'nowy ciąg tekstowy',
        'column2' => 44
    );
    $formats_values = array( '%s', '%d' );
    $wpdb->insert( $wpdb->custom, $values, $formats_values );
    ?> 

Podobnie jak w metodzie update(), wartością zwrotną tej metody także
jest false w przypadku błędu lub liczba całkowita wskazująca liczbę
rekordów, których dotyczyło zapytanie.

Najczęściej stosowane metody

Nie wszystkie wykonywane zapytania będą prostymi poleceniami UPDATE lub
INSERT. Klasa wpdb oferuje wiele innych metod przeznaczonych np. do
pobierania pojedynczej wartości, całego rekordu lub wykonywania różnych
skomplikowanych poleceń.

Pobranie zmiennej

Metoda get_var() zwraca pojedynczą zmienną z bazy danych WordPress (lub
NULL, gdy wartość nie zostanie znaleziona).

Przykładowo w celu pobrania liczby opublikowanych wpisów bloga można
wykonać przedstawione poniżej polecenie:

    <?php
    $sql = "SELECT COUNT(ID) FROM {$wpdb->posts}
            WHERE post_status = 'publish' AND post_type = 'post'";
    $num_of_posts = $wpdb->get_var( $sql );
    ?> 

Pobranie rekordu

W celu pobrania całego rekordu (lub jego fragmentów) należy użyć metody
get_row(), która zwraca wynik w postaci obiektu, tablicy asocjacyjnej
lub tablicy indeksowanej liczbowo. Składnia wymienionej metody jest
następująca:

    <?php
    $wpdb->get_row( $sql, $output_type, $row_offset );
    ?> 

Metoda wymaga podania trzech parametrów

-   $sql — zapytanie SQL;
-   $output_type — opcjonalnie jedna z trzech predefiniowanych stałych:
    OBJECT (wynik będzie zwrócony w postaci obiektu), ARRAY_A (wynik
    będzie zwrócony w postaci tablicy asocjacyjnej) lub ARRAY_N (wynik
    będzie zwrócony w postaci tablicy indeksowanej liczbowo), przypadku
    pominięcia wartością domyślną jest OBJECT;
-   $row_offset — opcjonalnie można podać żądany rekord, wartością
    domyślną jest 0.

Przykładowo poniższy fragment kodu pobiera z tabeli users adres e-mail i
URL użytkownika admin, a następnie wyświetla wyniki w różnych
postaciach. Samo zapytanie SQL jest następujące:

    <?php
    $sql = "SELECT `user_email`, `user_url`
            FROM $wpdb->users
            WHERE user_login = 'admin'";
    $object  = $wpdb->get_row( $sql, OBJECT );
    $array_a = $wpdb->get_row( $sql, ARRAY_A );
    $array_n = $wpdb->get_row( $sql, ARRAY_N );
    ?> 

Wyniki powyższego zapytania można wyświetlić za pomocą funkcji
var_dump(). Przeanalizuj naturę każdego wyniku, w zależności od
wybranego typu wartości zwrotnej:

    <?php
    var_dump( $object );
    /*
    object(stdClass)#824 (2) {
      ["user_email"] => string(17) "ozh@ozh.org"
      ["user_url"] => string(21) "http://ozh.org/"
    }
    */
    var_dump( $array_a );
    /*
    array(2) {
      ["user_email"] => string(17) "ozh@ozh.org"
      ["user_url"] => string(21) "http://ozh.org/"
    }
    */
    var_dump( $array_n );
    /*
    array(2) {
      [0] => string(17) "ozh@ozh.org"
      [1] => string(21) "http://ozh.org/"
    }
    */
    ?> 

Natura wyniku będzie miała wpływ na sposób uzyskania dostępu do
poszczególnych rekordów. Aby np. pobrać adres e-mail wskazanego
użytkownika, można użyć jednej z trzech wymienionych poniżej konstrukcji
składni:

    <?php
    $email = $object-> user_email;
    $email = $array_a['user_email'];
    $email = $array_n[0];
    ?> 

Warto zwrócić uwagę, że w dwóch pierwszych konstrukcjach mamy odwołanie
do user_email, czyli nazwy kolumny w bazie danych.

------------------------------------------------------------------------

Uwaga

Podczas pobierania wartości z bazy danych warto preferować wynik w
postaci obiektu lub tablicy asocjacyjnej. Te dwa formaty danych
wyjściowych mogą zawierać nazwy kolumn bazy danych, co zwiększa
czytelność.

------------------------------------------------------------------------

Pobranie kolumny

Za pomocą tej metody można pobrać całą kolumnę lub jej fragment, a wynik
jest zwracany w postaci tablicy. Metoda wymaga pierwszego parametru w
postaci zapytania oraz opcjonalnie drugiego w postaci wartości
przesunięcia kolumny, jeśli zwrócona ma być więcej niż tylko jedna
kolumna. (Wartością domyślną drugiego parametru jest 0).

Wyobraź sobie sytuację, w której chcesz wysłać wiadomość e-mail do
wszystkich zarejestrowanych użytkowników Twojej instalacji WordPress i
poinformować ich o tymczasowym zawieszeniu usługi ze względu na
konieczność przeprowadzenia konserwacji.

Najpierw trzeba wykonać zapytanie względem tabeli $wpdb->users i pobrać
kolumnę user_email:

    <?php
    $sql = "SELECT `user_email` FROM $wpdb->users";
    $emails = $wpdb->get_col( $sql );
    ?> 

Teraz można już każdemu zarejestrowanemu użytkownikowi wysłać wiadomość
e-mail:

    <?php
    $subject = 'Konserwacja bloga';
    $message = 'Drogi użytkowniku, ze względu na konserwację blog będzie nieczynny
       przez 15 minut.';
    foreach( $emails as $email ) {
        wp_mail( $email, $subject, $message );
    }
    ?> 

Pobranie ogólnych wyników

Kiedy trzeba pobrać ogólne wyniki z wielu rekordów, można użyć metody o
nazwie get_results(). Funkcja to potrzebuje — oczywiście — parametru w
postaci zapytania SQL oraz opcjonalnie podania formatu danych
wyjściowych: OBJECT, ARRAY_N lub ARRAY_A (zostały omówione we
wcześniejszej części podrozdziału).

Jako przykład bardziej skomplikowanego zapytania poniżej wymieniona
metoda jest używana do pobrania liczby wpisów bloga, które zostały
opublikowane każdego roku:

    <?php
    $sql = "SELECT YEAR(post_date) AS `year`, count(ID) as posts
            FROM $wpdb->posts
            WHERE post_type = 'post' AND post_status = 'publish'
            GROUP BY YEAR(post_date)
            ORDER BY post_date DESC";
    $results = $wpdb->get_results( $sql, ARRAY_A );
    ?> 

Po użyciu funkcji print_r( $results ) otrzymana tablica asocjacyjna może
mieć następującą postać:

    Array (
        [0] =>  Array (
                [year] =>  2010
                [posts] =>  13
            )
        [1] =>  Array (
                [year] =>  2009
                [posts] =>  37
            )
        [2] =>  Array (
                [year] =>  2008
                [posts] =>  9
            )
    ) 

Aby wyniki wyświetlić w postaci czytelniejszej dla człowieka,
rozwiązaniem jest zastosowanie pętli przeprowadzającej iterację przez
tablicę $results, np. w następujący sposób:

    <?php
    foreach( $results as $sum ) {
        $year  = $sum['year'];
        $count = $sum['posts'];
        echo "<p>Liczba wpisów bloga opublikowanych w roku $year wynosi: $count</p>";
    }
    ?> 

------------------------------------------------------------------------

Uwaga

Dobrym nawykiem jest używanie polecenia SELECT do pobierania jedynie
potrzebnych informacji i unikanie stosowania leniwego polecenia w
postaci SELECT * FROM. Ograniczenie zapytania jedynie do wymaganych pól
pomaga w zmniejszeniu obciążenia bazy danych i redukuje zużycie pamięci.

------------------------------------------------------------------------

Ma to szczególne znaczenie w środowiskach współdzielonych, w których w
tym samym czasie setki innych procesów może pobierać lub zapisywać dane
w bazie danych. Umiejętność minimalizacji obciążenia bazy danych
gwarantuje, że Twoja wtyczka nie będzie obwiniana o nadmierne zużywanie
zasobów.

Dowolne zapytania

Oczywiście, najczęściej stosowane metody obiektu $wpdb nie ograniczają
się jedynie do poleceń SELECT. Za pomocą metody query() można
przetworzyć dowolne zapytanie. Wartością zwrotną jest false w przypadku
wystąpienia błędu lub liczba całkowita wskazująca liczbę rekordów,
których dotyczyło zapytanie.

Przykładowo poniższy kod powoduje usunięcie wszystkich komentarzy z
bloga, jeśli prowadzą na niepożądaną witrynę internetową:

    <?php
    $sql = "DELETE from wp_comments
            WHERE comment_author_url
            LIKE '%wroga.witryna.pl%'";
    $deleted = $wpdb->query( $sql );
    ?> 

Po wykonaniu powyższego kodu wartością zmiennej $deleted będzie false w
przypadku wystąpienia błędu (np.. w sytuacji, gdy prefiksem tabeli nie
jest wp_, co powoduje, że wskazana w zapytaniu tabela wp_comments nie
istnieje) lub liczba całkowita określająca liczbę usuniętych rekordów.

Istnieje również możliwość użycia metody query(), gdy trzeba zachować
większą elastyczność składni i parametrów. W tym praktycznym przykładzie
kod powoduje zablokowanie możliwości dodawania komentarzy we wszystkich
wpisach bloga starszych niż 90 dni.

    <?php
    $sql = "UPDATE $wpdb->posts
            SET comment_status = 'closed'
            WHERE post_date < DATE_SUB( NOW(), INTERVAL 90 DAY )
            AND post_status = 'publish'";
    $wpdb->query( $sql );
    ?> 

I teraz ostatni przykład — wyobraź sobie, że Twój przyjaciel i
jednocześnie częsty komentator Twojego bloga zmienił adres URL swojego
bloga. Przy użyciu przedstawionego poniżej pojedynczego zapytania możesz
uaktualnić jego wszystkie komentarze i zmienić podany przez niego
wcześniej adres URL na aktualny:

    <?php
    $sql = "UPDATE $wpdb->comments
            SET comment_author_url =
            REPLACE( comment_author_url, 'http://starawitryna/', 'http://nowawitryna/' )";
    $wpdb->query( $sql );
    ?> 

Ochrona zapytań przed atakami typu SQL Injection

Być może zauważyłeś, że przedstawione powyżej przykładowe zapytania nie
były oczyszczane. To nie było konieczne, ponieważ zapytania były na
stałe umieszczone w kodzie i nie zawierały żadnych dynamicznych i
potencjalnie niebezpiecznych danych.

Kiedy trzeba przygotować własne dynamiczne zapytanie, w którym nie można
na stałe zapisać każdego komponentu, wówczas przed wykonaniem takiego
zapytania konieczne jest jego oczyszczanie za pomocą funkcji esc_sql().
Ten krok można przeprowadzić za pomocą metody prepare(), która zezwala
na użycie tego samego ścisłego formatu weryfikacji, tak jak w metodach
insert() i update().

Proces sprowadza się do dwóch kroków:

1.  Przygotowanie zapytania SQL za pomocą metody prepare(), której
    wartością zwrotną jest oczyszczone polecenie.
2.  Wykonanie zapytania zawierającego przygotowane polecenie przy użyciu
    jednej z wcześniej omówionych metod.

W jaki sposób można np. pobrać tytuły wszystkich wpisów bloga
utworzonych we wskazanym miesiącu przez autora o podanym
identyfikatorze? Zapytanie SQL do pobrania tego rodzaju danych może być
podobne do poniższego:

    SELECT `post_title`
        FROM $wpdb->posts
        WHERE `post_author` = 1
        AND post_status = 'publish'
        AND post_type = 'post'
        AND DATE_FORMAT( `post_date`, '%Y-%m' ) = '2010-11' 

Teraz można zdefiniować ogólne zapytanie SQL wraz z miejscami
zarezerwowanymi:

    <?php
    $sql = "SELECT `post_title`
            FROM $wpdb->posts
            WHERE `post_author` = %d
            AND post_status = 'publish'
            AND post_type = 'post'
            AND DATE_FORMAT( `post_date`, '%%Y-%%m') = %s ";
    ?> 

Powyższy fragment kodu można potraktować jako szablon zapytania, w
którym %d oznacza liczbę całkowitą, a %s — ciąg tekstowy. Warto zwrócić
uwagę na poprzedzenie znaków % drugim znakiem % (%%) oraz na brak
konieczności stosowania apostrofów wokół zdefiniowanych miejsc
zarezerwowanych.

Teraz można "przygotować" zapytanie i je przetworzyć. Poniżej podano
gotowe zapytanie pobierające wszystkie tytuły wpisów bloga utworzone w
listopadzie 2010 roku przez autora o identyfikatorze 1:

    <?php
    $id = 1;
    $month = '2010-11'
    $safe_sql = $wpdb->prepare( $sql, $id, $month );
    $posts = $wpdb->get_results( $safe_sql );
    ?> 

Metoda prepare() pobiera dowolną liczbę parametrów. Pierwszym parametrem
jest szablon polecenia SQL wraz z miejscami zarezerwowanymi. Po nim
znajduje się dowolna liczba parametrów zawierających wartości do
umieszczenia w zdefiniowanych miejscach zarezerwowanych. Wspomniane
wartości mogą być podane pojedynczo lub zgrupowane w tablicy. Ważne jest
tutaj, aby wartości przekazywać w takiej samej kolejności, w jakiej w
zapytaniu zdefiniowano odpowiadające im miejsca zarezerwowane. To
przypomina użycie funkcji PHP o nazwie printf().

Po użyciu funkcji var_dump() względem wynikowej zmiennej $posts jej
zawartość może być podobna do przedstawionej poniżej:

    array(3) {
      [0]=> 
      object(stdClass)#251 (1) {
        ["post_title"] => string(30) "Święto Odzyskania Niepodległości minęło,
           zbliża się Boże Narodzenie"
      }
      [1]=> 
      object(stdClass)#250 (1) {
        ["post_title"] => string(25) "Wszystkiego najlepszego Michale!"
      }
      [2]=> 
      object(stdClass)#249 (1) {
        ["post_title"] => string(27) "Wyrzuciłem mojego maka i kupiłem PC"
      } 

Różne metody i właściwości obiektu wpdb

Obiekt $wpdb zawiera jeszcze kilka metod i właściwości, których można
używać, zwłaszcza podczas procesu usuwania błędów.

Włączenie wyświetlania błędów

Istnieje możliwość włączenia i wyłączenia wyświetlania błędów:

    <?php
    // Włączenie:
    $wpdb->show_errors();
    // Wyłączenie:
    $wpdb->hide_errors();
    ?> 

Za pomocą metody print_error() lub właściwości last_error można
wyświetlić błąd (o ile taki wystąpił) wygenerowany przez ostatnio
wykonane zapytanie:

    <?php
    echo $wpdb->last_error;
    $wpdb->print_error();
    ?> 

Więcej podpowiedzi dotyczących procesu usuwania błędów znajduje się w
rozdziale 16.

Śledzenie liczby zapytań

Zmienna num_queries klasy wpdb przechowuje liczbę wykonanych zapytań. Tę
samą informację można otrzymać także w wyniku wywołania funkcji
get_num_queries(). I znów więcej informacji na ten temat znajduje się w
rozdziale 16., który jest poświęcony tematowi usuwania błędów i
optymalizacji kodu.

Inne zmienne klasy

W tabeli 6.2 wymieniono listę innych wartych poznania zmiennych klasy
wpdb oraz podano przechowywane przez nie informacje.

Tabela 6.2. Niektóre zmienne klasy wpdb

  ---------------------- ------------------------------------------------------------------------------------
  Zmienna                Przechowywane informacje
  $wpdb->insert_id       Identyfikator wygenerowany dla kolumny AUTO_INCREMENT w ostatnim zapytaniu INSERT.
  $wpdb->num_rows        Liczba rekordów zwróconych przez ostatnio wykonane zapytanie.
  $wpdb->rows_affected   Liczba rekordów, których dotyczyło ostatnio wykonane zapytanie.
  ---------------------- ------------------------------------------------------------------------------------

Dobre nawyki bezpieczeństwa

Bezpieczeństwo to delikatna materia obejmująca projektowanie,
przemyślenie projektu i jego ogólną koncepcję. Wszystkie informacje
przedstawione w tym rozdziale mogą Ci pomóc, w rozdziale opisano też
odpowiednie narzędzia, ale to Ty sam musisz wyrobić sobie kilka dobrych
nawyków.

-   Zawsze próbuj włamać się do tworzonej wtyczki i znaleźć nielegalne,
    diabelskie oraz złośliwe sposoby wykorzystania utworzonego kodu. Nie
    zapomnij także o rozważeniu najgłupszych sposobów użycia wtyczki.
    Niektórzy użytkownicy w ogóle nie czytają dokumentacji, podobnie jak
    niektórzy programiści piszą kiepską i niejasną dokumentację. Nie
    przyjmuj założenia, że użytkownicy zawsze będą robili to, czego od
    nich oczekujesz.
-   Kwestie bezpieczeństwa przemyśl już na samym początku prac nad
    projektem. Jeżeli nie zaprojektujesz wtyczki z uwzględnieniem jej
    bezpieczeństwa, z góry będziesz skazany na usuwanie wcześniej czy
    później odkrytych w niej luk w zabezpieczeniach.
-   Programiści tworzący platformę WordPress poważnie podchodzą do jej
    bezpieczeństwa. Po odkryciu i potwierdzeniu istnienia luki w
    zabezpieczeniach zwykle w przeciągu godzin wydawana jest nowa,
    poprawiona wersja oprogramowania. Jednak twórcy nie zapewniają
    obsługi starszych wersji WordPress. Z tego powodu upewnij się, że
    używasz najnowszej i przez to najbezpieczniejszej wersji platformy.
    Tworzenie wtyczek przy użyciu porzuconych wtyczek bądź API naraża
    Twój produkt na istnienie luk w zabezpieczeniach.
-   Programiści tworzący platformę WordPress poważnie podchodzą do jej
    bezpieczeństwa, ponieważ wiedzą, że nie jest doskonała. Jeżeli w
    trakcie pracy z kodem WordPress znajdziesz nową lukę w
    zabezpieczeniach, przyczyń się do usprawnienia platformy. Zrób to w
    etyczny sposób: nie ujawniaj publicznie znalezionej luki, ale zgłoś
    problem na adres security@wordpress.com.
-   Niektóre funkcje omówione w rozdziale są całkiem nowe. Jeżeli prace
    nad wtyczkami dla WordPress rozpocząłeś wiele lat temu i nie
    uaktualniałeś ich na bieżąco zgodnie z usprawnieniami wprowadzonymi
    w ostatnich wersjach WordPress, teraz jest dobry moment na powrót do
    wcześniej utworzonych wtyczek i poprawienie ich kodu.
-   Twórz dokumentację kodu. W przyszłości, gdy powrócisz do kodu
    wtyczki utworzonego wiele miesięcy wcześniej, podziękujesz sobie za
    ten krok. W ten sposób ułatwiasz sobie obsługę kodu, a także
    szybciej możesz zauważyć słabe punkty w zabezpieczeniach.
-   Bądź otwarty w stosunku do społeczności użytkowników i nie ignoruj
    ich. Reaguj na pojawiające się informacje o lukach w
    zabezpieczeniach, to przecież żaden wstyd. Szybko usuwaj luki i
    informuj o tym publicznie, zachęcając tym samym użytkowników do
    uaktualnienia wtyczki.
-   Wszystkie dynamiczne dane zawsze uznawaj za niebezpieczne.

------------------------------------------------------------------------

Uwaga

Złotą regułę dotyczącą bezpieczeństwa, wyrażoną słowami Marka Jaquitha
(głównego programisty platformy WordPress i eksperta z zakresu
bezpieczeństwa), można podsumować następująco: wszystko to, co nie jest
na stałe zapisane w kodzie, jest podejrzane.

------------------------------------------------------------------------

Wprawdzie nie ma oficjalnego zespołu platformy WordPress
przeprowadzającego audyt z zakresu bezpieczeństwa wtyczek, który mógłby
Ci pomóc w poprawieniu kodu bądź weryfikacji wtyczki, to jednak nie
oznacza, że jesteś pozostawiony sam sobie. Publiczne wydanie wtyczki i
zaangażowanie się w społeczność platformy WordPress może skutkować
nawiązaniem kontaktu nie tylko z jej użytkownikami, ale również z
programistami pracującymi nad samą platformą. Społeczność WordPress to
także odpowiednie miejsce na zasugerowanie innym programistom
wprowadzenia określonych poprawek. Więcej informacji na ten temat
znajduje się w rozdziale 17.

Podsumowanie

Ważna informacja, którą należy zapamiętać z lektury tego rozdziału
brzmi: zapewnienie bezpieczeństwa wtyczkom WordPress nie jest wcale
takie trudne. Do tego celu służą wygodne funkcje przeznaczone do obsługi
wielu różnych aspektów bezpieczeństwa.

Najważniejsza reguła do zapamiętania brzmi: zawsze sprawdzaj zarówno
dane wejściowe, jak i wyjściowe. Obejmują one miejsca, w których
użytkownicy mogą przesłać dane do serwera (adresy URL, pola formularzy,
pliki cookies itd.) oraz miejsca odsyłania danych do użytkownika (dane
wyjściowe wyświetlane w przeglądarce internetowej). Każdy rodzaj
interakcji pomiędzy użytkownikiem i witryną internetową jest z natury
zarówno niebezpieczny, jak i łatwy do zabezpieczenia.

Rozdział 7 Ustawienia wtyczki

W tym rozdziale:

-   Używanie bazy danych WordPress do zapisywania i pobierania danych
-   Wykorzystanie funkcji API do tworzenia zwięzłego i niezawodnego kodu
-   Zapisywanie opcji globalnych oraz opcji dla poszczególnych
    użytkowników
-   Zapisywanie specjalnego typu opcji, czyli opcji wygasających
-   Tworzenie własnej tabeli bazy danych: kiedy oraz w jakim celu

Platforma WordPress pozwala na bardzo łatwe uzyskanie dostępu do bazy
danych w celu przechowywania i pobierania danych, takich jak opcje,
które użytkownicy mogą modyfikować i zapisywać na stronach ustawień.
Inny rodzaj danych przechowywanych w bazie danych to wewnętrzne
informacje wymagane do działania wtyczki. Czytając ten rozdział, dowiesz
się, jak zapisywać i pobierać te dane za pomocą wewnętrznych funkcji
WordPress oraz API.

API Options

API Options to zestaw funkcji pozwalających na łatwe uzyskanie dostępu
do bazy danych, w której platforma WordPress, wtyczki i motywy zapisują
(oraz z której pobierają) wymagane informacje.

Opcje są przechowywane w tabeli bazy danych standardowo nazwanej
wp_options i mogą być w postaci tekstu, liczb całkowitych, tablic lub
obiektów. Przykładowo w wymienionej tabeli platforma WordPress
przechowuje tytuł bloga, listę aktywnych wtyczek, nowości wyświetlane w
kokpicie oraz datę określającą, kiedy należy sprawdzić dostępność nowej
wersji.

W tym rozdziale dowiesz się, w jaki sposób używać funkcji pozwalających
na uzyskanie dostępu, uaktualnienie i zapisywanie opcji, takich jak
add_option(), update_option(), get_option() oraz delete_option().

Zapisywanie opcji

Na początek zapiszemy pierwszą opcję o nazwie boj_myplugin_color, której
wartością będzie red. Funkcja wykonująca takie zadanie ma następującą
postać:

    <?php
    add_option( 'boj_myplugin_color', 'red' );
    ?> 

Pierwszym parametrem jest nazwa opcji. Znaczenie krytyczne ma tutaj jej
unikalność, ponadto jej przeznaczenie nie powinno budzić wątpliwości.

-   Unikalność — nazwa nigdy nie powinna kolidować z wewnętrzną
    istniejącą lub przyszłą opcją platformy WordPress albo ustawieniami,
    które mogą być tworzone przez inne wtyczki.
-   Jasne przeznaczenie — nazwa powinna jasno pokazywać, że dana opcja
    jest ustawieniem wtyczki, a nie została utworzona przez WordPress.

------------------------------------------------------------------------

Uwaga

Używanie tego samego prefiksu, np. boj_myplugin w nazwach funkcji, opcji
i zmiennych jest gorąco zalecane, ponieważ pozwala na zachowanie
spójności kodu, a także chroni przed konfliktami z innymi wtyczkami.
Złota reguła "zawsze stosuj prefiks", wprowadzona po raz pierwszy w
rozdziale 2., tutaj również ma zastosowanie.

------------------------------------------------------------------------

Drugim parametrem jest wartość opcji; praktycznie to dowolna wartość,
którą może przechowywać zmienna, czyli ciąg tekstowy, liczba całkowita,
liczba zmiennoprzecinkowa, wartość boolowska, obiekt lub tablica.

Uaktualnienie opcji odbywa się przy użyciu podobnego wywołania funkcji:

    <?php
    update_option( 'boj_myplugin_color', 'blue' );
    ?> 

Różnica pomiędzy funkcjami add_option() i update_option() polega na tym,
że pierwsza funkcja nie podejmuje żadnego działania, jeśli opcja o
podanej nazwie już istnieje. Natomiast update_option() przed
uaktualnieniem wartości najpierw sprawdza, czy opcja już istnieje, i
tworzy ją, gdy wystąpi taka konieczność.

Zapisywanie tablicy opcji

Każda zapisana opcja dodaje nowy rekord w tabeli opcji platformy
WordPress. Istnieje możliwość jednorazowego zapisania większej liczby
opcji za pomocą tablicy. W ten sposób unika się nadmiernego obciążania
bazy danych, a operacja uaktualnienia wartości następuje w ramach
pojedynczego zapytania MySQL, co wiąże się z większą efektywnością i
szybkością operacji.

    <?php
    $options = array(
        'color'    => 'red',
        'fontsize' => '120%',    
        'border'   => '2px solid red'
    );
    update_option( 'boj_myplugin_options', $options );
    ?> 

Zapisywanie opcji wtyczki w jednej tablicy zamiast w pojedynczych
rekordach może mieć ogromny wpływ na czas wczytywania platformy
WordPress, zwłaszcza w przypadku zapisywania lub uaktualniania wielu
opcji. W większości przypadków kod PHP jest wykonywany szybko, natomiast
zapytania SQL zwykle wpływają na zmniejszenie wydajności, więc należy
ich unikać, gdy tylko istnieje taka możliwość.

Pobieranie opcji

Aby pobrać wartość opcji z bazy danych, należy użyć funkcji
get_option():

    <?php
    $myplugin_color = get_option( 'boj_myplugin_color' );
    ?> 

Jeżeli opcja nie istnieje, wówczas wartością zwrotną funkcji
get_option() będzie false. Ponadto, kiedy przechowywana jest wartości
boolowska, wartością zwrotną wymienionej funkcji będzie liczba
całkowita.

Oto przykład takiego zachowania. Spójrz na przedstawiony poniżej
fragment kodu, który tworzy kilka nowych opcji przy użyciu zmiennych
różnego typu:

    <?php
    update_option( 'test_bool_true',  true );
    update_option( 'test_bool_false', false );
    ?> 

Teraz można utworzyć kod pobierający te opcje wraz z nieistniejącą i
przekonać się, jakie typy zmiennych (wymienione w wierszu komentarza tuż
pod wywołaniem funkcji get_option()) zostaną zwrócone:

    <?php
    var_dump( get_option( 'nonexistent_option' ) );
    // bool(false)
    var_dump( get_option( 'test_bool_true' ) );
    // string(1) "1"
    var_dump( get_option( 'test_bool_false' ) );
    // bool(false)
    ?> 

W celu uniknięcia błędów podczas sprawdzania wartości opcji, true i
false należy przechowywać jako odpowiednio 1 i 0. Oznacza to możliwość
przeprowadzenia ścisłego porównania wartości zwrotnej funkcji
get_option() z wartością false i przekonanie się, czy dana opcja
istnieje:

    <?php
    if( get_option( 'boj_myplugin_someoption' ) === false ) {
        // Opcja nie została jeszcze zdefiniowana.
        // ...
    } else {
        // Opcja istnieje.
        // ...
    }
    ?> 

Istnieje również możliwość wskazania wartości, która powinna być
zwrócona, jeśli dana opcja nie zostanie znaleziona w bazie danych. Do
tego służy drugi parametr funkcji get_option():

    <?php
    $option = get_option( 'boj_myplugin_option', 'wartość, gdy opcja nie zostanie znaleziona' );
    ?> 

Wczytywanie tablicy opcji

Dowiedziałeś się już, że zapisanie wielu opcji w pojedynczej tablicy
jest najlepszym rozwiązaniem. Poniżej przedstawiono pełny przykład
zapisania, a następnie pobrania wartości z pojedynczej tablicy:

    <?php
    // Wszystkie opcje zostają zapisane za pomocą pojedynczego wywołania funkcji:
    $myplugin_options = array(
        'color'    => 'red',
        'fontsize' => '120%',
        'border'   => '2px solid red'
    );
    update_option( 'boj_myplugin_options', $myplugin_options ) ;
    // Teraz poszczególne wartości zostają pobrane również za pomocą pojedynczego wywołania funkcji:
    $options  = get_option( 'boj_myplugin_options' );
    $color    = $options[ 'color' ];
    $fontsize = $options[ 'fontsize' ];
    $border   = $options[ 'border' ];
    ?> 

Zapisywanie i pobieranie opcji umieszczonych w tablicy ma jeszcze jedną
zaletę: zmienne typu boolowskiego w tablicy zostają zachowane. Spójrz na
przedstawiony poniżej fragment kodu:

    <?php
    add_option( 'test_bool', array(
        'booltrue'  => true,
        'boolfalse' => false
        )
    );
    ?> 

Teraz wartości opcji zostają pobrane z bazy danych za pomocą wywołania
funkcji var_dump( get_option( 'test_bool' ) ).

    // Dane wyjściowe po wywołaniu funkcji var_dump(get_option('test_bool')).
    array(2) {
      ["booltrue"] => bool(true)
      ["boolfalse"]=> bool(false)
    } 

Usuwanie opcji

Usunięcie opcji odbywa się poprzez wywołanie funkcji delete_option():

    <?php
    delete_option( 'boj_myplugin_options' );
    ?>

Wartościami zwrotnymi wymienionej funkcji są true lub false, jeśli nie
można znaleźć opcji przeznaczonej do usunięcia. Opcje są najczęściej
usuwane w funkcjach dezinstalacji wtyczki (zobacz rozdział 2.).

Parametr autoload

Domyślnie wszystkie opcje przechowywane w bazie danych są pobierane za
pomocą pojedynczego zapytania SQL podczas inicjalizacji platformy
WordPress, a następnie buforowane. Dotyczy to wewnętrznych ustawień
jądra platformy WordPress oraz opcji utworzonych i przechowywanych przez
wtyczki.

To jest bardzo efektywne rozwiązanie: niezależnie od liczby wydanych
wywołań funkcji get_option() we wtyczce, nie powodują one wykonania
dodatkowych zapytań SQL, a tym samym spowolnienia całej witryny.
Potencjalną wadą techniki automatycznego wczytywania jest to, że rzadko
używane opcje zawsze są wczytywane do pamięci, nawet gdy nie ma takiej
potrzeby. Przykładowo nie ma konieczności pobierania wewnętrznych opcji
kodu, gdy czytelnik uzyskuje dostęp do wpisu bloga.

W celu rozwiązania tego problemu podczas zapisywania opcji po raz
pierwszy można określić jej parametr autoload, jak to zrobiono w
poniższym przykładzie:

    <?php
    add_option( 'boj_myplugin_option', $value, '', $autoload );
    ?> 

Warto zwrócić uwagę na pusty trzeci parametr — został on porzucony kilka
wersji wcześniej i nie jest już dłużej potrzebny. Mimo wszystko, należy
się upewnić, że nie zostanie pominięty.

Nas interesuje czwarty parametr. Jeżeli wartość parametru $autoload jest
inna niż no (lub po prostu nie jest ustawiona), opcja
boj_myplugin_option będzie odczytana podczas uruchamiania platformy
WordPress, a kolejne wywołania funkcji get_option() nie spowodują
wykonania żadnego dodatkowego zapytania SQL. Ustawienie parametrowi
$autoload wartości no można wyjaśnić następująco: opcja ta nie będzie
wczytywana podczas uruchamiania platformy WordPress; w ten sposób
przyczyniamy się do oszczędzania pamięci i skrócenia czasu inicjalizacji
platformy. Jednak w takim przypadku pierwsze odwołanie się do wartości
tej opcji w kodzie spowoduje wykonanie dodatkowego zapytania SQL.

------------------------------------------------------------------------

Uwaga

Jeżeli chcesz podać parametr autoload, w trakcie pierwszego tworzenia
opcji musisz użyć funkcji add_option() zamiast update_option(). Jeśli
natomiast nie potrzebujesz wymienionego parametru, wtedy zawsze używaj
funkcji update_option() zarówno do tworzenia, jak i uaktualniania
wartości opcji. W ten sposób kod będzie prostszy i spójniejszy.

------------------------------------------------------------------------

Oczywiście, określenie parametru autoload po utworzeniu opcji nie
zmienia sposobu, w jaki pobierasz, uaktualniasz lub usuwasz jej wartość.

Rozdzielanie opcji wtyczki

Funkcja służąca do inicjalizacji opcji wtyczki i wywoływana podczas jej
aktywacji, tak jak opisano w rozdziale 2., może przedstawiać się
następująco:

    <?php
    function boj_myplugin_create_options() {
        // Opcje interfejsu: wczytywane automatycznie.
        add_option( 'boj_myplugin_options', array(
            'color'    => 'red',
            'fontsize' => '120%',
            'border'   => '2px solid red'
        );
        // Opcje kodu wewnętrznego: wczytywane, jeśli trzeba.
        add_option( 'boj_myplugin_admin_options', array(
            'version'    => '1.0',
            'donate_url' => 'http://x.y/z/',
            'advanced_options' => '1'
        ), '', 'no' );
    }
    ?> 

Warto przypomnieć ponownie, że nie należy zapominać o pustym trzecim
parametrze tuż przed wartością autoload. To może się wydawać nieco
zagmatwane i rzeczywiście tak jest w przypadku ustawiania niewielkiej
liczby opcji. Jednak ta profesjonalna technika ma sens, jeśli tworzona
wtyczka ma dziesiątki opcji lub gdy opcje zawierają długie ciągi
tekstowe.

------------------------------------------------------------------------

Uwaga

Jeżeli opcje muszą zaliczać się do publicznej części bloga, warto
tworzyć je wraz z parametrem autoload. Gdy natomiast dotyczą jedynie
obszaru administracyjnego, wtedy trzeba tworzyć je bez parametru
autoload.

------------------------------------------------------------------------

Włączanie i wyłączanie parametru autoload

Parametr autoload jest ustawiany, gdy opcja jest tworzona za pomocą
funkcji add_option(), i nie jest przeznaczony do późniejszej zmiany.
Jeżeli jesteś przekonany, że efektywność wtyczki można poprawić poprzez
zmianę wartości parametru autoload, modyfikację można przeprowadzić
bardzo łatwo. W tym celu wystarczy po prostu usunąć, a następnie
ponownie utworzyć opcję wraz ze zdefiniowanym stanem parametru autoload:

    <?php
    function boj_myplugin_recreate_options() {
        // Pobranie starej wartości.
        $old = get_option( 'boj_myplugin_admin_options' );
        // Usunięcie opcji, a następnie jej ponowne utworzenie z wyłączonym parametrem autoload.
        delete_option( 'boj_myplugin_admin_options' );
        add_option( 'boj_myplugin_admin_options', $old, '', 'no' );
    }
    ?> 

API Settings

Opcje mogą być wewnętrznie tworzone i uaktualniane przez wtyczkę
(przykładowo przechowywanie znacznika czasu kolejnej iteracji
procedury). Jednak bardzo często są używane do przechowywania ustawień
modyfikowanych przez użytkownika za pośrednictwem strony
administracyjnej wtyczki.

Podczas tworzenia lub uaktualniania zdefiniowanych przez użytkownika
opcji wtyczki z wykorzystaniem API Settings tworzony kod może być
zarówno prostszy, jak i znacznie efektywniejszy.

Zalety API Settings

Obsługa danych wejściowych użytkownika wprowadza nowe ograniczenia w
procesie opcji: trzeba przygotować interfejs użytkownika, monitorować
wysyłanie formularzy, zająć się kwestiami bezpieczeństwa oraz
weryfikacją danych użytkownika. W celu ułatwienia zarządzania
wymienionymi zadaniami platforma WordPress opakowuje funkcje opcji
wygodnym i kompletnym API Settings.

API Settings pozwala na obsługę prostych zadań. Oto one.

-   Poinformowanie platformy WordPress, że będą używane nowe opcje oraz
    określenie sposobu ich wyświetlenia.
-   Wskazanie funkcji odpowiedzialnej za oczyszczanie danych wejściowych
    użytkownika.

Ponadto API Settings umożliwia platformie WordPress zarządzanie
uciążliwymi i nieustannie powtarzającymi się czynnościami, takimi jak:

-   samodzielne generowanie większości strony opcji;
-   monitorowanie wysyłania formularzy i obsługa danych $_POST;
-   tworzenie i uaktualnienie opcji, jeśli trzeba;
-   zarządzanie wymaganymi środkami bezpieczeństwa oraz ukrytymi polami
    formularzy zawierającymi unikalne identyfikatory, co zostało
    dokładnie omówione w rozdziale 6.

Teraz możemy przystąpić do szczegółowej analizy API Settings. Dowiesz
się, jak z niego korzystać na podstawie dokładnych przykładów, krok po
kroku.

Funkcje API Settings

Funkcje API Settings wykonują trzy zadania.

1.  Najpierw informują platformę WordPress o nowych ustawieniach,
    którymi ma zarządzać. W ten sposób ustawienia zostają dodane do
    listy autoryzowanych opcji (to tzw. technika białej listy).
2.  Następnie definiują ustawienia (elementy typu pole tekstu, pole
    tekstowe i dowolny element formularza HTML) oraz wizualny sposób ich
    pogrupowania w sekcjach.
3.  Na końcu nakazują platformie WordPress wyświetlenia ustawień w
    rzeczywistym formularzu.

Pierwszym krokiem jest jednak określenie w danej wtyczce strony
zarządzania ustawieniami.

Utworzenie strony administracyjnej dla wtyczki

Strona wtyczki będzie miała adres
/wp-admin/options-general.php?page=boj_myplugin:

    <?php
    // Dodanie strony administracyjnej z opcjami.
    add_action('admin_menu', 'boj_myplugin_add_page');
    function boj_myplugin_add_page() {
        add_options_page( 'Moja wtyczka', 'Moja wtyczka', 'manage_options',
            'boj_myplugin', 'boj_myplugin_options_page' );
    }
    // Wygenerowanie strony z opcjami.
    function boj_myplugin_options_page() {
        ?> 
    <div class="wrap"> 
    <?php screen_icon(); ?> 
    <h2>Moja wtyczka</h2> 
    <form action="options.php" method="post"> 
    </form></div> 
    <?php
    }
    ?> 

Na tym etapie strona jest jeszcze pusta (zobacz rysunek 7.1). Wkrótce
zostaną do niej dodane opcje.

[]

Rysunek 7.1. Pusta strona administracyjna, na której znajdą się opcje
wtyczki

Temat tworzenia stron dla wtyczek został szczegółowo omówiony w
rozdziale 4. W przypadku wątpliwości dotyczących przedstawionego powyżej
kodu warto powrócić do tego rozdziału.

Rejestracja nowych ustawień

Do rejestracji nowych ustawień używana jest funkcja register_setting(),
która — jak pokazano poniżej — pobiera trzy parametry:

    <?php
    register_setting(
        'boj_myplugin_options',
        'boj_myplugin_options',
        'boj_myplugin_validate_options'
    );
    ?> 

Pierwszy parametr to nazwa grupy ustawień, drugi to nazwa opcji, która
będzie użyta w wywołaniu funkcji get_option(). Nazwa grupy może być
dowolna, ale prościej nadać jej taką samą nazwę jak opcji przechowywanej
w bazie danych.

Trzeci parametr to opcjonalna funkcja wywołania zwrotnego. To po prostu
ciąg tekstowy odwołujący się do funkcji (w omawianym przykładzie
boj_myplugin_validate_options()), który będzie przekazany wszystkim
opcjom zapisanym w formularzu. Funkcja ta zostanie zdefiniowana później.

Zdefiniowanie sekcji i ustawień

Teraz można przystąpić do dokładniejszego zdefiniowania ustawień za
pomocą funkcji add_settings_field() oraz do ich wizualnego grupowania z
wykorzystaniem funkcji add_settings_ section():

    <?php
    add_settings_section(
        'boj_myplugin_main',
        'Ustawienia wtyczki',
        'boj_myplugin_section_text',
        'boj_myplugin'
    );
    add_settings_field(
        'boj_myplugin_text_string',
        'Podaj dowolny tekst',
        'boj_myplugin_setting_input',
        'boj_myplugin',
        'boj_myplugin_main'
    );
    ?> 

Wywołanie pierwszej funkcji (add_settings_section()) definiuje sposób
wyświetlenia sekcji na stronie. Funkcja wymaga podania czterech
parametrów. Oto one:

-   identyfikator znacznika HTML dla sekcji;
-   tytuł sekcji, który zostanie wyświetlony przez znacznik <h3>;
-   nazwa wywoływanej funkcji odpowiedzialnej za wyświetlenie pewnych
    informacji dodatkowych dotyczących sekcji;
-   strona ustawień, na której znajdzie się sekcja (tzn. część
    ?page=boj_myplugin adresu URL).

Wywołanie drugiej funkcji (add_settings_field()) opisuje sposób dodania
elementu do formularza. Ta funkcja wymaga podania pięciu parametrów,
takich jak:

-   identyfikator znacznika HTML dla sekcji;
-   tekst, który zostanie wyświetlony obok danego elementu;
-   nazwa wywoływanej funkcji odpowiedzialnej za wyświetlenie elementu
    formularza;
-   strona ustawień, na której znajdzie się sekcja;
-   zdefiniowana w wywołaniu funkcji add_settings_section() sekcja na
    stronie ustawień, w której ma się znaleźć dane pole ustawień.

Kolejny krok to zdefiniowanie dwóch wywoływanych funkcji: pierwsza
wyświetla informacje dodatkowe dotyczące sekcji, natomiast druga jest
odpowiedzialna za wyświetlenie i wypełnienie pola formularza.

    <?php
    // Informacje dodatkowe dotyczące danej sekcji.
    function boj_myplugin_section_text() {
        echo '<p>W tym miejscu zdefiniuj ustawienia.</p>';
    }
    // Wyświetlenie i wypełnienie pola formularza.
    function boj_myplugin_setting_input() {
        // Pobranie z bazy danych wartości opcji 'text_string'.
        $options = get_option( 'boj_myplugin_options' );
        $text_string = $options['text_string'];
        // Wyświetlenie pola formularza.
        echo "<input id='text_string' name='boj_myplugin_options[text_string]'
            type='text' value='{$options['text_string']}' />";
    }
    ?> 

Wywołanie drugiej funkcji pobiera wartość opcji text_string
przechowywanej w tablicy.

Podczas wyświetlania pola danych wejściowych w formularzu HTML trzeba
zwrócić uwagę na jego nazwę. Za jej pomocą przeglądarka internetowa jest
informowana, jaką wartość ma umieścić w tablicy podczas zapisywania
opcji. Powinna być taka sama jak zdefiniowana wcześniej w wywołaniu
funkcji register_setting(). Każde pole, które nie zostało wcześniej
zarejestrowane i umieszczone na białej liście, zostanie przez WordPress
zignorowane.

Weryfikacja danych wejściowych użytkownika

Do zdefiniowania została jeszcze jedna wywoływana funkcja o nazwie
boj_myplugin_validate_options(), wymieniona we wcześniejszej części
rozdziału podczas rejestracji ustawień.

W omawianym przykładzie użytkownik został poproszony o podanie dowolnego
tekstu, więc funkcja weryfikacji po prostu sprawdza, czy dane wejściowe
składają się jedynie z liter:

    <?php
    function boj_myplugin_validate_options( $input ) {
        $valid = array();
        $valid['text_string'] = preg_replace(
            '/[^a-zA-Z]/',
            '',
            $input['text_string'] );
        return $valid;
    }?> 

W celu weryfikacji, czy dane użytkownika składają się jedynie z liter,
zastosowano dopasowanie do prostego wzorca (tzw. wyrażenie regularne),
które powoduje usunięcie wszystkich znaków innych niż litery.

Funkcja jest przekazywana danym $_POST jako parametr. W celu zwiększenia
poziomu bezpieczeństwa na początku zostaje utworzona nowa, pusta tablica
o nazwie $valid, która następnie zostaje wypełniona tylko oczekiwanymi
wartościami. W ten sposób, jeżeli z jakiegokolwiek powodu w formularzu
zostało wysłane nieoczekiwane pole, funkcja nie tylko zweryfikuje tę
informację, ale również zablokuje wszystkie nieoczekiwane dane. Więcej
wskazówek i informacji dotyczących funkcji weryfikacji danych znajduje
się w rozdziale 6.

Wygenerowanie formularza

Po zdefiniowaniu funkcji można przystąpić do ich użycia. Na początku
całego procesu utworzyłeś pustą stronę. Teraz możesz umieścić na niej
pola i przycisk wysłania formularza.

    <?php
    // Wygenerowanie strony z opcjami.
    function boj_myplugin_options_page() {
        ?> 
    <div class="wrap"> 
    <?php screen_icon(); ?> 
    <h2>Moja wtyczka</h2> 
    <form action="options.php" method="post"> 
    <?php
        settings_fields('boj_myplugin_options');
        do_settings_sections('boj_myplugin');
        ?> 
    <input name="Submit" type="submit" value="Zapisz zmiany" /> 
    </form></div> 
    <?php
    }?> 

Wywołanie funkcji settings_fields() odwołuje się do opcji z białej
listy, które zostały zdefiniowane za pomocą funkcji register_setting().
Funkcja zajmuje się obsługą ukrytych pól formularza, zapewnieniem
bezpieczeństwa oraz przekierowaniem formularza po jego wysłaniu.

Wywołanie drugiej funkcji — do_settings_sections() — powoduje
wyświetlenie wszystkich sekcji oraz wcześniej zdefiniowanych pól
formularza.

Wszystko gotowe!

Warto zwrócić uwagę, jak mała ilość kodu HTML została wykorzystana, a
mimo to strona wtyczki jest kompletna i w pełni funkcjonalna. Głównym
tego powodem jest niezawodność API Settings — Ty, jako programista, masz
się skoncentrować na funkcjach, a platformie WordPress pozostawić
zadanie utworzenia całego kodu HTML z odpowiednimi znacznikami i klasami
oraz obsługę wysyłania danych i oczyszczenia ciągów tekstowych przed ich
umieszczeniem w bazie danych.

------------------------------------------------------------------------

Uwaga

Projektowanie stron wtyczki z użyciem API Settings jest niezawodną
techniką — wyobraź sobie, że tworzysz wtyczkę dla klienta przeznaczoną
dla konkretnej wersji WordPress. Później, gdy interfejs administracyjny
platformy WordPress ulega zmianie (inny układ, kolory, klasy HTML),
utworzona przez Ciebie wtyczka nadal bez problemów integruje się z
platformą, a wszystko dlatego, że nie umieściłeś w niej na stałe kodu
HTML.

------------------------------------------------------------------------

Zebranie całości: pełna strona zarządzania wtyczką

Niektóre użyte tutaj wywołania funkcji muszą być zarejestrowane dla
odpowiednich zaczepów akcji WordPress, np. admin_init. Poniżej
przedstawiono pełny kod źródłowy wtyczki, której budowę właśnie
omówiono.

    <?php
    /*
    Plugin Name: Przykład API Settings
    Plugin URI: http://przyklad.pl/
    Description: Pełny i praktyczny przykład użycia API Settings.
    Author: WROX
    Author URI: http://wrox.com
    */
    // Dodanie menu dla strony opcji.
    add_action('admin_menu', 'boj_myplugin_add_page');
    function boj_myplugin_add_page() {
        add_options_page( 'Moja wtyczka', 'Moja wtyczka', 'manage_options',
            'boj_myplugin', 'boj_myplugin_option_page'
        );
    }
    // Wygenerowanie strony z opcjami.
    function boj_myplugin_option_page() {
        ?> 
    <div class="wrap"> 
    <?php screen_icon(); ?> 
    <h2>Moja wtyczka</h2> 
    <form action="options.php" method="post"> 
    <?php settings_fields('boj_myplugin_options'); ?> 
    <?php do_settings_sections('boj_myplugin'); ?> 
    <input name="Submit" type="submit" value="Zapisz zamiany" /> 
    </form></div> 
    <?php
    }
    // Zarejestrowanie i zdefiniowanie ustawień.
    add_action('admin_init', 'boj_myplugin_admin_init');
    function boj_myplugin_admin_init(){
        register_setting( 'boj_myplugin_options', 'boj_myplugin_options',
            'boj_myplugin_validate_options' );
        add_settings_section( 'boj_myplugin_main', 'Ustawienia wtyczki',
            'boj_myplugin_section_text', 'boj_myplugin' );
        add_settings_field( 'boj_myplugin_text_string', 'Podaj dowolny tekst',
            'boj_myplugin_setting_input', 'boj_myplugin', 'boj_myplugin_main' );
    }
    // Wygenerowanie nagłówka sekcji.
    function boj_myplugin_section_text() {
        echo '<p>W tym miejscu zdefiniuj ustawienia.</p>';
    }
    // Wyświetlenie i wypełnienie pola formularza.
    function boj_myplugin_setting_input() {
        // Pobranie z bazy danych wartości opcji 'text_string'.
        $options = get_option( 'boj_myplugin_options' );
        $text_string = $options['text_string'];
        // Wyświetlenie pola formularza.
        echo "<input id='text_string' name='boj_myplugin_options[text_string]'
            type='text' value='$text_string' />";
    }
    // Weryfikacja danych wejściowych użytkownika (dozwolone jest podanie jedynie tekstu).
    function boj_myplugin_validate_options( $input ) {
        $valid = array();
        $valid['text_string'] = preg_replace(
            '/[^a-zA-Z]/',
            '',
            $input['text_string'] );
        return $valid;
    }?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin1-standalone-page.php.

------------------------------------------------------------------------

Po aktywacji wtyczki przejdź na jej stronę
/wp-admin/options-general.php?page=boj_myplugin. W przeglądarce
internetowej powinien zostać wyświetlony interfejs podobny do pokazanego
na rysunku 7.2.

[]

Rysunek 7.2. Gotowa strona ustawień wtyczki

Usprawnienie reakcji funkcji i weryfikacja błędów

Zdefiniowana wcześniej funkcja weryfikująca może być nieco usprawniona i
informować użytkowników o wprowadzeniu przez nich nieoczekiwanej
wartości. W ten sposób użytkownik zwróci uwagę na wprowadzane dane
wejściowe i być może je poprawi.

Tutaj z pomocą przychodzi stosunkowo mało znana funkcja API Settings o
nazwie add_settings_ error(). Funkcja ta jest używana w następujący
sposób:

    <?php
    add_settings_error(
       'boj_myplugin_text_string',
       'boj_myplugin_texterror',
       'Wprowadzono nieprawidłową wartość!',
       'error'
    );
    ?> 

Zdefiniowania powyżej funkcja rejestruje komunikat błędu wyświetlany
użytkownikowi. Pierwszym parametrem jest tytuł ustawienia, którego
dotyczy komunikat błędu. Drugi parametr to identyfikator znacznika HTML.
Następnie znajduje się właściwy komunikat błędu, który platforma
WordPress opakuje odpowiednimi znacznikami <div> i <p>. Ostatni parametr
to klasa HTML; do wyboru mamy error lub update.

Funkcję weryfikującą można usprawnić następująco:

    <?php
    function boj_myplugin_validate_options( $input ) {
        $valid['text_string'] = preg_replace( 
            '/[^a-zA-Z]/',
            '',
            $input['text_string'] );
        if( $valid['text_string'] != $input['text_string'] ) {
            add_settings_error(
                'boj_myplugin_text_string',
                'boj_myplugin_texterror',
                'Wprowadzono nieprawidłową wartość!',
                'error'
            );
        }
        return $valid;
    }
    ?> 

Funkcja w tej postaci porównuje zweryfikowane dane z początkowymi danymi
wejściowymi i jeśli się różnią, wyświetla komunikat błędu (zobacz
rysunek 7.3).

[]

Rysunek 7.3. Usprawniona funkcja weryfikująca w działaniu

Dodawanie pól na istniejącej stronie

Dowiedziałeś się już, w jaki sposób utworzyć kompletną stronę ustawień
dla wtyczki oraz powiązanego z nią elementu w menu administracyjnym.
Takie rozwiązanie ma sens, gdy wtyczka zawiera wiele ustawień, a jej
strona administracyjna wyświetla większą ilość treści.

Jednak czasami po prostu nie warto dodawać elementu menu dla pojedynczej
opcji bądź jedynie kilku opcji wtyczki. Także w tej sytuacji API
Settings okazuje się użyteczne i pozwala na łatwe umieszczenie pól z
ustawieniami wtyczki na istniejącej stronie ustawień WordPress.

Jak to działa?

W celu wygenerowania sekcji i pól, które zostały wcześniej
zarejestrowane, używane są dwie wewnętrzne funkcje:
do_settings_sections() i do_settings_fields(). Zostały one użyte we
wcześniej omówionym przykładzie wtyczki.

Każda strona ustawień platformy WordPress wywołuje obie wymienione
funkcje, więc możesz i Ty.

Dodawanie sekcji na istniejącej stronie

W poprzednio omówionym przykładzie wtyczki dodano całą nową sekcję i jej
pole tekstowe jako samodzielną stronę. Teraz przedstawiony będzie kod
pozwalający na wstawienie tych samych danych na stronie
Ustawienia/Prywatność.

    <?php
    function boj_myplugin_admin_init(){
        register_setting(
            'privacy',
            'boj_myplugin_options',
            'boj_myplugin_validate_options'
        );
        add_settings_section(
            'boj_myplugin_options',
            'Ustawienia wtyczki',
            'boj_myplugin_section_text',
            'privacy'
        );
        add_settings_field(
            'boj_myplugin_text_string',
            'Podaj dowolny tekst',
            'boj_myplugin_setting_input',
            'privacy',
            'boj_myplugin_options'
        );
    }
    ?> 

Przedstawiony powyżej kod wtyczki powoduje umieszczenie własnej sekcji w
sekcji privacy, która jest umieszczona na stronie Ustawienia/Prywatność
(zobacz rysunek 7.4). Po zastąpieniu wszystkich wystąpień privacy słowem
media Twoja sekcja zostanie umieszczona na stronie Ustawienia/Media.

Za pomocą funkcji register_setting()trzeba ustawienie to umieścić na
białej liście. Pominięcie tego kroku spowoduje, że WordPress zignoruje
ustawienie podczas wysyłania danych formularza.

Dodawanie jedynie pól

Oczywiście, czasami sensowne będzie dodanie na istniejącej stronie po
prostu pojedynczego pola bez sekcji nagłówka. W tym celu przedstawioną
wcześniej funkcję należy następująco zmodyfikować:

    <?php
    function boj_myplugin_admin_init(){
        register_setting(
            'privacy',
            'boj_myplugin_options',
            'boj_myplugin_validate_options'
        );
        add_settings_field(
            'boj_myplugin_text_string',
            'Podaj dowolny tekst',
            'boj_myplugin_setting_input',
            'privacy',
            'default'

[]

Rysunek 7.4. Umieszczenie własnej sekcji na istniejącej stronie

        );
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin2-add-to-page.php.

------------------------------------------------------------------------

Pojedyncze pole zostanie dodane do zbioru pól default sekcji privacy,
jak pokazano na rysunku 7.5.

[]

Rysunek 7.5. Dodanie pojedynczego pola na istniejącej stronie

Sekcja WordPress i pola ustawień

W celu dodania sekcji na istniejącej stronie lub pola do istniejącej
sekcji trzeba jedynie znać nazwę strony. W tabeli 7.1 wymieniono nazwy
wszystkich sekcji i zbiorów pól używanych na stronach Ustawienia na
platformie WordPress 3.0.

Tabela 7.1. Lista podstawowych sekcji i pól używanych na stronach
Ustawienia platformy WordPress

+-----------------------+-----------------------+-----------------------+
| Strona Ustawienia     | Nazwy sekcji          | Nazwy zbiorów pól     |
| platformy WordPress   |                       |                       |
+-----------------------+-----------------------+-----------------------+
| Ogólne                | general               | default               |
| (options-general.php) |                       |                       |
+-----------------------+-----------------------+-----------------------+
| Pisanie               | writing               | default               |
| (options-writing.php) |                       | remote_publishing     |
|                       |                       | post_via_email        |
+-----------------------+-----------------------+-----------------------+
| Czytanie              | reading               | default               |
| (options-reading.php) |                       |                       |
+-----------------------+-----------------------+-----------------------+
| Dyskusja              | discussion            | default               |
| (op                   |                       | avatars               |
| tions-discussion.php) |                       |                       |
+-----------------------+-----------------------+-----------------------+
| Media                 | media                 | default               |
| (options-media.php)   |                       | embeds                |
|                       |                       | uploads               |
+-----------------------+-----------------------+-----------------------+
| Prywatność            | privacy               | default               |
| (options-privacy.php) |                       |                       |
+-----------------------+-----------------------+-----------------------+
| Bezpośrednie          | permalink             | optional              |
| odnośniki             |                       |                       |
| (o                    |                       |                       |
| ptions-permalink.php) |                       |                       |
+-----------------------+-----------------------+-----------------------+

Rozważania dotyczące interfejsu użytkownika

Decyzja o umieszczeniu ustawień wtyczki na oddzielnej stronie bądź ich
dołączeniu na istniejącej stronie WordPress to bardzo często kwestia
wyboru odpowiedniego interfejsu użytkownika dla właściwego użytkownika
końcowego.

Podczas pracy nad witryną dla klienta prawdopodobnie koncentrujesz się
na dostarczeniu niezawodnego rozwiązania z zakresu CMS, a nie na
wyjaśnianiu, czym jest WordPress oraz jak wtyczki mogą rozbudować
możliwości oferowane przez platformę. Umieszczenie ustawień Twojej
wtyczki na stronie Ustawienia platformy może zwiększyć poziom integracji
wtyczki z platformą, ponieważ wówczas ustawienia wtyczki nie różnią się
od ustawień WordPress. Z punktu widzenia klienta tworzona przez Ciebie
wtyczka jest standardowym elementem platformy WordPress, podobnie jak
wtyczki wbudowane.

Jeśli jednak wtyczka jest przeznaczona do swobodnego pobierania, jej
użytkownicy prawdopodobnie rozumieją koncepcję dodawania nowych funkcji
do podstawowych oferowanych przez WordPress. Ci użytkownicy z reguły
będą oczekiwali istnienia oddzielnego menu prowadzącego na stronę, na
której mogą zarządzać wtyczką. Jeżeli wolisz dodawać pola na
istniejących stronach, upewnij się o wyraźnym poinformowaniu
użytkowników o tym fakcie, np. w dokumentacji wtyczki.

API Transients

Czasami trzeba przechowywać w bazie danych zmienne wartości. Przykładowo
wyobraź sobie wtyczkę pobierającą nazwę piosenki aktualnie odtwarzanej
na witrynie internetowego radia. Ogólnie rzecz biorąc, takie dane "żyją"
bardzo krótko i najczęściej zmieniają się co kilka minut.

Aby zachować efektywność i uniknąć zbyt częstego wykonywania zapytań do
internetowego radia, tego rodzaju wtyczka może pobrać tytuł piosenki i
przechowywać przez kilka minut, a następnie sprawdzić, czy jest już
dostępny nowy tytuł.

API Transients oferuje prosty sposób tymczasowego przechowywania
buforowanych danych w bazie danych. API jest podobne do API Options i
powoduje dodanie atrybutu określającego czas utraty ważności. Po upływie
zdefiniowanego czasu opcja zostanie uznana za nieważną i usunięta.

API Transients wykorzystuje trzy funkcje: set_transient(),
get_transient() i delete_transient(). W tym podrozdziale nauczysz się z
nich korzystać.

Zapisywanie opcji, która ma utracić ważność

Wyobraź sobie, że wtyczka określiła tytuł piosenki aktualnie odtwarzanej
na witrynie internetowego radia: to "I Heart WordPress" wykonywana przez
sławny fikcyjny zespół WROX Hackers. Poniżej przedstawiono sposób
zapisania tej informacji, która pozostanie ważna przez trzy minuty:

    <?php
    set_transient( 'boj_myplugin_song', 'I Heart WordPress', 180 );
    ?> 

Podobieństwo do funkcji add_option() jest oczywiste: na początku
znajduje się nazwa krótkotrwałych danych, następnie ich wartość. Kluczem
jest tutaj trzeci parametr wskazujący liczbę sekund ważności tych
danych.

Pobieranie opcji, która ma utracić ważność

Podczas każdego żądania strony wtyczka może teraz pobrać zapisane
krótkotrwałe dane:

    <?php
    $song = get_transient( 'boj_myplugin_song' );
    ?> 

Zachowanie funkcji get_transient() jest następujące:

-   jeżeli dane istnieją i są ważne, wartością zwrotną jest true;
-   jeżeli dane utraciły ważność lub nigdy nie zostały ustawione,
    wartością zwrotną jest false.

Usunięcie opcji, która utraciła ważność

Aby ręcznie usunąć krótkotrwałe dane, należy użyć funkcji
delete_transient():

    <?php
    delete_transient( 'boj_myplugin_song' );
    ?> 

Po pomyślnym usunięciu danych wartością zwrotną funkcji będzie true, w
przeciwnym razie, np. jeśli danych nie można znaleźć w bazie danych,
wartością zwrotną będzie false.

Używanie krótkotrwałych nie powoduje zaśmiecenia bazy danych, ponieważ
dane, które utraciły ważność, są automatycznie usuwane w trakcie próby
pobrania ich wartości. Zwykle ta funkcja nie jest używana, wyjątkiem
jest procedura dezinstalacji wtyczki.

Praktyczny przykład użycia krótkotrwałych danych

Poniżej przedstawiono kod źródłowy omawianej wtyczki, która pobiera
tytuł piosenki.

    <?php
    // Pobranie z internetowego radia tytułu aktualnie odtwarzanej piosenki.
    function boj_myplugin_fetch_song_title_from_radio() {
        // ... kod pobierający dane ze zdalnej witryny internetowej.
        return $title;
    }
    // Pobranie tytułu piosenki z bazy danych i ustawienie jej czasu ważności na trzy minuty.
    function boj_myplugin_get_song_title() {
        // Pobranie krótkotrwałej wartości.
        $title = get_transient( 'boj_myplugin_song' );
        // Jeżeli krótkotrwała wartość nie istnieje lub utraciła ważność, należy ją odświeżyć.
        if( false === $title ) {
            $title = boj_myplugin_fetch_song_title_from_radio();
            set_transient( 'boj_myplugin_song', $title, 180 );
        }
        return $title;
    }?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin3-transients.php.

------------------------------------------------------------------------

Funkcja boj_myplugin_fetch_song_title_from_radio() działa następująco:

-   pobiera dane z zewnętrznej witryny internetowego radia;
-   przetwarza pobrane dane w celu wyodrębnienia tytułu aktualnie
    odtwarzanej piosenki;
-   zwraca wyodrębniony tytuł piosenki.

Omówienie wymienionych zadań wykracza poza zakres tematyczny tego
rozdziału, ale zostały przedstawione w rozdziale 9., który jest
poświęcony tematowi żądań HTTP.

Funkcja boj_myplugin_fetch_song_title_from_radio() to kompletny przykład
pokazujący użycie funkcji API Transients: pobranie krótkotrwałej
wartości i jeśli funkcja zwróci false, wówczas następuje odświeżenie
wartości i jej przywrócenie.

Szczegółowe informacje techniczne

Przy krótkotrwałych danych, ze względu na ich naturę, korzystne jest
stosowanie buforowania, podczas gdy w zwykłych opcjach już tak nie jest.
Przykładowo w serwerach wykorzystujących memcached (system buforowania)
po dodaniu wtyczki memcached wartości krótkotrwałe platforma WordPress
będzie przechowywała w szybkiej pamięci, a nie w bazie danych. Z tego
powodu nigdy nie należy przyjmować założenia, że krótkotrwałe dane
znajdują się w bazie danych, ponieważ one w ogóle mogą nie być
przechowywane.

Idea krótkotrwałych danych

Za każdym razem, gdy trzeba przechowywać dane, które istnieją przez
krótki okres czasu, należy prawdopodobnie korzystać z krótkotrwałych
danych. Poniżej przedstawiono kilka przykładowych zadań lub funkcji
wtyczek, w których doskonale sprawdzi się API Transients:

-   blog korporacji, na którym klienci będą wyświetlać bieżącą wartość
    ich udziałów;
-   aktualna liczba przyjaciół w profilu Facebook;
-   ostatnia wiadomość utworzona i opublikowana w serwisie Twitter;
-   ostatni artykuł pobrany z kanału RSS.

Zapisywanie ustawień poszczególnych użytkowników

Wtyczki za pomocą większej ilości opcji dają użytkownikom platformy
WordPress jeszcze większą kontrolę nad ich witrynami internetowymi.
Wtyczka zwykle dodaje w menu Ustawienia swoją stronę, na której można
modyfikować jej opcje i tym samym dostosować zachowanie platformy do
własnych potrzeb.

Istnieją sytuacje, w których tego rodzaju implementacja (tzn. wpływ na
zachowanie całej instalacji WordPress) nie jest idealnym rozwiązaniem.
Przykładowo w pojedynczej witrynie internetowej z wieloma użytkownikami
może wystąpić potrzeba zezwolenia na stosowanie ustawień dla
poszczególnych użytkowników zamiast opcji globalnych.

Tworzenie wtyczki

Wyobraź sobie, że Twój nowy klient to firma zatrudniająca pracowników
posługujących się językiem zarówno polskim, jak i angielskim. Twoim
zadaniem jest opracowanie systemu CMS (oczywiście, na bazie WordPress)
działającego w intranecie i umożliwienie użytkownikom wyboru języka, w
którym ma być wyświetlany interfejs WordPress.

Przy zastosowaniu wcześniej wymienionych konwencji nazw wtyczka może
nosić nazwę BOJ Admin Lang i korzystać z prefiksu boj_adminlang. Ucząc
się, jak używać funkcji wymaganych do zapisywania i pobierania ustawień
dla poszczególnych użytkowników, możesz zbudować tego rodzaju wtyczkę.

Metadane użytkownika

Dane dotyczące użytkowników są zapisywane w dwóch miejscach bazy danych
WordPress.

-   Podstawowe informacje (imię i nazwisko, adres e-mail, data
    rejestracji i hasło) używane głównie przez proces logowania są
    przechowywane w tabeli wp_users.
-   Metainformacje, tzn. inny rodzaj informacji o użytkowniku
    (biografia, preferencje edytora wizualnego itd.) znajdują się w
    tabeli wp_usermeta.

Tabela metadanych użytkownika została zaprojektowana do przechowywania
wszelkich informacji powiązanych z użytkownikiem i może być łatwo
rozbudowana. Do uzyskania dostępu oraz podczas pracy z rekordami
wymienionej tabeli można zastosować funkcje: add_user_meta(),
update_user_meta(), get_user_meta() i delete_user_meta().

Cztery funkcje są podobne do istniejących w API Options, ale z
interesującą różnicą: umożliwiają one powielanie danych.

Zapisywanie metadanych użytkownika

Wywołanie funkcji odpowiedzialnej za zapisanie metadanych użytkownika ma
następującą składnię:

    <?php
    add_user_meta( $user_id, $meta_key, $meta_value, $unique );
    ?> 

Parametry:

-   $user_id — w tabeli użytkowników sami użytkownicy są identyfikowani
    za pomocą identyfikatorów. Pobieranie identyfikatora użytkownika
    będzie pokazane w dalszej części rozdziału.
-   $meta_key i $meta_value — to jest para metadanych: nazwa i wartość,
    podobnie jak w poprzednio omówionych funkcjach, np. add_option().
-   $unique — opcjonalna wartość boolowska. Jeżeli przyjmie wartość
    true, danemu użytkownikowi nie można dodać kilku metadanych o takiej
    samej nazwie. Wartością domyślną jest false, co oznacza, że jeśli
    nie zostanie określone inaczej, istnieje możliwość powielenia kluczy
    metadanych. W celu zachowania przejrzystości kodu zaleca się, aby
    nie pomijać tego parametru.

Różne typy poprzednio omówionych opcji muszą być unikalne, ale wiele
metadanych dla danego użytkownika może mieć ten sam klucz. To ma sens w
niektórych sytuacjach, kiedy przykładowo użytkownik może przechowywać
informacje o wielu posiadanych książkach:

    <?php
    add_user_meta( 3, 'books', 'Profesjonalny WordPress', false);
    add_user_meta( 3, 'books', 'Uwielbiam WP', false);
    ?> 

W zależności od kontekstu sensowne może być również wyraźne wskazanie,
że dany klucz metadanych musi być unikalny. Wróćmy do wtyczki BOJ Admin
Lang: przechowywanie wybranego przez użytkownika języka interfejsu to
przykład ustawienia, które nie może mieć wielu wartości:

    <?php
    add_user_meta( 3, 'boj_adminlang_lang', 'pl_PL', true );
    ?> 

Powyższy fragment kodu to informacja, że użytkownik trzeci chce, aby
interfejs użytkownika został przetłumaczony na język polski przy użyciu
ustawień lokalnych dla pl_PL (więcej informacji dotyczących ustawień
lokalnych znajduje się w rozdziale 5.).

Uaktualnianie metadanych użytkownika

Składnia funkcji update_user_meta() jest następująca:

    <?php
    update_user_meta( $user_id, $meta_key, $meta_value, $prev_value );
    ?> 

Pierwsze trzy parametry powinny już być znane. Natomiast czwarty
parametr, jeśli zostanie podany, wskazuje dane przeznaczone do
uaktualnienia. W przypadku jego pominięcia uaktualnione będą wszystkie
metadane $meta_key użytkownika.

W poprzednim przykładzie dla użytkownika trzeciego zapisano dwa tytuły
książek. Poniższe polecenie powoduje uaktualnienie drugiego tytułu
książki i zastąpienie WP słowem WordPress:

    <?php
    update_user_meta( 3, 'books', 'Uwielbiam WordPress', 'Uwielbiam WP' );
    ?> 

Pominięcie czwartego parametru spowoduje uaktualnienie wszystkich
tytułów książek. Wróćmy teraz do wtyczki zapewniającej obsługę języków:
ponieważ klucz metadanych jest unikalny, nie trzeba stosować czwartego
parametru. Poniższy fragment kodu powoduje ustawienie pustej wartości
opcji wyboru języka interfejsu:

    <?php
    update_user_meta( 3, 'boj_adminlang_lang', '' );
    ?> 

Pobieranie metadanych użytkownika

Przed wyświetleniem interfejsu podczas wczytywania platformy WordPress
możemy za pomocą wtyczki sprawdzić, czy dla danego użytkownika istnieją
metadane określające język, który powinien być użyty. Zobaczmy więc,
jaki język preferuje trzeci użytkownik:

    <?php
    $lang = get_user_meta( 3, 'boj_adminlang_lang', true );
    ?> 

Pierwszy i drugi parametr to identyfikator użytkownika i klucz
metadanych. Znaczenie trzeciego parametru nie jest już taki oczywiste:
to wartość boolowska wskazująca, czy wartość zwrotna ma być pojedyncza
(true), czy w postaci tablicy (false).

Wtyczka przechowuje unikalne metadane o nazwie boj_adminlang_lang, więc
jako ciąg tekstu ma być pobrana ta unikalna wartość. Aby pobrać listę
książek z poprzedniego przykładu, trzeci parametr powinien mieć wartość
false, co spowoduje zwrot tablicy. (Wynik wywołania funkcji został
przedstawiony w wierszu komentarza tuż po wierszu wywołania funkcji).

    <?php
    $book = get_user_meta( 3, 'books', false );
    // array( 'Profesjonalny WordPress', 'Uwielbiam WordPress' );
    ?> 

Usunięcie metadanych użytkownika

Ostatnią funkcją, którą należy poznać, jest delete_user_meta().
Wartością zwrotną wymienionej funkcji jest true po pomyślnym usunięciu
metadanych oraz false w przeciwnym przypadku (gdy np. klucz metadanych
nie zostanie znaleziony w bazie danych). Składnia funkcji jest
następująca:

    <?php
    delete_user_meta( $user_id, $meta_key, $meta_value )
    ?> 

Rekordy można dopasować jedynie na podstawie klucza lub na podstawie
klucza i wartości, co pozwala na obsługę wielokrotnie użytych kluczy
metadanych. Kiedy wiadomo, że klucz metadanych jest unikalny, można
pominąć trzeci parametr:

    <?php
    delete_user_meta( 3, 'boj_adminlang_lang' );
    ?> 

Kiedy klucz metadanych nie jest unikalny, jak ma to miejsce w
przykładzie dotyczącym tytułów książek, można wskazać rekord do
usunięcia lub po prostu usunąć wszystkie o określonym kluczu:

    <?php
    // Usunięcie jednego rekordu:
    delete_user_meta( 3, 'books', 'Uwielbiam WordPress' );
    // Usunięcie wszystkich rekordów:
    delete_user_meta( 3, 'books' );
    ?> 

Pobieranie identyfikatora użytkownika

Wcześniej spotkałeś się z wyrażeniem "identyfikator użytkownika", a w
przykładach używałeś identyfikatora o wartości 3. W jaki sposób można
pobrać identyfikator użytkownika?

Niektóre akcje i filtry na platformie WordPress przekazują jako argument
identyfikator bieżącego użytkownika, o czym mogłeś się przekonać,
budując poprzednią wtyczkę zupełnie od początku. Jeżeli identyfikator
bieżącego użytkownika jest nieznany, należy użyć poniższego kodu:

    <?php
    $user = wp_get_current_user();
    $userid = $user->ID;
    ?> 

W powyższym fragmencie kodu $user staje się obiektem zawierającym
wszystkie znane dane bieżącego użytkownika, takie jak nazwa używana
podczas logowania, adres e-mail, uprawnienia w obszarze
administracyjnym, preferencje edytora wizualnego, metadane itd. Jedną z
właściwości jest ID (identyfikator); wartością tej właściwości jest
liczba całkowita będąca identyfikatorem użytkownika.

Dodawanie pól na stronie profilu

Ponieważ ustawienia będą przechowywane dla poszczególnych użytkowników,
nie ma sensu tworzenie globalnej strony opcji wtyczki. Pola opcji można
przecież dodać na stronie profilu użytkownika. Strony profilu wywołują
wiele akcji, które można wykorzystać w celu umieszczenia na nich swojej
treści:

-   personal_options — dodaje treść na końcu sekcji Personalizacja;
-   profile_personal_options — dodaje treść za sekcją Personalizacja;
-   show_user_profile — dodaje treść przed przyciskiem Zaktualizuj
    profil.

Przedstawiony poniżej kod powoduje dodanie rozwijanego menu
pozwalającego w sekcji Personalizacja wybrać język — polski lub
angielski:

    <?php
    // Dodanie i wypełnienie dodatkowego pola danych wejściowych w profilu użytkownika.
    function boj_adminlang_display_field( $user ) {
        $userid = $user->ID;
        $lang = get_user_meta( $userid, 'boj_adminlang_lang', true );
        ?> 
        <tr> 
            <th scope="row">Język</th> 
            <td> 
            <select name="boj_adminlang_lang" > 
            <option value=""
                <?php selected( '', $lang); ?> >angielski</option> 
            <option value="es_ES"
                <?php selected( 'pl_PL', $lang); ?> >polski</option> 
            </select> 
            </td> 
        </tr> 
        <?php
    }
    // Wywołanie funkcji w zaczepie akcji 'personal_options'.
    add_action( 'personal_options', 'boj_adminlang_display_field' );
    ?> 

Zaczep akcji personal_options przekazuje funkcję
boj_adminlang_display_field() obiektowi użytkownika. Funkcja pobiera
identyfikator użytkownika, z metadanych — preferencje użytkownika
dotyczące języka interfejsu, a następnie generuje kod HTML, który dodaje
opcję we wskazanej sekcji (zobacz rysunek 7.6).

[]

Rysunek 7.6. Dodanie opcji w sekcji na stronie profilu użytkownika

W dodanym polu wykorzystano funkcję WordPress o nazwie selected() do
automatycznego zaznaczenia odpowiedniej opcji na podstawie wyboru
wcześniej dokonanego przez użytkownika.

Na stronach profilu trzeba monitorować wysłanie formularza i sprawdzać,
czy użytkownik wprowadził jakiekolwiek własne metadane. W tym celu można
wykorzystać zaczep akcji personal_options_update i sprawdzić dane
$_POST:

    <?php
    // Monitorowanie wysłania formularza i uaktualnienie ustawień użytkownika w odpowiedni sposób.
    function boj_adminlang_update_field( $userid ) {
        if( isset( $_POST['boj_adminlang_lang'] ) ) {
            $lang = $_POST['boj_adminlang_lang'] == 'pl_PL' ? 'pl_PL' : '';
            update_user_meta( $userid, 'boj_adminlang_lang', $lang );
        }
    }
    add_action( 'personal_options_update', 'boj_adminlang_update_field' );
    ?> 

Na tym kończy się praca nad widoczną częścią wtyczki: opcją wyświetlaną
na stronie profilu każdego użytkownika i powodującą zapis wybranego
ustawienia.

Warto zwrócić uwagę na użycie operatora trójargumentowego, który pozwala
na skrócenie kodu. Poniższy pojedynczy wiersz:

    <?php
    $lang = $_POST['boj_adminlang_lang'] == 'pl_PL' ? 'pl_PL' : '';
    ?> 

odpowiada dłuższej strukturze:

    <?php
    if( $_POST['boj_adminlang_lang'] == 'pl_PL' ) {
        $lang = 'pl_PL';
    } else {
        $lang = '';
    }
    ?> 

Wtyczka BOJ Admin Lang

Pozostało już tylko upewnienie się, że obszar administracyjny został
przetłumaczony zgodnie z wyborem dokonanym przez użytkownika. Kiedy
platforma WordPress "musi wiedzieć", którego języka ma użyć, jej
wewnętrzna funkcja get_locale() zwraca ustawienia lokalne po
zastosowaniu filtra. W kodzie źródłowym WordPress plik
wp-includes/l10n.php zawiera następujący wiersz:

    <?php
    return apply_filters( 'locale', $locale );
    ?> 

Pozostało wykorzystanie wymienionego zaczepu akcji i pobranie ustawień
lokalnych przechowywanych w metadanych użytkownika. Poniżej
przedstawiono pełny kod źródłowy wtyczki wraz z jej nagłówkiem:

    <?php
    /*
    Plugin Name: Przykład ustawień dla poszczególnych użytkowników
    Plugin URI: http://przykład.pl/
    Description: Wtyczka pozwala na wybór języka używanego na stronach administracyjnych: angielski 
           ålub polski.
    Author: WROX
    Author URI: http://wrox.com
    */
    // Pobranie ustawień lokalnych użytkownika.
    function boj_adminlang_set_user_locale() {
        $user = wp_get_current_user();
        $userid = $user->ID;
        $locale = get_user_meta( $userid, 'boj_adminlang_lang', true );
        return $locale;
    }
    // Poniższa funkcja będzie wywołana za każdym razem, gdy platforma WP sprawdza wartość ustawień lokalnych.
    add_filter( 'locale', 'boj_adminlang_set_user_locale' );
    // Dodanie i wypełnienie dodatkowego pola danych wejściowych w profilu użytkownika.
    function boj_adminlang_display_field( $user ) {
        $userid = $user->ID;
        $lang = get_user_meta( $userid, 'boj_adminlang_lang', true );
        ?> 
        <tr> 
        <th scope="row">Język</th> 
            <td> 
            <select name="boj_adminlang_lang" > 
            <option value=""
                <?php selected( '', $lang); ?> >angielski</option> 
            <option value="es_ES"
                <?php selected( 'pl_PL', $lang); ?> >polski</option> 
            </select> 
            </td> 
        </tr> 
    <?php
    }
    add_action( 'personal_options', 'boj_adminlang_display_field' );
    // Monitorowanie wysłania formularza i uaktualnienie ustawień użytkownika w odpowiedni sposób.
    function boj_adminlang_update_field( $userid ) {
        if( isset( $_POST['boj_adminlang_lang'] ) ) {
            $lang = $_POST['boj_adminlang_lang'] == 'pl_PL' ? 'pl_PL' : '';
            update_user_meta( $userid, 'boj_adminlang_lang', $lang );
        }
    }
    add_action( 'personal_options_update', 'boj_adminlang_update_field' );
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin4-per-user-option.php.

------------------------------------------------------------------------

Po aktywacji wtyczki wybierz opcję "angielski" i… hurra, strony
administracyjne Twojego bloga są teraz wyświetlone w języku angielskim,
co pokazano na rysunku 7.7.

------------------------------------------------------------------------

Uwaga

Aby powyższa wtyczka funkcjonowała, instalacja platformy WordPress musi
zawierać pliki z polskim tłumaczeniem, które można pobrać z witryny
http://pl.wordpress.org/. Pliki pl_PL trzeba umieścić w katalogu
wp-content/languages (może wystąpić konieczność ręcznego utworzenia
wymienionego katalogu).

------------------------------------------------------------------------

Ustawienia dla poszczególnych użytkowników — najlepsze praktyki

Jeżeli chcesz, aby wtyczka przechowywała ustawienia dla poszczególnych
użytkowników, upewnij się, że charakteryzuje się następującymi cechami:

-   wizualnie jest doskonale zintegrowana z platformą WordPress;
-   jest solidnie zaimplementowana.

[]

Rysunek 7.7. Strony administracyjne bloga wyświetlone w języku
angielskim

Wizualna integracja. Ponieważ treść będzie umieszczana na stronach
profilu użytkownika, dodawana treść musi wizualnie pasować do
oryginalnego interfejsu platformy WordPress. Trzeba stosować poprawny
kod HTML i klasy, jak pokazano w przykładowej wtyczce. Ustawienia
wtyczki będą prezentowały się tak samo jak ustawienia platformy,
ponieważ nie tworzysz dodatkowej strony administracyjnej. Z tego powodu
bez zarzutu integrują się z WordPress.

Solidna implementacja. Czasami rozsądne jest utworzenie oddzielnej
strony opcji dla wtyczki bądź dodanie kilku opcji na stronie Ustawienia
platformy WordPress w postaci ustawień globalnych zamiast dla
poszczególnych użytkowników. Większość blogów WordPress to po prostu
blogi pojedynczych użytkowników, którzy niekoniecznie muszą przechodzić
na stronę profilu w celu sprawdzenia dostępności nowych ustawień.

Przechowywanie danych we własnych tabelach

Podczas lektury rozdziału dowiedziałeś się, jak przechowywać opcje
standardowe. Wiesz też, jak zarządzać opcjami standardowymi, opcjami
tracącymi ważność oraz metadanymi użytkownika. Platforma WordPress jest
dostarczana wraz z pewną liczbą tabel bazy danych; w większości
przypadków wszystko, co chcesz przechowywać, będzie idealnie pasowało do
udostępnianych tabel. Jednak nadal mogą zdarzać się sytuacje, w których
wystąpi konieczność utworzenia własnych tabel oraz zapisywania i
pobierania z nich danych.

Typy danych

Poniżej wymieniono dwa typy rekordów, które będziesz chciał
przechowywać:

-   informacje konfiguracyjne;
-   zebrane dane.

Informacje konfiguracyjne to najczęściej opcje wtyczki. Użytkownicy
konfigurują i zapisują pewne ustawienia po instalacji wtyczki.
Ustawienia można modyfikować w przyszłości, ale liczba rekordów w tabeli
nie ulega zmianie. Tego typu dane najlepiej przechowywać w tabeli opcji.

Zebrane dane to informacje dodawane przez użytkownika podczas używania
bloga. Te dane mogą być związane z wpisami bloga, komentarzami lub z
dowolnym komponentem platformy WordPress. Ilość takich danych będzie się
z czasem zwiększała i są one doskonałym kandydatem do umieszczania we
własnych tabelach.

Standardowe tabele WordPress

Platforma WordPress instaluje jedenaście tabel oraz wskazuje tabele
bardziej przeznaczone do przechowywania wielu danych użytkownika.
Poniżej wymieniono nazwy domyślne tabel:

-   wp_posts — zawartość witryny;
-   wp_postmeta — metadane dotyczące wpisów bloga;
-   wp_commentmeta — metadane komentarzy;
-   wp_usermeta — metadane dotyczące użytkowników;
-   wp_options — opcje.

W tabelach tych nie tylko można przechowywać praktycznie to wszystko, co
będziesz musiał zachować, oferują one także wygodne funkcje API
pozwalające na zapisywanie i pobieranie danych. Warto utworzyć
połączenie pomiędzy informacjami, które chcesz przechowywać, i tabelą
metadanych.

Czasami trzeba nieco inaczej spojrzeć, aby uzmysłowić sobie, że
określona tabela jest jak najbardziej odpowiednia do przechowywania
Twoich danych. Warto np. rozważyć tabelę wp_post wraz z przechowywanymi
własnymi menu, której prawdopodobnie w pierwszej chwili nie uznasz za
odpowiednią do przechowywania określonego typu wpisu bloga.

Warto podkreślić ponownie: w 99% przypadków tabele standardowe będą
wystarczające, w większości sytuacji dane będziesz przechowywał w tabeli
opcji.

Tworzenie własnej tabeli

Wyobraź sobie wtyczkę danych statystycznych przechowującą adres IP i
znacznik czasu każdego odwiedzającego blog. Tego rodzaju wtyczka będzie
wymagała użycia własnej tabeli z trzema kolumnami (zobacz tabela 7.2).

Tabela 7.2. Struktura tabeli i typy przechowywanych w niej danych

  --------------------------------- ---------------------- ----------
  HIT_ID                            HIT_IP                 HIT_DATE
  int(11) NOT NULL AUTO INCREMENT   varchar(100) NOT NUL   datetime
  --------------------------------- ---------------------- ----------

Polecenie SQL służące do utworzenia tabeli o powyższej strukturze
przedstawia się następująco:

    CREATE TABLE `wp_hits` (
        `hit_id` INT( 11 ) NOT NULL AUTO_INCREMENT,
        `chitin` VARCHAR( 100 ) NOT NULL ,
        `hit_date` DATETIME
    ); 

Teraz możesz wykorzystać wbudowaną funkcję WordPress o potężnych
możliwościach — dbDelta(). Funkcja nie jest domyślnie wczytywana, więc
trzeba ją ręcznie dołączyć we wtyczce. Następnie można przystąpić do
utworzenia własnej tabeli:

    <?php
    $tablename = $wpdb->prefix . "hits";
    $sql = "CREATE TABLE `$tablename` (
        `hit_id` INT( 11 ) NOT NULL AUTO_INCREMENT,
        `hit_ip` VARCHAR( 100 ) NOT NULL ,
        `hit_date` DATETIME
    );";
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
    ?> 

Powyższy kod wykonuje następujące zadania.

1.  Pobiera prefiks tabeli bazy danych i używa go podczas nadawania
    nazwy własnej tabeli.
2.  Definiuje polecenie SQL: każda kolumna w oddzielnym wierszu.
3.  Dołącza plik zawierający definicję funkcji dbDelta().
4.  Wywołuje tę funkcję.

------------------------------------------------------------------------

Uwaga

W pliku wp-config.php właściciel witryny bazującej na WordPress może
zdefiniować własny prefiks tabeli bazy danych; domyślnym jest wp_.
Podczas tworzenia własnej tabeli nie należy na sztywno podawać jej
pełnej nazwy, ale zawsze stosować wywołanie $wpdb->prefix.

------------------------------------------------------------------------

Sprawdzenie istnienia tabeli

Przed utworzeniem tabeli warto najpierw sprawdzić, czy taka tabela już
istnieje. W tym celu wynik wykonania polecenia SQL SHOW TABLE należy
porównać z rzeczywistą nazwą tabeli:

    <?php
    $tablename = $wpdb->prefix . "hits";
    if( $wpdb->get_var("SHOW TABLES LIKE '$tablename'") != $tablename ) {
        // Tabela nie istnieje!
    }
    ?> 

Funkcja dbDelta() sprawdza istnienie tabeli przed podjęciem próby jej
utworzenia bądź uaktualnienia. Samodzielne sprawdzanie ma sens np. w
celu określenia, czy wtyczka musi dołączyć niepotrzebny w innym
przypadku plik zawierający funkcje uaktualnienia tabeli.

Uaktualnienie struktury własnej tabeli

Prawdziwa potęga funkcji dbDelta() kryje się w możliwości uaktualnienia
tabeli przy użyciu tej samej składni, która została użyta podczas jej
tworzenia. Funkcja analizuje bieżącą strukturę tabeli i porównuje ją z
żądaną strukturą, a następnie — w zależności od potrzeb — dodaje lub
modyfikuje tabelę.

Dzięki temu kod jest łatwiejszy w utrzymaniu, bo instalacja i
uaktualnienie tabeli są przeprowadzane za pomocą tego samego wywołania
funkcji.

Wróćmy znów do naszej wtyczki zbierającej dane statystyczne: teraz można
dodać czwartą kolumnę przeznaczoną do przechowywania identyfikatora
wpisu bloga WordPress, który został wyświetlony przez użytkownika. Przy
okazji można usprawnić strukturę tabeli poprzez utworzenie klucza
podstawowego w pierwszej kolumnie hit_id.

Poniżej znajduje się pełny kod funkcji tworzącej lub uaktualniającej
tabelę:

    <?php
    // Tworzenie lub uaktualnienie własnej tabeli.
    function boj_hits_create_table() {
        global $wpdb;
        $tablename = $wpdb->prefix . "hits";
        $sql = "CREATE TABLE `$tablename` (
              `hit_id` int(11) NOT NULL AUTO_INCREMENT,
              `hit_ip` varchar(100) NOT NULL,
              `hit_date` datetime,
              `post_id` int(11) NOT NULL,
              PRIMARY KEY (`hit_id`)
            );";
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($sql);
    }
    ?> 

------------------------------------------------------------------------

Uwaga

Nie zapomnij o umieszczeniu w Twojej funkcji obiektu $wpdb z zasięgu
globalnego.

------------------------------------------------------------------------

Podpowiedzi dotyczące używania funkcji dbDelta()

Funkcja dbDelta() może być trudna w użyciu. Tolerancja bazy danych MySQL
dla błędów w składni lub danych szacunkowych jest ograniczona, podobnie
jak dbDelta(), która w zasadzie jest funkcją opakowującą. Czasami
wystarczy pojedyncza spacja (brakująca lub nadmiarowa), aby wywołanie
funkcji zakończyło się niepowodzeniem.

Obserwowanie składni i stylu poleceń SQL

Funkcja dbDelta() jest wrażliwa i wymaga starannego sformatowania
polecenia SQL:

-   każda kolumna powinna znajdować się we własnym wierszu polecenia
    SQL;
-   należy używać słowa kluczowego KEY zamiast jego synonimu INDEX;
-   nie należy stosować dodatkowych spacji pomiędzy słowami kluczowymi
    MySQL.

Najprostszym sposobem zagwarantowania starannego formatowania poleceń
SQL jest zaprojektowanie tabeli za pomocą narzędzia, takiego jak
phpMyAdmin (zobacz rozdział 18.), a następnie eksport przygotowanej
struktury tabeli, jak pokazano na rysunku 7.8. Tak wygenerowany kod SQL
będzie sformatowany w odpowiedni sposób do przyjęcia przez funkcję
dbDelta().

Sprawdzenie wartości zwrotnej w przygotowanym środowisku

W przypadku powodzenia lub niepowodzenia funkcja dbDelta() może nie
wyświetlić żadnego komunikatu, ale zwróci pewną cenną informację o
wyniku jej wywołania.

[]

Rysunek 7.8. Narzędzie phpMyAdmin wyświetlające strukturę tabeli hits

Utworzona przez Ciebie wtyczka nie może wyświetlać informacji procesu
usuwania błędów, ponieważ wystąpienie błędu o znaczeniu krytycznym
uniemożliwia aktywację wtyczki. Zamiast tego można bardzo łatwo
przygotować środowisko do testowania funkcji i przeglądania za pomocą
print_r() wyników wywołania funkcji dbDelta().

W katalogu głównym platformy WordPress utwórz pusty plik o nazwie
testsql.php i umieść w nim przedstawiony poniżej kod:

    <?php
    require('./wp-load.php');
    ?> 
    <pre> 
    <?php
    $wpdb->show_errors();
    $tablename = $wpdb->prefix . "hits";
    $sql = "CREATE TABLE `$tablename` (
        `hit_id` int(11) NOT NULL AUTO_INCREMENT,
        `hit_ip` varchar(100) NOT NULL,
        `hit_date` datetime,
        `post_id` int(11) NOT NULL,
        PRIMARY KEY (`hit_id`)
    );";
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    var_dump( dbDelta($sql) );
    $wpdb->print_error();
    ?> 
    </pre> 

Powyższy plik spowoduje wczytanie środowiska platformy WordPress, a
następnie uruchomi Twój testowany kod. W przeglądarce internetowej
trzeba podać adres prowadzący do utworzonego pliku (np.
http://przyklad.pl/testsql.php), co pozwoli na przejrzenie wyników w
postaci podobnej do poniższej:

    Array
    (
        [`wpb_hits`] => Created table `wpb_hits`
    ) 

Jeżeli polecenie SQL będzie nieprawidłowe, otrzymana tablica wynikowa
będzie pusta. Warto zwrócić uwagę na wyraźnie włączone na początku pliku
wyświetlanie błędów oraz wyświetlanie ostatniego błędu SQL, o ile taki
wystąpił.

Uruchomienie testowego polecenia SQL

Funkcja dbDelta() akceptuje dwa parametry: obowiązkowy w postaci
polecenia SQL oraz opcjonalny w postaci wartości boolowskiej, którego
wartość false może faktycznie uniemożliwić wykonanie polecenia SQL:

    <?php
    // Wykonanie polecenia i wyświetlenie jego wyników:
    var_dump( dbDelta( $sql ) );
    // Przetestowanie polecenia bez jego faktycznego wykonania i wyświetlenie wyników:
    var_dump( dbDelta( $sql, false ) );
    ?> 

W środowisku produkcyjnym (tzn. na witrynie klienta lub w udostępnionej
publicznie wtyczce) prawdopodobnie nigdy nie będziesz stosował opisanego
parametru opcjonalnego, ale jego użycie może być użyteczne podczas
procesu usuwania błędów w przedstawionym wcześniej środowisku testowym.

Uzyskanie dostępu do własnej tabeli

Po utworzeniu własnej tabeli można uzyskać do niej dostęp za pomocą
globalnego obiektu $wpdb. W przedstawionym poniżej fragmencie kodu
pokazano standardowe zapytanie SQL:

    <?php
    $tablename = $wpdb->prefix . "hits";
    // Wstawienie rekordu.
    $newdata = array(
        'hit_ip' => '127.0.0.1',
        'hit_date' => current_time( 'mysql' ),
        'post_id' => '123'
    );
    $wpdb->insert(
        $tablename,
        $newdata
    );
    // Uaktualnienie rekordu.
    $newdata = array( 'post_id' => '456' );
    $where   = array( 'post_id' => '123', 'hit_id' => 1 );
    $wpdb->update( $tablename, $newdata, $where );
    ?>

Szczegółowe omówienie sposobu używania klasy wpdb znajduje się w
rozdziale 6.

Podsumowanie

Zapisywanie danych to kluczowy krok podczas tworzenia wtyczek. Dzięki
temu wtyczki mogą być dostosowane do potrzeb użytkowników, którzy na
dodatek z radością powitają możliwość dostrojenia funkcji. Wykorzystanie
funkcji omówionych w rozdziale pozwala na łatwą integrację wtyczki z
platformą WordPress poprzez użycie efektywnego, zwięzłego i niezawodnego
kodu.

Rozdział 8 Użytkownicy

W tym rozdziale:

-   Praca z użytkownikami i funkcjami dotyczącymi użytkowników
-   Dodawanie, uaktualnianie i pobieranie danych użytkowników
-   Programowanie z uwzględnieniem ról i możliwości
-   Ograniczanie dostępu za pomocą uprawnień
-   Dostosowanie ról użytkowników

Kilka lat temu rozdział dotyczący użytkowników prawdopodobnie nie byłby
zbyt ekscytujący dla twórców wtyczek. W tym czasie platforma WordPress
była w dużej mierze używana wyłącznie do prowadzenia bloga, na którym
wpisy publikował jeden lub kilku użytkowników. Opracowywanie wtyczek
przeznaczonych do integracji z systemem użytkowników prawdopodobnie nie
przysporzyłoby twórcy zbyt dużej popularności w społeczności WordPress.

Obecnie platforma WordPress stanowi bazę dla wielu ogromnych witryn
internetowych wykorzystywanych przez tysiące, a nawet dziesiątki tysięcy
użytkowników. Wiedza z zakresu obsługi użytkowników przez WordPress jest
teraz ważnym narzędziem w arsenale każdego twórcy wtyczek. W dużej
ilości opracowywanych wtyczek będziesz musiał zajmować się wieloma
aspektami dotyczącymi użytkowników.

Aby opracować niezawodną i bezpieczną wtyczkę, prawdopodobnie
najważniejsze dla Ciebie będzie zrozumienie ról i możliwości systemu.
Wspomniane role i możliwości definiują to, co użytkownik może zrobić na
poszczególnych witrynach zbudowanych na bazie WordPress.

Użytkownicy wykorzystują platformę WordPress do tworzenia prywatnych
witryn komercyjnych, portali społecznościowych, internetowych czasopism,
medycznych baz danych, centrów edukacyjnych itd. Wszystkie te cele mogą
wymagać wtyczek zapewniających obsługę użytkowników i uprawnień. Podczas
tworzenia wtyczek dla wymienionego typu witryn internetowych bardzo
często konieczne jest użycie odpowiednich funkcji WordPress, aby
informacje poufne dotyczące użytkowników nie były wyświetlane osobom
nieupoważnionym.

W rozdziale zostaną omówione narzędzia przeznaczone do pracy z
użytkownikami WordPress, rolami i możliwościami systemu. Ponadto
przekonasz się, jak komponenty te współpracują ze sobą w środowisku
platformy WordPress.

Praca z użytkownikami

Na platformie WordPress użytkownikiem jest osoba, która zarejestrowała
unikalną nazwę użytkownika na danej witrynie. W ten sposób taki
użytkownik otrzymuje swoje konto w konkretnej instalacji WordPress.
Pojęcie "użytkownik" nie powinno być mylone z pojęciem "odwiedzający".
Odwiedzający to po prostu osoba czytająca witrynę, ale bez rejestracji
konta. W tym rozdziale koncentrujemy się głównie na użytkownikach.

We wszystkich instalacjach WordPress spotkamy przynajmniej jednego
użytkownika. To będzie osoba, która zainstalowała WordPress i
przeprowadziła początkową konfigurację platformy. Jej konto tradycyjnie
jest znane jako "admin", ponieważ starsze wersje WordPress automatycznie
powodowały utworzenie konta o nazwie admin. Obecnie po rejestracji
platforma pozwala na użycie innej nazwy użytkownika.

------------------------------------------------------------------------

Ostrzeżenie

Pewne starsze wtyczki zakładają istnienie konta o nazwie admin, co było
błędem w przeszłości i pozostało błędem również dzisiaj. Nigdy nie wolno
przyjmować założenia o istnieniu konta o konkretnej nazwie użytkownika.
Ponadto nigdy nie należy zakładać, że jeśli nazwa użytkownika jest w
użyciu, to dany użytkownik ma określone uprawnienia.

------------------------------------------------------------------------

Funkcje użytkownika

Platforma WordPress oferuje wiele funkcji przeznaczonych do pracy z
użytkownikami. W tym punkcie zostaną omówione wybrane funkcje
podstawowe.

------------------------------------------------------------------------

Ostrzeżenie

Wiele funkcji przeznaczonych do pracy z użytkownikami nie podlega
wczytaniu aż do chwili wczytania wtyczek. Poza tym, bieżący użytkownik
nie będzie uwierzytelniony aż do wywołania zaczepu akcji init (zobacz
rozdział 3.). Próba użycia na platformie WordPress funkcji użytkownika
przed wywołaniem zaczepu akcji init prawdopodobnie spowoduje wystąpienie
błędu o znaczeniu krytycznym.

------------------------------------------------------------------------

is_user_logged_in()

Funkcja is_user_logged_in() to znacznik warunkowy pozwalający na
sprawdzenie, czy użytkownik zalogował się w witrynie. Wartościami
zwrotnymi są true lub false w zależności od tego, czy bieżący użytkownik
ma identyfikator. Funkcja zalicza się do kategorii zastępowalnych, co
oznacza, że możesz utworzyć własną funkcję o nazwie is_user_logged_in()
i zupełnie nadpisać funkcjonalność oryginalnej. Osoby, które się
zalogowały, są uznawane za użytkowników, natomiast osoby niezalogowane
są uznawane za odwiedzających.

W przedstawionym poniżej fragmencie kodu następuje wyświetlenie w stopce
witryny komunikatu na podstawie wartości zwrotnej funkcji
is_user_logged_in(). Użytkownicy i odwiedzający zobaczą zupełnie
odmienne komunikaty.

    <?php
    add_action( 'wp_footer', 'boj_footer_user_logged_in' );
    function boj_footer_user_logged_in() {
        if ( is_user_logged_in() )
            echo 'Aktualnie jesteś zalogowany na tej witrynie.';
        else
            echo 'Nie jesteś zalogowany na tej witrynie.';
    }
    ?> 

Funkcja is_user_logged_in() jest ważna, ponieważ pozwala na wykonanie
określonego kodu jedynie wtedy, kiedy trzeba. Wprawdzie to jest
użyteczne, ale w tworzonych wtyczkach prawdopodobnie będziesz
wykorzystywał inne sposoby sprawdzania (zobacz podrozdział "Role i
możliwości" dalej w tym rozdziale).

get_users()

Funkcja get_users() pozwala na pobranie z tabeli bazy danych informacji
dotyczących użytkowników na podstawie argumentów przekazanych funkcji za
pomocą parametru $args. Parametr to tablica argumentów, które można
zdefiniować w celu ograniczenia liczby użytkowników zwróconych przez
funkcję.

    <?php
    get_users( $args );
    ?> 

Po wykonaniu zapytania pobierającego zbiór użytkowników wartością
zwrotną będzie tablica, na której można przeprowadzić pewne operacje.
Przykładowo możesz wyświetlić listę użytkowników na podstawie daty ich
rejestracji na witrynie.

Parametr $args zawiera wiele opcji pozwalających na ograniczenie liczby
użytkowników zwracanych przez zapytanie. Parametr jest opcjonalny; jeśli
nie zostanie zdefiniowany żaden argument, funkcja zwraca wszystkich
użytkowników. Oto opcje tego parametru.

-   blog_id — pobranie użytkowników zarejestrowanych w określonym blogu
    w sieci blogów. Opcja jest użyteczna jedynie w instalacjach
    wykorzystujących sieci blogów (tzw. multisite, zobacz rozdział 15.).
    Wartością domyślną jest identyfikator bieżącego bloga.
-   role — nazwa roli użytkownika. Wartością domyślną jest pusty ciąg
    tekstowy, używane są wszystkie role.
-   meta_key — klucz metadanych z tabeli $wpdb->usermeta.
-   meta_value — wartość metadanych z tabeli $wpdb->usermeta.
-   meta_compare — operator warunkowy pozwalający na porównanie względem
    argumentu meta_value. Niektóre dozwolone wartości to =, !=, >, >=, <
    i <=.
-   include — tablica identyfikatorów użytkowników, które mają być
    uwzględnione w zapytaniu.
-   exclude — tablica identyfikatorów użytkowników, które nie mają być
    uwzględnione w zapytaniu.
-   search — ciąg tekstowy używany do wyszukania użytkowników. Operacja
    wyszukiwania będzie przeprowadzona w kolumnach user_login,
    user_nicename, user_email, user_url i display_name tabeli
    $wpdb->users.
-   orderby — kolumna, względem której mają być ułożeni użytkownicy.
    Domyślnie używana jest kolumna login. Istnieje również możliwość
    zastosowania kolejności względem kolumn email, url, registered,
    name, user_login i post_count.
-   order — określenie kolejności rosnącej (ASC) lub malejącej (DESC).
    Domyślnie stosowana jest kolejność rosnąca (ASC).
-   offset — liczba użytkowników w bazie danych, których należy pominąć
    przed rozpoczęciem pobierania informacji o użytkownikach.
-   number — liczba całkowita ograniczająca liczbę użytkowników
    zwróconych przez zapytanie. Domyślnie funkcja zwraca wszystkich
    użytkowników dopasowanych do argumentów podanych w zapytaniu.

Pora wykorzystać funkcję get_users() w praktyce. W tym podpunkcie
zostanie zbudowana niewielka wtyczka wyświetlająca awatar (zdjęcie
użytkownika) każdego użytkownika w danej roli. Wtyczka to prosta funkcja
pozwalająca użytkownikowi na podanie roli. Następnie funkcja wyświetli
awatary wszystkich użytkowników wskazanej roli.

    <?php
    /*
    Plugin Name: Awatary użytkowników
    Plugin URI: http://przyklad.pl
    Description: Wtyczka wyświetla awatary użytkowników danej roli.
    Author: WROX
    Author URI: http://wrox.com
    */
    function boj_user_avatars( $role = 'subscriber' ) {
        /* Pobranie użytkowników na podstawie roli. */
        $users = get_users(
            array(
                'role' => $role
            )
        );
        /* Sprawdzenie, czy zwrócony został jakikolwiek użytkownik. */
        if ( is_array( $users ) ) {
            /* Iteracja przez każdego zwróconego użytkownika. */
            foreach ( $users as $user ) {
                /* Wyświetlenie awataru użytkownika. */
                echo get_avatar( $user );
            }
        }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-user-avatars.php.

------------------------------------------------------------------------

Aby powyższą wtyczkę wykorzystać na witrynie, użytkownik wtyczki
korzysta z przedstawionego poniżej wywołania funkcji i podaje nazwę
roli. W poniższym przykładzie podano rolę editor.

    <?php
    boj_user_avatars( 'editor' );
    ?> 

get_users_of_blog()

Jeżeli chcemy pobrać wszystkich użytkowników bloga, nie trzeba używać
omówionej powyżej funkcji get_users(). Funkcja get_users_of_blog()
zwraca tablicę wszystkich identyfikatorów użytkowników zarejestrowanych
w aktualnie wyświetlanym blogu.

    <?php
    get_users_of_blog( $id );
    ?> 

Funkcja pobiera jeden parametr: $id. Jest on użyteczny tylko w sieci
blogów i wtedy oznacza identyfikator określonej witryny.

W kolejnym przykładzie zostanie utworzona funkcja wyświetlająca
wszystkich użytkowników bloga. Funkcja wyświetla nazwę użytkownika oraz
odnośnik do strony archiwum danego użytkownika.

    <?php
    function boj_list_users_of_blog() {
        /* Pobranie użytkowników bieżącego bloga. */
        $users = get_users_of_blog();
        /* Sprawdzenie, czy funkcja zwróciła jakiegokolwiek użytkownika. */
        if ( !empty( $users ) ) {
            /* Początek listy użytkowników. */
            echo '<ul class="users-list">';
            /* Iteracja przez każdego zwróconego użytkownika. */
            foreach ( $users as $user ) {
                /* Utworzenie listy wraz z odnośnikami do stron archiwum poszczególnych użytkowników. */
                echo '<li><a href="' . get_author_posts_url( $user->ID ) . '">';
                echo get_the_author_meta( 'display_name', $user->ID );
                echo '</a></li>';
            }
            /* Zakończenie listy użytkowników. */
            echo '</ul>';
        }
    }
    ?> 

W ten sposób powstała funkcja przeznaczona do wyświetlania eleganckiej
listy użytkowników bloga. Tę funkcjonalność można wbudować do skrótu
(zobacz rozdział 10.) lub widgetu (zobacz rozdział 4.) poprzez wywołanie
funkcji boj_list_users_of_blog(). Przedstawiony poniżej kod powinien być
umieszczony w miejscu motywu, w którym ma zostać wyświetlona lista
użytkowników.

    <?php boj_list_users_of_blog(); ?>

count_users()

Funkcja count_users() pozwala na obliczenie użytkowników witryny
internetowej. Sprawdza liczbę wszystkich użytkowników oraz użytkowników
w poszczególnych rolach. Funkcja pobiera pojedynczy parametr o nazwie
$strategy określający sposób obliczania użytkowników. Parametr może
przyjąć jedną z dwóch wartości:

-   time — wartość domyślna, intensywnie wykorzystująca procesor;
-   memory — wartość powodująca intensywne wykorzystanie pamięci.

W poniższym fragmencie kodu następuje wyświetlenie liczby użytkowników
witryny. Kod powoduje wyświetlenie nie tylko całkowitej liczby
użytkowników, ale także liczby użytkowników w poszczególnych rolach.

    <?php
    /* Obliczenie liczby użytkowników. */
    $user_count = count_users();
    /* Początek nieuporządkowanej listy. */
    echo '<ul class="user-counts">';
    /* Wyświetlenie całkowitej liczby użytkowników. */
    echo '<li>Całkowita liczba użytkowników: ' . $user_count['total_users'] . '</li>';
    /* Iteracja przez wszystkie role. */
    foreach ( $user_count['avail_roles'] as $role => $count ) {
        /* Wyświetlenie ról i liczby ich użytkowników. */
        echo '<li>' . $role . ': ' . $count . '</li>';
    }
    /* Koniec nieuporządkowanej listy. */
    echo '</ul>';
    ?> 

Tworzenie, uaktualnianie i usuwanie użytkowników

Platforma WordPress ma wbudowany interfejs służący do tworzenia,
uaktualniania i usuwania użytkowników, który będzie wykorzystywany przez
większość osób. Jednak czasami trzeba utworzyć wtyczkę, która wymienione
zadania będzie przeprowadzać poza standardowym interfejsem WordPress.

Poniżej podano kilka powodów, dla których wymienione zadania trzeba
będzie zaimplementować w kodzie wtyczki.

-   Klient wymaga zaimportowania do WordPress tysięcy użytkowników z
    innego systemu, a ręczne tworzenie poszczególnych użytkowników nie
    jest brane pod uwagę.
-   Budujesz wtyczkę dla portalu społecznościowego, który wymaga
    interfejsu przeznaczonego do rejestracji konta użytkownika.
-   Wtyczka pozwala administratorowi na równoczesne przeprowadzenie
    wielu operacji edycji (uaktualnienia) danych użytkownika w różnej
    postaci w szybki i sprawny sposób.
-   Tworzysz widget panelu bocznego, który w wielu motywach WordPress
    będzie obsługiwał zadanie rejestracji użytkownika.

Jak możesz się przekonać na podstawie powyższej listy, istnieje wiele
powodów rezygnacji z używania standardowego interfejsu platformy
WordPress do obsługi użytkowników. Wprawdzie nie będziesz korzystał ze
standardowego interfejsu WordPress, ale zastosujesz standardowe funkcje,
które platforma oferuje do przeprowadzania wymienionych zadań.

wp_insert_user()

Funkcja wp_insert_user() powoduje wstawienie nowych użytkowników do bazy
danych. Zajmuje się również uaktualnieniem zarejestrowanych kont
użytkowników, pod warunkiem że przekazanym parametrem będzie
identyfikator użytkownika.

Funkcja ma pojedynczy parametr — $userdata. To tablica argumentów dla
danych wejściowych, które mają zostać umieszczone w tabelach
$wpdb->users i $wpdb->usermeta dla danego użytkownika.

    <?php
    wp_insert_user( $userdata );
    ?> 

Oto argumenty, które można zastosować w $userdata.

-   ID — identyfikator bieżącego użytkownika. Tej opcji należy używać
    jedynie podczas uaktualniania danych użytkownika. Platforma
    WordPress automatycznie tworzy nowy identyfikator użytkownika.
-   user_pass — hasło do konta nowego użytkownika.
-   user_login — to jest "nazwa użytkownika" przypisana do nowego konta.
    Ten argument jest wymagany i jeśli nie będzie unikalny, funkcja
    wygeneruje komunikat błędu.
-   user_nicename — alternatywna nazwa użytkownika używana np. w
    odnośnikach bezpośrednich do archiwum użytkownika. Wartością
    domyślną jest wartość argumentu user_login.
-   user_url — odnośnik do witryny osobistej użytkownika.
-   user_email — adres e-mail użytkownika. Ten argument jest wymagany i
    jeśli nie zostanie podany lub gdy podany adres jest już w użyciu,
    funkcja wygeneruje komunikat błędu.
-   display_name — wyświetlana nazwa użytkownika. Wartością domyślną
    jest wartość argumentu user_login.
-   nickname — tzw. "nick" użytkownika. Wartością domyślną jest wartość
    argumentu user_login.
-   first_name — imię użytkownika.
-   last_name — nazwisko użytkownika.
-   description — informacje o użytkowniku (biografia).
-   rich_editing — opcja wskazuje, czy podczas tworzenia wpisu bloga ma
    być używany edytor wizualny. Wartością domyślną jest true.
-   user_registered — data i godzina rejestracji użytkownika. Jeśli ten
    argument nie zostanie podany, platforma WordPress automatycznie
    wstawia bieżącą datę i godzinę.
-   role — rola użytkownika. Wartością domyślną jest rola domyślna
    administratora witryny, która została zdefiniowana w opcjach
    WordPress.
-   admin_color — schemat kolorów używany w obszarze administracyjnym
    WordPress.
-   comment_shortcuts — ten argument wskazuje, czy użytkownik podczas
    moderacji komentarzy może używać skrótów klawiaturowych. Wartością
    domyślną jest false.

Wymienione powyżej argumenty można wykorzystać podczas tworzenia nowego
użytkownika za pomocą funkcji wp_insert_user(). Istnieje możliwość
użycia dowolnych z wymienionych argumentów, ale trzeba pamiętać o
argumentach wymaganych (user_login, user_pass i user_email). W
przedstawionym poniżej przykładzie utworzony użytkownik będzie należał
do roli editor i będzie nosił nazwę helion. Trzeba się również upewnić o
utworzeniu użytkownika i wyświetlić wygenerowany przez WordPress
komunikat błędu, jeśli proces kreowania użytkownika zakończył się
niepowodzeniem.

Utworzymy teraz nowy plik wtyczki o nazwie boj-insert-user.php i
wykorzystamy przedstawiony poniżej kod do przygotowania wtyczki, która
wstawi nowego użytkownik do bazy danych przy użyciu funkcji
wp_insert_user().

    <?php
    /*
    Plugin Name: Wstawianie użytkownika
    Plugin URI: http://przyklad.pl
    Description: Wtyczka wstawiająca nowego użytkownika.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Zarejestrowanie dla zaczepu init funkcji wstawiania nowego użytkownika. */
    add_action( 'init', 'boj_insert_user' );
    /* Wstawienie nowego użytkownika. */
    function boj_insert_user() {
        /* Jeżeli użytkownik o nazwie helion już istnieje, nie rób nic. */
        if ( username_exists( 'helion' ) )
            return;
        /* Podanie danych użytkownika. */
        $userdata = array(
            'user_login' => 'helion',
            'user_email' => 'helion@przyklad.pl',
            'user_pass' => '123456789',
            'user_url' => 'http://przyklad.pl',
            'display_name' => 'Helion',
            'description' => 'Uwielbia publikować doskonałe książki o WordPress!',
            'role' => 'editor'
        );
        /* Utworzenie użytkownika. */
        $user = wp_insert_user( $userdata );
        /* Jeżeli użytkownik nie został utworzony, trzeba wyświetlić komunikat błędu. */
        if ( is_wp_error( $user ) )
            echo $result->get_error_message();
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-insert-user.php.

------------------------------------------------------------------------

wp_create_user()

Możesz się zastanawiać, jaki jest cel istnienia funkcji
wp_create_user(), skoro funkcja wp_insert_user() wykonuje swoje zadanie?
Jednak funkcja wp_create_user() to użyteczna alternatywa pozwalająca na
szybkie utworzenie nowych użytkowników bez konieczności zajmowania się
wszystkimi argumentami wykorzystywanymi w funkcji wp_insert_user().

    <?php
    wp_create_user( $username, $password, $email );
    ?> 

Powyższa funkcja pozwala na użycie minimalnej liczby argumentów podczas
tworzenia użytkownika, co znacznie upraszcza cały proces. To szczególnie
użyteczne, kiedy do wstawienia nie ma żadnych innych danych.

Parametry:

-   $username — unikalna nazwa użytkownika dla tworzonego konta;
-   $password — hasło, które będzie używane przez użytkownika do
    zalogowania się na witrynie;
-   $email — unikalny adres e-mail powiązany z tworzonym kontem
    użytkownika.

Przedstawiony poniżej kod powoduje utworzenie nowego użytkownika o
nazwie helion2. Użytkownik ten będzie zaliczany do domyślnej roli
zdefiniowanej przez administratora witryny. Utwórz więc nowy plik
wtyczki o nazwie boj-create-user.php i umieść w nim poniższy kod, w
którym wykreujesz nowego użytkownika za pomocą funkcji wp_create_user().

    <?php
    /*
    Plugin Name: Utworzenie użytkownika
    Plugin URI: http://przyklad.pl
    Description: Wtyczka tworząca nowego użytkownika.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Zarejestrowanie dla zaczepu init funkcji utworzenia nowego użytkownika. */
    add_action( 'init', 'boj_create_user' );
    /* Utworzenie nowego użytkownika. */
    function boj_create_user() {
        /* Jeżeli użytkownik o nazwie helion2 już istnieje, nie rób nic. */
        if ( username_exists( 'helion2' ) )
            return;
        /* Utworzenie użytkownika helion2. */
        wp_create_user(
            'helion2',
            '123456789',
            'helion2@przyklad.pl'
        );
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-create-user.php.

------------------------------------------------------------------------

wp_update_user()

To kolejna funkcja, której zadanie z powodzeniem można wykonać za pomocą
funkcji wp_insert_user(). Ta jest z kolei funkcją opakowującą z jedną
ważną różnicą: jeżeli hasło użytkownika (argument user_pass) zostanie
uaktualnione, funkcja automatycznie zeruje plik cookie w przeglądarce
internetowej użytkownika.

    <?php
    wp_update_user( $userdata );
    ?> 

Funkcja wp_update_user() pobiera jeden parametr o nazwie $userdata
akceptujący wszystkie te same argumenty, które zostały omówione przy
okazji funkcji wp_insert_user(). Jednak podczas operacji uaktualniania
danych użytkownika wymagane jest podanie argumentu ID. W przypadku braku
argumentu ID nastąpi utworzenie nowego użytkownika.

W kolejnym przykładowym fragmencie kodu funkcja wp_update_user()
zostanie wykorzystana w celu wymuszenia na aktualnie zalogowanym
użytkowniku zmiany schematu kolorów w obszarze administracyjnym. To
użyteczne zadanie i pozwala zagwarantować, że wszyscy użytkownicy będą
mieli ten sam interfejs użytkownika w obszarze administracyjnym. Po
utworzeniu nowego pliku wtyczki o nazwie boj-force-admin-color.php
należy umieścić w nim przedstawiony poniżej kod:

    <?php
    /*
    Plugin Name: Wymuszenie zmiany kolorów obszaru administracyjnego
    Plugin URI: http://przyklad.pl
    Description: Wtyczka wymusza zmianę schematu kolorów używanego w obszarze administracyjnym.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Zmiana kolorów dotyczy jedynie obszaru administracyjnego. */
    add_action( 'admin_init', 'boj_force_admin_color' );
    /* Wymusza na aktualnie zalogowanym użytkowniku zmiany schematu kolorów w obszarze administracyjnym. */
    function boj_force_admin_color() {
        /* Pobranie obiektu aktualnego użytkownika. */
        $user = wp_get_current_user();
        /* Jeżeli zmienna $user nie jest pusta, można kontynuować działanie. */
        if ( !empty( $user ) ) {
            /* Pobranie schematu kolorów używanych w obszarze administracyjnym. */
            $admin_color = get_user_meta( $user->ID, 'admin_color', true );
            /* Jeżeli schemat kolorów to nie 'fresh', należy go zmienić. */
            if ( $admin_color !== 'fresh' ) {
                /* Ustawienie danych użytkownika. */
                $userdata = array(
                    'ID' => $user->ID,
                    'admin_color' => 'fresh'
                );
                /* Uaktualnienie użytkownika. */
                wp_update_user( $userdata );
            }
        }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-force-admin-color.php.

------------------------------------------------------------------------

wp_delete_user()

Funkcja wp_delete_user() jest nieco odmienna od omówionych wcześniej,
ponieważ istnieje jedynie w obszarze administracyjnym WordPress. Dlatego
też teoretycznie funkcję można wywołać, jedynie będąc administratorem. W
przeciwnym razie nastąpi wygenerowanie błędu PHP.

    <?php
    wp_delete_user( $user_id, $reassign );
    ?> 

Funkcja jest wykorzystywana do usuwania poszczególnych użytkowników oraz
do ponownego przypisania ich wpisów bloga i odnośników alternatywnemu
użytkownikowi. Funkcja pobiera dwa parametry.

-   $id — identyfikator użytkownika przeznaczonego do usunięcia.
-   $reassign — identyfikator użytkownika, który zostanie określony jako
    autor wpisów bloga i odnośników poprzednio opublikowanych przez
    usuwanego użytkownika. Jeżeli ten parametr nie zostanie użyty, wpisy
    bloga i odnośniki usuwanego użytkownika również zostaną usunięte z
    bazy danych.

W przedstawionym poniżej fragmencie kodu następuje usunięcie użytkownika
o identyfikatorze 100 oraz przypisanie opublikowanych przez niego wpisów
bloga i odnośników użytkownikowi o identyfikatorze 1.

    <?php
    /* Usunięcie użytkownika o identyfikatorze 100 oraz przypisanie opublikowanych przez niego wpisów bloga i odnośników użytkownikowi o identyfikatorze 1. */
    wp_delete_user( 100, 1 );
    ?> 

Dane użytkownika

Dane użytkownika na platformie WordPress są zapisywane w dwóch różnych
tabelach bazy danych: $wpdb->users i $wpdb->usermeta. W tabeli users
znajdują się informacje o użytkowniku, których platforma WordPress
wymaga do funkcjonowania. Z kolei w tabeli usermeta znajdują się
dodatkowe metadane dotyczące użytkowników. Czasami te informacje muszą
być wczytywane, tworzone, uaktualniane i usuwane z poziomu wtyczki.

Podczas pracy z danymi użytkownika zapisanymi w tabeli users z reguły
masz do czynienia z kilkoma różnymi wartościami ustawionymi dla każdego
użytkownika witryny.

-   ID — identyfikator zarejestrowanego użytkownika.
-   user_login — "nazwa użytkownika" przypisana do nowego konta.
-   user_pass — hasło do konta użytkownika. Warto pamiętać, aby hasła
    nigdy nie wyświetlać publicznie.
-   user_nicename — alternatywna nazwa użytkownika używana np. w
    adresach URL.
-   user_url — odnośnik do witryny osobistej użytkownika.
-   user_email — adres e-mail użytkownika. Adresu e-mail nigdy nie
    należy wyświetlać publicznie bez zgody użytkownika.
-   user_registered — data i godzina rejestracji użytkownika na
    witrynie.
-   display_name — wyświetlana na witrynie nazwa użytkownika.

get_userdata()

Funkcja get_userdata() służy do pobierania danych użytkownika z tabeli
users. Zwraca również dane z tabeli usermeta, ale platforma WordPress ma
inne funkcje przeznaczone do pobierania tych informacji. Funkcja pobiera
jeden argument $user_id będący identyfikatorem użytkownika
zarejestrowanego na witrynie. W przypadku znalezienia użytkownika
wartością zwrotną jest obiekt danych użytkownika, w przeciwnym razie
wartością zwrotną jest false.

Pamiętaj, funkcja ta może również zwrócić metadane użytkownika, ale nie
należy tych danych wyświetlać za jej pomocą. Problem ten zostanie
omówiony w dalszej części rozdziału.

Załóżmy, że potrzebujesz funkcji pozwalającej na szybkie wyświetlenie
nazwy użytkownika i adresu jego witryny internetowej. Poniżej znajduje
się kod funkcji wyświetlającej wymienione informacje.

    <?php
    function boj_display_user_website( $user_id ) {
        /* Pobranie danych użytkownika. */
        $data = get_userdata( $user_id );
        /* Sprawdzenie, czy dane zostały zwrócone. */
        if ( !empty( $data ) ) {
            /* Sprawdzenie, czy użytkownik podał adres URL. */
            if ( !empty( $data->user_url ) ) {
                /* Wyświetlenie nazwy użytkownika oraz podanego przez niego adresu URL. */
                echo $data->display_name . ': ' . $data->user_url;
            }
    }
    ?> 

Tak przygotowaną funkcję boj_display_user_website() można wykorzystać do
wyświetlenia nazwy użytkownika oraz podanego przez niego adresu URL
witryny. W tym celu funkcji trzeba przekazać identyfikator użytkownika
(jako parametr $user_id). Aby np. wyświetlić te informacje dla
użytkownika o identyfikatorze 100, należy wywołać funkcję w następujący
sposób:

    <?php
    boj_display_user_website( 100 );
    ?> 

wp_get_current_user()

Funkcja wp_get_current_user() pobiera z tabeli users dane dotyczące
aktualnie zalogowanego użytkownika. Może być wykorzystana do
wyświetlania informacji po zalogowaniu się na witrynie określonego
użytkownika. Funkcja nie pobiera parametrów i zwraca obiekt zawierający
dane użytkownika.

W przedstawionym poniżej fragmencie kodu następuje wyświetlenie w
obszarze administracyjnym platformy WordPress komunikatu powitania
przygotowanego na podstawie nazwy użytkownika.

    <?php
    /* Wyświetlenie komunikatu powitalnego w stopce obszaru administracyjnego. */
    add_action( 'in_admin_footer', 'boj_user_welcome_message' );
    function boj_user_welcome_message() {
        /* Pobranie danych bieżącego użytkownika. */
        $data = wp_get_current_user();
        /* Wyświetlenie komunikatu użytkownikowi. */
        echo "Witaj {$data->display_name}.<br />";
    }
    ?> 

get_currentuserinfo()

Funkcja get_currentuserinfo() jest podobna do omówionej powyżej. W
rzeczywistości, w celu pobrania informacji dotyczących użytkownika
funkcja wp_get_current_user() powoduje wywołanie get_currentuserinfo().
Największa różnica pomiędzy wymienionymi funkcjami polega na tym, że
get_currentuserinfo() nie zwraca zmiennej. Zamiast tego ustawia wartość
zmiennej globalnej $current_user.

W większości przypadków preferowane jest użycie funkcji
wp_get_current_user(). Jednak obie funkcje zaliczają się do
zastępowalnych (tzn. możesz utworzyć ich własne wersje). Trzeba to wziąć
pod uwagę podczas budowania wtyczki, w której następuje nadpisanie
wymienionych funkcji.

Przedstawiony poniżej fragment kodu można wykorzystać do wyświetlenia
daty rejestracji bieżącego użytkownika. Po utworzeniu nowego pliku
wtyczki o nazwie boj-user-registration-date.php należy umieścić w nim
poniższy kod. Jak wspomniano, kod powoduje wyświetlenie w stopce strony
administracyjnej daty rejestracji bieżącego użytkownika.

    <?php
    /*
    Plugin Name: Data rejestracji użytkownika
    Plugin URI: http://przyklad.pl
    Description: Wtyczka wyświetla w stopce strony administracyjnej datę rejestracji użytkownika.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Wyświetlenie w stopce strony administracyjnej daty rejestracji użytkownika. */
    add_action( 'in_admin_footer', 'boj_display_user_registration_date' );
    function boj_display_user_registration_date() {
        /* Zglobalizowanie zmiennej $current_user. */
        global $current_user;
        /* Wywołanie funkcji get_currentuserinfo(). */
        get_currentuserinfo();
        /* Odpowiednie sformatowanie daty rejestracji użytkownika. */
        $date = mysql2date( 'j F, Y', $current_user->user_registered );
        /* Wyświetlenie daty rejestracji użytkownika. */
        echo "Zarejestrowałeś się dnia {$date}.<br />";
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-user-registration-date.php.

------------------------------------------------------------------------

count_user_posts()

Kiedy trzeba określić liczbę wpisów bloga opublikowanych przez
użytkownika, z pomocą przychodzi funkcja count_user_posts(). Wymieniona
funkcja bierze pod uwagę jedynie liczbę wpisów bloga typu post.
Przykładowo nie będą uwzględnione strony lub wpisy własnego typu.
Funkcja pobiera jeden parametr —$user_id — jest to identyfikator
użytkownika, którego wpisy bloga mają być zliczone.

Przyjmijmy założenie, że masz system ocen użytkowników w zależności od
liczby opublikowanych przez nich wpisów bloga. Ocenę "srebrny" chcesz
przyznać użytkownikom, którzy opublikowali przynajmniej 25 wpisów bloga,
natomiast ocenę "złoty" przyznajesz za opublikowanie przynajmniej 50
wpisów bloga. W tym celu wystarczy po zapisaniu wpisu bloga wykonać kod.
Utwórz nowy plik wtyczki o nazwie boj-user-ratings.php, a następnie
umieść w nim przedstawiony poniżej kod odpowiedzialny za przyznawanie
ocen użytkownikom. Pamiętaj, że ocena użytkownika jest zapisywana jako
jego metadane jedynie podczas publikacji wpisu bloga. (Obsługa
metadanych została omówiona w dalszej części rozdziału poświęconej
metadanym).

    <?php
    /*
    Plugin Name: Ocena użytkownika
    Plugin URI: http://przyklad.pl
    Description: Wtyczka uaktualnia ocenę użytkownika na podstawie liczby opublikowanych wpisów 
    bloga.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Uaktualnienie oceny użytkownika następuje wyłącznie podczas zapisu wpisu bloga. */
    add_action( 'save_post', 'boj_add_user_rating' );
    function boj_add_user_rating() {
        /* Pobranie bieżącego użytkownika. */
        $user = wp_get_current_user();
        /* Pobranie bieżącej oceny użytkownika. */
        $rating = get_user_meta( $user->ID, 'user_rating', true );
        /* Jeżeli użytkownik ma już ocenę 'złoty', wówczas nie ulega ona zmianie. */
        if ( 'złoty' == $rating )
            return;
        /* Obliczenie liczby wpisów bloga opublikowanych przez użytkownika. */
        $posts = count_user_posts( $user->ID );
        /* Sprawdzenie, czy liczba opublikowanych wpisów bloga jest większa niż 50. */
        if ( 50 <= $posts ) {
            /* Przyznanie użytkownikowi oceny 'złoty'. */
            update_user_meta( $user->ID, 'user_rating', 'złoty' );
        }
        /* Sprawdzenie, czy liczba opublikowanych wpisów bloga jest równa lub większa niż 25. */
        elseif ( 25 <= $posts ) {
            /* Przyznanie użytkownikowi oceny 'srebrny'. */
            update_user_meta( $user->ID, 'user_rating', 'srebrny' );
        }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-user-ratings.php.

------------------------------------------------------------------------

count_many_users_posts()

Czasami trzeba określić liczbę wpisów bloga opublikowanych przez wielu
użytkowników, a nie tylko pojedynczego. W takich sytuacjach należy użyć
funkcji count_many_users_posts() zamiast omówionej powyżej
count_user_posts(). Dzięki temu unika się wielokrotnego wykonywania
zapytań do bazy danych.

Funkcja count_many_users_posts() akceptuje pojedynczy parametr $users,
który powinien być tablicą identyfikatorów użytkowników. Wartością
zwrotną funkcji również jest tablica, w której kluczem jest
identyfikator użytkownika, natomiast wartością liczba opublikowanych
przez niego wpisów bloga.

W przedstawionym poniżej fragmencie kodu utworzono funkcję akceptującą
tablicę identyfikatorów użytkowników. Wartością zwrotną jest liczba
wpisów bloga opublikowanych przez poszczególnych użytkowników.

    <?php
    function boj_list_users_posts_counts( $user_ids = array() ) {
        /* Upewnienie się o otrzymaniu tablicy identyfikatorów użytkowników. */
        if ( empty( $user_ids ) )
            return '';
        /* Obliczenie liczby wpisów bloga opublikowanych przez poszczególnych użytkowników. */
        $users_counts = count_many_users_posts( $user_ids );
        /* Początek nieuporządkowanej listy. */
        echo '<ul class="users-posts-counts">';
        /* Iteracja przez wszystkich podanych użytkowników. */
        foreach ( $users_counts as $user => $count ) {
            /* Wyświetlenie komunikatu zawierającego identyfikator użytkownika i liczbę opublikowanych wpisów bloga. */
            echo "<li>Użytkownik o identyfikatorze {$user} opublikował {$count} wpisów
               bloga.</li>";
        }
        /* Koniec nieuporządkowanej listy. */
        echo '</ul>';
    }
    ?> 

Użytkownik wtyczki może wykorzystać powyższy kod do wyświetlenia
sformatowanej listy zawierającej wybranych użytkowników oraz liczbę
opublikowanych przez nich wpisów bloga. Załóżmy, że użytkownik wtyczki
chce wyświetlić liczbę wpisów bloga opublikowanych przez użytkowników o
identyfikatorach 100, 200 i 300. W takim przypadku musi jedynie
przekazać przedstawionej powyżej funkcji identyfikatory interesujących
go użytkowników:

    <?php boj_list_users_posts_counts( array( 100, 200, 300 ) ); ?> 

Metadane użytkownika

Metadane użytkownika to zapisane w tabeli $wpdb->usermeta bazy danych
informacje dotyczące użytkownika. Są to dodatkowe dane, które wtyczka
może dołączyć poza standardowymi kolumnami tabeli $wpdb->users.

Mogą to być dowolnego rodzaju dane wymagane podczas implementacji
wtyczki z obsługą ustawień dla poszczególnych użytkowników. Dane są
zapisywane w postaci par klucz-wartość, a pojedynczy klucz może mieć
większą liczbę wartości. Klucze metadanych są sposobem przedstawienia
informacji dostarczanych przez wartości metadanych. Można je potraktować
jak czytelne dla człowieka identyfikatory reprezentujące informacje, z
którymi on pracuje. Z kolei wartości metadanych to fragmenty danych
pobierane dla danego klucza metadanych.

Metadane mogą być dosłownie dowolnego rodzaju danymi, które mają zostać
zapisane dla danego użytkownika. Poniżej wymieniono niektóre rodzaje
metadanych:

-   konto w serwisie Twitter lub Facebook;
-   lokalizacja (kraj, miasto, województwo);
-   numer telefonu;
-   ulubiona książka;
-   ustawienia konfiguracyjne danej witryny internetowej;
-   prywatne informacje o koncie.

------------------------------------------------------------------------

Ostrzeżenie

Warto pamiętać, aby podczas zapisywania poufnych informacji dotyczących
użytkowników upewnić się, że wtyczka nigdy publicznie nie wyświetli tych
danych.

------------------------------------------------------------------------

W tym punkcie skoncentrujemy się na dodawaniu, wyświetlaniu,
uaktualnianiu i usuwaniu określonych danych użytkownika. W ten sposób
przekonasz się, jak funkcjonują metadane podczas przeprowadzania
operacji na danych.

W przykładach przyjęto założenie pracy z użytkownikiem o identyfikatorze
100 i kluczu metadanych o nazwie favorite_books. Taki klucz metadanych
zapisuje wartości w postaci ulubionych książek użytkownika.

add_user_meta()

Do dodania nowych metadanych użytkownika wykorzystywana jest funkcja
add_user_meta(). Po zakończonym powodzeniem wstawieniu danych do bazy
danych wartością zwrotną funkcji jest true, w przeciwnym przypadku —
false.

    <?php
    add_user_meta( $user_id, $meta_key, $meta_value, $unique );
    ?> 

Parametry:

-   $user_id — identyfikator użytkownika, dla którego mają zostać dodane
    metadane.
-   $meta_key — użyty w bazie danych klucz metadanych.
-   $meta_value — pojedyncza wartość do dodania w parze z $meta_key.
-   $unique — parametr wskazuje, czy wymusić na funkcji zwrócenie tylko
    jednego rekordu (true) z tabeli usermeta, czy wielu rekordów dla
    wielu wartości meta (false). Wartością domyślną parametru jest
    false.

Teraz dla użytkownika o identyfikatorze 100 zostaną dodane trzy wartości
metadanych określające ulubione książki. Tytuły dodawanych książek są
następujące: WordPress dla początkujących, WordPress dla zaawansowanych
i WordPress dla ekspertów.

    <?php
    add_user_meta( 100, 'favorite_books', 'WordPress dla początkujących', false );
    add_user_meta( 100, 'favorite_books', 'WordPress dla zaawansowanych, false );
    add_user_meta( 100, 'favorite_books', 'WordPress dla ekspertów', false );
    ?> 

Wartość parametru $unique wynosi false. Aby można było zapisać wiele
wartości dla tego samego klucza metadanych (tutaj favorite_books),
wymieniony parametr musi mieć ustawioną wartość false. Jeśli natomiast
klucz metadanych ma mieć pojedynczą wartość, parametrowi można ustawić
true.

get_user_meta()

Po poznaniu sposobu dodawania metadanych dla użytkownika pora dowiedzieć
się, w jaki sposób można je wyświetlić. Funkcja get_user_meta() pobiera
metadane z bazy danych na podstawie identyfikatora użytkownika oraz
klucza metadanych.

    <?php
    get_user_meta( $user_id, $meta_key, $single );
    ?> 

Parametry:

-   $user_id — identyfikator użytkownika, dla którego mają zostać
    pobrane metadane.
-   $meta_key — klucz metadanych, dla którego ma zostać pobrana wartość
    lub wartości.
-   $single — parametr wskazuje, czy wartością zwrotną funkcji ma być
    tablica wartości metadanych (false), czy pojedyncza wartość (true).
    Wartością domyślną parametru jest false.

W celu wyświetlenia listy ulubionych książek użytkownika dodanych
wcześniej za pomocą funkcji add_user_meta() można użyć przedstawionego
poniżej kodu.

    <?php
    /* Pobranie ulubionych książek użytkownika. */
    $favorite_books = get_user_meta( 100, 'favorite_books', false );
    /* Sprawdzenie, czy w ogóle użytkownik ma zapisane jakiekolwiek ulubione książki. */
    if ( !empty( $favorite_books ) ) {
        /* Początek nieuporządkowanej listy. */
        echo '<ul class="favorite-books">';
        /* Iteracja przez wszystkie ulubione książki. */
        foreach ( $favorite_books as $book ) {
            /* Wyświetlenie tytułu książki. */
            echo '<li>' . $book . '</li>';
        }
    }
    ?> 

Jeżeli klucz favorite_books będzie przechowywał tylko pojedynczą wartość
zamiast wielu, wówczas nie trzeba używać pętli do przeprowadzenia
iteracji przez tablicę. W takim przypadku wystarczy po prostu wyświetlić
na ekranie wartość zwrotną funkcji.

    <?php
    /* Pobranie ulubionej książki użytkownika (tylko jedna książka). */
    $favorite_book = get_user_meta( 100, 'favorite_books', true );
    /* Wyświetlenie tytułu ulubionej książki. */
    echo $favorite_book;
    ?> 

update_user_meta()

Funkcja update_user_meta() pozwala na uaktualnienie pojedynczej wartości
metadanych, niezależnie od tego, czy istnieje jedna, czy wiele tych
wartości. Jeżeli klucz metadanych ma wiele wartości, wówczas można
również nadpisać je wszystkie. Tę funkcję można wykorzystać także do
wstawienia nowych metadanych, jeśli takie jeszcze nie istnieją dla
wskazanego użytkownika.

    <?php
    update_user_meta( $user_id, $meta_key, $meta_value, $prev_value );
    ?> 

Parametry:

-   $user_id — identyfikator użytkownika, dla którego mają zostać
    pobrane metadane.
-   $meta_key — klucz metadanych, dla którego mają być uaktualnione
    wartości.
-   $meta_value — nowa wartość dla danego klucza metadanych.
-   $prev_value — poprzednia wartość metadanych do nadpisania. Jeżeli
    nie zostanie podana, wówczas wszystkie wartości metadanych będą
    nadpisane pojedynczą, nową wartością podaną w parametrze
    $meta_value.

Przypuśćmy, że zachodzi konieczność zmiany tytułu jednej z ulubionych
książek użytkownika: WordPress dla początkujących na WordPress dla
każdego. W takim przypadku w parametrze $meta_value trzeba podać nowy
tytuł książki, natomiast w parametrze $prev_value — poprzedni tytuł
książki.

    <?php
    update_user_meta(
        100,
        'favorite_books',
        'WordPress dla każdego',
        'WordPress dla początkujących'
    );
    ?> 

Jeżeli wszystkie ulubione książki mają być zastąpione jedną, wystarczy
podać wartość parametru $meta_value i pozostawić pusty parametr
$prev_value.

    <?php
    update_user_meta( 100, 'favorite_books', 'WordPress dla każdego' );
    ?> 

delete_user_meta()

Funkcja delete_user_meta() pozwala na usunięcie wszystkich wartości i
klucza metadanych lub pojedynczej wartości metadanych dla podanego
klucza.

    <?php
    delete_user_meta( $user_id, $meta_key, $meta_value = '' );
    ?> 

Parametry:

-   $user_id — identyfikator użytkownika, dla którego mają zostać
    usunięte metadane.
-   $meta_key — klucz metadanych przeznaczony do usunięcia lub klucz
    metadanych, dla którego mają być usunięte wartości.
-   $meta_value — określona wartość metadanych przeznaczona do
    usunięcia. Jeżeli ten parametr zostanie pominięty (będzie pusty),
    wówczas usunięty będzie klucz i wszystkie wartości metadanych dla
    tego użytkownika.

Jeżeli chcesz usunąć pojedynczą książkę z listy ulubionych książek
użytkownika, w parametrze $meta_value musisz podać tytuł tej książki.
Przedstawiony poniżej kod powoduje usunięcie książki WordPress dla
zaawansowanych z listy ulubionych książek użytkownika.

    <?php
    delete_user_meta( 100, 'favorite_books', 'WordPress dla zaawansowanych' );
    ?> 

Jeśli natomiast chcesz usunąć wszystkie ulubione książki danego
użytkownika, parametr $meta_value powinien pozostać pusty.

    <?php
    delete_user_meta( 100, 'favorite_books' );
    ?> 

user_contactmethods

user_contactmethods to zaczep (zobacz rozdział 3.), a nie funkcja, na
których koncentrujemy się w tym rozdziale. To bardzo ważne, ponieważ
zaczep ten stanowi szybką metodę dodawania metadanych użytkownika dla
alternatywnych metod kontaktu, takich jak nazwa użytkownika w serwisie
Twitter, profil w serwisie Facebook lub numery telefonów.

Za pomocą jedynie kilku wierszy kodu pozwala na utworzenie dodatkowych
pól na stronie edycyjnej użytkownika. Platforma WordPress domyślnie
dodaje pięć metod. Ostatnie trzy to metadane, które zostaną omówione w
tym rozdziale:

-   e-mail,
-   witryna internetowa,
-   AIM,
-   Yahoo IM,
-   Jabber/Google Talk.

Zaczep filtru user_contactmethods zwraca tablicę kluczy metadanych oraz
etykiety dla tych oznaczonych kluczy. W celu dodania nowych kluczy
metadanych, do wspomnianej tablicy trzeba wstawić nowe wartości, jak
przedstawiono w poniższym kodzie.

    <?php
    /*
    Plugin Name: Metody kontaktu z użytkownikiem
    Plugin URI: http://przyklad.pl
    Description: Dodatkowe metody kontaktu z użytkownikiem.
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Dodanie filtru do zaczepu. */
    add_filter( 'user_contactmethods', 'boj_user_contactmethods' );
    /* Funkcja dodająca nowe metody kontaktu. */
    function boj_user_contactmethods( $user_contactmethods ) {
        /* Dodanie kontaktu w postaci nazwy użytkownika w serwisie Twitter. */
        $user_contactmethods['twitter'] = 'Nazwa użytkownika w serwisie Twitter';
        /* Dodanie kontaktu w postaci numeru telefonu. */
        $user_contactmethods['phone'] = 'Numer telefonu';
        /* Zwrócenie tablicy z nowo dodanymi wartościami. */
        return $user_contactmethods;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-user-contact-methods.php.

------------------------------------------------------------------------

Powyższy kod powoduje umieszczenie dodatkowych pól kontaktowych w sekcji
Dane kontaktowe na stronie profilu użytkownika (zobacz rysunek 8.1).

[]

Rysunek 8.1. Dodatkowe pola kontaktowe, które pojawiły się na stronie
profilu użytkownika

Platforma WordPress sama zajmie się odpowiednim dodaniem, uaktualnieniem
i usunięciem metadanych w obszarze administracyjnym. W celu pobrania
dodanych wartości należy użyć omówionej wcześniej funkcji
get_user_meta().

Utworzenie wtyczki z metadanymi użytkownika

Skoro poznałeś już sposoby obsługi metadanych użytkownika, warto tę
wiedzę wykorzystać w praktycznym projekcie. W wielu sytuacjach własne
metadane użytkownika używane przez wtyczkę muszą być zdefiniowane przez
użytkownika na stronie jego profilu.

Teraz zbudujemy wtyczkę, która na stronie profilu użytkownika w obszarze
administracyjnym umieści dodatkową sekcję. Formularz będzie zawierał
pole wyboru wpisów bloga na witrynie. Użytkownik będzie mógł wybrać
jeden z wpisów bloga, który w ten sposób stanie się jego ulubionym.

Pracę trzeba zacząć od utworzenia nowego pliku w katalogu wtyczek i
nadania mu nazwy boj-user-favorite-post.php. Następnie należy utworzyć
nagłówek wtyczki i umieścić formularz na stronie profilu użytkownika.

    <?php
    /*
    Plugin Name: Ulubiony wpis bloga użytkownika
    Plugin URI: http://przyklad.pl
    Description: Wtyczka pozwala użytkownikowi na wybór ulubionego wpisu bloga na jego witrynie.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Dodanie formularza na stronie profilu użytkownika w obszarze administracyjnym. */
    add_action( 'show_user_profile', 'boj_user_favorite_post_form' );
    add_action( 'edit_user_profile', 'boj_user_favorite_post_form' );
    /* Funkcja wyświetlająca dodatkowy formularz na stronie profilu użytkownika. */
    function boj_user_favorite_post_form( $user ) {
        /* Pobranie aktualnego ulubionego wpisu bloga użytkownika. */
        $favorite_post = get_user_meta( $user->ID, 'favorite_post', true );
        /* Pobranie listy wszystkich wpisów bloga. */
        $posts = get_posts( array( 'numberposts' => -1 ) );
        ?> 
        <h3>Ulubione</h3> 
        <table class="form-table"> 
        <tr> 
            <th><label for="favorite_post">Ulubiony wpis bloga</label></th> 
            <td> 
                <select name="favorite_post" id="favorite_post"> 
                    <option value=""></option> 
                <?php foreach ( $posts as $post ) { ?> 
                    <option value="<?php echo esc_attr( $post->ID ); ?>"
                    <?php selected( $favorite_post, $post->ID ); ?>> 
                        <?php echo esc_html( $post->post_title ); ?> 
                    </option> 
                <?php } ?> 
                </select> 
                <br /> 
                <span class="description">Wybierz ulubiony wpis bloga.</span> 
            </td> 
        </tr> 
    </table> 
    <?php } 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-user-favorite-post.php.

------------------------------------------------------------------------

Jak pokazano na rysunku 8.2, kod powoduje umieszczenie dodatkowej sekcji
na stronie profilu użytkownika.

Na tym etapie formularz jest jedynie wyświetlony. Kolejnym krokiem jest
zapis w postaci metadanych ulubionego wpisu bloga użytkownika.

    /* Zarejestrowanie w zaczepie funkcji uaktualniającej metadane użytkownika. */
    add_action( 'personal_options_update', 'boj_user_favorite_post_update' );
    add_action( 'edit_user_profile_update', 'boj_user_favorite_post_update' );
    /* Funkcja uaktualniająca informacje o ulubionym wpisie bloga użytkownika. */

[]

Rysunek 8.2. Dodatkowa sekcja wyświetlona na stronie profilu użytkownika

    function boj_user_favorite_post_update( $user_id ) {
        /* Sprawdzenie, czy bieżący użytkownik ma uprawnienia do edycji informacji. */
        if ( !current_user_can( 'edit_user', $user_id ) )
            return false;
        /* Ponieważ to identyfikator wpisu bloga, akceptowane są tylko cyfry od 0 do 9. */
        $favorite_post = preg_replace( "/[^0-9]/", '', $_POST['favorite_post'] );
        /* Uaktualnienie informacji o ulubionym wpisie bloga użytkownika. */
        update_user_meta( $user_id, 'favorite_post', $favorite_post );
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-user-favorite-post.php.

------------------------------------------------------------------------

Na tym etapie wtyczka jest ukończona. Jednak te informacje są zapisane
tylko w bazie danych i wyświetlane na stronie profilu użytkownika w
obszarze administracyjnym. Jeżeli chcesz wyświetlić ulubiony wpis bloga
użytkownika, musisz użyć funkcji get_user_meta() w celu pobrania
odpowiednich informacji z bazy danych.

Za pomocą przedstawionego niżej kodu możesz pobrać ulubiony wpis bloga
wybrany przez użytkownika o identyfikatorze 100, a następnie wyświetlić
jego tytuł. Ponieważ identyfikator wpisu bloga jest zapisany w postaci
wartości metadanych, pobranie dodatkowych informacji o wskazanym wpisie
bloga, takich jak jego tytuł, odbywa się za pomocą funkcji get_post().

    <?php
    /* Pobranie identyfikatora ulubionego wpisu bloga użytkownika. */
    $favorite_post = get_user_meta( 100, 'favorite_post', true );
    /* Sprawdzenie, czy użytkownik wybrał swój ulubiony wpis bloga. */
    if ( !empty( $favorite_post ) ) {
        /* Pobranie obiektu wpisu bloga na podstawie pobranego identyfikatora wpisu. */
        $post = get_post( $favorite_post );
        /* Wyświetlenie tytułu wpisu bloga. */
        echo $post->post_title;
    }
    ?> 

Role i możliwości

Jak się przekonałeś, czytając wcześniejszą część rozdziału, platforma
WordPress oferuje elastyczny system użytkowników. Jednak wspomniany
system reprezentuje dane poszczególnych użytkowników; nie definiuje
tego, co użytkownik może zrobić na danej witrynie. Do tego celu na
platformie WordPress zaimplementowano system ról i tzw. możliwości,
które pozwalają na zachowanie pełni kontroli nad uprawnieniami
użytkowników.

Role są tym, co definiuje użytkowników w systemie platformy WordPress.
Ujmując to dokładniej: role nadają użytkownikom zestaw uprawnień
nazywanych możliwościami.

Czym są role i możliwości?

Role to sposób pogrupowania użytkowników platformy WordPress, który
pozwala na nadanie etykiet różnym zbiorom użytkowników. Trzeba
koniecznie zapamiętać, że role nie są hierarchiczne. Przykładowo
administrator niekoniecznie musi mieć większe znaczenie niż redaktor.
Role są zdefiniowane wyłącznie w celu określenia tego, co użytkownik
może i czego nie może zrobić. To rodzaj systemu uprawnień.

Z kolei możliwości są systemem kontroli uprawnień. Role mają przypisane
możliwości, które definiują, co w ramach danej roli można zrobić, a
czego nie można. Istnieje możliwość wykorzystania domyślnych ról
WordPress lub przygotowania całkowicie własnych przeznaczonych dla danej
witryny. Jak twórca wtyczek nie możesz przyjmować zbyt wielu założeń
dotyczących określonych ról i ich uprawnień.

Wyobraź sobie konieczność zdefiniowania możliwości poszczególnych
użytkowników na witrynie, gdzie są ich tysiące, a każdy użytkownik ma
mieć własny zestaw uprawnień. To byłoby praktycznie niemożliwe do
skutecznej obsługi. Role pozwalają na pogrupowanie użytkowników w
oddzielnych grupach, z których każda ma zdefiniowane własne uprawnienia.

Zrozumienie sposobu działania użytkowników, ról, możliwości oraz
związków zachodzących między nimi to kolejny istotny aspekt pracy twórcy
wtyczek.

-   Użytkownicy to konta zarejestrowane na witrynie. Każda rola
    użytkownika określa to, co dany użytkownik może zrobić na witrynie.
-   Rola to zestaw możliwości przypisanych użytkownikom. Użytkownikowi
    można przypisać kilka ról, choć nie jest to takie oczywiste w
    interfejsie platformy WordPress.
-   Możliwości to uprawnienia ról, które są nadawane użytkownikom danej
    roli.

Ogólnie rzecz biorąc, przy opracowywaniu większości wtyczek nie trzeba
znać ról użytkowników. Większość wtyczek pracuje bezpośrednio z
możliwościami, ponieważ to one definiują, czy dany użytkownik może
wykonać określone zadanie na witrynie.

------------------------------------------------------------------------

Ostrzeżenie

Błędem często popełnianym przez twórców wtyczek jest sprawdzenie roli
użytkownika przed wykonaniem kodu. Rzadko istnieje dobry powód, aby to
robić. Wtyczka powinna sprawdzać możliwości, ponieważ to one definiują
uprawnienia użytkownika do przeprowadzenia konkretnej operacji.

------------------------------------------------------------------------

Role domyślne

Platforma WordPress jest standardowo dostarczana wraz z pięcioma rolami,
które sprawdzają się w większości sytuacji. Wprawdzie role nie są
hierarchiczne, ale domyślny zestaw roli wydaje się być systemem
hierarchicznym.

-   Administrator — kontroluje wszystko na witrynie.
-   Editor (redaktor) — ma uprawnienia do publikacji wpisów bloga oraz
    edycji wpisów bloga opublikowanych przez wszystkich użytkowników.
-   Author (autor) — ma uprawnienia do publikacji wpisów bloga oraz
    edycji własnych, ale nie ma dostępu do treści przygotowanej przez
    innych użytkowników.
-   Contributor (współpracownik) — może przekazywać wpisy bloga, ale nie
    może ich publikować.
-   Subscriber (subskrybent) — ma dostęp do swojego profilu oraz kokpitu
    platformy WordPress.

Powyższa lista to ogólny opis ról. Wprawdzie to są role domyślne, ale
użytkownicy wtyczek mogą instalować inne wtyczki pozwalające na
zarządzanie rolami, a następnie za ich pomocą zmieniać możliwości
poszczególnych ról.

------------------------------------------------------------------------

Uwaga

Warto zwrócić uwagę na kontekst, w którym używane jest słowo autor,
ponieważ może się ono odnosić do domyślnej roli WordPress bądź do autora
wpisu bloga. Z reguły to nie jest problem, ale jedna z drobnych wad
platformy WordPress, do której można się przyzwyczaić.

------------------------------------------------------------------------

Własne role

Platforma WordPress pozwala na stosowanie własnych ról, które mogą być
tworzone przez wtyczki i motywy. Platforma nie oferuje interfejsu
przeznaczonego do tworzenia własnych ról, choć istnieje kilka wtyczek
zarządzania rolami, które pozwalają użytkownikom na kreowanie nowych ról
dla swojej witryny.

Z tego powodu, gdy np. jako twórca wtyczki wykonujesz pracę dla klienta
i nie masz bezpośredniego dostępu do instalacji, nigdy nie będziesz
dokładnie wiedział, jakie role mogą istnieć na danej witrynie. Warto o
tym pamiętać podczas tworzenia wtyczek.

Podczas pracy nad wtyczką możesz spotkać się z koniecznością utworzenia
własnych ról. Wyobraź sobie budowanie wtyczki implementującej forum w
ramach instalacji platformy WordPress. Ponieważ WordPress nie wie, w
jaki sposób ma być zarządzane forum, powstaje konieczność zdefiniowania
własnych ról w ramach wtyczki. Niektóre z przykładowych ról dla forum
mogą obejmować:

-   administratora forum;
-   moderatora forum;
-   członka forum;
-   zawieszonego członka forum.

Więcej informacji na temat tworzenia własnych ról znajduje się w dalszej
części rozdziału.

Ograniczanie dostępu

"Ograniczanie dostępu" to sposób opisania procesu pracy z możliwościami
WordPress w celu sprawdzenia, czy użytkownik ma uprawnienia do uzyskania
dostępu do zasobu bądź wykonania określonego zadania w ramach danej
instalacji WordPress.

Domyślnie dostęp do większości zasobów na platformie WordPress jest
ograniczony do administratora. Administrator może ujawnić potencjalnie
ważne informacje dotyczące witryny, więc ważne jest upewnienie się, że
jedynie użytkownicy z odpowiednimi uprawnieniami mają dostęp do
określonych obszarów witryny. Jeśli trzeba, platforma WordPress zajmuje
się obsługą weryfikacji uprawnień. Problemy związane z bezpieczeństwem
pojawiają się, kiedy wtyczka nie uwzględnia możliwości użytkowników.

Platforma WordPress oferuje dwa rodzaje możliwości:

-   możliwości roli — nadawane poszczególnym rolom, a tym samym
    stosowane przez użytkowników znajdujących się w tej roli;
-   możliwości meta — bazują na określonym obiekcie (takim jak
    użytkownik, wpis bloga, odnośnik itd.).

Dobrym sposobem zrozumienia ich rozróżnienia jest przeanalizowanie
przykładu. Użytkownik A otrzymuje możliwość edit_posts (nadaną jego
roli), która pozwala na przeprowadzanie edycji wpisów bloga. Jednak ta
możliwość nie powinna nadawać mu uprawnień do edycji wpisów bloga
użytkownika B. Tutaj z pomocą przychodzą możliwości meta. Jeżeli
użytkownik A spróbuje przeprowadzić edycję wpisu bloga użytkownika B,
nastąpi wywołanie meta możliwości edit_post, ale w rzeczywistości to nie
ta możliwość będzie sprawdzana. Wbudowana funkcja WordPress o nazwie
map_meta_cap() poprzez zwrócenie tablicy możliwości roli sprawdzanej na
podstawie użytkownika i wpisu bloga decyduje, czy użytkownik może
przeprowadzić edycję wpisu bloga.

Podczas dodawania stron ustawień we wtyczce podawane są możliwości.
Jednak proces sprawdzenia jest przeprowadzany przez platformę WordPress,
więc nie musisz się zajmować pisaniem własnego kodu w celu ograniczenia
dostępu do tych stron. Więcej informacji dotyczących dodawania stron
ustawień znajduje się w rozdziale 7.

W tym rozdziale przedstawiono jedynie kilka dostępnych możliwości.
Szczegółowa lista dostępnych możliwości znajduje się na stronie
http://codex.wordpress.org/Roles_and_Capabilities.

Sprawdzanie uprawnień użytkownika

Podczas weryfikacji uprawnień użytkownika sprawdzasz, czy rola
użytkownika ma określone możliwości lub czy użytkownik wyposażony jest w
możliwość meta dotyczącą określonego obiektu. W większości przypadków
wtyczki nie muszą zajmować się możliwościami meta, ale zdarzają się
sytuacje, w których to będzie konieczne.

current_user_can()

Funkcja current_user_can() pozwala sprawdzić, czy aktualnie zalogowany
użytkownik ma uprawnienia do wykorzystania określonej możliwości. Jeżeli
użytkownika ma takie uprawnienia, wartością zwrotną funkcji będzie true.
Gdy natomiast użytkownik nie jest zalogowany lub nie posiada
odpowiednich uprawnień, funkcja zwróci false.

    <?php
    current_user_can( $capability, $args );
    ? 

Parametry:

-   $capability — pojedyncza możliwość, względem której następuje
    sprawdzenie roli użytkownika;
-   $args — argumenty dodatkowe, najczęściej identyfikator obiektu (np.
    identyfikator wpisu bloga), używane podczas sprawdzania, czy
    użytkownika ma możliwość meta.

Powyższą funkcję będziesz wykorzystywał podczas sprawdzania uprawnień z
poziomu wtyczki. Istnieje również sposób użycia do sprawdzenia
domyślnych możliwości WordPress lub własnych zaimplementowanych przez
wtyczkę.

Załóżmy, że przed utworzeniem odnośnika do strony z wpisami bloga w
obszarze administracyjnym witryny chcesz sprawdzić, czy użytkownik ma
uprawnienia do edycji wpisów bloga. W takim przypadku wystarczy wywołać
funkcję current_user_can() względem możliwości edit_posts.

    <?php
    /* Sprawdzenie, czy aktualny użytkownik ma możliwość edycji wpisów bloga. */
    if ( current_user_can( 'edit_posts' ) ) {
        /* Odnośnik prowadzący na stronę edycji wpisów bloga znajdującą się w obszarze administracyjnym. */
        echo '<a href="' . admin_url( 'edit.php' ) . '">Edycja wpisów bloga</a>';
    }
    ?> 

W przypadku konieczności sprawdzenia możliwości meta zastosujesz tę samą
technikę. Jednak w tym przypadku trzeba podać drugi parametr funkcji
current_user_can(), którym jest identyfikator obiektu. Przykładowo
przyjmujemy założenie, że chcesz zapisać pewne metadane wpisu bloga o
identyfikatorze 100, ale przed uaktualnieniem metadanych (więcej
informacji na ten temat znajduje się w rozdziale 11.) musisz sprawdzić,
czy użytkownik ma możliwość edycji wpisu bloga.

    <?php
    /* Sprawdzenie, czy bieżący użytkownik ma możliwość edycji określonego wpisu bloga. */
    if ( current_user_can( 'edit_post', 100 ) {
        /* Uaktualnienie metadanych wpisu bloga. */
        update_post_meta( 100, 'boj_example_meta', 'Example' );
    }
    ?> 

------------------------------------------------------------------------

Ostrzeżenie

Wtyczka nie powinna sprawdzać uprawnień na podstawie roli. Pamiętaj,
role nie są hierarchiczne, więc nie można przyjąć założenia, że rola ma
uprawnienia do wykonania określonego zadania. Uprawnienia zawsze należy
sprawdzać według ich możliwości.

------------------------------------------------------------------------

current_user_can_for_blog()

Funkcja jest przeznaczona do użycia w instalacjach obsługujących wiele
witryn. Działa niemalże w taki sam sposób jak current_user_can(), ale
posiada parametr wskazujący identyfikator bloga.

    <?php
    current_user_can_for_blog( $blog_id, $capability );
    ?> 

Parametry:

-   $blog_id — identyfikator bloga w instalacji obejmującej wiele witryn
    internetowych, względem którego nastąpi sprawdzenie możliwości;
-   $capability — pojedyncza możliwość, względem której następuje
    sprawdzenie roli użytkownika dla danego identyfikatora bloga.

Więcej informacji dotyczących pracy w środowisku obejmującym wiele
witryn internetowych znajduje się w rozdziale 15.

author_can()

Funkcja author_can() działa podobnie jak funkcja current_user_can().
Umożliwia sprawdzenie, czy autor wpisu bloga (nie rola autor) może
wykonać określone zadanie na podstawie możliwości dla danego wpisu
bloga. Funkcja sprawdza autora wpisu bloga i nie jest rozszerzana na
pozostałych użytkowników.

    <?php
    author_can( $post, $capability );
    ?> 

Parametry:

-   $post — obiekt wpisu bloga lub identyfikator wpisu bloga;
-   $capability — pojedyncza możliwość do sprawdzenia względem autora
    wpisu bloga.

W większości przypadków będzie używana funkcja current_user_can().
Jednak funkcja author_can() również ma swoje miejsce i powinna być
używana w sytuacji, gdy trzeba sprawdzić, czy autor wpisu bloga ma
uprawnienia do wykonania określonego zadania.

W przedstawionym poniżej fragmencie kodu następuje sprawdzenie, czy
autor wpisu bloga o identyfikatorze 100 ma uprawnienia do jego
opublikowania. Następnie w zależności od wyniku sprawdzenia wyświetlany
jest odpowiedni komunikat.

    <?php
    /* Sprawdzenie, czy autor wpisu bloga ma uprawnienia do jego publikacji. */
    if ( author_can( 100, 'publish_posts' ) ) {
        /* Wyświetlenie komunikatu. */
        echo 'Autor tego wpisu bloga ma uprawnienia do jego opublikowania.';
    }
    /* Jeżeli autor nie ma uprawnień do publikacji wpisów bloga... */
    else {
        /* Wyświetlenie komunikatu. */
        echo 'Autor tego wpisu bloga nie ma uprawnień do jego opublikowania.';
    }
    ?> 

Powyższa funkcja może być użyteczna w przypadku budowania systemu
powiadomień dla redaktorów i administratorów witryny w celu ich
zawiadomienia o napisaniu nowego wpisu bloga, który czeka na
opublikowanie. W ten sposób użytkownicy posiadający możliwość
publish_post mogą się zalogować i nacisnąć przycisk Opublikuj.

user_can()

Funkcja user_can() działa podobnie do wcześniej omówionych. Różnica
poleca na sprawdzeniu, czy dowolny użytkownik platformy WordPress ma
wskazaną możliwość.

    <?php
    user_can( $user, $capability );
    ?> 

Parametry:

-   $user_id — identyfikator użytkownika lub obiektu, względem którego
    nastąpi sprawdzenie możliwości;
-   $capability — pojedyncza możliwość do sprawdzenia względem danego
    użytkownika.

Tej funkcji będziesz używał tylko wtedy, gdy musisz sprawdzić możliwość
względem autora wpisu bloga lub określonego użytkownika, a nie aktualnie
zalogowanego. Jeżeli użytkownik ma wskazaną możliwość, wartością zwrotną
funkcji będzie true, w przeciwnym razie false.

map_meta_cap()

Zaczep filtru map_meta_cap jest stosowany względem wartości zwrotnej
funkcji map_meta_cap(), która jest funkcją mapującą możliwości roli do
możliwości meta danego obiektu. Przykładowo wymieniona funkcja jest
wywoływana podczas używania funkcji current_user_can() do sprawdzania
możliwości meta. Wartością zwrotną funkcji jest tablica możliwości roli,
które musi mieć rola użytkownika bazująca na możliwości meta i obiekcie.

Aby uprościć powyższy opis, wyobraź sobie, że sprawdzasz, czy określony
użytkownik może przeprowadzić edycję wskazanego wpisu bloga. To zadanie
wykona funkcja map_meta_cap(). Jednak wtyczki mogą nadpisać tę funkcję
przy użyciu zaczepu map_meta_cap.

    <?php
    apply_filters( 'map_meta_cap', $caps, $cap, $user_id, $args );
    ?> 

Parametry:

-   $caps — tablica możliwości, które musi mieć użytkownik. Użytkownik
    musi posiadać każdą możliwość w tablicy, aby funkcja
    current_user_can() zwróciła wartość true.
-   $cap — możliwość meta do sprawdzenia, jeżeli użytkownik może wykonać
    daną operację sprawdzenia.
-   $user_id — identyfikator użytkownika, względem którego ma nastąpić
    sprawdzenie możliwości.
-   $args — tablica argumentów dodatkowych przekazywanych funkcji
    map_meta_cap(). Ogólnie rzecz biorąc, identyfikator obiektu będzie
    pierwszym argumentem tej tablicy.

Wyobraź sobie, że chcesz utworzyć wtyczkę ograniczającą innym
użytkownikom edycję lub usuwanie wpisów bloga administratora. Pamiętaj,
ponieważ role nie są hierarchiczne, każdy użytkownik mający możliwość
edit_others_posts może przeprowadzić edycję wpisów bloga administratora,
a każdy użytkownik z możliwością delete_other_posts może je usuwać.

W tym miejscu utworzysz wtyczkę ograniczającą edycję wpisów bloga
administratora jedynie do użytkowników będących administratorami.
Odbędzie się to poprzez sprawdzenie powiązanej z administratorem
możliwości o nazwie delete_users. W ten sposób użytkownik mający
możliwość edit_others_posts nie będzie mógł edytować wpisów bloga
administratora, a użytkownik z możliwością delete_other_posts nie będzie
mógł usuwać wpisów bloga administratora.

Nadpisana zostanie domyślna funkcjonalność platformy WordPress w celu
wyświetlenia systemu roli w sposób bardziej hierarchiczny.

    <?php
    /*
    Plugin Name: Ograniczenie możliwości edycji wpisów bloga administratora
    Plugin URI: http://przyklad.pl
    Description: Tylko administratorzy mogą edytować wpisy bloga utworzone przez administratorów.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Zarejestrowanie funkcji dla zaczepu filtru map_meta_cap. */
    add_filter( 'map_meta_cap', 'boj_restrict_admin_post_editing', 10, 4 );
    /* Funkcja ograniczająca użytkownikom możliwość edycji wpisów bloga administratorów. */
    function boj_restrict_admin_post_editing( $caps, $cap, $user_id, $args ) {
        /* Jeżeli użytkownik próbuje przeprowadzić edycję wpisu bloga lub go usunąć. */
        if ( 'edit_post' == $cap || 'delete_post' == $cap ) {
            /* Pobranie obiektu wpisu bloga. */
            $post = get_post( $args[0] );
            /* Jeżeli administrator jest autorem wpisu bloga. */
            if ( author_can( $post, 'delete_users' ) ) {
                /* Dodanie możliwości, że tylko administratorzy mogą usuwać tablicę . */
                $caps[] = 'delete_users';
            }
        }
        /* Zwrócenie tablicy z możliwościami. */
        return $caps;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku
boj-restrict-admin-post-editing.php.

------------------------------------------------------------------------

W idealnej sytuacji podczas opracowywania wtyczki budującej tego rodzaju
system hierarchiczny utworzysz własne możliwości i będziesz je
sprawdzać. Własne możliwości zostały przedstawione w dalszej części
rozdziału.

Czy użytkownik jest administratorem?

Czasami wtyczka musi sprawdzić, czy użytkownik jest administratorem na
witrynie. To może być trudne dla twórcy wtyczki, ponieważ role nie są
hierarchiczne. Pamiętaj, użytkownicy w roli "administrator" nie zawsze
mają pełną kontrolę nad witryną. Jednak w większości przypadków
faktycznie ją mają.

Ogólnie rzecz biorąc, nie należy sprawdzać, czy użytkownik jest
administratorem. Lepszym rozwiązaniem będzie sprawdzenie możliwości na
podstawie konkretnego zadania, które użytkownik ma wykonać.

Określenie stanu administratora może być niebezpieczną operacją, jeśli
nie zrozumiesz sposobu działania ról i możliwości, ponieważ nie ma
pojedynczej możliwości definiującej użytkownika jako administratora.
Platforma WordPress oferuje funkcję służącą do sprawdzenia, czy
użytkownik jest administratorem, ale powinna być ona używana tylko
wtedy, gdy nie wiadomo, jaką możliwość użytkownika trzeba sprawdzić.

is_super_admin()

Funkcja is_super_admin() została dodana jako część pakietu
zapewniającego obsługę wielu witryn, ale działa doskonale również w
instalacji WordPress dla pojedynczej witryny. Podaje dokładną
informację, kto jest administratorem na witrynie.

Funkcja akceptuje pojedynczy parametr $user_id będący identyfikatorem
użytkownika, którego status administratora chcesz sprawdzić. Jeżeli
użytkownik jest administratorem, wartością zwrotną funkcji będzie true;
w przeciwnym przypadku false.

W instalacjach obsługujących wiele witryn funkcja is_super_admin()
działa nieco inaczej niż w instalacjach WordPress z pojedynczą witryną.
Superadministrator w środowisku obejmującym wiele witryn ma pełną
kontrolę na witryną. Więcej informacji na temat pracy
superadministratora w środowisku składającym się z wielu witryn znajduje
się w rozdziale 15.

W instalacji z tylko jedną witryną funkcja is_super_admin() sprawdza,
czy bieżący administrator ma możliwość delete_users, ponieważ to ona
daje użytkownikowi największe uprawnienia na witrynie. Można to łatwo
zrobić także za pomocą funkcji current_user_can(). Wydaje się niemal
głupie sprawdzanie, czy ktoś jest administratorem poprzez weryfikację,
czy ma możliwość delete_users, zwłaszcza jeśli zadanie do wykonania nie
ma nic wspólnego z usuwaniem użytkowników.

Przypuśćmy, że przed wykonaniem określonego zadania wtyczka musi
sprawdzić, czy użytkownik o identyfikatorze 100 jest administratorem.
Sprawdzenie można przeprowadzić za pomocą przedstawionego poniżej kodu:

    <?php
    /* Sprawdzenie, czy użytkownik jest administratorem. */
    if ( is_super_admin( 100 ) ) {
        /* Wyświetlenie komunikatu. */
        echo 'Użytkownik 100 jest adminstratorem. */
    }
    ?> 

------------------------------------------------------------------------

Ostrzeżenie

Pamiętaj, że w pewnych własnych konfiguracjach bycie administratorem i
zaliczanie się do roli administratora nie jest tym samym.

------------------------------------------------------------------------

Nadanie własnych uprawnień

Platforma WordPress jest dostarczana z wieloma standardowymi
możliwościami, które rozszerzają całą kontrolę, jakiej przeciętny
użytkownik będzie kiedykolwiek potrzebował. Większość wtyczek nigdy nie
wymaga stosowania własnych możliwości. Jednak pewne wtyczki wykorzystują
własne możliwości w celu kontrolowania uprawnień powiązanych z ich
funkcjonalnością.

Załóżmy, że chcesz utworzyć wtyczkę pozwalającą użytkownikom na
utworzenie za pomocą prostego skrótu (zobacz rozdział 10.) sekcji
prywatnych w treści wpisu bloga. W takim przypadku konieczne jest
opracowanie własnej możliwości do kontrolowania, kto może widzieć
określoną treść. Sprawdzenie wymienionej możliwości będzie odbywało się
za pomocą funkcji current_user_can().

    <?php
    /*
    Plugin Name: Treść prywatna
    Plugin URI: http://przyklad.pl
    Description: Skrót pozwalający na ukrycie treści prywatnej.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Zarejestrowanie skrótu w zaczepie akcji init. */
    add_action( 'init', 'boj_private_content_register_shortcodes' );
    /* Funkcja rejestrująca skrót. */
    function boj_private_content_register_shortcodes() {
        /* Dodanie skrótu [boj-private]. */
        add_shortcode( 'boj-private', 'boj_private_content_shortcode' );
    }
    /* Funkcja obsługująca dane wyjściowe skrótu. */
    function boj_private_content_shortcode( $attr, $content = null ) {
        /* Jeżeli nie ma żadnej treści, zakończ działanie. */
        if ( is_null( $content ) )
            return $content;
        /* Sprawdzenie, czy bieżący użytkownik ma możliwość read_private_content. */
        if ( current_user_can( 'read_private_content' ) ) {
            /* Wygenerowanie treści prywatnej. */
            return $content;
        }
        /* Zwrócenie pustego ciągu tekstowego. */
        return '';
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-private-content.php.

------------------------------------------------------------------------

Autorzy wpisów bloga mogą ukrywać treść, używając skrótu [boj-private] w
edytorze wpisu bloga. Przykładowo autor wpisu bloga może ukryć pewną
treść w następujący sposób:

    [boj-private]
    Ten komunikat zobaczysz tylko wtedy, gdy masz odpowiednie uprawnienia.
    [/boj-private] 

Podczas tworzenia powyższej wtyczki mogłeś zauważyć, że żaden użytkownik
nie ma uprawnień do uzyskania dostępu do treści. Wynika to z faktu, że
żadna rola nie ma przypisanej możliwości read_private_content. Aby
przypisać roli wymienioną możliwość, użytkownik musi zainstalować
wtyczkę służącą do zarządzania rolami lub sama wtyczka po aktywacji musi
przypisać tę możliwość.

Więcej informacji na temat przypisywania możliwości rolom przedstawiono
w dalszej części rozdziału.

Dostosowanie ról do własnych potrzeb

Role platformy WordPress są elastyczne, a wtyczki mogą je stosować w
dowolny sposób wedle wymagań. W tym podrozdziale zostaną omówione tematy
dostosowania ról do własnych potrzeb, tworzenia nowych ról oraz
dodawania możliwości do nowych lub istniejących ról.

Musisz wiedzieć, że wszystkie zmiany dotyczące ról są zapisywane w bazie
danych. Jeżeli wtyczka wprowadzi zmianę, po jej dezaktywacji wprowadzona
zmiana nie będzie cofnięta. Dlatego też wtyczka powinna usuwać własne
możliwości, które zostały dodane, a także wszystkie dodane role, jeśli
do nich nie jest już przypisany żaden użytkownik.

Tworzenie roli

Platforma WordPress pozwala wtyczkom na tworzenie własnych ról.
Najlepszym miejscem na utworzenie nowej roli dla wtyczki jest zaczep
aktywacji wtyczki (zobacz rozdział 2.). Operacja tworzenia roli jest
przeprowadzana jednokrotnie, więc warto wykorzystać wymieniony zaczep,
ponieważ jest wywoływany jedynie podczas aktywacji wtyczki.

add_role()

Funkcja add_role() pozwala twórcy wtyczki na łatwe dodawanie nowych ról.
Jeżeli operacja zakończyła się powodzeniem, wartością zwrotną funkcji
jest obiekt roli. Jeśli natomiast rola już istnieje, wartością zwrotną
będzie null.

    <?php
    add_role( $role, $display_name, $capabilities );
    ?> 

Parametry:

-   $role — nazwa roli do dodania. Powinna działać jako klucz i składać
    się jedynie ze znaków alfanumerycznych i znaków podkreślenia.
-   $display_name — etykieta dla roli. To nazwa roli, która będzie
    używana na wszelkich obszarach publicznych.
-   $capabilities — tablica możliwości przypisanych danej roli.
    Możliwości można również dodać lub usunąć później.

Powróćmy teraz na chwilę do przykładu przedstawionego w poprzednim
podrozdziale, w którym wymieniono cztery role, jakie mogłyby zostać
zdefiniowane przez wtyczkę obsługującą forum. Chodzi tu o role:

-   administratora forum;
-   moderatora forum;
-   członka forum;
-   zawieszonego członka forum.

W poniższym fragmencie kodu następuje utworzenie tych ról i nadanie im
podstawowej możliwości read, która pozwala użytkownikowi jedynie na
wyświetlenie profilu oraz kokpitu administratora.

    <?php
    /* Utworzenie roli administratora forum. */
    add_role( 'forum_administrator', 'Administrator forum', array( 'read' ) );
    /* Utworzenie roli moderatora forum. */
    add_role( 'forum_moderator', 'Moderator forum', array( 'read' ) );
    /* Utworzenie roli członka forum. */
    add_role( 'forum_member', 'Członek forum', array( 'read' ) );
    /* Utworzenie roli zawieszonego członka forum. */
    add_role( 'forum_suspended', 'Zawieszony członek forum', array( 'read' ) );
    ?> 

Nowa rola po dodaniu pojawia się w rozwijanym menu na stronie profilu
użytkownika, jak pokazano na rysunku 8.3, a także na stronie Użytkownicy
w obszarze administracyjnym.

Usunięcie roli

Przy użyciu odpowiedniej funkcji WordPress usunięcie roli jest równie
łatwe jak jej dodanie. Gdy jednak wtyczka musi usunąć rolę, wówczas
przed jej usunięciem powinna sprawdzić, czy żaden inny użytkownik na
witrynie nie należy do danej roli. W przeciwnym razie można doprowadzić
do uszkodzenia własnej konfiguracji przygotowanej przez użytkownika.

Najlepszym miejscem na usunięcie roli jest zaczep aktywacji lub
dezaktywacji wtyczki (zobacz rozdział 2.). Usunięcie roli trzeba
przeprowadzić tylko jednokrotnie, więc warto wykorzystać wymieniony
zaczep, ponieważ jest wywoływany jedynie podczas aktywacji lub
dezaktywacji wtyczki.

[]

Rysunek 8.3. Nowo dodane role pojawiają się w rozwijanym menu

remove_role()

Funkcja remove_role() może usunąć rolę z zapisanej w bazie danych listy
ról. Akceptuje jeden parametr $role, który jest nazwą roli (nie etykietą
lub nazwą wyświetlaną publicznie) przeznaczonej do usunięcia.

Przypuśćmy, że chcesz usunąć rolę Moderator forum utworzoną w poprzednim
przykładzie. W tym celu parametr $role powinien otrzymać wartość
forum_moderator.

    <?php
    /* Usunięcie roli Moderator forum. */
    remove_role( 'forum_moderator' );
    ?> 

Jeżeli przed usunięciem roli chcesz sprawdzić, czy znajduje się w niej
jakikolwiek użytkownik, musisz wykorzystać przedstawioną wcześniej
funkcję get_users(). Jeżeli funkcja nie zwróci żadnego użytkownika,
wtedy można usunąć rolę. Gdy natomiast funkcja zwróci jakiegokolwiek
użytkownika, wtedy tę rolę trzeba pozostawić.

    <?php
    add_action( 'admin_init', 'boj_remove_forum_moderator' );
    function boj_remove_forum_moderator() {
        /* Pobranie przynajmniej jednego użytkownika znajdującego się w roli forum_moderator. */
        $users = get_users( array( 'role' => 'forum_moderator', 'number' => 1 ) );
        /* Sprawdzenie, czy w tej roli są inni użytkownicy. */
        if ( empty( $users ) ) {
            /* Usunięcie roli Moderator forum. */
            remove_role( 'forum_moderator' );
        }
    }
    ?> 

Na potrzeby omawianego przykładu powyższy kod został wywołany przez
zaczep admin_init, który platforma WordPress wywołuje na każdej stronie
administracyjnej. W rzeczywistości kod ten powinien być wykonany tylko
jednokrotnie, prawdopodobnie w zaczepie dezaktywacji wtyczki. Wspomniany
zaczep zostanie wykorzystany podczas tworzenia wtyczki w dalszej części
rozdziału.

Dodanie możliwości do roli

Podobnie jak można tworzyć własne role, tak samo można kreować własne
możliwości. Platforma pozwala także na dodawanie możliwości WordPress do
nowych lub istniejących ról. Z technicznego punktu widzenia możliwość
nie istnieje, jeśli nie jest przypisana do roli. Wtyczka powinna dodawać
możliwości do roli tylko jednokrotnie. Oznacza to, że najczęściej
odpowiedzialny za to kod jest wykonywany w zaczepie aktywacji wtyczki
(zobacz rozdział 2.).

get_role()

W celu dodania możliwości do roli trzeba najpierw pobrać obiekt roli
zwracany przez funkcję get_role(). Funkcja akceptuje pojedynczy parametr
$role będący nazwą roli. Po otrzymaniu obiektu roli należy użyć metody
add_cap() w celu nadania roli określonej możliwości.

Przypuśćmy, że domyślnej roli WordPress o nazwie contributor
(współpracownik) chcesz dodać możliwość publikowania wpisów bloga. Tę
zmianę można przeprowadzić za pomocą poniższego kodu.

    <?php
    /* Pobranie roli contributor. */
    $role = &  get_role( 'contributor' );
    /* Sprawdzenie, czy rola istnieje. */
    if ( !empty( $role ) ) {
        /* Dodanie do roli możliwości publish_posts. */
        $role->add_cap( 'publish_posts' );
    }
    ?> 

Powróćmy teraz do pomysłu wtyczki zapewniającej obsługę forum i własnych
ról dodanych z poprzedniego punktu: za pomocą powyższej metody możesz
bardzo łatwo dodać do tych ról nowe możliwości. Przyjmijmy założenie, że
roli administratora forum chcesz dodać dwie możliwości o nazwach
publish_forum_topics i delete_forum_topics.

    <?php
    /* Pobranie roli administratora forum. */
    $role = & get_role( 'forum_administrator' );
    /* Sprawdzenie, czy rola istnieje. */
    if ( !empty( $role ) ) {
        /* Dodanie do roli możliwości publish_forum_topics. */
        $role->add_cap( 'publish_forum_topics' );
        /* Dodanie do roli możliwości delete_forum_topics. */
        $role->add_cap( 'delete_forum_topics' );
    }
    ?> 

Usuwanie możliwości z roli

Platforma WordPress jest pomocna także podczas usuwania możliwości z
roli. Za każdym razem, gdy tworzysz wtyczkę przypisującą własne
możliwości do użycia we wtyczce, powinieneś również zadbać o
posprzątanie po sobie i usunięcie wszystkich dodanych możliwości.
Operacja usunięcia możliwości z wtyczki powinna być przeprowadzona tylko
jednokrotnie, a nie w trakcie każdego wczytywania strony. Najlepszym
miejscem na umieszczenie odpowiedzialnego za to kodu jest zaczep
aktywacji lub dezaktywacji wtyczki (zobacz rozdział 2.).

Podobnie jak w przypadku dodawania możliwości, najpierw za pomocą
funkcji get_role() trzeba pobrać rolę, z której mają być usunięte
możliwości. Różnica polega na tym, że do usunięcia możliwości z roli
używana jest metoda remove_cap().

W poprzednim podpunkcie do roli współpracownika dodano możliwość
publish_posts. W metodzie dezinstalacji wtyczki lub w zaczepie
dezaktywacji wtyczki (zobacz rozdział 2.) trzeba tę możliwość usunąć.

    <?php
    /* Pobranie roli contributor. */
    $role =& get_role( 'contributor' );
    /* Sprawdzenie, czy rola istnieje. */
    if ( !empty( $role ) ) {
        /* Usunięcie z roli możliwości publish_posts. */
        $role->remove_cap( 'publish_posts' );
    }
    ?> 

Wtyczka obsługująca własne role i możliwości

Po zapoznaniu się ze sposobem tworzenia własnych ról i możliwości warto
tę wiedzę wykorzystać praktycznie. W tym punkcie zostanie zbudowana
wtyczka łącząca w sobie omówione wcześniej funkcje.

Punktem wyjścia jest wtyczka przeznaczona do obsługi forum, o której
kilkakrotnie wspominano w rozdziale. Przed rozpoczęciem tworzenia kodu
trzeba określić możliwości, które powinny posiadać poszczególne role.
Ponieważ możliwości obsługują uprawnienia, należy zdefiniować to, na co
pozwalają poszczególne możliwości. Poniżej przedstawiono opis czterech
fikcyjnych możliwości, które mogłyby się znaleźć we wtyczce
przeznaczonej do obsługi forum (rzeczywista wtyczka tego typu
prawdopodobnie będzie miała ich znacznie więcej):

-   publish_forum_topics — uprawnienia do publikowania nowych tematów na
    forum;
-   edit_others_forum_topics — uprawnienia do edycji tematów na forum
    utworzonych przez innych użytkowników;
-   delete_forum_topics — uprawnienia do usuwania tematów opublikowanych
    na forum;
-   read_forum_topics — uprawnienia do czytania tematów opublikowanych
    na forum.

Po naszkicowaniu możliwości można się skoncentrować na tym, które role
powinny mieć poszczególne możliwości. W tym miejscu zostaną wykorzystane
własne role przedstawione wcześniej oraz domyślna rola administratora
WordPress.

-   Administrator — domyślna rola administratora w WordPress powinna
    mieć wszystkie wymienione wcześniej możliwości dotyczące forum.
-   Administrator forum — powinien mieć wszystkie wymienione wcześniej
    możliwości, aby zachować pełną kontrolę nad forum.
-   Moderator forum — powinien mieć możliwości publish_forum_topics,
    edit_others_forum_topics oraz read_forum_topics.
-   Członek forum — powinien mieć możliwości publish_forum_topics i
    read_forum_topics.
-   Zawieszony członek forum — ponieważ to zawieszony użytkownik,
    powinien mieć jedynie możliwość read_forum_topics.

Tworzona jest rola administratora forum, aby użytkownicy wtyczki nie
musieli łączyć tej roli ze zwykłą rolą administratora, a tym samym nie
byli zmuszeni do udzielania administratorom forum pełnego dostępu do
witryny.

Po przygotowaniu założeń ról i możliwości używanych we wtyczce można
przystąpić do jej utworzenia.

    <?php
    /*
    Plugin Name: Role dla forum
    Plugin URI: http://przyklad.pl
    Description: Tworzy role i możliwości dla fikcyjnej wtyczki obsługi forum.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Utworzenie klasy ról i możliwości forum. */
    class BOJ_Forum_Roles {
        /* Metoda konstruktora PHP4. */
        function BOJ_Forum_Roles() {
            /* Rejestracja zaczepu aktywacji wtyczki. */
            register_activation_hook( __FILE__, array( &$this, 'activation' ) );
            /* Rejestracja zaczepu dezaktywacji wtyczki. */
            register_deactivation_hook( __FILE__, array( &$this, 'deactivation' ) );
        }
        /* Metoda aktywacji wtyczki. */
        function activation() {
            /* Pobranie domyślnej roli administratora. */
            $role =& get_role( 'administrator' );
            /* Dodanie do roli administratora możliwości z zakresu obsługi forum. */
            if ( !empty( $role ) ) {
                $role->add_cap( 'publish_forum_topics' );
                $role->add_cap( 'edit_others_forum_topics' );
                $role->add_cap( 'delete_forum_topics' );
                $role->add_cap( 'read_forum_topics' );
            }
            /* Utworzenie roli administratora forum. */
            add_role(
                'forum_administrator',
                'Administrator forum',
                array(
                    'publish_forum_topics',
                    'edit_others_forum_topics',
                    'delete_forum_topics',
                    'read_forum_topics'
                )
            );
            /* Utworzenie roli moderatora forum. */
            add_role(
                'forum_moderator',
                'Moderator forum',
                array(
                    'publish_forum_topics',
                    'edit_others_forum_topics',
                    'read_forum_topics'
                )
            );
            /* Utworzenie roli członka forum. */
            add_role(
                'forum_member',
                'Członek forum',
                array(
                    'publish_forum_topics',
                    'read_forum_topics'
                )
            );
            /* Utworzenie roli zawieszonego członka forum. */
            add_role(
                'forum_suspended',
                'Zawieszony członek forum',
                array( 'read_forum_topics' )
            );
        }
        /* Metoda dezaktywacji wtyczki. */
        function deactivation() {
            /* Pobranie domyślnej roli administratora. */
            $role =& get_role( 'administrator' );
            /* Usunięcie możliwości z roli administratora. */
            if ( !empty( $role ) ) {
                $role->remove_cap( 'publish_forum_topics' );
                $role->remove_cap( 'edit_others_forum_topics' );
                $role->remove_cap( 'delete_forum_topics' );
                $role->remove_cap( 'read_forum_topics' );
            }
            /* Przygotowanie tablicy ról do usunięcia. */
            $roles_to_delete = array(
                'forum_administrator',
                'forum_moderator',
                'forum_member',
                'forum_suspended'
            );
            /* Iteracja przez każdą rolę i jej usunięcie. */
            foreach ( $roles_to_delete as $role ) {
                /* Pobranie użytkowników roli. */
                $users = get_users( array( 'role' => $role ) );
                /* Sprawdzenie, czy w roli znajduje się jakikolwiek użytkownik. */
                if ( count( $users ) <= 0 ) {
                    /* Usunięcie roli z witryny. */
                    remove_role( $role );
                }
            }
        }
    }
    $forum_roles = new BOJ_Forum_Roles();
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-forum-roles.php.

------------------------------------------------------------------------

Powyższa wtyczka powoduje udostępnienie na stronie Użytkownicy w
obszarze administracyjnym czterech dodatkowych ról, jak pokazano na
rysunku 8.4. Dzięki temu użytkownicy wtyczki mogą dodawać dowolnych
użytkowników przeznaczonych do obsługi forum.

[]

Rysunek 8.4. Utworzona powyżej wtyczka w działaniu

Podsumowanie

Systemy użytkowników, ról oraz możliwości oferowane przez platformę
WordPress są potężne i elastyczne, a także pozwalają na zbudowanie
dowolnego rodzaju wtyczki w celu zmiany ich sposobu działania. W każdym
podrozdziale pokrótce opisano poszczególne systemy. Jako twórca wtyczek
możesz przygotować instalację testową wraz z wieloma fikcyjnymi
użytkownikami testowymi. Następnie wykorzystaj wiedzę zdobytą w
rozdziale i rozpocznij tworzenie kodu.

Z lektury rozdziału powinieneś zapamiętać, w jaki sposób funkcjonują
związki pomiędzy użytkownikami, rolami i możliwościami. Możliwości
kontrolują uprawnienia. Role są nadanymi możliwościami. Użytkownicy są
przypisywani do ról, a możliwości każdej roli przechodzą na jej
użytkowników. Pamiętając o tym podczas tworzenia własnych wtyczek,
znacznie ułatwisz sobie pracę.

Rozdział 9 API HTTP

W tym rozdziale:

-   Poznanie żądań HTTP
-   Wykonywanie żądań HTTP na platformie WordPress
-   Używanie w blogu API firm zewnętrznych
-   Odczytywanie odpowiedzi serwera w różnych formatach
-   Tworzenie własnego zdalnego API

W nowoczesnej sieci określonej mianem 2.0 bazujące na internecie usługi
komunikują się między sobą: czytniki pobierają dane z kanałów RSS blogów
i kont serwisu Twitter, a prywatne witryny internetowe wyświetlają
plakietki Facebooka lub wideo YouTube.

Twoja witryna nie powinna być wyjątkiem i również może wykorzystywać
takie możliwości współpracy usług. W tym rozdziale dowiesz się, jak
platforma WordPress może wymieniać informacje z API zdalnych serwerów i
utworzyć w ten sposób całkiem nową gamę możliwości.

Szybki kurs wykonywania żądań HTTP

W tym podrozdziale zostanie wyjaśnione, czym tak naprawdę jest żądanie
HTTP, do czego może być używane oraz dlaczego raz jeszcze podziękujesz
platformie WordPress za pomocną dłoń i wykonywanie za Ciebie
niewygodnych zadań.

Czym jest żądanie HTTP?

Hyper Text Transfer Protocol (HTTP) to protokół sieciowy, który stanowi
podstawę dla komunikacji danych w internecie.

Koncepcje żądania HTTP

Jeśli nawet nie potrafisz wymienić lub wyjaśnić poniższych koncepcji, to
i tak się z nimi spotkałeś podczas codziennej pracy z internetem, kiedy
używałeś przeglądarki internetowej: HTTP to protokół typu
żądanie-odpowiedź w modelu klient-serwer.

-   Klient-serwer — aplikacja (klient) komunikuje się z inną aplikacją
    (serwer), która w tym samym czasie może udzielać odpowiedzi wielu
    klientom. W modelu HTTP klient jest np. przeglądarką internetową,
    taką jak Firefox uruchomioną w Twoim komputerze. Natomiast serwer to
    serwer WWW bazujący np. na oprogramowaniu Apache, PHP i MySQL wraz z
    uruchomioną platformą WordPress. Klient może być też robotem
    indeksującym internet lub skryptem PHP, który pobiera i przetwarza
    stronę internetową w celu wyodrębnienia pewnych informacji. To
    ostatnie zadanie przeprowadzisz w dalszej części rozdziału.
-   Protokół typu żądanie-odpowiedź — klient wykonuje żądanie HTTP (np.
    w postaci "Cześć, jestem przeglądarka Firefox, proszę wyślij mi plik
    przyklad.html"), a serwer udziela odpowiedzi na to żądanie (np. w
    postaci "Cześć, jestem serwer Apache z uruchomionym PHP, tutaj masz
    żądany plik, jego wielkość to 4 kB", a następnie w odpowiedzi
    znajduje się wskazany plik). Obydwa żądania zawierają potencjalnie
    interesujące informacje, których sposób rozszyfrowania i używania
    poznasz w rozdziale.

Szczegółowa analiza transakcji HTTP

Transakcja HTTP to prosta komunikacja tekstowa pomiędzy klientem i
serwerem.

Klient wysyła żądanie

Żądanie klienta najczęściej składa się z kilku wierszy wysłanych do
serwera w postaci zwykłego tekstu. Przy użyciu przeglądarki internetowej
Firefox i próbie wczytania fikcyjnej strony http://przyklad.pl/plik.html
ze strony wyników Google żądanie może przybrać następującą postać:

    GET /plik.html HTTP/1.1
    Host: www.przyklad.pl
    User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0) Firefox/3.6
    Referer: http://www.google.com/search?q=przyklad.pl
    Cookie: lastvisit=235456684 

Pierwszy wiersz rozpoczyna się od GET: sesja GET to sposób
poinformowania serwera o chęci pobrania dokumentu (tutaj plik.html) z
serwera przyklad.pl. Inne główne metody żądania, których można użyć,
obejmują HEAD (w celu otrzymania jedynie nagłówków odpowiedzi serwera) i
POST (wysłanie danych formularza).

Warto również zwrócić uwagę na sposób wysyłania przez klienta
informacji, takich jak poprzednio odwiedzony adres URL oraz ciąg
tekstowy agenta użytkownika. W rozdziale 6. dowiedziałeś się, że tym
danym nie wolno ufać. To prawda, w przykładzie przedstawionym w dalszej
części rozdziału zobaczysz, jak wymienione informacje można sfałszować,
aby zawierały dowolne wartości.

Serwer udziela odpowiedzi

Odpowiedź udzielana przez serwer składa się z trzech części: nagłówka
wraz z informacjami dotyczącymi odpowiedzi, pustego wiersza oraz
właściwej odpowiedzi.

Nagłówek to kilka wierszy informacji, które mogą być w następującej
postaci:

    HTTP/1.1 200 OK
    Date: Mon, 23 May 2012 22:38:34 GMT
    Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)
    Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
    Set-Cookie: lastvisit=235456951
    Content-Length: 438
    Content-Type: text/html; charset=UTF-8

Pierwszą interesującą informacją jest kod stanu, w tym przypadku 200.
Każda odpowiedź serwera powinna zawierać kod stanu, który dostarcza
szczegółowych informacji na temat sposobu obsłużenia transakcji przez
serwer. Kod 200 oznacza, że wszystko jest w porządku, 404 — że nie
znaleziono żądanego zasobu. Najważniejsze kody stanu HTTP wymieniono w
tabeli 9.1.

Tabela 9.1. Najważniejsze kody stanu HTTP

  ----------- ------------------------------
  Kod stanu   Opis
  200         Wszystko w porządku.
  301         Zasób przeniesiony na stałe.
  302         Zasób przeniesiony czasowo.
  403         Dostęp do zasobu zabroniony.
  404         Zasób nie został znaleziony.
  500         Wewnętrzny błąd serwera.
  503         Usługa niedostępna.
  ----------- ------------------------------

Źródło: http://pl.wikipedia.org/wiki/Kod_odpowiedzi_HTTP.

Oczywiście, nie trzeba pamiętać wszystkich kodów stanu, ale przy
odrobinie wysiłku można szybko opanować najważniejsze klasy wymienione w
tabeli 9.2.

Tabela 9.2. Klasy kodów odpowiedzi HTTP

  ----------- -----------------------------------------------------------------------------------------------------------------------------------------------
  Kod stanu   Opis
  2xx         Żądanie zakończone powodzeniem.
  3xx         Żądanie zostało przekierowane do innego zasobu (np. do skróconego adresu URL).
  4xx         Żądanie zakończyło się niepowodzeniem ze względu na błąd klienta (np. w wyniku podania nieprawidłowej kombinacji nazwy użytkownika i hasła).
  5xx         Żądanie zakończyło się niepowodzeniem ze względu na błąd serwera (np. w wyniku nieprawidłowej konfiguracji serwera lub uszkodzonego skryptu).
  ----------- -----------------------------------------------------------------------------------------------------------------------------------------------

Odpowiedź serwera zwykle zawiera informacje dotyczące oprogramowania
działającego w serwerze, typu udostępnianego dokumentu oraz jego
wielkości.

Wykorzystywanie żądań HTTP

Pierwszym oczywistym sposobem użycia żądania HTTP jest pobranie zdalnego
dokumentu lub określonej informacji ze zdalnego dokumentu: ostatniej
wiadomości opublikowanej przez użytkownika w serwisie Twitter, bieżącej
wartości udziału giełdowego lub zakodowanych w formacie JSON danych z
API zdalnej usługi.

Istnieje możliwość wysłania informacji do zdalnego dokumentu, takiego
jak formularz lub API HTTP, oraz modyfikacji danych z poziomu skryptu
klienta.

Żądanie jest wykonywane za pomocą metod GET lub POST, czasami wraz z
podaniem danych uwierzytelniających (nazwa użytkownika i hasło lub w
postaci innego mechanizmu uwierzytelniania) bądź też innych parametrów.
Sposób wykonywania tego typu żądań zostanie omówiony w dalszej części
rozdziału.

Inna interesująca aplikacja używającą żądań HEAD to taka, która sprawdza
stan zdalnego dokumentu bez jego pobierania. Przykładowo wtyczka
wyszukująca uszkodzone odnośniki pozwoli upewnić się, że ulubione
zakładki zapisane w WordPress nie będą zwracały kodu stanu 404.

Jak wykonywać żądania HTTP w PHP?

W samym języku PHP, tzn. bez zainstalowanej platformy WordPress,
istnieje kilka sposobów wykonywania żądań HTTP. Warto poznać te
podstawowe metody, ponieważ czasami trzeba utworzyć fragment kodu poza
środowiskiem WordPress.

Przedstawione poniżej przykłady wykonują to samo zadanie: wysyłają
żądanie GET do witryny http://wordpress.org i wyświetlają pobraną treść
(tzn. stronę główną).

Użycie rozszerzenia HTTP

W celu wykonania żądania GET do witryny http://wordpress.org i
wyświetlenia pobranej treści można wykorzystać rozszerzenie HTTP.

    <?php
    $r = new HttpRequest( 'http://wordpress.org/', HttpRequest::METH_GET );
    $r->send() ;
    echo $r->getResponseBody();
    ?> 

Użycie strumienia fopen()

W celu wykonania żądania GET do witryny http://wordpress.org i
wyświetlenia pobranej treści można również użyć funkcji strumienia
fopen().

    <?php
    if( $stream = fopen( 'http://wordpress.org/', 'r' ) ) {
     echo stream_get_contents( $stream );
     fclose($stream);
    }
    ?> 

Użycie standardowej funkcji fopen()

W celu wykonania żądania GET do witryny http://wordpress.org i
wyświetlenia pobranej treści można użyć standardowej funkcji fopen().

    <?php
    $handle = fopen( "http://wordpress.org/", "rb" );
    $contents = '';
    while( !feof( $handle ) ) {
     $contents .= fread( $handle, 8192 );
    }
    fclose( $handle );
    echo $contents;
    ?> 

Użycie funkcji fsockopen()

W celu wykonania żądania GET do witryny http://wordpress.org i
wyświetlenia pobranej treści można użyć funkcji fsockopen().

    <?php
    $fp = fsockopen( "wordpress.org", 80, $errno, $errstr, 30 );
    if (!$fp) {
     echo "$errstr ($errno) <br />\n";
    } else {
     $out = "GET / HTTP/1.1\r\n";
     $out .= "Host: wordpress.org\r\n";
     $out .= "Connection: Close\r\n\r\n";
     fwrite($fp, $out);
     while (!feof($fp)) {
     echo fgets($fp, 128);
     }
     fclose($fp);
    }
    ?> 

Użycie rozszerzenia CURL

W celu wykonania żądania GET do witryny http://wordpress.org i
wyświetlenia pobranej treści można użyć także rozszerzenia CURL.

    <?php
    $ch = curl_init();
    curl_setopt( $ch, CURLOPT_URL, "http://wordpress.org/" );
    curl_setopt( $ch, CURLOPT_HEADER, 0 );
    curl_exec($ch);
    curl_close($ch);
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku http_request_tests.php.

------------------------------------------------------------------------

Zbyt wiele sposobów?

Każdy sposób ma swoje wady i zalety: niektóre są proste i szybkie do
utworzenia, inne pozwalają na użycie większej liczby parametrów czy
dokładniejszą kontrolę nad żądaniem, obsługują różne metody wykonywania
żądań lub są szybsze do wykonania. Warto zwrócić uwagę, jak uciążliwe w
porównaniu do użycia strumienia lub rozszerzenia HTTP jest wykorzystanie
funkcji fsockopen() wymagającej pełnych nagłówków żądania.

Problem jest następujący: w zależności od możliwości i konfiguracji
serwera, wersji PHP i ustawień bezpieczeństwa niektóre metody będą
niedozwolone lub nawet niedostępne. Podczas pracy dla konkretnego
klienta trzeba dostosować się do istniejącej, specyficznej architektury
serwera i użyć metod, które będą działały. Takie podejście jest jednak
po prostu niemożliwe podczas tworzenia wtyczki udostępnianej publicznie
szerokiej rzeszy użytkowników.

Wybór sprowadza się do prostego rozwiązania: albo przetestuj metodę
przed jej użyciem, albo wykorzystaj API HTTP oferowane przez platformę
WordPress.

Funkcje obsługi HTTP oferowane przez WordPress

Platforma WordPress implementuje sprytną i użyteczną klasę o nazwie
WP_Http znajdującą się w pliku wp-includes/class-http.php, która może
przetestować wcześniej wymienione metody, a następnie wybrać najlepszą
dla bieżącego komputera.

API HTTP obsługuje wszystkie metody, których trzeba będzie używać (GET,
POST i HEAD), i umożliwia dostosowanie do własnych potrzeb wielu
parametrów, takich jak tunelowanie proxy.

------------------------------------------------------------------------

Uwaga

Do wykonywania żądań HTTP nie wykorzystuj rodzimych metod PHP. Pamiętaj,
mogą być one niedostępne lub zabronione w wielu konfiguracjach serwerów
WWW. Zawsze korzystaj z API HTTP oferowanego przez platformę WordPress i
jego funkcji, które omówiono poniżej.

------------------------------------------------------------------------

Funkcje rodziny wp_remote_*

Żądanie HTTP na platformie WordPress można wykonać za pomocą trzech
funkcji: wp_remote_ get(), wp_remote_post() i wp_remote_head(), które
odpowiednio wykonują żądania GET, POST i HEAD.

Wszystkie funkcje działają w taki sam sposób:

-   żądanie HTTP jest wykonywane za pomocą tytułowej metody;
-   akceptowane są dwa parametry: wymagany i opcjonalny;
-   wartością zwrotną jest tablica lub obiekt.

Składnia wszystkich trzech funkcji jest następująca:

    <?php
    $get_result = wp_remote_get( $url, $args );
    $post_result = wp_remote_post( $url, $args );
    $head_result = wp_remote_head( $url, $args );
    ?> 

Wszystkie funkcje można uznać za proste skróty bardziej ogólnej funkcji
wp_remote_request(). Faktycznie, trzy powyższe wiersze odpowiadają trzem
poniższym:

    <?php
    $get_result = wp_remote_request( $url, array( 'method' => 'GET' ) );
    $post_result = wp_remote_request( $url, array( 'method' => 'POST' ) );
    $head_result = wp_remote_request( $url, array( 'method' => 'HEAD' ) );
    ?> 

Funkcja wp_remote_request() działa dokładnie tak samo jak pozostałe
funkcje wp_remote_*, więc przedstawione poniżej informacje mają
zastosowanie również w stosunku do dowolnej funkcji wp_remote_*.

Teraz poznasz nieco dokładniej wspomniane funkcje: ich parametry,
zwracane dane oraz sposoby wykorzystywania.

Parametry wejściowe funkcji wp_remote_*

Pierwszym parametrem tych funkcji jest $url. To ciąg tekstowy
reprezentujący poprawny adres URL witryny, względem której zostanie
wykonane żądanie HTTP. Obsługiwane protokoły to HTTP i HTTPS. Czasami
obsługiwane są także inne protokoły, np. FTP, ale nie należy przyjmować
takiego założenia.

Drugi parametr — $args — jest opcjonalną tablicą parametrów, które mają
nadpisać parametry domyślne. Wspomniane parametry domyślne znajdują się
w następującej tablicy:

    <?php
    $defaults = array (
     'method' => 'GET',
     'timeout' => 5,
     'redirection' => 5,
     'httpversion' => '1.0',
     'user-agent' => 'WordPress/3.1; http://przyklad.pl/',
     'blocking' => true,
     'headers' => array (),
     'cookies' => array (),
     'body' => NULL,
     'compress' => false,
     'decompress' => true,
     'sslverify' => true,
    )
    ?> 

Powyższa tablica zawiera wartości domyślne parametrów, które są używane,
gdy w żądaniu nie podasz innych. Przykładowo zamiast identyfikować blog
w ciągu tekstowym agenta użytkownika oraz aby odróżnić żądanie HTTP od
wykonanego przez ogólną przeglądarkę internetową, można użyć
przedstawionego poniżej kodu:

    <?php
    $args = array(
     'user-agent' => 'Mozilla/5.0 (Windows NT 5.1; en-US) Firefox/3.6.8',
    );
    $result = wp_remote_get( $url, $args );
    ?> 

W rozdziale 6. dowiedziałeś się, że pomimo budzącej zaufanie nazwy,
tablicy $_SERVER wygenerowanej przez PHP nie wolno ufać. Jak możesz się
przekonać, umieszczenie w niej dowolnej wartości następuje po utworzeniu
pojedynczego wiersza kodu PHP, np. $_SERVER['HTTP_USER_AGENT'].

W tabeli 9.3 przedstawiono dokładne omówienie najważniejszych wartości
domyślnych parametrów. Pozostałe możesz uznać za częściowo
zaimplementowane, nie zawsze funkcjonujące lub po prostu mniej ważne.

Tabela 9.3. Wartości domyślne opcjonalnych parametrów funkcji
wp_remote_*

  ------------ -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  Parametr     Opis
  method       To GET, POST lub HEAD. Czasami (np. dzięki rozszerzeniu HTTP lub CURL) dozwolone jest użycie innych, rzadziej używanych metod, takich jak PUT lub TRACE, ale nie należy przyjmować założenia o ich dostępności.
  timeout      Liczba sekund, po upływie których otwarte połączenie zostanie zerwane, jeśli w tym czasie nie nastąpiło udzielenie odpowiedzi.
  user-agent   Agent użytkownika jest stosowany w celu identyfikacji "kto" wykonuje żądanie. Wartością domyślną jest "WordPress/", wersja platformy oraz adres URL bloga wykonującego żądanie.
  headers      Tablica nagłówków dodatkowych.
  cookies      Tablica wartości cookies przekazanych do serwera.
  body         Część główna żądania w postaci ciągu tekstowego lub tablicy. Te dane zostaną przekazane na wskazany adres URL.
  ------------ -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Wartości zwrotne funkcji wp_remote_*

Jeżeli żądanie zostanie wykonane z powodzeniem, wszystkie funkcje
wp_remote_* zwracają tablicę. W przeciwnym razie wartością zwrotną
będzie obiekt błędu.

Żądania HTTP zakończone niepowodzeniem

W przypadku nieprawidłowego żądania HTTP lub jeśli żądanie nie będzie
mogło zostać wykonane z innego powodu (np. witryna nie odpowiada,
tymczasowy problem z połączeniem itd.), wynikiem będzie egzemplarz
obiektu klasy WordPress o nazwie WP_Error zawierający kod oraz komunikat
błędu, co przedstawiono w poniższym fragmencie kodu:

    <?php
    var_dump( wp_remote_get( 'nieprawidlowy-adres-url' ) );
    ?> 

Wynikiem wykonania powyższego kodu będzie nieprawidłowe żądanie GET,
np.:

    object(WP_Error)#259 (2) {
     ["errors"]=> 
     array(1) {
     ["http_request_failed"]=> 
     array(1) {
     [0]=> 
     string(29) "Podano niepoprawny adres URL."
     }
     }
     ["error_data"]=> 
     array(0) {
     }
    } 

Obiekty błędów zwracane przez żądania HTTP zawierają kod błędu
http_request_failed oraz czytelne dla użytkownika wyjaśnienie błędu.
Warto przeanalizować przedstawiony poniżej fragment kodu:

    <?php
    $bad_urls = array(
     'nieprawidlowy',
     'http://0.0.0.0/',
     'irc://przyklad.pl/',
     'http://nieistniejacy',
    );
    foreach( $bad_urls as $bad_url ) {
     $response = wp_remote_head( $bad_url, array('timeout'=> 1) );
     if( is_wp_error( $response ) ) {
     $error = $response->get_error_message();
     echo "<p>Adres $bad_url zwrócił komunikat: <br /> $error </p>";
     }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku wp_remote_errors.php.

------------------------------------------------------------------------

W powyższym fragmencie kodu warto zwrócić uwagę na kilka rzeczy.

-   W celu przyśpieszenia wykonywania zapytań (ponieważ wiadomo, że
    zakończą się one niepowodzeniem) nie trzeba czekać pięciu sekund w
    przypadku każdego zapytania — ustawiono wartość 1 parametru
    opcjonalnego timeout.
-   Ponieważ w przypadku niepowodzenia żądanie HTTP zwraca obiekt
    WP_Error, odpowiedź można sprawdzić za pomocą funkcji is_wp_error().
    Więcej informacji na temat pracy z błędami oraz klasą WP_Error
    znajduje się w rozdziale 16.

Dane wyjściowe wygenerowane przez powyższy fragment kodu przedstawiają
się następująco:

    Adres nieprawidlowy zwrócił komunikat:
    Podano niepoprawny adres URL.
    Adres http://0.0.0.0/ zwrócił komunikat:
    Nie można nawiązać połączenia z serwerem.
    Adres irc://przyklad.pl/zwrócił komunikat:
    Nieobsługiwny protokół: irc.
    Adres http://nieistniejacy zwrócił komunikat:
    Nie można znaleźć serwera: nieistniejacy; Brak rekordu danych dla żądanego typu.

Jak możesz zobaczyć, funkcje wykonujące żądania HTTP mogą zdiagnozować
większość sytuacji. Dlatego też można na nich polegać, jeśli trzeba
znaleźć przyczyny nieoczekiwanego zachowania kodu.

Żądania HTTP zakończone powodzeniem

Kiedy żądanie HTTP zostanie zakończone pomyślnie, funkcja wp_remote_*
zwraca wielowymiarową tablicę czterech elementów zawierającą odpowiedź
serwera w czterech częściach: headers, body, response i cookies.

Warto przeanalizować poniższe żądanie:

    <?php
    var_dump( wp_remote_get( 'http://przyklad.pl/asdfgh' ) );
    ?> 

Dane wyjściowe powyższego żądania mogą być następujące:

    array(4) {
     ["headers"] => array(5) {
     ["date"] => string(29) "Wed, 01 Sep 2010 14:39:21 GMT"
     ["server"] => string(85) "Apache/2.2.8 mod_ssl/2.2.8 PHP/5.2.5"
     ["content-length"] => string(3) "461"
     ["connection"] => string(5) "close"
     ["content-type"] => string(25) "text/html; charset=utf-8"
     }
     ["body"] => string(461) "<html><head> 
    <title>404 Nie znaleziono</title></head><body> 
    (... cięcie ...)
    </body></html> 
    "
     ["response"] => array(2) {
     ["code"] => int(404)
     ["message"] => string(14) "Nie znaleziono"
     }
     ["cookies"] => array(0) {}
    } 

Pierwszą rzeczą, na którą trzeba zwrócić uwagę, jest fakt, że mimo iż
wykonano żądanie HTTP względem nieistniejącej strony, ono nadal zostało
uznane za zakończone powodzeniem. Kiedy serwer WWW udzieli odpowiedzi,
to niezależnie od rodzaju tej odpowiedzi transakcja HTTP jest uznawana
za kompletną.

Cztery elementy odpowiedzi umieszczone w tablicy są następujące.

-   headers — zwykła lista odpowiedzi serwera, zgodnie z opisem
    przedstawionym na początku rozdziału, ale bez kodu odpowiedzi HTTP.
-   body — część główna odpowiedzi serwera, którą najczęściej jest treść
    strony HTML. Podczas wykonywania żądania do zdalnego API treść ta
    może mieć postać danych zakodowanych w formacie JSON lub XML.
-   response — kod odpowiedzi serwera i jego znaczenie, zgodnie z
    objaśnieniami przedstawionymi w tabelach 9.1 i 9.2. Te informacje są
    szczególnie cenne: wprawdzie transakcja HTTP może być uznana za
    zakończoną z powodzeniem, ale wynik zapytania może być zupełnie
    odmienny od oczekiwanego. Zawsze należy sprawdzać, czy wartość kodu
    odpowiedzi wynosi 200.
-   cookies — jeżeli serwer chce, aby klient przechowywał informacje w
    postaci cookie, to będą one dołączone w tym miejscu. W takim
    przypadku informacje te trzeba dołączać do każdego kolejnego żądania
    HTTP (wywołania funkcji wp_remote_*) w postaci parametru
    opcjonalnego.

Funkcje pomocnicze wp_remote_*

Tablica zwracana przez funkcje wp_remote_* jest dość szczegółowa i jako
taka może zawierać zbyt wiele informacji, a może być potrzebna tylko ich
część.

Oprócz funkcji wykonujących żądania HTTP istnieją także funkcje
"pomocnicze", które umożliwiają uzyskanie szybkiego dostępu do części
danych zwróconej tablicy. Oto te funkcje.

-   wp_remote_retrieve_response_code() — funkcja zwraca jedynie kod
    odpowiedzi (np. 200) na żądanie HTTP.
-   wp_remote_retrieve_response_message() — funkcja zwraca jedynie
    komunikat odpowiedzi (np. OK) na żądanie HTTP.
-   wp_remote_retrieve_body() — funkcja zwraca część główną odpowiedzi
    na żądanie HTTP.
-   wp_remote_retrieve_headers() — funkcja zwraca wszystkie nagłówki
    odpowiedzi na żądanie HTTP.
-   wp_remote_retrieve_header() — funkcja zwraca jeden wskazany nagłówek
    odpowiedzi na żądanie HTTP.

Przykładowo w celu sprawdzenia, czy odnośnik istnieje i nie zwraca kodu
404 (Nie znaleziono) można wykorzystać przedstawiony poniżej fragment
kodu:

    <?php
    $url = 'http://www.przyklad.pl/bleh';
    // Wykonanie żądania GET.
    $response = wp_remote_get( $url );
    // Sprawdzenie otrzymanej odpowiedzi serwera.
    if( is_wp_error( $response ) ) {
     $code = $response->get_error_message();
     wp_die( 'Żądanie nie mogło zostać wykonane. Wystąpił błąd: ' . $code );
    }
    // Sprawdzenie, czy serwer wygenerował kod odpowiedzi 404.
    if( wp_remote_retrieve_response_code( $response ) == 404 ) {
     wp_die( 'Odnośnik nie został znaleziony' );
    }
    // Jak dotąd wszystko dobrze.
    echo 'Odnośnik został znaleziony';
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku wp_remote_check_404.php.

------------------------------------------------------------------------

Wymienione funkcje pomocnicze wykorzystasz w kolejnych przykładach i
wtyczkach.

Konfiguracja zaawansowana i wskazówki

Korzystając z funkcji wp_remote_*, możesz z poziomu standardowego
środowiska WordPress wykonać większość zadań wymagających użycia żądań
HTTP. Jednak nie wszystkie środowiska są standardowe, a nie wszystkie
zadania zaliczają się do prostych. Na szczęście, API HTTP jest
rozszerzalne i wszechstronne.

Przykładowo sieci w środowiskach korporacyjnych bardzo często są
umieszczone za zaporą sieciową lub proxy. Teraz dowiesz się, jak można
sobie z tym poradzić i inaczej potraktować odpowiedzi na żądania HTTP.

W kolejnych podpunktach dowiesz się, w jaki sposób dostosować do
własnych potrzeb zachowanie API HTTP, wykorzystując zaczepy akcji i
filtrów, np. podczas rejestrowania żądań w celu późniejszego użycia tych
informacji w trakcie procesu rozwiązywania problemów.

Obsługa proxy

W sieciach komputerowych serwer proxy to serwer, który po prostu działa
w charakterze pośrednika pomiędzy klientem i żądanym serwerem.

Doskonałym aspektem API HTTP i kolejnym powodem jego przewagi nad
rodzimymi funkcjami PHP przedstawionymi na początku rozdziału jest
możliwość obsługi połączeń poprzez proxy bez konieczności
przeprowadzania dodatkowej skomplikowanej konfiguracji.

W celu włączenia obsługi proxy trzeba po prostu mieć zdefiniować
wymienione poniżej stałe:

    <?php
    define( 'WP_PROXY_HOST', 'zapora.sieciowa.korporacji.przyklad.pl' );
    define( 'WP_PROXY_PORT', '3128' );
    define( 'WP_PROXY_USERNAME', 'nazwauzytkownika' );
    define( 'WP_PROXY_PASSWORD', 'haslo' );
    ?> 

To jest szczególnie ważne dla użytkowników w środowiskach
korporacyjnych, w których serwery proxy są często stosowane i mogą
zablokować wszystkie wychodzące żądania WordPress, o ile użytkownik nie
skonfiguruje proxy prawidłowo, tak jak pokazano powyżej.

W sieciach korporacyjnych, w których zapora sieciowa może w różny sposób
obsługiwać połączenia wychodzące do internetu i te pozostające w sieci
intranet, pod uwagę trzeba wziąć kolejną stałą. Wspomniana stała określa
domeny (w postaci listy rozdzielonej przecinkami), które nie powinny
przechodzić przez proxy:

    <?php
    // Wymienione poniżej domeny nie będą przechodzić przez proxy.
    define( 'WP_PROXY_BYPASS_HOSTS', 'sprzedaz.przyklad.pl, hr.przyklad.pl' );
    ?> 

Domena bloga i localhost są automatycznie dodawane do powyższej listy,
więc nie trzeba ich tam umieszczać.

Ponadto podczas pracy z klientami działającymi w korporacyjnej sieci
intranet za zaporą sieciową departament IT klienta może ograniczyć
połączenia wychodzące jedynie do witryn internetowych umieszczonych na
białej liście. W takim przypadku trzeba użyć stałych
WP_HTTP_BLOCK_EXTERNAL i WP_ACCESSIBLE_HOSTS, np. w następujący sposób:

    <?php
    // Zablokowanie wszystkich żądań wychodzących przez API HTTP.
    define( 'WP_HTTP_BLOCK_EXTERNAL', true );
    // Wyjątkiem są poniższe domeny.
    define( 'WP_ACCESSIBLE_HOSTS',
     'api.wordpress.org, sprzedaz.przyklad.pl, partner.web' );
    ?> 

Umieszczenie domeny api.wordpress.org na liście dozwolonych domen może
zagwarantować, że wbudowana funkcja uaktualniania jądra platformy,
wtyczek i motywów będzie działała.

Filtrowanie żądań i odpowiedzi

Podobnie jak w przypadku każdego innego fragmentu kodu WordPress, API
HTTP wykorzystuje znaczną liczbę zaczepów. Przeglądając kod źródłowy
klasy WP_Http, można znaleźć wiele wywołań zaczepów akcji i filtrów.

Przykład: modyfikacja parametru domyślnego

Jeśli np. chcesz, aby wszystkie Twoje wtyczki zawierały własną wartość w
ciągu tekstowym agenta użytkownika zapisywanym w dziennikach serwera
podczas wykonywania zapytań, możesz wykorzystać poniższy kod:

    <?php
    // Zarejestrowanie funkcji dla zaczepu filtru ustawiającego agenta użytkownika dla żądania HTTP.
    add_filter( 'http_headers_useragent', 'boj_myplugin_user_agent' );
    // Przygotowanie własnego ciągu tekstowego agenta użytkownika.
    function boj_myplugin_user_agent() {
     global $wp_version;
     return "WordPress wersja $wp_version ; ".
     "Potrzebujesz specjalisty WordPress? Skontaktuj się z nami! ".
     "BOJ Studio www.przyklad.pl";
    }
    ?> 

Ten filtr pozwala na zdefiniowanie nowej wartości domyślnej dla ciągu
tekstowego agenta użytkownika. Oznacza to możliwość jego nadpisania w
danym żądaniu, jak we wcześniejszym przykładzie, w którym wykonane
żądanie było odmienne od wykonywanego przez ogólną przeglądarkę
internetową.

Przykład: rejestracja żądań HTTP i udzielanej odpowiedzi na żądanie

Zaczepy, które okazują się przydatne podczas usuwania błędów z żądań i
odpowiedzi serwera, to http_request_args i http_response. Są one używane
do modyfikacji parametrów żądania tuż przed jego wykonaniem lub tuż
przed zwróceniem odpowiedzi serwera.

W kodzie źródłowym klasy WP_Http (plik wp-includes/class-http.php) można
znaleźć żądania wykorzystujące wymienione filtry:

    <?php
    // Przed wysłaniem żądania:
    $r = apply_filters( 'http_request_args', $r, $url );
    // Przed przetworzeniem odpowiedzi:
    return apply_filters( 'http_response', $response, $r, $url );
    ?> 

Teraz zbudujemy wtyczkę, która będzie zapisywała w zwykłym pliku
tekstowym każde żądanie HTTP i jego parametry oraz odpowiedź udzieloną
przez serwer. Prefiksem stosowanym w tej wtyczce jest boj_loghttp.

    <?php
    /*
    Plugin Name: Rejestracja żądań HTTP
    Plugin URI: http://przyklad.pl/
    Description: Każde żądanie HTTP jest rejestrowane w celu jego dalszej analizy.
    Author: WROX
    Author URI: http://wrox.com
    */
    // Rejestracja funkcji w zaczepach.
    add_filter( 'http_request_args', 'boj_loghttp_log_request', 10, 2 );
    add_filter( 'http_response', 'boj_loghttp_log_response', 10, 3 );
    // Rejestracja żądań.
    // Parametry przekazane: parametry żądania i adres URL.
    function boj_loghttp_log_request( $r, $url ) {
    // Pobranie parametrów żądania sformatowanych w celu wyświetlenia.
     $params = print_r( $r, true );
    // Pobranie daty w formacie 2010-11-25 @ 13:37:00.
     $date = date( 'Y-m-d @ H:i:s' );
    // Zapisanie danych w dzienniku zdarzeń:
     $log = <<<LOG
     $date: żądanie wysłane na adres $url
     Parametry: $params
     --------------
    LOG;
    // Zapis danych w jednorodnym pliku tekstowym.
     error_log( $log, 3, dirname( __FILE__ ).'/http.log' );
    // Nie należy zapomnieć o zwróceniu argumentów żądania!
     return $r;
    }
    // Rejestracja odpowiedzi.
    // Parametry przekazane: odpowiedź serwera, parametry żądania i adres URL.
    function boj_loghttp_log_response( $response, $r, $url ) {
    // Pobranie odpowiedzi serwera sformatowanej w celu wyświetlenia.
     $resp = print_r( $response, true );
    // Pobranie daty w formacie 2010-11-25 @ 13:37:00.
     $date = date( 'Y-m-d @ H:i:s' );
    // Zapisanie danych w dzienniku zdarzeń:
     $log = <<<LOG
     $date: odpowiedź otrzymana z adresu $url
     Odpowiedź: $resp
     --------------
    LOG;
    // Zapis danych w jednorodnym pliku tekstowym.
     error_log( $log, 3, dirname( __FILE__ ).'/http.log' );
    // Nie należy zapomnieć o zwróceniu odpowiedzi!
     return $response;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_loghttp.php.

------------------------------------------------------------------------

Dwie przedstawione funkcje rejestracji danych są podobne: od filtru
otrzymują pewną liczbę parametrów, które następnie są zapisywane w
jednorodnym pliku tekstowym za pomocą funkcji PHP o nazwie error_log().
Filtry przekazują niezmodyfikowane, przefiltrowane wartości.

Warto zwrócić uwagę na składnię (nazywaną heredoc) użytą do ograniczenia
ciągów tekstowych. Otwierający ogranicznik ciągu tekstowego jest
identyfikatorem umieszczonym po <<<, natomiast zamykający ogranicznik to
sam identyfikator bez wcięcia.

Po aktywacji wtyczki w katalogu wtyczek zostanie umieszczony plik
http.log, do którego będą dołączane dane kolejnych wykonywanych żądań i
udzielonych na nie odpowiedzi. To jest interesująca wtyczka pokazująca
działanie wewnętrznego kodu tworzącego platformę WordPress, ponieważ
będą rejestrowane wszystkie transakcje z domeną api.wordpress.org
podczas sprawdzania dostępności najnowszych wersji platformy, wtyczek i
motywów, a także w trakcie pobierania wiadomości wyświetlanych w
kokpicie.

------------------------------------------------------------------------

Uwaga

Pamiętaj, że rejestracja zdarzeń służy jedynie do celów usuwania błędów
i nie nadaje się do stosowania w środowiskach produkcyjnych, ponieważ
może doprowadzić do ujawnienia informacji poufnych lub nawet zapełnienia
dysku rejestrowanymi danymi.

------------------------------------------------------------------------

Przykład: zaawansowane filtrowanie

Filtry i akcje w klasie WP_Http pozwalają na dostosowanie do własnych
potrzeb sposobu, w jaki platforma WordPress obsługuje żądania HTTP.

Wyobraź sobie pracę dla klienta, który chce utworzenia wtyczki
monitorującej zawartość katalogu FTP. Jako doświadczony twórca wtyczek
wiesz, że API HTTP obsługuje jedynie protokoły HTTP i HTTPS. Ponieważ
masz doświadczenie w pracy z PHP, to pamiętasz, że rozszerzenie CURL
obsługuje żądania FTP.

Oczywiście, możesz utworzyć kod bezpośrednio używający rozszerzenia CURL
zamiast funkcji API HTTP, ale to nie jest najlepsze rozwiązanie,
ponieważ w ten sposób tracisz dostęp do zaczepów oferowanych przez
wymienione API.

Po upewnieniu się, że serwer klienta będzie obsługiwał rozszerzenie
CURL, możesz przygotować wtyczkę do wykorzystania możliwości
rozszerzenia CURL podczas pracy z protokołem FTP.

Teraz pozostało już utworzenie fragmentu takiej wtyczki, który będzie
wykonywał poniższe zadania:

-   wyłączenie wszystkich metod transportu poza CURL;
-   dodanie własnych parametrów do sesji CURL;
-   pobranie i wyświetlenie zawartości katalogu FTP (np.
    ftp://ftp.gnu.org, repozytorium publiczne).

    <?php
    // Wyłączenie wszystkich metod transportu poza CURL.
    function boj_onlycurl_force_curl() {
     add_ﬁlter( 'use_fsockopen_transport', '__return_false' );
     add_ﬁlter( 'use_fopen_transport', '__return_false' );
     add_ﬁlter( 'use_streams_transport', '__return_false' );
     add_ﬁlter( 'use_http_extension_transport', '__return_false' );
    }
    // Dodanie własnych parametrów do żądań CURL.
    // Wyświetlenie jedynie nazw katalogów FTP (bez atrybutów, wielkości itd.).
    function boj_onlycurl_hack_curl_handle( $handle ) {
     curl_setopt( $handle, CURLOPT_FTPLISTONLY, true );
     return $handle;
    }
    // Podłączenie żądań CURL do zdefiniowanej wcześniej funkcji.
    add_action( 'http_api_curl', 'boj_onlycurl_hack_curl_handle' );
    // Wykonanie właściwego zadania.
    boj_onlycurl_force_curl();
    var_dump( wp_remote_get( 'ftp://ftp.gnu.org' ) );
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_onlycurl.php.

------------------------------------------------------------------------

Dzięki użyciu API HTTP, nawet po zredukowaniu jedynie do użycia
rozszerzenia CURL, taki kod nadal łatwo współdziała z platformą
WordPRess, np. ze zdefiniowanym wcześniej filtrem modyfikującym ciąg
tekstowy agenta użytkownika.

Warto zwrócić uwagę na użycie wygodnej funkcji __return_false(). Na
platformie WordPress jest dostępnych kilka funkcji skrótu, które mogą
być używane do zwracania zawsze tej samej wartości: __return_true(),
__return_false(), __return_zero() i __return_empty_array().

Wymienione funkcje skrótów zostały zaprojektowane do używania w
kontekście filtrów i mają na celu uproszczenie kodu. Wszystkie trzy
poniższe przykłady wykonują to samo zadanie:

    <?php
    // 1. Stary sposób.
    // Trzeba utworzyć dodatkową funkcję, która być może będzie użyta tylko jednokrotnie.
    add_filter( 'somefilter', 'boj_always_return_false' );
    function boj_always_return_false() {
     return false;
    }
    // 2. Trudna wersja użycia skrótu.
    add_filter( 'somefilter', create_function('$a', 'return false;') );
    // 3. Elegancki i prosty sposób.
    add_filter( 'somefilter', '__return_false' );
    ?> 

Używanie w PHP funkcji anonimowych (lambda) wraz z create_function()
wiąże się z kilkoma niedogodnościami, których warto unikać.

-   Lista argumentów i część główna są ciągami tekstowymi, więc trzeba
    zwrócić dodatkową uwagę na ich cytowanie.
-   Twój ulubiony edytor lub środowisko IDE nie może poprawnie stosować
    kolorowania składni kodu w ciągu tekstowym części głównej funkcji,
    co może utrudnić tworzenie kodu bardziej skomplikowanych operacji.
-   Techniki buforowania, takie jak APC i PHP Accelerator, nie mogą
    buforować takich funkcji dynamicznych.

Pewne ograniczenia dotyczące sprawdzania odpowiedzi HTTP

Kiedy w sposób programowy chcesz sprawdzić istnienie i poprawność
odnośnika za pomocą żądania HTTP, analizę możesz przeprowadzić w dwóch
krokach: jeśli wykonanie żądania zakończyło się powodzeniem, a otrzymany
kod to 404, wówczas wiadomo, że odnośnik nie istnieje. W przeciwnym
razie konieczne jest przeprowadzenie dokładniejszego sprawdzenia, w
zależności od kontekstu.

-   Jeżeli wynikiem żądania jest is_wp_error(), to może być skutkiem
    zarówno nieprawidłowego adresu URL, jak również tymczasowego
    problemu uniemożliwiającego dotarcie do serwera WWW i sprawdzenie
    adresu URL (np. problem z połączeniem, problem z DNS itd.).
-   Jeżeli kod odpowiedzi pochodzi z grupy 5xx (wewnętrzny błąd serwera,
    zobacz tabela 9.2), wówczas prawdopodobnie wystąpił błąd tymczasowy
    serwera i sprawdzenie należy powtórzyć nieco później.
-   Niektóre serwery WWW zostały skonfigurowane do obsługi błędu "Nie
    znaleziono" w sposób nieco inny od oczekiwanego. Przykładowo adres
    http://przyklad.pl/ikony zwróci kod 404, podczas gdy oczekiwane jest
    przekierowanie na faktycznie istniejący adres
    http://przyklad.pl/ikony/.
-   Pewne serwery proxy lub DNS, zwłaszcza w środowiskach
    korporacyjnych, są konfigurowane do zakończonej powodzeniem obsługi
    wszystkich żądań, nawet tych, które powinny zwrócić błąd.
    Przykładowo poniższy wynik to tak naprawdę wartość zwrotna wywołania
    wp_remote_head( 'http://przyklad.ppl' ). Zwróć uwagę na błąd
    popełniony w nazwie domeny najwyższego poziomu. W tym przypadku
    nieistniejąca domena jest traktowana tak samo jak zwykły błąd 404.
    (Na rysunku 9.1 pokazano czytelny dla człowieka wynik otrzymany w
    przeglądarce internetowej).

    array(4) {
     ["headers"]=> 
     array(6) {
     ["cache-control"]=> 
     string(8) "no-cache"
     ["pragma"]=> 
     string(8) "no-cache"
     ["content-type"]=> 
     string(24) "text/html; charset=utf-8"
     ["proxy-connection"]=> 
     string(10) "Keep-Alive"
     ["connection"]=> 
     string(10) "Keep-Alive"
     ["content-length"]=> 
     string(3) "762"
     }
     ["body"]=> 
     string(0) ""
     ["response"]=> 
     array(2) {
     ["code"]=> 
     int(404)
     ["message"]=> 
     string(14) "Nie znaleziono"
     }

[]

Rysunek 9.1. Komunikat błędu wyświetlony w przeglądarce internetowej

     ["cookies"]=> 
     array(0) {
     }
    } 

Ćwiczenie praktyczne: odczyt formatu JSON z zewnętrznego API

Po zdobyciu niemal całej wiedzy z zakresu API HTTP warto ją wykorzystać
w praktyce.

Serwis Twitter to interesujące praktyczne pole doświadczalne, ponieważ
oferowane przez serwis API jest przyjazne dla programistów, doskonale
udokumentowane (zobacz https://dev.twitter.com/doc), a wyniki mogą być
otrzymane w różnych formatach, np. JSON, XML lub RSS.

------------------------------------------------------------------------

Uwaga

Podczas pracy ze zdalnym API zawsze należy sprawdzać bieżącą
dokumentację i zapoznawać się z ostatnio wprowadzonymi zmianami. Bardzo
często usługi oferowane przez firmy trzecie otrzymują nowe metody, a
pewne istniejące są porzucane, co może doprowadzić do niedziałania
poprzednio funkcjonującego kodu.

------------------------------------------------------------------------

W tym podrozdziale zostanie utworzona wtyczka pobierająca liczbę osób
śledzących w serwisie Twitter wskazanego użytkownika oraz ostatnio
opublikowaną wiadomość. Dowiesz się także, jak pobierać i przetwarzać
dane JSON, czyli dane w formacie często spotykanym podczas używania
zewnętrznego API.

Pobieranie i odczytywanie danych JSON

Zapytanie do API URL
http://api.twitter.com/1/​users/show.json?screen_name=$username odbywa
się za pomocą prostego żądania GET. Otrzymane w wyniku dane są w
formacie JSON, a po sformatowaniu do postaci czytelnej dla człowieka
mogą wyglądać tak, jak pokazano poniżej:

    {
     "followers_count" : 1731,
     "friends_count" : 108,
     "name" : "Ozh RICHARD",
     "description" : "WordPress & PHP hacker.",
     "screen_name" : "ozh",
     "status" : {
     "created_at" : "Sun Sep 05 09:01:56 +0000 2010",
     "id" : 23045381793,
     "retweet_count" : 1337,
     "text" : "Piszę książkę na temat wtyczek platformy WordPress!",
     },
     "statuses_count" : 1730,
     "time_zone" : "Paris",
     "url" : "http://ozh.org/",
    } 

JSON (ang. JavaScript Object Notation) to popularny format danych
tekstowych przechowywanych w postaci struktury par nazwa:wartość
(name:value), które w PHP tworzą tablicę wielowymiarową. Powodem dużej
popularności formatu jest łatwość, z jaką można go programowo
przetwarzać i generować za pomocą funkcji json_encode() i json_decode().

------------------------------------------------------------------------

Uwaga

Funkcje json_encode() i json_decode() zostały wbudowane w wersję PHP 5.2
i nowsze. Platforma WordPress w pliku wp-includes/compat.php zawiera
wersje tych funkcji przeznaczone dla starszych platform.

------------------------------------------------------------------------

Po zebraniu danych JSON w ciągu tekstowym $json funkcja json_decode()
konwertuje je na postać obiektu lub tablicy, np.:

    <?php
    // Konwersja ciągu tekstowego JSON na postać obiektu.
    $json_object = json_decode( $json );
    $followers = $json_object->followers_count;
    $last_tweet = $json_object->status->text;
    // Konwersja ciągu tekstowego JSON na postać tablicy: jako drugi parametr trzeba przekazać wartość true.
    $json_array = json_decode( $json, true );
    $followers = $json_array['followers_count'];
    $last_tweet = $json_array['status']['text'];
    ?> 

Funkcjonująca wtyczka

Poniżej przedstawiono pełny kod kompletnej wtyczki Twitter Info, w
której użytym prefiksem jest boj_ti_:

    <?php
    /*
    Plugin Name: Twitter Info
    Plugin URI: http:// przyklad.pl/
    Description: Pobranie liczby śledzących wskazanego użytkownika oraz jego ostatnią wiadomość opublikowaną w serwisie Twitter.
    Author: WROX
    Author URI: http://wrox.com
    */
    // Zdefiniowanie nazwy użytkownika serwisu Twitter.
    define( 'BOJ_TI_USERNAME', 'ozh' );
    // Nazwa klucza używanego do buforowania wartości.
    define( 'BOJ_TI_KEY', 'boj_ti_key' );
    // Użycie API serwisu Twitter.
    // Zwrot tablicy (liczba śledzących, ostatnia opublikowana wiadomość w serwisie) lub false w przypadku wystąpienia błędu.
    function boj_ti_ask_twitter() {
    // Wykonanie żądania GET do API serwisu Twitter.
     $api_url = 'http://api.twitter.com/1/users/show.json?screen_name=';
     $api_response = wp_remote_get( $api_url . urlencode( BOJ_TI_USERNAME ) );
    // Pobranie obiektu JSON.
     $json = wp_remote_retrieve_body( $api_response );
    // Upewnienie się, że wykonanie żądania zakończyło się powodzeniem; w przeciwnym razie wartością zwrotną jest false.
     if( empty( $json ) )
     return false;
    // Dekodowanie obiektu JSON.
    // Zwrot tablicy zawierającej liczbę śledzących oraz ostatnią opublikowaną wiadomość w serwisie.
     $json = json_decode( $json );
     return array(
     'followers' => $json->followers_count,
     'last_tweet' => $json->status->text
     );
    }
    // Zwrot tablicy zawierającej liczbę śledzących oraz ostatnią opublikowaną wiadomość w serwisie.
    // Wynik jest pobierany z bufora lub następuje pobranie nowej wartości.
    function boj_ti_get_infos( $info = 'followers' ) {
    // W pierwszej kolejności sprawdzamy, czy jest buforowany wynik.
     if ( false !== $cache = get_transient( BOJ_TI_KEY ) )
     return $cache[$info];
    // Brak buforowanego wyniku? Trzeba więc pobrać nową wartość.
     $fresh = boj_ti_ask_twitter();
    // Domyślny czas ważności bufora wynosi 1 godzinę (3600 sekund).
     $cache = 3600;
    // Jeżeli zapytanie do serwisu Twitter zakończy się niepowodzeniem, fikcyjne wartości będą przechowywane przez 5 minut.
     if( $fresh === false ) {
     $fresh = array(
     'followers' => 0,
     'last_tweet' => '',
     );
     $cache = 60*5;
     }
    // Przechowywanie wartości tymczasowej.
     set_transient( BOJ_TI_KEY, $fresh, 60*5 );
    // Zwrot nowych informacji.
     return $fresh[$info];
    }
    // Wyświetlenie liczby osób śledzących wskazanego użytkownika serwisu Twitter.
    function boj_ti_followers() {
     $num = boj_ti_get_infos( 'followers' );
     echo "<p>W serwisie Twitter śledzi mnie $num osób!</p>";
    }
    // Wyświetlenie ostatniego opublikowanego komunikatu.
    function boj_ti_last_tweet() {
     $tweet = boj_ti_get_infos( 'last_tweet' );
     echo "<p>Mój ostatni opublikowany komunikat: $tweet</p>";
    }
    // Rejestracja własnych akcji.
    add_action( 'boj_ti_followers' , 'boj_ti_followers' );
    add_action( 'boj_ti_last_tweet', 'boj_ti_last_tweet' );
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_twitter_info.php.

------------------------------------------------------------------------

W przedstawionej wtyczce funkcja boj_ti_ask_twitter() wykonuje żądanie
GET do API serwisu Twitter, upewnia się o otrzymaniu wyniku w formacie
JSON, dekoduje wynik, a następnie zwraca tablicę zawierającą liczbę osób
śledzących wskazanego użytkownika oraz jego ostatni opublikowany
komunikat w serwisie Twitter.

Funkcja boj_ti_get_infos() doskonale wykorzystuje omówione w rozdziale
7. API Transients w celu uniknięcia nieustannego wykonywania zapytań do
serwisu Twitter. Warto również zwrócić uwagę na buforowanie fikcyjnych
wartości przez krótki okres czasu, jeśli zapytanie do API serwisu
Twitter zwróci błąd. To dobra praktyka podczas współpracy z API firm
trzecich, nad którymi nie masz kontroli.

Ponieważ główna funkcja boj_ti_get_infos() zwraca tablicę zawierającą
liczbę osób śledzących wskazanego użytkownika oraz jego ostatni
opublikowany komunikat w serwisie Twitter, aby zapewnić jeszcze większą
wygodę, dodano dwie proste funkcje skrótu pozwalające na uzyskanie
łatwego dostępu do danych: boj_ti_followers() i boj_ti_last_tweet().

W celu użycia wtyczki tradycyjnie wykorzystywany jest poniższy fragment
kodu:

    <?php
    if( function_exists( 'boj_ti_followers' ) )
     boj_ti_followers()
    ?> 

W ten sposób, jeśli z jakiegokolwiek powodu wtyczka zostanie
dezaktywowana, nie wystąpi awaria bloga w wyniku wywołania
niezdefiniowanej funkcji.

Warto bliżej przyjrzeć się końcówce kodu wtyczki: znajdują się tam
definicje dwóch własnych akcji. To również dobra praktyka, ponieważ
pozwala na stosowanie poniższego, jednowierszowego polecenia:

    <?php
    do_action( 'boj_ti_followers' );
    ?> 

Używanie powyższej metody jest prostsze dla użytkownika końcowego
(mniejsza ilość kodu do dodania) i bezpieczniejsze. (Jeżeli wtyczka
zostanie dezaktywowana, akcja po prostu nie istnieje, więc nie będzie
wywołana).

Ćwiczenie praktyczne: wysyłanie danych do zdalnego API

Teraz w praktyce można wykorzystać wiedzę dotyczącą żądań POST.

Kod prostej wtyczki powoduje automatyczne utworzenie kopii zapasowej
wpisów bloga poprzez ich umieszczenie w serwisie Tumblr. Wspomniany
Tumblr to popularna, bezpłatna platforma bloga dostępna na witrynie
https://www.tumblr.com/. Oferuje proste API, które zostało
udokumentowane na stronie http://www.tumblr.com/docs/en/api.

Formatowanie parametrów dla żądań POST

Najpierw trzeba w serwisie Tumblr utworzyć konto — podać adres e-mail
używany do logowania oraz zdefiniować hasło dostępu.

Wykonywanie żądań POST przypomina wysyłanie formularza w przeglądarce
internetowej. Informacje zamiast zapisywania w polach formularza są
zbierane w tablicy, która następnie jest wysyłana w części głównej
żądania.

Po opublikowaniu nowego wpisu bloga wtyczka umieści jego tytuł i treść w
zmiennych (odpowiednio) $post_title i $post_content. Na tym etapie można
wykonać żądanie POST do serwisu Tumblr:

    <?php
    // Adres URL API serwisu Tumblr.
    $api = 'http://www.tumblr.com/api/write';
    // Dane żądania POST.
    $data = array(
     'email' => 'email@przyklad.pl',
     'password' => '123456',
     'type' => 'regular',
     'title' => $post_title,
     'body' => $post_body
    );
    // Wykonanie żądania POST.
    $response = wp_remote_post( $api,
     array(
     'body' => $data,
     'timeout' => 20
     )
    );
    ?> 

Dane żądania POST są przekazywane jako część główna tablicy parametrów
żądania wraz z pozostałymi parametrami, np. z użytym w przykładzie
okresem czasu utraty ważności.

Gotowa wtyczka

Poniżej przedstawiono pełny kod wtyczki Simple Tumblr Backup, która jako
prefiksu używa boj_stb:

    <?php
    /*
    Plugin Name: Prosta kopia zapasowa w serwisie Tumblr
    Plugin URI: http://przyklad.pl/
    Description: Utworzenie kopii zapasowej opublikowanych wpisów bloga poprzez ich umieszczenie w serwisie Tumblr.
    Author: WROX
    Version: 1.00
    Author URI: http://wrox.com/
    */
    // Uzupełnij poniższe dane:
    define( 'BOJ_STB_TUMBLR_EMAIL', 'email@przyklad.pl' );
    define( 'BOJ_STB_TUMBLR_PASSW', '132456' );
    // Akcje związane z opublikowaniem nowego wpisu bloga.
    add_action( 'draft_to_publish', 'boj_stb_newpost' );
    add_action( 'pending_to_publish', 'boj_stb_newpost' );
    add_action( 'future_to_publish', 'boj_stb_newpost' );
    // Funkcja wywoływana po opublikowaniu nowego wpisu bloga. Oczekuje obiektu wpisu bloga.
    function boj_stb_newpost( $post ) {
    // Pobranie informacji dotyczących wpisu bloga.
     $post_title = $post->post_title;
     $post_content = $post->post_content;
    // Adres URL API serwisu Tumblr.
     $api = 'http://www.tumblr.com/api/write';
    // Dane żądania POST.
     $data = array(
     'email' => BOJ_STB_TUMBLR_EMAIL,
     'password' => BOJ_STB_TUMBLR_PASSW,
     'type' => 'regular',
     'title' => $post_title,
     'body' => $post_content
     );
    // Wykonanie żądania POST.
     $response = wp_remote_post( $api,
     array(
     'body' => $data,
     'timeout' => 20
     )
     );
    // Wszystko zrobione!
    }
    ?> 

Zastosowana sztuczka polega na powiązaniu funkcji wykonującej żądanie do
serwisu Tumblr z każdą akcją wywoływaną podczas publikowania nowego
wpisu bloga:

-   szkice wpisów bloga, które ostatecznie zostaną opublikowane (akcja:
    draft_to_publish);
-   wpis bloga oczekujący na sprawdzenie i teraz opublikowany (akcja:
    pending_to_publish);
-   już wcześniej utworzony wpis bloga, ale przeznaczony do
    opublikowania w przyszłości (akcja: future_to_publish).

Po aktywacji wtyczki każdy opublikowany przez Ciebie na platformie
WordPress wpis bloga zostanie automatycznie wysłany do wskazanego konta
Tumblr, jak pokazano na rysunku 9.2.

[]

Rysunek 9.2. Wpis bloga WordPress przekazany do konta w serwisie Tumblr

Ćwiczenie praktyczne: odczyt dowolnej treści

Nie zawsze wykonanie żądania do zdalnego API przyniesie skutek w postaci
elegancko sformatowanych danych JSON lub XML. Czasami trzeba pobrać
dowolną treść, np. zwykłą stronę HTML, i wyodrębnić z niej informacje.

W rozdziale 7. w przykładzie praktycznego użycia API Transients pokazano
fikcyjną funkcję przeznaczoną do pobierania tytułu piosenki aktualnie
odtwarzanej na witrynie internetowego radia. Wykorzystany kod miał
następującą postać:

    <?php
    // Pobranie z witryny internetowego radia tytułu aktualnie odtwarzanej piosenki.
    function boj_myplugin_fetch_song_title_from_radio() {
    // ... kod pobierający dane ze zdalnej witryny.
     return $title;
    }
    ?> 

Teraz możemy uzupełnić tę funkcję, aby stała się bliższa rzeczywistej.
Kod będzie pobierał tytuł aktualnie odtwarzanej piosenki, np. w radiu
KNAC na witrynie http://www.knac.com/.

Witryna internetowa nie oferuje wygodnego API, ale po chwili
dokładniejszej analizy można odkryć, że system generuje plik tekstowy
dostępny pod adresem http://knac.com/text1.txt i sformatowany w
następujący sposób:

    text1=<b>NOW PLAYING</b>: EL DORADO<br><b>BY:</b>IRON MAIDEN
    <current_song> EL DORADO
    <current_artist> IRON MAIDEN
    <current_album> THE FINAL FRONTIER
    <last_5_songs_played> 10:32:37 - SLAYER, WAR ENSEMBLE <br> (... cięcie ...) 

Widać tutaj pewne podobieństwo do XML, ale to nie jest kod XML. Naszym
zadaniem jest samodzielne przetworzenie tego pliku. Do wyodrębnienia
żądanych informacji z przedstawionego tekstu zostaną wykorzystane
wyrażenia regularne.

Poniżej przedstawiono kod działającej funkcji:

    <?php
    function boj_myplugin_fetch_song_title_from_radio() {
     $url = 'http://knac.com/text1.txt';
     $text = wp_remote_retrieve_body( wp_remote_get( $url ) );
     preg_match( '/\ < current_song\ > (.*)/', $text, $matches );
     $song = trim( $matches[1] );
     preg_match( '/\ < current_artist\ > (.*)/', $text, $matches );
     $artist = trim( $matches[1] ); return "$song by $artist";
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_current_title.php.

------------------------------------------------------------------------

Użyte w przykładzie wyrażenie regularne powoduje wyodrębnienie tytułu
piosenki, np. /\<current_ song\>(.*)/ oznacza: ciąg tekstowy
<current_song>, po którym znajduje się dowolny znak (kropka) powtórzony
zero lub więcej razy (gwiazdka) aż do końca wiersza.

Wyrażenia regularne mają znaczenie kluczowe podczas przetwarzania
dowolnej treści. Jeśli jeszcze się z nimi nie oswoiłeś (zostały
wprowadzone w rozdziale 6.), to więcej informacji na ich temat
znajdziesz na stronie http://pl.php.net/pcre.

Utworzenie własnego repozytorium wtyczki

Doskonałą cechą platformy WordPress jest fakt, że gdy wtyczki są
przechowywane na stronie http://wordpress.org/extend/plugins/,
użytkownicy w obszarze administracyjnym będą mogli dowiedzieć się o
wydaniu nowej wersji danej wtyczki. Dzięki temu mogą ją uaktualnić bez
opuszczania bloga. Jak się przekonasz w rozdziale 17., centralne
repozytorium WordPress ma na rynku wtyczek znaczenie kluczowe.

Jednak nie wszystkie tworzone przez Ciebie wtyczki mogą być przeznaczone
do publicznego użytku i umieszczone w repozytorium WordPress. Klienci
bardzo często wymagają, aby utworzone dla nich wtyczki pozostały
niedostępne dla innych. Z tego powodu może wystąpić konieczność
sprzedawania wtyczek za pomocą własnego repozytorium.

Jeśli nawet dostarczasz własne repozytorium, to Twoi użytkownicy nadal
mogą odnieść korzyści z wbudowanej na platformie WordPress funkcji
automatycznego uaktualniania wtyczek.

Jak działa proces uaktualnienia wtyczki na platformie WordPress?

Dwukrotnie w ciągu dnia platforma WordPress wykonuje żądanie do witryny
api.wordpress.org i przekazuje listę aktualnie zainstalowanych wtyczek.
Serwer udziela odpowiedzi, przekazując listę nowych dostępnych wersji
oraz informacji o tych wersjach.

Jeśli przykładowo masz blog z tylko jedną zainstalowaną i aktywną
wtyczką, żądanie POST wykonywane na adres
http://api.wordpress.org/​plugins/update-check/1.0/ będzie przypominało
poniższe:

    <?php
    // Przykładowe żądanie wykonane na adres api.wordpress.org w celu sprawdzenia dostępności nowych wersji wtyczek.
    $request = array(
     'plugins' => array (
     'boj_myplugin/plugin.php' => array (
     'Name' => 'My BOJ Plugin',
     'PluginURI' => 'http://przyklad.pl/',
     'Version' => '',
     'Description' => 'Ta wtyczka jest niesamowicie użyteczna.',
     'Author' => 'Ozh',
     'AuthorURI' => 'http://wrox.com/',
     'TextDomain' => '',
     'DomainPath' => '',
     'Network' => false,
     'Title' => 'My BOJ Plugin',
     ),
     ),
     'active' => array (
     0 => 'boj_myplugin/plugin.php',
     ),
    )
    ?> 

Jeżeli wtyczka jest przechowywana na witrynie WordPress.org i będzie
dostępna nowa wersja, wówczas udzielona przez serwer API odpowiedź
będzie zawierają poniższą tablicę informacyjną:

    <?php
    // Przykładowa odpowiedź serwera api.wordpress.org, jeśli dostępna jest nowa wersja wtyczki.
    $response = array(
     'boj_myplugin/plugin.php' => array(
     'id' => 10256,
     'slug' => 'boj_myplugin',
     'new_version' => '2.0',
     'url' => 'http://wordpress.org/extend/plugins/boj_myplugin/',
     'package' => 'http://downloads.wordpress.org/plugin/boj_myplugin.zip'
     )
    );
    ?> 

Tak więc co dwanaście godzin blog sprawdza dostępność nowych wersji
wtyczek. Wykonywane żądania i otrzymywane odpowiedzi są przechowywane w
postaci danych tymczasowych update_plugins, zawierających następujące
informacje:

1.  last_checked — data i godzina ostatniej operacji sprawdzenia
    dostępności nowych wersji wtyczek;
2.  checked — lista aktualnie zainstalowanych wtyczek i ich wersje;
3.  response — odpowiedź serwera API wraz z informacjami o nowej wersji.

Funkcją odpowiedzialną za takie zachowanie jest wp_update_plugins().
Wymienioną funkcję można znaleźć w pliku wp-includes/update.php.

Wykonywanie żądań do alternatywnego API z poziomu wtyczki

W tym momencie potrafisz już utworzyć wtyczkę, która może wykonywać
żądania do alternatywnego API w celu sprawdzenia dostępności nowej
wersji wtyczki nieprzechowywanej na witrynie WordPress.

Tuż przed umieszczeniem krótkotrwałych danych na Twoim blogu względem
tych danych zostaje zastosowany filtr
pre_set_site_transient_update_plugins. Na tym etapie wtyczka wykonuje
żądanie do alternatywnego API, a otrzymaną odpowiedź dołącza do
krótkotrwałych danych. Odpowiedź zawiera informacje o nowych danych, o
ile są dostępne, a także wskazuje adres URL pakietu, który nie jest
przechowywany na witrynie WordPress.org.

    <?php
    /*
    Plugin Name: BOJ Alternate Plugin API
    Plugin URI: http://przyklad.pl/
    Description: Wtyczka sprawdza dostępność swojej nowej wersji w samodzielnie przygotowanym API.
    Version: 1.0
    Author: Ozh
    Author URI: http://wrox.com/
    */
    define( 'BOJ_ALT_API', 'http://przyklad.pl/plugin-api/' );

Stała definiuje alternatywne API, które będzie wysyłało informacje o
dostępności nowej wersji wtyczki. Później można przygotować kod serwera
dla tego API.

Poniżej przedstawiono kod funkcji sprawdzającej API tuż przed operacją
zapisu krótkotrwałych danych:

    // Rejestracja funkcji sprawdzającej dostępność nowej wersji wtyczki.
    add_filter('pre_set_site_transient_update_plugins', 'boj_altapi_check');
    // Sprawdzenie alternatywnego API przed zapisem danych krótkotrwałych.
    function boj_altapi_check( $transient ) {
    // Sprawdzenie, czy dane krótkotrwałe zawierają informacje checked.
    // Jeżeli nie, należy zwrócić je bez zmian.
     if( empty( $transient->checked ) )
     return $transient;
    // Wartość krótkotrwała zawiera informacje checked.
    // W takim razie tę informację należy dołączyć do otrzymanych z API.
     $plugin_slug = plugin_basename( __FILE__ );
    // Dane POST przeznaczone do wysłania do API.
     $args = array(
     'action' => 'update-check',
     'plugin_name' => $plugin_slug,
     'version' => $transient->checked[$plugin_slug],
     );
    // Wykonanie zapytania sprawdzającego dostępność nowej wersji.
     $response = boj_altapi_request( $args );
    // Jeżeli wartością zwrotną jest false, nie należy zmieniać wartości krótkotrwałej.
     if( false !== $response ) {
     $transient->response[$plugin_slug] = $response;
     }
     return $transient;
    }
    // Wykonanie żądania do alternatywnego API, wartością zwrotną jest obiekt lub false.
    function boj_altapi_request( $args ) {
    // Wykonanie żądania.
     $request = wp_remote_post( BOJ_ALT_API, array( 'body' => $args ) );
    // Upewnienie się, że wykonanie żądania zakończyło się powodzeniem.
     if( is_wp_error( $request )
     or
     wp_remote_retrieve_response_code( $request ) != 200
     ) {
    // Wykonanie żądania zakończyło się niepowodzeniem.
     return false;
     }
    // Odczytanie odpowiedzi serwera, powinna być w postaci obiektu.
     $response = unserialize( wp_remote_retrieve_body( $request ) );
     if( is_object( $response ) ) {
     return $response;
     } else {
    // Nieoczekiwana odpowiedź.
     return false;
     }
    } 

Przeznaczeniem funkcji boj_altapi_check() jest wstawienie do danych
krótkotrwałych informacji o wtyczce pochodzących z innego miejsca niż
repozytorium WordPress. Szczególnie chodzi o wstawienie adresu URL
pakietu z nową wersją wtyczki.

Na tym etapie alternatywne API informuje o dostępności nowej wersji
wtyczki. W obszarze administracyjnym zostaje wyświetlony odnośnik
pozwalający na przeprowadzenie uaktualnienia (zobacz rysunek 9.3) i
można uruchomić wbudowaną funkcję uaktualniania własnego pakietu (zobacz
rysunek 9.4).

[]

Rysunek 9.3. Informacja o dostępności nowej wersji wtyczki

Rozwiązanie nie jest jeszcze doskonałe: trzeba się zająć odnośnikiem
Wyświetl informacje szczegółowe o wersji, który na tym etapie wciąż
pobiera informacje szczegółowe z witryny api.wordpress.org, a tym samym
wyświetla pusty ekran.

Wykorzystana zostanie wewnętrzna funkcja o nazwie plugins_api() — można
ją znaleźć w pliku wp-admin/includes/plugin-install.php — która korzysta
z filtru plugins_api:

    // Rejestracja funkcji wyświetlającej stronę z informacjami szczegółowymi o wtyczce.
    add_filter('plugins_api', 'boj_altapi_information', 10, 3);
    function boj_altapi_information( $false, $action, $args ) {
     $plugin_slug = plugin_basename( __FILE__ );

[]

Rysunek 9.4. Wykorzystanie wbudowanego mechanizmu uaktualniania wtyczek
WordPress do uaktualnienia wtyczki z własnego repozytorium

    // Sprawdzenie, czy API dotyczy tej konkretnej wtyczki.
     if( $args->slug != $plugin_slug ) {
     return false;
     }
    // Dane POST przeznaczone do wysłania do API.
     $args = array(
     'action' => 'plugin_information',
     'plugin_name' => $plugin_slug,
     'version' => $transient->checked[$plugin_slug],
     );
    // Wykonanie żądania w celu pobrania informacji szczegółowych.
     $response = boj_altapi_request( $args );
    // Wykonanie żądania sprawdzenia informacji.
     $request = wp_remote_post( BOJ_ALT_API, array( 'body' => $args ) );
     return $response;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_altapi.php.

------------------------------------------------------------------------

Po kliknięciu odnośnika wyświetlającego informacje szczegółowe wtyczka
powinna je pobrać ze zdefiniowanego własnego API (zobacz rysunek 9.5).

Utworzenie alternatywnego API

Oczywiście, Twoja wtyczka jest w zupełności zależna od alternatywnego
API, które musi udzielać informacji dotyczących wtyczki. Na szczęście,
implementacja tego rodzaju API jest całkiem prosta.

W zdalnym serwerze zdefiniowanym jako http://przyklad.pl/plugin-api/ API
składa się z pojedynczego skryptu, który może obsługiwać dwa rodzaje
żądań wykonywanych przez wtyczkę:

[]

Rysunek 9.5. Wyświetlenie informacji szczegółowych o wtyczce

-   sprawdzenie dostępności nowej wersji (parametr akcji update-check),
    na które odpowiedzią powinien być nowy numer wersji oraz adres URL
    wskazujący położenie nowej wersji wtyczki;
-   sprawdzenie informacji szczegółowych o uaktualnionej wtyczce
    (parametr akcji plugin_information).

    <?php
    $action = $_REQUEST['action'];
    $slug = $_REQUEST['plugin_name'];
    // Utworzenie nowego obiektu.
    $response = new stdClass;
    switch( $action ) {
    // API zostało zapytane o dostępność nowej wersji wtyczki.
     case 'update-check':
     $response->slug = $slug;
     $response->new_version = '2.0';
     $response->url = 'http://przyklad.pl/boj-altapi/';
     $response->package = 'http://przyklad.pl/plugin-api/boj_altapi.zip';
     break;
    // Żądanie informacji szczegółowych o wtyczce.
     case 'plugin_information':
     $response->slug = 'boj_altapi.php';
     $response->plugin_name = 'boj_altapi.php';
     $response->new_version = '2.0';
     $response->requires = '2.9.2';
     $response->tested = '3.5';
     $response->downloaded = 12540;
     $response->last_updated = "2010-08-23";
     $response->sections = array(
     'description' => 'Ta wtyczka sprawdza samodzielnie utworzone API',
     'changelog' => 'Dodano nowe funkcje!'
     );
     $response->download_link = 'http://przyklad.pl/plugin-api/boj_altapi.
    zip';
     break;
    }
    echo serialize( $response );
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin-api/index.php.

------------------------------------------------------------------------

Ten pojedynczy skrypt generuje obiekt odpowiedzi, który musi być
serializowany (tzn. przekształcony na ciąg tekstowy). Kluczową zmienną w
odpowiedzi jest adres URL pakietu .zip, który nie jest przechowywany na
witrynie WordPress.org.

Kilka ostrzeżeń dotyczących własnych API

Elastyczność API wtyczek WordPress pozwala na ich dostosowanie do
własnych potrzeb, w tym rezygnację z przechowywania na witrynie
WordPress.org, jeśli będzie trzeba.

Jeżeli wtyczka ma być dostępna publicznie, warto jednak rozważyć
umieszczenie jej na witrynie WordPress.org. Z lektury rozdziału 17.
dowiesz się, jak ogromną rolę może to odegrać w Twojej strategii
promocji.

Przypadek specjalny: pobieranie zdalnych wiadomości RSS

Funkcje API HTTP pozwalają na pobieranie dowolnego typu zdalnej treści,
np. dokumentów HTML, obrazów, archiwów zip lub danych JSON. Jednak w
celu pobrania zdalnych wiadomości RSS jest lepsza alternatywa: platforma
WordPress jest dostarczana wraz z SimplePie, popularnym i efektywnym
analizatorem składni RSS dostarczanym przez firmę trzecią.

Funkcją, którą należy wykorzystać, jest fetch_feed(). Wymaga ona podania
jednego argumentu (adresu URL kanału wiadomości RSS, np.
http://przyklad.pl/feed/). Natomiast wartość zwrotna to obiekt SimplePie
w przypadku powodzenia operacji lub WP_Error w przeciwnym razie.

Aby zilustrować użycie funkcji fetch_feed() i jej wartości zwrotnej,
przedstawiony poniżej kod powoduje pobranie pięciu ostatnich wiadomości
RSS z witryny internetowej oraz wyświetlenie ich tytułów, daty
publikacji i odnośników do tych artykułów.

    <?php
    // Pobranie obiektu SimplePie ze źródła wiadomości RSS.
    $rss = fetch_feed('http://przyklad.pl/feed/');
    // Upewnienie się o prawidłowym utworzeniu obiektu SimplePie.
    if( is_wp_error( $rss ) )
     wp_die( 'Nie można pobrać wiadomości.' );
    echo 'Znaleziono wiadomości, zawierają '. $rss->get_item_quantity() . ' artykułów.';
    // Utworzenie tablicy pięciu elementów, począwszy od elementu #0.
    $rss_items = $rss->get_items( 0, 5 );
    // Początek uporządkowanej listy.
    echo ' <ol> ';
    // Iteracja przez wszystkie elementy i wyświetlenie tytułu, daty publikacji i odnośnika do artykułu.
    foreach( $rss_items as $item ) {
     $title = $item->get_title();
     $date = $item->get_date('Y/m/d @ g:i a');
     $link = $item->get_permalink();
     echo " <li><a href='$link'>$title</a> ($date)</li>\n";
    }
    // Koniec uporządkowanej listy.
    echo ' </ol> ';
    ?> 

Podczas używania funkcji fetch_feed() wiadomości witryny internetowej są
domyślnie buforowane przez dwanaście godzin i przechowywane w postaci
danych krótkotrwałych.

Klasę SimplePie wyposażono w wiele różnych metod, z którymi można się
zapoznać na stronie http://simplepie.org/​wiki/reference/start.

Podsumowanie

Funkcje API HTTP stanowią rodzaj pomostu pomiędzy Twoim blogiem i
światem interakcji z usługami zdalnymi. Praktycznie wszystkie nowoczesne
usługi sieciowe oferują programistom API. W ten sposób znacznie
zwiększają się możliwości, jakie jawią się przez wtyczkami WordPress.

Z lektury tego rozdziału powinieneś szczególnie zapamiętać jedno:
zapomnij o sposobach tworzenia żądań, które stosowałeś przed używaniem
platformy WordPress, czyli prawdopodobnie z użyciem rozszerzenia CURL.
Jak się już dowiedziałeś, poleganie na API platformy WordPress daje
znacznie większą elastyczność (możliwość wykorzystania wewnętrznych
zaczepów API) oraz zapewnia bezpieczeństwo, ponieważ możesz być pewny,
że twórcy platformy wybierają do wykonywania żądań najlepsze funkcje.

Rozdział 10 API Shortcode

W tym rozdziale:

-   Tworzenie własnego skrótu
-   Rejestracja skomplikowanych i sparametryzowanych skrótów
-   Zaawansowane wskazówki dotyczące skrótów
-   Połączenie witryny z usługą Google Mapy

Skróty (ang. shortcode) to charakterystyczny dla WordPress kod
pozwalający na wykonywanie różnych operacji przy minimalnym wysiłku, np.
osadzanie treści lub tworzenie obiektów, które normalnie wymagałyby
użycia dużej ilości skomplikowanego kodu.

W tym rozdziale dowiesz się, jak za pomocą jedynie niewielkiej liczby
znaków umożliwić użytkownikom Twoich wtyczek rozbudowę wpisów bloga o
zaawansowaną treść.

Tworzenie skrótu

W tym podrozdziale przekonasz się, czym są skróty oraz jak można je
tworzyć; zaczniemy od zamienników w postaci prostych ciągów tekstowych,
a skończymy na funkcjach zaawansowanych wraz z parametrami.

Czym jest skrót?

API Shortcode pozwala na tworzenie prostego kodu makro, czasami
nazywanego BBCode z racji podobieństwa do popularnej składni w różnego
rodzaju forach i serwisach komputerowych.

Ogólnie rzecz biorąc, skrót to prosta składnia znaczników w nawiasach
kwadratowych, np. [znacznik], stosowanych we wpisach bloga. W trakcie
generowania i wyświetlania takiego wpisu bloga skrót jest dynamicznie
zastępowany bardziej skomplikowaną i zdefiniowaną przez użytkownika
treścią. Na rysunku 10.1 pokazano przykład wtyczki skrótu, która
znacznik [date] zastępuje bieżącą datą i godziną.

[]

Rysunek 10.1. Wtyczka skrótu w działaniu

Platforma WordPress domyślnie rejestruje wiele skrótów gotowych do
wykorzystania. Przykładowo podczas wysyłania do serwera wielu obrazów
dołączonych do danego wpisu bloga można w nim umieścić skrót [gallery],
co spowoduje zastąpienie obrazów ładnie sformatowaną galerią.

Z technicznego punktu widzenia skrót może być dowolnym ciągiem tekstowym
odpowiednim do użycia w charakterze klucza tablicy. Przykładowo
wymienione poniżej ciągi tekstowe można zastosować jako skróty:

-   [foo],
-   [Foo],
-   [123],
-   [133t],
-   [Witaj Jestem Jan Kowalski].

W praktyce, w celu zachowania prostoty i uniknięcia potencjalnych
konfliktów pomiędzy różnymi skrótami skróty będziesz rejestrował jako
proste ciągi tekstowe zapisane małymi literami.

------------------------------------------------------------------------

Uwaga

Nie wolno rejestrować własnych skrótów o nazwach [wp_caption],
[caption], [gallery] i [embed], ponieważ są już zarejestrowane przez
WordPress.

------------------------------------------------------------------------

Rejestracja własnego skrótu

W tym punkcie dowiesz się, w jaki sposób rejestrować własne skróty.
Ponadto poznasz praktyczne sposoby ich wykorzystania, od prostego
zastępowania tagów aż po bardziej skomplikowane i sparametryzowane dane
wyjściowe.

Przedstawione poniżej wtyczki skrótów używają prefiksu w postaci
boj_scX, gdzie X oznacza liczbę.

[ksiazka]

Celem użycia skrótu jest przyśpieszenie wprowadzania danych i
zastąpienie często stosowanych zdań ich skrótami, łatwymi do
zapamiętania i szybszymi do wpisania.

Jeżeli np. często wspominasz tytuł książki, którą promujesz w serwisie
Amazon, wówczas zamiast za każdym razem pisać
<a href="http://www.amazon.com/dp/0470560541">książka</a>, o wiele
szybciej i prościej będzie napisać po prostu [ksiazka], prawda?

W tym celu trzeba użyć funkcji add_shortcode() wymagającej podania dwóch
parametrów:

-   wzorca znacznika (bez otaczających go nawiasów kwadratowych);
-   wywoływanej funkcji odpowiedzialnej za zastąpienie znacznika.

    <?php
    /*
    Plugin Name: Przykład skrótu nr 1
    Plugin URI: http://przyklad.pl/
    Description: Zastępuje znacznik [ksiazka] długim odnośnikiem prowadzącym do serwisu Amazon.
    Version: 1.0
    Author: Ozh
    Author URI: http://wrox.com/
    */
    // Rejestracja nowego skrótu: [ksiazka].
    add_shortcode( 'ksiazka', 'boj_sc1_book' );
    // Funkcja wywoływana w celu zastąpienia znacznika [ksiazka].
    function boj_sc1_book() {
        return '<a href="http://www.amazon.com/dp/0470560541">książka<a/>';
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_sc1.php.

------------------------------------------------------------------------

Jak to działa?

1.  Za pomocą funkcji add_shortcode() zarejestrowano znacznik [ksiazka]
    jako nowy skrót, który będzie zastąpiony przez dane wyjściowe
    wygenerowane przez funkcję boj_sc1_book().
2.  Wywoływana funkcja zastępująca skrót (tutaj: boj_sc1_book()) musi na
    końcu zwrócić wartość za pomocą polecenia return. Błędem bardzo
    często popełnianym przez początkujących jest użycie do wyświetlenia
    wartości polecenia echo zamiast return. Trzeba pamiętać, że w tym
    przypadku nie można użyć polecenia echo.

Po aktywacji wtyczki można już napisać: "Kup moją [ksiazka]" na stronie
wpisu bloga, a znacznik zostanie zastąpiony odnośnikiem prowadzącym na
stronę w serwisie Amazon.

Warto zwrócić uwagę, że platforma WordPress jest bardzo elastyczna w
zakresie składni skrótu: można stosować znaczniki mniej lub więcej
przypominające znaczniki XHTML dowolnego typu, np. [ksiazka],
[ksiazka ], [ksiazka/] i [ksiazka /]. Jedynym warunkiem jest, aby
pomiędzy nawiasem otwierającym znacznik i samym znacznikiem nie było
spacji.

[ksiazki tytul="xkcd"]

Co zrobić w sytuacji, gdy chcesz promować więcej niż jedną książkę?

Pierwszą opcją będzie utworzenie wielu skrótów w sposób przedstawiony
powyżej, po jednym dla każdej książki (np. [ksiazka1], [ksiazka2],
[ksiazka3] itd.). Jednak znacznie bardziej eleganckim rozwiązaniem
będzie użycie atrybutu dla skrótu. W ten sposób można zastosować
sprytniejszą składnię w postaci [ksiazki tytul="prowp"] lub
[ksiazki tytul="xkcd"].

W kodzie ponownie będzie użyta ta sama funkcja add_shortcode(), ale tym
razem z nowym parametrem $attr, który pobiera tablicę atrybutu — parę
wartości.

    <?php
    /*
    Plugin Name: Przykład skrótu nr 2
    Plugin URI: http://przyklad.pl/
    Description: Zastępuje znacznik [ksiazki tytul="xxx"] różnymi odnośnikami prowadzącymi do serwisu Amazon.
    Version: 1.0
    Author: Ozh
    Author URI: http://wrox.com/
    */
    // Rejestracja nowego skrótu: [ksiazki tytul="xxx"].
    add_shortcode( 'ksiazki', 'boj_sc2_multiple_books' );
    // Funkcja wywoływana w celu zastąpienia znacznika [ksiazki].
    function boj_sc2_multiple_books( $attr ) {
        switch( $attr['tytul'] ) {
            case 'xkcd':
                $asin = '0615314465';
                $title = 'XKCD Volume 0';
                break;
            default:
            case 'prowp':
                $asin = '0470560541';
                $title = 'Professional WordPress';
                break;
        }
        return "<a href='http://www.amazon.com/dp/$asin'>$title<a/>";
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_sc2.php.

------------------------------------------------------------------------

Jak to działa?

1.  Za pomocą funkcji add_shortcode() zarejestrowano znacznik [ksiazki]
    jako nowy skrót.
2.  Funkcja odpowiedzialna za zastąpienie znacznika
    boj_sc2_multiple_books() oczekuje podania parametru $attr w postaci
    tablicy atrybutu — pary wartości do użycia w skrócie. Przykładowo po
    użyciu znacznika [ksiazki tytul="prowp"] funkcja otrzyma parametr w
    postaci array( 'tytul' => 'prowp' ).
3.  Funkcja odpowiedzialna za zastąpienie znacznika będzie zwracała
    różne wartości w zależności od przekazanego jej atrybutu.
4.  Użycie znacznika [ksiazki] bez atrybutu spowoduje, że funkcja
    otrzyma pusty ciąg tekstowy. W takim przypadku zwrócona będzie
    wartość domyślna zdefiniowana w kodzie.

[amazon asin="12345"]tytuł książki[/amazon]

Przygotowaną powyżej wtyczkę można jeszcze bardziej usprawnić, czyli
umożliwić sparametryzowanie tekstu w odnośniku prowadzącym do serwisu
Amazon.

Użyta będzie ponownie ta sama funkcja add_shortcode(), ale tym razem z
drugim parametrem — $content — który będzie przekazywał ciąg tekstowy
wykorzystany następnie jako tekst w odnośniku.

    <?php
    /*
    Plugin Name: Przykład skrótu nr 3
    Plugin URI: http://przyklad.pl/
    Description: Zastępuje znacznik [amazon isbn="xxx"]tytul ksiazki[/amazon].
    Version: 1.0
    Author: Ozh
    Author URI: http://wrox.com/
    */
    // Rejestracja nowego skrótu: [amazon isbn="123"]tytul ksiazki[/amazon].
    add_shortcode( 'amazon', 'boj_sc3_amazon' );
    // Funkcja wywoływana w celu zastąpienia znacznika [amazon].
    function boj_sc3_amazon( $attr, $content ) {
        // Pobranie numeru ASIN (Amazon Standard Identification Number).
        if( isset( $attr['asin'] ) ) {
            $asin = preg_replace( '/[^\d]/', '', $attr['asin'] );
        } else {
            $asin = '0470560541';
        }
        // Oczyszczenie treści lub ustawienie domyślnej.
        if( !empty( $content ) ) {
            $content = esc_html( $content );
        } else {
            if( $asin == '0470560541' ) {
                $content = 'Professional WordPress';
            } else {
                $content = 'ta książka';
            }
        }
        return "<a href='http://www.amazon.com/dp/$asin'>$content<a/>";
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_sc3.php.

------------------------------------------------------------------------

Jak to działa?

1.  Zarejestrowano kolejny skrót, tym razem używając znacznika [amazon].
2.  Funkcja odpowiedzialna za zastąpienie znacznika boj_sc3_amazon()
    oczekuje dwóch opcjonalnych parametrów: tablicy atrybutu — pary
    wartości do użycia w skrócie oraz ciągu tekstowego umieszczonego
    pomiędzy znacznikami skrótu otwierającym i zamykającym.
3.  Funkcja odpowiedzialna za zastąpienie znacznika musi obsłużyć różne
    kombinacje brakującego atrybutu w postaci numeru ASIN (ang. Amazon
    Standard Identification Number) i (lub) tytułu książki: znaczniki
    [amazon], [amazon asin="123"] i [amazon]super książka[/amazon]
    działają bez problemów.
4.  Skrót może zwrócić dowolną treść, więc trzeba pamiętać o
    zastosowaniu technik omówionych w rozdziale 6. Numer ASIN trzeba
    oczyścić, aby składał się jedynie z cyfr. Ponadto należy się
    upewnić, że tytuł książki może być bezpiecznie wyświetlony w Twoim
    blogu i nie zniszczy znacznika <a>, w którym będzie umieszczony.

Podsumowanie: funkcja add_shortcode() i funkcja odpowiedzialna za zastąpienie znacznika

Podczas rejestracji nowego skrótu dwa parametry definiują wzorzec
znacznika w nawiasach kwadratowych oraz funkcję wywoływaną w celu
zastąpienia znacznika:

    <?php
    add_shortcode( 'boj', 'boj_my_shortcode' );
    ?> 

Funkcja odpowiedzialna za zastąpienie znacznika pobiera dwa parametry
(puste, jeśli zostaną pominięte), czyli tablicę atrybutu — para wartości
— oraz ciąg tekstowy definiujący treść umieszczaną pomiędzy znacznikami
skrótu otwierającym i zamykającym. Podobnie jak w kodzie HTML, wielkość
liter w atrybutach nie ma znaczenia.

Tak jak w każdej innej funkcji PHP, istnieje możliwość zdefiniowania
wartości domyślnych. Trzeba pamiętać, że funkcja odpowiedzialna za
zastąpienie znacznika musi zwrócić wartość.

    <?php
    function boj_my_shortcode( $attr = array( 'var' => 'wartość' ), $content = 'książka' ) {
        // $attr to tablica asocjacyjna.
        // $content to ciąg tekstowy.
        return $something;
    }
    ?> 

Atrybuty skrótu nie rozróżniają wielkości liter, mogą mieć dowolną
wartość lub nie mieć jej wcale, a także obsługują znaki cudzysłowu lub
akceptują ich brak. Przedstawione poniżej przykłady pokazują wartości
tablicy $attr w funkcji odpowiedzialnej za zastąpienie znacznika, w
zależności od sposobu użycia skrótu:

-   [boj] : $attr będzie pustym ciągiem tekstowym;
-   [boj hello] : $attr będzie tablicą array( 'hello' );
-   [boj name=ozh skillz='1337' MAP="q3dm6"] : $attr będzie tablicą
    array ( 'name' => 'ozh', 'skillz' => '1337', 'map' => 'q3dm6' ).

Wskazówki dotyczące skrótów

Skróty to doskonały sposób wzbogacenia wpisu bloga skomplikowaną i
dynamiczną treścią. W celu zagwarantowania dostarczenia użytkownikowi
najlepszych wrażeń autor wtyczki powinien pamiętać o dwóch podstawowych
zasadach:

-   zbuduj prostą i niezawodną wtyczkę;
-   pamiętaj, że jest dynamiczna.

Pomyśl o prostocie

Użytkownik jest zadowolony, kiedy otrzymuje nowe funkcje do bloga i
jednocześnie może stosować skróty pozwalające na wyświetlanie znacznie
bardziej skomplikowanej treści. Jednak zapamiętywanie składni parametrów
skrótu jest niewygodne: powstaje wrażenie konieczności poznania nowego
języka znaczników.

Powróćmy jeszcze na chwilę do skrótu [amazon]: istnieje możliwość
przygotowania wtyczki, która będzie dodawała skrót [amazonobraz]
wyświetlający obraz produktu z serwisu Amazon. Zadaniem użytkownika jest
podanie numeru ASIN, typu obrazu (książka czy płyta CD) oraz jego
wielkości.

Po zbudowaniu wtyczka będzie zezwalała na użycie skrótu, takiego jak
[amazonobraz asin='12345' typ='CD' wielkoscobrazu='maly'].

Kiedy użytkownik posiada tę wtyczkę od dłuższego czasu, może zapomnieć
nazwy i składni atrybutów. Czy to było [amazonobraz], czy [obrazamazon]?
Czy atrybutem jest isbn, czy asin? Czy wielkoscobrazu='ogromny', czy
'duzy'? Czy typ='CD', czy typ='dysk'?

Wprawdzie posiadanie dużej liczby opcji może być zaletą, ale
równocześnie nie chcesz, aby użytkownicy musieli nieustannie sięgać do
dokumentacji, ponieważ to sprawia niekorzystne wrażenie. Warto sprawy
uprościć i pozwolić użytkownikom na instynktowne używanie wtyczki.

Po wprowadzeniu modyfikacji kod wtyczki przedstawia się następująco:

    <?php
    <?php
    /*
    Plugin Name: Przykład skrótu nr 4
    Plugin URI: http:/przyklad.pl/
    Description: Zastąpienie znacznika [amazonobraz] obrazem z serwisu Amazon.
    Version: 1.0
    Author: Ozh
    Author URI: http://wrox.com/
    */
    // Rejestracja skrótów [amazonobraz] i [obrazamazon]
    add_shortcode( 'amazonobraz', 'boj_sc4_amazonimage' );
    add_shortcode( 'obrazamazon', 'boj_sc4_amazonimage' );
    // Funkcja odpowiedzialna za zastąpienie skrótu [amazonobraz].
    function boj_sc4_amazonimage( $attr, $content ) {
        // Pobranie numeru ASIN lub ustawienie domyślnego.
        $possible = array( 'asin', 'isbn' );
        $asin = boj_sc4_find( $possible, $attr, '0470560541' );
        
        // Pobranie powiązanego identyfikatora lub ustawienie domyślnego.
        $possible = array( 'aff', 'affiliate' );
        $aff = boj_sc4_find( $possible, $attr, 'aff_id' );
        
        // Pobranie wielkości obrazu, jeśli podano.
        $possible = array( 'wielkosc', 'obraz', 'wielkoscobrazu' );
        $size = boj_sc4_find( $possible, $attr, '' );
        
        // Pobranie typu, jeśli podano.
        if( isset( $attr['type'] ) ) {
            $type = strtolower( $attr['typ'] );
            $type = ( $type == 'cd' or $type == 'dysk' ) ? 'cd' : '';
        }
        
        // Utworzenie adresu URL prowadzącego do obrazu w serwisie Amazon.
        $img = 'http://images.amazon.com/images/P/';
        $img .= $asin;
        // Opcje obrazu: wielkość.
        if( $size ) {
            switch( $size ) {
                case 'maly':
                    $size = '_AA100';
                    break;
                default:
                case 'sredni':
                    $size = '_AA175';
                    break;
                case 'duzy':
                case 'ogromny':
                    $size = '_SCLZZZZZZZ';
                    break; // Dobra praktyka, nie zapomnij o ostatnim poleceniu break.
            }
        }
        // Opcje obrazu: typ.
        if( $type == 'cd' ) {
            $type = '_PF';
        }
        // Dołączenie opcji do adresu URL, o ile podano jakiekolwiek opcje.
        if( $type or $size ) {
            $img .= '.01.'.$type.$size;
        }
        // Zakończenie tworzenia adresu URL obrazu.
        $img .= '.jpg';
        
        // Trzeba pamiętać o zwróceniu obrazu.
        return "<a href='http://www.amazon.com/dp/$asin'><img src='$img' /></a>";
    }
    // Funkcja pomocnicza:
    // Wyszukuje $find_keys w tablicy $in_array, zwraca $default, jeśli nie znajdzie $find_keys.
    function boj_sc4_find( $find_keys, $in_array, $default ) {
        foreach( $find_keys as $key ) {
            if( isset( $in_array[$key] ) )
                return $in_array[$key];
        }
        return $default;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_sc4.php.

------------------------------------------------------------------------

Najpierw uwagę należy zwrócić na rejestrację dwóch skrótów wywołujących
tę samą funkcję: w ten sposób użytkownik może użyć skrótu zarówno
[amazonobraz], jak i [obrazamazon].

Następnie warto zwrócić uwagę na to, jak wiele atrybutów jest
traktowanych jako synonimy: przy użyciu funkcji pomocniczej o nazwie
boj_sc4_find() główna funkcja odpowiedzialna za obsługę skrótu sprawdza
wartości $attr['asin'] i $attr['isbn']. Gdy ich brakuje powoduje
ustawienie wartości domyślnej.

Kiedy informacje nie są związane z platformą WordPress, warto także
przyjrzeć się sposobowi tworzenia przez wtyczkę odnośnika do obrazu w
serwisie Amazon. Podstawowy adres URL to
http://images.amazon.com/images/P/; do niego są dołączane następujące
elementy:

-   numer ASIN, np. w postaci B002OEBMN4;
-   jeśli mają być użyte opcje, trzeba dołączyć .01.;
-   pierwsza użyta opcja to wielkość: dołączenie _AA100 powoduje
    pobranie obrazu o szerokości 100 pikseli, podczas gdy dołączenie
    _SCLZZZZZZZ pobiera dużą wersję obrazu;
-   inna możliwa opcja to pobranie obrazu płyty CD: w tym celu do
    tworzonego adresu URL trzeba dołączyć _PF;
-   na końcu adres URL obrazu trzeba zakończyć, dodając .jpg.

Po aktywacji wtyczki można utworzyć nowy wpis bloga o treści
Aktualnie słucham [amazonobraz asin="B00008WT5E" typ="cd" wielkosc= "maly"],
a otrzymany wynik będzie podobny do pokazanego na rysunku 10.2.

[]

Rysunek 10.2. Wtyczka pobierająca dane z serwisu Amazon w działaniu

Pamiętaj o dynamiczności

Dane skrótu są generowane dynamicznie: za każdym razem, gdy platforma
WordPress wyświetla stronę (pojedynczy wpis bloga lub archiwum), treść
skrótu jest przetwarzana, a wszystkie skróty zastępowane są danymi
zwracanymi przez wywołania funkcji obsługujących te skróty.

Zamienniki, takie jak wykorzystane w rozdziale, są bardzo szybkie, więc
podczas rejestrowania nowego skrótu nie trzeba się przejmować
wydajnością działania platformy WordPress.

Jednak wydajność nabierze większego znaczenia, gdy skróty będą pobierały
informacje z bazy danych bądź ze zdalnych witryn internetowych.

-   W pierwszym przypadku kod spowoduje wykonanie dodatkowych zapytań
    SQL, co może drastycznie zmniejszyć wydajność w wolniejszych
    serwerach.
-   W drugim przypadku kod będzie wykonywał zewnętrzne żądania HTTP,
    które mogą spowolnić wygenerowanie całej strony, bo platforma
    WordPress będzie oczekiwała na odpowiedź ze zdalnego serwera.

W takich przypadkach warto rozważyć buforowanie wyniku przetworzenia
skrótu, np. w metadanych wpisu bloga. W kolejnej wtyczce zostanie
zaimplementowana taka technika buforowania.

Wewnętrzny sposób działania

Oprócz add_shortcode() służącej do rejestracji nowego skrótu istnieją
także inne interesujące funkcje. Ponadto warto poznać kilka faktów
dotyczących API Shortcode, które można wykorzystać w tworzonych
wtyczkach.

$shortcode_tags

Wszystkie zarejestrowane skróty są przechowywane w tablicy globalnej o
nazwie $shortcode_tags w postaci par
'nazwa_skrótu' => 'funkcja_obsługująca_dany_skrót':

    <?php
    global $shortcode_tags;
    var_dump( $shortcode_tags );
    /* Wynik:
    array (
        'wp_caption'  => 'img_caption_shortcode',
        'caption' => 'img_caption_shortcode',
        'gallery' => 'gallery_shortcode',
        'embed' => '__return_false',
        'amazonimage' => 'boj_sc4_amazonimage',
        'amazonimg' => 'boj_sc4_amazonimage',
    )
    */
    ?> 

remove_shortcode()

Przy użyciu funkcji remove_shortcode() mamy możliwość dynamicznego
wyrejestrowania skrótu, np.:

    remove_shortcode( 'amazonobraz' );

remove_all_shortcodes()

Podobnie, w celu dynamicznego wyrejestrowania wszystkich skrótów należy
użyć funkcji remove_all_shortcodes() bez parametrów. Z technicznego
punktu widzenia wymieniona funkcja po prostu zeruje tablicę globalną
$shortcode_tags, która staje się pusta.

strip_shorcodes()

Funkcja strip_shorcodes() powoduje usunięcie zarejestrowanych skrótów z
treści, co przedstawiono w poniższym przykładzie:

    <?php
    $content = <<<S
    Pewne istniejące skróty: [amazonobraz] [gallery]
    Nieistniejące skróty: [bleh] [123]
    S;
    echo strip_shortcodes( $content );
    /* Result:
    Pewne istniejące skróty:
    Nieistniejące skróty: [bleh] [123]
    */
    ?> 

shortcode_atts()

Funkcja może być użyta do porównania atrybutów podanych przez
użytkownika względem listy obsługiwanych atrybutów, a następnie do
ustawienia wartości domyślnych, jeśli będzie trzeba.

Spójrz np. na sposób działania wbudowanego skrótu [gallery].
Odpowiedzialna za jego obsługę funkcja to gallery_shortcode(), która
przetwarza atrybuty skrótu następująco:

    <?php
    function gallery_shortcode( $attr ){
        // Zdefiniowanie atrybutów obsługiwanych oraz ich wartości domyślne.
        $defaults = array(
            'order'      => 'ASC',
            'orderby'    => 'menu_order ID',
            'id'         => $post->ID,
            'itemtag'    => 'dl',
            'icontag'    => 'dt',
            'captiontag' => 'dd',
            'columns'    => 3,
            'size'       => 'thumbnail',
            'include'    => '',
            'exclude'    => ''
        );
        // Filtrowanie atrybutów podanych przez użytkownika oraz ustawienie ich wartości domyślnych, jeśli zostały pominięte.
        $options = shortcode_atts( $defaults, $attr );
        // [... dalsza część kodu...]
        // Plik: wp-includes/media.php
    }
    ?> 

Dość długa lista obsługiwanych atrybutów oraz ich wartości domyślne
zdefiniowane w tablicy $defaults są łączone z atrybutami dostarczonymi
przez użytkownika w tablicy $attr. Wszystkie nieznane atrybuty są
ignorowane.

do_shortcode()

Funkcja do_shortcode() przeszukuje pod kątem skrótów przekazany jej jako
parametr ciąg tekstowy treści, a następnie przetwarza je. Podczas
inicjalizacji platformy WordPress jest powiązana z filtrem the_content,
więc zajmuje się treścią wpisu bloga:

    <?php
    // W pliku wp-includes/shortcodes.php
    add_filter( 'the_content', 'do_shortcode', 11 );
    ?> 

Skróty rekurencyjne

Może się zdarzyć, że treść skrótu będzie zawierała inne skróty.
Przykładowo możesz zarejestrować skróty [b] i [i] do wyświetlania tekstu
pogrubionego i zapisanego kursywą. Skróty powinny działać w
zagnieżdżonej strukturze, takiej jak [b]pewien [i]ciekawy[/i] tekst[/b].

Struktura taka nie stanowi problemu, ponieważ funkcja obsługująca dany
skrót może rekurencyjnie wywołać funkcję do_shortcode():

    <?php
    // Dodanie skrótów [b] i [i].
    add_shortcode( 'i', 'boj_sc5_italic' );
    add_shortcode( 'b', 'boj_sc5_bold' );
    // Funkcja obsługująca skrót: zwraca pogrubiony tekst.
    function boj_sc5_bold( $attr, $content ) {
        return '<strong>' . do_shortcode( $content ) . '</strong>';
    }
    // Funkcja obsługująca skrót: zwraca tekst zapisany kursywą.
    function boj_sc5_italic( $attr, $content ) {
        return '<em>' . do_shortcode( $content ) . '</em>';
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_sc5.php.

------------------------------------------------------------------------

Każda funkcja obsługująca skrót upewnia się, że przetworzony zostanie
skrót znajdujący się w tekście danego skrótu.

Kod BBCode we wtyczce obsługującej komentarze

Na tym etapie można utworzyć nową wtyczkę, która umożliwi stosowanie w
komentarzach znaczników typu BBCode. W większości forów zamiast zwykłych
znaczników HTML, np. <a> lub <b>, komentujący muszą stosować znaczniki,
takie jak [url] i [b].

Wtyczka będzie ponadto charakteryzowała się następującymi cechami.

-   Nie będzie zmieniać sposobu tworzenia wpisów bloga przez autorów
    (czyli z użyciem znaczników HTML).
-   W komentarzach nie będą stosowane skróty zarejestrowane do używania
    w innych miejscach wpisu bloga, takie jak np. zdefiniowany wcześniej
    skrót [amazonobraz] lub [gallery].

Poniżej przedstawiono pełny kod wtyczki.

    <?php
    /*
    Plugin Name: Przykład skrótu nr 6
    Plugin URI: http://przyklad.pl/
    Description: Umożliwia stosowanie skrótów [url] i [b] w komentarzach.
    Version: 1.0
    Author: Ozh
    Author URI: http://wrox.com/
    */
    // Rejestracja dla zaczepu 'comment_text' funkcji odpowiedzialnej za przetworzenie komentarza.
    add_filter( 'comment_text', 'boj_sc6_comments' );
    // Funkcja przetwarzająca treść komentarza.
    function boj_sc6_comments( $comment ) {
        
        // Zapisanie zarejestrowanych skrótów.
        global $shortcode_tags;
        $original = $shortcode_tags;
        
        // Wyrejestrowanie wszystkich skrótów.
        remove_all_shortcodes();
        
        // Zarejestrowanie nowych skrótów.
        add_shortcode( 'url', 'boj_sc6_comments_url' );
        add_shortcode( 'b', 'boj_sc6_comments_bold' );
        add_shortcode( 'strong', 'boj_sc6_comments_bold' );
        
        // Usunięcie wszystkich znaczników HTML z komentarza.
        $comment = wp_strip_all_tags( $comment );
        
        // Przetworzenie treści komentarza z uwzględnieniem skrótów.
        $comment = do_shortcode( $comment );
        
        // Wyrejestrowanie skrótów komentarza, przywrócenie zapisanych skrótów.
        $shortcode_tags = $original;
        
        // Zwrócenie komentarza.
        return $comment;
    }
    // Skrót [b] lub [strong] powoduje wywołanie funkcji zastępującej skrót znacznikiem <strong>.
    function boj_sc6_comments_bold( $attr, $text ) {
        return '<strong>' .do_shortcode( $text ). '</strong>';
    }
    // Skrót [url] powoduje wywołanie funkcji zastępującej skrót znacznikiem <a>.
    function boj_sc6_comments_url( $attr, $text ) {
        $text = esc_url( $text );
        return "<a href=\"$text\">$text</a>";
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_sc6.php.

------------------------------------------------------------------------

Jak to działa?

1.  Jak możesz zobaczyć, wtyczka nie powoduje zarejestrowania nowych
    skrótów [url] i [b] od razu na początku, ponieważ w takim przypadku
    wpływałyby one na treść wpisu bloga. Pierwszym zadaniem wtyczki jest
    przechwycenie treści komentarza.
2.  Funkcja przetwarzająca komentarz boj_sc6_comments() najpierw tworzy
    kopię wszystkich skrótów, a następnie je wyrejestrowuje.
3.  Kolejnym krokiem jest rejestracja nowych skrótów: [url] i [b]. (W
    celu ułatwienia życia użytkownikowi [strong] jest odpowiednikiem
    [b]).
4.  Z treści komentarza przechowywanej w zmiennej $comment następuje
    usunięcie zwykłych znaczników HTML, a następnie zastosowanie nowo
    zarejestrowanych skrótów.
5.  Warto zwrócić uwagę, jak funkcja odpowiedzialna za pogrubienie
    tekstu rekurencyjnie wywołuje funkcję do_shortcode(), co pozwala na
    stosowanie zagnieżdżonych struktur.
6.  Kolejny krok to przywrócenie oryginalnych skrótów, przy okazji
    następuje wyrejestrowanie skrótów komentarza [url] i [b].
7.  Sformatowana treść komentarza zostaje zwrócona w celu wyświetlenia.

Teraz możesz aktywować wtyczkę i dodać nowy komentarz. Spójrz na rysunek
10.3, aby przekonać się, jak ignorowane są znaczniki HTML. Skróty [b] i
[url] są przetwarzane, ale zwykłe skróty, takie jak [gallery], które są
przetwarzane we wpisie bloga, są w komentarzach ignorowane.

[]

Rysunek 10.3. Wtyczka umożliwiająca stosowanie znaczników typu BBCode w
działaniu

Ograniczenia skrótów podczas obsługi struktur zagnieżdżonych

Jak się wcześniej dowiedziałeś, platforma WordPress potrafi obsługiwać
zagnieżdżone struktury skrótów przy założeniu, że funkcje odpowiedzialne
za ich obsługę rekurencyjnie wywołują do_shortcode(). Jednak tego
rodzaju rozwiązanie ma swoje ograniczenia i czasami może po prostu nie
działać, o czym się wkrótce przekonasz.

Struktura przedstawiona poniżej jest obsługiwana prawidłowo, ponieważ
zagnieżdżone skróty są inne, a każdy z nich jest prawidłowo osadzony:

    Działa:
    [foo]
        [bar]
            [baz]
        [/bar]
    [/foo] 

Struktura przedstawiona niżej nie będzie prawidłowo obsłużona, bo
osadzony skrót jest taki sam jak skrót, w którym się zawiera:

    Nie działa:
    [foo]
        [foo]
        [/foo]
    [/foo] 

Pamiętaj, że skróty mogą być samozamykające się (samodzielny skrót [foo]
lub [foo/]) bądź mogą zawierać treść ([foo]treść[/foo]). Wspomniana
treść również może uniemożliwiać prawidłowe przetwarzanie pewnych
struktur:

    Nie działa:
    [foo]
    [foo]
        treść
    [/foo] 

Integracja z usługą Google Mapy

Jako pełny i znacznie bardziej skomplikowany przykład użycia skrótów
utworzymy wtyczkę pozwalającą na integrację usługi Google Mapy z Twoją
witryną bazującą na platformie WordPress.

Google oferuje wiele różnych API pozwalających na uzyskanie dostępu do
usług, szczególnie do usługi map. Usługa ta bazuje na dwóch powiązanych
z nią usługach: API Google Geocoding i API Google Maps.

------------------------------------------------------------------------

Uwaga

Google udostępnia dokładną dokumentację API Google Maps. Więcej
informacji na ten temat można znaleźć na stronie
http://code.google.com/​apis/maps/documentation/​javascript/.

------------------------------------------------------------------------

W tym podrozdziale utworzymy wtyczkę pozwalającą na konwersję adresu
zapisanego w postaci zwykłego tekstu (np. ul. Kościuszki 1c, 44-100
Gliwice) na dynamicznie generowaną, interaktywną mapę Google.

Uzyskanie dostępu do API Google Geocoding

Pierwszym krokiem podczas konwersji adresu na mapę jest utworzenie
"geokodu" adresu. Tworzenie geokodu to proces opisany jako konwersja
standardowego adresu (np. ul. Kościuszki 1c, 44-100 Gliwice) na
współrzędne geograficzne (50.289, 18.660). Współrzędne są używane przez
API Google Maps do znalezienia wskazanego położenia na mapie oraz
umieszczenia na niej znaczników zależnych od podanych współrzędnych.

Obecnie API Google Geocoding zwraca wyniki w dwóch formatach: JSON i
XML. W omawianym tutaj przykładzie zostanie wykorzystany format JSON.
Ponadto będziemy stosować techniki omówione w rozdziale 9., który jest
poświęcony wykonywaniu i obsłudze żądań HTTP.

Firma Google uprościła proces współpracy z API. W celu otrzymania
współrzędnych można wykonać żądanie na następujący adres URL:
http://maps.google.com/​maps/api/geocode​/$output?$parameters, gdzie
$output oznacza format danych wyjściowych (np. 'json'), natomiast
$parameter to ciąg tekstowy zapytania zawierający parametry dodatkowe
dla geokodu.

Do API trzeba przekazać tylko dwa wymagane parametry: address lub latlng
i sensor.

-   Ponieważ nie są znane współrzędne geograficzne, użyty będzie
    parametr address. Ten parametr to zapisany w postaci zwykłego tekstu
    pełny adres, który ma zostać zamieniony na geokod. Adres jest
    zakodowany w adresie URL.
-   Parametr sensor wskazuje, czy żądanie pochodzi z urządzenia
    zawierającego sensor lokalizacji (np. smartfon). Tej zmiennej
    ustawimy wartość false.

Możesz to bardzo łatwo przetestować: wczytaj API Google Geocoding
poprzez uruchomienie dowolnej przeglądarki internetowej i przejdź na
stronę
http://maps.google.com/maps/​api/geocode/json?address=Kościuszki+​1c+Gliwice&sensor=false.

Jak widać, zwrócone dane JSON zawierają współrzędne geograficzne
podanego adresu, a także dane dodatkowe, takie jak kod pocztowy (który
nie został podany w żądaniu).

Teraz możemy przystąpić do tworzenia funkcji boj_gmap_geocode(), która
wygeneruje geokod dla wskazanego adresu:

    <?php
    // Utworzenie geokodu na podstawie adresu: wartością zwrotną jest tablica zawierająca współrzędne geograficzne.
    function boj_gmap_geocode( $address ) {
        // Utworzenie adresu URL do API Google Geocoding.
        $map_url = 'http://maps.google.com/maps/api/geocode/json?address=';
        $map_url .= urlencode( $address ).' & sensor=false';
        // Wykonanie żądania GET.
        $request = wp_remote_get( $map_url );
        // Pobranie obiektu JSON.
        $json = wp_remote_retrieve_body( $request );
        // Upewnienie się, że żądanie zakończyło się powodzeniem. W przeciwnym razie trzeba zwrócić false.
        if( empty( $json ) )
            return false;
        // Odkodowanie obiektu JSON.
        $json = json_decode( $json );
        // Pobranie współrzędnych geograficznych.
        $lat = $json->results[0]->geometry->location->lat;    // Szerokość geograficzna.
        $long = $json->results[0]->geometry->location->lng;   // Długość geograficzna.
        // Zwrócenie tablicy zawierającej współrzędne geograficzne.
        return compact( 'lat', 'long' );
    }
    ?> 

Funkcja wykonuje żądanie do API Google Geocoding i otrzymuje odpowiedź w
formacie JSON, która po zdekodowaniu będzie zawierała współrzędne
geograficzne. Można to sprawdzić, analizując otrzymaną wartość zwrotną:

    <?php
    $coords = boj_gmap_geocode( 'ul. Kościuszki 1c, Gliwice' );
    var_dump( $coords );
    /* Wynik:
    array(2) {
      ["lat"]=>  float(50.28891549)
      ["long"]=>  float(18.65953990)
    }
    */
    ?> 

Więcej informacji wraz z objaśnieniem funkcji użytych w powyższej
funkcji można znaleźć w rozdziale 9.

Przechowywanie wyników

Jednym z ważniejszych aspektów skrótów jest fakt, że za każdym razem
dynamicznie generują swoją treść. Jednak wykonywanie żądania HTTP do API
Google Geocoding podczas każdego wyświetlania wpisu bloga nie będzie
efektywnym rozwiązaniem, ponieważ doprowadzi do spowolnienia wczytywania
każdej strony.

Alternatywą jest przechowywanie współrzędnych danego adresu w metadanych
dołączanych do wpisu bloga. W ten sposób podczas kolejnego wyświetlenia
wpisu bloga współrzędne geograficzne zostaną pobrane z bazy danych wraz
z pozostałymi metadanymi wpisu bloga. W ten sposób unika się wykonywania
dodatkowego żądania HTTP.

------------------------------------------------------------------------

Uwaga

Metadane wpisu bloga dostępne w interfejsie WordPress są pobierane razem
z samym wpisem bloga. Tak więc odczyt tych informacji nie powoduje
wykonania dodatkowego zapytania SQL. Więcej informacji na temat
metadanych znajduje się w rozdziale 11.

------------------------------------------------------------------------

Zamiast pobierać współrzędne z API Google za pomocą funkcji
boj_gmap_geocode(), można użyć funkcji proxy o nazwie
boj_gmap_get_coords(), która sprawdza dostępność tych informacji w
metadanych wpisu bloga. Jeżeli informacje nie zostaną znalezione w
metadanych, będą pobrane z API Google, a następnie zapisane w metadanych
w celu ich późniejszego wykorzystania.

Poniżej przedstawiono kod funkcji proxy:

    <?php
    // Konwersja adresu zapisanego w postaci zwykłego tekstu na współrzędne geograficzne.
    // Współrzędne będą pobrane z metadanych, o ile to możliwe. W przeciwnym razie będą pobrane z API Google.
    function boj_gmap_get_coords( $address = 'ul. Kościuszki 1c, Gliwice' ) {
        // Identyfikator bieżącego wpisu bloga.
        global $id;
        // Sprawdzenie, czy współrzędne geograficzne znajdują się w bazie danych.
        $saved = get_post_meta( $id, 'boj_gmap_addresses' );
        foreach( (array)$saved as $_saved ) {
            if( isset( $_saved['address'] ) && $_saved['address'] == $address ) {
                extract( $_saved );
                return compact( 'lat', 'long' );
            }
        }
        // Współrzędne nie są jeszcze buforowane, więc trzeba je pobrać z Google.
        $coords = boj_gmap_geocode( $address );
        if( !$coords )
            return false;
        // Buforowanie wyniku w metadanych wpisu bloga.
        add_post_meta( $id, 'boj_gmap_addresses', array(
            'address' => $address,
            'lat' => $coords['lat'],
            'long' => $coords['long']
            )
        );
        extract( $coords );
        return compact( 'lat', 'long' );
    }
    ?> 

Gdy adres będzie po raz pierwszy konwertowany na geokod, wywołanie
add_post_meta() spowoduje wstawienie do metadanych (o nazwie
boj_gmap_addresses) wpisu bloga tablicy, podobnej do przedstawionej
poniżej:

    array(
        "address" => "ul. Kościuszki 1c, Gliwice",
        "lat"     => "50.28891549",
        "long"    => "18.65953990"
    ) 

Podczas kolejnego wczytywania strony współrzędne geograficzne powinny
już być znalezione i pobrane wraz z metadanymi wpisu bloga.

Uzyskanie dostępu do API Google Maps

Kiedy wiadomo, w jaki sposób skonwertować adres na współrzędne
geograficzne przy użyciu API Google Geocoding, można przystąpić do
wykorzystania tych współrzędnych w usłudze Google Mapy za pomocą API
Google Maps.

Koncepcje API

Interaktywne mapy usługi Google Mapy są tworzone za pomocą kodu
JavaScript. Ten kod musi być wstawiony na stronie, na której ma zostać
wyświetlona mapa. Przed rozpoczęciem integracji usługi z wtyczką warto
dowiedzieć się, jak można osadzić mapę na stronie HTML.

Na początek trzeba dodać skrypt główny:

    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false">

Następnie należy wstawić kod JavaScript dotyczący map i mieszczący się
we własnej funkcji:

    function initialize_map() { 

Obiekt przechowuje nowy egzemplarz Google Maps wraz z podanymi
parametrami szerokości i długości geograficznej:

    var myLatlng = new google.maps.LatLng(45.124099,-123.113634); 

Inny obiekt może zdefiniować opcje mapy: poziom przybliżenia,
wycentrowanie oraz rodzaj mapy (teren, mapa, satelita lub widok
hybrydowy):

    var myOptions = {
        zoom: 4,
        center: myLatlng,
        mapTypeId: google.maps.MapTypeId.SATELLITE
    } 

Teraz mapę można już dołączyć do obiektu HTML, takiego jak <div>; w
omawianym przykładzie obiekt ma atrybut o identyfikatorze map_canvas:

    var map = new google.maps.Map( document.getElementById("map_canvas"), myOptions ); 

Przedstawiony poniżej ciąg tekstowy przechowuje własny tekst
wyświetlający informacje w oknie, które się pokazuje po kliknięciu
znacznika znajdującego się na mapie:

    var contentString = '<div id="content">'+
        '<p><b>Ikona Firefox</b>: Gdzieś w Oregonie, ta ikona o średnicy 67 '+
        'metrów została utworzona przez grupę użytkowników systemu Linux Uniwersytetu '+
        'Stanowego w celu świętowania wydania przeglądarki Firefox 2</p>'+
        '</div>'+
        '</div>'; 

Ten ciąg tekstowy jest teraz dołączony do nowego egzemplarza obiektu
InfoWindow:

    var infowindow = new google.maps.InfoWindow({
        content: contentString
    }); 

Pozostało umieszczenie znacznika na mapie:

    var marker = new google.maps.Marker({
        position: myLatlng,
        map: map,
        title: 'Ikona Firefox'
    }); 

Trzeba jeszcze zdefiniować odpowiednie zachowanie, czyli wyświetlenie
okna z informacjami po kliknięciu znacznika:

        google.maps.event.addListener(marker, 'click', function() {
            infowindow.open(map,marker);
        });
    } 

Prawie gotowe! Teraz tworzymy pusty obiekt HTML, który otrzyma mapę, i
wywołujemy funkcję JavaScript odpowiedzialną za wyświetlenie mapy:

    <p>Mapa jest wyświetlona poniżej:</p> 
    <div id="map_canvas" style="width:600px;height:600px"></div> 
    <script type="text/javascript">initialize_map()</script>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku google_map_api_example.html.

------------------------------------------------------------------------

W pliku przedstawiono koncepcję używania API Google Maps w celu
wyświetlenia mapy (zobacz rysunek 10.4).

Teraz jesteś przygotowany do implementacji dynamicznej mapy Google we
własnej wtyczce.

Implementacja wtyczki

Trzeba przygotować główną część wtyczki: funkcję rejestrującą skrót
[googlemap] i wyświetlającą mapę Google. Skrót będzie używany w
następujący sposób:

     [googlemap width=500 height=300 zoom=12]ul. Kościuszki 1c, Gliwice[/googlemap]

[]

Rysunek 10.4. Gotowa mapa wyświetlona w przeglądarce internetowej

Najpierw należy zarejestrować sam skrót. Można również zarejestrować
podobne skróty, np. [googlemaps], [google_map] i [google_maps], które
będą obsługiwane przez tę samą funkcję.

    <?php
    // Dodanie obsługi skrótu [googlemap].
    add_shortcode( 'googlemap', 'boj_gmap_generate_map' ); 

Kolejny krok to rozpoczęcie definiowania funkcji odpowiedzialnej za
analizę i przetworzenie atrybutów skrótu oraz jego treści:

    // Funkcja odpowiedzialna za obsługę skrótu.
    function boj_gmap_generate_map( $attr, $address ) {
        // Ustawienie wartości domyślnych mapy.
        $defaults = array(
            'width'  => '500',
            'height' => '500',
            'zoom'   => 12,
        );
        // Pobranie atrybutów mapy (w przypadku ich pominięcia będą miały wartości domyślne).
        extract( shortcode_atts( $defaults, $attr ) ); 

W części pierwszej następuje przygotowanie tablicy wartości domyślnych
połączonych z rzeczywistymi atrybutami przy użyciu funkcji
shortcode_atts(), która zwraca tablicę. Wywołanie extract() powoduje
zaimportowanie zmiennych z tablicy w taki sposób, że dla egzemplarza
array( 'size' => 300 ) otrzymamy $size = 300.

    // Pobranie współrzędnych.
    $coord = boj_gmap_get_coords( $address );
    // Upewniamy się, że mamy współrzędne. W przeciwnym razie trzeba zwrócić pusty ciąg tekstowy.
    if( !$coord )
        return ''; 

W tym miejscu utworzono geokod na podstawie adresu (albo pobrano z API
albo z bazy danych wraz z metadanymi wpisu bloga). Gdy utworzenie
geokodu zakończy się niepowodzeniem (np. na skutek tymczasowego problemu
między serwerami Twoim i Google), należy zwrócić pusty ciąg tekstowy.

    // Dane wyjściowe skrótu.
    $output = '';
    // Przypisanie wartości zmiennym $lat i $long.
    extract( $coord ); 

Po przygotowaniu wszystkich wymaganych zmiennych, a przed wygenerowaniem
danych wyjściowych, trzeba je oczyścić. Niektóre będą umieszczone w
ciągach tekstowych JavaScript, jeszcze inne użyte jako atrybuty
elementów HTML. Konieczne jest więc prawidłowe ich oczyszczenie, zgodnie
z opisem przedstawionym w rozdziale 6.

    // Oczyszczenie zmiennych w zależności od kontekstu, w którym będą użyte.
    $lat     = esc_js( $lat );
    $long    = esc_js( $long );
    $address = esc_js( $address );
    $zoom    = esc_js( $zoom );
    $width   = esc_attr( $width );
    $height  = esc_attr( $height );

Teraz przechodzimy do kodu JavaScript.

Główny skrypt najczęściej umieszczany jest w elemencie <head> dokumentu
HTML, ale w tym przypadku to nie jest najlepsze rozwiązanie, ponieważ
skrypt będzie wówczas wstawiony nawet na tej stronie, na której nie jest
potrzebny.

Lepiej skrypt osadzić w kodzie jako fragment kodu skrótu. W ten sposób
znajdzie się tylko na wymagającej go stronie.

    // Wygenerowanie unikalnego identyfikatora mapy, co pozwala mieć wiele map na stronie.
    $map_id = 'boj_map_'.md5( $address );
    // Tylko jednokrotne dodanie głównego skryptu Google Maps na stronie.
    static $script_added = false;
    if( $script_added == false ) {
        $output .= '<script type="text/javascript"
        src="http://maps.google.com/maps/api/js?sensor=false" ></script>';
        $script_added = true;
     } 

Teraz można wstawić kod JavaScript odpowiedzialny za obsługę mapy. Każda
funkcja i każde miejsce zarezerwowane dla mapy będą miały unikalne
nazwy, uzyskamy to, używając wcześniej wygenerowanej zmiennej $map_id,
co pozwala na umieszczenie wielu map na tej samej stronie.

    // Dodanie kodu dotyczącego mapy.
    $output .= <<<CODE
    <div id="$map_id" ></div> 
    <script type="text/javascript" > 
        function generate_$map_id() {
            var latlng = new google.maps.LatLng( $lat, $long );
            var options = {
                zoom: $zoom,
                center: latlng,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            }
            var map = new google.maps.Map(
                document.getElementById("$map_id"),
                options
            );
            var legend = '<div class="map_legend"><p> $address </p></div> ';
            var infowindow = new google.maps.InfoWindow({
                content: legend,
            });
            var marker = new google.maps.Marker({
                position: latlng,
                map: map,
            });
            google.maps.event.addListener(marker, 'click', function() {
                infowindow.open(map,marker);
            });
        }
        generate_$map_id();
    </script> 

Do danych wyjściowych dodajemy proste style w postaci atrybutów
zdefiniowanych przez użytkownika:

        <style type"text/css"> 
        .map_legend{
            width:200px;
            max-height:200px;
            min-height:100px;
        }
        #$map_id {
            width: {$width}px;
            height: {$height}px;
        }
        </style> 
    CODE; 

Oczywiście, nie wolno zapomnieć o zwróceniu treści zamiennika dla
skrótu:

        return $output;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_sc7.php.

------------------------------------------------------------------------

Na tym etapie wtyczka jest już gotowa do użycia! Utwórz nowy wpis bloga
i zastosuj np. poniższy skrót:

    [googlemap width=450 height=300 zoom=14]ul. Kościuszki 1c, Gliwice[/googlemap]

Tak utworzony wpis bloga powinien być podobny do pokazanego na rysunku
10.5.

Więcej pomysłów dotyczących skrótów

Przy użyciu skrótów można bardzo łatwo dodawać interesujące i praktyczne
funkcje, tutaj ograniczeniem jest jedynie Twoja wyobraźnia. Istnieje np.
możliwość zarejestrowania skrótu wyświetlającego treść tylko dla
zalogowanych użytkowników, wyświetlającego treść zależną ograniczoną
czasowo, zaciemniającego adres e-mail oraz wiele innych. W kolejnych
punktach zostaną przedstawione niektóre opcje.

[]

Rysunek 10.5. Wpis bloga zintegrowany z mapą Google

Wyświetlanie treści jedynie dla zalogowanych użytkowników

Pierwszy krótki implementowany skrót to elegancki sposób wyświetlenia
treści jedynie zalogowanym użytkownikom. Jego sposób użycia we wpisie
bloga może być następujący:

    Dzisiejsza porada Jedi:
    [czlonkowie]Używaj mocy[/czlonkowie] 

Funkcja odpowiedzialna za obsługę wspomnianego skrótu znajduje się w
poniższym fragmencie kodu:

    <?php
    add_shortcode( 'czlonkowie', 'boj_sc8_loggedin' );
    function boj_sc8_loggedin( $attr, $content ) {
        if( is_user_logged_in() ) {
            return $content;
        } else {
            return "<p>Tylko dla zalogowanych użytkowników</p>";
        }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_sc8.php.

------------------------------------------------------------------------

Wynikiem jest treść umieszczona pomiędzy znacznikami skrótu
[czlonkowie]. Będzie ona wyświetlona tylko zalogowanym użytkownikom.
Przykład tej samej koncepcji, jednak omówiony bardziej szczegółowo,
znajduje się w rozdziale 8.

Wyświetlenie treści ograniczonej czasowo

Innym prostym i przydatnym skrótem jest kod pozwalający na wyświetlenie
treści ograniczonej czasowo, np. odnośnik promocyjny ważny przez jedynie
24 godziny:

    Ten odnośnik promocyjny jest ważny przez jedynie 24 godziny:
    [24godziny] http://przyklad.pl/promo/ [/24godziny] 

W celu zaimplementowania takiego skrótu trzeba wykorzystać przedstawiony
poniżej fragment kodu, który po prostu sprawdza bieżącą godzinę oraz
godzinę opublikowania wpisu bloga:

    <?php
    add_shortcode( '24godziny', 'boj_sc8_24hours' );
    function boj_sc8_24hours( $attr, $content ) {
        $now = time();
        $post_time = get_the_date( 'U' );
        if( ( $now - $post_time ) > 86400 ) {
            return 'Oferta wygasła!';
        } else {
            return $content;
        }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_sc8.php.

------------------------------------------------------------------------

Jeżeli bieżący wpis bloga był opublikowany wcześniej niż 86 400 sekund
wcześniej (czyli 24 godziny), to tekst znajdujący się między znacznikami
[24godziny] nie zostanie wyświetlony.

Zaciemnienie adresu e-mail

W kolejnym krótkim i użytecznym skrócie pokazano praktyczny sposób
konwersji adresu e-mail zapisanego w postaci zwykłego tekstu na odnośnik
mailto:, który będzie zaciemniony (tzn. mniej czytelny) dla robotów
spamowych. We wpisie bloga wystarczy po prostu użyć skrótu:

    Napisz do mnie na adres [email]ozh@ozh.org[/email] 

Funkcja obsługująca skrót wykorzystuje funkcję WordPress o nazwie
antispambot(), która po prostu konwertuje znaki na encje HTML, które są
trudniejsze do odczytania przez roboty spamowe i roboty kolekcjonujące
adresy e-mail:

    <?php
    add_shortcode( 'email', 'boj_sc8_email' );
    function boj_sc8_email( $attr, $content ) {
        if( is_email( $content ) ) {
            $content = antispambot( $content );
            return sprintf( '<a href="mailto:%s" > %s <a/>', $content, $content );    } 
    else {
            return '';
        }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku plugin_boj_sc8.php.

------------------------------------------------------------------------

Umieszczenie adresu e-mail między znacznikami [email][/email] spowoduje
zaciemnienie tego adresu przez skrót. Przykładowo po podaniu adresu
ozh@ozh.org wartością zwrotną skrótu będzie
&#122;&#104;&#64;&#111;z&#104;&#46;org.

Podsumowanie

Skróty otwierają użytkownikom końcowym drzwi do zaawansowanej,
dostosowanej do własnych potrzeb i dynamicznej treści. Ci użytkownicy
nie muszą znać skomplikowanego kodu HTML, JavaScript, CSS lub PHP albo
mogą nie mieć ochoty na jego tworzenie.

Za pomocą skrótów można przygotować dla klientów zaawansowane makra i
znacznie zwiększyć wartość swojej pracy przy niewielkim wysiłku.

Rozdział 11 Rozbudowa wpisów bloga: metadane, własne typy wpisów bloga i taksonomie

W tym rozdziale:

-   Tworzenie własnych typów wpisu bloga
-   Używanie własnych typów wpisu bloga
-   Dodawanie i używanie metadanych wpisu bloga
-   Tworzenie własnej taksonomii
-   Używanie własnej taksonomii

Na platformie WordPress wpisy bloga reprezentują treść danej witryny.
Treść ta to najczęściej najważniejszy aspekt posiadania witryny
internetowej. Z kolei taksonomie to sposób klasyfikacji bądź
kategoryzowania blogu. Natomiast metadane to informacje dodatkowe
dotyczące poszczególnych wpisów bloga. Poszczególne elementy można
łączyć, tworząc w ten sposób dowolny rodzaj witryny internetowej.

W tym rozdziale powstanie jedna wtyczka przeznaczona do obsługi kolekcji
muzycznej użytkownika. Wtyczka będzie wspomagana zarówno przez typy
wpisów bloga, jak i taksonomie. Niemal każdy fragment kodu przedstawiony
w rozdziale przyczynia się do rozbudowy wtyczki i pokazuje, jak omawiane
tutaj koncepcje pomagają w zarządzaniu treścią.

Warto pamiętać o jednej ważnej rzeczy dotyczącej typów wpisu bloga,
metadanych wpisu bloga i taksonomii — ich wyświetlanie jest najczęściej
kontrolowane przez motywy. Dlatego też twórca wtyczki nie zawsze
zachowuje pełną kontrolę nad sposobem ich obsługi. Oczywiście, zależy to
od funkcji wtyczki dostarczanej użytkownikowi. Tworzenie motywów
platformy WordPress wychodzi poza zakres tematyczny tej książki. Jednak
zdobycie wiedzy dotyczącej sposobu działania motywów w środowisku
WordPress może zwiększyć Twoje umiejętności z zakresu tworzenia wtyczek.

Tworzenie własnych typów wpisów bloga

Domyślnie platforma WordPress oferuje kilka predefiniowanych typów
wpisów bloga, które pozwalają użytkownikom na tworzenie treści witryny i
zarządzanie nią. Dla przeciętnego użytkownika bloga dostarczane
standardowe typy wpisów bloga są w zupełności wystarczające.

-   Wpis bloga — wpisy bloga są zwykle wyświetlane na witrynie
    internetowej w kolejności od najnowszego do najstarszego.
-   Strona — najwyższego poziomu, hierarchiczne typy treści, takie jak
    Autor, Kontakt i wiele innych stron.
-   Załącznik — pliki multimedialne dołączane do innych typów wpisu
    bloga, np. obrazy lub pliki wideo dla wpisu bloga.
-   Wersja wpisu bloga — różne wersje innych typów wpisu bloga używane
    jako system kopii zapasowej na wypadek konieczności przywrócenia
    starszej wersji.
-   Element menu nawigacyjnego — elementy dodawane do menu nawigacyjnego
    za pomocą wbudowanego w WordPress systemu zarządzania menu.

Ponieważ WordPress staje się coraz szerzej używanym systemem, tworzenie
innych typów treści to konieczność w witrynach, którym nie wystarczają
wymienione typy predefiniowane, przygotowane pod kątem prowadzenia
bloga. Platforma WordPress umożliwia twórcom wtyczek budowanie innych
typów treści przeznaczonych do obsługi różnych wymagań.

Możliwe typy wpisów bloga

Po wydaniu WordPress 3.0 użytkownicy uzyskali nieskończone możliwości.
Mogą oni wykorzystać platformę do uruchamiania dowolnego typu witryny
internetowej. Platforma WordPress stała się poważnym kontrkandydatem dla
innych, znacznie solidniejszych systemów zarządzania treścią (CMS). Nie
jest już uznawana za platformę przeznaczoną tylko do prowadzenia bloga.

Obecnie na platformie WordPress można używać własnych typów wpisów bloga
w celu zdefiniowania dowolnego rodzaju treści. Poniżej wymieniono
przykładową listę pomysłów, które mogą być obsługiwane za pomocą
własnych typów wpisu bloga. Oto one:

-   kolekcja muzyczna;
-   opinie o produkcie;
-   sklep internetowy;
-   cytaty;
-   zdarzenia kalendarza;
-   portfolio;
-   baza danych książek;
-   pokaz slajdów;
-   wideo.

Rejestracja typu wpisu bloga

Platforma WordPress ułatwia programistom tworzenie nowych wpisów bloga
przy użyciu niewielkiej ilości kodu. Przed zagłębieniem się w proces
tworzenia własnego typu wpisu bloga trzeba poznać podstawowe funkcje
stosowane podczas opracowywania własnych typów wpisów bloga oraz ich
argumenty.

register_post_type()

Utworzenie nowego typu wpisu bloga dla witryny następuje za pomocą
funkcji register_post_type(). Funkcja jest prosta w użyciu i podczas
tworzenia typu wpisu bloga daje twórcy wtyczki dużą elastyczność.

    <?php
    register_post_type( $post_type, $args );
    ?> 

Wartością zwrotną funkcji register_post_type() jest obiekt typu wpisu
bloga, a sama funkcja akceptuje dwa parametry:

-   $post_type — nazwa typu wpisu bloga, powinna zawierać jedynie znaki
    alfanumeryczne oraz znak podkreślenia;
-   $args — tablica argumentów definiujących typ wpisu bloga oraz sposób
    jego obsługi przez platformę WordPress.

Platforma WordPress pozwala na stosowanie wielu różnych argumentów dla
parametru $args; każdy ma własną unikalną funkcjonalność, która
umożliwia zdefiniowanie sposobu działania własnego typu wpisu bloga w
środowisku WordPress. Przedstawione poniżej opisy pozwalają na ogólne
zrozumienie każdego z nich.

public

Argument określa, czy własny typ wpisu bloga będzie wyświetlany na
publicznie dostępnych stronach witryny oraz w obszarze administracyjnym.
Wartością domyślną jest false. To jest argument definiujący argumenty
show_ui, publicly_queryable i exclude_from_search, jeżeli nie zostały
ustawione pojedynczo.

show_ui

Ten argument wskazuje, czy strony administracyjne w obszarze
administracyjnym powinny być wyświetlane dla tego typu wpisu bloga.
Wartość domyślna jest ustawiana przez argument public.

publicly_queryable

Argument określa, czy typ wpisu bloga powinien być dostępny publicznie
na stronach witryny internetowej. Wartość domyślna jest ustawiana przez
argument public.

exclude_from_search

Ten argument pozwala na wyłączenie typów wpisu bloga z wyników
wyszukiwania w danej witrynie. Wartość domyślna jest ustawiana przez
argument public.

supports

Argument pozwala wtyczce na zdefiniowanie funkcji obsługiwanych przez
własny typ wpisu bloga. Akceptuje tablicę wartości, które są wewnętrznie
sprawdzane przez WordPress. Jednak funkcje obsługiwane przez platformę
WordPress to nie jedyne, które mogą być obsłużone przez własny typ wpisu
bloga. Inne wtyczki lub motywy mogą opcjonalnie weryfikować możliwość
obsługi określonych funkcji.

Platforma WordPress sprawdza możliwość obsługi funkcji wymienionych
poniżej. Jeżeli wtyczka nie ustawi tego argumentu, wartościami
domyślnymi są title i editor.

-   title — pozwala użytkownikom na podanie tytułu wpisu bloga.
-   editor — wyświetla edytor treści na stronie edycji wpisu bloga oraz
    pozwala na umieszczanie treści multimedialnej.
-   author — oferuje rozwijane menu, z którego można wybrać autora
    danego wpisu bloga.
-   thumbnail — pozwala na kompleksową obsługę obrazów dla wpisu bloga.
-   excerpt — na stronie edycji wpisu bloga wyświetla edytor pozwalający
    na podanie fragmentu wpisu.
-   comments — pozwala na ustalenie, czy dla danego typu wpisu bloga
    dozwolone będzie dodawanie komentarzy.
-   trackbacks — określa, czy dla danego typu wpisu bloga dozwolone
    będzie stosowanie mechanizmów trackback i pingback.
-   custom-fields — na stronie edycji wpisu bloga wyświetla obszar
    pozwalający na edycję własnych pól.
-   page-attributes — wyświetla pole atrybutów pozwalające na ustalenie
    kolejności wpisów bloga. Aby to działało, argument hierarchical musi
    mieć ustawioną wartość true.
-   revisions — zapisuje wersje tego typu wpisów bloga.

labels

Argument jest tablicą ciągów tekstowych wyświetlanych w różnych
miejscach obszaru administracyjnego dla danego typu wpisu bloga.
Informacje szczegółowe dotyczące każdej etykiety znajdują się w tym
rozdziale, w punkcie "Ustawianie etykiet we własnym typie wpisu bloga".

capability_type

Argument pozwala na dodanie własnego zbioru możliwości. To rodzaj
zestawu, w którym tworzone są nowe możliwości. Argument może nadpisywać
poszczególne zestawy możliwości. Wartością domyślną jest post.

capabilities

Ten argument jest tablicą własnych możliwości wymaganych podczas edycji,
usuwania, czytania i publikowania wpisów bloga danego typu. Więcej
informacji na ten temat znajduje się w punkcie "Używanie własnych
możliwości".

hierarchical

Argument pozwala na określenie, że wpisy bloga tego typu będą układane
hierarchicznie (podobnie jak w przypadku typu page oferowanego przez
WordPress) lub niehierarchicznie (podobnie jak w przypadku typu post
oferowanego przez WordPress). Po ustawieniu argumentowi wartości true
wpisy bloga będą mogły być układane hierarchicznie, w strukturze
przypominającej drzewo. Wartością domyślną argumentu jest false.

has_archive

Ten argument buduje stronę archiwum dla danego typu wpisów bloga.
Przypomina to stronę tworzoną przez platformę WordPress dla wpisów typu
wpis bloga i wyświetlającą kilka ostatnich wpisów. Sposób wyświetlania
tych wpisów bloga zależy od motywu zainstalowanego przez użytkownika.
Domyślnie wartością argumentu jest false. Po ustawieniu wartości true
platforma WordPress utworzy stronę archiwum.

query_var

Argument jest nazwą zmiennej zapytania dla wpisów bloga danego typu.
Przykładowo zmienna ta będzie używana podczas pobierania z bazy danych
tego typu wpisów bloga.

rewrite

Ten argument tworzy unikalne bezpośrednie odnośniki dla danego typu
wpisu bloga. Poprawne wartości argumentu to true, false oraz tablica.
Wartość true oznacza utworzenie bezpośrednich odnośników na podstawie
argumentu query_var oraz tytułów poszczególnych wpisów bloga. Wartość
false oznacza brak tworzenia struktury odnośników bezpośrednich.

Jeżeli użyta jest tablica, można ustawić kilka wartości.

-   with_front — określenie, czy odnośniki bezpośrednie będą poprzedzone
    prefiksem. Wartością domyślną jest true.
-   slug — unikalny ciąg tekstowy używany przed tytułem wpisu bloga w
    odnośniku bezpośrednim. Wartością domyślną tego ciągu tekstowego
    jest wartość zapisana w argumencie query_var.
-   feeds — określenie, czy dany typ wpisu bloga powinien stosować kanał
    wiadomości RSS dla utworzonych wpisów bloga. Aby ten argument
    działał, konieczne jest ustawienie wartości true argumentu
    has_archive. Jeżeli argument feeds nie zostanie podany, przyjmie
    wartość argumentu has_archive.
-   pages — określenie, czy strony archiwum mają być stronicowane.
    Wartością domyślną jest true. Argument jest używany tylko wtedy, gdy
    argumentowi has_archive ustawiono wartość true.

taxonomies

Argument pozwala na dodanie do danego typu wpisów bloga obsługi
istniejących taksonomii. Jako wartość akceptuje tablicę nazw taksonomii.
Więcej informacji na ten temat znajduje się w punkcie "Dołączanie
istniejących taksonomii".

menu_position

Argument pozwala na określenie położenia, w którym menu administracyjne
będzie wyświetlone w obszarze administracyjnym. Domyślnie nowe typy
wpisów bloga są dodawane po elemencie menu Komentarze.

menu_icon

Argument akceptuje nazwę pliku graficznego, który będzie użyty jako
ikona menu w menu administracyjnym.

show_in_nav_menus

Jeśli wpisy bloga danego typu mogą pojawiać się w menu nawigacyjnym
WordPress, argumentowi show_in_nav_menus należy ustawić wartość true; w
przeciwnym razie trzeba użyć false. Wartość domyślna jest ustawiana
przez argument public.

can_export

Platforma WordPress zawiera funkcje importu (eksportu) pozwalające
użytkownikom na import lub eksport wpisów bloga. Ten argument pozwala na
określenie, czy użytkownicy mogą eksportować wpisy bloga danego typu.
Wartością domyślną jest true.

register_meta_box_cb

Wtyczki mogą dodawać metadane na stronie edycji wpisu bloga. Argument
pozwala na zdefiniowanie własnej funkcji wywoływanej w celu dodania dla
danego typu wpisu bloga własnych pól metadanych za pomocą funkcji
add_meta_box(). (Więcej informacji na temat pól użytkownika znajduje się
w rozdziale 4.).

permalink_epmask

Argument pozwala na ustawienie maski bitowej dla wpisów bloga danego
typu. Wartością domyślną jest EP_PERMALINK.

Rejestracja własnego typu wpisu bloga

Po zapoznaniu się z argumentami funkcji register_post_type() warto
utworzyć pierwszy, własny typ wpisu bloga, który jest tematem przewodnim
tego rozdziału.

Pierwszym krokiem jest utworzenie nowego pliku wtyczki o nazwie
boj-music-collection-post-types.php przeznaczonego dla budowanej tutaj
wtyczki o nazwie Wpis bloga typu kolekcja muzyczna. Przedstawiony
poniżej kod jest odpowiedzialny za zarejestrowanie własnego typu wpisu
bloga o nazwie music_album.

    <?php
    /*
    Plugin Name: Wpis bloga typu kolekcja muzyczna
    Plugin URI: http://przyklad.pl
    Description: Utworzenie własnego typu wpisu bloga o nazwie music_album.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Konfiguracja typu wpisu bloga. */
    add_action( 'init', 'boj_music_collection_register_post_types' );
    /* Rejestracja typu wpisu bloga. */
    function boj_music_collection_register_post_types() {
        /* Ustawienie argumentów dla typu wpisu bloga music_album. */
        $album_args = array(
            'public' => true,
            'query_var' => 'music_album',
            'rewrite' => array(
                'slug' => 'music/albums',
                'with_front' => false,
            ),
            'supports' => array(
                'title',
                'thumbnail'
            ),
            'labels' => array(
                'name' => 'Albumy',
                'singular_name' => 'Album',
                'add_new' => 'Dodaj nowy album',
                'add_new_item' => 'Dodaj nowy album',
                'edit_item' => 'Edytuj album',
                'new_item' => 'Nowy album',
                'view_item' => 'Wyświetl album',
                'search_items' => 'Szukaj w albumach',
                'not_found' => 'Nie znaleziono albumów',
                'not_found_in_trash' => 'Nie znaleziono albumów w koszu'
            ),
        );
        /* Rejestracja typu wpisu bloga music_album. */
        register_post_type( 'music_album', $album_args );
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku
boj-music-collection-post-types.php.

------------------------------------------------------------------------

Przedstawiony powyżej kod powoduje utworzenie w obszarze
administracyjnym WordPress nowego elementu menu najwyższego poziomu o
nazwie Albumy (zobacz rysunek 11.1). Ten element menu posiada dwa
podelementy — Albumy oraz Dodaj nowy album. Pierwszy podelement powoduje
wyświetlenie strony zawierającej listę albumów (po ich utworzeniu) w
kolejności opublikowania. Natomiast drugi podelement wyświetla nową
stronę pozwalającą na opublikowanie nowego albumu.

[]

Rysunek 11.1. Nowy element menu najwyższego poziomu w obszarze
administracyjnym

------------------------------------------------------------------------

Ostrzeżenie

Funkcja tworząca we wtyczce nowe typy wpisów bloga musi być wywoływana
przez zaczep akcji init. W przeciwnym razie typ wpisu bloga nie zostanie
poprawnie zarejestrowany.

------------------------------------------------------------------------

Ustawianie etykiet we własnym typie wpisu bloga

W obszarze administracyjnym WordPress wyświetlanych jest wiele ciągów
tekstowych dotyczących typu wpisu bloga. Każdy fragment tekstu
najczęściej reprezentuje odnośnik, przycisk lub informacje dodatkowe o
danym wpisie bloga. Domyślnie hierarchiczne typy wpisów bloga zawierają
pojęcie "strony" we wspomnianych ciągach tekstowych, natomiast
niehierarchiczne — pojęcie "wpisu".

Wspomniane ciągi tekstowe są miejscami zarezerwowanymi, które wtyczka
będzie uzupełniać w zależności od utworzonego typu wpisu bloga.
Przykładowo nie chcesz wyświetlenia polecenia Wyświetl wpis bloga, a
zamiast niego chcesz otrzymać Wyświetl album. Po odpowiednim ustawieniu
wspomnianych ciągów tekstowych użytkowników wtyczki czekają znacznie
przyjemniejsze wrażenia.

Podczas początkowej konfiguracji nowego typu wpisu bloga zdefiniowano
tablicę labels dla parametru $args. Tablica zawiera wiele wartości, co
pokazano w poniższym fragmencie kodu, który pochodzi z przedstawionego
powyżej:

    <?php
    'labels' => array(
        'name' => 'Albumy',
        'singular_name' => 'Album',
        'add_new' => 'Dodaj nowy album',
        'add_new_item' => 'Dodaj nowy album',
        'edit_item' => 'Edytuj album',
        'new_item' => 'Nowy album',
        'view_item' => 'Wyświetl album',
        'search_items' => 'Szukaj w albumach',
        'not_found' => 'Nie znaleziono albumów',
        'not_found_in_trash' => 'Nie znaleziono albumów w koszu'
    ),
    ?> 

Każda ze zdefiniowanych etykiet jest wyświetlana w obszarze
administracyjnym i odpowiada za odniesienie przez użytkownika
przyjemniejszych wrażeń podczas używania wtyczki.

-   name — nazwa typu wpisu bloga w liczbie mnogiej, która czasami jest
    używana w obszarze administracyjnym WordPress oraz przez inne
    wtyczki i motywy.
-   singular_name — nazwa typu wpisu bloga w liczbie pojedynczej.
    Czasami jest używana w obszarze administracyjnym WordPress oraz
    przez inne wtyczki oraz motywy.
-   add_new — etykieta używana przez element podmenu powodujący dodanie
    nowego elementu. Wartością domyślną jest Dodaj nowy.
-   add_new_item — tekst przycisku na głównej stronie wyświetlającej
    listę wpisów pozwalającego na dodanie nowego wpisu bloga. Wartością
    domyślną jest Dodaj nowy wpis/stronę.
-   edit_item — tekst przycisku pozwalającego na edycję poszczególnych
    wpisów bloga. Wartością domyślną jest Edytuj wpis/stronę.
-   new_item — tekst przycisku pozwalającego na utworzenie nowego wpisu
    bloga. Wartością domyślną jest Nowy wpis/strona.
-   view_item — tekst przycisku pozwalającego na wyświetlenie danego
    wpisu bloga. Wartością domyślną jest Wyświetl wpis/stronę.
-   search_items — tekst przycisku pozwalającego na wyszukanie wpisów
    bloga danego typu. Wartością domyślną jest Szukaj wpisów/stron.
-   not_found — komunikat wyświetlany, gdy nie zostaną znalezione
    szukane wpisy bloga. Domyślnie wyświetlanym komunikatem jest Nie
    znaleziono żadnych wpisów/stron.
-   not_found_in_trash — komunikat wyświetlany, gdy w koszu nie zostaną
    znalezione szukane wpisy bloga. Domyślnie wyświetlanym komunikatem
    jest Nie znaleziono żadnych wpisów/stron w koszu.
-   parent_item_colon — komunikat wyświetlany podczas wyświetlania wpisu
    bloga nadrzędnego dla danego. Ten komunikat jest stosowany jedynie w
    przypadku hierarchicznych typów wpisów bloga, a jego treść domyślna
    to Strona nadrzędna:.

Wykorzystanie własnych możliwości

W niektórych instalacjach WordPress istnieje wielu użytkowników, a każdy
z nich ma własne zadania do wykonania w witrynie. Warto o tym pamiętać
podczas tworzenia własnych typów wpisów bloga, ponieważ administratorzy
witryn bardzo często przypisują różnym użytkownikom role pozwalające na
edycję i publikowanie treści w określonych sekcjach witryny. W rozdziale
8. omówiono sposoby manipulowania rolami i możliwościami. Jednak podczas
rejestracji własnych typów wpisów bloga prawdopodobnie będziesz chciał
zdefiniować swoje możliwości przeznaczone do obsługi treści.

Argumenty capability_type i capabilities w tablicy $args funkcji
register_post_type() pozwalają na przeprowadzenie odpowiedniej
konfiguracji. Argument capability_type umożliwia globalną kontrolę nad
możliwościami. Z kolei argument capabilities to tablica dająca kontrolę
nad poszczególnymi możliwościami.

Przypuśćmy, że chcesz utworzyć własne możliwości do konfiguracji
uprawnień dla własnego typu wpisów bloga. Pierwszym rozwiązaniem jest po
prostu zdefiniowanie argumentu capability_type, który może automatycznie
ustawić każdą opcję tablicy capabilities.

    <?php
    'capability_type' => 'album',
    ?> 

W ten sposób następuje utworzenie domyślnych możliwości pozwalających na
edycję, odczyt, usuwanie i publikowanie wpisów bloga, takich jak:

-   edit_album,
-   edit_albums,
-   edit_others_albums,
-   publish_albums,
-   read_album,
-   read_private_albums,
-   delete_album.

Jeżeli chcesz zachować pełną kontrolę nad nazwami tych możliwości,
konieczne jest użycie argumentu capabilities zamiast capability_type,
jak pokazano w poniższym fragmencie kodu:

    <?php
    'capabilities' => array(
        'edit_post' => 'edit_album',
        'edit_posts' => 'edit_albums',
        'edit_others_posts' => 'edit_others_albums',
        'publish_posts' => 'publish_albums',
        'read_post' => 'read_album',
        'read_private_posts' => 'read_private_albums',
        'delete_post' => 'delete_album',
    ),
    ?> 

Każda możliwość daje uprawnienia do wykonania określonego zadania
podczas procesu publikowania wpisów bloga danego typu.

-   edit_post — możliwość meta używana w celu określenia, czy użytkownik
    może edytować dany wpis bloga.
-   edit_posts — możliwość pozwalająca na tworzenie i edycję wpisów
    bloga, ale nie na ich publikowanie.
-   edit_others_posts — możliwość pozwalająca na edycję wpisów bloga
    utworzonych przez innych użytkowników.
-   publish_posts — możliwość pozwalająca na opublikowanie dowolnych
    wpisów bloga danego typu.
-   read_post —możliwość meta używana w celu określenia, czy użytkownik
    może czytać dany wpis bloga.
-   read_private_posts — możliwość pozwalająca użytkownikowi na czytanie
    wpisów bloga opublikowanych jako prywatne.
-   delete_post — możliwość meta używana w celu określenia, czy
    użytkownik może usunąć dany wpis bloga.

Nie musisz trzymać się specyficznych formuł dla własnych typów wpisów
bloga, Twoja wtyczka może je różnie łączyć. Tę samą możliwość można
ustawić dla wielu opcji. Ewentualnie ta sama możliwość może być
ustawiona dla każdej opcji. Przykładowo każdej z wymienionych możliwości
można przypisać wartość manage_music_collection, o ile wiadomo, że tylko
określeni użytkownicy będą mieli uprawnienia do zarządzania wszystkimi
wpisami bloga dotyczącymi albumów muzycznych.

Inna możliwość, którą możesz ustawić, to do_not_allow, jeśli nie chcesz
udzielać dostępu do określonego zadania. Raczej nie będziesz jej używać,
ale zdarzają się sytuacje, gdy jednak trzeba z niej skorzystać.
Przykładowo być może będzie trzeba ustawić dla możliwości
edit_others_posts wartość do_not_allow, aby użytkownik nie mógł edytować
wpisów bloga utworzonych przez innych.

Dołączanie istniejących taksonomii

Jeżeli chcesz, by w opracowywanym przez Ciebie typie wpisu bloga dało
się wykorzystać istniejące taksonomie, możesz to bardzo łatwo
skonfigurować w argumencie tablicy $args funkcji register_post_type().
Przykładowo platforma WordPress zawiera dwie ogólne taksonomie, które
doskonale sprawdzają się z pozostałymi typami wpisów bloga, czyli
category i post_tag. Jednak nie jesteś ograniczony do taksonomii
wbudowanych na platformie WordPress. Utworzony przez Ciebie typ wpisu
bloga może również stosować taksonomie oferowane przez inne wtyczki i
motywy.

Wyobraź sobie, że chcesz dodać tagi wpisu bloga do utworzonego wcześniej
typu music_album. W tym celu możesz skorzystać z przedstawionego poniżej
kodu:

    <?php
    'taxonomies' => array( 'post_tag' ),
    ?> 

Po dodaniu tej wartości do tablicy $args funkcji register_post_type() w
menu Albumy pojawi się nowy podelement Tagi wpisów, co pokazano na
rysunku 11.2.

[]

Rysunek 11.2. W menu Albumy pojawił się nowy podelement

Używanie własnych typów wpisów bloga

Skoro dowiedziałeś się, w jaki sposób tworzyć własne typy wpisów bloga,
możesz wykorzystać tę wiedzę w praktyce. Sposoby użycia własnych typów
wpisów bloga będą w ogromnym stopniu zależne od funkcjonalności danego
typu wpisu bloga. Jednak pobieranie treści dostarczanej przez wpisy
danego typu niemal zawsze bazuje na oferowanych przez platformę
WordPress funkcjach powiązanych z obsługą wpisów bloga.

Gdy szukasz funkcji pobierających informacje wpisu bloga, przyjrzyj się
dwóm plikom w instalacji platformy WordPress:

-   wp-includes/post.php — funkcje obsługi wpisów bloga i ich funkcje
    pomocnicze;
-   wp-includes/post-template.php — szablony funkcji służące do
    wyświetlania treści wpisu bloga.

Każda funkcja służy do wykonywania określonego zadania na platformie
WordPress. Podczas analizy i użycia funkcji z wymienionych plików możesz
dowiedzieć się, jak działają funkcje obsługujące wpisy bloga.

Ogólnie rzecz biorąc, wyświetlanie na stronie internetowej wpisów bloga
jest zadaniem motywu WordPress. Jednak nie wszystkie własne typy wpisów
bloga będą wyświetlane w ten sam sposób. Zależy to od funkcjonalności i
przeznaczenia własnego typu wpisu bloga. Aby skorzystać z własnych typów
wpisów bloga, trzeba poznać kilka funkcji zwykle uznawanych za należące
do motywu.

Utworzenie pętli własnego typu wpisu bloga

Kiedy chcesz pobrać zawartość wpisu lub wielu wpisów bloga, możesz
wykonać odpowiednie zapytanie do bazy danych poprzez inicjalizację
nowego obiektu WP_Query i przeprowadzenie iteracji przez każdy pobrany
wpis bloga. Wewnątrz tej pętli musisz użyć funkcji szablonu w celu
wygenerowania określonych fragmentów poszczególnych obiektów wpisu
bloga.

Załóżmy, że we wtyczce chcesz utworzyć listę tytułów wszystkich albumów
ułożoną alfabetycznie, a każdy odnośnik ma prowadzić do konkretnego
albumu w kolekcji muzycznej. Powstanie konstrukcja nazywana pętlą, w
której polecenie PHP while jest używane do przeprowadzenia iteracji
przez każdy wpis bloga.

Przedstawiony poniżej fragment kodu to przykład wykorzystania pętli za
pomocą skrótu, który użytkownicy mogą zastosować w obszarze obsługującym
skróty, takim jak edytor strony (więcej informacji na temat API skrótów
znajduje się w rozdziale 10.). W wymienionym obszarze użytkownik musi
umieścić jedynie skrót [music_albums]. Poniższy kod można dodać do
utworzonego wcześniej kodu wtyczki Wpis bloga typu kolekcja muzyczna.

    <?php
    add_action( 'init', 'boj_music_album_register_shortcodes' );
    function boj_music_album_register_shortcodes() {
        /* Rejestracja skrótu [music_albums]. */
        add_shortcode( 'music_albums', 'boj_music_albums_shortcode' );
    }
    function boj_music_albums_shortcode() {
        /* Pobranie z bazy danych informacji o albumach. */
        $loop = new WP_Query(
            array(
                'post_type' => 'music_album',
                'orderby' => 'title',
                'order' => 'ASC',
                'posts_per_page' => -1,
            )
        );
        /* Sprawdzenie, czy zostały pobrane dane jakiegokolwiek albumu. */
        if ( $loop->have_posts() ) {
            /* Początek nieuporządkowanej listy. */
            $output = '<ul class="music-collection">';
            /* Przeprowadzenie iteracji przez albumy (pętla). */
            while ( $loop->have_posts() ) {
                $loop->the_post();
                /* Wyświetlenie tytułu albumu. */
                $output .= the_title(
                    '<li><a href="' . get_permalink() . '">',
                    '</a></li>',
                    false
                );
            }
            /* Koniec nieuporządkowanej listy. */
            $output .= '</ul>';
        }
        /* Jeżeli nie znaleziono żadnych albumów. */
        else {
            $output = '<p>Nie opublikowano żadnych albumów.</p>';
        }
        /* Zwrot listy albumów muzycznych. */
        return $output;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-post-type-loop.php.

------------------------------------------------------------------------

Pętla wygeneruje listę elementów podobną do pokazanej na rysunku 11.3, o
ile zostały opublikowane jakiekolwiek albumy.

Najważniejszą częścią w przedstawionym powyżej kodzie jest argument
post_type w tablicy przekazanej do WP_Query. Jego wartością musi być
nazwa własnego typu wpisu bloga. W omawianym przykładzie użyto
music_album, ponieważ jest to nazwa własnego typu wpisu bloga.

[]

Rysunek 11.3. Lista wygenerowana przez pętlę

Jedynym ograniczeniem w sposobie wyświetlania własnych typów wpisów
bloga są umiejętności twórcy w zakresie programowania w PHP.
Przedstawioną pętlę można wykorzystać do wyświetlania wpisów bloga w
dowolny sposób. Wpisy mogą więc zostać wyświetlone w widgetach (zobacz
rozdział 4.) lub można utworzyć skrót, podobnie jak to zrobiono w
powyższym kodzie (skróty zostały omówione w rozdziale 10.). To
zdecydowanie zależy od przeznaczenia wtyczki.

Pobieranie treści własnego typu wpisu bloga

Platforma WordPress ma wiele funkcji przeznaczonych do pobierania treści
wpisu bloga. W tym punkcie skoncentrujemy się na najczęściej używanych
funkcjach pobierających dane wpisu bloga. Warto jednak pamiętać, że
oprócz przedstawionych tutaj istnieją także inne funkcje. One powinny
być stosowane wewnątrz pętli utworzonej w poprzednim punkcie. Zazwyczaj
motyw platformy WordPress korzysta ze wspomnianych funkcji do
wyświetlenia treści w witrynie internetowej. Twoja wtyczka będzie
potrzebowała tych funkcji do wyświetlenia wpisów bloga.

the_title()

Funkcja wyświetla tytuł wpisu bloga. Tytuł będzie wyświetlony tylko
wtedy, gdy został podany dla danego wpisu bloga. Jeśli przykładowo
wtyczka nie ustawi argumentu title w tablicy supports przekazywanej
funkcji register_post_type(), nie można użyć funkcji the_title() w celu
wyświetlenia tytułu. Funkcja akceptuje trzy parametry.

    <?php
    the_title( $before, $after, $echo );
    ?> 

Parametry:

-   $before — treść przeznaczona do wyświetlenia przed tytułem wpisu
    bloga. Wartością domyślną jest pusty ciąg tekstowy.
-   $after — treść przeznaczona do wyświetlenia po tytule wpisu bloga.
    Wartością domyślną jest pusty ciąg tekstowy.
-   $echo — parametr wskazuje, czy tytuł ma zostać wyświetlony na
    ekranie, czy zwrócony do dalszego użycia w kodzie PHP. Wartością
    domyślną jest true.

the_content()

Funkcja pozwala na wyświetlenie treści wpisu napisanej w edytorze wpisu
bloga. Aby wyświetlić treść, trzeba ją wcześniej utworzyć. Ponadto, aby
dodanie treści było możliwe, wartość editor musi znajdować się w tablicy
supports przekazywanej funkcji register_post_type(). Jeżeli wymieniona
wartość nie została ustawiona, prawdopodobnie nie potrzebujesz tej
funkcji.

    <?php
    the_content( $more_link_text, $stripteaser );
    ?> 

Parametry:

-   $more_link_text — tekst wyświetlany w odnośniku pozwalającym na
    przeczytanie dalszej części wpisu bloga, o ile użytkownik ustawił
    tag <!--more--> w edytorze wpisu bloga.
-   $stripteaser — treść przeznaczona do wyświetlenia przed tagiem
    <!--more-->. Wartością domyślną jest false.

the_excerpt()

Funkcja wyświetla cytat pochodzący z treści wpisu bloga. Jeżeli w
przekazywanej funkcji register_post_type() tablicy supports zdefiniowano
argument excerpt, można utworzyć pole z cytatem, w którym użytkownik
umieści własny cytat. Jeśli argument excerpt nie został zdefiniowany lub
użytkownik nie chce tworzyć cytatów, jeden zostanie utworzony
automatycznie i będzie pochodził z treści wpisu bloga.

    <?php
    the_excerpt();
    ?> 

the_permalink()

Funkcja wyświetla odnośnik bezpośredni (adres URL) prowadzący do danego
wpisu bloga. Ten link powoduje wyświetlenie strony zawierającej tylko
dany wpis bloga. Odnośnik będzie używany w atrybucie href łączy HTML.

    <?php
    the_permalink();
    ?> 

Sprawdzenie istnienia typu wpisu bloga

Mogą wystąpić sytuacje, w których przed wykonaniem określonego kodu
trzeba będzie sprawdzić istnienie wskazanego typu wpisu bloga.
Przykładowo przed zarejestrowaniem własnego typu wpisu bloga music_album
można sprawdzić, czy taki typ już istnieje. Inny przykład to
umożliwienie integracji z typami wpisów bloga oferowanymi przez inne
wtyczki.

post_type_exists()

Funkcja post_type_exists() sprawdza, czy wskazany typ wpisu bloga został
już zarejestrowany na platformie WordPress. Funkcja akceptuje pojedynczy
parametr $post_type, który powinien być ciągiem tekstowym
reprezentującym nazwę sprawdzanego typu wpisu bloga. Jeżeli dany typ
wpisu bloga już istnieje, wartością zwrotną funkcji będzie true, w
przeciwnym razie false.

    <?php
    post_type_exists( $post_type );
    ?> 

Przypuśćmy, że chcesz wyświetlić wiadomość w zależności od tego, czy typ
music_album został już zarejestrowany. Takie zadanie można wykonać za
pomocą przedstawionego poniżej kodu:

    <?php
    /* Jeżeli typ wpisu bloga music_album został już zarejestrowany. */
    if ( post_type_exists( 'music_album' ) ) {
        echo 'Typ wpisu bloga music_album został już zarejestrowany.';
    }
    /* Jeżeli typ wpisu bloga music_album nie został jeszcze zarejestrowany. */
    else {
        echo 'Typ wpisu bloga music_album nie został jeszcze zarejestrowany.';
    }
    ?> 

Metadane wpisu bloga

Na platformie WordPress wpisy bloga mogą zawierać powiązane z nimi
informacje dodatkowe. Informacje te noszą nazwę metadanych wpisu bloga i
są zapisywane w tabeli $wpdb->postmeta bazy danych.

W terminologii WordPress dla metadanych wpisu bloga bardzo często
używana jest nazwa "własne pola". To pojęcie jest najczęściej używane ze
względu na użytkowników, aby nie przerażać ich pojęciami stosowanymi
przez programistów, np. takimi jak metadane. Domyślnie platforma
WordPress na stronie edycji wpisu bloga dodaje własne pola lub strony,
co pokazano na rysunku 11.4.

[]

Rysunek 11.4. Własne pola na platformie WordPress

W przypadku własnych typów wpisu bloga, aby na stronie edycji wpisu było
możliwe użycie własnych pól, wartość custom-fields musi znaleźć się w
tablicy supports przekazywanej funkcji register_post_type(), zgodnie z
opisem przedstawionym w podrozdziale "Rejestracja typu wpisu bloga".

Prawdziwa potęga metadanych wpisu bloga nie kryje się w umożliwieniu
użytkownikom ręcznego tworzenia oraz dodawania kluczy i wartości w
sekcji własnych pól na stronie edycji wpisu bloga. Za pomocą wtyczek
można tworzyć, uaktualniać i usuwać te wartości, a użytkownik nie będzie
nawet wiedział, że wtyczka manipuluje metadanymi.

Aby to ukryć przed użytkownikiem końcowym, należy utworzyć własne pola
użytkownika na ekranie wpisu bloga. (Więcej informacji na temat
tworzenia pól użytkownika znajduje się w rozdziale 4.). W tym rozdziale
koncentrujemy się na funkcjach używanych do manipulowania metadanymi.

W tym podrozdziale dotyczącym metadanych wpisu bloga zostaną omówione
zadania tworzenia, pobierania, uaktualniania i usuwania z albumów
muzycznych ulubionych piosenek użytkownika (własny typ wpisu bloga
został utworzony już wcześniej).

Dodawanie metadanych wpisu bloga

Na platformie WordPress zaimplementowano prostą funkcję pozwalającą na
dodawanie nowych metadanych do wpisu bloga. Wykorzystamy ją do
uaktualnienia informacji o ulubionej piosence użytkownika. Nowe metadane
po dodaniu zostaną wyświetlone w polu użytkownika, tak jak pokazano na
rysunku 11.4.

add_post_meta()

Dodanie nowych metadanych do określonego wpisu bloga jest możliwe przy
użyciu funkcji add_post_meta(), która akceptuje cztery parametry.

    <?php
    add_post_meta( $post_id, $meta_key, $meta_value, $unique );
    ?> 

Parametry:

-   $post_id — identyfikator wpisu bloga, dla którego będą dodane
    metadane.
-   $meta_key — klucz metadanych (nazwa), do którego będą dodane
    wartości (lub pojedyncza wartość).
-   $meta_value — wartość przeznaczona do dodania do klucza metadanych.
    Do pojedynczego klucza można dodać wiele wartości.
-   $unique — parametr określa, czy dostarczona wartość metadanych ma
    być jedyną. Wartość true parametru oznacza, że będzie pojedyncza
    wartość metadanych. Z kolei false oznacza możliwość dodania wielu
    wartości metadanych. Wartością domyślną parametru jest false.

Po poznaniu sposobu działania parametrów funkcji add_post_meta() można
przystąpić do dodania metadanych dla określonego wpisu bloga.
Przypuśćmy, że mamy wpis bloga (album) o identyfikatorze 100, a ulubiona
piosenka użytkownika w tym albumie to "Gdyby kod mógł mówić". Za pomocą
poniższego kodu można dodać wymienioną wartość metadanych:

    <?php
    add_post_meta( 100, 'favorite_song', 'Gdyby kod mógł mówić', true );
    ?> 

Ustawienie wartości true parametru $unique powoduje, że można dodać
tylko pojedynczą wartość metadanych. Jeżeli do klucza favorite_song ma
być dodanych więcej wartości, parametr $unique musi być ustawiony jako
false. Załóżmy, że użytkownik chce dodać kolejną ulubioną piosenkę, tym
razem o tytule "WordPress mnie uszczęśliwia". Obie piosenki można dodać,
dwukrotnie wywołując funkcję add_post_meta().

    <?php
    add_post_meta( 100, 'favorite_song', 'Gdyby kod mógł mówić', false );
    add_post_meta( 100, 'favorite_song', 'WordPress mnie uszczęśliwia', false );
    ?> 

------------------------------------------------------------------------

Uwaga

W celu ukrycia kluczy metadanych, tak aby nie pojawiały się w ramce
"Własne pola" na stronie edycji wpisu bloga, nazwę klucza trzeba
poprzedzić znakiem podkreślenia, np. _favorite_song. Wtedy użytkownicy
nigdy nie zobaczą tak zapisanych kluczy. To często stosowana praktyka
podczas tworzenia własnych pól meta.

------------------------------------------------------------------------

Pobieranie metadanych

Platforma WordPress ułatwia pobieranie metadanych w celu ich
wyświetlenia bądź wykorzystania w innych funkcjach PHP. Dobrym miejscem
wykorzystania tych funkcji jest pętla, którą przedstawiono w
podrozdziale "Używanie własnych typów wpisów bloga".

    <?php
    get_post_meta( $post_id, $meta_key, $single );
    ?> 

Parametry:

-   $post_id — identyfikator wpisu bloga, dla którego będą pobrane
    metadane.
-   $meta_key — klucz metadanych (nazwa), dla którego będą pobrane
    wartości (lub pojedyncza wartość).
-   $single — parametr określa, czy zwrócona będzie pojedyncza wartość
    metadanych (true), czy tablica (false).Wartością domyślną parametru
    jest false.

Przypuśćmy, że chcesz pobrać pojedynczą wartość dla klucza metadanych
favorite_song. W celu wyświetlenia komunikatu Ulubioną piosenką z tego
albumu jest: Gdyby kod mógł mówić możesz wykorzystać poniższy fragment
kodu:

    <?php
    /* Pobranie jednej ulubionej piosenki z klucza metadanych favorite_song. */
    $favorite_song = get_post_meta( 100, 'favorite_song', true );
    /* Wyświetlenie wartości metadanych. */
    echo 'Ulubioną piosenką z tego albumu jest: ' . $favorite_song;
    ?> 

Istnieje również możliwość wyświetlenia wszystkich wartości metadanych
zapisanych dla klucza favorite_song. Wyobraź sobie, że tworzysz listę
wszystkich ulubionych piosenek. W celu ich wyświetlenia możesz
wykorzystać poniższy kod:

    <?php
    /* Pobranie wszystkich wartości metadanych dla klucza favorite_song. */
    $favorite_songs = get_post_meta( 100, 'favorite_song', false );
    /* Początek nieuporządkowanej listy. */
    echo '<ul class="favorite-songs">';
    /* Iteracja przez wszystkie pobrane wartości metadanych. */
    foreach ( $favorite_songs as $song ) {
        /* Wyświetlenie wartości poszczególnych metadanych. */
        echo '<li>' . $song . '</li>';
    }
    /* Koniec nieuporządkowanej listy . */
    echo '</ul>';
    ?> 

Uaktualnienie metadanych wpisu bloga

Platforma WordPress pozwala również na uaktualnienie metadanych wpisu
bloga. Funkcjonalność tę można wykorzystać, gdy wystąpi konieczność
uaktualnienia istniejących wartości metadanych lub całkowitego
nadpisania wartości metadanych dla wskazanego klucza. Jeżeli klucz lub
wartość metadanych nie istnieją, wówczas nastąpi po prostu dodanie
metadanych.

update_post_meta()

Funkcja update_post_meta() istnieje po to, by umożliwić uaktualnianie
istniejących metadanych dla wskazanego wpisu bloga lub dodawanie nowych
metadanych, jeśli jeszcze nie istnieją. Funkcja akceptuje cztery
parametry.

    <?php
    update_post_meta( $post_id, $meta_key, $meta_value, $prev_value );
    ?> 

Parametry:

-   $post_id — identyfikator wpisu bloga, dla którego będą uaktualniane
    metadane.
-   $meta_key — klucz metadanych (nazwa), do którego będą uaktualniane
    wartości (lub pojedyncza wartość).
-   $meta_value — wartość przeznaczona do dodania do klucza metadanych.
-   $prev_value — poprzednia wartość metadanych przeznaczona do
    nadpisania. Jeżeli ten parametr nie zostanie podany, wszystkie
    wartości metadanych zostaną nadpisane wartością podaną w parametrze
    $meta_value.

Jeżeli chcesz uaktualnić istniejącą wartość metadanych, użyj funkcji
update_post_meta(). Jeśli przykładowo chcesz zmienić ulubioną piosenkę w
kluczu favorite_song z Gdyby kod mógł mówić na WP Blues, to zadanie
możesz wykonać za pomocą poniższego fragmentu kodu:

    <?php
    update_post_meta( 100, 'favorite_song', 'WP Blues', 'Gdyby kod mógł mówić' );
    ?> 

Alternatywnym rozwiązaniem jest nadpisanie wszystkich wartości
metadanych dla klucza favorite_song poprzez pominięcie ostatniego
parametru $prev_value. Poniższy fragment kodu powoduje nadpisanie
wszystkich istniejących wartości nową WP Blues.

    <?php
    update_post_meta( 100, 'favorite_song', 'WP Blues' );
    ?> 

Usuwanie metadanych

Czasami zdarzają się sytuacje wymagające usunięcia wszystkich metadanych
wpisu bloga lub tylko pojedynczej wartości metadanych ze wskazanego
klucza. Platforma WordPress ułatwia także i to zadanie.

delete_post_meta()

Funkcja delete_post_meta() pozwala na usunięcie metadanych dla
wskazanego wpisu bloga i akceptuje trzy parametry.

    <?php
    delete_post_meta( $post_id, $meta_key, $meta_value );
    ?> 

Parametry:

-   $post_id — identyfikator wpisu bloga, dla którego będą usunięte
    metadane.
-   $meta_key — klucz metadanych do usunięcia lub klucz metadanych, do
    którego będzie usunięta wartość.
-   $meta_value — wartość przeznaczona do usunięcia z podanego klucza
    metadanych. Jeżeli ten parametr zostanie pominięty, nastąpi
    usunięcie wszystkich metadanych dla wskazanego klucza.

Jeżeli chcesz usunąć pojedynczą wartość z klucza metadanych
favorite_song, musisz się upewnić o podaniu parametru $meta_value. W
omawianym przykładzie następuje usunięcie wartości Gdyby kod mógł mówić
poprzez jej podanie w parametrze $meta_value.

    <?php
    delete_post_meta( 100, 'favorite_song', 'Gdyby kod mógł mówić' );
    ?> 

Powyższe wywołanie funkcji delete_post_meta() spowodowało usunięcie
pojedynczej wartości metadanych. Jeżeli chcesz usunąć wszystkie wartości
metadanych tego wpisu bloga przypisane kluczowi favorite_song, musisz
pominąć parametr $meta_value:

    <?php
    delete_post_meta( 100, 'favorite_song' );
    ?> 

Tworzenie własnych taksonomii

Taksonomie to sposób grupowania i kategoryzowania na platformie
WordPress obiektów, takich jak wpisy bloga, odnośniki lub użytkownicy. W
tym podrozdziale skoncentrujemy się na tworzeniu taksonomii dla wpisów
bloga.

Platforma WordPress jest standardowo dostarczana z kilkoma taksonomiami.
Oto one.

-   Kategoria — taksonomia hierarchiczna używana do kategoryzowania
    wpisów bloga.
-   Tag wpisu — taksonomia niehierarchiczna używana do nadawania tagów
    wpisom bloga.
-   Odnośnik — taksonomia niehierarchiczna używana do kategoryzowania
    odnośników.
-   Menu nawigacyjne — taksonomia niehierarchiczna przedstawiająca menu
    nawigacyjne i grupująca elementy menu nawigacyjnego.

Najbardziej użyteczną cechą własnych taksonomii jest możliwość tworzenia
ich dla własnych typów wpisów bloga. Utworzenie własnego typu wpisu
bloga niemal zawsze powoduje konieczność dodania dodatkowych metod
organizacyjnych dla poszczególnych wpisów bloga danego typu.

Zrozumienie taksonomii

Aby zrozumieć sposób działania taksonomii, trzeba wiedzieć, że
poszczególne taksonomie to grupy pojęć. Każde pojęcie taksonomii
definiuje sposób, w jaki wpis bloga mieści się w danej taksonomii.

W tym rozdziale przedstawiono utworzenie nowego typu wpisu bloga —
albumu muzycznego. Użytkownicy będą korzystali z tego typu do
uporządkowania kolekcji albumów muzycznych. Każdy wpis bloga będzie
pojedynczym albumem. Użytkownicy mogą potrzebować sposobów na dalsze
uporządkowanie kolekcji muzycznej, np. możliwości pogrupowania podobnych
albumów na podstawie danych taksonomii. Oto niektóre z możliwych
taksonomii dla albumów muzycznych:

-   Artysta (WP Hot Boys, Code Rockstars);
-   Gatunek (rock, blues, R&B);
-   Format (CD, winyl, kaseta);
-   Studio (WP Productions, Code Is Music).

Każda z tych taksonomii pozwoli użytkownikom na dodanie do albumów
muzycznych informacji dodatkowych, które definiują ich treść. Taksonomia
w zasadzie pozwala na czytelniejsze uporządkowanie i zdefiniowanie
treści.

W tym punkcie skoncentrujemy się na utworzeniu taksonomii Artysta i
Gatunek dla wpisu bloga typu album muzyczny, który został wcześniej
zdefiniowany.

------------------------------------------------------------------------

Uwaga

W rozdziale koncentrujemy się jedynie na utworzeniu taksonomii dla typów
wpisów bloga, ponieważ to zadanie jest najczęściej realizowane. Jednakże
na platformie WordPress istnieje również możliwość dodawania taksonomii
do innych typów obiektów, np. odnośników lub użytkowników.

------------------------------------------------------------------------

Rejestracja własnej taksonomii

Rejestracja taksonomii wymaga użycia tylko jednej funkcji dostarczanej
przez platformę WordPress, czyli register_taxonomy(). Funkcja pozwala na
rejestrację nowej taksonomii oraz jej konfigurację przy użyciu własnych
argumentów definiujących jej sposób obsługi na platformie WordPress.

register_taxonomy()

W pliku wtyczki do utworzenia nowej taksonomii używana jest funkcja
register_taxonomy(), która akceptuje trzy parametry.

    <?php
    register_taxonomy( $taxonomy, $object_type, $args );
    ?> 

Parametry:

-   $taxonomy — nazwa taksonomii tworzonej przez wtyczkę. Powinna
    zawierać jedynie znaki alfanumeryczne oraz znak podkreślenia.
-   $object_type — pojedynczy obiekt lub tablica obiektów, które zostaną
    dodane do taksonomii.
-   $args — tablica argumentów definiujących sposób obsługi taksonomii
    przez platformę WordPress.

Parametr $args pozwala na dostosowanie taksonomii do własnych potrzeb.
Przedstawione poniżej opisy wszystkich argumentów pozwalają na ogólne
zrozumienie, jak utworzyć taksonomię, która będzie spełniała stawiane
przed nią wymagania.

public

Argument określa, czy taksonomia będzie publicznie dostępna na stronach
witryny. Wartością domyślną jest true.

show_ui

Ten argument wskazuje, czy w celu zarządzania taksonomią do obszaru
administracyjnego powinien być dodany wygenerowany przez platformę
WordPress interfejs użytkownika. Wartość domyślna jest ustawiana przez
argument public.

hierarchical

Argument pozwala na określenie, że pojęcia taksonomii będą układane w
formatach hierarchicznym lub niehierarchicznym. Po ustawieniu
argumentowi wartości true, pojęcia taksonomii będą mogły mieć pojęcia
nadrzędne. Wartością domyślną argumentu jest false.

query_var

Argument jest nazwą zmiennej zapytania dla pojęć taksonomii. Przykładowo
zmienna ta będzie używana podczas pobierania z bazy wpisów bloga dla
określonego pojęcia danej taksonomii. Wartością tego argumentu może być
dowolny ciąg tekstowy, true lub false. Wartość true powoduje, że
taksonomia użyje nazwy jako argumentu, natomiast false uniemożliwia
wykonywanie zapytań. Domyślnie wartością argumentu jest nazwa
taksonomii.

rewrite

Argument tworzy unikalne bezpośrednie odnośniki dla stron archiwum pojęć
danej taksonomii. Poprawne wartości argumentu to true, false oraz
tablica. Wartość true oznacza utworzenie bezpośrednich odnośników na
podstawie nazwy taksonomii oraz poszczególnych pojęć. Wartość false
oznacza brak tworzenia struktury odnośników bezpośrednich.

Jeżeli użyta jest tablica, wówczas można ustawić kilka wartości.

-   with_front — określenie, czy odnośniki bezpośrednie będą poprzedzone
    prefiksem. Wartością domyślną jest true.
-   slug — unikalny ciąg tekstowy używany przed pojęciem taksonomii w
    odnośniku bezpośrednim. Wartością domyślną tego ciągu tekstowego
    jest nazwa taksonomii.
-   hierarchical — określenie, czy pojęcia posiadające pojęcia nadrzędne
    powinny je wyświetlać w strukturze odnośników bezpośrednich. Aby ten
    argument był użyteczny, taksonomia musi być hierarchiczna. Wartością
    domyślną jest false.

update_count_callback

Argument pozwala na wskazanie własnej funkcji wywoływanej podczas
uaktualniania licznika pojęć, co ogólnie rzecz biorąc, zachodzi podczas
zapisywania wpisu bloga.

show_tagcloud

Argument wskazuje, czy taksonomia będzie mogła być używana w widgecie
WordPress o nazwie "Tagi wpisów". Wartość true oznacza, że pojęcia
taksonomii mogą być wyświetlane przez widget, natomiast wartość false
oznacza brak takiej możliwości. Wartością domyślną jest wartość
argumentu show_ui.

show_in_nav_menus

Ten argument określa, czy pojęcia taksonomii mogą pojawiać się w
utworzonym przez użytkownika menu nawigacyjnym w obszarze
administracyjnym. Wartość domyślna jest ustawiana przez argument public.

labels

Podczas tworzenia taksonomii trzeba zadbać, aby użytkownik odnosił
przyjemne wrażenia podczas jej używania. Argument labels pozwala na
zdefiniowanie ciągów tekstowych, które będą stosowane w obszarze
administracyjnym w celu dostarczenia informacji dotyczących taksonomii
oraz jej pojęć. Jeżeli wspomniane ciągi tekstowe nie zostaną
zdefiniowane, platforma WordPress automatycznie utworzy etykiety Tag dla
taksonomii niehierarchicznych oraz Kategorie dla taksonomii
hierarchicznych.

Argument labels to tablica ciągów tekstowych. Poniżej przedstawiono opis
każdego klucza tej tablicy.

-   name — nazwa taksonomii w liczbie mnogiej.
-   singular_name — nazwa taksonomii w liczbie pojedynczej.
-   search_items — tekst wyświetlany podczas wyszukiwania pojęcia w
    ramach taksonomii.
-   popular_items — tekst wyświetlany podczas pokazywania tagów wpisu
    popularnych pojęć taksonomii. Ten tekst nie jest używany w
    taksonomiach hierarchicznych.
-   all_items — tekst wyświetlany dla odnośnika, który powoduje
    wyświetlenie wszystkich pojęć taksonomii.
-   parent_item — tekst używany do wyświetlania pojęcia nadrzędnego. Ten
    tekst nie jest używany w taksonomiach niehierarchicznych.
-   parent_item_colon — tekst wyświetlany podczas pokazywania pojęcia
    nadrzędnego, na jego końcu znajduje się dwukropek. Ten tekst nie
    jest używany w taksonomiach niehierarchicznych.
-   edit_item — tekst wyświetlany podczas edycji pojęcia.
-   update_item — tekst wyświetlany podczas uaktualniania pojęcia.
-   add_new_item — tekst wyświetlany podczas tworzenia nowego pojęcia.
-   new_item_name — tekst wyświetlany podczas tworzenia nazwy nowego
    pojęcia.
-   separate_items_with_commas — zdanie informujące użytkownika o
    możliwości oddzielenia poszczególnych pojęć przecinkami. Ten tekst
    nie jest używany w taksonomiach hierarchicznych.
-   add_or_remove_items — zdanie informujące użytkownika o możliwości
    dodania lub usunięcia pojęć po wyłączeniu obsługi JavaScript w
    przeglądarce internetowej. Ten tekst nie jest używany w taksonomiach
    hierarchicznych.
-   choose_from_the_most_used — zdanie umożliwiające użytkownikowi wybór
    najczęściej używanych pojęć taksonomii. Ten tekst nie jest używany w
    taksonomiach hierarchicznych.

capabilities

Podczas tworzenia własnych taksonomii trzeba pamiętać, że użytkownicy
powinni zachować uprawnienia do zarządzania, edytowania, usuwania i
przypisywania pojęć taksonomii. Argument capabilities jest tablicą
możliwości, za pomocą których można to wszystko kontrolować. Możliwości
zostały szczegółowo omówione w rozdziale 8.

-   manage_terms — daje użytkownikom możliwość zarządzania pojęciami
    taksonomii. Dzięki tej możliwości mogą używać konwertera
    kategoria-do-tagu oraz przeglądać pojęcia taksonomii na stronie
    taksonomii w obszarze administracyjnym. Wartością domyślną jest
    manage_categories.
-   edit_terms — daje użytkownikom możliwość edycji pojęć taksonomii.
    Wartością domyślną jest manage_categories.
-   delete_terms — daje użytkownikom możliwość usuwania pojęć
    taksonomii. Wartością domyślną jest manage_categories.
-   assign_terms — daje użytkownikom możliwość przypisywania pojęć
    taksonomii do wpisu bloga. Wartością domyślną jest edit_posts.

Rejestracja taksonomii gatunku i artysty

Po szczegółowym zapoznaniu się z parametrami i argumentami funkcji
register_taxonomy() warto wykorzystać tę wiedzę i utworzyć nowe
taksonomie.

W poniższym przykładzie powstaną dwie nowe taksonomie — album_artist i
album_genre — przeznaczone dla typu wpisu bloga album muzyczny, który
został zdefiniowany w części pierwszej rozdziału. Taksonomia artysty
jest niehierarchiczna, podczas gdy taksonomia gatunku jest
hierarchiczna.

    <?php
    /* Konfiguracja nowych taksonomii. */
    add_action( 'init', 'boj_music_collection_register_taxonomies' );
    /* Rejestracja taksonomii. */
    function boj_music_collection_register_taxonomies() {
        /* Konfiguracja argumentów taksonomii artysty. */
        $artist_args = array(
            'hierarchical' => false,
            'query_var' => 'album_artist',
            'show_tagcloud' => true,
            'rewrite' => array(
                'slug' => 'music/artists',
                'with_front' => false
            ),
            'labels' => array(
                'name' => 'Artyści',
                'singular_name' => 'Artysta',
                'edit_item' => 'Edytuj artystę',
                'update_item' => 'Uaktualnij artystę',
                'add_new_item' => 'Dodaj nowego artystę',
                'new_item_name' => 'Nowa nazwa artysty',
                'all_items' => 'Wszyscy artyści',
                'search_items' => 'Wyszukaj artystów',
                'popular_items' => 'Popularni artyści',
                'separate_items_with_commas' => 'Rozdziel artystów przecinkami',
                'add_or_remove_items' => 'Dodaj lub usuń artystów',
                'choose_from_most_used' => 'Wybierz z najpopularniejszych artystów',
            ),
        );
        /* Konfiguracja argumentów taksonomii gatunku. */
        $genre_args = array(
            'hierarchical' => true,
            'query_var' => 'album_genre',
            'show_tagcloud' => true,
            'rewrite' => array(
                'slug' => 'music/genres',
                'with_front' => false
            ),
            'labels' => array(
                'name' => 'Gatunki',
                'singular_name' => 'Gatunek',
                'edit_item' => 'Edytuj gatunek',
                'update_item' => 'Uaktualnij gatunek',
                'add_new_item' => 'Dodaj nowy gatunek',
                'new_item_name' => 'Nowa nazwa gatunku',
                'all_items' => 'Wszystkie gatunki',
                'search_items' => 'Wyszukaj gatunki',
                'parent_item' => 'Gatunek nadrzędny',
                'parent_item_colon' => 'Gatunek nadrzędny:',
            ),
        );
        /* Rejestracja taksonomii artysty albumu. */
        register_taxonomy( 'album_artist', array( 'music_album' ), $artist_args );
        /* Rejestracja taksonomii gatunku albumu. */
        register_taxonomy( 'album_genre', array( 'music_album' ), $genre_args );
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku music-collection-taxonomies.php.

------------------------------------------------------------------------

Po dodaniu powyższego kodu w menu Album wyświetlanym w obszarze
administracyjnym zostaną dodane dwa nowe podelementy o nazwach Artyści i
Gatunki. Na stronie pojawiły się także dwa nowe pola meta pozwalające na
przypisanie artysty i gatunku poszczególnym artystom (zobacz rysunek
11.5).

[]

Rysunek 11.5. Nowo dodane taksonomie w działaniu

------------------------------------------------------------------------

Ostrzeżenie

Funkcja odpowiedzialna za rejestrację nowych taksonomii musi być
wywoływana przez zaczep akcji init. W przeciwnym razie taksonomie nie
będą poprawnie zarejestrowane.

------------------------------------------------------------------------

Przypisanie taksonomii do typu wpisu bloga

Czasami będzie trzeba przypisać taksonomię do typu wpisu bloga, gdy
wtyczka nie tworzy taksonomii bądź typu wpisu bloga. Jeżeli wtyczka
tworzy taksonomię, odbywa się to za pomocą funkcji register_taxonomy().
Jeśli natomiast wtyczka musi dodać istniejącą taksonomię, wówczas
wykorzystywana jest omówiona wcześniej funkcja register_post_type().
Jednak podczas przypisywania taksonomii do typu wpisu bloga nie zawsze
można użycia wymienionych funkcji.

register_taxonomy_for_object_type()

Funkcja pozwala na ustawienie taksonomii dla dowolnego typu obiektu,
który zwykle będzie określonym typem wpisu bloga. Funkcja akceptuje dwa
parametry i zwraca wartość true, gdy jej wykonanie zakończy się
powodzeniem, i false w przypadku niepowodzenia.

    <?php
    register_taxonomy_for_object_type( $taxonomy, $object_type );
    ?> 

Parametry:

-   $taxonomy — nazwa taksonomii, którą wtyczka doda do typu wpisu
    bloga.
-   $object_type — nazwa typu obiektu, do którego ma zostać dodana
    taksonomia. W większości przypadków będzie to typ wpisu bloga. Ta
    wartość może być pojedynczym typem obiektu lub tablicą typów
    obiektu.

Jednym z przykładów ustawienia określonej taksonomii dla typu wpisu
bloga jest nadanie wpisowi bloga typu "strona" taksonomii o nazwie "tagi
wpisu", która zwykle jest używana dla wpisu typu "wpis bloga". Za pomocą
poniższego kodu do typu "strona" można dodać wymienioną taksonomię.

    <?php
    /* Dodanie taksonomii post_tag do wpisu bloga typu "strona". */
    register_taxonomy_for_object_type( 'post_tag', 'page' );
    ?> 

Używanie własnych taksonomii

Podobnie jak własne typy wpisu bloga, taksonomie są najczęściej używane
w plikach szablonów platformy WordPress. Jednak zdarzają się sytuacje, w
których wtyczka musi użyć funkcji taksonomii w celu wyświetlenia
informacji.

Pobieranie taksonomii

W pewnych sytuacjach może wystąpić konieczność pobierania obiektu
taksonomii w celu uzyskania informacji o zarejestrowanej taksonomii.
Obiekt taksonomii w PHP to obiekt utworzony dla zarejestrowanych
taksonomii za pomocą argumentów przekazanych funkcji register_taxonomy()
w tablicy $args.

get_taxonomy()

Funkcja get_taxonomy() akceptuje pojedynczy parametr $taxonomy, którym
powinna być nazwa taksonomii. Wartością zwrotną funkcji jest obiekt
taksonomii.

    <?php
    get_taxonomy( $taxonomy );
    ?> 

Załóżmy, że trzeba wyświetlić etykietę singular_name dla zarejestrowanej
wcześniej taksonomii album_genre. W celu pobrania obiektu taksonomii i
wyświetlenia tej etykiety można wykorzystać poniższy fragment kodu:

    <?php
    /* Pobranie obiektu taksonomii gatunku. */
    $genre = get_taxonomy( 'album_genre' );
    /* Wyświetlenie nazwy taksonomii gatunku w liczbie pojedynczej. */
    echo $genre->labels->singular_name;
    ?> 

Używanie taksonomii wraz z wpisami bloga

Podczas stosowania taksonomii wraz z wpisami bloga, ogólnie rzecz
biorąc, następuje pobranie pojęć taksonomii dla danego wpisu bloga wraz
z pewną lub całą treścią danego wpisu bloga. W ten sposób oglądający
wiedzą o przypisaniu taksonomii do danego wpisu bloga i mają możliwość
wyszukania pokrewnych wpisów bloga na podstawie danego pojęcia
taksonomii.

the_terms()

Funkcja the_terms() zwraca sformatowaną listę pojęć danej taksonomii dla
określonego wpisu bloga. Funkcja akceptuje pięć parametrów.

    <?php
    the_terms( $id, $taxonomy, $before, $sep, $after );
    ?> 

Parametry:

-   $id — identyfikator wpisu bloga, dla którego będzie wyświetlona
    lista pojęć taksonomii.
-   $taxonomy — nazwa taksonomii, dla której będzie wyświetlona lista
    pojęć.
-   $before — treść przeznaczona do wyświetlenia przed listą pojęć.
-   $sep — dowolny ciąg tekstowy lub kod HTML przeznaczony do
    rozdzielenia poszczególnych elementów listy. Domyślnie stosowany
    jest przecinek.
-   $after — treść przeznaczona do wyświetlenia po liście pojęć.

Funkcja the_terms() jest opakowaniem dla funkcji get_the_term_list().
Pierwsza z funkcji wyświetla listę pojęć taksonomii, natomiast druga
zwraca je w celu dalszego użycia w kodzie PHP.

Teraz warto ponownie uaktualnić zdefiniowany wcześniej własny skrót
pozwalający na wyświetlenie wpisów bloga nowo zdefiniowanego typu albumu
muzycznego. Tym razem użyta będzie funkcja get_the_term_list(), która
powoduje umieszczenie na liście artysty i gatunku każdego albumu.

W celu wyświetlenia artysty i gatunku albumu do funkcji tworzącej skrót
należy dodać dwa poniższe wiersze kodu:

    $output .= get_the_term_list( get_the_ID(), 'album_artist', 'Artysta: ', ', ', ' ' );
    $output .= get_the_term_list( get_the_ID(), 'album_genre', 'Gatunek: ', ', ', ' ' ); 

Poniżej przedstawiono kod odpowiedzialny za wyświetlanie pojęć
taksonomii album_artist i album_genre:

    <?php
    add_action( 'init', 'boj_music_album_register_shortcodes' );
    function boj_music_album_register_shortcodes() {
        /* Rejestracja skrótu [music_albums]. */
        add_shortcode( 'music_albums', 'boj_music_albums_shortcode' );
    }
    function boj_music_albums_shortcode() {
        /* Pobranie z bazy danych informacji o albumach. */
        $loop = new WP_Query(
            array(
                'post_type' => 'music_album',
                'orderby' => 'title',
                'order' => 'ASC',
                'posts_per_page' => -1,
            )
        );
        /* Sprawdzenie, czy zostały pobrane dane jakiegokolwiek albumu. */
        if ( $loop->have_posts() ) {
            /* Początek nieuporządkowanej listy. */
            $output = '<ul class="music-collection">';
            /* Przeprowadzenie iteracji przez albumy (pętla). */
            while ( $loop->have_posts() ) {
                $loop->the_post();
                /* Wyświetlenie tytułu albumu. */
                $output .= the_title(
                    '<li><a href="' . get_permalink() . '">',
                    '</a></li>',
                    false
                );
                /* Wstawienie pustego wiersza. */
                $output .= '<br />';
                /* Wyświetlenie artysty albumu. */
                $output .= get_the_term_list( get_the_ID(), 'album_artist',
                    'Artysta: ', ', ', ' ' );
                /* Wyświetlenie gatunku albumu. */
                $output .= get_the_term_list( get_the_ID(), 'album_genre',
                    'Gatunek: ', ', ', ' ' );
            }
            /* Koniec nieuporządkowanej listy. */
            $output .= '</ul>';
        }
        /* Jeżeli nie znaleziono żadnych albumów. */
        else {
            $output = '<p>Nie opublikowano żadnych albumów.</p>';
        }
        /* Zwrot listy albumów muzycznych. */
        return $output;
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-post-type-taxonomy-loop.php.

------------------------------------------------------------------------

Po dodaniu powyższego kodu wyświetlona lista elementów będzie podobna do
pokazanej na rysunku 11.6.

[]

Rysunek 11.6. Lista albumów wzbogacona o informacje dodatkowe

Tagi warunkowe taksonomii

Platforma WordPress zawiera kilka tagów warunkowych dla taksonomii. Tagi
warunkowe sprawdzają występowanie określonego warunku i zwracają wartość
true, jeśli warunek jest spełniony, lub wartość false w przeciwnym
razie.

taxonomy_exists()

Funkcja taxonomy_exists() sprawdza, czy taksonomia została
zarejestrowana na platformie WordPress. Akceptuje pojedynczy parametr
$taxonomy, którym powinna być nazwa sprawdzanej taksonomii.

    <?php
    taxonomy_exists( $taxonomy );
    ?> 

Przypuśćmy, że chcesz sprawdzić istnienie utworzonej wcześniej
taksonomii artysty albumu. Za pomocą przedstawionego poniżej kodu możesz
na podstawie wartości zwrotnej funkcji taxonomy_exists() wyświetlić
odpowiedni komunikat:

    <?php
    /* Jeżeli taksonomia artysty albumu istnieje. */
    if ( taxonomy_exists( 'album_artist' ) ) {
        echo 'Taksonomia "artist" została zarejestrowana.';
    }
    /* Jeżeli taksonomia artysty albumu nie istnieje. */
    else {
        echo 'Taksonomia "artist" nie została zarejestrowana.';
    }
    ?> 

is_taxonomy_hierarchical()

Funkcja is_taxonomy_hierarchical() określa, czy dana taksonomia jest
hierarchiczna. Funkcja akceptuje pojedynczy parametr $taxonomy, którym
powinna być nazwa sprawdzanej taksonomii.

    <?php
    is_taxonomy_hierarchical( $taxonomy );
    ?> 

Utworzona wcześniej taksonomia gatunku albumu jest hierarchiczna,
natomiast taksonomia artysty albumu nie jest hierarchiczna. Poniższy kod
tworzy tablicę nazw taksonomii, a następnie przeprowadza iterację przez
każdą z nich i generuje listę odpowiednich komunikatów.

    <?php
    /* Utworzenie tablicy własnych taksonomii. */
    $taxonomies = array(
        'album_artist',
        'album_genre'
    );
    /* Początek nieuporządkowanej listy. */
    echo '<ul>';
    /* Przeprowadzenie iteracji przez tablicę taksonomii. */
    foreach ( $taxonomies as $tax ) {
        /* Jeżeli taksonomia jest hierarchiczna. */
        if ( is_taxonomy_hierarchical( $tax ) ) {
            echo '<li>Taksonomia ' . $tax . ' jest hierarchiczna.</li>';
        }
        /* Jeżeli taksonomia nie jest hierarchiczna. */
        else {
            echo '<li>Taksonomia ' . $tax . ' nie jest hierarchiczna.</li>';
        }
    }
    /* Koniec nieuporządkowanej listy. */
    echo '</ul>';
    ?> 

is_tax()

Funkcja is_tax() określa, czy odwiedzający stronę znajduje się na
stronie archiwum pojęć. Kiedy funkcja zostanie wywołana bez parametrów,
po prostu sprawdza, czy odwiedzający znajduje się w dowolnym archiwum
taksonomii. Jednak można użyć opcjonalnych parametrów w celu
przeprowadzenia dokładniejszego sprawdzenia.

    <?php
    is_tax( $taxonomy, $term );
    ?> 

Parametry:

-   $taxonomy — nazwa taksonomii przeznaczona do sprawdzenia. Wartością
    domyślną jest pusty ciąg tekstowy.
-   $before — nazwa pojęcia z taksonomii przeznaczona do sprawdzenia.
    Wartością domyślną jest pusty ciąg tekstowy.

W przedstawionym poniżej fragmencie kodu następuje wyświetlenie do
trzech różnych komunikatów w zależności od spełnienia bądź nie danego
warunku. Najpierw sprawdzane jest, czy odwiedzający znajduje się na
stronie archiwum pojęć taksonomii. Następne sprawdzenie dotyczy
konkretnej taksonomii, czyli gatunku. Ostatnie sprawdzenie dotyczy
konkretnego gatunku — blues.

    <?php
    /* Jeżeli odwiedzający znajduje się na stronie archiwum pojęć taksonomii. */
    if ( is_tax() ) {
        echo 'Znajdujesz się na stronie archiwum pojęć taksonomii.';
    }
    /* Jeżeli odwiedzający znajduje się na konkretnej stronie archiwum pojęć taksonomii: gatunek . */
    if ( is_tax( 'album_genre' ) ) {
        echo 'Znajdujesz się na stronie archiwum dla pojęcia taksonomii: gatunek.';
    }
    /* Jeżeli odwiedzający znajduje się na stronie konkretnego gatunku. */
    if ( is_tax( 'album_genre', 'blues' ) ) {
        echo 'Znajdujesz się na stronie gatunku blues.';
    }
    ?> 

Wtyczka typu wpisu bloga oraz taksonomii

Po poznaniu sposobów używania własnych typów wpisów bloga oraz
taksonomii zdobytą wiedzę można wykorzystać do utworzenia nowej wtyczki
o nazwie Kolekcja muzyczna. Wtyczka umożliwia użytkownikom tworzenie
nowych albumów muzycznych oraz ich porządkowanie względem gatunku i
artysty. W tym miejscu zostanie przedstawiony kod, który był już
omówiony we wcześniejszych częściach rozdziału.

Pierwszym krokiem jest utworzenie nowego pliku w katalogu wtyczek,
nadanie mu nazwy boj-music-collection.php, a następnie umieszczenie na
jego początku poniższego nagłówka.

    <?php
    /*
    Plugin Name: Kolekcja muzyczna
    Plugin URI: http://przyklad.pl
    Description: Pozwala uporządkować kolekcję muzyczną względem albumu, artysty i gatunku.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */ 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-music-collection.php.

------------------------------------------------------------------------

Kolejnym krokiem jest utworzenie typu wpisu bloga music_album, co
zostało omówione w podpunkcie "Rejestracja własnego typu wpisu bloga".

    /* Konfiguracja typu wpisu bloga. */
    add_action( 'init', 'boj_music_collection_register_post_types' );
    /* Rejestracja typu wpisu bloga. */
    function boj_music_collection_register_post_types() {
        /* Ustawienie argumentów dla typu wpisu bloga 'music_album'. */
        $album_args = array(
            'public' => true,
            'query_var' => 'music_album',
            'rewrite' => array(
                'slug' => 'music/albums',
                'with_front' => false,
            ),
            'supports' => array(
                'title',
                'thumbnail'
            ),
            'labels' => array(
                'name' => 'Albumy',
                'singular_name' => 'Album',
                'add_new' => 'Dodaj nowy album',
                'add_new_item' => 'Dodaj nowy album',
                'edit_item' => 'Edytuj album',
                'new_item' => 'Nowy album',
                'view_item' => 'Wyświetl album',
                'search_items' => 'Szukaj w albumach',
                'not_found' => 'Nie znaleziono albumów',
                'not_found_in_trash' => 'Nie znaleziono albumów w koszu'
            ),
        );
        /* Rejestracja typu wpisu bloga music_album. */
        register_post_type( 'music_album', $album_args );
    }

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-music-collection.php.

------------------------------------------------------------------------

Ostatnim krokiem procesu budowy wtyczki jest utworzenie taksonomii
album_artist i album_genre dla typu wpisu bloga music_album. Temat
rejestracji taksonomii został omówiony w punkcie "Rejestracja własnej
taksonomii".

    /* Konfiguracja nowych taksonomii. */
    add_action( 'init', 'boj_music_collection_register_taxonomies' );
    /* Rejestracja taksonomii. */
    function boj_music_collection_register_taxonomies() {
        /* Konfiguracja argumentów taksonomii artysty. */
        $artist_args = array(
            'hierarchical' => false,
            'query_var' => 'album_artist', 
            'show_tagcloud' => true,
            'rewrite' => array(
                'slug' => 'music/artists',
                'with_front' => false
            ),
            'labels' => array(
                'name' => 'Artyści',
                'singular_name' => 'Artysta',
                'edit_item' => 'Edytuj artystę',
                'update_item' => 'Uaktualnij artystę',
                'add_new_item' => 'Dodaj nowego artystę',
                'new_item_name' => 'Nowa nazwa artysty',
                'all_items' => 'Wszyscy artyści',
                'search_items' => 'Wyszukaj artystów',
                'popular_items' => 'Popularni artyści',
                'separate_items_with_commas' => 'Rozdziel artystów przecinkami',
                'add_or_remove_items' => 'Dodaj lub usuń artystów',
                'choose_from_most_used' => 'Wybierz z najpopularniejszych artystów',
            ),
        );
        /* Konfiguracja argumentów taksonomii gatunku. */
        $genre_args = array(
            'hierarchical' => true,
            'query_var' => 'album_genre', 
            'show_tagcloud' => true,
            'rewrite' => array(
                'slug' => 'music/genres',
                'with_front' => false
            ),
            'labels' => array(
                'name' => 'Gatunki',
                'singular_name' => 'Gatunek',
                'edit_item' => 'Edytuj gatunek',
                'update_item' => 'Uaktualnij gatunek',
                'add_new_item' => 'Dodaj nowy gatunek',
                'new_item_name' => 'Nowa nazwa gatunku',
                'all_items' => 'Wszystkie gatunki',
                'search_items' => 'Wyszukaj gatunki',
                'parent_item' => 'Gatunek nadrzędny',
                'parent_item_colon' => 'Gatunek nadrzędny:',
            ),
        );
        /* Rejestracja taksonomii artysty albumu. */
        register_taxonomy( 'album_artist', array( 'music_album' ), $artist_args );
        /* Rejestracja taksonomii gatunku albumu. */
        register_taxonomy( 'album_genre', array( 'music_album' ), $genre_args );
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-music-collection.php.

------------------------------------------------------------------------

Na tym etapie zbudowałeś już całą wtyczkę za pomocą minimalnej ilości
kodu odpowiedzialnego za utworzenie i uporządkowanie nowego typu treści
na platformie WordPress. Pozostało już poznanie innych technik
omówionych w książce, dzięki którym wtyczka stanie się jeszcze
solidniejsza; przykładowo dodanie widgetów (zobacz rozdział 4.) lub
zdefiniowanie skrótów (zobacz rozdział 10.) dla typów wpisów bloga i
taksonomii.

Podsumowanie

W tym rozdziale przedstawiono jedynie niewielki wycinek możliwości
oferowanych przez własne typy wpisów bloga, metadane wpisu bloga oraz
taksonomie. Warto zapamiętać, że za pomocą platformy WordPress można
utworzyć dosłownie dowolny typ treści i zarządzać nią. Platforma
WordPress nie jest ograniczona jedynie do obsługi wpisów bloga i stron.

Informacje przedstawione w rozdziale odkrywają przed twórcami wtyczek
wiele nowych możliwości. Możesz więc budować wtyczki przeznaczone do
użytku publicznego, które tysiącom użytkowników zaoferują nowe sposoby
zarządzania treścią. Poznane narzędzia możesz wykorzystać w celu
dostosowania witryn internetowych klientów do obsługi unikalnej treści.

Rozdział 12 Technologie JavaScript i Ajax na platformie WordPress

W tym rozdziale:

-   Zrozumienie biblioteki jQuery i technologii Ajax
-   Prawidłowe wczytywanie kodu JavaScript na platformie WordPress
-   Dodawanie skryptów tylko wtedy, gdy są niezbędne
-   Tworzenie interaktywnych interfejsów WordPress za pomocą technologii
    Ajax
-   Zapewnienie bezpieczeństwa podczas wykonywania żądań Ajax

JavaScript to język programowania używany przede wszystkim do tworzenia
skryptów w postaci zwykłego tekstu, które działają po stronie klienta,
czyli w przeglądarce internetowej. W tym rozdziale wystąpienie słowa
"skrypt" odnosi się do skryptu utworzonego w języku JavaScript.

W rozdziale przedstawiono zwięzłe wprowadzenie do jQuery — biblioteki
JavaScript używanej w WordPress oraz technologii Ajax. Następnie
skoncentrowano się na platformie WordPress — omówiono funkcje i
koncepcje, które trzeba poznać, aby ostatecznie tworzyć wtyczki
wykorzystujące język JavaScript i technologię Ajax.

Krótkie wprowadzenie do jQuery

jQuery to popularna biblioteka JavaScript: jest stosowana na ponad 40% z
miliona najpopularniejszych witryn internetowych (źródło:
http://trends.builtwith.com/​javascript) i co najważniejsze z punktu
widzenia tematu tej książki, jest używana także na platformie WordPress.
Bibliotece jQuery można poświęcić niejedną książkę, więc tutaj zostanie
przedstawione jedynie krótkie wprowadzenie.

Zalety wynikające z używania jQuery

Poniżej wymieniono powody, dla których biblioteka jQuery jest uznawana
za doskonałą, oraz powody jej umieszczenia na platformie WordPress.

-   Jest niewielka: zminimalizowana i spakowana wersja biblioteki
    zajmuje tylko 24 kB.
-   Używa krótkiej i zwięzłej składni, co pozwala na szybkie tworzenie
    kodu (biblioteka typu pisz mniej, osiągnij więcej).
-   Jest całkowicie niezależna od używanej przeglądarki internetowej:
    utworzony za jej pomocą kod działa w przeglądarkach IE 6+, Firefox
    2+, Safari 3+, Chrome i Opera 9+.
-   Jest zgodna ze standardem CSS 3: obsługuje selektory dostępne w
    specyfikacji CSS 1 – 3 (pozwala na wybór elementów dokumentu, takich
    jak div p.asides lub tr:nth-child(odd) td).
-   Znacznie ułatwia pracę ze zdarzeniami, modelem DOM, upraszcza
    tworzenie efektów, narzędzi itd.
-   Powoduje, że technologia Ajax może znacznie łatwiej odczytywać
    formaty JSON i XML.
-   Posiada doskonałą dokumentację dostępną na stronie
    http://docs.jquery.com/Main_Page.

Na platformie WordPress istnieje, oczywiście, możliwość użycia innej
biblioteki, np. PrototypeJS, Mootools lub YUI. Jednak ponieważ WordPress
wewnętrznie używa biblioteki jQuery, otrzymujesz w ten sposób sporą
ilość kodu, który można przeanalizować i przestudiować, co pozwala na
zrozumienie wewnętrznego działania pewnych mechanizmów.

Krótki kurs jQuery

Zakres materiału przedstawionego w tym punkcie nie spowoduje, że
nauczysz się w ciągu kilku minut używania tej użytecznej biblioteki
JavaScript. Naszym celem jest omówienie pewnych podstaw, dzięki którym
będziesz mógł w pełni wykorzystać platformę WordPress.

Obiekt jQuery

W dawnych czasach być może tworzyłeś w języku JavaScript poniższy kod:

    document.getElementById('container').getElementsByTagName('a') 

w celu wybrania elementów, które CSS po prostu określa mianem
#container a. Korzystając z biblioteki jQuery, możesz teraz użyć
znacznie prostszego polecenia:

    $('#container a')

Znak $ jest skrótem oznaczającym obiekt biblioteki jQuery.

Składnia i łączenie

Metody biblioteki jQuery mogą być łączone, co spowoduje zwrócenie
obiektu jQuery; o tym przekonasz się, stosując poniższy, praktyczny
fragment kodu.

Pierwszym krokiem jest utworzenie minimalnego szkieletu dokumentu HTML
zawierającego najnowszą wersję skryptu jQuery pobranego z oficjalnej
witryny:

    <html> 
    <head> 
    <script src='http://code.jquery.com/jquery.js'></script> 
    <title>Przykład użycia jQuery</title> 
    </head> 
    <body> 
    <p class="target">kliknij mnie!</p> 
    <p class="target">kliknij mnie!</p> 
    <p class="target">kliknij mnie!</p> 
    </body> 
    </html> 

Następnie, tuż przed zamykającym znacznikiem </body>, umieść
przedstawiony poniżej fragment kodu jQuery. Ten kod spowoduje dodanie
każdemu akapitowi koloru tła oraz obramowania, a po kliknięciu kolor tła
ulegnie zmianie, akapit zmniejszy swoje rozmiary na dwie sekundy, po
czym całkowicie zniknie:

    <script type="text/javascript"> 
    $('p.target')
        .css( { background:'#eef', border: '1px solid red' } )
        .click(function(){
        $(this)
            .css('background','#aaf')
            .animate(
                { width:'300px', borderWidth:'30px', marginLeft:'100px'},
                2000,
                function(){
                    $(this).fadeOut();
                }
            );
        });
    </script> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku jquery-example.html.

------------------------------------------------------------------------

Po przeanalizowaniu powyższego fragmentu kodu można dostrzec główną
strukturę:

    $('p.target').css(   ).click( function(){   } ); 

Powyższy kod powoduje zastosowanie pewnych stylów względem wskazanego
akapitu, a następnie definiuje jego zachowanie po wywołaniu zdarzenia
click w tym elemencie. Łączenie metod pozwala na zwrócenie samego
obiektu, a tym samym zmniejszenie poziomu używania zmiennych
tymczasowych, i umożliwia używanie bardziej zwięzłej składni.

Podobnie wewnątrz funkcji definiującej zachowanie elementu po
wystąpieniu zdarzenia click można dostrzec kilka metod zastosowanych
względem obiektu $(this). Dzięki temu odwołują się do bieżącego obiektu
jQuery utworzonego przez początkowe polecenie $('p.target').

Skutkiem uruchomienia powyższego kodu są trzy animowane akapity, co
pokazano na rysunku 12.1.

[]

Rysunek 12.1. Efekt animacji akapitów uzyskany za pomocą biblioteki
jQuery

Tryb bezkonfliktowy na platformie WordPress

jQuery to nie jedyna biblioteka JavaScript używająca znaku $.
Przykładowo PrototypeJS korzysta ze znaku $ jako skrótu funkcji o
znacznie dłuższej nazwie document.getElementById().

Aby umożliwić współegzystowanie z innymi bibliotekami, jQuery wyposażono
w tzw. tryb bezkonfliktowy aktywowany domyślnie przez platformę
WordPress, który pozwala innym bibliotekom na używanie znaku $. Dlatego
też podczas przenoszenia istniejącego kodu jQuery do środowiska
WordPress trzeba używać jednego z dwóch rozwiązań:

1.  zapisywać jQuery() zamiast $();
2.  stosować opakowanie dla jQuery.

W celu zilustrowania tego procesu przedstawiono początkowy kod jQuery,
który ma zostać przeniesiony do bezkonfliktowego środowiska WordPress:

    $('.cokolwiek').each( function(){
        $(this).addClass( 'polecenia' );
    });
    $.data( document.body, 'foo', 1337 ); 

Po zastosowaniu pierwszego rozwiązania otrzymamy kod w postaci:

    jQuery('.cokolwiek').each( function(){
        jQuery(this).addClass( 'polecenia' );
    });
    jQuery.data( document.body, 'foo', 1337 );

Natomiast zastosowanie rozwiązania drugiego daje kod:

    // Bezkonfliktowe opakowanie kodu jQuery:
    (function($) {
        // Funkcja $() będzie teraz działała.
        $('.cokolwiek').each( function(){
            $(this).addClass( 'polecenia' );
        });
        $.data( document.body, 'foo', 1337 );
    })(jQuery); 

Pod względem programistycznym obydwa rozwiązania są identyczne, ale
zastosowanie bezkonfliktowego opakowania pozwala na znacznie
wygodniejsze i łatwiejsze użycie istniejącego kodu bez konieczności
zastępowania każdego wystąpienia $ znacznie dłuższym jQuery.

Wykonanie kodu w gotowym dokumencie

Bardzo często spotykanym wymaganiem w kodzie JavaScript jest upewnienie
się o wczytaniu elementów strony przed rozpoczęciem wykonywania operacji
względem nich. Poniżej przedstawiono fragment kodu, który mogłeś
wcześniej stosować:

    window.onload = function(){
        /* dowolne operacje */
    } 

Ta antyczna technika ma dwa słabe punkty:

1.  inny skrypt może we własnej funkcji bardzo łatwo nadpisać definicję
    window.onload;
2.  przed wykonaniem zdarzenie onload w JavaScript czeka na wczytanie
    wszystkich elementów strony łącznie z obrazami, banerami
    reklamowymi, zewnętrznymi widgetami itd.

Dzięki bibliotece jQuery można zastosować znacznie lepsze rozwiązanie:

    $(document).ready( function(){
        /* dowolne operacje */
    }); 

Teraz po utworzeniu pełnej hierarchii modelu DOM następuje wywołanie
zdarzenia ready: ma to miejsce przed wczytaniem obrazów i przed
wyświetleniem reklam. W ten sposób użytkownik odnosi wrażenie, że
wczytanie strony nastąpiło szybciej.

Funkcję gotowości dokumentu można połączyć z opakowaniem noConflict()
biblioteki jQuery, np. w poniższy sposób:

    jQuery(document).ready(function($) {
        // Funkcja $() będzie działała jako alias dla jQuery() wewnątrz tej funkcji.
    }); 

Stosując tę technikę, nadal można używać składni $() i mieć pewność, że
nie nastąpi odwołanie do elementu modelu DOM przed jego wygenerowaniem
przez przeglądarkę internetową.

Technologia Ajax

W interfejsie platformy WordPress podczas tworzenia nowego wpisu bloga
można tagi oraz kategorie dodawać i usuwać bez konieczności odświeżenia
całej strony — odbywa się to właśnie przy użyciu technologii Ajax.

Ajax to techniki programowania sieciowego pozwalające stronie na
asynchroniczne pobieranie danych w tle oraz uaktualnianie fragmentów
strony bez konieczności jej całkowitego odświeżania. Słowo pochodzi od
akronimu Asynchronous JavaScript And XML (asynchroniczny JavaScript i
XML), ale pomimo nazwy, używanie XML tak naprawdę nie jest konieczne.
Czasami można spotkać się z zapisem AJAX, ale wersja zapisana jako Ajax
jest znacznie częściej spotykana.

Ajax to nie jest pojedyncza technologia lub język programowania, ale
grupa technologii. Opiera się na skryptach działających po stronie
klienta, np. JavaScript, oraz na skryptach działających po stronie
serwera, np. PHP, odpowiedzialnych za wygenerowanie treści w HTML, CSS,
XML i JSON — czyli naprawdę dowolnej.

Czym jest Ajax?

Teraz utworzymy prosty, choć jasny fragment kodu pokazujący, czym jest
Ajax. Strona będzie asynchronicznie pobierała dane z serwisu Twitter i
wyświetlała ostatnie komunikaty opublikowane przez wskazanego
użytkownika.

Pierwszym krokiem jest przygotowanie podstawowego szkieletu strony HTML.

    <html> 
    <head> 
        <title>Przykład użycia technologii Ajax</title> 
        <script src='http://code.jquery.com/jquery.js'></script> 
    </head> 
    <body> 
        <h1>Przykład użycia technologii Ajax, odczyt odpowiedzi JSON</h1> 
        <p>Wyświetl <a id="load" href="http://twitter.com/ozh">ostatnie komunikaty 
            opublikowane przez użytkownika Ozh</a></p> 
        <div id="tweets"></div></body> 
    </html> 

W powyższym dokumencie HTML warto zwrócić uwagę na dwa szczegóły:

1.  strona zawiera odwołanie do skryptu jQuery;
2.  strona zawiera puste miejsce zarezerwowane <div id="tweets"></div>.

Teraz można wykorzystać technologię Ajax: po kliknięciu odnośnika
prowadzącego do serwisu Twitter, zamiast przejścia do wymienionego
serwisu, strona wyświetli ostatnie komunikaty opublikowane przez
wskazanego użytkownika. Zachowanie strony po kliknięciu łącza zostało
zdefiniowane w poniższym fragmencie kodu:

    <script type="text/javascript"> 
    // Kiedy model DOM będzie już przygotowany, odnośnikowi zostanie przypisane odpowiednie zachowanie.
    $(document).ready(function(){
        $('#load').click(function(){
            load_tweets();
            // Pominięcie zachowania domyślnego (np. przekierowania do adresu URL wskazanego w odnośniku).
            return false;
        });
    });
    </script> 

Pozostało już tylko zdefiniowanie funkcji odpowiedzialnej za pobranie i
wyświetlenie ostatnich komunikatów opublikowanych przez użytkownika:

    <script type="text/javascript"> 
    // Funkcja główna: wczytanie komunikatów w formacie JSON.
    function load_tweets() {
        // Wskaźnik postępu operacji:
        $('#tweets').html('wczytuję komunikaty...');
        // Żądanie Ajax JSON.
        $.getJSON(
            // Utworzenie adresu URL dla żądania JSONP.
            'http://twitter.com/status/user_timeline/ozh.json?count=5&callback=?',
            // Funkcja odpowiedzialna za obsługę odpowiedzi JSON.
            function(data) {
                // Umieszczenie w miejscu zarezerwowanym pustego znacznika listy <ul>.
                $('#tweets').html('<ul></ul>');
                // Odczytanie każdego obiektu w odpowiedzi JSON.
                $(data).each(function(i, tweet) {
                    $('#tweets ul').append('<li>'+tweet.text+'</li>');
                });
            }
        );
    }
    </script> 

Jak to działa?

Po wywołaniu funkcji load_tweets() poprzez kliknięcie odnośnika
następuje wyświetlenie komunikatu informującego o przeprowadzaniu pewnej
operacji (wczytuję komunikaty...). Jednocześnie do serwisu Twitter jest
wykonywane żądanie JSON. Jeżeli zakończy się powodzeniem, otrzymana
odpowiedź będzie obsłużona za pomocą funkcji, która przeprowadza
iterację przez każdy element i umieszcza go w miejscu zarezerwowanym.
Zdarzenia następują na tej samej stronie, bez konieczności jej
odświeżania (zobacz rysunek 12.2).

W ten sposób utworzyłeś stronę wraz ze skryptem działającym po stronie
klienta, która uaktualnia część dokumentu HTML (puste miejsce
zarezerwowane <div>) asynchronicznie pobieranymi danymi. To jest typowy
przykład użycia technologii Ajax.

[]

Rysunek 12.2. Strona używająca technologii Ajax w działaniu

------------------------------------------------------------------------

Uwaga

Trzeba koniecznie zrozumieć ważne ograniczenie technologii Ajax, jakim
jest polityka tego samego źródła. Ze względu na bezpieczeństwo większość
żądań Ajax nie może pobierać danych z różnych domen, subdomen, a nawet
protokołów. Żądania JSONP (użyte w przykładzie) nie podlegają
ograniczeniom polityki tego samego źródła.

------------------------------------------------------------------------

Poniżej przedstawiono cały kod strony zawierający HTML i JavaScript:

    <html>
    <head>
        <title>Przykład użycia technologii Ajax</title>
        <script src='http://code.jquery.com/jquery.js'></script>
    </head>
    <body>
        <h1>Przykład użycia technologii Ajax, odczyt odpowiedzi JSON</h1>
        <p>Wyświetl <a id="load" href="http://twitter.com/ozh">ostatnie komunikaty
            opublikowane przez użytkownika Ozh</a></p>
        <div id="tweets"></div>
        
    <script type="text/javascript">
    // Kiedy model DOM będzie już przygotowany, odnośnikowi zostanie przypisane odpowiednie zachowanie.
    $(document).ready(function(){
        $('#load').click(function(){
            load_tweets();
            // Pominięcie zachowania domyślnego (np. przekierowania do adresu URL wskazanego w odnośniku).
            return false;
        });
    });
    // Funkcja główna: wczytanie komunikatów w formacie JSON.
    function load_tweets() {
        // Wskaźnik postępu operacji:
        $('#tweets').html('wczytuję komunikaty...');
        // Żądanie Ajax JSON.
        $.getJSON(
            'http://twitter.com/status/user_timeline/ozh.json?count=6&callback=?',
            // Funkcja odpowiedzialna za obsługę odpowiedzi JSON.
            function(data) {
                // Umieszczenie w miejscu zarezerwowanym pustego znacznika listy <ul>.
                $('#tweets').html('<ul></ul>');
                // Odczytanie każdego obiektu w odpowiedzi JSON.
                $(data).each(function(i, tweet) {
                    $('#tweets ul').append('<li>'+tweet.text+'</li>');
                });
            }
        );
    }
    </script>
    </body>
    </html>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku ajax-example-twitter.html.

------------------------------------------------------------------------

Najlepsze praktyki dotyczące technologii Ajax

Utworzona prosta strona jest doskonałym przykładem stosowania kilku
dobrych praktyk dotyczących języka JavaScript i technologii Ajax. Oto
one.

-   Dyskretny kod JavaScript — żadnych nieeleganckich poleceń typu
    onclick="dowolnaFunkcja()" dodawanych do elementów HTML. Zachowanie
    elementów jest zdefiniowane przez kod JavaScript, a sama treść
    pozostaje oddzielona od kodu funkcji. Najpierw należy tworzyć treść,
    a dopiero później funkcje.
-   Bezproblemowy dostęp do treści — bezpośrednią konsekwencją tworzenia
    nierzucającego się w oczy kodu JavaScript jest fakt, że przeglądarka
    bez włączonej lub wbudowanej obsługi języka JavaScript, np. czytnik
    ekranu dla osób z wadami wzroku, pozwala na używanie zbudowanej
    przykładowej strony, o ile będzie podany prawidłowy odnośnik do
    serwisu Twitter.
-   Wskaźnik postępu — kiedy użytkownik kliknie odnośnik wyświetlający
    komunikaty opublikowane w serwisie Twitter, otrzymuje natychmiastową
    informację o bieżącym stanie aplikacji (wczytuję komunikaty…).
    Bardzo ważne jest informowanie użytkownika o procesach
    przeprowadzanych w tle.
-   Informowanie użytkownika — zakończone powodzeniem uaktualnienie
    fragmentu strony powinno być oczywiste dla użytkownika. (Innym
    przykładem może być pole logowania wyświetlane na górze strony,
    które będzie dodawało treść wyświetlaną na dole strony). W przypadku
    bardziej skomplikowanych aplikacji bardzo ważne jest zapewnienie
    obsługi błędów i poinformowanie użytkownika o niespodziewanych
    niepowodzeniach.

------------------------------------------------------------------------

Uwaga

Technologia Ajax spopularyzowała użycie małych animowanych obrazów
nazywanych throbbers, które wskazują operacje przeprowadzane w tle.
Witryny, takie jak http://ajaxload.info/, pozwalają na utworzenie
własnych obrazów dostosowanych do projektu witryny.

------------------------------------------------------------------------

Dodawanie kodu JavaScript do WordPress

Powróćmy jednak do naszego ulubionego tematu: WordPress! Teraz dowiesz
się, w jaki sposób używać języka JavaScript na platformie WordPress.
Najpierw poznasz najważniejsze techniki, a później przejdziemy do
kompletnych wtyczek wykorzystujących zdobytą wiedzę.

Podstawową umiejętnością jest umieszczanie kodu JavaScript na stronach
generowanych przez WordPress. W pierwszej chwili może to wydawać się
trywialnym zadaniem, ale nieprawidłowe wykonanie tego zadania szybko
stanie się źródłem konfliktów z innymi wtyczkami lub jądrem platformy.

Prawidłowy sposób dołączania skryptów

Podstawowa funkcja przeznaczona do wstawiania kodu JavaScript na stronie
WordPress nosi nazwę wp_enqueue_script(). Jak sama nazwa wskazuje,
funkcja powoduje dodanie skryptu do kolejki wymaganych skryptów.

Wprowadzenie do funkcji wp_enqueue_script()

Zadaniem funkcji wp_enqueue_script() jest zarejestrowanie skryptu i
nakazanie platformie WordPress, by prawidłowo wstawiła skrypt na
stronie. Funkcja pobiera pięć argumentów, a jej składnia została
przedstawiona poniżej:

    <?php
    // Dodanie skryptu do kolejki wstawianych skryptów.
    wp_enqueue_script( $handle, $src, $dependencies, $ver, $in_footer );
    ?> 

Parametry:

-   $handle — to jedyny wymagany argument funkcji, który przedstawia
    nazwę skryptu w postaci ciągu tekstowego zapisanego małymi literami.
    Nazwa skryptu jest dostarczana przez WordPress bądź jest własną
    nazwą zarejestrowaną przez wtyczkę. W każdym przypadku trzeba
    zadbać, aby pozostała unikalna.
-   $src — jeśli ten argument zostanie podany, oznacza adres URL
    skryptu. Platforma WordPress potrzebuje tego argumentu tylko wtedy,
    gdy jeszcze nie zna skryptu. Jeżeli skrypt jest znany, parametr
    zostanie po prostu zignorowany.
-   $dependencies — opcjonalna tablica obsługująca skrypt; wskazuje
    elementy, które muszą być wczytane przed skryptem. Ten parametr jest
    wymagany tylko wtedy, gdy platforma WordPress nie zna skryptu.
-   $ver — opcjonalny numer wersji w postaci dowolnego ciągu tekstowego,
    np. 1.0 lub 3.0.1-RC1. To gwarantuje, że przeglądarka internetowa
    pobiera odpowiednią wersję skryptu, niezależnie od ustawień
    buforowania.
-   $in_footer — opcjonalna wartość boolowska true, która oznacza, że
    zamiast umieszczenia skryptu w elemencie <head> dokumentu powinien
    on znaleźć się na końcu strony, w okolicach zamykającego znacznika
    </body>.

Używanie systemu kolejkowania skryptów oferowanego przez platformę
WordPress ma cztery zalety.

1.  Niezależnie od liczby wtyczek wymagających tego samego skryptu,
    będzie on dodany na stronie tylko jeden raz.
2.  Istnieje możliwość dokładnego wskazania strony, na której ma znaleźć
    się skrypt. To zostanie omówione w dalszej części rozdziału.
3.  Określenie zależności, co zostanie omówione w dalszej części
    rozdziału, pozwala na wskazanie kolejności dołączania skryptów na
    stronie, niezależnie od kolejności wywołań funkcji
    wp_enqueue_script().
4.  Skrypty są dodawane w zgodzie z wartością stałej FORCE_SSL_ADMIN.
    (Oznacza to, że jeśli użytkownik używa platformy WordPress z
    wykorzystaniem protokołu https, skrypty również będą wczytane za
    pomocą protokołu https).

Funkcja wp_enqueue_script() zazwyczaj jest rejestrowana dla zaczepu
akcji wywoływanego jeszcze przed wysłaniem treści do przeglądarki
internetowej. Przykładem takiego zaczepu jest init lub
template_redirect. Wynikiem wywołania funkcji jest umieszczenie
prawidłowego znacznika <script> w wygenerowanym dokumencie HTML, np.
tak, jak pokazano w poniższym fragmencie kodu:

    <?php
    add_action( 'init', 'boj_js_add_script' );
    function boj_js_add_script() {
        wp_enqueue_script( $handle, $src, $dependencies, $ver, $in_footer );
    }
    ?> 

W zależności od potrzeb będziesz wykorzystywał różne parametry funkcji
wp_enqueue_script(), o czym przekonasz się na konkretnych przykładach
przedstawionych poniżej.

Dodanie podstawowego skryptu

Funkcję wp_enqueue_script() można wykorzystać w celu dodania
podstawowego skryptu do kodu PHP, np. biblioteki Prototype JavaScript:

    <?php
    // Przykład 1.: dodanie biblioteki prototype.js dołączonej do platformy WordPress.
    function boj_js_add_script1() {
        wp_enqueue_script( 'prototype' );
    }
    ?> 

W powyższym przykładzie nie podano adresu skryptu: platforma WordPress
jest dostarczana wraz z biblioteką PrototypeJS, więc wie, gdzie znaleźć
ten skrypt.

Powyższy kod jest odpowiednikiem poniższego, który można umieścić w
elemencie <head> dokumentu:

    <script type="text/javascript"
        src="http://przyklad.pl/wp-includes/js/prototype.js?ver=1.6.1"></script>

Warto zwrócić uwagę na ciąg tekstowy zapytania dołączony do adresu URL
skryptu: w przypadku znanych skryptów platforma WordPress dołącza
informacje o wersji.

Dodanie własnego skryptu

Aby za pomocą funkcji wp_enqueue_script() dodać do kodu własny skrypt,
trzeba wskazać jego położenie.

    <?php
    // Przykład 2.: dodanie własnego skryptu.
    function boj_js_add_script2() {
        wp_enqueue_script( 'boj1', 'http://przyklad.pl/skrypt1.js' );
    }
    ?> 

W powyższym fragmencie kodu trzeba było podać pełną ścieżkę dostępu do
skryptu, ponieważ nie jest to skrypt dostarczany wraz z platformą.

Powyższemu kodowi odpowiada poniższy, który można umieścić w elemencie
<head> dokumentu:

    <script type="text/javascript"
        src="http://przyklad.pl/skrypt1.js?ver=3.1"></script> 

Warto ponownie zwrócić uwagę na adres URL skryptu. Ponieważ w wywołaniu
funkcji wp_enqueue_script() pominięto numer wersji, platforma WordPress
dołącza do adresu własny numer wersji.

Dodanie własnego skryptu wraz z zależnościami

Poniższy fragment kodu pokazuje, jak dodać własny skrypt, który jest
zależny od innych skryptów.

    <?php
    // Przykład 3.: dodanie własnego skryptu, który polega na komponentach jQuery.
    function boj_js_add_script3() {
        wp_enqueue_script(
            'boj2',
            'http://przyklad.pl/skrypt2.js',
            array( 'jquery-ui-tabs', 'jquery-ui-draggable' )
        );
    }
    ?> 

W powyższym przykładzie pokazano, jak wskazać skrypty, od których zależy
dodawany skrypt. W ten sposób platforma otrzymuje informacje, które
skrypty powinny być wczytane wcześniej. Wymienione skrypty są
dostarczane wraz z WordPress, więc platforma ma wystarczającą ilość
informacji na ich temat. Poniższe wywołanie funkcji powoduje
wygenerowanie w dokumencie HTML listy znaczników <script>:

    <script type='text/javascript'
     src='http://przyklad.pl/wp-includes/js/jquery/jquery.js?ver=1.4.2'></script> 
    <script type='text/javascript'
     src='http://przyklad.pl/wp-includes/js/jquery/ui.core.js?ver=1.7.3'></script> 
    <script type='text/javascript'
     src='http://przyklad.pl/wp-includes/js/jquery/ui.tabs.js?ver=1.7.3'></script> 
    <script type='text/javascript'
     src='http://przyklad.pl/wp-includes/js/jquery/ui.draggable.js?ver=1.7.3'></script> 
    <script type='text/javascript'
     src='http://przyklad.pl/skrypt2.js?ver=3.1'></script> 

Dodanie własnego skryptu wraz z numerem wersji

Dołączenie numeru wersji do skryptu często jest praktyczne i bardzo
łatwe do zrobienia.

    <?php
    // Przykład 4.: dodanie własnego skryptu wraz z numerem wersji.
    function boj_js_add_script4() {
        wp_enqueue_script( 'boj3', 'http://przyklad.pl/skrypt3.js', '', '1.3.3.7' );
    }
    ?> 

Powyższy kod powoduje wstawienie w elemencie <head> dokumentu poniższego
znacznika <script>:

    <script type='text/javascript'
        src='http://przyklad.pl/skrypt3.js?ver=1.3.3.7'> </script> 

Jeżeli zapewniasz obsługę skryptu i uaktualniasz jego kod JavaScript,
stosowanie numeru wersji jest dobrym pomysłem i pozwala na uniknięcie
problemów związanych z buforowaniem w przeglądarce internetowej. Zwykle
wystarczy zdefiniować stałą przechowującą aktualną wersję wtyczki, a
następnie korzystać z niej w kodzie wtyczki.

Dodanie skryptów w stopce dokumentu

Funkcja wp_enqueue_script() domyślnie generuje znaczniki <script> w
elemencie <head> dokumentu HTML. Jednak dzięki użyciu piątego argumentu
o wartości true istnieje możliwość umieszczenia znacznika <script> na
końcu dokumentu HTML:

    <?php
    // Przykład 5.: dodanie własnego skryptu w stopce dokumentu.
    function boj_js_add_script5() {
        wp_enqueue_script( 'boj4', 'http://przyklad.pl/skrypt4.js', '', '', true );
    }
    ?> 

Przykład piąty powoduje umieszczenie skryptu w pobliżu zamykającego
znacznika </body>. Potencjalne korzyści wynikające z dodawania skryptów
w stopce strony zostaną przedstawione w dalszej części rozdziału, w
punkcie "Gdzie umieszczać skrypty?".

------------------------------------------------------------------------

Ostrzeżenie

Wstawienie skryptu w stopce dokumentu jest możliwe, jeśli platforma
WordPress "wie", że generuje stopkę. W obszarze administracyjnym takie
rozwiązanie zawsze się sprawdza, natomiast na publicznie dostępnych
stronach bloga konieczne jest stosowanie w stopce motywu funkcji
wp_footer(). Każdy porządny motyw wywołuje wymienioną funkcję, ale warto
pamiętać o tym wymaganiu.

------------------------------------------------------------------------

Jednoczesne użycie wszystkich parametrów

W poniższym przykładzie przedstawiono wywołanie funkcji
wp_enqueue_script(), w którym jednocześnie wykorzystano jej wszystkie
parametry:

    <?php
    // Przykład 6: wszystkie parametry zostały podane.
    function boj_js_add_script6() {
        wp_enqueue_script(
            'boj5',
            'http://przyklad.pl/skrypt5.js',
            array( 'boj1' ),
            '6.6.6',
            true
        );
    }
    ?> 

Powyższe wywołanie funkcji powoduje dołączenie w stopce dokumentu
skryptu o numerze wersji 6.6.6. Warto zwrócić na sposób zdefiniowania
zależności od skryptu boj1. Można użyć takiego sposobu, ponieważ od
przykładu 2. platforma WordPress zna już ten skrypt. Wskazanie w
zależnościach nieznanego platformie skryptu spowoduje, że na stronie nie
zostanie dołączony żaden skrypt.

Domyślne skrypty dostarczane przez platformę

Jak dowiedziałeś się podczas lektury rozdziału bądź może wiedziałeś
wcześniej, platforma WordPress jest dostarczana z wieloma skryptami
JavaScript, które można znaleźć w katalogach:

-   /wp-includes/js — ten katalog i jego podkatalogi zawierają skrypty
    używane zarówno w części publicznej witryny, jak i w obszarze
    administracyjnym;
-   /wp-admin/js — ten katalog i jego podkatalogi zawierają skrypty
    używane przez WordPress w obszarze administracyjnym.

Wszystkie skrypty są dostarczane w dwóch wersjach: jako zminimalizowany
plik .js oraz w pełni czytelny (z komentarzami i wcięciami) plik
.dev.js. Domyślnie wersja zminimalizowana jest dostarczana w celu
oszczędności przepustowości łącza, ale istnieje możliwość wyboru wersji
skryptu poprzez umieszczenie w pliku wp-config.php poniższego wiersza:

    <?php
    define( 'SCRIPT_DEBUG', true );
    ?> 

Obsługa wszystkich standardowych skryptów platformy jest zdefiniowana w
funkcji wp_default_scripts(), którą można znaleźć w pliku
wp-includes/script-loader.php. Do funkcji należy się odwoływać, gdy
trzeba dodać skrypt standardowy. Skryptami standardowymi najczęściej
używanymi we wtyczkach są:

-   jquery — biblioteka jQuery;
-   komponenty biblioteki jQuery, np. jquery-ui-core, jquery-ui-tabs,
    jquery-ui-sortable lubjquery-ui-draggable;
-   thickbox — pływający element iframe (np. pojawiający się, gdy trzeba
    przesłać do serwera obraz, który będzie użyty we wpisie bloga).

Usunięcie zakolejkowanego skryptu

Jeżeli nie chcesz wczytania danego skryptu, wówczas za pomocą funkcji
wp_dequeue_script() możesz go usunąć z kolejki skryptów:

    <?php
    add_action( 'init', 'boj_js_remove_queued' );
    function boj_js_remove_queued() {
        // Nie dołączaj biblioteki PrototypeJS.
        wp_dequeue_script( 'prototype' );
        // Nie dołączaj skryptu dodanego przez inną wtyczkę.
        wp_dequeue_script( 'inny_skrypt' );
    }
    ?> 

Istnieje możliwość użycia funkcji wp_script_is( $handle ) w celu
sprawdzenia, czy skrypt został zarejestrowany i umieszczony w kolejce.
Tego rodzaju sprawdzenie może być użyteczne w przedstawionej poniżej i —
niestety — nie tylko hipotetycznej sytuacji.

Wyobraź sobie, że opracowałeś nową wtyczkę z elegancką stroną ustawień
wykorzystującą język JavaScript i technologię Ajax. Wkrótce zaczynasz
otrzymywać od użytkowników informacje o nieprawidłowym działaniu kodu
JavaScript po aktywacji pewnej określonej wtyczki.

Niestety, często zdarza się, że autorzy wtyczek nieprawidłowo dodają
swoje skrypty na wszystkich stronach administracyjnych, choć naprawdę są
one niezbędne tylko na stronie ustawień wtyczki. (W dalszej części
rozdziału, w punkcie "Dodawanie skryptów jedynie wtedy, gdy są
potrzebne", dowiesz się, w jaki sposób dodawać skrypty jedynie na
wybranych stronach). Dodawanie skryptów na wszystkich stronach może
doprowadzić do nieumyślnego uszkodzenia stron ustawień innych wtyczek.

Na tym etapie masz dwie możliwości przywrócenia prawidłowego działania
wtyczki.

-   Skontaktowanie się z autorem wtyczki powodującej problemy i
    poproszenie go o poprawienie kodu, aby skrypt był dołączany
    prawidłowo jedynie na stronach wymagających danego skryptu. Jeśli
    masz szczęście, autor poprawi wtyczkę.
-   Drugie rozwiązanie to umieszczenie we własnej wtyczce kodu
    powodującego usunięcie nieprawidłowo dołączanego skryptu z kolejki
    skryptów.

Zastąpienie skryptu standardowego własnym

Platforma WordPress jest dostarczana wraz z własnymi skryptami, ale —
oczywiście — możesz je zastąpić swoimi. Przykładowo zamiast używania
wbudowanej biblioteki jQuery możesz budowanym witrynom internetowym
nakazać pobranie biblioteki z sieci Google CDN (ang. Content Delivery
Network). W ten sposób przeglądarka internetowa użytkownika będzie
pobierała bibliotekę z wysoko wydajnego serwera, który dzięki centrom
danych Google pod względem geograficznym znajduje się bliżej
użytkownika. Istnieje również prawdopodobieństwo, że użytkownik ma już
wskazany plik w buforze, więc będzie możliwość zaoszczędzenia
przepustowości łącza własnego serwera.

Aby powyższe rozwiązanie zastosować w praktyce, w kodzie wtyczki należy
umieścić poniższy fragment kodu:

    <?php
    // Zastąpienie wbudowanej biblioteki jQuery wersją pobraną z serwerów Google.
    add_action( 'init', 'boj_jquery_from_cdn' );
    if( !function_exists( 'boj_jquery_from_cdn' ) ) {
        function boj_jquery_from_cdn() {
            wp_deregister_script( 'jquery' );
            wp_register_script(
                'jquery',
                'http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js'
            );
        }
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_jquery_cdn.php.

------------------------------------------------------------------------

Powyższy fragment kodu wykonuje następujące zadania.

-   Na wczesnym etapie inicjalizacji platformy WordPress (podczas
    wykonywania zaczepu akcji init) następuje wywołanie funkcji
    boj_jquery_from_cdn().
-   Wymieniona funkcja (zdefiniowana tylko wtedy, gdy nie istnieje,
    ponieważ ten fragment kodu można umieścić w wielu wtyczkach)
    wyrejestrowuje bibliotekę jQuery znaną platformie WordPress, a
    następnie rejestruje ją ponownie, ale tym razem wykorzystuje skrypt
    z innej lokalizacji.

Funkcja wp_register_script() nie powoduje zakolejkowania skryptu w celu
jego umieszczenia na stronie, a jedynie "przedstawia" skrypt platformie
WordPress, która będzie mogła go wykorzystać później, jeżeli będzie
trzeba.

Rejestrowanie skryptów i umieszczanie ich w kolejce

Jeżeli we wtyczce ten sam skrypt trzeba umieścić w kolejce kilkakrotnie,
można użyć funkcji skrótu wp_register_script() przedstawionej już w
poprzednim podpunkcie.

Najpierw należy zdefiniować skrypt przy użyciu tych samych parametrów,
jakie są stosowane w funkcji wp_enqueue_script():

    <?php
    wp_register_script( $handle, $src, $deps, $ver, $in_footer );
    ?> 

Następnie skrypt można w dowolnej chwili umieścić w kolejce:

    <?php
    wp_enqueue_script( $handle );
    ?> 

Zarządzanie stylami na platformie WordPress

Ten temat wykracza poza zakres tematyczny tego rozdziału, ale ze względu
na podobieństwo nie można było go pominąć. Istnieje możliwość dodawania,
rejestrowania i umieszczania w kolejce arkuszy stylów (pliki CSS)
dokładnie tak samo jak skryptów. Używane są tutaj podobne funkcje, które
akceptują te same parametry:

-   style standardowe są zdefiniowane w funkcji wp_default_styles()
    znajdującej się w pliku wp-includes/script-loader.php;
-   style są dodawane za pomocą funkcji wp_enqueue_style().

Gdzie umieszczać skrypty?

Wiesz już, że używając funkcji wp_enqueue_script(), możesz wstawić
skrypt w nagłówku bądź na końcu dokumentu. Powstaje pytanie, czy miejsce
umieszczenia skryptu ma znaczenie?

Dowiedziałeś się również, jak ważne jest, aby skrypty były wstawiane
tylko wtedy, gdy są potrzebne, np. na stronie ustawień wtyczki. W jaki
sposób można to zrobić?

W nagłówku? W stopce? Osadzać w kodzie?

Funkcja wp_enqueue_script() może umieszczać skrypty w nagłówku dokumentu
(element <head>) lub w pobliżu zamykającego znacznika </body>. Jednak
skrypt można także wstawić ręcznie przy użyciu polecenia typu
<script src="http://przyklad.pl/skrypt.js"></script>. Ponadto skrypt
można osadzić w dowolnym miejscu kodu. Każda sytuacja ma swoje
preferowane metody.

W nagłówku

Skrypty JavaScript zwykle są dodawane w nagłówku dokumentu (element
<head>), to jest również domyślne miejsce umieszczenia skryptu przez
funkcję wp_enqueue_script():

    <head> 
    <script type="text/javascript" src="/js/biblioteka.js"></script> 
    </head> 

W przypadku tego rozwiązania elementy strony mogą być niedostępne, zanim
nie nastąpi wczytanie skryptu. W tym miejscu można dołączać biblioteki i
definicje funkcji używanych później na stronie.

W pobliżu stopki dokumentu

Zupełnie przeciwnym rozwiązaniem jest umieszczenie znacznika <script> w
pobliżu końca dokumentu HTML, czyli najczęściej w stopce strony:

    <script type="text/javascript" src="/js/skrypt.js"></script> 
    </body> 
    </html> 

Ta technika jest gorąco polecana przez Yahoo! w ich dokumencie[1] Best
Practices for Speeding Up Your Web Site
(http://developer.yahoo.com/​performance/rules.html). Ta technika będzie
bardzo efektywna, jeżeli trzeba umieścić na stronie skrypt firmy
trzeciej (np. widget pobierany z innego serwera), który potencjalnie
może spowolnić lub nawet wstrzymać generowanie strony. Dołączenie
skryptu na końcu strony powoduje, że silnik przeglądarki ma szansę
wygenerować przynajmniej część treści strony, zanim widget wstrzyma jej
dalsze wyświetlanie. W ten sposób użytkownik ma wrażenie, że strona jest
generowana płynniej.

W treści strony

Innym sposobem dodania kodu JavaScript na stronie jest umieszczenie
znacznika <script> w dowolnym miejscu strony:

    </p> 
    </div> 
    <div > 
    <script type="text/javascript" src="/js/skrypt.js"></script> 

Zdarzają się sytuacje, gdy nie chcesz, aby skrypt był zawsze wczytywany
w nagłówku bądź stopce strony. Powróćmy na chwilę do rozdziału 10.
poświęconego skrótom. W wymienionym rozdziale omówiono utworzenie
wtyczki, która dodaje skrypt usługi Google Mapy tylko wtedy, gdy strona
zawiera odpowiedni skrót. W takim przypadku skrypt jest wczytywany
wyłącznie wtedy, gdy strona wymaga jego użycia, zamiast każdorazowego
wczytywania go za pomocą funkcji wp_enqueue_script().

Osadzony w kodzie

Ostatnim sposobem dodania kodu JavaScript jest jego osadzenie w
dokumencie zamiast podawania atrybutu src znacznika <script>:

        </p> 
    </div> 
    <div > 
    <script type="text/javascript"> 
        var cokolwiek = 123;
        zrob_cokolwiek();
    </script> 

Niewielkie ilości kodu JavaScript można osadzać w kodzie zwłaszcza
wtedy, kiedy nie powoduje to zaśmiecenia strony zbyt dużą ilością
osadzonej treści i jednocześnie nie ma potrzeby tworzenia zewnętrznego
skryptu JavaScript.

Jeżeli zwracasz uwagę na poprawność kodu HTML lub XHTML, to pamiętaj o
stosowaniu odpowiedniej składni.

Poprawna składnia dla XHTML:

    <script type="text/javascript"> 
    /*  < ![CDATA[ */
    // To jest miejsce na umieszczenie kodu JavaScript.
    /* ]] >  */
    </script> 

Poprawna składnia dla HTML5:

    <script > 
    // To jest miejsce na umieszczenie kodu JavaScript.
    </script> 

Wybór najlepszego rozwiązania

Preferowaną biblioteką JavaScript na platformie WordPress jest jQuery.
Oferuje ona wygodną metodę określającą, że skrypt powinien być
uruchomiony tylko wtedy, gdy model DOM (tzn. elementy strony) jest już
gotowy. W przypadku stosowania wspomnianej biblioteki jQuery miejsce
umieszczenia skryptu nie ma już tak dużego znaczenia — skrypt można
dołączyć w dowolnym miejscu strony.

W skryptach utworzonych przez innych, które nie polegają na technice
gotowości modelu DOM, nadal trzeba wybrać najlepsze miejsce ich
dołączenia na stronie.

Dodawanie skryptów jedynie wtedy, gdy są potrzebne

Ważniejsze od miejsca dołączenia skryptu na stronie jest jego wczytanie
tylko wtedy, gdy będzie potrzebny. W ten sposób można zmniejszyć
obciążenie witryny, skrócić czas generowania strony, zaoszczędzić
przepustowość łącza, a także zmniejszyć ryzyko powstania konfliktów
między różnymi dołączanymi skryptami.

Poniżej zostaną przedstawione techniki tworzenia wtyczki, w której dany
skrypt będzie wczytywany tylko wtedy, gdy stanie się potrzebny. Ponieważ
celem ćwiczenia jest zaprezentowanie techniki dołączania skryptów
JavaScript na określonych stronach, same skrypty są bardzo proste i
składają się z wywołań funkcji alert() w celu poinformowania o wczytaniu
skryptu.

Pobieranie położenia skryptów wtyczki

Wtyczka powinna określić swój adres URL na platformie WordPress, zanim
będzie mogła umieszczać na stronach kod JavaScript dostarczany wraz z
platformą. W rozdziale 2. przedstawiono poprawną strukturę katalogów
wtyczki wraz z podkatalogami dla każdego typu pliku (zobacz rysunek
12.3).

[]

Rysunek 12.3. Poprawna struktura katalogów wtyczki

Jeżeli będziesz stosował przedstawioną strukturę, poniższy fragment kodu
znajdzie się w pliku o nazwie script.js umieszczonym w podkatalogu /js
wtyczki:

    <?php
    // Określenie adresu URL katalogu bieżącej wtyczki.
    $plugin_url = plugin_dir_url( __FILE__);
    // Umieszczenie skryptu w kolejce.
    wp_enqueue_script( 'boj_script', $plugin_url.'js/script.js' );
    ?> 

To jest fragment kodu doskonały do wielokrotnego użycia: nic dotyczącego
instalacji użytkownika nie jest na stałe zdefiniowane (np. położenie
katalogu wp-content). Wartością zwrotną funkcji plugin_dir_url() jest
adres URL będący ścieżką dostępu (wraz z ukośnikiem na końcu) do pliku
wtyczki przekazanego jako parametr funkcji. (Przykładowo wartość zwrotna
może być w postaci http://przyklad.pl/wp-content/​plugins/bj_insertjs/).

------------------------------------------------------------------------

Uwaga

Nigdy nie należy umieszczać w kodzie na stałe zdefiniowanego adresu URL
wtyczki. Nie można mieć stuprocentowej pewności dotyczącej miejsca
umieszczenia katalogu wp-content, ponieważ może się on znajdować poza
katalogiem głównym platformy WordPress. Zamiast tego zawsze warto
wykorzystać przedstawiony powyżej bezpieczny fragment kodu, który działa
nawet wtedy, gdy użytkownik zmieni nazwę katalogu wtyczek.

------------------------------------------------------------------------

W poniższej wtyczce można użyć prefiksu boj_insertjs, a sama wtyczka
wskazuje na początku miejsce położenia skryptu:

    <?php
    /*
    Plugin Name: Dodaj JavaScript
    Plugin URI: http://przyklad.pl/
    Description: Pokazuje, jak prawidłowo wstawić kod JS na różnych stronach,
    Author: Ozh
    Author URI: http://wrox.com
    */
    // Adres URL wskazujący podkatalog /js wtyczki.
    define( 'BOJ_INSERTJS', plugin_dir_url( __FILE__).'js' );

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_insertjs/plugin.php.

------------------------------------------------------------------------

Dodawanie skryptu na stronach administracyjnych

Ogólna zasada mówi, że funkcja wp_enqueue_script() musi być wywołana na
wczesnym etapie inicjalizacji, jeszcze przed wygenerowaniem na stronie
jakiejkolwiek treści. Wykorzystana technika i zaczep zależą od
konkretnych oczekiwań dotyczących skryptu.

Wtyczka ma możliwość dodania różnych skryptów na różnych stronach:

-   jeden skrypt na wszystkich stronach administracyjnych;
-   jeden skrypt tylko na stronie ustawień wtyczki;
-   jeden skrypt tylko w menu Użytkownicy na stronie wygenerowanej przez
    inną wtyczkę;
-   jeden skrypt tylko na stronie edycji komentarzy.

Ponieważ dodawany w tym miejscu skrypt dotyczy jedynie obszaru
administracyjnego, można wykorzystać zaczep wywoływany tylko w tym
kontekście. Skoro do menu administracyjnego będzie dodanych kilka stron,
odpowiednim kandydatem jest zaczep admin_menu:

    // Dodanie nowych stron administracyjnych.
    add_action('admin_menu', 'boj_insertjs_add_page');
    // Dodanie nowych stron administracyjnych.
    function boj_insertjs_add_page() { 

Wewnątrz zdefiniowanej funkcji nastąpi kolejno dodanie czterech
skryptów, co szczegółowo pokazano w poniższych fragmentach kodu:

    // 1. Dodanie skryptu JavaScript na wszystkich stronach administracyjnych.
    wp_enqueue_script( 'boj_insertjs_1', BOJ_INSERTJS.'/admin.js' );

W kolejce umieszczony zostaje skrypt, który będzie wczytany na
wszystkich stronach w obszarze administracyjnym zarówno wbudowanych, np.
kokpit, jak i utworzonych przez wtyczki.

    // 2. Dodanie strony w menu Ustawienia.
    $settings = add_options_page( 'Dodaj JS', 'Dodaj JS', 'manage_options',
        'boj_insertjs_settings', 'boj_insertjs_options_page'
    ); 

Za pomocą funkcji add_options_page() dodano element menu. Gdy używamy
wartości zwrotnej tego wywołania funkcji, można wykorzystać zaczep
load-$pagename, w którym nazwa strony jest istotnym elementem.

    // Dodanie skryptu JavaScript jedynie na stronie ustawień wtyczki.
    add_action( 'load-'.$settings, 'boj_insertjs_add_settings_script' ); 

Powyższy zaczep akcji jest wywoływany jedynie podczas wyświetlania
strony ustawień wtyczki. Teraz można utworzyć inną stronę wtyczki i
zastosować inny zaczep, który będzie wywoływany jedynie na danej
stronie:

    // 3. Dodanie strony w menu Użytkownicy.
    $users = add_users_page( 'Dodaj JS', 'Dodaj JS', 'manage_options',
        'boj_insertjs_users', 'boj_insertjs_users_page'
    );
    // 4. Dodanie skryptu JavaScript na stronie menu Użytkownicy przy użyciu innego zaczepu.
    add_action( 'admin_print_scripts-'.$users, 'boj_insertjs_add_users_script' );
    } // Koniec funkcji boj_insertjs_add_page().

Dwie strony obszaru administracyjnego wymagają zdefiniowania dwóch
określonych zaczepów akcji. Będą to zwykłe wywołania funkcji
wp_enqueue_script():

    // Dodanie skryptu JavaScript na stronie ustawień wtyczki.
    function boj_insertjs_add_settings_script() {
        wp_enqueue_script( 'boj_insertjs_2', BOJ_INSERTJS.'/settings.js' );
    }
    // Dodanie skryptu JavaScript na stronie menu Użytkownicy, tym razem dla odmiany w stopce strony.
    function boj_insertjs_add_users_script() {
        wp_enqueue_script( 'boj_insertjs_3', BOJ_INSERTJS.'/users.js',
            '', '', true
        );
    } 

Teraz można wczytać inny skrypt na określonej stronie platformy
WordPress, np. na stronie komentarzy. Ponownie zaczep load-$pagename
okazuje się całkiem użyteczny:

    // Dodanie skryptu JavaScript na stronie komentarzy.
    add_action( 'load-edit-comments.php', 'boj_insertjs_on_comments' );
    function boj_insertjs_on_comments() {
        wp_enqueue_script( 'boj_insertjs_4', BOJ_INSERTJS.'/comments.js' );
    } 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_insertjs/plugin.php.

------------------------------------------------------------------------

Stosując funkcje wp_enqueue_script() zarejestrowane dla określonych
zaczepów administracyjnych, zagwarantowałeś, że skrypty będą wczytane
tylko wtedy, gdy będą potrzebne, czyli w obszarze administracyjnym.

------------------------------------------------------------------------

Uwaga

To mogło nie zostać wystarczająco mocno podkreślone, więc powtórzmy raz
jeszcze: zawsze starannie wybieraj miejsce dodawania kodu JavaScript i
określaj strony, które będą wymagały użycia skryptów. W większości
przypadków własny skrypt będzie musiał być dodawany jedynie na stronie
ustawień wtyczki. Wówczas możesz wykorzystać przedstawioną powyżej
technikę.

------------------------------------------------------------------------

Dodawanie skryptu na stronach publicznych

Podczas dodawania skryptów na stronach publicznych reguła jest podobna:
staraj się wykorzystać zaczep, który będzie wywoływany jedynie podczas
wyświetlania danej części bloga. Przykładem może być zaczep
template_redirect wywoływany przez platformę WordPress podczas
wczytywania motywu.

    // Dodanie skryptu JavaScript na stronach bloga.
    add_action( 'template_redirect', 'boj_insertjs_add_scripts_blog' );
    function boj_insertjs_add_scripts_blog() {
        // Na wszystkich stronach bloga.
        wp_enqueue_script( 'boj_insertjs_5', BOJ_INSERTJS.'/blog.js' );
        // Tylko na stronach wyświetlających pojedynczy wpis bloga.
        if( is_single() ) {
            wp_enqueue_script( 'boj_insertjs_6', BOJ_INSERTJS.'/single.js' );
        }
        // Tylko na stronie "O mnie".
        if( is_page('About') ) {
            wp_enqueue_script( 'boj_insertjs_7', BOJ_INSERTJS.'/about.js' );
        }
    } 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_insertjs/plugin.php.

------------------------------------------------------------------------

W powyższym fragmencie kodu zarejestrowano funkcje w zaczepie akcji
wywoływanym jedynie w części publicznej bloga, a następnie użyto tagów
warunkowych, takich jak is_single(), w celu przejścia na określone
strony. Więcej informacji na temat tagów warunkowych można znaleźć na
stronie http://codex.wordpress.org/Conditional_Tags.

Oczywiście, wyboru strony, na której ma zostać dodany kod JavaScript,
można dokonać za pomocą innych warunków, nie jedynie typu strony.
Poniżej przedstawiono przykłady dodania skryptu, jeśli użytkownik nie
jest zalogowany, oraz dodania innego skryptu, gdy strona wyświetla tylko
pojedynczy wpis bloga lub zawiera komentarze.

    // Dodanie skryptu, jeśli użytkownik nie jest zalogowany.
    add_action( 'template_redirect', 'boj_insertjs_notlogged' );
    function boj_insertjs_notlogged() {
        if( !is_user_logged_in() )
            wp_enqueue_script( 'boj_insertjs_8', BOJ_INSERTJS.'/notlogged.js' );
    }
    // Dodanie skryptu na stronie zawierającej pojedynczy wpis bloga oraz na stronach posiadających komentarze.
    add_action( 'template_redirect', 'boj_insertjs_add_ifcomments' );
    function boj_insertjs_add_ifcomments() {
        if( is_single() ) {
            global $post;
            if( $post->comment_count )
                wp_enqueue_script( 'boj_insertjs_9', BOJ_INSERTJS.'/hascomments.js' );
        }
    } 

Skrypty dynamiczne na platformie WordPress

Pliki JavaScript to najczęściej statyczne pliki .js, choć czasami
trzeba, aby skrypt obsługiwał dane pochodzące z platformy WordPress, np.
takie jak wartość opcji lub ścieżka dostępu wtyczki.

W jaki sposób tego nie robić i dlaczego?

Oczywistym sposobem sprawienia, że skrypt JavaScript będzie dynamiczny,
jest utworzenie pliku skrypt.js.php zamiast statycznego, dzięki czemu
PHP wygeneruje skrypt JavaScript w locie.

Aby skrypt wykorzystywał dane pochodzące z platformy WordPress, spora
grupa programistów wykorzystuje przedstawione poniżej metody.

1.  Umieszczenie dynamicznego skryptu w kolejce platformy WordPress w
    zwykły sposób:

        <?php
        wp_enqueue_script( 'dyn', $path.'/script.js.php' );
        ?> 

2.  Umieszczenie na początku pliku script.js.php poniższego kodu:

        <?php
        header('Content-type: application/javascript');
        include( '../../../wp-load.php' );
        ?> 
        /* Miejsca na kod JavaScript (i PHP). */ 

Powyższe (niestety, często stosowane) rozwiązania mają kilka wad o
znaczeniu krytycznym.

-   Znalezienie plików wp-load.php lub wp-config.php może być trudne:
    cały katalog wp-content może być umieszczony w innym,
    niestandardowym miejscu i niekoniecznie jako podkatalog katalogu
    zawierającego plik wp-load.php. Nieudana próba dołączenia
    wymienionego pliku może spowodować powstanie błędu o znaczeniu
    krytycznym, gdy skrypt będzie próbował uzyskać dostęp do funkcji
    WordPress.
-   Wymóg wczytania pliku wp-load.php w osadzonym pliku powoduje ponowną
    inicjalizację platformy WordPress, co oznacza wykonanie ponownego
    żądania do serwera WWW dla każdej strony. W ten sposób mamy dwie
    procedury inicjalizacyjne, obie odczytują dane z pamięci, obie
    wczytują wtyczki itd.
-   W zależności od konfiguracji, przeglądarka internetowa może nie
    buforować plików .js.php, co spowoduje zwiększenie obciążenia
    serwera i większe wykorzystanie łącza w intensywnie odwiedzanych
    witrynach internetowych.

Lepsze rozwiązanie

Przedstawione powyżej rozwiązanie jest kuszące, ponieważ plik .js.php
zapewnia elastyczność kodu, np. możliwość wygenerowania zupełnie innego
kodu JavaScript, w zależności od wartości zmiennej.

Jeżeli trzeba użyć tego rodzaju pliku, znacznie lepszym rozwiązaniem
będzie przekazanie wymaganej zmiennej jako argumentu zapytania do pliku
.js.php i jego całkowite oddzielenie od platformy WordPress (tzn. bez
wczytywania pliku wp-load.php).

1.  Na platformie WordPress należy pobrać wymagane informacje, a
    następnie umieścić w kolejce dynamiczny skrypt wraz z argumentami
    zapytania:

        <?php
        // Pobranie informacji dotyczących wymagań skryptu.
        $var1 = get_option( 'myplugin_var1' );
        $var2 = get_home_url();
        // Utworzenie atrybutów zapytania dla dynamicznego skryptu.
        $script = 'script.js.php?var1=' . $var1 . ' & var2=' . $var2 ;
        wp_enqueue_script( 'dyn', $path.'/'.$script );
        ?> 

2.  Teraz plik .script.js.php będzie miał postać podobną do
    przedstawionej poniżej:

        <?php
        header('Content-type: application/javascript');
        // Pobranie zmiennych.
        $var  = isset( $_GET['var1'] ? $_GET['var1'] : '' );
        $home = isset( $_GET['var2'] ? $_GET['var2'] : '' );
        ?> 
        /* Miejsce na kod JavaScript (i PHP) używający zmiennych $var i $home. */

Przedstawione rozwiązanie jest bezsprzecznie lepsze, ponieważ nie
powoduje przeprowadzenia ponownej inicjalizacji platformy WordPress w
pliku skryptu, który obecnie jest całkowicie niezależny od platformy
oraz położenia katalogu.

Do rozwiązania nadal pozostał potencjalny problem związany z
buforowaniem plików przez przeglądarkę internetową, która może lub nie
buforować plik script.js.php?args. Jeżeli skrypt będzie używany jedynie
w obszarze administracyjnym, to nie stanowi dużego problemu. Jednak
używanie skryptu na stronach publicznych witryny może być problemem,
ponieważ strony te są odwiedzane znacznie częściej oraz przez dużo
większą liczbę różnych użytkowników.

Rozwiązanie idealne

Znacznie solidniejszym rozwiązaniem jest dynamiczne generowanie wartości
zmiennych w kodzie osadzonym na stronie WordPress wymagającej skryptu
JavaScript, a następnie umieszczenie w kolejce całkowicie statycznego,
możliwego do buforowania pliku. Przykładowo w kolejnym podrozdziale
zatytułowanym "Technologia Ajax na platformie WordPress" utworzysz
wtyczkę w technologii Ajax, która będzie musiała znać adres URL pliku
obsługującego żądania Ajax na platformie WordPress, np.
http://przyklad.pl/wp-admin/admin-ajax.php. We wspomnianej wtyczce
użyjesz omówionej tutaj techniki.

Pierwszym krokiem jest umieszczenie w kolejce zupełnie statycznego
skryptu. Odbywa to się w zwykły sposób:

    <?php
    // Umieszczenie skryptu w kolejce.
    wp_enqueue_script( 'boj_myplugin', plugin_dir_url( __FILE__ ).'js/script.js', );
    ?> 

Kolejny krok to zebranie w tablicy wszystkich danych WordPress
wymaganych przez skrypt:

    <?php
    $params = array(
        'option1' => get_option( 'boj_myplugin_option' ),
        'home'    => get_home_url();
    );
    ?> 

Ostatnim krokiem jest poinformowanie platformy WordPress, że jeśli
będzie zawierała ten statyczny skrypt, to wcześniej powinna wygenerować
odpowiednie zmienne:

    <?php
    wp_localize_script( 'boj_myplugin', 'boj_myplugin_params', $params );
    ?> 

Funkcja wp_localize_script() wymaga trzech argumentów: skryptu
zarejestrowanego wcześniej za pomocą wywołania funkcji
wp_enqueue_script(), unikalnej nazwy dla opcji oraz tablicy ciągów
tekstowych, które zostaną skonwertowane na poprawnie przygotowany (z
obsługą niebezpiecznych znaków i znaków cytowania) ciąg tekstowy
JavaScript.

Poniżej przedstawiono pełny przykładowy fragment kodu oraz wygenerowany
przez niego rzeczywisty kod na stronie:

    <?php
    // Umieszczenie skryptu w kolejce.
    wp_enqueue_script( 'boj_myplugin', plugin_dir_url( __FILE__ ).'js/script.js', );
    $params = array(
        'option1' => get_option( 'boj_myplugin_option' ),
        'home'    => get_home_url();
    );
    wp_localize_script( 'boj_myplugin', 'boj_myplugin_params', $params );
    ?> 

Powyższy fragment kodu powoduje wygenerowanie kodu HTML podobnego do
poniższego:

    <script type='text/javascript'> 
    /*  < ![CDATA[ */
    var boj_myplugin_params = {
        option1: "to jest wartość opcji",
        home: "http://przyklad.pl/"
    };
    /* ]] >  */
    </script> 
    <script
       type='text/javascript'
       src='http://przyklad.pl/wp-content/plugins/boj_myplugin/js/script.js?ver=3.1'> 
    </script> 

Funkcja JavaScript znajdująca się w pliku script.js może teraz bardzo
łatwo uzyskać dostęp do zmiennych dynamicznych, którymi będą odpowiednio
boj_myplugin_params.option1 i boj_myplugin_params.home.

Użycie omówionej w rozdziale 5. funkcji wp_localize_script() może w
pierwszej chwili wydawać się nieco nieoczekiwane, ponieważ w tym miejscu
nie przeprowadzamy tłumaczenia skryptu na inne języki. Wiąże się jednak
z pewnymi korzyściami.

-   Pozwala na użycie w pełni statycznego skryptu, a tym samym
    buforowanego przez przeglądarki internetowe i niewymagającego
    przetwarzania przez serwer.
-   Osadzony kod JavaScript jest powiązany z głównym skryptem
    zdefiniowanym przez funkcję wp_enqueue_script(). Następuje
    precyzyjne wskazanie stron docelowych. Jeżeli wystąpi konieczność
    usunięcia głównego skryptu z kolejki, w kodzie nie pozostanie żaden
    osadzony kod JavaScript.
-   Osadzony kod JavaScript zawsze będzie poprawnie przygotowany
    (obsługa niebezpiecznych znaków i znaków cytowania).
-   Funkcja zajmuje się dodaniem wymaganych znaczników CDATA, które
    umożliwią przejście weryfikacji przez kod XHTML.

Technologia Ajax na platformie WordPress

Jak dotąd dowiedziałeś się w jaki sposób bezproblemowo umieścić skrypt
JavaScript na stronach generowanych przez platformę WordPress. Warto
więc teraz nauczyć się, jak obsłużyć i przetworzyć żądania Ajax.

Technologia Ajax na platformie WordPress: reguły

Jak wspomniano na początku rozdziału, podczas używania technologii Ajax
można wyodrębnić serię zdarzeń, które przedstawiono na rysunku 12.4.

Implementacja technologii Ajax na platformie WordPress to prosty proces:
przy użyciu biblioteki jQuery można bardzo łatwo zarówno wysyłać, jak i
odbierać dane Ajax, podczas gdy dedykowana akcja platformy WordPress
zajmuje się całą obsługą procesu po stronie serwera.

[]

Rysunek 12.4. Zdarzenia zachodzące podczas używania technologii Ajax

Strona klienta: wykonywanie żądania Ajax, otrzymywanie odpowiedzi

Kiedy po stronie klienta występują zdarzenia (kliknięty element,
upłynęła zdefiniowana ilość czasu, wysłany formularz itd.), możesz
przetworzyć i zebrać dane, które znajdą się w żądaniu Ajax:

    var data = {
        action:    'boj_myplugin_do_ajax_request',
        some_var:  'dowolna wartość',
        other_var: 'inna wartość'
    }; 

Warto zwrócić uwagę na parametr action, będziemy go używać później.

Dzięki wykorzystaniu biblioteki jQuery wykonywanie żądań Ajax (tutaj za
pomocą metody POST) i oczekiwanie na udzielenie odpowiedzi przez serwer
jest obsługiwane przy użyciu pojedynczego wywołania funkcji. Funkcja ta
otrzymuje adres URL pliku admin-ajax.php, dane oraz nazwę funkcji
odpowiedzialnej za ich przetworzenie:

    jQuery.post( 'http://przyklad.pl/wp-admin/admin-ajax.php', data, function( resp ) {
        /*
        1. przetworzenie obiektu odpowiedzi 'resp';
        2. uaktualnienie pewnego fragmentu strony.
        */
    }); 

Wszystkie żądania Ajax są przekazywane plikowi admin-ajax.php
znajdującemu się w katalogu wp-admin. Pomimo nazwy strony i jej
położenia, wymieniony plik jest przeznaczony do obsługi i przetwarzania
żądań Ajax wykonywanych zarówno z obszaru administracyjnego, jak i z
publicznie dostępnej części witryny. Warto w tym miejscu dodać, że
żądania Ajax mogą wykonywać użytkownicy zalogowani i niezalogowani.

------------------------------------------------------------------------

Uwaga

Więcej informacji na temat składni żądań Ajax w jQuerytype="note" można
znaleźć na stronie http://api.jquery.com/category/ajax/.

------------------------------------------------------------------------

Strona serwera: otrzymanie żądania Ajax, udzielenie odpowiedzi

W omawianym przykładzie po stronie klienta kod JavaScript przekazuje
dane plikowi admin-ajax.php wraz z parametrem o nazwie action i wartości
boj_myplugin_do_ajax_request(). Odgadłeś prawidłowo: wymieniona wartość
musi być unikalna, a użycie prefiksu jest dobrą praktyką.

Parametr action określa sposób połączenia funkcji zdefiniowanej na
platformie WordPress z żądaniem Ajax za pomocą dwóch akcji wp_ajax_*:

-   wp_ajax_$action — wskazuje funkcję wywoływaną, gdy użytkownik jest
    zalogowany;
-   wp_ajax_nopriv_$action — wskazuje funkcję wywoływaną, gdy użytkownik
    nie jest zalogowany lub nie posiada uprawnień.

Przykładowo we wtyczce może być zdefiniowany następujący zaczep akcji:

    <?php
    add_action( 'wp_ajax_boj_myplugin_do_ajax_request', 'boj_myplugin_process_ajax' );
    ?> 

Teraz można już zdefiniować funkcję odpowiedzialną za przetworzenie
żądania i zwrócenie danych:

    <?php
    // Przetworzenie danych żądania Ajax oraz udzielenie odpowiedzi.
    function boj_myplugin_process_ajax() {
        // Sprawdzenie możliwości i uprawnień użytkownika: current_user_can().
        // Sprawdzenie intencji: wp_verify_nonce().
        // Przetworzenie danych przekazanych przez żądanie Ajax.
        // Przekazanie danych odpowiedzi, które będą przetworzone przez funkcję obsługującą żądanie Ajax.
        die();
    }
    ?> 

W zależności od sytuacji trzeba zwrócić uwagę na uprawnienia i intencje
użytkownika, co wyjaśniono w rozdziale 6., który poświęcono zapewnieniu
bezpieczeństwa.

Po przeprowadzeniu operacji związanych z zapewnieniem bezpieczeństwa
funkcja może przystąpić do przetwarzania danych z tablicy $_POST i
przekazania wyniku w postaci zrozumiałej dla funkcji obsługującej
żądanie Ajax po stronie klienta oraz wywołania die().

------------------------------------------------------------------------

Uwaga

Wszystkie żądania Ajax pochodzące zarówno z publicznie dostępnej części
witryny, jak i z obszaru administracyjnego są obsługiwane przez plik
admin-ajax.php. Jeżeli katalog zawierający wymieniony plik jest
chroniony na poziomie niższym niż platforma WordPress (np. za pomocą
hasła .htaccess), wówczas plik będzie niedostępny dla niezalogowanych
użytkowników i próba wykonania żądania Ajax zakończy się niepowodzeniem.

------------------------------------------------------------------------

Aby praktycznie wykorzystać wiedzę z zakresu omówionego procesu
implementacji oraz technik wstawiania kodu JavaScript, zbudujemy teraz
interesującą wtyczkę.

Kompletny przykład: natychmiastowe odnośniki "Czytaj dalej"

Jak już wiesz, wpis bloga WordPress możesz podzielić znacznikiem
<!--more-->. To daje możliwość utworzenia eleganckiej wtyczki, która
pozwoli czytelnikowi na przeczytanie dalszej części wpisu bloga bez
wykonywania przekierowania na nową stronę. Po kliknięciu odnośnika
Czytaj dalej nastąpi wyświetlenie dalszej części wpisu bloga, co
pokazano na rysunku 12.5.

Prefiksem wykorzystywanym w tej wtyczce Ajax Czytaj dalej jest boj_arm_.
Wtyczka musi wykonać wymienione poniżej zadania:

[]

Rysunek 12.5. Działanie wtyczki obsługującej natychmiastowe odnośniki
"Czytaj dalej"

-   wstawić skrypt odpowiedzialny za monitorowanie kliknięcia odnośnika
    Czytaj dalej;
-   wstawić skrypt tylko wtedy, gdy na stronie znajduje się odnośnik
    Czytaj dalej;
-   pobrać pozostałą część wpisu bloga po kliknięciu odnośnika.

Wstawianie kodu JavaScript

Do chwili wygenerowania przez platformę WordPress elementu <head> strony
nie wiadomo, czy strona będzie zawierała odnośnik Czytaj dalej. Z tego
powodu trzeba zastosować sprytniejszą technikę wstawiania skryptu.

1.  Umieścić skrypt JavaScript w kolejce do wstawienia w stopce.
2.  Po wyświetleniu każdego wpisu bloga sprawdzić istnienie odnośnika
    Czytaj dalej.
3.  Tuż przed faktycznym wstawieniem skryptu w stopce sprawdzić, czy
    naprawdę jest potrzebny; w przeciwnym razie należy go usunąć z
    kolejki skryptów do wstawienia.

Pierwszym krokiem jest umieszczenie skryptu JavaScript w kolejce
skryptów do wstawienia w stopce strony.

    <?php
    // Wersja wtyczki, po uaktualnieniu wtyczki należy zwiększyć numer wersji.
    define( 'BOJ_ARM_VERSION', '1.0' );
    // Umieszczenie skryptu JavaScript w kolejce skryptów do wstawienia w stopce strony.
    add_action( 'template_redirect', 'boj_arm_add_js' );
    function boj_arm_add_js() {
        //  Umieszczenie skryptu w kolejce.
        wp_enqueue_script( 'boj_arm',
            plugin_dir_url( __FILE__ ).'js/script.js',
            array('jquery'), BOJ_ARM_VERSION, true
        );
        // Pobranie protokołu bieżącej strony.
        $protocol = isset( $_SERVER["HTTPS"]) ? 'https://' : 'http://';
        // Wyświetlenie strony admin-ajax.php z użyciem takiego samego protokołu jak na bieżącej stronie.
        $params = array(
          'ajaxurl' => admin_url( 'admin-ajax.php', $protocol )
        );
        wp_localize_script( 'boj_arm', 'boj_arm', $params );
    }
    ?> 

Jak już wcześniej wyjaśniono, akcje Ajax są obsługiwane przez plik
admin-ajax.php znajdujący się w katalogu wp-admin, którego położenie
jest określane za pomocą funkcji admin_url(). Trzeba również pamiętać o
omówionych we wcześniejszej części rozdziału ważnych ograniczeniach
technologii Ajax: z powodu stosowania polityki tego samego źródła
żądania i odpowiedzi Ajax muszą być przetwarzane przez tę samą domenę z
użyciem tego samego protokołu (HTTP lub HTTPS).

Na platformie WordPress można wymusić stosowanie protokołu HTTPS w
obszarze administracyjnym (definiując stałą FORCE_SSL_ADMIN wraz z
wartością true), nawet jeśli publicznie dostępna część witryny korzysta
z protokołu HTTP. Nie można jednak wyświetlić strony na witrynie
http://przyklad.pl/, która wykonuje żądanie Ajax do strony
https://przyklad.pl/wp-admin/​admin-ajax.php.

Z tego powodu w kodzie następuje wywołanie funkcji admin_url() wraz z
drugim parametrem, który wymusza zastosowanie bieżącego protokołu
użytego w publicznej części adresu i wskazującego położenie pliku
admin-ajax.php. Innymi słowy, jeśli nawet w obszarze administracyjnym
ustawiono używanie protokołu https://, wyświetlane strony publiczne
stosujące protokół http:// będą udzielały odpowiedzi stronie
http://przyklad.pl/wp-admin/admin-ajax.php.

------------------------------------------------------------------------

Uwaga

Pamiętaj, aby żądanie Ajax zakończyło się powodzeniem, musi być wykonane
w ramach tej samej domeny, subdomeny (http://przyklad.pl/ i
https://przyklad.pl są uznawane za inne) i protokołu (HTTP lub HTTPS).

------------------------------------------------------------------------

Drugi krok to, jak już wcześniej wspomniano, sprawdzenie, czy na stronie
wpisu bloga znajduje się odnośnik Czytaj dalej, który uzasadni
dołączenie skryptu JavaScript w stopce strony.

    <?php
    // Określenie, czy wstawienie skryptu jest konieczne.
    global $boj_arm_needjs;
    $boj_arm_needjs = false;
    // Przegląd każdego wpisu bloga i sprawdzenie, czy zawiera odnośnik "Czytaj dalej".
    add_action( 'the_post', 'boj_arm_check_readmore' );
    function boj_arm_check_readmore( $post ) {
        if ( preg_match('/<!--more(.*?)?-->/', $post->post_content ) && !is_single() ) {
            global $boj_arm_needjs;
            $boj_arm_needjs = true;
        }
    }
    ?> 

W powyższym fragmencie kodu podczas każdej iteracji pętli
przeprowadzanej względem nieprzetworzonego i niesformatowanego wpisu
bloga następuje sprawdzenie, czy treść wpisu ($post->post_content)
zawiera znacznik <!--more-->. Jeżeli dana strona nie zawiera jednego, w
pełni wyświetlonego wpisu bloga, nastąpi ustawienie wartości true opcji
boolowskiej, co oznacza konieczność dołączenia skryptu JavaScript.

Trzeci ostatni krok w procesie wstawiania skryptu JavaScript zachodzi w
stopce, tuż przed dodaniem skryptu przez platformę WordPress. W tym
miejscu trzeba sprawdzić, czy skrypt jest faktycznie niezbędny. Jeśli
nie, należy go usunąć z kolejki skryptów do wstawienia.

    <?php
    // Nie dodawaj skryptu, jeśli faktycznie nie jest potrzebny.
    add_action( 'wp_print_footer_scripts', 'boj_arm_footer_maybe_remove', 1 );
    function boj_arm_footer_maybe_remove() {
        global $boj_arm_needjs;
        if( !$boj_arm_needjs ) {
            wp_deregister_script( 'boj_arm' );
        }
    }
    ?> 

Platforma WordPress dodaje skrypty w stopce strony w chwili wywołania
zaczepu akcji wp_print_footer_scripts. Jeżeli wartość opcji boolowskiej
wynosi false, skrypt JavaScript zostanie po prostu wyrejestrowany.
Ponieważ użyto także funkcji wp_localize_script() w celu osadzenia
poleceń JavaScript w kodzie, po usunięciu skryptu z kolejki ten kod
również trzeba usunąć, aby w kodzie strony nie pozostawić niepotrzebnych
poleceń.

Skrypt JavaScript działający po stronie klienta

Po zagwarantowaniu, że skrypt zostanie wstawiony jedynie wtedy, gdy
będzie potrzebny, można przystąpić do jego utworzenia. Zadaniem skryptu
jest przejście przez każdy odnośnik posiadający atrybut
class="more-link" i dodanie mu następującego zachowania po kliknięciu.

-   Określenie identyfikatora wpisu bloga z odnośnika Czytaj dalej,
    który będzie znajdował się we fragmencie typu #more-45.
-   Zmiana tekstu odnośnika na wczytywanie…, aby czytelnik wiedział, że
    w tle następuje wczytywanie pozostałej części wpisu bloga.
-   Wykonanie żądania Ajax do pliku admin-ajax.php wraz z
    identyfikatorem wpisu bloga i żądaniem pozostałej części wpisu.
-   Pobranie pozostałej części wpisu bloga oraz jej wyświetlenie w
    miejscu odnośnika Czytaj dalej.

Poniżej przedstawiono pełny kod skryptu:

    (function($) {
        $('a.more-link').click(function(){
            // Utworzenie kopii obiektu w celu późniejszego użycia.
            var link = this;
            // Zmiana tekstu odnośnika.
            $(link).html('wczytywanie...');
            // Pobranie identyfikatora wpisu bloga  z adresu odnośnika.
            var post_id = $(link).attr('href').replace(/^.*#more-/, '');
            // Przygotowanie danych żądania Ajax: akcja i identyfikator wpisu bloga.
            var data = {
                action: 'boj_arm_ajax',
                post_id: post_id
            };
            // Wykonanie żądania Ajax wraz z przygotowanymi danymi.
            $.get(boj_arm.ajaxurl, data, function(data){
                // Dodanie treści po odnośniku i usunięcie samego odnośnika.
                $(link).after(data).remove();
            });
            // Wyłączenie zachowania domyślnego po kliknięciu odnośnika.
            return false;
        });
    })(jQuery); 

Warto zwrócić uwagę, że skrypt używa adresu URL pliku admin-ajax.php
zawartego w boj_arm.ajaxurl i dostarczonego przez wywołanie funkcji
wp_localize_script().

Przetwarzanie żądania Ajax po stronie serwera

Ostatnim elementem wtyczki jest przetwarzanie po stronie serwera: plik
admin-ajax.php otrzymuje identyfikator wpisu bloga, który będzie
wykorzystany do pobrania pozostałej części wpisu bloga odpowiadającego
podanemu identyfikatorowi.

Na początek należy zdefiniować akcję Ajax i powiązaną z nią funkcję:

    <?php
    // Obsługa żądania Ajax.
    add_action('wp_ajax_nopriv_boj_arm_ajax', 'boj_arm_ajax');
    add_action('wp_ajax_boj_arm_ajax', 'boj_arm_ajax');
    function boj_arm_ajax() {
        // Modyfikacja sposobu pobierania treści wpisu bloga przez platformę WordPress.
        add_filter( 'the_content', 'boj_arm_get_2nd_half' );
        // Konfiguracja zapytania.
        query_posts( 'p='.absint( $_REQUEST['post_id'] ) );
        // Pętla.
        if ( have_posts() ) : while ( have_posts() ) : the_post();
            the_content();
        endwhile; else:
            echo "nie znaleziono wpisu bloga :/";
        endif;
        // Zerowanie zapytania.
        wp_reset_query();
        // W funkcjach przygotowujących treść dla żądania Ajax zawsze należy wywoływać die().
        die();
    }
    ?> 

Ponieważ czytający wpis bloga może być anonimowym lub przypadkowym
czytelnikiem bądź użytkownikiem z określonymi uprawnieniami, używane są
zaczepy wp_ajax_* i wp_ajax_nopriv_*, które prowadzą do tej samej
funkcji o nazwie boj_arm_ajax().

Funkcja obsługująca żądanie Ajax (boj_arm_ajax()) to przede wszystkim
pętla, która jest ograniczona do jednego wpisu bloga o podanym
identyfikatorze. Nie zostały w niej zaimplementowane żadne mechanizmy
bezpieczeństwa poza sprawdzeniem, czy identyfikator wpisu bloga
faktycznie jest liczbą całkowitą. Zadaniem pętli jest wyświetlenie
treści wpisu bloga, co jest dozwolone dla każdego użytkownika, stąd brak
sprawdzania uprawnień.

Wartością zwrotną funkcji jest cały wpis bloga, ale w tym miejscu
potrzebujemy tylko jego niewyświetlanej części. To zadanie będzie
wykonane za pomocą filtra dostępnego w funkcji:

    <?php
    // Pobranie tej części wpisu bloga, która znajduje się po odnośniku "Czytaj dalej".
    function boj_arm_get_2nd_half( $content ) {
        $id = absint( $_REQUEST['post_id'] );
        $content = preg_replace( "!^.*<span id=\"more-$id\"></span>!s", '', $content );
        return $content;
    }
    ?> 

Funkcja po zarejestrowaniu w zaczepie the_content będzie otrzymywała
sformatowaną treść wpisu bloga, którą zwróci po wcześniejszym usunięciu
wszystkiego aż do napotkania elementu <span> używanego przez platformę
WordPress do umieszczenia odnośnika Czytaj dalej.

Praca została zakończona! Poniżej przedstawiono pełny kod źródłowy
wtyczki Ajax Czytaj dalej i używanego przez nią skryptu JavaScript:

    <?php
    /*
    Plugin Name: Ajax Czytaj dalej
    Plugin URI: http://przyklad.pl/
    Description: Obsługa odnośników "Czytaj dalej" za pomocą technologii Ajax.
    Version: 1.0
    Author: Ozh
    Author URI: http://wrox.com
    */
    // Określenie, czy wstawienie skryptu jest konieczne.
    global $boj_arm_needjs;
    $boj_arm_needjs = false;
    // Wersja wtyczki, po uaktualnieniu wtyczki należy zwiększyć numer wersji.
    define( 'BOJ_ARM_VERSION', '1.0' );
    // Umieszczenie skryptu JavaScript w kolejce skryptów do wstawienia w stopce strony.
    add_action( 'template_redirect', 'boj_arm_add_js' );
    function boj_arm_add_js() {
        // Umieszczenie skryptu w kolejce.
        wp_enqueue_script( 'boj_arm',
            plugin_dir_url( __FILE__ ).'js/script.js',
            array('jquery'), BOJ_ARM_VERSION, true
        );
        // Pobranie protokołu bieżącej strony.
        $protocol = isset( $_SERVER["HTTPS"]) ? 'https://' : 'http://';
        // Wyświetlenie strony admin-ajax.php z użyciem takiego samego protokołu jak na bieżącej stronie.
        $params = array(
          'ajaxurl' => admin_url( 'admin-ajax.php', $protocol )
        );
        wp_localize_script( 'boj_arm', 'boj_arm', $params );
    }
    // Nie dodawaj skryptu, jeśli faktycznie nie jest potrzebny.
    add_action( 'wp_print_footer_scripts', 'boj_arm_footer_maybe_remove', 1 );
    function boj_arm_footer_maybe_remove() {
        global $boj_arm_needjs;
        if( !$boj_arm_needjs ) {
            wp_deregister_script( 'boj_arm' );
        }
    }
    // Przegląd każdego wpisu bloga i sprawdzenie, czy zawiera odnośnik "Czytaj dalej".
    add_action( 'the_post', 'boj_arm_check_readmore' );
    function boj_arm_check_readmore( $post ) {
        if ( preg_match('/<!--more(.*?)?-->/', $post->post_content )
        && !is_single() ) {
            global $boj_arm_needjs; 
            $boj_arm_needjs = true;
        }
    }
    // Obsługa żądania Ajax.
    add_action('wp_ajax_nopriv_boj_arm_ajax', 'boj_arm_ajax');
    add_action('wp_ajax_boj_arm_ajax', 'boj_arm_ajax');
    function boj_arm_ajax() {
        // Modyfikacja sposobu pobierania treści wpisu bloga przez platformę WordPress.
        add_filter( 'the_content', 'boj_arm_get_2nd_half' );
        // Konfiguracja zapytania.
        query_posts( 'p='.absint( $_REQUEST['post_id'] ) );
        // Pętla.
        if ( have_posts() ) : while ( have_posts() ) : the_post();
            the_content();
        endwhile; else:
            echo "nie znaleziono wpisu bloga :/";
        endif;
        // Zerowanie zapytania.
        wp_reset_query();
        die();
    }
    // Pobranie tej części wpisu bloga, która znajduje się po odnośniku "Czytaj dalej".
    function boj_arm_get_2nd_half( $content ) {
        $id = absint( $_REQUEST['post_id'] );
        $content = preg_replace( "!^.*<span id=\"more-$id\"></span>!s", '', $content );
        return $content;
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_readmore/plugin.php.

------------------------------------------------------------------------

    (function($) {
        $('.more-link').click(function(){
            var link = this;
            $(link).html('wczytywanie...');
            var post_id = $(link).attr('href').replace(/^.*#more-/, '');
            var data = {
                action: 'boj_arm_ajax',
                post_id: post_id
            };
            $.get(boj_arm.ajaxurl, data, function(data){
                $(link).after(data).remove();
            });
            return false;
        });
    })(jQuery); 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_readmore/js/script.js.

------------------------------------------------------------------------

Kolejny przykład: usunięcie komentarza ze strony

W tym punkcie powstanie inna wtyczka, która użytkownikowi z
wystarczającymi uprawnieniami pozwoli na usunięcie komentarza ze strony.
Taka operacja przebiega natychmiastowo i nie wymaga oczekiwania na
odświeżenie strony (zobacz rysunek 12.6).

[]

Rysunek 12.6. Wtyczka pozwalająca na natychmiastowe usunięcie komentarza
ze strony w działaniu

Podczas tworzenia kodu wtyczki Natychmiastowe usunięcie komentarza
następuje wykorzystanie trzech aspektów używania technologii Ajax na
platformie WordPress.

-   W jaki sposób zaimplementować zapewnienie bezpieczeństwa podczas
    stosowania technologii Ajax?
-   Klasa Wp_Ajax_Response i jej odpowiedź w formacie XML.
-   W jaki sposób odczytywać odpowiedź XML w kodzie JavaScript?

Podstawowy kod wtyczki

Najpierw trzeba utworzyć kod wtyczki dodający skrypt JavaScript tylko
wtedy, gdy trzeba, a także umieszczający odnośnik Usuń komentarz pod
każdym komentarzem. Stosowanym prefiksem we wtyczce jest boj_idc_.

    <?php
    /*
    Plugin Name: Natychmiastowe usunięcie komentarza
    Plugin URI: http://przyklad.pl/
    Description: Dodaje odnośnik pozwalający na natychmiastowe usunięcie komentarza.
    Author: Ozh
    Version: 1.0
    Author URI: http://wrox.com/
    */
    // Dodanie skryptu na stronie zawierającej pojedynczy wpis bloga oraz na stronach z komentarzami, ale tylko wtedy, gdy użytkownik na uprawnienia do edycji.
    add_action( 'template_redirect', 'boj_idc_addjs_ifcomments' );
    function boj_idc_addjs_ifcomments() {
        if( is_single() && current_user_can( 'moderate_comments' ) ) {
            global $post;
            if( $post->comment_count ) {
                $path = plugin_dir_url( __FILE__ );
                wp_enqueue_script( 'boj_idc', $path.'js/script.js' );
                $protocol = isset( $_SERVER["HTTPS"]) ? 'https://' : 'http://';
                $params = array(
                  'ajaxurl' => admin_url( 'admin-ajax.php', $protocol )
                );
                wp_localize_script( 'boj_idc', 'boj_idc', $params );
            }
        }
    }
    // Dodanie odnośnika administracyjnego pod każdym komentarzem.
    add_filter( 'comment_text', 'boj_idc_add_link' );
    function boj_idc_add_link( $text ) {
        // Pobranie identyfikatora bieżącego komentarza.
        global $comment;
        $comment_id = $comment->comment_ID;
        // Pobranie odnośnika do strony administracyjnej w celu usunięcia komentarza oraz dodanie unikalnej wartości.
        $link = admin_url( 'comment.php?action=trash&c='.$comment_id );
        $link = wp_nonce_url( $link, 'boj_idc-delete-'.$comment_id );
        $link = "<a href='$link' class='boj_idc_link'>Usuń komentarz</a>";
        
        // Dodanie odnośnika do tekstu komentarza.
        return $text."<p>[admin: $link]</p>";
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_deletecomment/plugin.php.

------------------------------------------------------------------------

Funkcja boj_idc_addjs_ifcomments() nie wymaga objaśnienia. Z kolei w
funkcji boj_idc_add_link() następuje zmodyfikowanie tekstu komentarza.
Warto zwrócić uwagę na użycie funkcji wp_nonce_url(), która została
szczegółowo omówiona w rozdziale 6.

Odnośnik dodany pod każdym komentarzem ma atrybut klasy boj_idc_link
oraz wykorzystuje następujący wzorzec adresu
http://przyklad.pl/wp-admin/​comment.php?action=​trash&c=11&_wpnonce=551e407bc1.
Po kliknięciu odnośnik powoduje przekazanie poprzez żądanie Ajax
parametru c (identyfikator wpisu bloga) oraz unikalnej wartości.

Obsługa żądania Ajax po stronie serwera: zapewnienie bezpieczeństwa oraz przetworzenie odpowiedzi XML

Obsługa żądania Ajax po stronie serwera odbywa się za pomocą
przedstawionej poniżej funkcji:

    <?php
    // Obsługa żądania Ajax.
    add_action( 'wp_ajax_boj_idc_ajax_delete', 'boj_idc_ajax_delete' );
    function boj_idc_ajax_delete() {
        $cid = absint( $_POST['cid'] );
        
        $response = new WP_Ajax_Response;
        if(
            current_user_can( 'moderate_comments' ) &&
            check_ajax_referer( 'boj_idc-delete-'.$cid, 'nonce', false ) &&
            wp_delete_comment( $cid  )
        ) {
            // Żądanie zakończyło się powodzeniem.
            $response->add( array(
                'data' => 'success',
                'supplemental' => array(
                    'cid'     => $cid,
                    'message' => 'ten komentarz został usunięty'
                ),
            ) );
        } else {
            // Żądanie zakończyło się niepowodzeniem.
            $response->add( array(
                'data' => 'error',
                'supplemental' => array(
                    'cid'     => $cid,
                    'message' => 'wystąpił błąd'
                ),
            ) );
        }
        $response->send();
        exit();
    }
    ?> 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_deletecomment/plugin.php.

------------------------------------------------------------------------

Warto zwrócić uwagę na kroki podjęte w celu zapewnienia bezpieczeństwa
oraz na użycie nowej klasy — WP_Ajax_Response.

Zapewnienie bezpieczeństwa: unikalna wartość i uprawnienia

Jak to omówiono w rozdziale 6., pierwszym krokiem przed wykonaniem
żądania jest sprawdzenie uprawnień użytkownika oraz jego intencji.

Działanie funkcji check_ajax_referer() jest podobne do
check_admin_referer(), a sama funkcja może pobrać trzy parametry.

1.  $action — ciąg tekstowy odpowiadający unikalnej akcji używanej do
    wygenerowania unikalnej wartości, tutaj
    'boj_idc-delete-'.$comment_id.
2.  $query-arg — nazwa parametru przekazywanego do żądania Ajax i
    zawierającego ciąg z unikalną wartością. Jeżeli ten parametr
    zostanie pominięty, funkcja przeszuka tablicę $_REQUEST pod kątem
    istnienia elementów _ajax_nonce lub _wpnonce. W takim przypadku
    szukany jest ciąg tekstowy unikalnej wartości, który powinien
    znajdować się w parametrze nonce.
3.  $die — wartość boolowska, domyślnie true, informuje platformę
    WordPress, że działanie ma zostać zakończone wraz z komunikatem -1.
    Wymieniony komunikat można zinterpretować jako niepowodzenie skryptu
    JavaScript działającego po stronie klienta. W omawianej wtyczce
    trzeba samodzielnie zatroszczyć się o obsługę błędów, stąd użycie
    wartości false.

Klasa WP_Ajax_Response

Warto zwrócić uwagę na użycie egzemplarza tej nowej klasy w funkcji
boj_idc_ajax_delete():

    <?php
    // Nowy egzemplarz klasy.
    $response = new WP_Ajax_Response;
    // Dodanie danych do odpowiedzi.
    $response->add( array(
        'data' => 'success',
        'supplemental' => array(
            'cid'     => $cid,
            'message' => 'ten komentarz został usunięty'
        ),
    ) );
    // Udzielenie odpowiedzi.
    $response->send();
    ?> 

Przeznaczeniem tej klasy jest przygotowanie doskonale sformatowanej
odpowiedzi XML, która będzie łatwa do przetworzenia za pomocą biblioteki
jQuery. W metodzie add() następuje dodanie argumentu do odpowiedzi XML.
Oczekiwane jest podanie ciągu tekstowego dla elementu data oraz
przekazanie tablicy dla elementu supplemental. Przykładowo w tym miejscu
można bardzo łatwo przekazać statycznemu kodowi JavaScript strony
internetowej przetłumaczone ciągi tekstowe.

Metoda send() przekazuje dane w postaci dokumentu XML, a następnie
kończy działanie funkcji, uniemożliwiając tym samym wygenerowanie
jakichkolwiek dalszych danych wyjściowych. Otrzymany wynik może być
podobny do przedstawionego poniżej fragmentu kodu XML:

    <?xml version='1.0' standalone='yes'?> 
    <wp_ajax> 
        <response action="boj_idc_ajax_delete_0"> 
            <object id="0" position="1"> 
                <response_data>success</response_data> 
                <supplemental> 
                    <cid>12</cid> 
                    <message>ten komentarz został usunięty</message> 
                </supplemental> 
            </object> 
        </response> 
    </wp_ajax> 

Teraz należy utworzyć skrypt JavaScript działający po stronie klienta
oraz przekonać się, jak można przetwarzać przedstawioną powyżej
odpowiedź XML.

Przetwarzanie odpowiedzi XML po stronie klienta

Poniżej przestawiono pełny kod skryptu działającego po stronie klienta:

    jQuery(document).ready(function($) {
        $('.boj_idc_link').click(function(){
            var link = this;
            // Pobranie identyfikatora komentarza oraz unikalnej wartości.
            var href = $(link).attr( 'href' );
            var id =    href.replace(/^.*c=(\d+).*$/, '$1');
            var nonce = href.replace(/^.*_wpnonce=([a-z0-9]+).*$/, '$1');
            var data = {
                action: 'boj_idc_ajax_delete',
                cid: id,
                nonce: nonce
            }
            $.post( boj_idc.ajaxurl, data, function(data){
                var status  = $(data).find('response_data').text();
                var message = $(data).find('supplemental message').text();
                if( status == 'success' ) {
                    $(link).parent().after( '<p><b>'+message+'</b></p>' ).remove();
                } else {
                    alert( message );
                }
            });
            return false;
        });
    }); 

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_deletecomment/js/script.js.

------------------------------------------------------------------------

Podobnie jak w poprzedniej wtyczce, także tutaj funkcja ta modyfikuje
zachowanie odnośnika po kliknięciu. Ponadto przetwarza atrybut href
odnośnika w celu pobrania identyfikatora komentarza oraz unikalnej
wartości, a następnie przekazuje te dane w żądaniu Ajax.

Funkcja pokazuje, jak łatwo za pomocą biblioteki jQuery można
przetwarzać odpowiedź XML. Do wyszukania konkretnego elementu w drzewie
elementów wykorzystano funkcję $.find() — to przypomina wybór elementu
na stronie HTML.

Usuwanie błędów podczas używania technologii Ajax

Podczas tworzenia kodu PHP można natychmiast zauważyć błąd — serwer
wyświetli komunikat błędu przy użyciu pogrubionej czcionki. Ponadto za
pomocą funkcji, takiej jak var_dump(), można sprawdzić wartości
zmiennych i zawartość obiektów. Trudność podczas używania technologii
Ajax polega na tym, że procesy z nią związane zachodzą w tle. Tak więc
niepowodzenie wykonania skryptu po stronie klienta lub serwera może
okazać się trudniejsze do wychwycenia.

Dla przeglądarki Firefox powstało nieocenione i bezpłatne rozszerzenie o
nazwie Firebug, które okazuje się niezbędne do analizowania żądań Ajax.
Jak pokazano na rysunku 12.7, przy jego użyciu można np. sprawdzić
parametry oraz otrzymywaną odpowiedź XML.

[]

Rysunek 12.7. Rozszerzenie Firebug przeglądarki Firefox podczas analizy
żądania Ajax

Rozszerzenie dla przeglądarki Firefox można pobrać z witryny
http://getfirebug.com/. Przeglądarka internetowa Chrome ma wbudowane
narzędzie inspektora dostarczające tę samą funkcjonalność.

Za pomocą funkcji console.log() przeglądarka Firefox wraz z
rozszerzeniem Firebug i przeglądarka Chrome pozwalają również na łatwe
sprawdzanie zawartości zmiennych JavaScript, tablic lub obiektów. Odbywa
się to w podobny sposób jak w PHP przy użyciu funkcji var_dump():

    if( typeof(console) == 'object' ) {
        console.log( 'skrypt został wczytany' );
        console.log( tablica, obiekt, dowolny_ciąg_tekstowy);
    }

Podsumowanie

Jeżeli z lektury tego rozdziału miałbyś zapamiętać tylko jedno, wówczas
powinieneś zapamiętać, że podczas dodawania skryptu JavaScript na
stronie WordPress zawsze powinieneś wskazywać miejsce jego dodania przy
użyciu odpowiedniego wywołania funkcji wp_enqueue_script().

Kolejną rzeczą wartą utrwalenia jest to, że stosowanie technologii Ajax
na platformie WordPress jest całkiem łatwe dzięki dostępności
dedykowanych akcji wp_ajax_* i wp_ajax_nopriv_*. Jedyną trudnością
będzie więc opanowanie języka JavaScript i poznanie wspaniałej
biblioteki jQuery.

[1] Omówienie technik w wymienionym dokumencie można również znaleźć w
książce Wydajne witryny internetowe. Przyspieszanie działania serwisów
WWW wydanej przez Grupę Wydawniczą Helion — przyp. tłum.

Rozdział 13 Cron

W tym rozdziale:

-   Zrozumienie demona cron
-   Zarządzanie harmonogramem zadań cron i pojedynczymi zadaniami
-   Usuwanie zadań cron
-   Wyświetlanie wszystkich zadań cron w harmonogramie
-   Tworzenie własnych odstępów czasu w demonie cron
-   Praktyczne przykłady użycia

Wykonywanie określonych funkcji wedle harmonogramu to kluczowa funkcja
API platformy WordPress. W tym rozdziale dowiesz się, jak tworzyć
harmonogramy zadań demona cron, usuwać zadania z harmonogramu oraz
definiować własne odstępy czasu demona cron. Ponadto w rozdziale
utworzymy znacznie bardziej zaawansowane, praktyczne wtyczki używające
demona cron.

Czym jest cron?

Mechanizm cron to oferowany przez platformę WordPress sposób obsługi
zadań zapisanych w harmonogramie. Pojęcie cron pochodzi od stosowanego w
systemie UNIX harmonogramu zadań do wykonania. WordPress wykorzystuje
cron w wielu funkcjach stanowiących jądro platformy. Wspomniane zadania
harmonogramu cron to m.in. sprawdzenie dostępności nowej wersji
platformy WordPress, sprawdzenie dostępności uaktualnień wtyczek i
tematów, a także wyświetlanie wpisów przewidzianych do opublikowania w
konkretnym dniu i godzinie.

W jaki sposób działa demon cron?

Jednym z błędnie przyjmowanych założeń dotyczących cron na platformie
WordPress jest to, że cron działa nieustannie, sprawdzając, czy są
jakiekolwiek zadania do wykonania. To nieprawda. Mechanizm cron działa w
chwili wczytania strony witryny internetowej zarówno dostępnej
publicznie, jak i wyświetlanej w obszarze administracyjnym. W trakcie
każdego żądania wyświetlenia strony platforma WordPress sprawdza, czy
istnieją jakiekolwiek zadania cron do wykonania. Dowolna odsłona strony
— zarówno przez człowieka, jak i robota wyszukiwarki internetowej — może
spowodować wywołanie zadania cron.

Jednak proces ten ma jedną wadę. Ponieważ cron jest wywoływany podczas
wczytywania strony, nie zapewnia 100% dokładności. Jeżeli zadanie cron
ma wedle harmonogramu zostać wykonane o północy, ale w tym czasie nie
będzie żadnego ruchu w witrynie, jego wykonanie może się opóźnić do
godziny np. 0:30 lub jeszcze późniejszej, ponieważ w tym czasie nikt nie
odwiedza danej witryny.

Tworzenie harmonogramu zadań cron

W harmonogramie zadań cron platformy WordPress można zdefiniować dwa
rodzaje zadań: pojedyncze i powtarzające się. Zadanie powtarzające się
jest zdefiniowane w harmonogramie i ma ustaloną stałą godzinę, o której
jest za każdym razem wykonywane. Natomiast zadanie pojedyncze jest
wykonywane tylko jeden raz i nigdy nie będzie wykonane ponownie, o ile
znów nie zostanie umieszczone w harmonogramie.

Utworzenie powtarzającego się zadania harmonogramu

Umieszczenie zadania w harmonogramie w celu jego wykonania przez cron
rozpoczyna się od utworzenia własnego zaczepu akcji. Wspomniany zaczep
będzie zarejestrowany wraz z harmonogramem zadań cron, które zostaną
wykonane w zdefiniowanym czasie. Podczas wywołania zaczepu akcji nastąpi
uruchomienie własnej funkcji zdefiniowanej w zaczepie oraz przetworzenie
kodu przekazanego tej funkcji.

Aby na platformie WordPress utworzyć w harmonogramie zadanie, należy
użyć funkcji wp_ schedule_event():

    <?php wp_schedule_event( timestamp, recurrence, hook, args ); ?>

Funkcja akceptuje następujące parametry:

-   timestamp — godzina, o której ma zostać wykonane dane zadanie;
-   recurrence — częstotliwość, z jaką zadanie ma być ponownie
    uruchamiane;
-   hook — nazwa zaczepu akcji do wywołania;
-   args — argumenty przekazane funkcji zdefiniowanej w zaczepie akcji.

Teraz utworzymy prostą wtyczkę w celu zademonstrowania potężnych
możliwości zadań harmonogramu. Podobnie jak w przypadku większości
wtyczek, powstanie strona oraz opcja menu Ustawienia:

    <?php
    add_action( 'admin_menu', 'boj_cron_menu' );
    function boj_cron_menu() {
        // Utworzenie przykładowej strony ustawień.
        add_options_page( 'Przykład ustawień cron', 'Ustawienia cron',
    'manage_options', 'boj-cron', 'boj_cron_settings' );
    }
    ?> 

W omawianym przykładzie zostanie zdefiniowane zadanie, które będzie
wykonywane, gdy użytkownik po raz pierwszy wyświetli stronę ustawień.
Zadanie harmonogramu można zdefiniować na wiele różnych sposobów, np.
podczas aktywacji wtyczki lub po włączeniu określonej wartości opcji.
Jednak na potrzeby omawianego przykładu strona ustawień będzie
wystarczająca.

Kolejnym krokiem jest utworzenie własnego zaczepu akcji i funkcji
wykonywanej po uruchomieniu zadania przez cron.

    <?php
    add_action('boj_cron_hook', 'boj_cron_email_reminder');
    function boj_cron_email_reminder() {
        // Wysłanie wiadomości e-mail.
        wp_mail( 'ty@przyklad.pl', 'Przypomnienie', 'Tylko nie zasypiaj!' );
    }
    ?> 

Jak możesz zobaczyć, na początek utworzono własny zaczep akcji o nazwie
boj_cron_hook. Po jego wywołaniu nastąpi uruchomienie zdefiniowanej
własnej funkcji o nazwie boj_email_reminder(). Wymieniona funkcja będzie
wykonana po uruchomieniu zadania harmonogramu. W przykładzie
wykorzystano funkcję wp_mail(), której celem jest wysłanie użytkownikowi
wiadomości e-mail.

Kolejnym krokiem jest utworzenie własnej funkcji boj_cron_settings()
odpowiedzialnej za wyświetlenie strony ustawień oraz umieszczenie
zadania w harmonogramie.

    <?php
    function boj_cron_settings() {
        // Upewnienie się, że zadanie nie zostało wcześniej umieszczone w harmonogramie.
        if ( !wp_next_scheduled( 'boj_cron_hook' ) ) {
            // Określenie, że zadanie będzie wywoływane co godzinę.
            wp_schedule_event( time(), 'hourly', 'boj_cron_hook' );
        }
    }
    ?> 

Najpierw użyto funkcji wp_next_scheduled() w celu upewnienia się, że
zadanie nie zostało jeszcze umieszczone w harmonogramie. Wartością
zwrotną funkcji jest znacznik czasu zadania cron, a jeśli zadanie nie
istnieje, funkcja zwraca wartość false.

Po upewnieniu się, że zadanie nie zostało jeszcze umieszczone w
harmonogramie, należy je w tym harmonogramie umiejscowić! Odbywa się to
za pomocą wywołania funkcji wp_schedule_event(). Pierwszym parametrem
jest bieżąca godzina, natomiast drugi parametr określa częstotliwość
ponownego uruchamiania tego zadania. Platforma WordPress domyślnie
stosuje trzy wartości ponownego uruchamiania zadania: hourly (co
godzinę), daily (raz dziennie) oraz twicedaily (dwa razy dziennie). W
omawianym przykładzie zdefiniowano, że zadanie będzie uruchamiane co
godzinę. Ostatnim parametrem jest nazwa zaczepu akcji do wywołania po
uruchomieniu zadania. Tutaj użyto utworzonego wcześniej własnego zaczepu
akcji boj_cron_hook.

W ten sposób udało się utworzyć zadanie harmonogramu na platformie
WordPress! Co godzinę platforma będzie wysyłała wiadomość e-mail
przypominającą o tym, abyś nie zasnął.

Poniżej przedstawiono pełny kod źródłowy wtyczki:

    <?php
    /*
    Plugin Name: Przykładowa wtyczka używająca cron
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka demonstrująca użycie cron na platformie WordPress.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    add_action( 'admin_menu', 'boj_cron_menu' );
    function boj_cron_menu() {
        // Utworzenie przykładowej strony ustawień.
        add_options_page( 'Przykład ustawień cron', 'Ustawienia cron', 'manage_options', 'boj-cron', 'boj_cron_settings' );
    }
    add_action('boj_cron_hook', 'boj_cron_email_reminder');
    function boj_cron_email_reminder() {
        // Wysłanie wiadomości e-mail.
        wp_mail( 'ty@przyklad.pl', 'Przypomnienie', 'Tylko nie zasypiaj!' );
    }
    function boj_cron_settings() {
        // Upewnienie się, że zadanie nie zostało wcześniej umieszczone w harmonogramie.
        if ( !wp_next_scheduled( 'boj_cron_hook' ) ) {
            // Określenie, że zadanie będzie wywoływane co godzinę.
            wp_schedule_event( time(), 'hourly', 'boj_cron_hook' );
        }
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-cron.php.

------------------------------------------------------------------------

Utworzenie jednorazowego zadania harmonogramu

Tworzone zadania harmonogramu najczęściej się powtarzają, ale czasami
trzeba zdefiniować zadanie jednorazowe. Takie zadanie jest uruchamiane
tylko jeden raz i nie będzie wywołane ponownie. Do utworzenia
jednorazowego zadania harmonogramu używana jest funkcja
wp_schedule_single_event():

    <?php wp_schedule_single_event( timestamp, hook, args ); ?> 

Funkcja akceptuje następujące parametry:

-   timestamp — godzina, o której ma zostać wykonane dane zadanie;
-   hook — nazwa zaczepu akcji do wywołania;
-   args — argumenty przekazane funkcji zdefiniowanej w zaczepie akcji.

Teraz przeanalizujemy przykład praktyczny. Podobnie jak wcześniej,
zaczynamy od dodania elementu menu Ustawienia:

    <?php
    // Utworzenie menu wtyczki.
    add_action( 'admin_menu', 'boj_cron_single_menu' );
    function boj_cron_single_menu() {
        // Utworzenie przykładowej strony ustawień.
        add_options_page('Przykład ustawień cron', 'Ustawienia cron',
            'manage_options', 'boj-single-cron', 'boj_cron_single_settings' );
    }
    ?> 

Kolejnym krokiem jest utworzenie strony ustawień, która spowoduje
dodanie pojedynczego zadania do harmonogramu.

    <?php
    function boj_cron_single_settings() {
        // Upewnienie się, że zadanie nie zostało wcześniej umieszczone w harmonogramie.
        if ( !wp_next_scheduled( 'boj_single_cron_hook' ) ) {
            // Określenie, że zadanie będzie wykonane w ciągu godziny.
            wp_schedule_single_event( time()+3600,
                'boj_single_cron_hook' );
        }
    }
    ?> 

Za pomocą funkcji wp_schedule_single_event() zdefiniowano czas wykonania
zadania na time()+3600, czyli na dokładnie jedną godzinę od chwili
dodania zadania do harmonogramu. Drugi parametr — boj_single_cron_hook —
to własny zaczep, który będzie wywołany przez uruchomione zadanie cron.
Pozostało więc utworzenie wspomnianego zaczepu.

    <?php
    // Utworzenie własnego zaczepu wywoływanego przez zadanie harmonogramu.
    add_action( 'boj_single_cron_hook',
        'boj_cron_single_email_reminder' );
    function boj_cron_single_email_reminder () {
        // Wysłanie wiadomości e-mail.
        wp_mail('ty@przyklad.pl', 'Przypomnienie', 'Masz spotkanie!' );
    }
    ?> 

Poniżej przedstawiono pełny kod źródłowy omówionej wtyczki:

    <?php
    /*
    Plugin Name: Jednorazowe zadanie cron
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Utworzenie jednorazowego zadania cron.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    // Utworzenie menu wtyczki.
    add_action( 'admin_menu', 'boj_cron_single_menu' );
    function boj_cron_single_menu() {
        // Utworzenie przykładowej strony ustawień.
        add_options_page( 'Przykład ustawień cron', 'Ustawienia cron', 
        'manage_options', 'boj-single-cron', 'boj_cron_single_settings' );
    }
    // Utworzenie własnego zaczepu wywoływanego przez zadanie harmonogramu.
    add_action( 'boj_single_cron_hook', 'boj_cron_single_email_reminder' );
    function boj_cron_single_email_reminder() {
        // Wysłanie wiadomości e-mail.
        wp_mail( 'ty@przyklad.pl', 'Przypomnienie', 'Masz spotkanie!' );
    }
    function boj_cron_single_settings() {
        // Upewnienie się, że zadanie nie zostało wcześniej umieszczone w harmonogramie.
        if ( !wp_next_scheduled( 'boj_single_cron_hook' ) ) {
            // Określenie, że zadanie będzie wykonane w ciągu godziny.
            wp_schedule_single_event( time()+3600, 'boj_single_cron_hook' );
        }
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-single-event.php.

------------------------------------------------------------------------

------------------------------------------------------------------------

Uwaga

Podczas dodawania jednorazowego zadania cron nie ma potrzeby usuwania go
z harmonogramu. Demon cron uruchamia to zadanie, a następnie po
zakończeniu usuwa je z harmonogramu.

------------------------------------------------------------------------

Usunięcie zadania z harmonogramu

Zadanie cron po dodaniu jest na platformie WordPress przechowywane w
tabeli wp_options. Oznacza to, że zadanie harmonogramu nie zostanie
usunięte w wyniku dezaktywacji wtyczki. Jeżeli wtyczka zostanie
dezaktywowana bez prawidłowego usunięcia zadania z harmonogramu,
platforma WordPress nie będzie mogła uruchamiać tego zadania z powodu
niedostępności kodu wtyczki. Jednak zadanie cron nadal będzie znajdowało
się w harmonogramie, a platforma WordPress wciąż będzie próbowała je
uruchomić w zdefiniowanym czasie.

W celu prawidłowego usunięcia zadania z harmonogramu należy użyć funkcji
wp_unschedule_event():

    <?php wp_unschedule_event( timestamp, hook, args ); ?> 

Funkcja akceptuje następujące parametry:

-   timestamp — godzina kolejnego wykonania danego zadania;
-   hook — nazwa zaczepu akcji do wyrejestrowania;
-   args — argumenty przekazane funkcji zdefiniowanej w zaczepie akcji.

Poniżej przedstawiono przykład usunięcia z harmonogramu wcześniej
dodanych zadań:

    <?php
    // Pobranie godziny kolejnego, zaplanowanego wykonania zadania.
    $timestamp = wp_next_scheduled( 'boj_cron_hook' );
    // Usunięcie własnego zaczepu akcji.
    wp_unschedule_event( $timestamp, 'boj_cron_hook' );
    ?> 

Najpierw użyto funkcji wp_next_scheduled() w celu dokładnego ustalenia
godziny kolejnego, zaplanowanego wykonania zadania harmonogramu. Po
ustaleniu tej godziny można zadanie usunąć za pomocą funkcji
wp_unschedule_event(). Jedyne dwa wymagane parametry wymienionej funkcji
to ustalona godzina oraz nazwa własnego zaczepu powiązanego z usuwanym
zadaniem. Po wywołaniu wymienionej funkcji wskazane zadanie powinno być
usunięte z harmonogramu, a platforma WordPress nie będzie już próbowała
go uruchamiać.

Zdefiniowanie własnych odstępów czasu

Jak już wcześniej wspomniano, platforma WordPress stosuje trzy
częstotliwości ponownego wykonywania zadań harmonogramu: co godzinę, raz
dziennie i dwa razy dziennie. Jednocześnie platforma pozwala na bardzo
łatwe utworzenie własnego odstępu czasu, w którym będzie wykonywane
zadanie harmonogramu. W celu utworzenia własnego odstępu czasu należy
użyć zaczepu filtru cron_schedules. Przedstawiony poniżej fragment kodu
powoduje utworzenie odstępu czasu wynoszącego tydzień.

    <?php
    add_filter( 'cron_schedules', 'boj_cron_add_weekly' );
    function boj_cron_add_weekly( $schedules ) {
        // Utworzenie odstępu czasu wynoszącego tydzień.
        $schedules['weekly'] = array(
            'interval' => 604800,
            'display' => 'Raz w tygodniu'
        );
        return $schedules;
    }
    ?> 

Pierwszym krokiem jest wywołanie funkcji add_filter() w celu wywołania
zaczepu filtru cron_schedules. Filtr będzie wykonywał własną funkcję
boj_cron_add_weekly(). Warto zwrócić uwagę na sposób przekazania własnej
funkcji zmiennej $schedules w postaci parametru funkcji. Zmienna
przechowuje w postaci tablicy WordPress harmonogram wszystkich wywołań
zdarzenia. Aby utworzyć nowy harmonogram, do wspomnianej tablicy trzeba
dodać wartości.

Podczas dodawania wartości do tablicy najpierw trzeba zdefiniować nazwę
danej częstotliwości (tutaj weekly) poprzez wydanie polecenia
$schedules['weekly'] = array(). Następnie trzeba dodać dwie wartości
nowej częstotliwości: odstęp czasu oraz wyświetlaną nazwę. Odstęp czasu
jest wyrażany w sekundach i określa liczbę sekund, które muszą upłynąć,
zanim dane zadanie zostanie uruchomione. W omawianym przykładzie użyto
wartości 604800, co odpowiada liczbie sekund w tygodniu. Natomiast
wyświetlana nazwa to czytelna dla człowieka nazwa nowej częstotliwości.

Ostatnim krokiem podczas tworzenia własnej częstotliwości wykonywania
zdarzenia jest zwrócenie wartości $schedules. Własną częstotliwość po
przygotowaniu można bardzo łatwo wykorzystać podczas definiowania
zadania cron, np. tak:

    <?php wp_schedule_event( time(), 'weekly', 'boj_cron_hook' ); ?> 

Wyświetlenie zadań harmonogramu cron

Podczas pracy z zadaniami cron użyteczne może być wyświetlenie zadań
zdefiniowanych w harmonogramie. Nie ma wbudowanej funkcji wyświetlającej
wszystkie zadania, więc w tym miejscu utworzymy wtyczkę, która będzie
pokazywała wszystkie zadania harmonogramu zdefiniowane na platformie
WordPress.

Pierwszym krokiem jest przygotowanie menu dla strony wtyczki.

    <?php
    add_action( 'admin_menu', 'boj_view_cron_menu' );
    function boj_view_cron_menu() {
        // Utworzenie strony ustawień wtyczki wyświetlającej zadania cron.
        add_options_page( 'Wyświetl zadania cron', 'Wyświetl zadania cron',
            'manage_options', 'boj-view-cron', 'boj_view_cron_settings' );
    }
    ?> 

Drugie zadanie to utworzenie funkcji boj_view_cron_settings()
odpowiedzialnej za wyświetlenie zadań harmonogramu:

    <?php
    function boj_view_cron_settings() {
        $cron = _get_cron_array();
        $schedules = wp_get_schedules();
        $date_format = 'M j, Y @ G:i';

W pierwszym wierszu funkcji zmienna $cron otrzymuje wartość
_get_cron_array(). Wymieniona funkcja przechowuje w tablicy wszystkie
zadania harmonogramu. Następnie zmienna $schedules otrzymuje wartość
wp_get_schedules(). Ta funkcja z kolei przechowuje wszystkie
zarejestrowane opcje częstotliwości dla zadań. Ostatnią zmienną jest
$date_format, która jest wykorzystywana do zdefiniowana używanego
później formatu daty i godziny.

Teraz można przystąpić do utworzenia tabeli wyświetlającej zadania
harmonogramu w miłym dla oka formacie:

    <div class="wrap" id="cron-gui">
    <h2>Zadania harmonogramu</h2>
        
    <table class="widefat fixed">
        <thead>
        <tr>
            <th scope="col">Kolejne uruchomienie zadania (GMT/UTC)</th>
            <th scope="col">Częstotliwość uruchamiania</th>
            <th scope="col">Nazwa zaczepu</th>
        </tr>
        </thead>
        <tbody>

W tabeli będą wyświetlane trzy kolumny danych: Kolejne uruchomienie
zadania, Częstotliwość uruchamiania i Nazwa zaczepu. Poniżej
zaprezentowano najbardziej interesujący fragment kodu, czyli iterację
przez zadania harmonogramu oraz ich wyświetlenie w tabeli:

            <?php foreach ( $cron as $timestamp => $cronhooks ) { ?>
                <?php foreach ( (array) $cronhooks as $hook => $events )
                    { ?>
                    <?php foreach ( (array) $events as $event ) { ?>
                    <tr>
                        <td>
                            <?php echo date_i18n( $date_format,
                                wp_next_scheduled( $hook ) ); ?>
                        </td>
                        <td>
                        <?php 
                        if ( $event[ 'schedule' ] ) {
                            echo $schedules[ $event[ 'schedule' ] ][ 'display' ]; 
                        } else {
                            ?>Jednorazowe<?php
                        }
                        ?>
                        </td>
                        <td><?php echo $hook; ?></td>
                    </tr>
                    <?php } ?>
                <?php } ?>
            <?php } ?>
            </tbody>
        </table>
        </div>
    <?
    }
    ?>

Powyższy kod może wydawać się nieco niezrozumiały, ale naprawdę jest
całkiem prosty. Zadaniem kodu jest przeprowadzenie iteracji przez
zmienną $cron, która przechowuje wartości tablicy z _get_cron_array()
oraz wyodrębnienie z każdego elementu tablicy wymaganych danych.

W celu wyświetlenia godziny kolejnego zaplanowanego uruchomienia zadania
użyto funkcji WordPress o nazwie date_i18n(). Funkcja powoduje konwersję
daty na zlokalizowany format, a bazuje na ustawieniach znacznika czasu.
W omawianym przykładzie znacznik czasu został skonfigurowany wcześniej w
zmiennej $date_format i ma wyświetlać datę w formacie dzień, miesiąc,
rok oraz godzina. Interesująca nas godzina w zdefiniowanym formacie jest
pobierana za pomocą funkcji wp_next_scheduled().

Kolejnym krokiem jest wyświetlenie harmonogramu przechowywanego w
zmiennej $schedules. Jeżeli zadanie jest powtarzane, zostanie podana
także częstotliwość jego uruchamiania. Jeśli natomiast zadanie jest
uruchamiane tylko jednokrotnie, wyświetlona będzie informacja
Jednorazowe. Ostatnie wyświetlane dane to nazwa zaczepu powiązanego z
danym zadaniem.

Po wyświetleniu strony ustawień wtyczki wszystkie zadania harmonogramu
zdefiniowane na platformie WordPress powinny być pokazane w tabeli wraz
z informacjami o dacie i godzinie kolejnego uruchomienia zadania,
częstotliwości jego uruchamiania oraz nazwie zaczepu powiązanego z danym
zadaniem (zobacz rysunek 13.1).

[]

Rysunek 13.1. Wyświetlona na stronie ustawień wtyczki tabela zawierająca
zadania harmonogramu

Poniżej przedstawiono pełny kod źródłowy wtyczki:

    <?php
    /*
    Plugin Name: Wyświetlenie zadań cron
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka demonstrująca użycie cron na platformie WordPress.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    add_action( 'admin_menu', 'boj_view_cron_menu' );
    function boj_view_cron_menu() {
        // Utworzenie strony ustawień wtyczki wyświetlającej zadania cron.
        add_options_page( 'Wyświetl zadania cron', 'Wyświetl zadania cron', 'manage_options', 'boj-view-cron', 'boj_view_cron_settings' );
    }
    function boj_view_cron_settings() {
        $cron = _get_cron_array();
        $schedules = wp_get_schedules();
        $date_format = 'j M Y @ G:i';
        ?>
        <div class="wrap" id="cron-gui">
        <h2>Zadania harmonogramu</h2>
        <table class="widefat fixed">
            <thead>
                <tr>
                    <th scope="col">Kolejne uruchomienie zadania (GMT/UTC)</th>
                    <th scope="col">Częstotliwość uruchamiania</th>
                    <th scope="col">Nazwa zaczepu</th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ( $cron as $timestamp => $cronhooks ) { ?>
                    <?php foreach ( (array) $cronhooks as $hook => $events ) { ?>
                        <?php foreach ( (array) $events as $event ) { ?>
                            <tr>
                                <td>
                                    <?php echo date_i18n( $date_format,
                                        wp_next_scheduled( $hook ) ); ?>
                                </td>
                                <td>
                                    <?php 
                                    if ( $event[ 'schedule' ] ) {
                                        echo $schedules[
                                            $event[ 'schedule' ] ][ 'display' ]; 
                                    } else {
                                        ?>Jednorazowe<?php
                                    }
                                    ?>
                                </td>
                                <td><?php echo $hook; ?></td>
                            </tr>
                        <?php } ?>
                    <?php } ?>
                <?php } ?>
            </tbody>
        </table>
        </div>
    <?
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-view-cron-jobs.php.

------------------------------------------------------------------------

Prawdziwy cron

Jak już wcześniej wspomniano, cron na platformie WordPress to nie jest
"prawdziwy" cron i działa na podstawie żądań wyświetlenia strony, a nie
faktycznych odstępów czasu. Istnieje jednak możliwość włączenia
prawdziwego procesu cron i wyłączenie procesu cron platformy WordPress
działającego na podstawie żądań wyświetlenia strony.

Pierwszym krokiem podczas włączania prawdziwego procesu cron jest
wyłączenie procesu platformy WordPress poprzez umieszczenie w pliku
wp-config.php poniższego wiersza:

    define('DISABLE_WP_CRON', true); 

W ten sposób platforma WordPress nie będzie wczytywała pliku wp-cron.php
w celu znalezienia zadań do wykonania. Po wyłączeniu procesu cron
zaimplementowanego na platformie WordPress trzeba skonfigurować inną
metodę wykonywania zadań cron.

Najczęściej stosowana metoda polega na użyciu polecenia wget w celu
wczytania pliku wp-cron.php. Jeżeli serwer działa w systemie Linux,
wtedy cron jest już zainstalowany, a harmonogram jego zadań można
modyfikować za pomocą polecenia crontab. W serwerze działającym w
systemie Windows można zainstalować polecenie wget i utworzyć zadanie
harmonogramu Windows w celu uruchomienia wget. Polecenie wget działa w
następujący sposób:

    wget http://www.przyklad.pl/wp-cron.php

Kiedy polecenie wget zażąda pliku wp-cron.php, wtedy platforma WordPress
sprawdza wszystkie zadania harmonogramu i uruchamia je, jeśli trzeba.
Konfiguracja prawdziwego procesu cron w serwerze daje gwarancję, że
zadania harmonogramu będą wykonywane dokładnie na czas, bez żadnych
opóźnień.

Przykłady praktyczne

Po poznaniu i zrozumieniu sposobu działania zadań cron, warto zapoznać
się z bardziej zaawansowanymi przykładowymi wtyczkami.

Usuwanie co tydzień wcześniejszych wersji wpisu bloga

Wersje wpisu bloga są umieszczane w bazie danych podczas każdego
zapisania wpisu bloga lub strony. To może bardzo szybko doprowadzić do
nadmiernego zwiększenia wielkości bazy danych, więc od czasu do czasu
należy usuwać wersje wpisów bloga. W omawianym przykładzie utworzymy
wtyczkę definiującą zadanie harmonogramu, które co tydzień będzie
usuwało z bazy danych wszystkie wersje wpisu bloga starsze niż 30 dni.

Na początek trzeba utworzyć własną akcję powiązaną z zadaniem
harmonogramu.

    <?php
    // Utworzenie własnego zaczepu dla zadania harmonogramu.
    add_action( 'boj_del_rev_cron_hook', 'boj_cron_rev_delete' );
    function boj_cron_rev_delete() {
        global $wpdb;
        $sql = " DELETE a,b,c
            FROM $wpdb->posts a
            LEFT JOIN $wpdb->term_relationships b ON (a.ID = b.object_id)
            LEFT JOIN $wpdb->postmeta c ON (a.ID = c.post_id)
            WHERE a.post_type = 'revision'
            AND DATEDIFF( now(), a.post_modified )  >  30 ";
        // Wykonanie zapytania i usunięcie wszystkich starych wersji bloga oraz powiązanych z nimi metadanych.
        $wpdb->query( $wpdb->prepare( $sql ) );
    }
    ?> 

Zaczep akcji boj_del_rev_cron_hook wywołuje własną funkcję o nazwie
boj_cron_rev_delete(). Najpierw trzeba zdefiniować $wpdb jako zmienną
globalną, aby klasa wpdb była dostępna do użycia podczas interakcji z
bazą danych WordPress. Następnie generowane jest zapytanie, które
powoduje usunięcie wszystkich wersji wpisu bloga starszych niż 30 dni.

Zmienna $sql przechowuje zapytanie przeznaczone do wykonania. Jak widać,
wspomniane zapytanie łączy dane z tabeli posts z danymi z tabel
term_relationships i postmeta. W ten sposób jest zagwarantowane
usunięcie nie tylko wersji wpisu bloga, ale również wszystkich
przechowywanych dla nich metadanych.

Na końcu przygotowane zapytanie jest wykonane za pomocą funkcji
wpdb_query() i prepare(). Funkcja prepare() jest jedną z najważniejszych
funkcji klasy wpdb. Odpowiada za oczyszczenie zmiennych przekazywanych
do zapytań SQL. Wprawdzie zapytanie w tej wtyczce nie posiada zmiennych
definiowanych przez użytkownika, ale najlepszą praktyką jest, aby
podczas wykonywania zapytań do bazy danych zawsze stosować polecenie
prepare().

Po przygotowaniu funkcji odpowiedzialnej za usunięcie starych wersji
wpisu bloga można dodać ustawienie włączające zadanie harmonogramu.
Wtyczka ta wykorzystuje API Settings (omówione w rozdziale 7.) w celu
dodania pojedynczej opcji na stronie Ogólne ustawień platformy
WordPress.

    <?php
    add_action( 'admin_init', 'boj_cron_rev_admin_init' );
    function boj_cron_rev_admin_init(){
        // Rejestracja opcji za pomocą API Settings.
        register_setting(
            'general',
            'boj_cron_rev_options'
        );
        // Rejestracja pola za pomocą API  Settings.
        add_settings_field(
            'boj_cron_rev_field',
            'Usunąć co tydzień starsze wersje wpisów bloga?',
            'boj_cron_rev_setting_input',
            'general',
            'default'
        );
        // Wczytanie wartości opcji.
        $options = get_option( 'boj_cron_rev_options' );
        $boj_del_rev = $options['boj_del_rev'];
        // Jeżeli opcja jest włączona, ale nie zdefiniowano zadania
        // harmonogramu, teraz trzeba dodać odpowiednie zadanie.
        if ( $boj_del_rev == 'on'  && 
            !wp_next_scheduled( 'boj_del_rev_cron_hook' ) ) {
            // Zadanie będzie wykonywane co godzinę.
            wp_schedule_event( time(), 'weekly',
                'boj_del_rev_cron_hook' );
        // Jeżeli opcja NIE jest włączona i zdefiniowano zadanie, trzeba je usunąć z harmonogramu.
        } elseif ( $boj_del_rev != 'on'  && 
            wp_next_scheduled( 'boj_del_rev_cron_hook' ) ) {
            // Pobranie godziny następnego uruchomienia zadania.
            $timestamp = wp_next_scheduled( 'boj_del_rev_cron_hook' );
            // Wyrejestrowanie własnego zaczepu akcji.
            wp_unschedule_event( $timestamp, 'boj_del_rev_cron_hook' );
        }
    }
    ?> 

W zaczepie akcji admin_init następuje wywołanie własnej funkcji
boj_cron_admin_init(). W celu rejestracji opcji wtyczki używane są
funkcje register_setting() i add_settings_field() pochodzące z API
Settings. Kod powoduje zarejestrowanie opcji boj_cron_rev_options. Opcja
ta to miejsce, w którym wtyczka będzie przechowywać jedynie wartość
opcji wskazującą, czy włączono zadanie harmonogramu. Dodanie pola
ustawień powoduje wywołanie funkcji boj_cron_ rev_setting_input().

Druga część powyższego kodu jest odpowiedzialna za określenie, czy opcja
wtyczki została włączona. Wartość opcji jest wczytywana za pomocą
funkcji get_option() i przechowywana w zmiennej $boj_del_rev. Jeżeli
opcja jest włączona, następuje sprawdzenie, czy zadanie jest
zdefiniowane w harmonogramie. Jeżeli nie, następuje dodanie do
harmonogramu odpowiedniego zadania. Jeśli opcja jest wyłączona, kod
sprawdza, czy zadanie zostało usunięte z harmonogramu i usuwa je, kiedy
trzeba.

Kolejnym krokiem jest utworzenie funkcji boj_cron_rev_setting_input()
wyświetlającej pole wyboru opcji.

    <?php
    function boj_cron_rev_setting_input() {
        // Wczytanie z bazy danych opcji 'boj_del_rev'.
        $options = get_option( 'boj_cron_rev_options' );
        $boj_del_rev = $options['boj_del_rev'];
        // Wyświetlenie pola wyboru opcji.
        echo "<input id='boj_del_rev' name='boj_cron_rev_options[boj_del_rev]'
            type='checkbox' ". checked( $boj_del_rev, 'on', false ). " />";
    }
    ?> 

Podobnie jak wcześniej, wartość opcji jest wczytywana za pomocą funkcji
get_option(). Będzie ona użyta w celu określenia, czy pole wyboru opcji
zostało zaznaczone. Następne kod HTML wyświetla samo pole wyboru opcji.
Kolejnym krokiem jest porównanie wartości zmiennej $boj_del_dev z 'on'.
Jeżeli będą identyczne, opcja zostanie włączona i pole opcji powinno być
zaznaczone. Wspomniane pole opcji jest wyświetlane na stronie Ogólne
ustawień platformy WordPress (zobacz rysunek 13.2).

Ostatni fragment kodu jest odpowiedzialny za utworzenie filtru, który
powoduje uruchomienie zadania harmonogramu raz w tygodniu. W ten sposób
wtyczka co tydzień będzie usuwała stare wersje wpisów bloga.

    <?php
    // Uruchamianie zadania raz w tygodniu.
    add_filter( 'cron_schedules', 'boj_cron_add_weekly' );
    function boj_cron_add_weekly( $schedules ) {
        // Utworzenie częstotliwości 'weekly', czyli raz w tygodniu.
        $schedules['weekly'] = array(
            'interval' => 604800,
            'display' => 'Raz w tygodniu'
        );

[]

Rysunek 13.2. Pole opcji wyświetlane przez wtyczkę na stronie ustawień
platformy WordPress

        return $schedules;
    }
    ?> 

Zadanie harmonogramu będzie uruchamiane raz w tygodniu. To już wszystko!
W ten sposób zbudowałeś w pełni funkcjonalną wtyczkę, która raz w
tygodniu automatycznie usuwa wszystkie wersje wpisów bloga starsze niż
30 dni. Poniżej przedstawiono pełny kod źródłowy wtyczki:

    <?php
    /*
    Plugin Name: Usunięcie wersji wpisów bloga 
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka demonstrująca użycie cron na platformie WordPress.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    // Utworzenie własnego zaczepu dla zadania harmonogramu.
    add_action('boj_del_rev_cron_hook', 'boj_cron_rev_delete');
    function boj_cron_rev_delete() {
        global $wpdb;
        $sql = "DELETE a,b,c  
            FROM $wpdb->posts a  
            LEFT JOIN $wpdb->term_relationships b ON (a.ID = b.object_id)  
            LEFT JOIN $wpdb->postmeta c ON (a.ID = c.post_id)  
            WHERE a.post_type = 'revision' 
            AND DATEDIFF( now(), a.post_modified ) > 30 ";
        // Wykonanie zapytania i usunięcie wszystkich starych wersji bloga oraz powiązanych z nimi 
                   // metadanych.
        $wpdb->query( $wpdb->prepare( $sql ) );
    }
    add_action('admin_init', 'boj_cron_rev_admin_init');
    function boj_cron_rev_admin_init(){
        // Rejestracja opcji za pomocą API Settings.
        register_setting(
            'general', 
            'boj_cron_rev_options' 
        );
        // Rejestracja pola za pomocą API Settings.
        add_settings_field(
            'boj_cron_rev_field',
            'Usunąć co tydzień starsze wersje wpisów bloga?',
            'boj_cron_rev_setting_input',
            'general',
            'default'
        );
        // Wczytanie wartości opcji.
        $options = get_option( 'boj_cron_rev_options' );
        $boj_del_rev = $options['boj_del_rev'];
        // Jeżeli opcja jest włączona, ale nie zdefiniowano zadania harmonogramu, to teraz trzeba dodać odpowiednie  zadanie.
        if ( $boj_del_rev == 'on' && !wp_next_scheduled( 'boj_del_rev_cron_hook' ) ) {
            // Zadanie będzie wykonywane co godzinę.
            wp_schedule_event( time(), 'weekly', 'boj_del_rev_cron_hook' );
        // Jeżeli opcja NIE jest włączona i zdefiniowano zadanie, trzeba je usunąć z harmonogramu.
        } elseif ( $boj_del_rev != 'on' && wp_next_scheduled( 
        'boj_del_rev_cron_hook' ) ) {
            // Pobranie godziny następnego uruchomienia zadania.
            $timestamp = wp_next_scheduled( 'boj_del_rev_cron_hook' );
            // Wyrejestrowanie własnego zaczepu akcji.
            wp_unschedule_event( $timestamp, 'boj_del_rev_cron_hook' );
        }
    }
    function boj_cron_rev_setting_input() {
        // Wczytanie z bazy danych opcji 'boj_del_rev'.
        $options = get_option( 'boj_cron_rev_options' );
        $boj_del_rev = $options['boj_del_rev'];
        // Wyświetlenie pola wyboru opcji.
        echo "<input id='boj_del_rev' name='boj_cron_rev_options[boj_del_rev]' 
            type='checkbox' ". checked( $boj_del_rev, 'on', false ). " />";
    }
    // Uruchamianie zadania raz w tygodniu.
    add_filter( 'cron_schedules', 'boj_cron_add_weekly' ); 
    function boj_cron_add_weekly( $schedules ) {
        // Utworzenie częstotliwości 'weekly', czyli raz w tygodniu.
        $schedules['weekly'] = array(
            'interval' => 604800,
            'display' => 'Raz w tygodniu'
        );
        return $schedules;
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-delete-rev-cron.php.

------------------------------------------------------------------------

Wtyczka automatycznie wysyłająca wiadomość e-mail

Teraz utworzymy wtyczkę automatycznie wysyłającą wiadomość e-mail, gdy w
przeciągu ostatnich trzech dni nie zostanie opublikowany żaden wpis
bloga. Tego rodzaju wtyczka może działać w charakterze przypomnienia o
potrzebie utworzenia nowego wpisu bloga.

Na początek trzeba utworzyć własny zaczep akcji oraz wywoływaną przez
niego funkcję:

    <?php
    // Utworzenie własnego zaczepu powiązanego z harmonogramem cron.
    add_action( 'boj_pester_cron_hook', 'boj_cron_pester_check' );
    function boj_cron_pester_check() {
        global $wpdb;
        // Ustalenie daty ostatnio opublikowanego wpisu bloga.
        $sql = " SELECT post_date FROM $wpdb->posts
            WHERE post_status = 'publish' AND post_type = 'post'
            ORDER BY post_date DESC LIMIT 1 ";
        $latest_post_date = $wpdb->get_var( $wpdb->prepare( $sql ) );
        if ( strtotime( $latest_post_date )  <= strtotime('-3 day') ) {
            // Wpis bloga jest starszy niż trzy dni.
            // Podanie informacji niezbędnych do wysłania wiadomości e-mail.
            $email_to = 'ty@przyklad.pl';
            $email_subject = 'Przypomnienie';
            $email_msg = 'Co się dzieje z blogiem? Minęły już co najmniej
                trzy dni, odkąd opublikowałeś ostatni wpis bloga.';
            // Wysłanie wiadomości e-mail.
            wp_mail( $email_to, $email_subject, $email_msg );
        }
    }
    ?> 

Funkcja boj_cron_pester_check() jest wykonywana przez cron i może
ustalić datę publikacji ostatniego wpisu bloga. Za pomocą funkcji
get_var() i prepare() klasy wpdb jest wykonywane własne zapytanie,
którego wartością zwrotną jest data publikacji ostatniego wpisu bloga.

Porównanie dat odbywa się za pomocą funkcji PHP o nazwie strtotime().
Wymieniona funkcja pobiera datę i zwraca znacznik czasu systemu UNIX. W
ten sposób można bardzo łatwo porównywać dwie daty, ponieważ są one w
tym samym formacie. W powyższym fragmencie kodu zmienna
$latest_post_date jest porównywana ze znacznikiem czasu systemu UNIX
sprzed trzech dni (-3 day). Jeżeli data publikacji ostatniego wpisu
bloga jest większa bądź równa wartości -3 day, wpis bloga powstał ponad
trzy dni temu. Ostatnim krokiem jest przygotowanie zmiennych niezbędnych
do wysłania wiadomości e-mail oraz jej wysłanie za pomocą funkcji
wp_mail().

Kolejny krok to utworzenie funkcji admin_init w celu rejestracji opcji
wtyczki oraz zdefiniowania zadania harmonogramu cron.

    <?php
    add_action( 'admin_init', 'boj_cron_pester_init' );
    function boj_cron_pester_init(){
        // Rejestracja opcji za pomocą API Settings.
        register_setting(
            'writing',
            'boj_cron_pester_options'
        );
        // Rejestracja pola za pomocą API Settings.
        add_settings_field(
            'boj_cron_pester_field',
            'Włączyć przypomnienie o potrzebie utworzenia nowego wpisu bloga?',
            'boj_cron_pester_setting',
            'writing',
            'default'
        );
        // Wczytanie wartości opcji.
        $options = get_option( 'boj_cron_pester_options' );
        $boj_pester = $options['boj_pester'];
        // Jeżeli opcja jest włączona, ale nie zdefiniowano zadania harmonogramu, to teraz trzeba dodać odpowiednie  zadanie.
        if ( $boj_pester == 'on' && 
            !wp_next_scheduled( 'boj_pester_cron_hook' ) ) {
            // Zadanie będzie wykonywane co godzinę.
            wp_schedule_event( time(), 'daily', 'boj_pester_cron_hook' );
        // Jeżeli opcja NIE jest włączona i zdefiniowano zadanie, trzeba je usunąć z harmonogramu.
        } elseif ( $boj_pester != 'on' && 
            wp_next_scheduled( 'boj_pester_cron_hook' ) ) {
            // Pobranie godziny następnego uruchomienia zadania.
            $timestamp = wp_next_scheduled( 'boj_pester_cron_hook' );
            // Wyrejestrowanie własnego zaczepu akcji.
            wp_unschedule_event( $timestamp, 'boj_pester_cron_hook' );
        }
    }
    ?> 

Jak pokazano na rysunku 13.3, wtyczka za pomocą API Settings powoduje
dodanie opcji na stronie Ustawienia pisania (menu Ustawienia/Pisanie).
Włączenie opcji powoduje zdefiniowanie zadania cron uruchamianego raz
dziennie. Oznacza to, że jeśli w ciągu ostatnich trzech dni nie został
opublikowany żaden wpis bloga, wtyczka wyśle wiadomość e-mail z
odpowiednim przypomnieniem. Wiadomość będzie wysyłana aż do dnia
opublikowania nowego wpisu bloga.

[]

Rysunek 13.3. Opcja na stronie Ustawienia pisania dodana przez budowaną
tutaj wtyczkę

Ostatnim krokiem podczas budowy tej wtyczki jest utworzenie pola
formularza przycisku opcji powodującego włączenie lub wyłączenie
wysłania wiadomości e-mail.

    <?php
    function boj_cron_pester_setting() {
        // Wczytanie z bazy danych opcji 'boj_pester'.
        $options = get_option( 'boj_cron_pester_options' );
        $boj_pester = $options['boj_pester'];
        // Wyświetlenie pola wyboru opcji.
        echo "<input id='boj_pester'
            name='boj_cron_pester_options[boj_pester]'
            type='checkbox' ". checked( $boj_pester, 'on', false ). " />";
    }
    ?> 

Podobnie jak wcześniej, do pobrania wartości opcji została użyta funkcja
get_option(). Ponadto w celu ustalenia, czy opcja jest włączona,
wykorzystano funkcję checked().

Poniżej przedstawiono pełny kod źródłowy wtyczki.

    <?php
    /*
    Plugin Name: Wtyczka automatycznie wysyłająca wiadomość e-mail
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wysyła wiadomość e-mail, jeśli przez trzy dni nie został opublikowany żaden wpis bloga.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    // Utworzenie własnego zaczepu powiązanego z harmonogramem cron.
    add_action( 'boj_pester_cron_hook', 'boj_cron_pester_check' );
    function boj_cron_pester_check() {
        global $wpdb;
        // Ustalenie daty ostatnio opublikowanego wpisu bloga.
        $sql = " SELECT post_date FROM $wpdb->posts
            WHERE post_status = 'publish' AND post_type = 'post'
            ORDER BY post_date DESC LIMIT 1 ";
        $latest_post_date = $wpdb->get_var( $wpdb->prepare( $sql ) );
       
        if ( strtotime( $latest_post_date )  <= strtotime('-3 day') ) {
            // Wpis bloga jest starszy niż trzy dni.
            // Podanie informacji niezbędnych do wysłania wiadomości e-mail.
            $email_to = 'ty@przyklad.pl';
            $email_subject = 'Przypomnienie';
            $email_msg = 'Co się dzieje z blogiem? Minęły już co najmniej
                trzy dni, odkąd opublikowałeś ostatni wpis bloga.';
            // Wysłanie wiadomości e-mail.
            wp_mail( $email_to, $email_subject, $email_msg );
        }
    }
    add_action( 'admin_init', 'boj_cron_pester_init' );
    function boj_cron_pester_init(){
        // Rejestracja opcji za pomocą API Settings.
        register_setting(
            'writing',
            'boj_cron_pester_options'
        );
        // Rejestracja pola za pomocą API Settings.
        add_settings_field(
            'boj_cron_pester_field',
            'Włączyć przypomnienie o potrzebie utworzenia nowego wpisu bloga?',
            'boj_cron_pester_setting',
            'writing',
            'default'
        );
        // Wczytanie wartości opcji.
        $options = get_option( 'boj_cron_pester_options' );
        $boj_pester = $options['boj_pester'];
        // Jeżeli opcja jest włączona, ale nie zdefiniowano zadania harmonogramu, to teraz trzeba dodać 
                   // odpowiednie  zadanie.
        if ( $boj_pester == 'on' && 
            !wp_next_scheduled( 'boj_pester_cron_hook' ) ) {
            // Zadanie będzie wykonywane co godzinę.
            wp_schedule_event( time(), 'daily', 'boj_pester_cron_hook' );
        // Jeżeli opcja NIE jest włączona i zdefiniowano zadanie, trzeba je usunąć z harmonogramu.
        } elseif ( $boj_pester != 'on' && 
            wp_next_scheduled( 'boj_pester_cron_hook' ) ) {
            // Pobranie godziny następnego uruchomienia zadania.
            $timestamp = wp_next_scheduled( 'boj_pester_cron_hook' );
            // Wyrejestrowanie własnego zaczepu akcji.
            wp_unschedule_event( $timestamp, 'boj_pester_cron_hook' );
        }
    }
    function boj_cron_pester_setting() {
        // Wczytanie z bazy danych opcji 'boj_pester'.
        $options = get_option( 'boj_cron_pester_options' );
        $boj_pester = $options['boj_pester'];
        // Wyświetlenie pola wyboru opcji.
        echo "<input id='boj_pester'
            name='boj_cron_pester_options[boj_pester]'
            type='checkbox' ". checked( $boj_pester, 'on', false ). " />";
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-blog-pester.php.

------------------------------------------------------------------------

Wtyczka usuwająca komentarze

Ostatnim przykładem jest wtyczka z wieloma opcjami, która będzie używała
harmonogram cron. Zadaniem wtyczki jest usunięcie komentarzy określonych
jako spam oraz innych przeznaczonych do usunięcia, które są starsze niż
zdefiniowana liczba dni. Przykładowo użytkownik będzie mógł usunąć
komentarze przeznaczone do usunięcia i określone jako spam, które są
starsze niż 15 dni.

Pierwszym krokiem jest zarejestrowanie funkcji dla zaczepu akcji
admin_init oraz zdefiniowanie zadania harmonogramu cron.

    <?php
    add_action( 'admin_init', 'boj_cron_comment_init' );
    function boj_cron_comment_init(){
        // Rejestracja opcji za pomocą API Settings.
        register_setting(
            'discussion',
            'boj_cron_comment_options'
        );
        // Rejestracja pola wyboru za pomocą API Settings.
        add_settings_field(
            'boj_cron_comment_type_field',
            'Wybierz komentarze do usunięcia',
            'boj_cron_comment_type',
            'discussion',
            'default'
        );
        // Rejestracja pola tekstowego za pomocą API Settings.
        add_settings_field(
            'boj_cron_days_old_field',
            'Usuń komentarze starsze niż',
            'boj_cron_days_old',
            'discussion',
            'default'
        );
        // Wczytanie wartości opcji.
        $options = get_option( 'boj_cron_comment_options' );
        $boj_comments = $options['boj_comments'];
        // Jeżeli opcja jest włączona, ale nie zdefiniowano zadania harmonogramu, to teraz trzeba dodać 
                    // odpowiednie zadanie.
        if ( $boj_comments  && 
            !wp_next_scheduled( 'boj_comment_cron_hook' ) ) {
            // Zadanie będzie wykonywane co godzinę.
            wp_schedule_event( time(), 'daily',
                'boj_comment_cron_hook' );
        // Jeżeli opcja NIE jest włączona i zdefiniowano zadanie, trzeba je usunąć z harmonogramu.
        } elseif ( !$boj_comments  && 
            wp_next_scheduled( 'boj_comment_cron_hook' ) ) {
            // Pobranie godziny następnego uruchomienia zadania.
            $timestamp = wp_next_scheduled( 'boj_comment_cron_hook' );
            // Wyrejestrowanie własnego zaczepu akcji.
            wp_unschedule_event( $timestamp, 'boj_comment_cron_hook' );
        }
    }
    ?> 

Jak pokazano na rysunku 13.4, wtyczka powoduje dodanie dwóch pól
ustawień na stronie Ustawienia dyskusji platformy WordPress (menu
Ustawienia/Dyskusje). Pierwsza opcja pozwala na wybór typu komentarzy
przeznaczonych do usunięcia. Natomiast druga umożliwia określenie liczby
dni, które muszą upłynąć od wystawienia danego komentarza, aby można
było go usunąć.

Teraz trzeba utworzyć dwa pola formularza zarejestrowane w poprzedniej
funkcji.

[]

Rysunek 13.4. Opcje na stronie Ustawienia dyskusji dodane przez budowaną
tutaj wtyczkę

    <?php
    function boj_cron_comment_type() {
    // Wczytanie z bazy danych opcji 'boj_comments'.
        $options = get_option( 'boj_cron_comment_options' );
        $boj_comments = $options['boj_comments'];
        // Wyświetlenie pola opcji wyboru.
        echo '<select name="boj_cron_comment_options[boj_comments]">';
            echo '<option value="" '. selected( $boj_comments, '', false ) '>brak</option>';
            echo '<option value="spam" '. selected( $boj_comments, 'spam', false )
                '>określone jako spam</option>';
            echo '<option value="moderated" '. selected( $boj_comments, 'moderated', false ) 
                '>inne przeznaczone do usunięcia</option>';
            echo '<option value="both" '. selected( $boj_comments, 'both', false ) 
                '>określone jako spam i inne przeznaczone do usunięcia</option>';
        echo '</select>';
    }
    ?> 

Pierwsze pole pozwala na wybór opcji. Za pomocą funkcji compare()
następuje porównanie opcji zapisanej na platformie WordPress z bieżącą
wartością opcji. Jeżeli są identyczne, dana opcja będzie wybrana. Drugie
pole to zwykłe pole tekstowe.

    <?php
    function boj_cron_days_old() {
        // Wczytanie z bazy danych opcji 'boj_days_old'.
        $options = get_option( 'boj_cron_comment_options' );
        $boj_days_old = ( $options['boj_days_old'] ) ?
            absint( $options['boj_days_old'] ) : 30;
        // Wyświetlenie pola tekstowego opcji.
        echo '<input type="text"
            name="boj_cron_comment_options[boj_days_old]"
            value="' .esc_attr( $boj_days_old ). '" size="3" /> dni';
    }
    ?> 

Do ustawienia wartości zmiennej $boj_days_old używany jest operator
trójargumentowy PHP. Jeżeli wartość istnieje, zostanie użyta. Jeśli
natomiast wartość jeszcze nie istnieje (tzn. wtyczka została dopiero
zainstalowana), wtedy będzie użyta wartość domyślna, czyli 30.

Po przygotowaniu wszystkich ustawień trzeba utworzyć powiązaną z
zaczepem akcji własną funkcję odpowiedzialną za usuwanie komentarzy.

    <?php
    // Utworzenie własnego zaczepu powiązanego z harmonogramem cron.
    add_action( 'boj_comment_cron_hook', 'boj_cron_delete_comments' );
    function boj_cron_delete_comments() {
        global $wpdb;
        $options = get_option( 'boj_cron_comment_options' );
        $boj_comments = $options['boj_comments'];
        $boj_days_old = ( $options['boj_days_old'] ) ?
            $options['boj_days_old'] : 30;
        // Potwierdzenie włączenia opcji.
        if ( $boj_comments ) {
            if ( $boj_comments == "spam" ) {
                $boj_comment_status = 'spam';
            } elseif ( $boj_comments == "moderated" ) {
                $boj_comment_status = '0';
            }
            $sql = " DELETE FROM $wpdb->comments
                WHERE ( comment_approved = '$boj_comment_status' )
                AND DATEDIFF( now(), comment_date ) > %d";
            if ( $boj_comments == "both" ) {
                $sql = " DELETE FROM $wpdb->comments
                    WHERE ( comment_approved = 'spam'
                        OR comment_approved = '0'  )
                    AND DATEDIFF( now(), comment_date ) > %d";
            }
            $wpdb->query( $wpdb->prepare( $sql, $boj_days_old ) );
        }
    }
    ?> 

Najpierw wtyczka wczytuje wartości obu opcji i umieszcza je w dwóch
zmiennych $boj_comments i $boj_days_old. Jeżeli zmienna $boj_comments ma
wartość, wtedy wiadomo, że została ustawiona przez użytkownika.
Następnie trzeba przygotować zapytanie odpowiedzialne za usunięcie
komentarzy na podstawie ustawień zdefiniowanych przez użytkownika.
Zapytanie korzysta również z funkcji DATEDIFF bazy danych MySQL
odpowiedzialnej za sprawdzenie, czy komentarz jest starszy niż wskazana
przez użytkownika liczba dni. Zapytanie po przygotowaniu jest wykonywane
przez funkcje query() i prepare() klasy wpdb.

Po skonfigurowaniu można łatwo określić komentarze do przeznaczone do
usunięcia oraz liczbę dni, które musiały upłynąć od ich wystawienia,
zanim będą mogły zostać usunięte. Zadanie harmonogramu cron będzie
uruchamiane raz dziennie i sprawdzi, czy są jakiekolwiek komentarze do
usunięcia.

Poniżej przedstawiono pełny kod źródłowy wtyczki.

    <?php
    /*
    Plugin Name: Usuwanie komentarzy zgodnie z harmonogramem
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Usuwa komentarze określone jako spam oraz inne przeznaczone do usunięcia, które są starsze niż wskazana liczba dni.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    // Utworzenie własnego zaczepu powiązanego z harmonogramem cron.
    add_action( 'boj_comment_cron_hook', 'boj_cron_delete_comments' );
    function boj_cron_delete_comments() {
        global $wpdb;
        $options = get_option( 'boj_cron_comment_options' );
        $boj_comments = $options['boj_comments'];
        $boj_days_old = ( $options['boj_days_old'] ) ?
            absint( $options['boj_days_old'] ) : 30;
        // Potwierdzenie włączenia opcji.
        if ( $boj_comments ) {
            if ( $boj_comments == "spam" ) {
                $boj_comment_status = 'spam';
            } elseif ( $boj_comments == "moderated" ) {
                $boj_comment_status = '0';
            }
            $sql = " DELETE FROM $wpdb->comments
                WHERE ( comment_approved = '$boj_comment_status' )
                AND DATEDIFF( now(), comment_date ) > %d";
            if ( $boj_comments == "both" ) {
                $sql = " DELETE FROM $wpdb->comments
                    WHERE ( comment_approved = 'spam'
                        OR comment_approved = '0'  )
                    AND DATEDIFF( now(), comment_date ) > %d";
            }
            $wpdb->query( $wpdb->prepare( $sql, $boj_days_old ) );
        }
    }
    add_action( 'admin_init', 'boj_cron_comment_init' );
    function boj_cron_comment_init(){
        // Rejestracja opcji za pomocą API Settings.
        register_setting(
            'discussion',
            'boj_cron_comment_options'
        );
        // Rejestracja pola wyboru za pomocą API Settings.
        add_settings_field(
            'boj_cron_comment_type_field',
            'Wybierz komentarze do usunięcia',
            'boj_cron_comment_type',
            'discussion',
            'default'
        );
        // Rejestracja pola tekstowego za pomocą API Settings.
        add_settings_field(
            'boj_cron_days_old_field',
            'Usuń komentarze starsze niż',
            'boj_cron_days_old',
            'discussion',
            'default'
        );
        // Wczytanie wartości opcji.
        $options = get_option( 'boj_cron_comment_options' );
        $boj_comments = $options['boj_comments'];
        // Jeżeli opcja jest włączona, ale nie zdefiniowano zadania harmonogramu, to teraz trzeba 
        // dodać odpowiednie zadanie.
        if ( $boj_comments  && 
            !wp_next_scheduled( 'boj_comment_cron_hook' ) ) {
            // Zadanie będzie wykonywane co godzinę.
            wp_schedule_event( time(), 'daily',
                'boj_comment_cron_hook' );
        // Jeżeli opcja NIE jest włączona i zdefiniowano zadanie, trzeba je usunąć z harmonogramu.
        } elseif ( !$boj_comments  && 
            wp_next_scheduled( 'boj_comment_cron_hook' ) ) {
            // Pobranie godziny następnego uruchomienia zadania.
            $timestamp = wp_next_scheduled( 'boj_comment_cron_hook' );
            // Wyrejestrowanie własnego zaczepu akcji.
            wp_unschedule_event( $timestamp, 'boj_comment_cron_hook' );
        }
    }
    function boj_cron_comment_type() {
        // Wczytanie z bazy danych opcji 'boj_comments'.
        $options = get_option( 'boj_cron_comment_options' );
        $boj_comments = $options['boj_comments'];
        // Wyświetlenie pola opcji wyboru.
        echo '<select name="boj_cron_comment_options[boj_comments]">';
            echo '<option value="" '. selected( $boj_comments, '', false ) '>brak</option>';
            echo '<option value="spam" '. selected( $boj_comments, 'spam', false )
                '>określone jako spam</option>';
            echo '<option value="moderated" '. selected( $boj_comments, 
            'moderated', false ) 
                '>inne przeznaczone do usunięcia</option>';
            echo '<option value="both" '. selected( $boj_comments, 'both', false ) 
                '>określone jako spam i inne przeznaczone do usunięcia</option>';
        echo '</select>';
    }
    function boj_cron_days_old() {
        // Wczytanie z bazy danych opcji 'boj_days_old'.
        $options = get_option( 'boj_cron_comment_options' );
        $boj_days_old = ( $options['boj_days_old'] ) ?
            absint( $options['boj_days_old'] ) : 30;
        // Wyświetlenie pola tekstowego opcji.
        echo '<input type="text"
            name="boj_cron_comment_options[boj_days_old]"
            value="' .esc_attr( $boj_days_old ). '" size="3" /> dni';
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-delete-comments.php.

------------------------------------------------------------------------

Podsumowanie

Mechanizm cron to potężne narzędzie, które przed twórcą wtyczek otwiera
interesujące możliwości. Po zrozumieniu sposobu działania procesu cron
oraz poznaniu tajników optymalizacji jego pracy w tworzonych wtyczkach
można zaimplementować funkcje zaawansowane, dzięki którym wtyczki
wzniosą się na kolejny poziom!

Rozdział 14 API Rewrite

W tym rozdziale:

-   Zrozumienie koncepcji zmiany adresów URL
-   Utworzenie reguł Rewrite we wtyczkach
-   Opracowanie zupełnie nowej struktury odnośników bezpośrednich
-   Integracja strony innej niż WordPress z tym samym układem adresu URL
-   Generowanie własnych kanałów wiadomości

API Rewrite jest bardzo często uznawane na najtrudniejsze na platformie
WordPress. Faktycznie, API to jest jednym z najsłabiej udokumentowanych
w internecie. W rozdziale zostaną przedstawione podstawowe informacje
dotyczące powodów zmiany adresów URL. Następnie dowiesz się, jak to
zadanie można wykonać na platformie WordPress. Na końcu zostaną
zaprezentowane rzeczywiste sytuacje, w których można wykorzystać zalety
API Rewrite.

Dlaczego czasem trzeba zmieniać adresy URL?

Witryny dynamiczne używają adresów URL generujących treść na podstawie
parametrów ciągu tekstowego zapytania. Wspomniane adresy URL są często
zmieniane na postać adresów URL statycznych stron witryny internetowej z
zastosowaniem hierarchii podkatalogów. Przykładowo rzeczywisty adres URL
strony wiki może być następujący
http://przyklad.pl/index.php?title=Rewrite_URL, ale po zmianie będzie
miał postać http://przyklad.pl/Rewrite_URL. Wykonanie żądania do
drugiego z tych adresów (łatwiejszego do zapamiętania) spowoduje, że
serwer WWW zmieni je na pierwszy, rzeczywisty adres URL.

W pierwszym punkcie rozdziału postaramy się przybliżyć koncepcję
"eleganckich odnośników bezpośrednich" (czasami w aplikacjach sieciowych
nazywanych "wymyślnymi adresami URL") oraz omówić ogólnie zmiany adresów
URL, zwłaszcza na platformie WordPress.

Zasady dotyczące odnośników bezpośrednich

Aplikacje sieciowe oraz witryny internetowe mają dwie zupełnie odmienne
rzesze odbiorców: czytelników (ludzi) i silniki wyszukiwarek
internetowych. Zasoby internetowe powinny być przyjazne zarówno dla
człowieka, jak i silnika wyszukiwarki internetowej.

Przyjazny dla silnika wyszukiwarki internetowej

Załóżmy, że opracowałeś dla klienta kompletny sklep internetowy wraz z
różnymi produktami i kategoriami. Z perspektywy programisty każdy adres
URL witryny będzie podobny do następującego:
http://przyklad.pl/sklep.php?​action=display&category=12&subcat=4. Ten
adres bardzo łatwo mapuje zmienne, które zwykle dostarczają informacji
pochodzących z bazy danych lub służących do przeprowadzenia pewnych
operacji.

Problem polega na tym, że przedstawiony adres URL może być zindeksowany
przez silnik wyszukiwarki internetowej jedynie w postaci
http://przyklad.pl/sklep.php, która nie dostarcza wystarczających
informacji.

Przyjazny dla użytkownika

Z punktu widzenia człowieka adres URL powinien być łatwy do zrozumienia
i — jeśli to możliwe — także łatwy do zapamiętania. Spójrz na
przedstawione poniżej dwa adresy URL prowadzące na tę samą stronę
produktu:

-   http://przyklad.pl/sklep.php?action=​display&category=123&subcat​=7&product_id=43
-   http://przyklad.pl/sklep/liquor/​whisky/lagavulin/

Pierwszy z adresów URL jest długi i niezrozumiały, podczas gdy drugi
jest znacznie krótszy i czytelny.

Jeśli nawet adresy URL nie są tak niezrozumiałe jak pierwszy z
wymienionych, posiadanie struktury przypominającej katalogi powoduje, że
stają się znacznie łatwiejsze do zrozumienia. Przykładowo dwa poniższe
adresy URL prowadzą na tę samą stronę witryny bazującej na WordPress:

-   http://przyklad.pl/​index.php?year=2011&paged=6
-   http://przyklad.pl/2011/page/6/

Moduł mod_rewrite serwera Apache

Twórcy serwerów WWW opracowali sposoby zmiany adresów URL z postaci
wygodnej pod względem programistycznym (sklep.php?product=43) na postać
przyjazną człowiekowi i silnikowi wyszukiwarki internetowej
(/kup/produkt/). W tym punkcie zostaną omówione sposoby zmiany adresów
URL w serwerze Apache, ale inne serwery WWW (Lighttpd, Nginx, IIS itd.)
również wyposażono w podobne techniki.

W serwerze Apache modułem o znaczeniu krytycznym dla obsługi odnośników
bezpośrednich jest mod_rewrite. Moduł pozwala na definiowanie reguł
zmiany adresów, które najczęściej są umieszczane w pliku .htaccess.
Klasyczna reguła zmiany adresów URL składa się z przedstawionego poniżej
bloku kodu:

    <IfModule mod_rewrite.c> 
    RewriteEngine on
    RewriteRule [ wzorzec ] [ zamiennik ] [ parametry opcjonalne ]
    </IfModule> 

Parametry wzorzec i zamiennik mogą zawierać wyrażenia regularne. Spójrz
na przedstawioną poniżej regułę zmiany adresów:

    RewriteRule /kup/([^/]+)/ /sklep.php?produkt=$1 [L] 

Kiedy klient zażąda adresu URL rozpoczynającego się od /kup/,
zawierającego wiele znaków niebędących ukośnikiem ([^/]+) oraz ukośnik
na końcu, serwer WWW spowoduje przekierowanie żądania na stronę
sklep.php i przekazanie parametru produkt wraz z wartością pobraną z
nawiasu wzorca.

Jeżeli chcesz dowiedzieć się więcej na temat modułu mod_rewrite i zmiany
adresów URL w środowisku innym niż WordPress, zapoznaj się z artykułem
na stronie http://articles.sitepoint.com/​article/guide-url-rewriting.

Zmiany adresów URL na platformie WordPress

Typowy adres URL platformy WordPress, taki jak /2011/03/witaj-swiecie/,
zwykle nie odpowiada fizycznej ścieżce dostępu w serwerze WWW, tzn. nie
ma katalogu witaj-swiecie w katalogu 03, który byłby podkatalogiem 2011.
Na pewnym etapie adres URL został więc zmieniony.

------------------------------------------------------------------------

Uwaga

Jeżeli instalacja WordPress działa w serwerze mającym odpowiednie
możliwości (najczęściej Apache wraz z modułem mod_rewrite), wówczas
można włączyć obsługę "eleganckich odnośników bezpośrednich" i
wykorzystać zalety płynące z posiadania adresów URL przyjaznych zarówno
dla człowieka, jak i silnika wyszukiwarki internetowej, np.
http://przyklad.pl/2011/03/witaj-swiecie/ zamiast
http://przyklad.pl/index.php?p=1. Więcej informacji na temat tej funkcji
można znaleźć na stronie http://codex.wordpress.org/Using_Permalinks.

------------------------------------------------------------------------

Po zainstalowaniu platforma WordPress tworzy w katalogu głównym plik
.htaccess zawierający poniższy blok kodu:

    <IfModule mod_rewrite.c> 
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    </IfModule> 

Dyrektywa mod_rewrite zawiera dodatkowe reguły zmiany adresów, w których
zamieszczono informacje dla serwera WWW. Oto one.

1.  Jeżeli żądanie dotyczy pliku index.php, wtedy wykonaj przekierowanie
    do tego pliku i nie próbuj dopasować pozostałych reguł. (Polecenie
    [L] oznacza ostatni).
2.  Jeżeli żądanie nie jest plikiem (%{REQUEST_FILENAME} !-f)…
3.  … i jeśli żądanie nie jest katalogiem (%{REQUEST_FILENAME} !-d)…
4.  … wówczas zmień adres URL na index.php i nie próbuj stosować
    dalszych reguł.

Taka dyrektywa .htaccess powoduje przekierowanie żądań typu
/2011/page/6/ na /index.php. Oznacza to, że praktycznie wszystkie
żądania publicznych stron danej witryny bazującej na WordPress są
wewnętrznie przekierowywane do pliku index.php, który następnie
interpretuje żądanie. Witamy w świecie API Rewrite.

W jaki sposób WordPress obsługuje zapytania?

Wiesz już, że kiedy odwiedzający wczytuje stronę bazującą na WordPress,
faktycznie wczytywanym plikiem jest index.php. Przykładowo żądanie
strony http://przyklad.pl/2011/03/witaj-swiecie/ spowoduje wewnętrzne
przekierowanie na adres URL http://przyklad.pl/index.php?p=1 i pobranie
z bazy danych wpisu bloga o identyfikatorze 1. Powstaje więc pytanie, w
jaki sposób adres URL jest przekształcany na zapytanie do bazy danych
MySQL?

W przedstawionych poniżej punktach znajdziesz wyjaśnienie, co się dzieje
podczas wyświetlania przez serwer WWW strony bazującej na platformie
WordPress oraz jaka może być rola wtyczek w tym procesie.

Ogólny opis procesu wykonania zapytania

Konieczne jest zrozumienie, jak i kiedy zachodzą pewne zdarzenia na
platformie WordPress, ponieważ to pomoże w wytypowaniu miejsc, w których
wtyczka może zostać włączona do całego procesu. Poniżej przedstawiono
cykl zdarzeń zachodzących podczas żądania strony, a także używane pliki
i wywoływane funkcje.

1.  Wczytanie pliku głównego index.php (zgodnie z regułą zmiany adresu
    znajdującą się w .htaccess) oraz wczytanie pliku wp-blog-header.php.

2.  Wczytanie pliku wp-load.php, który następnie wyszukuje i dołącza
    plik wp-config.php, a ten z kolei wczytuje wp-settings.php
    zawierający odniesienia do plików funkcji, aktywnych wtyczek oraz
    zastępowalnych funkcji.

3.  Ustanowienie nowych obiektów $wp_query i $wp_rewrite. Więcej
    informacji na temat tych obiektów znajduje się w dalszej części
    rozdziału.

4.  Wczytanych zostaje kilka plików dodatkowych, np. pliki z
    tłumaczeniami oraz plik funkcji motywu.

    ------------------------------------------------------------------------

    Uwaga

    Jeżeli jeszcze tego nie zrobiłeś, zapoznaj się z kodem źródłowym
    pliku wp-settings.php. Plik ten wyjaśnia przepływ wewnętrznych
    zdarzeń, które ogólnie przedstawiono w rozdziale 1.

    ------------------------------------------------------------------------

    Na tym etapie platforma WordPress jest w pełni wczytana i wtyczki
    mogą rozpocząć współpracę, ale jeszcze nie wiadomo, co powinno
    zostać wyświetlone oraz która strona została zażądana przez
    użytkownika. Wróćmy do pliku wp-blog-header.php: po wczytaniu
    wszystkiego plik ten wywołuje funkcję wp(), od której rozpoczyna się
    cała magia — funkcja WP::parse_request().

    Funkcja parse_request() pochodzi z klasy WP (zdefiniowanej w pliku
    wp-includes/classes.php) i przygotowuje wszystko, czego platforma
    WordPress potrzebuje w celu zrozumienia żądania strony.

5.  Funkcja pobiera listę wszystkich zarejestrowanych reguł zmiany
    adresów URL. Jak już wcześniej wyjaśniono podczas omawiania modułu
    mod_rewrite, zbiór reguł to lista par wzorzec => zamiennik.
    Informują one platformę WordPress, że adres
    /category/tutorials/page/2/ tak naprawdę oznacza
    /index.php?category_name=tutorials&paged=2.

6.  Funkcja przeprowadza iterację przez każdą regułę, porównuje ją do
    żądanego adresu URL i próbuje znaleźć dopasowanie. Jeżeli
    dopasowanie nie zostanie znalezione, wartością zwrotną będzie błąd o
    kodzie 404.

    Jeżeli na tym etapie żądanie nie powoduje wygenerowania błędu o
    kodzie 404, platforma WordPress ma wzorzec przekształcenia odnośnika
    bezpośredniego wraz z miejscami zarezerwowanymi ciągu tekstowego
    zapytania, np. index.php?category_name= <ciąg_tekstowy>&paged=
    <liczba>. Pozostało więc pobranie wartości dla tych zmiennych ciągu
    tekstowego zapytania.

7.  Funkcja parse_request() pobiera listę zarejestrowanych zmiennych
    ciągu tekstowego zapytania i dla każdej zmiennej sprawdza, czy przez
    wzorzec odnośnika bezpośredniego została ustawiona jej wartość
    (przekazana przez POST lub GET).

8.  Teraz platforma WordPress ma już wszystkie informacje wymagane do
    konwersji początkowego adresu URL na odpowiednie zapytanie do bazy
    danych MySQL. Pobiera więc dane odpowiedniego wpisu bloga, wczytuje
    wymagany szablon motywu oraz wyświetla żądaną stronę.

W powyższym wyjaśnieniu warto zwrócić uwagę na dwa wyrażenia:
"zarejestrowane reguły zmiany adresów" oraz "zarejestrowane zmienne
ciągu tekstowego zapytania". Jeżeli na pewnym etapie zostały
zarejestrowane, to może istnieje sposób pozwalający wtyczkom na ich
modyfikację? Oczywiście, tak!

Obiekt rewrite

Przedstawiony już wcześniej obiekt $wp_rewrite to pierwszy obiekt
używany podczas wykorzystywania API Rewrite. Warto spojrzeć na jego
zawartość, którą można wyświetlić za pomocą prostego wywołania
print_r( $wp_rewrite ):

    WP_Rewrite Object (
    ...
    [permalink_structure] => /%year%/%postname%/
    [use_trailing_slashes] => 1
    ...
    [rules] => Array (
      [category/(.+?)/?$] => index.php?category_name=$matches[1]
      [tag/([^/]+)/page/?([0-9]{1,})/?$] => index.php?tag=$matches[1]&paged=$matches[2]
      [tag/([^/]+)/?$] => index.php?tag=$matches[1]
      [(.+?)/trackback/?$] => index.php?pagename=$matches[1]&tb=1
      ...
      )
    [endpoints] => Array ()
    ...
    ) 

Pewne z wymienionych powyżej właściwości powinny być już znane: tablica
zawiera listę wszystkich zarejestrowanych reguł zmiany adresów URL. W
obiekcie $rewrite znajdują się wszystkie informacje powiązane ze
strukturą odnośników bezpośrednich witryny. Obejmują one pełny zestaw
reguł zmiany adresów pobranych w omówionym powyżej procesie lub listę
zarejestrowanych kanałów wiadomości i ich strukturę URL (np.
/feed/rss2/).

Obiekt query

Warto również spojrzeć na zawartość obiektu $wp_query wyświetlaną za
pomocą funkcji print_r() podczas żądania strony /2011/witaj-swiecie/ z
witryny internetowej bazującej na platformie WordPress:

    WP_Query Object (
      [query_vars] => Array (
        [page] => 0
        [year] => 2011
        [month] => 03
        [pagename] => 
        [category_name] =>
        [name] => witaj-swiecie
        ...
      )
      ...
      [is_single] => 1
      [is_preview] => 
      [is_page] => 
      ...
      [query] => Array (
        [year] => 2011
        [name] => witaj-swiecie
      )
      ...
    ) 

Obiekt $wp_query definiuje listę autoryzowanych zmiennych ciągu
tekstowego zapytania, które mogą być dopasowane przez reguły zmiany
adresów. Zmienne te przechowują wszystkie informacje niezbędne do
przekształcenia początkowego żądania strony na zapytanie do bazy danych
MySQL.

Co można zrobić przy użyciu wtyczek?

Za pomocą funkcji API Rewrite wtyczki mogą współpracować z obiektami
$wp_rewrite i $wp_query, wykonując np. zadania, które zostaną
przedstawione w kolejnym podrozdziale zatytułowanym "Przykłady
praktyczne". We wtyczkach można:

-   tworzyć własne reguły zmiany adresów URL oraz zdefiniować sposoby
    ich interpretacji przez platformę WordPress;
-   zintegrować witrynę WordPress ze stronami, które nie zostały
    utworzone w WordPress, i zachować spójny wzorzec adresu URL oraz
    projektu witryny;
-   tworzyć własne kanały wiadomości wraz z własnymi odnośnikami
    bezpośrednimi kanału wiadomości.

Po poznaniu ogólnych koncepcji API Rewrite warto wykorzystać tę wiedzę
praktycznie i rozpocząć tworzenie kodu.

Przykłady praktyczne

W tym podrozdziale zostaną przedstawione przykłady praktyczne oraz kod,
który można wykorzystać w rzeczywistych sytuacjach. Podczas lektury tego
podrozdziału dowiesz się więc, jak:

-   wykorzystać API Rewrite w celu łatwego wygenerowania dowolnej liczby
    podstron w hierarchii jednej strony nadrzędnej;
-   zdefiniować własną strukturę odnośników bezpośrednich w celu łatwego
    zintegrowania treści, która nie powstała w WordPress, z witryną
    utworzoną na bazie platformy WordPress;
-   zarejestrować nowe usługi za pomocą adresów URL punktów końcowych,
    np. w celu wyświetlania kodów QR;
-   wygenerować kanały wiadomości dla dowolnej własnej treści, np.
    ostatnio dodanych obrazów.

Zmiana adresu URL w celu utworzenia listy sklepów

Przeprojektowałeś właśnie witrynę internetową dużej firmy handlowej
posiadającej dziesiątki sklepów w całym kraju. Twoim zadaniem jest teraz
wyświetlenie listy tych sklepów na witrynie firmy. W jaki sposób można
to zrobić?

-   Opcja 1.: ręczne utworzenie strony dla każdego sklepu. Hmm, niezbyt
    zachęcająca perspektywa.
-   Opcja 2.: utworzenie strony znajdującej się pod adresem
    http://przyklad.pl/sklepy/ i przekazanie do platformy WordPress
    informacji, że adres http://przyklad.pl/sklepy/miasto/ wymaga
    wyświetlenia strony z informacjami o sklepie znajdującym się we
    wskazanym mieście. To znacznie przyjemniejsza perspektywa!

Utworzenie reguły zmiany adresów

Funkcja odpowiedzialna za zbudowanie nowej reguły zmiany adresów to
add_rewrite_rule(). Wymaga ona podania dwóch argumentów i działa
podobnie do sposobu działania modułu mod_rewrite: ciąg tekstowy
definiujący wzorzec adresu URL musi być dopasowany do innego ciągu
tekstowego przedstawiającego zamiennik adresu URL. W tworzonej tutaj
wtyczce trzeba więc użyć poniższego fragmentu kodu:

    <?php
    // Dodanie reguł.
    add_action( 'init', 'boj_rrs_add_rules' );
    function boj_rrs_add_rules() {
        add_rewrite_rule( 'sklepy/?([^/]*)',
            'index.php?pagename=sklepy&store_id=$matches[1]', 'top' );
    }
    ?> 

Ten kod powoduje wewnętrzne przekierowanie wszystkich żądań adresu
sklepy/miasto/ na stronę sklepy wraz z parametrem dodatkowym, np.
http://index.php?pagename​=sklepy&store_id=miasto.

Następnie do funkcji add_rewrite_rule() przekazany zostaje trzeci
parametr top określający, że ta lista będzie dodana przed wszystkimi
regułami zmiany adresów. Dzięki temu dopasowanie może być znalezione
wcześniej, jeszcze przed sprawdzeniem reguł wbudowanych.

Rejestracja zmiennej ciągu tekstowego zapytania

Teraz do listy zarejestrowanych zmiennych ciągu tekstowego zapytania
trzeba dodać parametr store_id:

    <?php
    // Dodanie zmiennej store_id, aby była rozpoznawana przez platformę WordPress.
    add_filter( 'query_vars', 'boj_rrs_add_query_var' );
    function boj_rrs_add_query_var( $vars ) {
        $vars[] = 'store_id';
        return $vars;
    }
    ?> 

Dotychczas zmodyfikowałeś listę zdefiniowanych reguł zmiany adresów
przechowywaną w obiekcie $wp_rewrite oraz listę autoryzowanych zmiennych
ciągu tekstowego zapytania przechowywaną w obiekcie $wp_query. Praca
jest prawie skończona!

Wyczyszczenie reguł zmiany adresów

Po wprowadzeniu modyfikacji do reguł zmiany adresów (np. po dodaniu,
zmodyfikowaniu lub usunięciu reguły) platformie WordPress trzeba nakazać
ponowny odczyt i przebudowę listy. W tym celu można odwiedzić stronę
Ustawienia/Bezpośrednie odnośniki w obszarze administracyjnym albo użyć
funkcji flush_rewrite_rules(), którą można wywołać podczas aktywacji lub
dezaktywacji wtyczki:

    <?php
    // Dodanie reguły zmiany adresów oraz wyczyszczenie listy podczas aktywacji wtyczki.
    register_activation_hook( __FILE__, 'boj_rrs_activate' );
    function boj_rrs_activate() {
        boj_rrs_add_rules();
        flush_rewrite_rules();
    }
    // Wyczyszczenie reguł zmiany adresów podczas dezaktywacji wtyczki.
    register_deactivation_hook( __FILE__, 'boj_rrs_deactivate' );
    function boj_rrs_deactivate() {
        flush_rewrite_rules();
    }
    ?> 

Podczas dodawania nowych reguł zmiany adresów warto pamiętać o kilku
najlepszych praktykach.

-   W trakcie aktywacji wtyczki dodajemy regułę i czyścimy listę reguł.
-   W zaczepie init również dodajemy regułę, na wypadek gdyby inna
    wtyczka wyczyściła listę reguł.
-   Nie należy czyścić listy reguł podczas każdego żądania strony (np.
    przy użyciu zaczepu init), ponieważ to powoduje powstanie
    niepotrzebnego obciążenia.
-   Podczas dezaktywacji wtyczki należy ponownie wyczyścić listę reguł.

Funkcjonalna wtyczka

Poniżej przedstawiono pełny kod źródłowy wtyczki:

    <?php
    /*
    Plugin Name: Lista sklepów
    Plugin URI: http://przyklad.pl/
    Description: Dodanie reguł zmiany adresów w celu wyświetlenia listy sklepów jako elementów 
    adrzędnych strony Sklepy.
    Version: 1.0
    Author: Ozh
    Author URI: http://wrox.com
    */
    // Dodanie reguły zmiany adresów oraz wyczyszczenie listy podczas aktywacji wtyczki.
    register_activation_hook( __FILE__, 'boj_rrs_activate' );
    function boj_rrs_activate() {
        boj_rrs_add_rules();
        flush_rewrite_rules();
    }
    // Wyczyszczenie reguł zmiany adresów podczas dezaktywacji wtyczki.
    register_deactivation_hook( __FILE__, 'boj_rrs_deactivate' );
    function boj_rrs_deactivate() {
        flush_rewrite_rules();
    }
    // Dodanie reguł.
    add_action( 'init', 'boj_rrs_add_rules' );
    function boj_rrs_add_rules() {
        add_rewrite_rule( 'sklepy/?([^/]*)',
            'index.php?pagename=sklepy&store_id=$matches[1]', 'top' );
    }
    // Dodanie zmiennej store_id, aby była rozpoznawana przez platformę WordPress.
    add_filter( 'query_vars', 'boj_rrs_add_query_var' );
    function boj_rrs_add_query_var( $vars ) {
        $vars[] = 'store_id';
        return $vars;
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_rewrite_shops/plugin.php.

------------------------------------------------------------------------

Na tym kończy się przygotowanie wtyczki. Teraz po podaniu adresu
http://przyklad.pl/sklepy/lodz/ przeglądarka spowoduje wykonanie
przekierowania na stronę nadrzędną WordPress o nazwie Sklepy wraz z
parametrem dodatkowym store_id. Kolejnym krokiem jest więc utworzenie
wspomnianej strony i dodanie prostej modyfikacji motywu.

Utworzenie strony sklepów, która może wygenerować strony potomne

Dodatkowy wewnętrzny parametr store_id jest zmienną ciągu tekstowego
zapytania, której wartość można odczytać za pomocą funkcji
get_query_var(), np. następująco:

    <?php
    // Pobranie identyfikatora sklepu.
    $store = get_query_var( 'store_id' );
    ?> 

Teraz można utworzyć zwykłą stronę WordPress, korzystając ze strony
administracyjnej Dodaj nową stronę, ale wiąże się to z pewnym problemem:
będzie ona korzystała z szablonu strony.

Kiedy platforma WordPress wyświetla stronę (w przeciwieństwie do wpisu
bloga), w bieżącym katalogu motywu szuka pliku o nazwie page.php.
Istnieje możliwość zdefiniowania, aby poszczególne strony korzystały z
nieco bardziej dopasowanego do ich potrzeb pliku szablonu o nazwie
sklepy.php. W tym celu należy utworzyć nowy plik w katalogu motywu i na
jego początku umieścić przedstawiony poniżej kod:

    <?php
    /*
    Template Name: Sklep
    */
    ?> 

Teraz w polu Atrybuty strony na stronie Dodaj nową stronę z rozwijanego
menu Szablon będzie można wybrać nowo dodany szablon (zobacz rysunek
14.1).

[]

Rysunek 14.1. Nowo dodany szablon dostępny do wyboru w rozwijanym menu

Kod szablonu strony oraz układ zależą od sposobu przygotowania szablonu,
np. od tego, jak są używane i nazywane elementy <div>. W omawianym
przykładzie przyjmujemy założenie, że witryna klienta stosuje domyślny
motyw WordPress o nazwie TwentyTen. Dlatego też strona szablonu
sklepy.php będzie miała taką samą strukturę jak oryginalna page.php:

    <?php
    /*
    Template Name: Sklep
    */
    ?> 
    <?php get_header(); ?> 
    <div id="container"> 
    <div id="content" role="main"> 
    </div><!-- #content --> 
    </div><!-- #container --> 
    <?php get_sidebar(); ?> 
    <?php get_footer(); ?> 

W znaczniku <div id="content"> znajduje się kod wyświetlający wszystkie
sklepy (po zażądaniu strony http://przyklad.pl/sklepy/) lub
wyświetlający informacje o danym sklepie (po zażądaniu strony np.
http://przyklad.pl/sklepy/lodz/). W tym celu wystarczy wykonać
następujące kroki:

-   zdefiniować tablicę danych sklepu: nazwę, imię i nazwisko menedżera,
    adres sklepu oraz numer telefonu do każdego istniejącego sklepu;
-   sprawdzić wartość zwrotną wywołania funkcji
    get_query_var( 'store_id' ) i jeśli identyfikator zostanie
    dopasowany do istniejącego sklepu, wyświetlić jego dane;
-   jeżeli wartość zwrotna wywołania funkcji get_query_var( 'store_id' )
    nie spowoduje dopasowania istniejącego sklepu, wyświetlić listę
    wszystkich sklepów.

Poniżej przedstawiono pełny kod źródłowy strony sklepy.php, którą należy
zapisać w katalogu głównym motywu:

    <?php
    /*
    Template Name: Sklep
    */
    ?>
    <?php get_header(); ?>
    <div id="container">
        <div id="content" role="main">
        <?php
        // Definicje wszystkich sklepów.
        $stores = array(
            'lodz' => array(
                'name'    => "Sklep w Łodzi",
                'manager' => 'Robert Nowak',
                'address' => 'ul. Nowa 123, Łódź',
                'phone'   => '555-31337-1337'
            ),
            'gliwice' => array(
                'name'    => "Sklep w Gliwicach",
                'manager' => 'Bartosz Malinowski',
                'address' => 'ul. Malinowa 45, Gliwice',
                'phone'   => '555-666-696969'
            ),
            'gdansk' => array(
                'name'    => "Sklep w Gdańsku",
                'manager' => 'Zuzanna Kowalska',
                'address' => 'ul. Nadbrzeżna 67',
                'phone'   => '4-8-15-16-23-42'
            )
        );
        
        // Pobranie identyfikatora sklepu.
        $store = get_query_var( 'store_id' );
        
        // Jeżeli sklep istnieje, wyświetlamy informacje na jego temat.
        if( array_key_exists( $store, $stores ) ) {
        
            extract( $stores[$store] );
            echo "<p>Sklep: $name</p>";
            echo "<p>Menedżer: $manager</p>";
            echo "<p>Adres: $address</p>";
            echo "<p>Kontakt: $phone</p>";
        
        // Jeżeli sklep nie istnieje, wyświetlamy listę wszystkich sklepów.
        } else {
            
            // Pobranie adresu URL bieżącej strony.
            global $post;
            $page = untrailingslashit( get_permalink( $post->ID ) );
            
            echo '<p>Nasze sklepy:</p>';
            echo '<ul>';
            foreach( $stores as $store => $info ) {
                $name = $info['name'];
                echo "<li><a href='$page/$store/'>$name</a></li>\n";
            }
            echo '</ul>';
        }
        
        ?>
        </div><!-- #content -->
    </div><!-- #container -->
    <?php get_sidebar(); ?>
    <?php get_footer(); ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_rewrite_shops/sklepy.php.

------------------------------------------------------------------------

Jak pokazano na rysunku 14.2, po przygotowaniu szablonu można na jego
podstawie dodać na platformie WordPress zwykłą stronę.

[]

Rysunek 14.2. Dodawanie strony na podstawie przygotowanego szablonu

Na witrynie internetowej jest teraz dostępna strona o nazwie Sklepy
znajdująca się pod adresem http://przyklad.pl/sklepy/, na której są
wyświetlane wszystkie sklepy oraz odnośniki prowadzące do poszczególnych
stron sklepów, np. http://przyklad.pl/lodz/ (zobacz rysunek 14.3).

Tworzenie nowej struktury odnośników bezpośrednich oraz integracja ze stronami, które nie powstały w WordPress

W poprzedniej wtyczce utworzyliśmy stronę WordPress, która stała się
stroną docelową dla zmiany adresów URL. Teraz opracujemy inne reguły
zmiany adresów, ale skorzystamy z odmiennego podejścia.

Przyjmujemy założenie, że klient, dla którego pracujesz, ma już skrypt
wyświetlający produkty i chce go zintegrować z nowo utworzoną przez
Ciebie witryną internetową. Platforma WordPress ma obsługiwać wszystkie
żądania http://przyklad.pl/sklep/cokolwiek/ i używać wspomnianego,
istniejącego skryptu.

[]

Rysunek 14.3. Strona wyświetlająca wszystkie sklepy oraz strona
wybranego sklepu

Utworzenie znacznika zmiany adresów

Na stronie Ustawienia/Bezpośrednie odnośniki można zdefiniować własne
znaczniki odnośników bezpośrednich, np. %rok% lub %miesiac%. Poniżej
przedstawiono definicję nowego znacznika %produkt% oraz jego użycie w
strukturze odnośników bezpośrednich w witrynie internetowej.

    <?php
    // Utworzenie nowego znacznika %produkt% i obsługa adresów URL /sklep/%produkt%.
    add_action('init', 'boj_products_rewrite');
    function boj_products_rewrite() {
        add_rewrite_tag( '%produkt%', '([^/]+)' );
        add_permastruct( 'produkt', 'sklep' . '/%produkt%' );
    }
    ?> 

Wywołanie funkcji add_rewrite_tag() powoduje zdefiniowanie znacznika
oraz dopasowywanych przez niego danych. W omawianym przykładzie znacznik
%produkt% powoduje dopasowanie za pomocą wyrażenia regularnego [^/]+
jednego lub większej liczby znaków, które nie są ukośnikami. To
wywołanie funkcji rejestruje także nową zmienną ciągu tekstowego
zapytania o takiej samej nazwie (produkt).

Po zdefiniowaniu znacznika wywołanie funkcji add_permastruct() zawiera
opis nowej struktury odnośników bezpośrednich. Funkcja pobiera dwa
parametry: dowolną nazwę dla struktury oraz sposób tworzenia adresów URL
i znaczników.

Teraz warto spojrzeć na reguły zmiany adresów, które zostały dodane do
obiektu $wp_rewrite i jego właściwości rules:

    [sklep/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$]
        => index.php?produkt=$matches[1]&feed=$matches[2]
    [sklep/([^/]+)/(feed|rdf|rss|rss2|atom)/?$]
        => index.php?produkt=$matches[1]&feed=$matches[2]
    [sklep/([^/]+)/page/?([0-9]{1,})/?$]
        => index.php?produkt=$matches[1]&paged=$matches[2]
    [sklep/([^/]+)/?$]
        => index.php?produkt=$matches[1]

Poniżej znajdują się przykładowe adresy URL dopasowane do zdefiniowanych
powyżej reguł zmiany adresów:

    http://przyklad.pl/sklep/cokolwiek/feed/rss2/
    http://przyklad.pl/sklep/produkty/atom/ 
    http://przyklad.pl/sklep/rzecz/page/3/ 
    http://przyklad.pl/sklep/element/

Powyższe adresy URL są wewnętrznie zmienione na poniższe:

    http://przyklad.pl/index.php?produkt=cokolwiek&feed=rss2
    http://przyklad.pl/index.php?produkt=produkty&feed=atom 
    http://przyklad.pl/index.php?produkt=rzecz&paged=3 
    http://przyklad.pl/index.php?produkt=element 

Gratulacje! Używając jedynie dwóch wywołań funkcji, utworzyłeś pełną,
nową strukturę odnośników bezpośrednich, która pozwala na obsługę
stronicowania oraz generowania kanałów wiadomości.

Wyświetlanie produktów sklepu

Na tym etapie, gdy żądania /sklep/cokolwiek/ są przekierowywane na
stronę index.php?produkt=
cokolwiek, można przystąpić do integracji z istniejącym skryptem
wyświetlającym produkty sklepu. Poniżej rzeczywisty skrypt integracji
został umieszczony w komentarzu i zastąpiony przykładowymi danymi
wyjściowymi.

    <?php
    // Jeżeli zmienna ciągu tekstowego zapytania ma wartość, wyświetlamy produkty sklepu.
    add_action( 'template_redirect', 'boj_products_display' );
    function boj_products_display() {
        if ( $product = get_query_var( 'produkt' ) ) {
            // include( 'display_product.php' );
            echo "Tutaj znajdują się informacje dotyczące <strong> $product </strong>";
            exit;
        }
    }
    ?> 

Poprzez wykorzystanie zaczepu akcji template_redirect można przechwycić
normalne wyświetlenie strony. Jeśli zmienna produkt ciągu tekstowego
zapytania (zarejestrowana przez wcześniejsze wywołanie funkcji
add_rewrite_tag()) ma wartość, wtedy dołączany jest skrypt wyświetlający
produkty. Nie zapomnij o użyciu funkcji exit(), aby platforma WordPress
nie próbowała dalej obsłużyć wyświetlania tej strony. W takim przypadku,
jeśli nie znajdzie wpisu bloga, wygeneruje komunikat błędu 404.

W celu przetestowania stronicowania i generowania kanałów wiadomości
można sprawdzić wartości get_query_var( 'paged' ) i
get_query_var( 'feed' ).

Po utworzeniu reguł zmiany adresów należy wyczyścić listę; wtyczka jest
teraz kompletna oraz w pełni funkcjonalna.

Funkcjonująca wtyczka

Poniżej przedstawiono pełny kod źródłowy wtyczki.

    <?php
    /*
    Plugin Name: Struktura odnośników bezpośrednich dla produktów
    Plugin URI: http://przyklad.pl/
    Description: Wtyczka tworzy całą strukturę odnośników bezpośrednich.
    Version: 1.0
    Author: Ozh
    Author URI: http://wrox.com
    */
    // Dodanie struktury odnośników bezpośrednich oraz wyczyszczenie reguł zmiany adresów podczas aktywacji wtyczki.
    register_activation_hook( __FILE__, 'boj_products_activate' );
    function boj_products_activate() {
        boj_products_rewrite();
        flush_rewrite_rules();
    }
    // Wyczyszczenie reguł zmiany adresów podczas dezaktywacji wtyczki.
    register_deactivation_hook( __FILE__, 'boj_products_deactivate' );
    function boj_products_deactivate() {
        flush_rewrite_rules();
    }
    // Utworzenie nowego znacznika %produkt% i obsługa adresów URL /sklep/%produkt%.
    add_action('init', 'boj_products_rewrite');
    function boj_products_rewrite() {
        add_rewrite_tag( '%produkt%', '([^/]+)' );
        add_permastruct( 'produkt', 'sklep' . '/%produkt%' );
    }
    // Jeżeli zmienna ciągu tekstowego zapytania ma wartość, wówczas wyświetlamy produkty sklepu.
    add_action( 'template_redirect', 'boj_products_display' );
    function boj_products_display() {
        if ( $product = get_query_var( 'produkt' ) ) {
            // include( 'display_product.php' );
            echo "wyszukiwanie produktu $product";
            exit;
        }
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_rewrite_products/plugin.php.

------------------------------------------------------------------------

Dodawanie punktu końcowego i zmiana formatu danych wyjściowych

Adres URL punktu końcowego definiuje nową usługę, np. /trackback/, na
stronie pojedynczego wpisu bloga WordPress. Istnieje możliwość
przygotowania wtyczki, która dołączy "format" punktu końcowego. Jeśli
teraz użytkownik do dowolnego adresu URL strony witryny dołączy ciąg
tekstowy /format/XXX/, zamieni witrynę na API:

-   dołączenie ciągu tekstowego /format/qr/ do adresu URL strony
    powoduje wyświetlenie kodu QR bieżącego adresu URL;

-   ciąg tekstowy /format/json/ użyty na stronie pojedynczego wpisu
    bloga lub pojedynczej stronie powoduje zwrot danych w formacie ciągu
    tekstowego zakodowanego jako JSON.

-   

    ------------------------------------------------------------------------

    Uwaga

    Kod QR w aplikacjach mobilnych czasami nazywany jest kodem flash. To
    po prostu zwykły kod kreskowy w postaci czarno-białego kwadratowego
    wzorca odczytywanego przez skanery kodu kreskowego, telefony
    komórkowe i smartfony wyposażone w kamerę. Kod zawiera zakodowane
    informacje, którymi mogą być ciągi tekstowe, adresy URL lub inne
    dane, takie jak numery telefonów. Kody QR są stosowane przez coraz
    więcej firm, przede wszystkim w Japonii.

    ------------------------------------------------------------------------

Definicja punktu końcowego

W celu zdefiniowania punktu końcowego dla usługi można użyć funkcji
add_rewrite_endpoint() wymagającej podania dwóch parametrów: ciągu
tekstowego dla składni punktu końcowego (tutaj format) oraz liczby
określającej "miejsca", tzn. typy adresów URL, do których punkt końcowy
będzie dodany.

W pliku wp-includes/rewrite.php można znaleźć definicje wielu stałych
dopasowanych do "miejsc" dodawania punktów końcowych. Przykładowo
EP_CATEGORIES (o wartości 512) powoduje dopasowanie jedynie adresów URL
z odnośnikiem bezpośrednim /kategoria/, np. http://przyklad.pl/
kategoria/bluzy/format/qr/.

Pełna lista stałych została wymieniona w tabeli 14.1.

Jeżeli przykładowo chcesz dodać punkt końcowy na stronie autorów,
wówczas musisz użyć wywołania funkcji
add_rewrite_endpoint( ' cokolwiek ' , 2048) lub
add_rewrite_endpoint( ' cokolwiek ' , EP_AUTHORS).

Jeśli natomiast chcesz dodać punkt końcowy na stronie zarówno autora,
jak i wyszukiwania, musisz dodać dwie wartości:
add_rewrite_endpoint( ' cokolwiek ' , EP_AUTHORS + EP_SEARCH).

W kodzie wtyczki punkt końcowy trzeba dodać do wszystkich adresów URL:

    <?php
    // Dodanie reguły zmiany adresów, która obsługuje punkty końcowe.
    add_filter( 'init', 'boj_ep_add_rules' );
    function boj_ep_add_rules() {
        add_rewrite_endpoint( 'format', EP_ALL );
    }
    ?> 

Powyższe pojedyncze wywołanie funkcji powoduje zarejestrowanie ciągu
tekstowego /format/ jako poprawnego punktu końcowego dla wszystkich
adresów URL, a także rejestruje nową zmienną ciągu tekstowego zapytania
o nazwie format. W ten sposób adresy URL w postaci /tag/bluzy/format/qr/
będą wewnętrznie zmienione na postać /index.php?tag=bluzy&format=qr.

Teraz można sprawdzić wartość zmiennej format oraz zmodyfikować dane
wyjściowe strony:

    <?php
    // Obsługa własnego formatu wyświetlania, jeśli trzeba.
    add_filter( 'template_redirect', 'boj_ep_template_redirect' );

Tabela 14.1. Pełna lista stałych dopasowywanych do "miejsc" dodawania
punktów końcowych

  --------------- --------- ------------------------
  Stała           Wartość   Miejsca
  EP_NONE         0         Brak
  EP_PERMALINK    1         Odnośniki bezpośrednie
  EP_ATTACHMENT   2         Strony załączników
  EP_DATE         4         Strony dat
  EP_YEAR         8         Strony lat
  EP_MONTH        16        Strony miesięcy
  EP_DAY          32        Strony dni
  EP_ROOT         64        Strony główne
  EP_COMMENTS     128       Strony komentarzy
  EP_SEARCH       256       Strony wyszukiwania
  EP_CATEGORIES   512       Strony kategorii
  EP_TAGS         1024      Strony tagów
  EP_AUTHORS      2048      Strony autorów
  EP_PAGES        4096      Strony "stron"
  EP_ALL          8191      Wszystko
  --------------- --------- ------------------------

    function boj_ep_template_redirect() {
        switch( get_query_var( 'format' ) ) {
            case 'qr':
                boj_ep_display_qr();
                exit;
            case 'json':
                if( is_singular() ) {
                    boj_ep_display_json();
                    exit;
                }
        }
    }
    ?> 

Aby zakończyć prace nad wtyczką, konieczne jest jeszcze dodanie
poniższych funkcji i funkcjonalności:

-   boj_ep_display_json() — koduje zmienną globalną $post przy użyciu
    funkcji json_encode(), a następnie ją wyświetla;
-   boj_ep_display_qr() — określa adres URL aktualnie wyświetlanej
    strony, pobiera obraz z API Google QR Code za pomocą funkcji
    omówionych w rozdziale poświęconym API Http, a następnie wyświetla
    ten obraz;
-   zaczepy aktywacji i dezaktywacji dodają punkt końcowy oraz czyszczą
    listę reguł zmiany adresów.

Funkcjonująca wtyczka

Poniżej przedstawiono pełny kod źródłowy wtyczki.

    <?php
    /*
    Plugin Name: Punkt końcowy format
    Plugin URI: http://przyklad.pl/
    Description: Dodaje punkt końcowy /format/ do wszystkich adresów URL.
    Version: 1.0
    Author: Ozh
    Author URI: http://wrox.com
    */
    // Dodanie struktury odnośników bezpośrednich oraz wyczyszczenie reguł zmiany adresów podczas aktywacji wtyczki.
    register_activation_hook( __FILE__, 'boj_ep_activate' );
    function boj_ep_activate() {
        boj_ep_add_rules();
        flush_rewrite_rules();
    }
    // Wyczyszczenie reguł zmiany adresów podczas dezaktywacji wtyczki.
    register_deactivation_hook( __FILE__, 'boj_ep_deactivate' );
    function boj_ep_deactivate(){
        flush_rewrite_rules();
    }
    // Dodanie reguły zmiany adresów, która obsługuje punkty końcowe.
    add_filter( 'init', 'boj_ep_add_rules' );
    function boj_ep_add_rules() {
        add_rewrite_endpoint( 'format', EP_ALL );
    }
    // Obsługa własnego formatu wyświetlania, jeśli trzeba.
    add_filter( 'template_redirect', 'boj_ep_template_redirect' );
    function boj_ep_template_redirect() {
        switch( get_query_var( 'format' ) ) {
            case 'qr':
                boj_ep_display_qr();
                exit;
            case 'json':
                if( is_singular() ) {
                    boj_ep_display_json();
                    exit;
                }
        }
    }
    // Wyświetlenie informacji JSON dotyczących wpisu bloga.
    function boj_ep_display_json() {
        global $post;
        header('Content-type: application/json');
        echo json_encode( $post );
        exit;
    }
    // Wyświetlenie kodu QR.
    function boj_ep_display_qr() {
        // Pobranie bieżącego adresu i usunięcie z niego fragmentu /format/qr/.
        $url = ( is_ssl() ? 'https://' : 'http://' )
            . $_SERVER['HTTP_HOST']
            . preg_replace( '!/format/qr/$!', '/', $_SERVER['REQUEST_URI'] );
        
        // Zakodowanie adresu URL, aby mógł być użyty przez zapytanie pobierające kod QR.
        $url = urlencode( $url );
        
        // Adres URL API Google QR Code:
        $qr = "http://chart.apis.google.com/chart?chs=150x150&cht=qr&chl="
            . $url . "&chld=L|0";
        
        // Pobranie obrazu wygenerowanego przez Google.
        $image = wp_remote_retrieve_body( wp_remote_get( $qr ) );
        // Wyświetlenie obrazu zawierającego kod QR.
        header( 'Content-Type: image/png' );
        echo $image;
        exit;
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_endpoints_format/plugin.php.

------------------------------------------------------------------------

Dodanie własnego kanału wiadomości informującego o ostatnio dodanych obrazach

Platforma WordPress domyślnie generuje kanały wiadomości w kilku
formatach (RSS, RSS2 i ATOM), a ich struktura odnośników bezpośrednich
jest zdefiniowana w obiekcie $wp_rewrite. Standardowo platforma
WordPress może wyświetlić następujące przykładowe rodzaje kanałów
wiadomości:

-   kanał wiadomości Atom dla wszystkich wpisów bloga:
    http://przyklad.pl/feed/atom/;
-   kanał wiadomości dla wpisów bloga oznaczonych tagiem, np. "piwo":
    http://przyklad.pl/tag/piwo/feed/rss/;
-   kanał wiadomości RFD dla komentarzy pojawiających się dla danego
    wpisu bloga: http://przyklad.pl/2011/​witaj-swiecie/feed/rdf/.

We wtyczce można zdefiniować własny kanał wiadomości oraz rodzaj
wyświetlanych przez niego danych wyjściowych, np. kanał wiadomości
informujący o ostatnio dodanych obrazach. Taki kanał wiadomości może być
dostępny pod adresem http://przyklad.pl/feed/obrazy/.

Rejestracja nowego kanału wiadomości

Funkcja API Rewrite przeznaczona do rejestracji nowego kanału wiadomości
nosi nazwę add_feed() i pobiera dwa argumenty: nazwę kanału wiadomości,
taką jak "atom" lub jak w omawianym przykładzie obrazy, oraz funkcję
odpowiedzialną za wygenerowanie jego danych wyjściowych.

    <?php
    // Rejestracja kanału wiadomości.
    add_filter( 'init', 'boj_addfeed_add_feed' );
    function boj_addfeed_add_feed() {
        add_feed( 'obrazy', 'boj_addfeed_do_feed' );
    }
    ?> 

Odtąd adres URL http://przyklad.pl/feed/obrazy/ będzie obsługiwany przez
funkcję boj_addfeed_add_feed(). Ponieważ na platformie WordPress obrazy
są w rzeczywistości własnym typem wpisu bloga "załącznik", co omówiono w
rozdziale 11., to bardzo łatwo można zbudować własną zmienną $post i
pętlę odpowiedzialną za wyświetlanie ostatnio dodanych obrazów. Jak
zwykle, nie wolno zapomnieć o wyczyszczeniu reguł zmiany adresów podczas
aktywacji i dezaktywacji wtyczki.

Funkcjonująca wtyczka

Poniżej przedstawiono pełny kod źródłowy wtyczki.

    <?php
    /*
    Plugin Name: Kanał wiadomości ostatnio dodanych obrazów
    Plugin URI: http://example.com/
    Description: Dodanie kanału wiadomości informującego o ostatnio dodanych obrazach.
    Version: 1.0
    Author: Ozh
    Author URI: http://wrox.com
    */
    // Dodanie struktury odnośników bezpośrednich oraz wyczyszczenie reguł zmiany adresów podczas 
    // aktywacji wtyczki.
    register_activation_hook( __FILE__, 'boj_addfeed_activate' );
    function boj_addfeed_activate() {
        boj_addfeed_add_feed();
        flush_rewrite_rules();
    }
    // Wyczyszczenie reguł zmiany adresów podczas dezaktywacji wtyczki.
    register_deactivation_hook( __FILE__, 'boj_addfeed_deactivate' );
    function boj_addfeed_deactivate() {
        flush_rewrite_rules();
    }
    // Rejestracja kanału wiadomości.
    add_filter( 'init', 'boj_addfeed_add_feed' );
    function boj_addfeed_add_feed() {
        add_feed( 'obrazy', 'boj_addfeed_do_feed' );
    }
    // Wyświetlenie kanału wiadomości.
    function boj_addfeed_do_feed( $in ) {
        // Utworzenie własnego zapytania w celu pobrania ostatnio dodanych obrazów.
        query_posts(array( 'post_type' => 'attachment', 'post_status' => 
        'inherit' ));
        header('Content-Type: application/atom+xml');
        echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>';
        ?>
    <feed xmlns="http://www.w3.org/2005/Atom">
        <title type="text">Ostatnio dodane obrazy na blogu <?php bloginfo_rss('name');?></title>
        <?php
        // Początek pętli.
        while (have_posts()) : the_post();
        ?>
        <entry>
            <title><![CDATA[<?php the_title_rss() ?>]]></title>
            <link href="<?php the_permalink_rss() ?>" />
            <published><?php echo get_post_time('Y-m-d\TH:i:s\Z'); ?></published>
            <content type="html"><![CDATA[<?php the_content() ?>]]></content>
        </entry>
        <?php
        // Koniec pętli.
        endwhile ;
        ?>
    </feed>
        <?php
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj_addfeed/plugin.php.

------------------------------------------------------------------------

Podsumowanie

Celem tego rozdziału było rozwianie tajemnicy okrywającej temat zmiany
adresów URL na platformie WordPress, który często jest uznawany za
skomplikowane zagadnienie. Za pomocą przedstawionych konkretnych wtyczek
możesz samodzielnie tworzyć reguły zmiany adresów. API Rewrite jest
nieocenione zwłaszcza wtedy, gdy trzeba zintegrować istniejącą treść
WordPress ze skryptami, które nie powstały w WordPress — to sytuacja
często spotykana u klientów posiadających już witryny internetowe.

API Rewrite jest uznawane za trudne do zrozumienia, ponieważ jest
najrzadziej używane i najmniej znane ze wszystkich API platformy
WordPress. Faktycznie, z tego API nie korzysta się codziennie. Poznanie
API Rewrite i umiejętność jego zastosowania niewątpliwie zwiększą Twoją
przewagę nad konkurencją!

Rozdział 15 Sieć Multisite

W tym rozdziale:

-   Używanie sieci Multisite jako alternatywy dla standardowej
    konfiguracji platformy WordPress
-   Zrozumienie terminologii sieci Multisite
-   Poznanie funkcji najczęściej używanych w sieci Multisite
-   Przełączanie pomiędzy witrynami w sieci
-   Zarządzanie agregacją treści pomiędzy witrynami
-   Praca z opcjami sieci i witryny
-   Zrozumienie użytkowników i ról witryny
-   Określenie różnic w schematach bazy danych
-   Instalacja i konfiguracja sieci Multisite

WordPress Multisite (wcześniej WordPress MU lub Multiuser) to oferowana
przez platformę WordPress konfiguracja sieci o dużych i użytecznych
możliwościach. Sieć Multisite pozwala na utworzenie wielu witryn
internetowych w ramach pojedynczej instalacji WordPress. Każdy
posiadający zainstalowaną platformę WordPress może dzięki sieci
Multisite bardzo łatwo utworzyć sieć witryn internetowych i
administrować nią. Sieć może być otwarta na nowych użytkowników i
witryny bądź zamknięta. W tym drugim przypadku tylko administratorzy
mogą tworzyć nowe witryny i użytkowników.

Każda witryna w ramach sieci Multisite może również mieć swoje wtyczki,
stosować inne motywy, oferować unikalną treść oraz posiadać zupełnie
oddzielną bazę użytkowników. Odkrycie potężnych możliwości oferowanych
przez sieć Multisite nie wymaga zbyt wiele wysiłku. Dlatego też jako
twórca wtyczek musisz dokładnie poznać funkcje, które są oferowane
podczas pracy z siecią Multisite na platformie WordPress.

Różnice

Sieć Multisite jest dostępna na platformie WordPress od wersji 3.0,
jednak nie jest włączona domyślnie. Pomiędzy standardową konfiguracją
platformy WordPress oraz z włączoną obsługą sieci Multisite występują
pewne różnice. Podczas pracy nad wtyczkami dla WordPress trzeba te
różnice znać i rozumieć.

Standardowa konfiguracja WordPress kontra sieć Multisite

Domyślnie po instalacji platformy WordPress dostępna jest pojedyncza
witryna internetowa. Od WordPress w wersji 3.0 sieć Multisite (czasami
określana skrótem WPMS) jest częścią WordPress. Jak już wspomniano, sieć
Multisite pozwala na obsługę wielu witryn internetowych w ramach
pojedynczej instalacji WordPress. Po włączeniu sieci Multisite możesz
wybrać sposób wyświetlania witryn na platformie WordPress albo w formie
subdomen (http://witryna1.przyklad.pl), albo podkatalogów
(http://przyklad.pl/witryna1). Istnieje nawet możliwość mapowania nazw
domen dla każdej witryny (http://przyklad.pl); w takim przypadku
odwiedzający nie będą wiedzieli, że witryny te są obsługiwane przez
pojedynczą instalację WordPress.

Jak widać, sieć Multisite to funkcja platformy WordPress o ogromnych
możliwościach. Nie ma żadnych ograniczeń dotyczących liczby witryn,
które mogą być obsługiwane przez WordPress. Jedynym ograniczeniem
pozostają zasoby dostępne dla używanego serwera WWW. Witryna
WordPress.com to tak naprawdę pojedyncza instalacja WordPress z włączoną
obsługą sieci Multisite zarządzającą milionami witryn w internecie.
Przykładowo WordPress.com obsługuje różnorodne witryny, począwszy od
pojedynczych blogów aż po witryny, takie jak TechCrunch.com.

Zrozumienie terminologii sieci Multisite

Aby skutecznie używać sieci Multisite, trzeba zrozumieć stosowaną w niej
terminologię. Dwa ważne pojęcia dotyczące Multisite to sieć i witryna.
Sieć to cała instalacja Multisite, po prostu zwykła sieć. Z kolei
witryna to pojedyncza witryna internetowa umieszczona w tej sieci.
Dlatego też WordPress Multisite to sieć witryn internetowych.

Podczas tworzenia wtyczek dla sieci Multisite trzeba określić, czy praca
będzie odbywała się w ramach sieci, czy pojedynczej witryny. Przykładowo
wpisy bloga mają być pobierane z pojedynczej witryny internetowej w
sieci lub możesz utworzyć dla wtyczki opcję o zasięgu całej sieci.

Wszystkie witryny w sieci Multisite mają zdefiniowany stan. Wspomniany
stan jest bardzo ważny i pozwala na określenie, czy witryna jest
dostępna publicznie. Poniżej wymieniono listę dostępnych stanów witryn w
sieci Multisite.

-   Public (publiczna) — witryna jest publiczna, jeżeli ustawienia
    prywatności pozwalają na jej indeksowanie przez silniki wyszukiwarek
    internetowych.
-   Archived (zarchiwizowana) — witryna została zarchiwizowana i nie
    jest dłużej dostępna publicznie.
-   Mature (dla dorosłych) — witryna została oznaczona jako przeznaczona
    dla dorosłych.
-   Spam — witryna została uznana za spam, nie jest dostępna publicznie.
-   Deleted (usunięta) — witryna została przeznaczona do usunięcia i nie
    jest dostępna publicznie.

Jedyne dwa stany, które pozwalają na publiczne udostępnienie witryny, to
Public i Mature. Stan Mature może być używany, gdy w sieci zgodzisz się
na zaoferowanie stron przeznaczonych dla dorosłych. Jednak w takim
przypadku odwiedzających trzeba wcześniej (jeszcze przed wyświetleniem
pierwszej strony) uprzedzić o treści znajdującej się w witrynie. Stan
Public bazuje na ustawieniach prywatności i określeniu, czy silniki
wyszukiwarek internetowych mogą indeksować daną witrynę.

Zalety sieci Multisite

Włączenie sieci Multisite na witrynach internetowych może przynieść
wiele korzyści. Najbardziej oczywistą jest posiadanie tylko jednej
instalacji WordPress, którą trzeba administrować. To znacznie ułatwia
zadania, takie jak uaktualnianie platformy WordPress, wtyczek i motywów.
Jeżeli posiadasz sieć WordPress Multisite składającą się z 50 witryn
internetowych, po wydaniu nowszej wersji wtyczki musisz uaktualnić ją
tylko w jednym miejscu, a zmiana będzie od razu odzwierciedlona na
wszystkich 50 witrynach. Gdyby każda witryna znajdowała się w oddzielnej
instalacji, wtyczkę musiałbyś uaktualniać 50 razy.

Inna zaleta sieci Multisite to łatwość, z jaką można agregować treść w
sieci. Jeśli przykładowo sieć składa się z 50 witryn internetowych,
wpisy bloga z wszystkich witryn możesz bardzo łatwo agregować na głównym
blogu sieci witryn. Gdyby wszystkie witryny znajdowały się w oddzielnych
instalacjach, tego rodzaju agregacja treści wymagałaby włożenia znacznie
większej ilości pracy.

Administracja siecią witryn również jest wszechstronna. Przykładowo
można bardzo łatwo określić ilość miejsca na dysku przeznaczoną dla
poszczególnych witryn. Ponadto można zdefiniować typy przekazywanych
witrynie plików oraz ich maksymalną wielkość. Istnieje nawet możliwość
zablokowania pewnych wtyczek i motywów przed ich administrowaniem lub
używaniem przez użytkowników sieci Multisite.

Włączenie sieci Multisite na platformie WordPress

Instalacja sieci Multisite na platformie WordPress jest w rzeczywistości
całkiem prostym zadaniem. Jedną z najlepszych funkcji sieci Multisite
jest możliwość jej włączenia przed instalacją platformy WordPress lub w
dowolnym momencie już po instalacji. Dlatego też jeśli np. po upływie
roku od instalacji platformy WordPress zdecydujesz się na jej konwersję
na sieć Multisite, możesz to zrobić bez problemów.

Pierwszym krokiem w procesie włączenia sieci Multisite jest modyfikacja
pliku wp-config.php. Plik zawiera ustawienia połączenia z bazą danych
oraz inne ważne opcje konfiguracyjne. W celu włączenia sieci Multisite
przedstawiony poniżej wiersz trzeba umieścić powyżej wiersza
/* To wszystko, zakończ edycję w tym miejscu! Miłego blogowania! */:

    define( 'WP_ALLOW_MULTISITE', true );

Po dodaniu powyższego wiersza do pliku wp-config.php w obszarze
administracyjnym pojawi się menu Narzędzia/Uruchamianie sieci (zobacz
rysunek 15.1).

Kliknięcie nowej opcji menu spowoduje przejście na stronę w obszarze
administracyjnym zatytułowaną Utwórz sieć witryn opartych na
WordPressie. Jeżeli nie zrobiłeś tego wcześniej, przed włączeniem sieci
Multisite zostaniesz poproszony o wyłączenie wszystkich wtyczek. Poniżej
znajdziesz szczegółowe omówienie kroków wymaganych do zakończenia
instalacji sieci Multisite. W omawianym przykładzie skonfigurujemy sieć
Multisite do pracy z podkatalogami. Dlatego też jeśli planujesz użycie
subdomen, stosuj się do przedstawionych wskazówek, ale pamiętaj, że kod
może być nieco inny.

[]

Rysunek 15.1. Menu Narzędzia/Uruchamianie sieci pojawia się po włączeniu
obsługi sieci Multisite

Kolejnym krokiem jest utworzenie podkatalogu blogs.dir w katalogu
wp-content. Sieć Multisite w inny sposób niż standardowa konfiguracja
platformy WordPress obsługuje odnośniki bezpośrednie obrazów. Wszystkie
obrazy są umieszczane w katalogach wp-content/blogs.dir/BLOG_ID/files/
ROK/MIESIĄC. Odnośniki bezpośrednie do plików mają postać:
http://przyklad.pl/files/2011/10/obraz.png.

Po utworzeniu katalogu blogs.dir w pliku wp-config.php trzeba umieścić
przedstawiony poniżej kod. Zwróć uwagę, że poniższy kod jest tylko
przykładowy i zmienna DOMAIN_CURRENT_SITE będzie zawierała nazwę Twojej
domeny, a nie przykładowo tu użytą przyklad.pl:

    define( 'MULTISITE', true );
    define( 'SUBDOMAIN_INSTALL', false );
    $base = '/';
    define( 'DOMAIN_CURRENT_SITE', 'przyklad.pl' );
    define( 'PATH_CURRENT_SITE', '/' );
    define( 'SITE_ID_CURRENT_SITE', 1 );
    define( 'BLOG_ID_CURRENT_SITE', 1 ); 

Ostatnim krokiem jest modyfikacja pliku .htaccess znajdującego się w
katalogu głównym instalacji WordPress. Istniejące tam reguły należy
zastąpić poniższym zestawem:

    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    # Pliki przekazywane do serwera.
    RewriteRule ^([_0-9a-zA-Z-]+/)?files/(.+) wp-includes/ms-files.php?file=$2 [L]
    # Dodanie ukośnika do /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] 

Po wprowadzeniu wymaganych zmian konieczne jest ponowne zalogowanie się
na platformie WordPress. Teraz sieć Multisite jest włączona i gotowa do
użycia!

Funkcje sieci Multisite

Po włączeniu sieci Multisite twórca wtyczek otrzymuje do dyspozycji
zupełnie nowy zestaw funkcji pozwalających na wykorzystanie możliwości
oferowanych przez tę sieć. Ich poznanie może Ci pomóc we wbudowaniu do
tworzonych wtyczek funkcji zapewniających obsługę sieci Multisite.
Ponadto będziesz wiedział, co zrobić, aby tworzone przez Ciebie wtyczki
już od samego początku były zgodne z Multisite.

Potęga identyfikatora bloga

Każda witryna internetowa w sieci Multisite ma unikalny identyfikator,
często nazywany identyfikatorem bloga. Identyfikator bloga jest
wykorzystywany w niemal każdej funkcji charakterystycznej dla sieci
Multisite. To pozwala platformie WordPress na ustalenie, względem której
witryny internetowej chcesz wykonać daną operację. Identyfikator bloga
jest również używany jako prefiks tabel bazy danych wykorzystywanych
przez daną witrynę internetową.

Jeśli przykładowo chcesz włączyć obsługę sieci Multisite i utworzyć
drugą witrynę w sieci, wówczas platforma WordPress wykreuje kilka tabel
bazy danych, takich jak wp_2_posts, gdzie wp_ to prefiks zdefiniowany
podczas instalacji platformy, natomiast 2_ to identyfikator bloga nowej
witryny. Po utworzeniu dodatkowych witryn platforma będzie budować
kolejne tabele bazy danych w taki sam sposób.

Identyfikator bloga jest przechowywany w zmiennej globalnej $blog_id, o
czym możesz się przekonać, uruchamiając poniższy kod:

    <?php
    global $blog_id;
    echo 'Identyfikator bieżącego bloga: ' .$blog_id;
    ?> 

Zmienna $blog_id istnieje w standardowej konfiguracji platformy
WordPress, ale zawsze ma wartość 1. W sieci Multisite identyfikator
bloga będzie miał wartość identyfikatora bloga aktualnie odwiedzanego
przez użytkownika.

Najczęściej używane funkcje

Podczas pracy z siecią Multisite można wykorzystać oferowane przez nią
funkcje. Pierwsza z wartych omówienia nosi nazwę is_multisite() i
określa, czy włączona została obsługa sieci Multisite. Spójrz na
przykład użycia tej funkcji:

    <?php
    if ( is_multisite() ) {
        echo 'Sieć Multisite jest włączona';
    }
    ?> 

Jak widzisz, omawiana funkcja nie pobiera żadnych parametrów. Po prostu
sprawdza, czy włączona jest obsługa sieci Multisite na platformie
WordPress i wówczas zwraca wartość true. Za każdym razem, gdy planujesz
użycie funkcji sieci Multisite, dobrym rozwiązaniem jest sprawdzenie,
czy obsługa sieci Multisite jest włączona. Jeżeli obsługa Multisite nie
jest włączona, jej domyślne funkcje nie będą dostępne do użycia w
standardowej konfiguracji platformy WordPress, co spowoduje
wygenerowanie błędów przez wtyczkę.

Inna użyteczna funkcja nosi nazwę get_blog_post() i pozwala na pobranie
wpisów bloga danej witryny. Wymieniona funkcja pobiera wpis bloga z
dowolnej witryny sieci.

    <?php get_blog_post( $blog_id, $post_id ); ?> 

Funkcja akceptuje dwa parametry: $blog_id oraz $post_id. Spójrz na
przykład jej użycia:

    <?php
    // Zdefiniowanie identyfikatorów bloga i wpisu bloga.
    $multisite_blog_id = 3;
    $multisite_post_id = 4;
    // Wczytanie danych wpisu bloga.
    $post_details = get_blog_post(
        $multisite_blog_id, $multisite_post_id );
    // Wyświetlenie tytułu wpisu bloga i jego treści.
    echo 'Tytuł wpisu bloga: ' .$post_details->post_title .'<br />';
    echo 'Treść wpisu bloga: ' .$post_details->post_content .'<br />';
    ?> 

W powyższym przykładzie przyjęto założenie, że identyfikator witryny to
3, natomiast identyfikator wpisu bloga do pobrania to 4. Przedstawiona
funkcja pozwala na bardzo łatwe i szybkie pobranie wpisu bloga z
dowolnej witryny sieci.

Przydatne może być również pobieranie określonych informacji dotyczących
aktualnie wykorzystywanej witryny. W celu pobrania informacji o witrynie
można użyć funkcji o nazwie get_blog_details().

    <?php get_blog_details( $fields, $getall ); ?>

Funkcja akceptuje dwa parametry:

-   $fields — identyfikator bloga, nazwa bloga oraz tablica pól, których
    informacje mają zostać pobrane;
-   $getall — określa, czy pobrać wszystkie informacje.

Wartością zwrotną funkcji jest obiekt zawierający wszystkie zmienne
publiczne przechowywane w tabeli wp_blogs. Oczywiście, istnieje
możliwość pobrania jednej, konkretnej zmiennej:

    <?php
    $blog_details = get_blog_details( 1 );
    print_r( $blog_details );
    ?> 

Wykonanie powyższego fragmentu kodu spowoduje otrzymanie następujących
danych wyjściowych:

    stdClass Object
    (
        [blog_id] => 1
        [site_id] => 1
        [domain] => przyklad.pl
        [path] => /
        [registered] => 2010-10-31 19:14:59
        [last_updated] => 2010-11-11 14:19:34
        [public] => 1
        [archived] => 0
        [mature] => 0
        [spam] => 0
        [deleted] => 0
        [lang_id] => 0
        [blogname] => Przykładowa witryna internetowa
        [siteurl] => http://przyklad.pl
        [post_count] => 420
    ) 

Jak możesz zobaczyć, dane wyjściowe zawierają wiele cennych informacji
dotyczących wskazanej witryny internetowej. Istnieje także możliwość
pobrania wartości pojedynczej opcji poprzez podanie jej nazwy:

    <?php
    echo 'Całkowita liczba wpisów bloga: ' .get_blog_details( 1 )->post_count;
    ?> 

Przełączenie i przywracanie witryn internetowych

Jedną z najważniejszych zalet używania sieci Multisite jest łatwość, z
jaką można agregować treść sieci, a także inne dane z różnych witryn
danej sieci.

Do pobierania danych z witryn internetowych sieci wykorzystywane są
przede wszystkim dwie funkcje. Pierwsza z nich nosi nazwę
switch_to_blog() i pozwala na przełączenie się do dowolnej witryny
internetowej w danej sieci Multisite.

    <?php switch_to_blog( $blog_id, $validate ); ?> 

Funkcja akceptuje dwa parametry:

-   $blog_id — identyfikator witryny, do której chcesz przejść;
-   $validate — określa, czy przed przejściem do wskazanej witryny
    sprawdzić jej istnienie.

Druga z tych funkcji nosi nazwę restore_current_blog(). Jej zadaniem
jest przeniesienie użytkownika z powrotem do aktualnie odwiedzanej
witryny internetowej. Po wywołaniu funkcji switch_to_blog() zawsze
należy stosować wywołanie restore_current_blog(). W przeciwnym razie
wszystkie zadania będą odbywały się względem danych witryny, do której
się przełączyłeś, a nie względem aktualnie odwiedzanej. To może
doprowadzić do bałaganu w widgetach, ustawieniach witryny itd.

Spójrz teraz na przykład. W poniższym kodzie tworzymy własną stronę
ustawień i wyświetlamy wpisy bloga opublikowane na blogu o
identyfikatorze 3.

    <?php
    add_action( 'admin_menu', 'boj_multisite_switch_menu' );
    function boj_multisite_switch_menu() {
        // Utworzenie własnego menu najwyższego poziomu.
        add_menu_page( 'Przełącznik witryn w sieci Multisite', 'Przełącznik witryn w sieci 
          Multisite', 'manage_options', 'boj-network-switch', 
          'boj_multisite_switch_page');
    }
    ?> 

Pierwszym krokiem jest utworzenie własnego menu najwyższego poziomu.
Spowoduje ono wywołanie funkcji boj_multisite_switch_page(), która
wyświetli stronę dla wpisów bloga opublikowanych na blogu o
identyfikatorze 3.

    <?php
    function boj_multisite_switch_page() {
        if ( is_multisite() ) {
            // Przejście do bloga o identyfikatorze 3.
            switch_to_blog( 3 );
            // Utworzenie własnej pętli.
            $recentPosts = new WP_Query();
            $recentPosts->query( 'posts_per_page=5' );
            // Rozpoczęcie wykonywania pętli.
            while ( $recentPosts->have_posts() ) :
                $recentPosts->the_post();
                // Przechowywanie ostatnich wpisów bloga w zmiennej.
                echo '<p><a href="' .get_permalink(). '" >' .
                    get_the_title() .'</a></p>';
            endwhile;
            // Przywrócenie bieżącej witryny.
            restore_current_blog();
        }
    }
    ?> 

Jak zwykle, włączenie sieci Multisite należy sprawdzić za pomocą funkcji
is_multisite(). Jeżeli obsługa sieci Multisite nie została włączona,
funkcje switch_to_blog() oraz restore_ current_blog() będą niedostępne
dla wtyczki. Kolejnym krokiem jest wywołanie funkcji switch_to_blog() w
celu przejścia do bloga o identyfikatorze 3. W omawianym przykładzie
identyfikator bloga został na stałe zdefiniowany w kodzie. Jednak zawsze
powinna to być zmienna dynamiczna ustawiana przez użytkownika. Po
przejściu do wskazanej witryny można rozpocząć pobieranie jej treści, co
wymaga utworzenia odpowiedniej pętli.

W celu utworzenia własnej pętli definiujemy zmienną o nazwie $recentPost
i tworzymy egzemplarz obiektu WP_Query. Następnie trzeba podać parametry
zapytania: w omawianym przykładzie wartość posts_per_page wynosi 5. W
ten sposób zwróconych zostanie pięć ostatnich wpisów bloga. Po
zdefiniowaniu obiektu WP_Query należy uruchomić pętlę i pobrać wyniki;
do tych zadań wykorzystywane są funkcje have_posts() i the_post().
Własna pętla wyświetli wpisy bloga pobrane w pętli.

Ostatnim krokiem jest wywołanie funkcji restore_current_blog(). Jeżeli
nie wywołasz tej funkcji, platforma WordPress pozostanie na witrynie, do
której nastąpiło przejście. W takim przypadku wykonanie kolejnych
poleceń spowoduje pobranie danych z witryny o identyfikatorze 3, a nie z
aktualnie odwiedzanej.

Teraz po pokazaniu strony ustawień wtyczki strona wyświetli pięć
ostatnich wpisów bloga opublikowanych na logu o identyfikatorze 3. Pełny
kod wtyczki przedstawiono poniżej.

    <?php
    /*
    Plugin Name: Przykład wtyczki przełączającej witryny sieci Multisite
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka demonstrująca przełączanie witryn w sieci Multisite.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    add_action( 'admin_menu', 'boj_multisite_switch_menu' );
    function boj_multisite_switch_menu() {
        // Utworzenie własnego menu najwyższego poziomu.
        add_menu_page( 'Przełącznik witryn w sieci Multisite', 'Przełącznik witryn w sieci Multisite', 'manage_options', 'boj-network-switch', 
       'boj_multisite_switch_page');
    }
    function boj_multisite_switch_page() {
        if ( is_multisite() ) {
            // Przejście do bloga o identyfikatorze 3.
            switch_to_blog( 3 );
            // Utworzenie własnej pętli.
            $recentPosts = new WP_Query();
            $recentPosts->query( 'posts_per_page=5' );
            // Rozpoczęcie wykonywania pętli.
            while ( $recentPosts->have_posts() ) :
                $recentPosts->the_post();
                // Przechowywanie ostatnich wpisów bloga w zmiennej.
                echo '<p><a href="' .get_permalink(). '" >' .
                    get_the_title() .'</a></p>';
            endwhile;
            // Przywrócenie bieżącej witryny.
            restore_current_blog();
        }
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-multisite-switch.php.

------------------------------------------------------------------------

W tym przykładzie zademonstrowano potęgę funkcji switch_to_blog() w
sieci Multisite.

Funkcja switch_to_blog() nie jest ograniczona jedynie do treści witryny.
Pozwala na pobranie także innych danych WordPress, m.in. widgetów,
paneli bocznych, menu itd. Ogólnie rzecz biorąc, wszelkie dane
przechowywane w tabelach bazy danych (wp_ID_nazwatabeli) są dostępne dla
funkcji switch_to_blog(). Warto teraz spojrzeć na kilka innych
przykładów. W poniższym przyjęto założenie, że mamy witrynę o
identyfikatorze 3 i chcemy pobrać menu nawigacyjne z tej witryny.

    <?php
    // Przejście do bloga o identyfikatorze 3.
    switch_to_blog( 3 );
    // Wyświetlenie menu nawigacyjnego.
    wp_nav_menu( 'Main Menu' );
    // Przywrócenie bieżącej witryny.
    restore_current_blog();
    ?> 

Na początku następuje wywołanie funkcji switch_to_blog(), które powoduje
przejście do bloga o identyfikatorze 3. Następnie funkcja wp_nav_menu()
wyświetla menu o nazwie Main Menu pochodzące ze wskazanej witryny. Na
końcu wywołanie funkcji restore_current_blog() powoduje powrót do
aktualnie odwiedzanego bloga. Wynikiem uruchomienia powyższego kodu jest
wyświetlenie menu głównego utworzonego w witrynie o identyfikatorze 3.
Wspomniane menu jest wyświetlone w miejscu uruchomienia kodu.

W kolejnym przykładzie pokazano, jak łatwo przy użyciu tej samej metody
można wczytać panel boczny witryny.

    <?php
    // Przejście do bloga o identyfikatorze 34.
    switch_to_blog( 34 );
    // Wczytanie podstawowego panelu bocznego.
    get_sidebar();
    // Przywrócenie bieżącej witryny.
    restore_current_blog();
    ?> 

Należy pamiętać, że funkcja switch_to_blog() działa jedynie względem
bazy danych. Oznacza to, że wtyczki witryny nie są uwzględniane podczas
przełączania witryn. Dlatego też jeśli witryna 2. ma wtyczkę o nazwie
Halloween Revenge, po przejściu do tej witryny wspomniana wtyczka nie
będzie dostępna, o ile nie została aktywowana na witrynie
przeprowadzającej operację przejścia do witryny 2.

Przykłady skrótów uzyskania dostępu do treści sieci

Przykład przełącznika zostanie teraz rozbudowany i wzbogacony o obsługę
skrótów. Wtyczka pozwoli na dodanie skrótu do wpisu bloga, zdefiniowanie
identyfikatora bloga, z którego mają zostać pobrane wpisy, oraz
wyświetlenie wpisów bloga na stronie.

Pierwszym krokiem jest utworzenie nowego skrótu za pomocą funkcji
add_shortcode() dokładnie omówionej w rozdziale 10. poświęconym skrótom.

    <?php
    add_shortcode( 'wpisy_bloga_sieci', 'boj_multisite_network_posts' );
    ?> 

Nowy skrót to [wpisy_bloga_sieci]. Kolejnym krokiem jest utworzenie
funkcji generującej wpisy bloga sieci przeznaczone do wyświetlenia po
użyciu we wpisie bloga lub na stronie zdefiniowanego skrótu.

    <?php
    function boj_multisite_network_posts( $attr ) {
        extract( shortcode_atts( array(
                "blogid" => '1',
                "num"    => '5'
                ), $attr ) );
        if ( is_multisite() ) {
            $return_posts = '';
            // Przejście do witryny wskazanej w skrócie.
            switch_to_blog( absint( $blogid ) );
            // Utworzenie własnej pętli.
            $recentPosts = new WP_Query();
            $recentPosts->query( 'posts_per_page=' .absint( $num ) );
            // Rozpoczęcie wykonywania pętli.
            while ( $recentPosts->have_posts() ) :
                $recentPosts->the_post();
                // Przechowywanie ostatnio opublikowanych wpisów bloga w zmiennej.
                $return_posts .= '<p><a href="' .get_permalink() '" >' .get_the_title()
                   .'</a></p>';
            endwhile;
            // Przywrócenie bieżącej witryny.
            restore_current_blog();
            // Zwrócenie wyników przeznaczonych do wyświetlenia.
            return $return_posts;
        }
    }
    ?> 

Skrót akceptuje dwa parametry: blogid oraz num. W ten sposób użytkownik
może wskazać blog, z którego mają zostać pobrane wpisy, oraz określić
liczbę wpisów przeznaczonych do wyświetlenia. Jak zawsze, przed
rozpoczęciem operacji należy sprawdzić, czy włączono obsługę sieci
Multisite.

Zmienna $return_posts przechowuje wszystkie wpisy bloga zwrócone przez
skrót i przeznaczone do wyświetlenia. Dlatego też pierwszym krokiem jest
wyzerowanie wartości tej zmiennej. Następnie za pomocą funkcji
switch_to_blog() przechodzimy do witryny internetowej wskazanej przez
skrót. Jeżeli użytkownik nie podał identyfikatora bloga, zostanie użyty
domyślny, czyli 1.

Kolejnym krokiem jest przygotowanie własnej pętli odpowiedzialnej za
pobranie wpisów bloga przeznaczonych do wyświetlenia. Możesz zobaczyć,
że parametrowi posts_per_page zostaje przypisana wartość $num podana
przez użytkownika podczas wywoływania skrótu. Jeżeli użytkownik nie
wskaże liczby wpisów bloga do wyświetlenia, domyślnie wyświetlonych
będzie pięć. Następnie pętla przeprowadza iterację przez wczytane wpisy
bloga i umieszcza je w zmiennej $return_posts.

Po zakończeniu działania pętli trzeba wywołać funkcję
restore_current_blog(). W ten sposób następuje powrót do aktualnie
przeglądanej witryny internetowej. Ostatnim krokiem jest zwrot zmiennej
$return_posts. Ten krok powoduje zastąpienie skrótu we wpisie bloga lub
na stronie wynikami wygenerowanymi przez pętlę.

Teraz możesz już bardzo łatwo pobierać wpisy bloga z dowolnej witryny
danej sieci Multisite, używając do tego skrótu, takiego jak
[wpisy_bloga_sieci blogid="3" num="10"]. Poniżej przedstawiono pełny kod
źródłowy wtyczki.

    <?php
    /*
    Plugin Name: Skrót przełączania witryn sieci Multisite
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka agregująca treść za pomocą skrótu.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    add_shortcode( 'network_posts', 'boj_multisite_network_posts' );
    function boj_multisite_network_posts( $attr ) {
        extract( shortcode_atts( array(
                "blogid" => '1',
                "num"    => '5'
                ), $attr ) );
        if ( is_multisite() ) {
            $return_posts = '';
            // Przejście do witryny wskazanej w skrócie.
            switch_to_blog( absint( $blogid ) );
            // Utworzenie własnej pętli.
            $recentPosts = new WP_Query();
            $recentPosts->query( 'posts_per_page=' .absint( $num ) );
            // Rozpoczęcie wykonywania pętli.
            while ( $recentPosts->have_posts() ) :
                $recentPosts->the_post();
                // Przechowywanie ostatnio opublikowanych wpisów bloga w zmiennej.
                $return_posts .= '<p><a href="' .get_permalink() '" >' .get_the_title() 
                   .'</a></p>';
            endwhile;
            // Przywrócenie bieżącej witryny.
            restore_current_blog();
            // Zwrócenie wyników przeznaczonych do wyświetlenia.
            return $return_posts;
        }
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-multisite-shortcode.php.

------------------------------------------------------------------------

Przykład z użyciem skrótu można jeszcze bardziej rozbudować i pobierać
wpisy bloga z wielu witryn internetowych danej sieci Multisite, a
następnie wyświetlać je na podstawie daty publikacji wpisu bloga.
Podobnie jak w poprzednim przykładzie, do zarejestrowania skrótu we
wtyczce zostanie użyta funkcja add_shortcode():

    <?php
    add_shortcode( 'latest_network_posts', 'boj_multisite_latest_network_posts' );
    ?> 

Kolejnym krokiem jest utworzenie własnej funkcji o nazwie
boj_multisite_latest_network_posts():

    <?php
    function boj_multisite_latest_network_posts() {
        if ( is_multisite() ) {
            $return_posts = ''; 

Jak zwykle, za pomocą wywołania funkcji is_multisite() należy
przeprowadzić sprawdzenie, czy obsługa sieci Multisite została włączona.
Przy okazji warto wyzerować wartość zmiennej $return_posts. Kolejnym
krokiem jest pobranie wpisów bloga.

    // Pobranie wpisów bloga z bieżącej witryny.
    $local_posts = get_posts( 'numberposts=5' );
    // Przejście do bloga o identyfikatorze 3.
    switch_to_blog( 3 );
    // Pobranie wpisów bloga z innej witryny.
    $network_posts = get_posts( 'numberposts=5' );
    // Przywrócenie bieżącej witryny.
    restore_current_blog(); 

Przy użyciu funkcji get_posts() pobieramy pięć ostatnich wpisów bloga z
bieżącej witryny. Następnie po przejściu na witrynę o identyfikatorze 3
wywołujemy tę samą funkcję get_posts() i pobieramy pięć ostatnich wpisów
bloga z tamtej witryny. Warto zwrócić uwagę, że zwrócone tablice
wartości są przechowywane w oddzielnych zmiennych: $local_posts i
$network_posts. Wywołanie funkcji restore_current_blog() powoduje powrót
do aktualnie odwiedzanej witryny.

Na tym etapie mamy po pięć wpisów bloga pochodzących z różnych witryn i
przechowywanych w oddzielnych tablicach. Obie tablice można połączyć w
jedną.

    // Połączenie dwóch tablic w jedną.
    $posts = array_merge( $local_posts, $network_posts ); 

Po zgromadzeniu wpisów bloga w pojedynczej tablicy trzeba je posortować
względem daty publikacji. Wpisy bloga powinny być ułożone w odwrotnej
kolejności, czyli jako pierwszy ma być opublikowany ostatnio. Do
posortowania tablicy na podstawie własnej funkcji porównywania, którą
napiszemy w dalszej części kodu, zostanie użyta funkcja PHP o nazwie
usort().

    // Posortowanie wpisów bloga względem daty publikacji.
    usort( $posts, 'boj_multisite_sort_posts_array' ); 

Na tym etapie wpisy bloga są umieszczone w tablicy w prawidłowej
kolejności. Pozostało więc wykonanie pętli, przeprowadzenie iteracji
przez tablicę i przypisanie wartości zmiennej $return_posts.

    foreach ( $posts as $post ) {
        // Przechowywanie ostatnio opublikowanych wpisów bloga w zmiennej.
        $return_posts .= $post->post_title .' - opublikowany dnia '
            .$post->post_date .'<br />';
    } 

Za pomocą standardowego polecenia PHP foreach następuje iteracja przez
otrzymane wyniki. Na końcu zwracana jest zmienna zawierająca dane
przeznaczone do wyświetlenia.

        // Zwrócenie wyników do wyświetlenia.
        return $return_posts;
        }
    } 

Ostatnim krokiem jest utworzenie własnej funkcji o nazwie
boj_multisite_sort_posts_array() odpowiedzialnej za posortowanie tablicy
wpisów bloga względem daty. Ta funkcja została wcześniej wywołana przez
funkcję PHP o nazwie usort().

    // Posortowanie tablicy względem daty.
    function boj_multisite_sort_posts_array( $a, $b ) {
        // Jeżeli daty są takie same, wartością zwrotną ma być zero.
        if ($a->post_date == $b->post_date)
            return 0;
        // Operator trójargumentowy w celu określenia, która data jest nowsza.
        return $a->post_date < $b->post_date ? 1 : -1;
    } 

Powyższa funkcja po prostu porównuje dwie wartości i zwraca 1 lub -1 w
zależności od tego, która wartość jest większa. Funkcja usort()
przeprowadza sortowanie tablicy na podstawie przypisanych liczb.

Poniżej przedstawiono pełny kod źródłowy wtyczki.

    <?php
    /*
    Plugin Name: Wpisy bloga z sieci Multisite
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wyświetla ostatnie wpisy bloga z wielu witryn sieci Multisite.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    add_shortcode( 'latest_network_posts', 'boj_multisite_latest_network_posts' );
    function boj_multisite_latest_network_posts() {
        if ( is_multisite() ) {
            $return_posts = '';
        // Pobranie wpisów bloga z bieżącej witryny.
        $local_posts = get_posts( 'numberposts=5' );
        // Przejście do bloga o identyfikatorze 3.
        switch_to_blog( 3 );
        // Pobranie wpisów bloga z innej witryny.
        $network_posts = get_posts( 'numberposts=5' );
        // Przywrócenie bieżącej witryny.
        restore_current_blog(); 
        // Połączenie dwóch tablic w jedną.
        $posts = array_merge( $local_posts, $network_posts ); 
        // Posortowanie wpisów bloga względem daty publikacji.
        usort( $posts, 'boj_multisite_sort_posts_array' ); 
        foreach ( $posts as $post ) {
            // Przechowywanie ostatnio opublikowanych wpisów bloga w zmiennej.
            $return_posts .= $post->post_title .' - opublikowany dnia '
                .$post->post_date .'<br />';
        } 
        // Zwrócenie wyników do wyświetlenia.
        return $return_posts;
        }
    } 
    // Posortowanie tablicy względem daty.
    function boj_multisite_sort_posts_array( $a, $b ) {
        // Jeżeli daty są takie same, wartością zwrotną ma być zero.
        if ($a->post_date == $b->post_date)
            return 0;
        // Operator trójargumentowy w celu określenia, która data jest nowsza.
        return $a->post_date < $b->post_date ? 1 : -1;
    } 
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku
boj-multisite-latest-network-posts.php.

------------------------------------------------------------------------

Podczas używania funkcji switch_to_blog() nie można zapominać o
wydajności. Użycie wymienionej funkcji może spowodować duży spadek
wydajności serwera, który jest zależny od wielkości sieci Multisite.
Podczas stosowania wymienionej funkcji otrzymane dane zawsze warto
buforować, jeśli tylko istnieje taka możliwość, zamiast pobierać je w
czasie rzeczywistym. W ten sposób można znacznie zmniejszyć obciążenie
serwera podczas pobierania treści oraz innych danych z różnych witryn
sieci Multisite. Temat buforowania został dokładnie omówiony w rozdziale
16.

Przykład widgetu z treścią sieciową

Innym zadaniem często wykonywanym podczas pracy w środowisku sieci
Multisite jest utworzenie widgetu wyświetlającego ostatnio opublikowane
wpisy bloga na witrynach należących do danej sieci Multisite. Utworzymy
więc teraz wtyczkę w postaci wspomnianego widgetu.

    <?php
    // Zaczep akcji widgets_init będzie użyty do wykonania własnej funkcji.
    add_action( 'widgets_init', 'boj_multisite_register_widget' );
    // Rejestracja naszego widgetu.
    function boj_multisite_register_widget() {
        register_widget( 'boj_multisite_widget' );
    }
    ?> 

Najpierw zaczep akcji widgets_init jest używany do wywołania własnej
funkcji odpowiedzialnej za rejestrację nowego widgetu. W omawianym
przykładzie widget będzie zarejestrowany za pomocą funkcji
boj_multisite_widget(). Kolejnym krokiem jest utworzenie nowej klasy
wykorzystującej nazwę widgetu. Nowa klasa będzie rozszerzeniem klasy
WP_Widget.

    <?php
    // Klasa boj_multisite_widget.
    class boj_multisite_widget extends WP_Widget {
        // Przetworzenie nowego widgetu.
        function boj_multisite_widget() {
            $widget_ops = array( 'classname' => 'boj_multisite_widget',
                'description' => 'Wyświetla najnowsze wpisy bloga
                    opublikowane na witrynach sieci Multisite.' );
            $this->WP_Widget( 'boj_multisite_widget_posts',
                'Ostatnie wpisy bloga sieci Multisite',
                $widget_ops );
        } 

Trzeba również zdefiniować ustawienia widgetu. Jego nazwa to "Ostatnie
wpisy bloga sieci Multisite", opis przedstawia przeznaczenie widgetu,
natomiast nazwa własnej klasy będzie używana podczas wyświetlania
widgetu.

Kolejnym krokiem jest utworzenie formularza ustawień widgetu. Widget
zawiera trzy opcje: tytuł, witrynę, z której będą pobierane ostatnie
wpisy bloga, oraz liczbę wpisów bloga przeznaczonych do wyświetlenia.

     // Zbudowanie formularza ustawień widgetu.
    function form( $instance ) {
        global $wpdb;
        $defaults = array( 'title' => 'Ostatnie wpisy bloga',
            'disp_number' => '5' );
        $instance = wp_parse_args( (array) $instance, $defaults );
        $title = $instance['title'];
        $siteid = $instance['siteid'];
        $disp_number = $instance['disp_number']; 

Do bazy danych zostanie wykonane własne zapytanie w celu pobrania
identyfikatora bloga sieci Multisite. To oznacza konieczność
zdefiniowania $wpdb jako zmiennej globalnej. Wartości domyślne widgetu
są zapisane w zmiennej $defaults; w omawianym przykładzie domyślny tytuł
brzmi Ostatnie wpisy bloga, natomiast domyślna liczba wpisów bloga
przeznaczonych do wyświetlenia wynosi pięć. Kolejnym krokiem jest
wczytanie wartości zmiennych egzemplarza, które będą wartościami
ustawień widgetu.

Po wczytaniu wartości ustawień widgetu trzeba dodać pola ustawień
formularza dla widgetu. Pierwsze to pole tekstowe zawierające
wyświetlany tytuł widgetu:

            // Pole tekstowe zawierające tytuł widgetu.
            echo '<p>Tytuł:  <input class="widefat" name="'
                .$this->get_field_name( 'title' )
                .'" type="text" value="'
                .esc_attr( $title ). '" /></p>'; 

Jak zawsze, podczas wyświetlania danych pochodzących od użytkownika,
trzeba się upewnić o użyciu prawidłowej funkcji oczyszczającej. W
omawianym przykładzie będzie to funkcja esc_attr(), która wyświetla
wartość $title.

Kolejne pole pozwoli na wybór witryny internetowej w danej sieci
Multisite, z której mają być pobierane ostatnie wpisy bloga. W celu
utworzenia tego pola konieczne jest pobranie listy wszystkich
identyfikatorów blogów dostępnych publicznie w danej sieci Multisite. Do
pobrania wspomnianych identyfikatorów zostanie napisane własne zapytanie
do bazy danych.

            // Pobranie listy wszystkich identyfikatorów blogów dostępnych publicznie w danej sieci Multisite.
            $sql = "SELECT blog_id FROM $wpdb->blogs
                WHERE public = '1' AND archived = '0' AND mature = '0'
                AND spam = '0' AND deleted = '0' ";
            $blogs = $wpdb->get_col( $wpdb->prepare( $sql ) ); 

Powyższe zapytanie pobiera wszystkie identyfikatory blogów dostępnych
publicznie w danej sieci Multisite, a następnie zwraca je w postaci
tablicy przechowywanej w zmiennej $blogs. Gdy mamy już wszystkie
identyfikatory blogów, trzeba przeprowadzić iterację i zbudować listę
wyboru.

            if ( is_array( $blogs ) ) {
                echo '<p>';
                echo 'Witryna, z której mają być pobierane ostatnie wpisy bloga';
                echo '<select name="' .$this->get_field_name('siteid')
                    .'" class="widefat" >';
                // Iteracja przez wszystkie identyfikatory blogów.
                foreach ($blogs as $blog) {
                    // Wyświetlenie każdej witryny jako opcji.
                    echo '<option value="' .$blog. '" '
                        .selected( $blog, $siteid )
                        .'>' .get_blog_details( $blog )->blogname
                        .'</option>';
                }
                echo '</select>';
                echo '</p>';
            } 

Przed rozpoczęciem pracy z tablicą dobrą praktyką jest sprawdzenie, czy
dana zmienna naprawdę jest tablicą. W tym celu można wykorzystać funkcję
PHP o nazwie is_array(). Po potwierdzeniu, że zmienna $blogs jest
tablicą, można wyświetlić rozwijane menu z listą opcji do wyboru. Aby
każda witryna była wyświetlona jako opcja, konieczne jest
przeprowadzenie iteracji przez tablicę wartości. Wyświetlenie nazwy
witryny następuje za pomocą funkcji get_blog_details(). Zmienna $blog
przechowująca identyfikator bloga ma przypisaną wartość pola opcji.

Ostatnie pole formularza pozwala na określenie liczby wpisów bloga,
które mają być wyświetlone.

            // Liczba wpisów bloga, które mają być wyświetlone.
            echo '<p>Liczba wpisów bloga do wyświetlenia:  <input class="widefat" name="'
                .$this->get_field_name( 'disp_number' ). '" type="text"
                value="' .esc_attr( $disp_number ). '" /></p>';
        } 

Podobnie jak w opcji pobierającej tytuł widgetu, to także jest
standardowe pole tekstowe, ale przechowuje liczbę wpisów bloga
przeznaczonych do wyświetlenia. To już jest ostatnie pola formularza,
więc nie wolno zapomnieć o nawiasie zamykającym. Na tym etapie formularz
opcji widgetu jest już utworzony i wygląda tak, jak pokazano na rysunku
15.2.

[]

Rysunek 15.2. Gotowy formularz opcji widgetu

Kolejnym krokiem jest zapis ustawień widgetu za pomocą funkcji update()
utworzonej klasy widgetu.

        // Zapisanie ustawień widgetu.
        function update( $new_instance, $old_instance ) {
            $instance = $old_instance;
            $instance['title'] = strip_tags( $new_instance['title'] );
            $instance['siteid'] = absint( $new_instance['siteid'] );
            $instance['disp_number'] =
                absint( $new_instance['disp_number'] );
            return $instance;
        } 

Klasa widgetu zajmie się obsługą zapisu ustawień. Należy się upewnić o
weryfikacji ustawień widgetu. Zarówno siteid, jak i disp_number zawsze
powinny być liczbami. Dlatego też używamy funkcji absint() w celu
sprawdzenia, czy wymienione ustawienia są dodatnimi liczbami
całkowitymi.

Ostatnim krokiem jest wyświetlenie widgetu.

        // Wyświetlenie widgetu.
        function widget( $args, $instance ) {
            extract( $args );
            echo $before_widget;
            // Wczytanie opcji widgetu.
            $title = apply_filters( 'widget_title', $instance['title'] );
            $siteid = empty( $instance['siteid'] ) ? 1 :
                $instance['siteid'];
            $disp_number = empty( $instance['disp_number'] ) ? 5 :
                $instance['disp_number'];
            // Wyświetlenie tytułu widgetu.
            if ( !empty( $title ) ) { echo $before_title . $title .
                $after_title; };
            echo '<ul>'; 

Na początek wyodrębniamy zmienną $args w celu uzyskania dostępu do
globalnych wartości motywu, takich jak $before_widget i $after_widget.
Następnie wczytywane są ustawienia widgetu. Zmienne $siteid i
$disp_number mają wartości ustawiane za pomocą operatora
trójargumentowego. Oznacza to, że jeśli opcja nie będzie ustawiona przez
użytkownika, otrzyma wartość domyślną. W przypadku zmiennej $siteid
wartość domyślna wynosi 1, natomiast dla $disp_number wynosi 5.

Teraz można wyświetlić zmienną $title otoczoną przez wartości globalne
$before_widget i $after_widget motywu. Na tym etapie można również
wyświetlić ostatnio opublikowane wpisy bloga, które zostały pobrane
przez widget ze wskazanej witryny.

            // Przejście na wskazaną witrynę.
            switch_to_blog( absint( $siteid ) );
            // Utworzenie własnej pętli.
            $recentPosts = new WP_Query();
            $recentPosts->query( 'posts_per_page='
                .absint( $disp_number ) );
            // Uruchomienie własnej pętli.
            while ( $recentPosts->have_posts() ) :
                $recentPosts->the_post();
                // Wyświetlenie ostatnio opublikowanego wpisu bloga wraz z odnośnikiem.
                echo '<li><a href="' .get_permalink(). '">'
                    .get_the_title() .' </a></li>';
            endwhile;
            // Przywrócenie aktualnie odwiedzanej witryny.
            restore_current_blog();
            echo '</ul>';
            echo $after_widget;
        }
    } 

Przy użyciu funkcji switch_to_blog() widget przechodzi na witrynę
wskazaną przez użytkownika w ustawieniach widgetu. Po wczytaniu witryny
za pomocą klasy WP_Query następuje utworzenie własnej pętli. Parametr
zapytania posts_per_page jest definiowany przez ustawienie widgetu
$disp_number. Ostatnio opublikowane wpisy bloga są wyświetlane na
nieuporządkowanej liście za pomocą pętli while. Po zakończeniu działania
pętli trzeba przywrócić aktualnie odwiedzaną witrynę, wywołując w tym
celu funkcję restore_current_blog().

W ten sposób powstał widget, który bardzo łatwo wyświetla wpisy bloga z
dowolnej witryny znajdującej się w danej sieci Multisite. Ten prosty
przykład pokazuje potężne możliwości w zakresie agregacji treści w sieci
Multisite oraz łatwość, z jaką można te możliwości wykorzystać.

    <?php
    /*
    Plugin Name: Widget wyświetla ostatnie wpisy bloga sieci Multisite
    Plugin URI:  http://przyklad.pl
    Description: Pobiera listę ostatnich wpisów bloga opublikowanych na witrynach sieci Multisite.
    Author: Brad Williams
    Version: 1.0
    Author URI: http://wrox.com
    */
    // Zaczep akcji widgets_init będzie użyty do wykonania własnej funkcji.
    add_action( 'widgets_init', 'boj_multisite_register_widget' );
    // Rejestracja naszego widgetu.
    function boj_multisite_register_widget() {
        register_widget( 'boj_multisite_widget' );
    }
    // Klasa boj_multisite_widget.
    class boj_multisite_widget extends WP_Widget {
        // Przetworzenie nowego widgetu.
        function boj_multisite_widget() {
            $widget_ops = array( 'classname' => 'boj_multisite_widget', 
                'description' => 'Wyświetla najnowsze wpisy bloga opublikowane na witrynach sieci Multisite.' );
            $this->WP_Widget( 'boj_multisite_widget_posts', 'Ostatnie wpisy bloga 
            sieci Multisite', $widget_ops );
    }
        // Zbudowanie formularza ustawień widgetu.
        function form( $instance ) {
            global $wpdb;
            $defaults = array( 'title' => 'Ostatnie wpisy bloga', 'disp_number' => 
            '5' );
            $instance = wp_parse_args( (array) $instance, $defaults );
            $title = $instance['title'];
            $siteid = $instance['siteid'];
            $disp_number = $instance['disp_number'];
            // Pole tekstowe zawierające tytuł widgetu.
            echo '<p>Tytuł: <input class="widefat" name="' 
                .$this->get_field_name( 'title' )
                . '" type="text" value="' .esc_attr( $title )
                . '" /></p>';
            // Pobranie listy wszystkich identyfikatorów blogów dostępnych publicznie w danej sieci 
            // Multisite.
            $sql = "SELECT blog_id FROM $wpdb->blogs 
                WHERE public = '1' AND archived = '0' AND mature = '0' 
                AND spam = '0' AND deleted = '0' ";
            $blogs = $wpdb->get_col( $wpdb->prepare( $sql ) );
            if ( is_array( $blogs ) ) {
                echo '<p>';
                echo 'Witryna, z której mają być pobierane ostatnie wpisy bloga:';
                echo '<select name="' .$this->get_field_name('siteid') 
                    .'" class="widefat" >';
                // Iteracja przez wszystkie identyfikatory blogów.
                foreach ($blogs as $blog) {
                    // Wyświetlenie każdej witryny jako opcji.
                    echo '<option value="' .$blog. '" ' 
                    .selected( $blog, $siteid )
                    . '>' .get_blog_details( $blog )->blogname
                    . '</option>';
                }
                echo '</select>';
                echo '</p>';
            }
            // Liczba wpisów bloga, które mają być wyświetlone.
            echo '<p>Liczba wpisów bloga do wyświetlenia: <input class="widefat" 
            name="' 
                .$this->get_field_name( 'disp_number' ). '" type="text" 
                value="' .esc_attr( $disp_number ). '" /></p>';
        }
        // Zapisanie ustawień widgetu.
        function update( $new_instance, $old_instance ) {
            $instance = $old_instance;
            $instance['title'] = strip_tags( $new_instance['title'] );
            $instance['siteid'] = absint( $new_instance['siteid'] );
            $instance['disp_number'] = absint( $new_instance['disp_number'] );
            return $instance;
        }
        // Wyświetlenie widgetu.
        function widget( $args, $instance ) {
            extract( $args );
            echo $before_widget;
            // Wczytanie opcji widgetu.
            $title = apply_filters( 'widget_title', $instance['title'] );
            $siteid = empty( $instance['siteid'] ) ? 1 : $instance['siteid'];
            $disp_number = empty( $instance['disp_number'] ) ? 5 : $instance['disp_number'];
            // Wyświetlenie tytułu widgetu.
            if ( !empty( $title ) ) {
                echo $before_title . $title . $after_title;
            };
            echo '<ul>';
            // Przejście na wskazaną witrynę.
            switch_to_blog( absint( $siteid ) );
            // Utworzenie własnej pętli.
            $recentPosts = new WP_Query();
            $recentPosts->query( 'posts_per_page=' .absint( $disp_number ) );
            // Uruchomienie własnej pętli.
            while ( $recentPosts->have_posts() ) :
                $recentPosts->the_post();
                // Wyświetlenie ostatnio opublikowanego wpisu bloga wraz z odnośnikiem.
                echo '<li><a href="' .get_permalink(). '">' 
                    .get_the_title() .'</a></li>';
            endwhile;
            // Przywrócenie aktualnie odwiedzanej witryny.
            restore_current_blog();
            echo '</ul>';
            echo $after_widget;
        }
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-multisite-widget.php.

------------------------------------------------------------------------

Utworzenie nowej witryny

Nowe witryny w sieci Multisite możesz bardzo łatwo tworzyć, korzystając
z kokpitu obszaru administracyjnego WordPress. Co jednak zrobić w
sytuacji, jeśli nowa witryna ma być utworzona za pomocą wtyczki? Jak
zwykle, do tego celu musisz zastosować odpowiednią, istniejącą już
funkcję o nazwie wpmu_create_blog().

    <?php wpmu_create_blog( $domain, $path, $title, $user_id, $meta, $blog_id ); ?> 

Funkcja przyjmuje sześć parametrów. Oto one.

-   $domain — domena dla nowej witryny.
-   $path — ścieżka dostępu do nowej witryny. W zależności od
    konfiguracji to będzie podkatalog lub subdomena.
-   $title — tytuł nowej witryny.
-   $user_id — identyfikator konta użytkownika, który będzie
    administratorem tej witryny.
-   $meta — dodatkowe informacje meta.
-   $blog_id — identyfikator bloga dla tworzonej witryny.

Tylko pierwsze cztery parametry są wymagane, dwa pozostałe są
opcjonalne. Jeżeli utworzenie nowej witryny zakończy się powodzeniem,
wartością zwrotną funkcji będzie nowo utworzony identyfikator bloga.

Jak zauważyłeś, prefiksem funkcji jest wpmu_. Wiele funkcji sieci
Multisite należało kiedyś do WordPress MU, zanim obie bazy kodu zostały
połączone. Nazwy takich funkcji mogą zawierać wpmu lub blog, co ma na
celu zapewnienie wstecznej zgodności.

Poniżej przedstawiono przykład wtyczki pozwalającej użytkownikom na
tworzenie witryn w sieci Multisite. Pierwszym krokiem jest zbudowanie
własnego menu najwyższego poziomu dla strony wtyczki.

    <?php
    add_action( 'admin_menu', 'boj_multisite_create_menu' );
    function boj_multisite_create_menu() {
        // Utworzenie własnego menu najwyższego poziomu.
        add_menu_page( ' Utworzenie witryny w sieci Multisite',
            'Utworzenie witryny w sieci Multisite',
            'manage_options', 'boj-network-create',
                'boj_multisite_create_sites_page' );
    }
    ?> 

Kolejnym krokiem jest zbudowanie funkcji wyświetlającej formularz
tworzenia nowej witryny.

    <?php
    function boj_multisite_create_sites_page() {
        // Sprawdzenie, czy włączono obsługę sieci Multisite.
        if ( is_multisite() ) { 
    ?>

Jak zawsze, przed użyciem jakiejkolwiek funkcji przeznaczonej dla sieci
Multisite należy sprawdzić, czy obsługa sieci Multisite została
włączona. Następnie trzeba dodać kod pobierający pola wysłanego
formularza oraz tworzący nową witrynę w sieci Multisite na podstawie
pobranych wartości:

    <?php
    // Jeżeli formularz został wysłany, wówczas należy go przetworzyć.
        if ( isset( $_POST['create_site'] ) ) {
            // Ustawienie wartości zmiennych na podstawie wartości podanych w formularzu.
            $domain = esc_html( $_POST['domain'] );
            $path = esc_html( $_POST['path'] );
            $title = esc_html( $_POST['title'] );
            $user_id = absint( $_POST['user_id'] );
            // Sprawdzenie, czy wymagane wartości zostały ustawione.
            if ( $domain && $path && $title && $user_id ) {
                // Utworzenie nowej witryny na platformie WordPress.
                $new_site = wpmu_create_blog( $domain, $path, $title, $user_id );
                // Wyświetlenie komunikatu w przypadku operacji zakończonej sukcesem.
                if ( $new_site ) {
                    echo '<div class="updated" >Nowa witryna '
                        .$new_site. ' została utworzona z powodzeniem!</div>';
                }
                // Wyświetlenie komunikatu błędu, jeśli wymagane wartości nie zostały ustawione.
                } else {
                    echo '<div class="error"> 
                        Nowa witryna nie mogła zostać utworzona.
                        Nie podano wymaganych wartości.</div>';
                }
            }
    ?> 

W powyższym fragmencie kodu pierwszym krokiem jest sprawdzenie, czy
istnieje wartość $_POST['create_site']. Wymieniona wartość będzie
istniała tylko wtedy, gdy formularz został wysłany. Następnie na
podstawie wartości podanych w formularzu następuje ustawienie zmiennych.
Warto zwrócić uwagę na użycie odpowiednich funkcji oczyszczających dane
użytkownika przekazane w formularzu.

Kolejnym krokiem jest sprawdzenie ustawienia wartości zmiennych $domain,
$path, $title oraz $user_id, ponieważ są one wymagane podczas tworzenia
nowej witryny za pomocą funkcji wpmu_create_blog(). Jeżeli wymienione
wartości nie zostały ustawione, na ekranie będzie wyświetlony komunikat
błędu. Po upewnieniu się, że wartości istnieją, następuje wywołanie
funkcji wpmu_create_blog() i utworzenie nowej witryny. Po pomyślnym
utworzeniu nowej witryny zmienna $new_site będzie zawierała jej
identyfikator, a na ekranie zostanie wyświetlony odpowiedni komunikat.

Ostatni fragment kodu jest odpowiedzialny za utworzenie formularza
pozwalającego na podanie opcji nowo tworzonej witryny.

            <div class="wrap">
                <h2>Tworzenie nowej witryny</h2>
                <form method="post">
                <table class="form-table">
                <tr valign="top"> 
                    <th scope="row"><label for="fname">Domena</label></th> 
                    <td><input maxlength="45" size="25" name="domain" 
                        value="<?php echo DOMAIN_CURRENT_SITE; ?>" /></td> 
                </tr>
                <tr valign="top"> 
                    <th scope="row"><label for="fname">Ścieżka dostępu</label></th> 
                    <td><input maxlength="45" size="10" name="path" /></td> 
                </tr>
                <tr valign="top"> 
                    <th scope="row"><label for="fname">Tytuł</label></th> 
                    <td><input maxlength="45" size="25" name="title" /></td> 
                </tr>
                <tr valign="top"> 
                    <th scope="row"><label for="fname">Identyfikator użytkownika</label></th> 
                    <td><input maxlength="45" size="3" name="user_id" /></td> 
                </tr>
                <tr valign="top"> 
                    <td>
                    <input type="submit" name="create_site" 
                        value="Utwórz witrynę" class="button-primary" /> 
                    <input type="submit" name="reset" value="Wyczyść" class="button-secondary" />
                    </td> 
                </tr>
                </table>
                </form>
            </div>

Powyżej przedstawiono całkiem prosty formularz sieciowy, który służy do
podania parametrów nowo tworzonej witryny.

Pełny kod źródłowy wtyczki przedstawia się następująco.

    <?php
    /*
    Plugin Name: Utworzenie witryny w sieci Multisite
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka demonstruje tworzenie witryn w sieci Multisite.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    add_action( 'admin_menu', 'boj_multisite_create_menu' );
    function boj_multisite_create_menu() {
        // Utworzenie własnego menu najwyższego poziomu.
        add_menu_page( ' Utworzenie witryny w sieci Multisite',
            'Utworzenie witryny w sieci Multisite',
            'manage_options', 'boj-network-create',
                'boj_multisite_create_sites_page' );
    }
    function boj_multisite_create_sites_page() {
        // Sprawdzenie, czy włączono obsługę sieci Multisite.
        if ( is_multisite() ) {
            // Jeżeli formularz został wysłany, wówczas należy go przetworzyć.
            if ( isset( $_POST['create_site'] ) ) {
                // Ustawienie wartości zmiennych na podstawie wartości podanych w formularzu.
                $domain = esc_html( $_POST['domain'] );
                $path = esc_html( $_POST['path'] );
                $title = esc_html( $_POST['title'] );
                $user_id = absint( $_POST['user_id'] );
                // Sprawdzenie, czy wymagane wartości zostały ustawione.
                if ( $domain && $path && $title && $user_id ) {
                    // Utworzenie nowej witryny na platformie WordPress.
                    $new_site = wpmu_create_blog( $domain, $path, $title, $user_id );
                    // Wyświetlenie komunikatu w przypadku operacji zakończonej sukcesem.
                    if ( $new_site ) {
                        echo '<div class="updated" >Nowa witryna '
                            .$new_site. ' została utworzona z powodzeniem! </div>';
                    }
                    // Wyświetlenie komunikatu błędu, jeśli wymagane wartości nie zostały ustawione.
                    } else {
                        echo '<div class="error"> 
                            Nowa witryna nie mogła zostać utworzona.
                            Nie podano wymaganych wartości.</div>';
                    }
                }
                ?>
                <div class="wrap">
                    <h2>Tworzenie nowej witryny</h2>
                    <form method="post">
                    <table class="form-table">
                    <tr valign="top"> 
                        <th scope="row"><label for="fname">Domena</label></th> 
                        <td><input maxlength="45" size="25" name="domain" 
                            value="<?php echo DOMAIN_CURRENT_SITE; ?>" /></td> 
                    </tr>
                    <tr valign="top"> 
                        <th scope="row"><label for="fname">Ścieżka dostępu</label></th> 
                        <td><input maxlength="45" size="10" name="path" /></td> 
                    </tr>
                    <tr valign="top"> 
                        <th scope="row"><label for="fname">Tytuł</label></th> 
                        <td><input maxlength="45" size="25" name="title" /></td> 
                    </tr>
                    <tr valign="top"> 
                        <th scope="row"><label for="fname">
                            Identyfikator użytkownika</label>
                        </th> 
                        <td><input maxlength="45" size="3" name="user_id" /></td> 
                    </tr>
                    <tr valign="top"> 
                        <td>
                        <input type="submit" name="create_site" 
                            value="Utwórz witrynę" class="button-primary" /> 
                        <input type="submit" name="reset" 
                            value="Wyczyść" class="button-secondary" />
                        </td> 
                    </tr>
                    </table>
                    </form>
                </div>
                <?php
        } else {
            echo '<p>Obsługa sieci Multisite nie została włączona.</p>';
        }
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-multisite-create-site.php.

------------------------------------------------------------------------

Istnieje również łatwa metoda uaktualnienia stanu witryny. To jest
użyteczna możliwość, jeżeli trzeba dynamicznie zarchiwizować witrynę lub
oznaczyć ją jako spam. Uaktualnienie stanu witryny jest przeprowadzane
za pomocą funkcji update_blog_status().

    <?php update_blog_status( $blog_id, $pref, $value, $refresh ); ?> 

Funkcja akceptuje cztery parametry:

-   $blog_id — identyfikator witryny, której stan ma być uaktualniony;
-   $pref — typ stanu do uaktualnienia;
-   $value — nowa wartość stanu;
-   $refresh — ten parametr określa, czy odświeżyć bufor informacji
    szczegółowych o witrynie.

Pierwsze trzy parametry są wymagane. Parametr $pref to stan do
uaktualnienia i akceptuje wartości site_id, domain, path, registered,
last_updated, public, archived, mature, spam, deleted oraz lang_id. W
przedstawionym poniżej fragmencie kodu witryna w sieci Multisite będzie
zarchiwizowana.

    <?php
    update_blog_status( $blog_id, 'archived', 1 );
    ?> 

Opcje witryny sieci Multisite

Opcje w sieci Multisite są przechowywane podobnie jak w standardowej
konfiguracji WordPress, choć używa się nich innego zestawu funkcji. Oto
on.

-   add_blog_option() — utworzenie nowej opcji.
-   update_blog_option() — uaktualnienie opcji i utworzenie jej, jeśli
    jeszcze nie istnieje.
-   get_blog_option() — wczytanie istniejącej opcji witryny.
-   delete_blog_option() — usunięcie opcji witryny.

Podstawowa różnica pomiędzy wymienionym zestawem funkcji i standardowymi
polega na tym, że każdej z powyższych funkcji trzeba przekazać parametr
w postaci identyfikatora bloga. Następnie funkcja przejdzie do wskazanej
witryny, obsłuży zadanie związane z opcją i na końcu powróci do bieżącej
witryny.

    <?php add_blog_option( $blog_id, $key, $value ); ?> 

Parametr $blog_id oznacza identyfikator witryny, do której ma zostać
dodana opcja. Parametr $key to nazwa opcji przeznaczonej do dodania,
natomiast $value to wartość nowej opcji.

Wczytanie opcji witryny jest równie łatwe. Za pomocą funkcji
get_blog_option() można wczytać dowolną, wymaganą opcję danej witryny.

    <?php
    $blog_id = 3;
    echo '<p>Identyfikator witryny: '.$blog_id .'</p>';
    echo '<p>Nazwa witryny: ' .get_blog_option( $blog_id, 'blogname' )
        .'</p>';
    echo '<p>Adres URL witryny: ' .get_blog_option( $blog_id, 'siteurl' ) .'</p>';
    ?> 

Użytkownicy w sieci

Użytkownicy w sieci Multisite działają nieco inaczej niż w standardowej
konfiguracji platformy WordPress. Jeżeli w ustawieniach sieciowych
włączono opcję pozwalającą na rejestrację nowych użytkowników, wówczas
odwiedzający witrynę będą mieli możliwość rejestracji nowych kont na
platformie WordPress. Podstawowa różnica polega na tym, że każda witryna
w danej sieci Multisite może posiadać odmienny zbiór użytkowników. W
poszczególnych witrynach sieci sami użytkownicy mogą również mieć
przyznane różne role. Użytkownik nie staje się automatycznie członkiem
wszystkich witryn w danej sieci Multisite, ale tylko witryny głównej
(pierwszej). Jeśli przykładowo sieć Multisite składa się z dwóch witryn
Halo Blog i Tekken Blog, rejestrujący się użytkownik będzie członkiem
witryny Halo Blog, ale już nie Tekken Blog.

Przed wykonaniem jakiegokolwiek kodu charakterystycznego dla danej
witryny należy sprawdzić, czy zalogowany użytkownik jest członkiem danej
witryny. Po włączeniu obsługi sieci Multisite programista otrzymuje
wiele funkcji pozwalających na pracę z użytkownikami. Aby sprawdzić, czy
użytkownik jest członkiem, należy użyć funkcji is_blog_user():

    <?php is_blog_user( $blog_id ) ?> 

Funkcja akceptuje jeden parametr, czyli $blog_id, który jest opcjonalny.
Jeżeli parametr nie zostanie podany, wartością domyślną jest
identyfikator bieżącego bloga.

    <?php
    if ( is_blog_user() ) {
        // Użytkownik jest członkiem tej witryny.
    }
    ?> 

Istnieje również możliwość wskazania identyfikatora bloga, jeśli trzeba
sprawdzić, czy użytkownik jest członkiem innej witryny w sieci
Multisite:

    <?php
    if ( is_blog_user( 3 ) ) {
        // Użytkownik jest członkiem witryny o identyfikatorze 3.
    }
    ?> 

Po poznaniu sposobów sprawdzania, czy użytkownik jest członkiem witryny,
warto dowiedzieć się, jak można dodać członków do witryny. W sieci
Multisite funkcja add_user_to_blog() powoduje dodanie dowolnego
użytkownika WordPress do wskazanej witryny sieci.

    <?php add_user_to_blog( $blog_id, $user_id, $role ); ?> 

Funkcja akceptuje trzy parametry:

-   $blog_id — identyfikator witryny, do której ma zostać dodany
    użytkownik;
-   $user_id — identyfikator użytkownika przeznaczonego do dodania;
-   $role — rola użytkownika, który będzie się znajdował w danej
    witrynie.

Oto przykład:

    <?php
    $blog_id = 18;
    $user_id = 4;
    $role = 'editor';
    add_user_to_blog( $blog_id, $user_id, $role );
    ?> 

Teraz zajmiemy się utworzeniem przykładowej wtyczki, której zadaniem
będzie automatyczne dodanie zalogowanych użytkowników do wszystkich
odwiedzanych przez nich witryn sieci Multisite. To użyteczne
rozwiązanie, jeśli użytkownicy mają się stać członkami wszystkich witryn
sieci Multisite; nie wymaga ich ręcznego dodawania do każdej z osobna.

Pierwszym krokiem jest wykorzystanie zaczepu akcji init do wywołania
własnej funkcji odpowiedzialnej za dodawanie użytkowników do witryny:

    <?php
    add_action( 'init', 'boj_multisite_add_user_to_site' );
    ?> 

Kolejnym krokiem jest utworzenie funkcji
boj_multisite_add_user_to_site(), która dodaje użytkowników.

    <?php
    function boj_multisite_add_user_to_site() {
        // Przed przejściem dalej trzeba sprawdzić, czy użytkownik jest zalogowany.
        if( !is_user_logged_in() )
            return false;
        // Wczytanie identyfikatora bieżącego bloga oraz danych użytkownika.
        global $current_user, $blog_id;
        // Sprawdzenie, czy użytkownik nie jest członkiem tej witryny.
        if( !is_blog_user() ) {
            // Dodanie użytkownika do witryny jako subskrybenta.
            add_user_to_blog( $blog_id, $current_user->ID, 'subscriber' );
        }
    }
    ?> 

Pierwsze zadanie wykonywane w powyższym kodzie to sprawdzenie, czy
użytkownik jest zalogowany. Jeżeli nie, wartością zwrotną funkcji będzie
false, a sama funkcja zakończy działanie. Po potwierdzeniu, że
użytkownik jest zalogowany, następuje wywołanie zmiennych globalnych
$current_user i $blog_id. Wymienione zmienne przechowują dane aktualnie
zalogowanego użytkownika oraz identyfikator bloga w danej chwili
odwiedzanego przez użytkownika. Kolejnym zadaniem jest potwierdzenie, że
użytkownik jest już członkiem przeglądanego bloga. Jeśli użytkownik jest
już członkiem bloga, nie ma powodu, aby ponownie dodawać go do witryny.

Ostatnim krokiem jest dodanie użytkownika do witryny za pomocą funkcji
add_user_to_blog(). Przekazywane funkcji informacje to identyfikator
bloga, identyfikator bieżącego użytkownika oraz rola, w której
użytkownik będzie znajdował się na stronie (w omawianym przykładzie to
rola o nazwie Subskrybent). To już wszystko! Aby ta wtyczka działała w
całej sieci Multisite, trzeba ją umieścić w katalogu /mu-plugins lub
aktywować wtyczkę w sieci na stronie Administracja siecią/Wtyczki. To
wymusi działanie wtyczki na wszystkich witrynach sieci Multisite.

Poniżej przedstawiono pełny kod wtyczki.

    <?php
    /*
    Plugin Name: Automatyczne dodawanie użytkownika do witryny sieci Multsite
    Plugin URI: http://przyklad.pl/wtyczki-wordpress/moja-wtyczka
    Description: Wtyczka automatycznie dodaje użytkownika do każdej odwiedzanej przez niego witryny.
    Version: 1.0
    Author: Brad Williams
    Author URI: http://wrox.com
    License: GPLv2
    */
    add_action( 'init', 'boj_multisite_add_user_to_site' );
    function boj_multisite_add_user_to_site() {
        // Przed przejściem dalej trzeba sprawdzić, czy użytkownik jest zalogowany.
        if( !is_user_logged_in() )
            return false;
        // Wczytanie identyfikatora bieżącego bloga oraz danych użytkownika.
        global $current_user, $blog_id;
        // Sprawdzenie, czy użytkownik nie jest członkiem tej witryny.
        if( !is_blog_user() ) {
            // Dodanie użytkownika do witryny jako Subskrybenta.
            add_user_to_blog( $blog_id, $current_user->ID, 'subscriber' );
        }
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-multisite-add-users.php.

------------------------------------------------------------------------

Równie łatwo można usuwać użytkowników z danej witryny. Służy do tego
funkcja o nazwie remove_user_from_blog().

    <?php remove_user_from_blog( $user_id, $blog_id, $reassign ); ?> 

Funkcja akceptuje trzy parametry:

-   $user_id — identyfikator użytkownika, który ma zostać usunięty z
    witryny;
-   $blog_id — identyfikator bloga, z którego ma zostać usunięty
    użytkownik;
-   $reassign — identyfikator użytkownika, któremu mają zostać
    przypisane wpisy bloga usuniętego użytkownika.

Oto przykład:

    <?php
    $user_id = 4;
    $blog_id = 18;
    $reassign = 1;
    remove_user_from_blog( $user_id, $blog_id, $reassign );
    ?> 

------------------------------------------------------------------------

Uwaga

Pamiętaj, że dodawanie i usuwanie użytkowników z witryny w sieci
Multisite nie powoduje w rzeczywistości utworzenia bądź usunięcia
użytkownika na platformie WordPress, ale jego dodanie lub usunięcie jako
członka danej witryny.

------------------------------------------------------------------------

Inną funkcją, która przydaje się podczas pracy z użytkownikami w sieci
Multisite, jest get_blogs_of_user(). Funkcja pobiera informacje o
wszystkich witrynach, których członkiem jest wskazany użytkownik.

    <?php
    $user_id = 1;
    $user_sites = get_blogs_of_user( $user_id );
    print_r( $user_sites );
    ?> 

Uruchomienie powyższego fragmentu kodu spowoduje zwrócenie poniższego
obiektu tablicy:

    Array
    (
        [1] => stdClass Object
            (
                [userblog_id] => 1
                [blogname] => Witryna główna
                [domain] => przyklad.pl
                [path] => /
                [site_id] => 1
                [siteurl] => http://przyklad.pl
            )
        [2] => stdClass Object
            (
                [userblog_id] => 2
                [blogname] => Halloween Revenge
                [domain] => przyklad.pl
                [path] => /myers/
                [site_id] => 1
                [siteurl] => http://przyklad.pl/myers
            )
        [8] => stdClass Object
            (
                [userblog_id] => 8
                [blogname] => Freddy żyje!
                [domain] => przyklad.pl
                [path] => /kruger/
                [site_id] => 1
                [siteurl] => http://przyklad.pl/kruger
            )
    ) 

Istnieje możliwość użycia pętli foreach w celu wyświetlenia określonych
danych z tablicy:

    <?php
    $user_id = 1;
    $user_sites = get_blogs_of_user( $user_id );
    foreach ( $user_sites AS $user_site ) {
        echo '<p>'.$user_site->siteurl .'</p>';
    }
    ?> 

Rola Superadministratora w sieci Multisite

Sieć Multisite wprowadza nową rolę o nazwie Superadministrator.
Użytkownicy w tej roli mają dostęp do sekcji Administracja siecią na
platformie WordPress. W sekcji znajdują się wszystkie ustawienia
sieciowe, motywy, wtyczki itd. Użytkownik w roli Superadministratora ma
również pełną kontrolę nad każdą witryną sieci Multisite, podczas gdy
zwykły administrator może jedynie zarządzać określonymi witrynami.

W sieci Multisite istniejącym użytkownikom można bardzo łatwo przypisać
rolę Superadministratora poprzez użycie funkcji grant_super_admin().
Funkcja akceptuje tylko jeden parametr — identyfikator użytkownika,
któremu mają zostać nadane uprawnienia.

    <?php
    $user_id = 4;
    grant_super_admin( $user_id );
    ?> 

Nadane uprawnienia można również bardzo łatwo odebrać, używając w tym
celu funkcji revoke_super_admin(). Ta funkcja również akceptuje tylko
jeden parametr — identyfikator użytkownika, któremu mają zostać odebrane
uprawnienia.

    <?php
    $user_id = 4;
    revoke_super_admin( $user_id );
    ?> 

Obie funkcje są zdefiniowane w pliku wp-admin/includes/ms.php. Oznacza
to, że nie są domyślnie dostępne na stronach publicznych witryny i mogą
być stosowane jedynie w obszarze administracyjnym. Jeśli przykładowo
spróbujesz wywołać dowolną z wymienionych funkcji w utworzonym skrócie,
zobaczysz wygenerowany komunikat błędu informujący o niezdefiniowanej
funkcji PHP.

Aby wyświetlić listę wszystkich użytkowników z uprawnieniami
Superadministratora, należy wywołać funkcję get_super_admins(). Funkcja
zwraca tablicę zawierającą nazwy wszystkich użytkowników sieci Multisite
z uprawnieniami Superadministratora.

    <?php
    $all_admins = get_super_admins();
    print_r( $all_admins );
    ?> 

Powyższy fragment kodu spowoduje zwrócenie przedstawionej poniżej
tablicy:

    Array
    (
        [0] => admin
        [1] => robert
    ) 

Bardzo łatwo można również sprawdzić użytkownika o określonym
identyfikatorze i przekonać się, czy ma uprawnienia Superadministratora
w danej sieci Multisite.

    <?php
    $user_id = 1;
    if ( is_super_admin( $user_id ) ) {
        echo 'Użytkownik ma uprawnienia Superadministrator';
    }
    ?> 

Sprawdzenie właściciela witryny

Każda witryna w sieci Multisite ma swojego właściciela. Właściciel jest
definiowany przy użyciu administracyjnego adresu e-mail, przechowywanego
w opcjach witryny i podawanego podczas tworzenia nowej witryny w sieci.
Jeżeli witryna pozwala na zakładanie nowych kont użytkowników, wówczas
użytkownik, który założył daną witrynę, jest jej właścicielem. Jeżeli
utworzyłeś witrynę z poziomu kokpitu, adres e-mail właściciela możesz
podać w trakcie budowania witryny.

W pewnych sytuacjach być może trzeba będzie sprawdzić, kto jest
właścicielem witryny oraz powiązanych z nią danych. Do tego celu służy
przedstawiony poniżej fragment kodu:

    <?php
    $blog_id = 3;
    $admin_email = get_blog_option( $blog_id, 'admin_email' );
    $user_info = get_user_by( 'email', $admin_email );
    print_r( $user_info );
    ?> 

Najpierw za pomocą funkcji get_blog_option() następuje pobranie wartości
admin_email dla bloga o identyfikatorze 3. Następnie funkcja
get_user_by() pobiera dane użytkownika, bazując na odczytanym wcześniej
adresie e-mail. Funkcja pozwala na pobranie danych użytkownika na
podstawie jego identyfikatora, adresu e-mail lub nazwy użytkownika. W
omawianym przypadku wykorzystano adres e-mail. Otrzymane dane zostały
przedstawione poniżej:

    stdClass Object
    (
        [ID] => 3
        [user_login] => freddy
        [user_pass] => $P$B0VRNh0UbN/4YqMFB8fl3OZM2FGKfg1
        [user_nicename] => Freddy Krueger
        [user_email] => freddy@przyklad.pl
        [user_url] = > 
        [user_registered] => 2011-10-31 19:00:00
        [user_activation_key] = > 
        [user_status] => 0
        [display_name] => Freddy
        [spam] => 0
        [deleted] => 0
        [first_name] => Freddy
        [last_name] => Krueger
        [nickname] => fredster
        [description] = > 
        [rich_editing] => true
        [comment_shortcuts] => false
        [admin_color] => fresh
        [use_ssl] => 0
        [aim] = > 
        [yim] = > 
        [jabber] = > 
        [source_domain] => przyklad.pl
        [primary_blog] => 3
        [wp_3_capabilities] => Array
            (
                [administrator] => 1
            )
        [wp_3_user_level] => 10
        [user_firstname] => Freddy
        [user_lastname] => Krueger
        [user_description] = > 
    ) 

Jak możesz zobaczyć, powyższe dane zawierają wiele użytecznych
informacji dotyczących użytkownika.

Dane statystyczne dotyczące sieci

Sieć Multisite oferuje kilka funkcji, które generują dane statystyczne
dotyczące sieci. Wartością zwrotną funkcji get_user_count() jest
całkowita liczba użytkowników zarejestrowanych na platformie WordPress.
Z kolei funkcja get_blog_count() podaje całkowitą liczbę witryn w sieci
Multisite. Obie te wartości można pobrać za jednym razem, wywołując
funkcję get_sitestats(), która zwraca tablicę.

    <?php
    $user_count = get_user_count();
    echo '<p>Całkowita liczba użytkowników: ' .$user_count .'</p>';
    $blog_count = get_blog_count();
    echo '<p>Całkowita liczba witryn: ' .$blog_count .'</p>';
    $network_stats = get_sitestats();
    print_r( $network_stats );
    ?> 

Schemat bazy danych sieci Multisite

Sieć Multisite stosuje inny schemat bazy danych niż standardowa
konfiguracja platformy WordPress. Podczas uaktualniania lub włączania
sieci Multisite platforma WordPress tworzy w bazie danych niezbędne
tabele wymagane do obsługi sieci Multisite.

Tabele stosowane w sieci Multisite

Platforma WordPress przechowuje globalne ustawienia sieci Multisite w
scentralizowanych tabelach. Wspomniane tabele, oprócz wp_users i
wp_usermeta, powstają jedynie podczas instalacji i aktywacji sieci
Multisite.

-   wp_blogs — tabela przechowuje każdą witrynę utworzoną w sieci
    Multisite.
-   wp_blog_versions — tabela przechowuje bieżącą wersję bazy danych
    każdej witryny w sieci Multisite.
-   wp_registration_log — tabela przechowuje dzienniki zdarzeń dotyczące
    wszystkich użytkowników zarejestrowanych i aktywowanych na
    platformie WordPress.
-   wp_signups — tabela przechowuje użytkowników i witryny
    zarejestrowane za pomocą procesu rejestracji platformy WordPress.
-   wp_site — tabela przechowuje informacje dotyczące adresu witryny
    podstawowej.
-   wp_sitecategories — jeżeli wyrażenia globalne są włączone, będą
    przechowywane w tej tabeli.
-   wp_sitemeta — tabela przechowuje dane różnych opcji witryny
    podstawowej, włącznie z kontami użytkowników z uprawnieniami
    Superadministrator.
-   wp_users — tabela przechowuje wszystkich użytkowników
    zarejestrowanych na platformie WordPress.
-   wp_usermeta — tabela przechowuje wszystkie metadane dla kont
    użytkowników platformy WordPress.

Prawdopodobnie zwróciłeś uwagę na brak na powyższej liście pewnych
ważnych tabel platformy WordPress. Pozostałe tabele tworzone dla sieci
Multisite są tabelami przeznaczonymi dla konkretnych witryn.

Tabele przeznaczone dla konkretnych witryn

Każda witryna w sieci Multisite zawiera przeznaczone wyłącznie dla niej
tabele. Przechowują one treść oraz ustawienia danej witryny. Pamiętaj,
że te tabele mają prefiks $table_prefix zdefiniowany w pliku
wp-config.php, po którym znajduje się identyfikator bloga ($blog_id), a
dopiero później nazwa tabeli. Oto te tabele:

-   wp_1_commentmeta,
-   wp_1_comments,
-   wp_1_links,
-   wp_1_options,
-   wp_1_postmeta,
-   wp_1_posts,
-   wp_1_terms,
-   wp_1_term_relationships,
-   wp_1_term_taxonomy.

Jak możesz zobaczyć, wymienione powyżej tabele mogą doprowadzić do
szybkiego wzrostu wielkości bazy danych. Z tego powodu jedynym
ograniczeniem sieci Multisite na platformie WordPress są zasoby serwera
WWW dostępne dla sieci. Jeżeli Twoja sieć zawiera 1000 witryn, w bazie
danych może znajdować się ponad 9000 tabel. Oczywiście, umieszczenie
takiej sieci na współdzielonym serwerze WWW nie będzie najlepszym
pomysłem.

Podsumowanie

Sieć Multisite na platformie WordPress daje nieograniczone możliwości;
jej włączenie pozwala na utworzenie zapierającej dech w piersiach sieci.
To również nowe możliwości dla tworzonych wtyczek, które mogą zawierać
funkcje zapewniające obsługę sieci Multisite.

Wtyczki budowane dla platformy WordPress trzeba testować w sieci
Multisite, aby zapewnić ich zgodność z tym środowiskiem. Obecnie sieć
Multisite można włączyć w każdej instalacji WordPress, więc coraz
większa grupa użytkowników decyduje się na konwersję standardowej
witryny na konfigurację zapewniającą obsługę Multisite. W ten sposób
będą mogli wykorzystać zalety szybkiego rozwoju i możliwości sieci.

Rozdział 16 Usuwanie błędów i optymalizacja

W tym rozdziale:

-   Uaktualnianie platformy WordPress
-   Usuwanie błędów z wtyczek
-   Rejestrowanie błędów
-   Buforowanie danych w celu zapewnienia optymalnej wydajności

Usuwanie błędów oraz optymalizację kodu można przeprowadzać na wiele
sposobów. W platformie WordPress zaimplementowano wiele prostych w
użyciu narzędzi, które ułatwiają pracę programistom. Jeden z
największych problemów polega na tym, że wielu twórców wtyczek po prostu
nie stosuje tych łatwych technik, co pozostawia sporo miejsca na
wprowadzenie ewentualnych usprawnień.

W tym rozdziale dowiesz się, jak uaktualnić starszą wersję platformy
WordPress, usuwać błędy z tworzonych wtyczek oraz buforować
(przechowywać) dane w celu ich późniejszego użycia. W tym rozdziale
omówiono całkiem proste funkcje, których stosowanie może przyczynić się
do poprawy jakości wtyczek.

Zapewnienie (lub nie) obsługi starszych wersji

Jako programista często myślisz, że powinieneś zapewnić wsteczną
zgodność ze starszymi wersjami oprogramowania. To najczęściej ma sens,
gdyż prowadzi do zwiększenia grupy zadowolonych użytkowników.

Jednak stosowana przez twórców platformy WordPress filozofia zapewnienia
zgodności jest całkiem inna. W społeczności programistów WordPress
czasami wręcz gardzi się możliwością zachowania wstecznej zgodności. Od
użytkowników oczekuje się wykorzystywania najnowszej wersji platformy.
Wspomniana filozofia sprowadza się do kilku kluczowych kwestii.

-   Użytkownicy są "ponaglani" do aktualizacji oprogramowania poprzez
    wyświetlanie odpowiedniego komunikatu na górze strony
    administracyjnej WordPress.
-   Istnieje wiele sposobów przeprowadzenia aktualizacji oprogramowania.
    Sam proces może sprowadzać się do jedynie kilku kliknięć myszą w
    obszarze administracyjnym platformy WordPress.
-   Jądro platformy WordPress jest uaktualniane dość często, zwykle co
    trzy, cztery miesiące.
-   Twórcy platformy WordPress nie oferują uaktualnień bezpieczeństwa
    dla starszych wersji oprogramowania. Używanie najnowszej wersji to
    jedyna gwarancja posiadania najbezpieczniejszego wydania platformy
    WordPress.

Z tych samych powodów programiści powinni oczekiwać od użytkowników
uaktualniania oprogramowania do najnowszych dostępnych wersji.

Zbyt duża rozpiętość między wersjami wtyczki wydanej przez programistę i
używanej przez użytkownika również nie jest dobra. Dobrą praktyką jest
zapewnienie pewnej zgodności wstecz, co daje użytkownikom czas na
przeprowadzenie uaktualnienia do nowszej wersji WordPress. Zalecaną
regułą jest zapewnienie wstecznej zgodności z jedną główną wersją
wstecz. W ten sposób programista może na bieżąco wykorzystywać nowe
funkcje oferowane przez platformę WordPress, a jednocześnie użytkownicy
mają trzy, cztery miesiące na przeprowadzenie uaktualnienia
oprogramowania platformy.

Niektóre wtyczki po prostu będą zgodne wstecz, ponieważ nie zastosowano
w nich żadnych nowych funkcji. Gdy jednak we wtyczce wykorzystano
funkcje wprowadzone w nowej wersji platformy, wówczas przed ich
wywołaniem można użyć funkcji PHP o nazwie function_exists() w celu
sprawdzenia, czy użytkownik korzysta z najnowszej wersji oprogramowania.

Przypuśćmy, że chcesz użyć funkcji get_users() platformy WordPress w
wersji 3.1, ale jednocześnie chcesz zachować wsteczną zgodność z
wydaniem WordPress 3.0. W takim przypadku Twój kod może mieć postać:

    <?php
    /* Jeżeli funkcja get_users() jest dostępna. */
    if ( function_exists( 'get_users' ) ) {
        /* Używamy funkcji get_users(). */
        $users = get_users();
    }
    /* Jeżeli funkcja get_users() nie jest dostępna. */
    else {
        /* Zastosowanie innych funkcji. */
    }
    ?> 

W powyższym fragmencie kodu użyto funkcji function_exists() w celu
sprawdzenia, czy istnieje funkcja get_users(). Jeżeli istnieje,
użytkownik korzysta z oprogramowania platformy WordPress w wersji 3.1
lub nowszej i we wtyczce można zastosować funkcję get_users(). Jeżeli
sprawdzana funkcja nie istnieje, wtyczka powinna zapewnić alternatywny
sposób wykonania danego zadania.

Aktualizacja oprogramowania zgodnie z cyklem rozwojowym WordPress

Aby zostać uznanym twórcą wtyczki dla platformy WordPress, musisz
pamiętać, że najważniejsza jest aktualizacja oprogramowania zgodnie z
cyklem rozwojowym WordPress. Platforma WordPress jest nieustannie
rozwijana. Praktycznie każdego dnia osoby pracujące nad kodem platformy
wprowadzają poprawki, rozwiązują istniejące problemy, dodają nowe
funkcje lub proponują nowe, różne pomysły na przyszłość. To jest
przecież duża, aktywna społeczność.

Minimalnym wymaganiem jest więc stosowanie najnowszej dostępnej wersji
oprogramowania platformy WordPress, co zapewnia wymienione poniżej
korzyści.

-   Dostarczanie nowych funkcji.
-   Wiedza o tym, że stare funkcje zostały uznane za zbędne lub
    usunięte.
-   Znalezienie ewentualnego błędu WordPress, który może wpływać na
    działanie tworzonej wtyczki.

Wykorzystywanie bieżącej wersji oprogramowania WordPress ma znaczenie
krytyczne podczas tworzenia najlepszych wtyczek. Czasami zdarza się, że
po wprowadzeniu nowych funkcji kod wtyczki można skrócić o wiele
zbędnych w tym momencie wierszy kodu. Po uznaniu pewnych funkcji
WordPress za zbędne można oczyścić kod wtyczki i zastąpić go nowo
wprowadzonymi funkcjami. Ponadto można sobie ułatwić pracę, bo nie
trzeba zajmować się tworzeniem obejść dla błędów znalezionych w
WordPress, które mogłyby wstrzymać prace nad wtyczką.

Warto również wiedzieć, w jaki sposób nowe wydania są obsługiwane przez
platformę WordPress. Zrozumienie tej prostej koncepcji pozwoli
prawidłowo określić, kiedy trzeba przejrzeć wtyczki i zastanowić się,
czy ich aktualizacja jest niezbędna. Istnieją dwa typy wydań: główne i
mniejsze.

-   Wydania główne mają postać 3.0, 3.1, 3.2 itd. Są dostępne co kilka
    miesięcy i oferują nowe funkcje oraz są pozbawione znalezionych
    błędów. Wydanie główne wiąże się także ze zmianami wprowadzonymi w
    kodzie.
-   Wydania mniejsze pojawiają się między wydaniami głównymi. Tak więc
    pomiędzy wydaniami 3.1 i 3.2 mogą pojawić się wydania 3.1.1, 3.1.2
    itd. Tego rodzaju wydania to, ogólnie rzecz biorąc, poprawki
    znalezionych błędów oraz usuwanie wykrytych luk w zabezpieczeniach,
    a nowe funkcje rzadko są dodawane.

Zaangażowanie w społeczność WordPress może pomóc podczas prac nad
wtyczkami. Wiele witryn internetowych i blogów opisuje zagadnienia
programistyczne i bieżące trendy na platformie WordPress. Jednak
najważniejszym miejscem do odwiedzania, które jest poświęcone problemom
i programowaniu na platformie WordPress, jest strona
http://core.trac.wordpress.org/. Na tej stronie można znaleźć najnowsze
informacje dotyczące platformy.

Zrozumienie sposobu działania systemu na wymienionej witrynie może
wymagać nieco czasu, ale po oswojeniu się z systemem prawdopodobnie sam
zaangażujesz się w prace nad platformą WordPress. Najlepszym sposobem
rozpoczęcia nauki systemu jest po prostu czytanie umieszczanych tam
zgłoszeń, a następnie śledzenie ich losu.

------------------------------------------------------------------------

Uwaga

Trudno znaleźć lepsze sposoby stania się dobrym twórcą wtyczek, niż
zaangażowanie się w prace nad samą platformą WordPress. Prace nad
platformą pomagają w poznawaniu nowych funkcji i pozwalają na
natychmiastowe zrozumienie sposobu działania tworzącego ją kodu.

------------------------------------------------------------------------

Funkcje uznane za przestarzałe

Funkcje uznane za przestarzałe są przeznaczone do usunięcia z platformy.
Są one wyraźnie oznaczane jako te, których programiści nie powinni już
stosować w tworzonych wtyczkach. Dla tego rodzaju funkcji bardzo często
są oferowane zamienniki. Funkcje PHP nie są jedynymi używanymi za
przestarzałe na platformie WordPress. Czasami za przestarzałe uznaje się
pliki oraz parametry lub argumenty.

Funkcje uznane za przestarzałe najczęściej można znaleźć w jednym z
kilku plików platformy WordPress przeznaczonych do ich przechowywania:

-   wp-includes/deprecated.php — ogólne funkcje uznane za przestarzałe;
-   wp-includes/ms-deprecated.php — funkcje sieci Multisite uznane za
    przestarzałe;
-   wp-includes/pluggable-deprecated.php — funkcje zastępowalne, które
    zostały uznane za przestarzałe;
-   wp-admin/includes/deprecated.php — funkcje administracyjne uznane za
    przestarzałe.

Przeglądanie kodu pod kątem funkcji uznanych za przestarzałe czasami
może być uciążliwe. Przejrzenie powyższych plików to dobra metoda
poznania wszystkich funkcji tego rodzaju. Jednak z przestarzałymi
funkcjami najczęściej będziesz się stykał podczas usuwania błędów, co
zostanie omówione w dalszej części rozdziału.

Obsługa zbędnych instalacji

Po publicznym udostępnieniu wtyczki nie masz żadnej kontroli nad tym,
czy użytkownicy będą korzystali z najnowszego oprogramowania platformy
WordPress. Podczas współpracy z klientami zawsze możesz z nimi
bezpośrednio porozmawiać, a czasem masz nawet dostęp do instalacji
WordPress.

Kiedy współpracujesz z klientami posiadającymi przestarzałą wersję
platformy WordPress, powinieneś zastanowić się, czy nie jesteś
odpowiedzialny za zagwarantowanie, aby używali najnowszej i
najbezpieczniejszej wersji. Jeśli klient nie chce przeprowadzić
aktualizacji, warto mieć pod ręką listę powodów, dla których jednak
powinien zaktualizować oprogramowanie platformy WordPress.

Oto wybrane zalety aktualizacji oprogramowania platformy WordPress u
klientów.

-   Ułatwienie zadania twórcom wtyczek. To może zarówno skrócić czas
    pracy nad wtyczką, jak i jej koszt.
-   Używanie najbezpieczniejszej z dostępnych wersji oprogramowania, co
    może zmniejszyć szanse przeprowadzenia udanego ataku na witrynę.
-   Klient może Ci zlecić uaktualnienie witryny i zapewnienie jej
    aktualności, co jest doskonałym rozwiązaniem, ponieważ stanowi
    dodatkowe źródło dochodu.

Jeżeli współpracujesz z klientem, który z jakiegokolwiek powodu jednak
nie chce zaktualizować oprogramowania, największym wyzwaniem będzie
zapewnienie bezpieczeństwa. Kliencie zwykle zgadzają się na
aktualizację, gdy słyszą przerażające historie o możliwości
przeprowadzenia udanego ataku na ich witryny.

Podczas przeprowadzania procesu uaktualnienia oprogramowania u klienta
najważniejsze jest utworzenie kilku kopii zapasowych. Proces
uaktualnienia platformy WordPress jest prosty, ale kiedy z lenistwa
zrezygnujesz z utworzenia kopii zapasowej, los potrafi spłatać figla, a
wtedy okazuje się, że kopia zapasowa jest przydatna.

Usuwanie błędów

Jednym z największych problemów dotykających dostępne obecnie wtyczki
dla WordPress jest fakt, że większość z nich nie została poddana
prawidłowemu procesowi usuwania błędów. Może to wynikać z braku wiedzy
dotyczącej usuwania błędów lub motywacji. Wykonując kroki przedstawione
w tym podrozdziale, możesz pokonać konkurencję dzięki oczyszczeniu i
poprawieniu kodu.

Usuwanie błędów to zadanie polegające na wyszukaniu błędów w kodzie
oprogramowania. W języku PHP błąd może uniemożliwić wyświetlenie całej
strony internetowej lub spowodować wyświetlenie na niej komunikatu
błędu. Jednak w wielu sytuacjach błędy pozostają ukryte. Na szczęście,
platforma WordPress oferuje możliwości pozwalające na ich wykrycie.

Zawsze powinieneś budować wtyczki z włączonym trybem usuwania błędów.
Niektóre z zalet wspomnianego trybu to m.in.:

-   poznanie dokładnego miejsca w kodzie, w którym wystąpił błąd;
-   możliwość usunięcia mniejszych błędów, które niekoniecznie wpływają
    na funkcjonalność wtyczki, ale mogą potencjalnie ujawnić znacznie
    poważniejsze błędy;
-   możliwość poprawienia głównych błędów wpływających na funkcjonalność
    wtyczki, ale jednocześnie trudnych do wychwycenia podczas
    przeglądania kodu źródłowego;
-   otrzymywanie informacji o użyciu funkcji, parametru, argumentu lub
    pliku uznanego na platformie WordPress za przestarzałe.

Proces usuwania błędów nie powinien odstraszać i zniechęcać do jego
wykonania. Większość znalezionych błędów to drobne problemy, których
poprawienie zajmuje niewiele czasu. Ponadto dzięki usuwaniu błędów
stajesz się lepszym programistą, bo znajdujesz miejsca, w których błędy
są popełniane najczęściej.

Włączenie trybu usuwania błędów

W tym punkcie dowiesz się, jak włączyć tryb usuwania błędów w instalacji
WordPress. Włączenie tego trybu jest gorąco zalecane podczas tworzenia
wtyczek. Dzięki temu można zbudować znacznie lepszą wtyczkę, gdyż
ewentualne błędy są sygnalizowane już na wczesnym etapie prac.

W instalacji WordPress należy otworzyć plik wp-config.php znajdujący się
w katalogu głównym. W pliku znajduje się poniższy wiersz kodu:

    define('WP_DEBUG', false); 

Powyższy wiersz kodu nakazuje platformie WordPress wyłączenie trybu
usuwania błędów, więc wszelkie komunikaty z tym związane nie będą
wyświetlane. W środowisku programisty ten tryb nie powinien być
wyłączony, więc należy go włączyć.

W celu włączenia trybu usuwania błędów opcję false trzeba zmienić na
true. Po wprowadzonej zmianie wspomniany wiersz będzie miał postać:

    define('WP_DEBUG', true);

Włączenie trybu usuwania błędów wiąże się z dwoma ważnymi możliwościami
związanymi z usuwaniem błędów w tworzonych wtyczkach:

-   Informacje o błędach są wyświetlane na ekranie natychmiast po ich
    wystąpieniu. To jest zachowanie domyślne po ustawieniu wartości true
    opcji WP_DEBUG.
-   Istnieje możliwość użycia funkcji rejestrowania błędów na platformie
    WordPress, co zostanie omówione w dalszej części rozdziału.

Wyświetlanie komunikatów związanych z usuwaniem błędów

Po włączeniu trybu usuwania błędów przejrzyj posiadaną instalację
WordPress. Jeżeli masz włączone jakiekolwiek wtyczki, wtedy w różnych
miejscach strony prawdopodobnie zobaczysz wiele komunikatów związanych z
usuwaniem błędów. Wynika to z faktu, że większość wtyczek nie została
utworzona zgodnie z wymaganymi standardami. Powinieneś wykorzystać
informacje przedstawione w tym rozdziale, a po jego lekturze nie
będziesz miał żadnych wymówek, jeżeli tworzone przez Ciebie wtyczki
również będą powodować wyświetlanie komunikatów błędów.

Teraz przekonasz się, jak po włączeniu trybu usuwania błędów wygląda
funkcja uznana za przestarzałą. Przypuśćmy, że chcesz sprawdzić
istnienie pewnej określonej taksonomii. Przed wydaniem WordPress 3.0 do
tego celu służyła funkcja is_taxonomy(). Jednak na platformie WordPress
3.0 wymieniona funkcja jest uznana za przestarzałą i jej miejsce zajęła
nowa. Wyświetlenie komunikatu o istnieniu taksonomii na platformie
WordPress w wersji wcześniejszej niż 3.0 jest możliwe za pomocą
poniższego fragmentu kodu:

    <?php
    if ( is_taxonomy( 'category' ) )
        echo 'Taksonomia category istnieje.';
    ?> 

Użycie tego kodu w nowszej wersji oprogramowania platformy spowoduje
wygenerowanie komunikatu pokazanego na rysunku 16.1.

[]

Rysunek 16.1. Przykładowy komunikat wyświetlany po włączeniu trybu
usuwania błędów

W pokazanym komunikacie widzimy kilka informacji na temat użycia funkcji
is_taxonomy():

-   funkcja is_taxonomy() jest uznana za przestarzałą;
-   wymieniona funkcja została uznana za przestarzałą na platformie
    WordPress 3.0;
-   zastępująca ją funkcja nosi nazwę taxonomy_exists().

Taka ilość informacji zwykle wystarcza do wprowadzenia odpowiednich
poprawek w kodzie wtyczki. W celu uaktualnienia przedstawionego kodu
wystarczy przestarzałą funkcję zastąpić podanym zamiennikiem. W
niektórych sytuacjach komunikat może nie zawierać informacji o funkcji
zamiennika. W takich przypadkach problem trzeba rozwiązać indywidualnie,
ponieważ każda tego typu sytuacja może wymagać zastosowania innego
rozwiązania.

Uaktualnienie powyższego kodu polega na zastąpieniu funkcji
is_taxonomy() nową o nazwie taxonomy_exists():

    <?php
    if ( taxonomy_exists( 'category' ) )
        echo 'Taksonomia category istnieje.';
    ?> 

Dzięki tej prostej zmianie kod został uaktualniony, natomiast na stronie
nie będzie wyświetlany komunikat błędu związany z użyciem przestarzałej
funkcji.

Poprawianie błędów wskazywanych przez komunikaty

Większość komunikatów wyświetlanych w trybie usuwania błędów powstaje na
podstawie informacji udzielanych przez PHP. Niektórzy programiści
wyłączają wyświetlanie tych komunikatów PHP, uznając je za
"nieszkodliwe", ponieważ nie prowadzą do wystąpienia awarii witryny.
Wprawdzie takie założenie może być prawdziwe do pewnego stopnia, ale
wspomniane komunikaty czasami naprawdę wskazują większe problemy
związane z kodem. Zawsze powinieneś uważać za swój obowiązek usunięcie w
kodzie wtyczki wszystkich problemów powodujących wyświetlanie
komunikatów błędów.

W tym punkcie zostaną przedstawione trzy komunikaty najczęściej
pojawiające się podczas usuwania błędów oraz sposoby usunięcia
problemów, które powodują wyświetlanie tych komunikatów:

-   użycie przestarzałej funkcji WordPress;
-   informacja o niezdefiniowaniu zmiennej lub właściwości;
-   próba pobrania właściwości z obiektu, który nie jest obiektem.

Aby zobaczyć komunikaty usuwania błędów w działaniu, wcześniej trzeba
przygotować wadliwą wtyczkę. To jedyne miejsce w tej książce, w którym
prosimy Cię o utworzenie tak koszmarnego kodu. Tym razem jest to jednak
dozwolone, ponieważ na podstawie tego kodu dowiesz się, jak usuwać
błędy.

Omawiany przykład będzie prosty. Zadaniem wtyczki jest dodanie na końcu
wpisu bloga pola z informacjami o autorze, czyli jego danych i krótkiego
opisu. Pierwszym krokiem jest utworzenie nowego pliku wtyczki o nazwie
boj-error-plugin.php i zapisanie go w katalogu wtyczek platformy
WordPress. Następnie w pliku należy umieścić przedstawiony poniżej kod.

    <?php
    /*
    Plugin Name: Wtyczka z błędami
    Plugin URI: http://przyklad.pl
    Description: Wtyczka zawiera błędy do poprawienia podczas procesu usuwania błędów.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Zaczep filtru 'the_content'. */
    add_filter( 'the_content', 'boj_error_plugin_author_box' );
    /* Dołączenie na końcu wpisów bloga informacji o autorze. */
    function boj_error_plugin_author_box( $content ) {
        /* Jeżeli wyświetlany wpis bloga jest typu 'post'. */
        if ( 'post' == $post->post_type ) {
            /* Początek znacznika <div> informacji o autorze. */
            $author_box = '<div class="author-box">';
            /* Wyświetlenie danych autora. */
            $author_box .= '<h3>' . get_the_author_meta( 'display_name' ) . 
            '</h3>';
            /* Wyświetlenie krótkiej notki o autorze. */
            $author_box .= '<p>' . get_the_author_description() . '</p>';
            /* Zamknięcie znacznika. */
            $author_box .= '</div>';
        }
        /* Dołączenie informacji o autorze do treści wpisu bloga. */
        $content = $content . $author_box;
        /* Zwrot treści wpisu bloga. */
        return $content;
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-error-plugin.php.

------------------------------------------------------------------------

W kodzie wtyczki popełniono kilka błędów. Ponieważ w konfiguracji
platformy WordPress włączono tryb usuwania błędów, na ekranie
prawdopodobnie zostaną wyświetlone trzy komunikaty, które pokazano na
rysunku 16.2. W kodzie tak naprawdę są cztery błędy, ale jeden z nich
nie został ujawniony, ponieważ pozostała część kodu jest tak kiepsko
napisana, że polecenia zawierające wspomniany czwarty błąd nie mają
nawet szans zostać wykonane.

[]

Rysunek 16.2. Trzy komunikaty błędów generowane przez przedstawioną
wtyczkę

Największy problem w kodzie wiąże się z poniższym wierszem:

    if ( 'post' == $post->post_type ) { 

Powyższe polecenie próbuje sprawdzić, czy wyświetlany wpis bloga jest
typu post. Pierwszy problem dotyczy "niezdefiniowanej zmiennej" —
zmienna $post nie została zdefiniowana w żadnym miejscu kodu. Ponieważ
nie została zdefiniowana, na pewno nie jest obiektem. W tym przypadku
mamy do czynienia z błędem "próba pobrania właściwości nie-obiektu".
Obydwa wymienione błędy można bardzo łatwo poprawić poprzez dodanie
wcześniej poniższego wiersza kodu:

    global $post; 

Po wprowadzeniu wspomnianej poprawki podczas wyświetlania wpisu bloga
trzeci komunikat błędu znika, ale pojawia się w przypadku innych typów
wpisu bloga, np. na stronach. Źródłem tego komunikatu błędu jest kolejny
wiersz wtyczki skutkujący wygenerowaniem informacji o niezdefiniowanej
zmiennej.

    $content = $content . $author_box; 

Problem polega na tym, że zmienna $author_box nie zawsze będzie
ustawiona. Wspomniana wcześniej informacja to najczęstszy objaw błędu, a
sam błąd jest najłatwiejszy do naprawienia. Dobrą praktyką jest
definiowanie zmiennych na początku funkcji, ale sprawdzenie istnienia
zmiennej przed próbą jej użycia. W omawianym przykładzie wykorzystana
będzie funkcja PHP o nazwie isset(), która przed dołączeniem zmiennej
$author_box do $content sprawdzi jej istnienie.

    if ( isset( $author_box ) )
        $content = $content . $author_box; 

Po poprawieniu trzech pierwszych problemów pojawia się czwarty.
Komunikat z procesu usuwania błędów informuje o użyciu przestarzałej
funkcji get_the_author_description(). Ten sam komunikat jednocześnie
informuje, że wymieniona funkcja została zastąpiona przez
get_the_author_meta('description'). Źródłem wspomnianego komunikatu
błędu jest poniższy wiersz kodu:

    $author_box .= '<p>' . get_the_author_description() . '</p>';

Ponownie poprawka jest bardzo prosta — musisz jedynie zastąpić wywołanie
przestarzałej funkcji nową, wymienioną w komunikacie. Po wprowadzeniu
zmiany wiersz będzie miał postać:

    $author_box .= '<p>' . get_the_author_meta( 'description' ) . '</p>'; 

Wprowadzenie tych drobnych omówionych zmian powoduje, że wtyczka nie
zawiera żadnych błędów. Ponadto zmiany prowadzą do tego, że wtyczka w
ogóle zaczyna działać i wykonywać swoje zadanie. Poniżej przedstawiono
pełny kod źródłowy wtyczki po wprowadzeniu omówionych poprawek.

    <?php
    /*
    Plugin Name: Wtyczka z poprawionymi błędami
    Plugin URI: http://przyklad.pl
    Description: Poprawione błędy wtyczki "Wtyczka z błędami".
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Zaczep filtru 'the_content'. */
    add_filter( 'the_content', 'boj_error_plugin_author_box' );
    /* Dołączenie na końcu wpisów bloga informacji o autorze. */
    function boj_error_plugin_author_box( $content ) {
        global $post;
        /* Jeżeli wyświetlany wpis bloga jest typu 'post'. */
        if ( 'post' == $post->post_type ) {
            /* Początek znacznika <div> informacji o autorze. */
            $author_box = '<div class="author-box">';
            /* Wyświetlenie danych autora. */
            $author_box .= '<h3>' . get_the_author_meta( 'display_name' ) . 
            '</h3>';
            /* Wyświetlenie krótkiej notki o autorze. */
            $author_box .= '<p>' . get_the_author_meta( 'description' ) . '</p>';
            /* Zamknięcie znacznika. */
            $author_box .= '</div>';
        }
        /* Dołączenie informacji o autorze do treści wpisu bloga. */
        if ( isset( $author_box ) )
            $content = $content . $author_box;
        /* Zwrot treści wpisu bloga. */
        return $content;
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-error-plugin-fixed.php.

------------------------------------------------------------------------

Rejestrowanie błędów

Platforma WordPress oferuje inne użyteczne narzędzie służące do usuwania
błędów — jest nim rejestracja błędów. Funkcja ta stanowi rozszerzenie
omówionego powyżej procesu usuwania błędów. Pozwala na utworzenie pliku
dziennika zawierającego informacje o problemach, które wystąpiły w danej
instalacji WordPress.

Funkcja rejestracji błędów jest użyteczna podczas procesu usuwania
błędów z wtyczek, ponieważ informacja o każdym zaistniałym problemie
jest zapisywana w określonym pliku. W ten sposób programista może bardzo
łatwo przejrzeć jednocześnie wszystkie błędy. Jednak prawdopodobnie
znacznie ważniejsza jest możliwość rejestracji błędów, użyteczna w
publicznie dostępnych witrynach. Ogólnie rzecz biorąc, witryny dostępne
publicznie nie powinny wyświetlać komunikatów z procesu usuwania błędów,
a raczej zapisywać je do pliku ukrytego przed odwiedzającymi. W ten
sposób programista może się zapoznać z powstałymi błędami.

Włączenie rejestrowania błędów

Po włączeniu rejestrowania błędów otrzymujesz łatwy sposób przeglądania
wszystkich usterek wygenerowanych przez witrynę. Zapisane informacje
oprócz treści komunikatu błędu zawierają także datę i godzinę jego
wystąpienia. Błędy są zapisywane w pliku debug.log znajdującym się
domyślnie w katalogu wp-content instalacji WordPress.

W celu włączenia rejestracji błędów trzeba przeprowadzić edycję pliku
wp-config.php, podobnie jak wcześniej podczas włączania trybu usuwania
błędów. Wcześniej włączono opcję WP_DEBUG, a teraz trzeba włączyć opcję
WP_DEBUG_LOG poprzez dodanie do wymienionego pliku poniższego wiersza
kodu:

    define( 'WP_DEBUG_LOG', true ); 

Po dodaniu powyższego wiersza sekcja usuwania błędów w pliku
wp-config.php będzie miała postać:

    define( 'WP_DEBUG', true );
    define( 'WP_DEBUG_LOG', true ); 

Dwa przedstawione wiersze kodu informują platformę WordPress o
konieczności włączenia trybu usuwania błędów oraz rejestrowania
wygenerowanych błędów w pliku dziennika błędów.

Istnieje także opcjonalna możliwość wyłączenia wyświetlania błędów na
witrynie i jedynie ich zapisywania w pliku dziennika błędów. To
użyteczna technika do zastosowania na udostępnionej publicznie witrynie,
ale nie w środowisku programisty. Wyłączenie wyświetlania błędów na
witrynie wymaga dodania dwóch kolejnych wierszy kodu:

    define( 'WP_DEBUG_DISPLAY', false );
    ini_set( 'display_errors', 0 ); 

Położenie pliku dziennika błędów

Po włączeniu rejestracji błędów platforma WordPress tworzy w katalogu
wp-content plik o nazwie debug.log. W większości sytuacji nazwa i
położenie pliku sprawdzają się doskonale. Jednak, na szczęście, istnieje
możliwość wprowadzenia zmian, jeśli będzie trzeba.

Po włączeniu rejestracji błędów w pliku konfiguracyjnym można
opcjonalnie dodać poniższy wiersz, który wskazuje nazwę i położenie
pliku zawierającego informacje o wygenerowanych błędach:

    ini_set( 'error_log', '/example/przyklad.pl/wp-content/logs/debug.log' ); 

Powyższy wiersz informuje platformę WordPress, że plik dziennika błędów
ma zostać umieszczony w katalogu logs. Warto w tym miejscu zwrócić uwagę
na konieczność podania poprawnej ścieżki dostępu do katalogu, a nie
adresu URI.

Plik dziennika błędów

Zawartość pliku debug.log utworzonego w wyniku włączenia rejestracji
błędów można wyświetlić za pomocą dowolnego edytora tekstowego. Nie
powinieneś mieć żadnych trudności z jego otworzeniem i odczytaniem
zawartości.

W podrozdziale "Usuwanie błędów" utworzyliśmy wtyczkę zawierającą błędy.
Dowiedziałeś się tam również, w jaki sposób poprawić błędy, o których
informują komunikaty wyświetlane na ekranie. Plik dziennika błędów to
inny sposób zapoznania się z tymi komunikatami, a są to te same
komunikaty, które wcześniej widziałeś na ekranie. Poniżej przedstawiono
komunikaty zapisane w dzienniku błędów po pierwszym uruchomieniu wtyczki
utworzonej w wymienionym podrozdziale:

    [27-Oct-2010 16:07:37] PHP Notice:  Undefined variable: post in
        C:\xampp\htdocs\wordpress\wp-content\plugins\boj-error-plugin.php on line 18
    [27-Oct-2010 16:07:37] PHP Notice:  Trying to get property of non-object in
        C:\xampp\htdocs\wordpress\wp-content\plugins\boj-error-plugin.php on line 18
    [27-Oct-2010 16:07:37] PHP Notice:  Undefined variable: author_box in
        C:\xampp\htdocs\wordpress\wp-content\plugins\boj-error-plugin.php on line 34 

Jak możesz zobaczyć, każdy komunikat tworzy nowy wiersz (wpis) w pliku.
Komentarze wyglądają niemal tak samo jak na rysunku pokazanym w
podrozdziale "Usuwanie błędów". Jedyna różnica polega na podaniu w pliku
dokładnej daty i godziny wystąpienia danego błędu.

Po zapoznaniu się z komunikatami zapisanymi w dzienniku błędów być może
będzie trzeba ponownie zapoznać się z materiałem przedstawionym w
podrozdziale "Usuwanie błędów" i poprawić znalezione błędy. Warto w tym
miejscu wspomnieć, że poprawienie błędu nie powoduje usunięcia z
dziennika błędów informacji o nim. Trzeba więc zwracać baczną uwagę na
znaczniki czasu, aby nie usunąć błędu, który już wcześniej został
naprawiony.

Buforowanie

Buforowanie to sposób przechowywania danych w celu ich późniejszego
użycia. Użytkownicy stosują wiele różnych typów buforowania, a także
odmienne metody buforowania danych witryn. Buforowane są najczęściej
dane, których wygenerowanie jest kosztowne. Po umieszczeniu w buforze
dane mogą być szybko wczytane, gdy tylko okażą się niezbędne. To jest
sposób optymalizacji czasu wczytywania strony.

Zamiast koncentrować się na budowaniu mechanizmu buforowania dla
poszczególnych wtyczek, na platformie WordPress wbudowano metody
pozwalające wtyczkom na obsługę buforowania. WordPress ma więc funkcję
WordPress Object Cache, która jest klasą PHP wykorzystywaną przez
wtyczki do przechowywania danych. Platforma WordPress sama nie
przechowuje danych. Dostarcza wtyczkom sposoby buforowania danych.
Zaoferowane metody pozwalają na zastosowanie różnych rozwiązań z zakresu
buforowania w zależności od potrzeb użytkownika.

Korzystanie z wbudowanych na platformie WordPress metod buforowania
wiąże się z dwiema ogromnymi zaletami:

-   dostępny jest pojedynczy zestaw funkcji, które mogą być
    wykorzystywane przez wszystkie wtyczki bez obawy wystąpienia
    konfliktów;
-   istnieje możliwość utworzenia wtyczek buforowania w celu obsługi
    trwałego buforowania, które pozwala na zapisanie danych i ich
    używanie podczas wyświetlania wielu stron.

Użycie funkcji WordPress Object Cache nie powoduje bezpośredniego
przyśpieszenia działania wtyczki. Domyślnie buforowane dane są
zapisywane jedynie dla danej strony internetowej, na której zostały
użyte. Przykładowo dane można zapisać raz, a następnie wielokrotnie z
nich skorzystać na tej samej stronie bez ponownego wykonania tego samego
kodu. Przy użyciu wtyczki trwałego buforowania dane mogą być
przechowywane i wykorzystywane przez wiele operacji wyświetleń strony.

Najważniejszym powodem stosowania takiego systemu jest umożliwienie
użytkownikom wtyczki wyboru metody buforowania, która przyniesie
najwięcej korzyści lub najlepiej sprawdzi się z daną konfiguracją
serwera. Platforma WordPress po prostu dostarcza niezbędne funkcje w
postaci wygodnego API, które może być używane przez wiele wtyczek.

------------------------------------------------------------------------

Uwaga

W rozdziale 7. omówiono API Transients. Oferuje ono możliwość
buforowania danych przez podany okres czasu. Jeśli jednak użytkownik
zainstaluje wtyczkę trwałego buforowania, obsługa tych krótkotrwałych
danych będzie odbywała się za pomocą funkcji WordPress Object Cache.

------------------------------------------------------------------------

Zapisywanie, wczytywanie i usuwanie buforowanych danych

Platforma WordPress dostarcza kilka łatwych w użyciu funkcji PHP
służących do pracy z systemem buforowania. Każda funkcja pozwala na
zapisanie, uaktualnienie, wczytanie lub usunięcie buforowanych danych.
Istnieją także inne funkcje powiązane z buforowaniem, które nie zostały
omówione w tym rozdziale. Jednak wymienione tutaj funkcje to te, które
są używane najczęściej.

Każda z tych funkcji korzysta z przynajmniej jednego z poniższych
parametrów.

-   $key — unikalny identyfikator używany do przechowywania i pobierania
    danych. Klucz buforowania nie musi być unikalny względem wielu grup
    buforowania, ale musi być unikalny w poszczególnych grupach
    buforowania.
-   $data — dane wtyczki, które mają być zapisane lub pobrane.
-   $group — sposób pogrupowania wielu elementów buforowanych danych.
    Przykładowo istnieje możliwość grupowania wielu kluczy buforowania.
    Ten parametr jest opcjonalny.
-   $expire — wyrażona w sekundach ilość czasu, przez który dane będą
    buforowane. Ten parametr jest opcjonalny, a jego wartość domyślna
    wynosi 0, co oznacza przechowywanie danych w nieskończoność.

wp_cache_add()

Funkcja wp_cache_add() powinna być używana, gdy wtyczka musi zapisać
dane w nieistniejącym jeszcze kluczu buforowania. Jeżeli klucz
buforowanie istnieje, nie będą dodane żadne dane.

    <?php
    wp_cache_add( $key, $data, $group, $expire );
    ?> 

wp_cache_replace()

Funkcja wp_cache_replace() pozwala wtyczce na nadpisanie danych
poprzednio zapisanych w tym samym kluczu buforowania.

    <?php
    wp_cache_replace( $key, $data, $group, $expire );
    ?> 

wp_cache_set()

Funkcja wp_cache_set() to połączenie funkcji wp_cache_add() i
wp_cache_replace(). Jeżeli wskazany klucz buforowania jeszcze nie
istnieje, nastąpi jego utworzenie. Jeśli natomiast podany klucz
buforowania istnieje, jego dotychczasowe dane będą nadpisane nowymi.

    <?php
    wp_cache_set( $key, $data, $group, $expire );
    ?> 

wp_cache_get()

Funkcja wp_cache_get() pozwala wtyczce na wczytanie buforowanych danych
poprzez podanie klucza buforowania i grupy. Jeśli dane nie zostaną
znalezione, wartością zwrotną funkcji będzie false. Gdy dane istnieją,
funkcja je zwróci.

    <?php
    wp_cache_get( $key, $group );
    ?> 

wp_cache_delete()

Funkcja wp_cache_delete() powoduje usunięcie buforowanych danych we
wskazanym kluczu i grupie. Gdy operacja usunięcia danych zakończy się
powodzeniem, funkcja zwróci wartość true. W przeciwnym razie wartością
zwrotną jest false.

    <?php
    wp_cache_delete( $key, $group );
    ?> 

Buforowanie danych we wtyczce

W tym punkcie zostanie utworzona prosta wtyczka, która będzie buforowała
listę wpisów bloga powiązanych z bieżącym. Lista zostanie dołączona do
treści wyświetlanego wpisu bloga. Każdy wpis bloga na witrynie
przechowuje swoje dane w grupie boj_related_posts w unikalnym kluczu
buforowania bazującym na identyfikatorze wpisu bloga.

We wtyczce wykorzystano dwie funkcje buforowania: wp_cache_set() w celu
buforowania powiązanych wpisów bloga oraz wp_cache_get() do pobrania
tych danych.

Nowo utworzona wtyczka o nazwie Buforowanie powiązanych wpisów bloga
została umieszczona w pliku o nazwie boj-cache-related-posts.php.

    <?php
    /*
    Plugin Name: Buforowanie powiązanych wpisów bloga
    Plugin URI: http://przyklad.pl
    Description: Wtyczka używa obiektu buforowania w celu buforowania powiązanych wpisów bloga.
    Version: 0.1
    Author: WROX
    Author URI: http://wrox.com
    */
    /* Dodanie do treści wyświetlanego wpisu bloga innych, powiązanych z nim wpisów. */
    add_filter( 'the_content', 'boj_cache_related_posts' );
    /* Dołączenie listy powiązanych wpisów bloga na stronie wyświetlającej pojedynczy wpis bloga. */
    function boj_cache_related_posts( $content ) {
        /* Jeżeli strona nie wyświetla tylko jednego wpisu bloga, wtedy trzeba zwrócić jej treść. */
        if ( !is_singular( 'post' ) )
            return $content;
        /* Pobranie identyfikatora bieżącego wpisu bloga. */
        $post_id = get_the_ID();
        /* Pobranie buforowanych danych dla określonego wpisu bloga. */
        $cache = wp_cache_get( $post_id, 'boj_related_posts' );
        /* Jeżeli żadne dane nie są buforowane. */
        if ( empty( $cache ) ) {
            /* Pobranie kategorii wpisu bloga. */
            $categories = get_the_category();
            /* Pobranie powiązanych wpisów bloga przy wzięciu pod uwagę kategorii wyświetlanego wpisu bloga. */
            $posts = get_posts(
                array(
                    'category' => absint( $categories[0]->term_id ),
                    'post__not_in' => array( $post_id ),
                    'numberposts' => 5
                )
            );
            /* Jeżeli nie zostaną znalezione żadne wpisy bloga. */
            if ( !empty( $posts ) ) {
                /* Utworzenie nagłówka i rozpoczęcie nieuporządkowanej listy. */
                $cache = '<h3>Powiązane wpisy bloga</h3>';
                $cache .= '<ul>';
                /* Iteracja przez każdy wpis bloga i pobranie odnośnika do strony, na której będzie wyświetlony tylko dany wpis bloga. */
                foreach ( $posts as $post ) {
                    $cache .= '<li><a href="' . get_permalink( $post->ID ) . '">' . 
                        get_the_title( $post->ID ) . '</a></li>';
                }
                /* Zamknięcie nieuporządkowanej listy. */
                $cache .= '</ul>';
                /* Buforowanie przez dwanaście godzin listy powiązanych wpisów bloga. */
                wp_cache_set( $post_id, $cache, 'boj_related_posts', 60 * 60 * 12 );
            }
        }
        /* Jeżeli są buforowane dane, wtedy należy je dołączyć do treści wpisu bloga. */
        if ( !empty( $cache ) )
            $content .= $cache;
        /* Zwrócenie treści wpisu bloga. */
        return $content;
    }
    ?>

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku boj-cache-related-posts.php.

------------------------------------------------------------------------

Pierwsza funkcja buforowania użyta w powyższym fragmencie kodu to
wp_cache_get(). Przy użyciu identyfikatora bieżącego wpisu bloga
sprawdza ($post_id), czy jest buforowana lista powiązanych z nim wpisów
bloga. Sprawdza także, czy dane są przechowywane w grupie
boj_related_posts. Jeżeli wpisy bloga powiązane z aktualnie wyświetlanym
są zapisane w określonym kluczu buforowania i grupie, lista ta będzie
dodana do treści bieżącego wpisu bloga. W ten sposób eliminowana jest
konieczność ponownego wygenerowania powiązanych ze sobą wpisów bloga.

Z kolei funkcja wp_cache_set() buforuje listę powiązanych wpisów bloga w
celu jej późniejszego użycia. W ten sposób lista będzie mogła być
pobrana przez funkcję wp_cache_get(). Wymieniona funkcja będzie używana
po utworzeniu listy powiązanych wpisów bloga. Lista została zapisana w
grupie boj_related_posts na podstawie identyfikatora wpisu bloga.
Ponadto czas buforowania danych określono na dwanaście godzin.

Podstawowe funkcje buforowania z reguły wymagają jedynie dwóch operacji,
które są wykonywane przez wtyczkę. Oto te operacje.

-   Sprawdzenie, czy są dostępne jakiekolwiek buforowane dane. Jeżeli
    tak, będą użyte, co pozwoli na uniknięcie konieczności ich ponownego
    wygenerowania.
-   Jeżeli buforowane dane nie istnieją, wtedy zostaną wygenerowane i
    buforowane, co pozwoli na ich późniejsze użycie.

Podsumowanie

Na temat usuwania błędów i optymalizacji można napisać całą książkę.
Celem tego rozdziału nie było przedstawienie każdego możliwego
rozwiązania. W rozdziale omówiono podstawy pozwalające na rozpoczęcie
pracy, a także podano ogólny opis funkcji oferowanych w tym zakresie
przez platformę WordPress.

Pewne najważniejsze zadania, które można wykonywać, to zapewnienie
używania najnowszej wersji oprogramowania platformy, usuwanie błędów z
tworzonych wtyczek oraz korzystanie z wbudowanego systemu buforowania.
Tworzone przez Ciebie wtyczki mogą korzystać z najnowszych dostępnych
funkcji, być mniej podatne na błędy oraz uszczęśliwiać użytkowników
dzięki pracy z preferowanymi przez nich rozwiązaniami z zakresu
buforowania. Wszystkie wymienione zadania nie są czasochłonne, a mogą
przyczynić się do poprawienia jakości tworzonej wtyczki.

Rozdział 17 Działania marketingowe

W tym rozdziale:

-   Wybór licencji, na której będzie udostępniona wtyczka
-   Umieszczenie wtyczki w repozytorium wtyczek
-   Wypromowanie wtyczki
-   Zaangażowanie się w społeczność WordPress

Niektóre z najpopularniejszych wtyczek dla platformy WordPress
niekoniecznie posiadają najlepiej utworzony kod lub są najbardziej
użyteczne. Czasami stały się popularne po prostu dlatego, że ich twórca
potrafił skutecznie wykorzystać marketing do wypromowania wtyczki.
Możesz więc zbudować najsolidniejszą, doskonale zoptymalizowaną i wysoce
użyteczną wtyczkę, ale bez odrobiny marketingu lub szczęścia nikt nawet
nie dowie się o jej istnieniu. Twoim celem jest więc poinformowanie
innych użytkowników o utworzonej wtyczce.

Programiści niekoniecznie muszą znać się na marketingu. Jeżeli w ogóle
są rozpoznawanymi osobami, to zwykle ze względu na budowanie użytecznych
wtyczek dla witryn internetowych. Ponieważ przeciętny użytkownik nie zna
różnicy pomiędzy zmienną PHP a funkcją, nie jest więc w stanie docenić
programisty podczas przeglądania utworzonego przez niego kodu
źródłowego. Niestety, wypromowanie wtyczki nie jest prostym zadaniem; w
przeciwnym razie wszyscy doskonali programiści byliby zarazem ekspertami
od marketingu.

Jako programista wtyczek w społeczności WordPress musisz jednak odgrywać
rolę zarówno programisty, jak i specjalisty od marketingu. Nie przejmuj
się jednak! Nie musisz mieć dyplomu z marketingu lub komunikacji
międzyludzkiej, aby skutecznie wypromować wtyczkę. Oczywiście,
wypromowanie będzie wymagało nieco wysiłku, ale Twoim celem jest
przekonanie użytkowników do używania opracowanej przez Ciebie wtyczki.
Metody omówione w rozdziale są proste i możliwe do wykonania przez
każdego pasjonata swojej pracy.

Niezależnie od motywacji pchającej Cię do tworzenia wtyczek, czyli
pieniędzy, popularności lub chęci podzielenia się z innymi czymś
użytecznym, informacje przedstawione w rozdziale mogą pomóc w
znalezieniu drogi do udostępnienia Twoich wtyczek ogromnej społeczności
użytkowników platformy WordPress.

Wybór licencji dla wtyczki

Platforma WordPress nie jest pozbawiona problemów i debat związanych z
licencją, na której została udostępniona. Rzadko zdarza się, aby choć
raz w tygodniu nie wybuchła kłótnia, której przedmiotem są kwestie
dotycząca licencjonowania. Największe kontrowersje budzi kwestia
licencji, na jakiej powinny być udostępniane wtyczki i motywy.
Wyznaczono pewne — zarówno jasne, jak i niezbyt jasne granice — a sami
programiści zawsze szukają luk i pewnych możliwości obejścia warunków
licencji, na której udostępniono platformę WordPress. W tym rozdziale
jednak nie zajmiemy się ideologią. Ten podrozdział został poświęcony
tematowi wyboru licencji, która z marketingowego punktu widzenia będzie
najlepsza dla Twojej wtyczki.

Platforma WordPress jest udostępniona na licencji GPL (GNU General
Public License, Powszechna Licencja Publiczna GNU), czyli licencji, na
której jest udostępniane oprogramowanie typu open source. Licencja ta
została opracowana przez fundację FSF (ang. Free Software Foundation) i
stanowi jej własność. Platforma WordPress jest udostępniona na licencji
GPL, ponieważ jej poprzednik (b2/cafelog) również był dostępny na
licencji GPL. Platforma WordPress stanowi pewne odgałęzienie
oprogramowania b2/cafelog i musi być udostępniona na licencji, na której
zostało wydane oprogramowanie stanowiące punkt wyjściowy do jej
utworzenia.

Licencja GPL zapewnia użytkownikom wolność w zakresie używania danego
oprogramowania. Daje każdemu użytkownikowi prawo do kopiowania
oprogramowania, modyfikowania go i dzielenia się nim, ale pod warunkiem
zachowania tej samej wolności (łącznie z licencją GPL). To jest podstawa
każdego projektu oprogramowania typu open source. Ideą przyświecającą
twórcom tej licencji było zapewnienie ochrony wolności użytkowników w
zakresie używania danego oprogramowania.

Różne opcje

Większość wtyczek jest udostępniana na licencji GPL. To jest
najłatwiejszy wybór i gwarantuje brak konfliktów z platformą WordPress,
która sama również jest rozpowszechniana na licencji GPL.

Wprawdzie licencja GPL jest stosowana przez większość programistów
społeczności, to jednak istnieją pewne inne opcje, które nie kłócą się z
licencją GPL lub ideami przyświecającymi tworzeniu oprogramowania typu
open source — to licencje zgodne z GPL. Jeżeli zdecydujesz się na ich
stosowanie, tworzone przez siebie wtyczki możesz wydawać na licencjach
tego typu.

Lista licencji zgodnych z GPL, na których możesz wydawać wtyczki,
znajduje się na witrynie GPL, a dokładnie na stronie
http://www.gnu.org/licenses/license-list.html. Niektóre z
najpopularniejszych licencji to:

-   LGPL,
-   Apache,
-   MIT (X11),
-   BSD.

Choć wymienione licencje są popularne, jednak nie znajdziesz zbyt wielu
wtyczek dla WordPress wydanych na ich podstawie. Większość wtyczek jest
wydawana na licencji GPL. Istnieje możliwość użycia innych licencji,
które nie są zgodne z GPL. Powinieneś więc wybrać tę licencję, która
najlepiej pasuje do Twojej wtyczki.

Wtyczki mogą być wydane na licencji podwójnej lub podzielonej.

-   Licencja podwójna. W takim przypadku wtyczka jest wydawana na dwóch
    licencjach. Obie licencje muszą być zgodne, a cały kod wtyczki jest
    wydawany na obu licencjach.
-   Licencja podzielona. Różne części wtyczki są wydawane na innych
    licencjach. Określone fragmenty mogą być więc wydane na zupełnie
    innej licencji niż pozostałe. Takie rozwiązanie jest stosowane, gdy
    wtyczka zawiera kod JavaScript, CSS lub pliki graficzne, które nie
    muszą być wydawane na licencji używanej przez platformę WordPress.
    Fundacja FSF stwierdziła, że wymienione pliki nie muszą być zawsze
    udostępniane na licencji GPL.

Wszystkie wtyczki umieszczone w repozytorium wtyczek WordPress (to
repozytorium będzie omówione w dalszej części rozdziału) muszą być
udostępniane w całości na licencji GPL. Nie wolno stosować żadnej
licencji niezgodnej z GPL, nawet jeśli prawo zezwala na użycie takiej
licencji. Takie warunki zostały ustalone w polityce witryny
WordPress.org w zakresie przekazywania wtyczek do oficjalnego
repozytorium.

Dlaczego licencja ma znaczenie?

Platforma WordPress od zawsze była oprogramowaniem pozwalającym
użytkownikom na wyrażenie swojej wolności. Sama platforma nigdy nie
powstałaby, gdyby oprogramowanie, na którym bazuje WordPress, nie było
udostępniane na licencji GPL, ponieważ wymieniona licencja pozwala na
tworzenie odgałęzień danego oprogramowania. Celem platformy nie jest
ograniczanie możliwości użytkowników w zakresie sposobów używania
otrzymywanego przez nich oprogramowania — to po prostu wyłącznie kwestia
zapewnienia użytkownikom pełnej swobody. Użytkownicy mają więc prawo do
modyfikowania i kopiowania oprogramowania oraz dzielenia się nim z
innymi użytkownikami bez żadnych ograniczeń.

Jeżeli planujesz zbudowanie wtyczki dla platformy WordPress i chcesz
wprowadzić dodatkowe ograniczenia dotyczące używania wtyczki lub
tworzącego ją kodu, wówczas WordPress prawdopodobnie nie jest najlepszą
platformą dla takiej wtyczki. Licencja GPL, na której jest udostępniana
platforma WordPress, oznacza usuwanie wszelkich ograniczeń dotyczących
sposobu używania oprogramowania przez użytkowników.

Żaden z autorów książki nie jest prawnikiem, więc naszym celem nie jest
udzielenie Ci porad prawnych dotyczących licencjonowania Twoich wtyczek.
Musisz jednak wiedzieć, że jeśli zdecydujesz się na użycie licencji
niezgodnej z GPL, możesz spowodować pewne problemy prawne.

Poza problemami prawnymi, udostępnianie swojego oprogramowania na
licencji niezgodnej z GPL to jedna z najgorszych rzeczy, jaką możesz
zrobić w społeczności WordPress. W najlepszym przypadku Twoja wtyczka
pozostanie nieobecna w oficjalnych kanałach dystrybucji, natomiast w
najgorszym zostanie potraktowana przez społeczność jak wyrzutek. Żadna z
wymienionych sytuacji nie jest pożądana podczas próby wypromowania
własnej wtyczki.

Poniżej wymieniono największe zalety udostępnienia wtyczki na bazie
licencji GPL lub zgodnej z GPL.

-   Ochrona wolności użytkowników — użytkownicy będą mieli bez żadnych
    ograniczeń prawo do edycji i kopiowania zmian wprowadzonych w kodzie
    oraz dzielenia się nim z innymi użytkownikami, oczywiście, przy
    zapewnieniu innym tej samej wolności.
-   Pomoc innym programistom w nauce — inni programiści mogą się uczyć
    na podstawie Twojego kodu, co pozwoli im na usprawnianie i
    udostępnianie społeczności kolejnych wtyczek.
-   Możliwość wprowadzania usprawnień — pozostawienie kodu otwartego
    oznacza, że pozostali programiści mogą z niego korzystać w innych
    celach, m.in. wyszukiwania błędów i jego usprawniania, oczywiście,
    bez zmiany licencji. Następnie przygotowany przez nich kod możesz
    wykorzystać we własnej pracy.
-   Użycie kodu utworzonego przez innych — masz prawo do pobierania,
    modyfikowania i rozpowszechniania we własnej pracy kodu innych
    programistów udostępnionego na licencji GPL. W ten sposób możesz się
    skoncentrować na budowie konkretnych rozwiązań przy użyciu kodu
    przygotowanego przez innych, zamiast samodzielnie tworzyć wszystko
    zupełnie od początku.
-   Uniknięcie problemów prawnych — ponieważ platforma WordPress jest
    dostępna na licencji GPL, nie musisz się obawiać żadnych problemów
    prawnych.
-   Akceptacja ze strony społeczności — udostępnienie wtyczki na
    licencji GPL oznacza znacznie większe prawdopodobieństwo, że
    zostanie ona zaakceptowana przez społeczność.

Z marketingowego punktu widzenia prawdopodobnie najważniejszą zaletą
jest ostatnia pozycja na powyższej liście. Aby zrealizować swój cel,
najlepszym sposobem jest uzyskanie akceptacji ze strony społeczności.
Jeżeli chcesz, by Twoja praca stała się znana, kłótnie dotyczące
licencji z osobami usprawniającymi platformę WordPress i pracującymi nad
nią to naprawdę nie jest najlepsza droga do sławy.

Jeśli nawet nie zgadzasz się z opiniami innych, filozofią lub licencją
platformy WordPress, to i tak powinieneś je szanować. Ważne jest, aby
samemu nie wykluczać się ze społeczności poprzez okazywanie braku
szacunku osobom tworzącym kod platformy WordPress.

Zarabianie pieniędzy pomimo stosowania licencji GPL

Platforma WordPress oraz inne oprogramowanie dostępne na licencji
zgodnej GPL są uznawane za wolne oprogramowanie. Pojęcie "wolne" oznacza
tutaj wolność. To — oczywiście — nie oznacza, że za pomocą takiego
oprogramowania nie wolno zarabiać pieniędzy. Opłaty można więc pobierać
za udostępnianie wtyczki innym bądź za usługi wykonane dla klienta.
Istnieje nawet możliwość zbudowania całej firmy na bazie bezpłatnego,
wolnego kodu typu open source, o ile wybierzesz taką drogę dla tworzonej
przez siebie wtyczki. Nie ma zakazu uniemożliwiającego zrobienie biznesu
na bazie platformy WordPress. Wielu programistom udało się zbudować
dobrze prosperujące firmy, co absolutnie nie kłóci się z zapisami
licencji GPL.

Licencja, na której wydano platformę WordPress, dotyczy dystrybucji
kodu. Jednym z największych nieporozumień związanych z licencją GPL jest
jej uznanie za niewłaściwą do zastosowania podczas świadczenia usług dla
klienta lub pracy na własny użytek. Wielu potencjalnych klientów i wiele
firm nie rozumie, że licencja GPL nie stanowi tutaj żadnego problemu.
Ponieważ licencja ma zastosowanie jedynie w chwili dystrybucji kodu, nie
ma więc wpływu na świadczone usługi, ponieważ one nie podlegają
dystrybucji. Dlatego też swoim klientom nie musisz świadczyć usług na
podstawie licencji zgodnej z GPL. Możesz przyjąć założenie, że praca
którą wykonujesz dla swoich klientów, nie będzie przekazana innym.

------------------------------------------------------------------------

Ostrzeżenie

Jeżeli zdecydujesz się na opublikowanie swojej pracy na licencji
niezgodnej z GPL, wówczas powinieneś zasięgnąć porady prawnej u
prawnika, a nie całkowicie polegać na informacjach przedstawionych w tym
rozdziale.

------------------------------------------------------------------------

Udostępnienie wtyczki na witrynie WordPress.org

Witryna WordPress.org to centralne miejsce w internecie przeznaczone na
oprogramowanie dla platformy WordPress. W wymienionej witrynie znajduje
się repozytorium zawierające tysiące wtyczek dostępnych do pobrania dla
milionów użytkowników platformy WordPress. To miejsce, z którego
większość użytkowników pobiera wtyczki. Dlatego też umieszczenie wtyczki
w tym repozytorium otwiera przed Tobą nieograniczone możliwości i
pozwala na pokazanie innym utworzonego przez siebie oprogramowania.

Wszystkie wtyczki WordPress znajdują się w repozytorium dostępnym na
stronie http://wordpress.org/extend/plugins/ (zobacz rysunek 17.1).
Wspomniane repozytorium pozwala użytkownikom platformy WordPress na
wyszukiwanie wtyczek, sprawdzanie wtyczek, przeglądanie listy
najpopularniejszych, najnowszych i ostatnio uaktualnionych wtyczek.

[]

Rysunek 17.1. Repozytorium wtyczek w witrynie WordPress.org

Repozytorium wtyczek obsługuje wiele zadań, którymi programista nie musi
się zajmować, bo może skorzystać z repozytorium. Jeżeli tworzysz
wtyczkę, która ma być udostępniona publicznie, wtedy nie ma zbyt wielu
powodów rezygnacji z umieszczenia jej w oficjalnym repozytorium wtyczek.

Niektóre z zalet umieszczenia wtyczek w oficjalnym repozytorium zostały
wymienione poniżej.

-   Zaufanie użytkowników — zbudowana przez Ciebie wtyczka znajduje się
    w "oficjalnym" repozytorium. To wiąże się z pewnym zaufaniem
    użytkowników do wtyczek oferowanych w repozytorium. Zaufanie to coś,
    co znacznie trudniej zbudować, umieszczając wtyczkę we własnej
    witrynie lub w innym miejscu.
-   Łatwe uaktualnienia — nie trzeba tworzyć specjalnego skryptu dla
    wtyczki lub wymuszać na użytkownikach przeprowadzenie ręcznego
    procesu uaktualniania wtyczki. Dzięki repozytorium uaktualnienie
    wtyczki wymaga od użytkownika jedynie kilku kliknięć myszą.
-   Kontrola wersji — wtyczki są umieszczane w repozytorium Subversion,
    co ułatwia ich uaktualnianie. Repozytorium wtyczek jest uaktualniane
    co piętnaście minut, więc uaktualnienia samych wtyczek są bardzo
    szybko dostępne dla użytkowników.
-   Dane statystyczne — otrzymujesz możliwość przeglądania danych
    statystycznych dotyczących wtyczki, np. liczby pobrań na przestrzeni
    wskazanego czasu bądź procentowej liczby użytkowników korzystających
    z określonej wersji wtyczki.
-   Zgodność — repozytorium pozwala użytkownikom na kliknięcie przycisku
    Działa lub Nie działa, dzięki któremu będziesz wiedział, jeśli dana
    wersja wtyczki nie działa z określoną wersją platformy WordPress.
-   Oceny — użytkownicy otrzymują możliwość oceniania wtyczek z
    wykorzystaniem systemu bazującego na przydzielaniu gwiazdek. W ten
    sposób dowiesz się, jak wtyczka jest odbierana i oceniana przez jej
    użytkowników.
-   Informacje o wtyczce — wszystkie informacje dotyczące wtyczki możesz
    przekazywać użytkownikom bezpośrednio na stronie wtyczki w
    repozytorium, co znacznie ułatwia np. przekazywanie instrukcji i
    poleceń.
-   Integracja z forum — wszystkie wtyczki w repozytorium są
    zintegrowane z forum. Dzięki temu pomoc techniczną możesz świadczyć
    bezpośrednio na witrynie WordPress.
-   Odnośnik do strony pozwalającej na złożenie datku — masz możliwość
    umieszczenia odnośnika, dzięki któremu użytkownicy wtyczki będą
    mogli złożyć datki.

Wyobraź sobie, że wszystkimi zadaniami wymienionymi na powyższej liście
musiałbyś się zajmować samodzielnie. To oznaczałoby wiele dodatkowej
pracy w celu opublikowania wtyczki. Oczywiście, tworzonych przez siebie
wtyczek nie musisz udostępniać poprzez oficjalne repozytorium.
Wspomniane repozytorium to po prostu doskonałe narzędzie oferowane
twórcom wtyczek, które ma im maksymalnie ułatwić udostępnienie wtyczek
innym użytkownikom.

Być może cele, które sobie założyłeś, nie obejmują publicznego
udostępnienia wtyczki. Być może jesteś zainteresowany opracowywaniem
wtyczek dla swoich klientów. W takich przypadkach możesz również uważać,
że umieszczanie w repozytorium na witrynie WordPress.org tworzonych
przez siebie wtyczek nie ma sensu. Do pewnego stopnia to prawda. Jednak
oficjalne repozytorium powinieneś postrzegać jako możliwość wypromowania
siebie lub swojej firmy. Jednym z najłatwiejszych sposobów promocji jest
pozwolenie innym, aby się przekonali, że wprawdzie profesjonalne usługi
świadczysz klientom, ale jednocześnie bezpłatnie udostępniasz publicznie
także inne tworzone przez siebie wtyczki. Warto przygotować kilka
wtyczek, które będą stanowiły swego rodzaju portfolio i mogą w
przyszłości skutkować otrzymywaniem zleceń od nowych klientów.

Utworzenie konta

Każdy posiadający konto na witrynie WordPress.org może umieścić wtyczkę
w oficjalnym repozytorium oraz korzystać z wielu innych funkcji
oferowanych przez tę witrynę. Jeśli nawet nie planujesz umieszczania
tutaj swoich wtyczek, nadal warto założyć konto, ponieważ jego
posiadanie otwiera możliwość skorzystania z wielu użytecznych narzędzi.

Rejestracja nowego konta jest bardzo łatwa i wymaga podjęcia jedynie
kilku prostych kroków. Po założeniu konta można już umieścić wtyczkę w
oficjalnym repozytorium WordPress.

1.  Przejdź na stronę http://wordpress.org/support/register.php.
2.  Wprowadź informacje w wymaganych polach formularza.
3.  Sprawdź pocztę e-mail i upewnij się, że otrzymałeś wiadomość z
    potwierdzeniem adresu e-mail oraz wygenerowanym hasłem.
4.  Zastosuj się do poleceń przedstawionych w otrzymanej wiadomości
    e-mail.

Zgłoszenie wtyczki do oficjalnego repozytorium

Przed umieszczeniem wtyczki w repozytorium wtyczek trzeba ją zgłosić i
poczekać na akceptację umieszczenia w repozytorium. Ten proces jest
bezproblemowy, a akceptacja umieszczenia wtyczki w repozytorium zwykle
następuje w przeciągu kilku dni, a czasem nawet kilku godzin od chwili
zgłoszenia.

Jak pokazano na rysunku 17.2, w dostępnym na stronie
http://wordpress.org/extend/plugins/add/ formularzu zgłoszenia trzeba
podać nazwę wtyczki, jej opis, adres URL (opcjonalnie).

[]

Rysunek 17.2. Formularz pozwalający na zgłoszenie nowej wtyczki do
oficjalnego repozytorium WordPress

Po przyjęciu do repozytorium wtyczka otrzyma poświeconą jej stronę pod
adresem http://wordpress.org/extend/plugins/nazwa-wtyczki, gdzie
nazwa-wtyczki to nazwa katalogu zawierającego wtyczkę. To jest odnośnik
bezpośredni do Twojej wtyczki w repozytorium. Na wspomnianej stronie
użytkownicy będą mogli zapoznać się z informacjami o wtyczce oraz ją
pobrać.

Konfiguracja SVN

Wszystkie wtyczki z oficjalnego repozytorium WordPress są przechowywane
w repozytorium Subversion, które jest po prostu systemem kontroli
wersji. W celu dodawania i uaktualniania plików wtyczki w repozytorium
wtyczki trzeba nauczyć się korzystania z Subversion.

Krótkie wprowadzenie do Subversion znajduje się na stronie
http://wordpress.org/extend/plugins/about/svn/, na której znajdziesz
wystarczającą ilość informacji do zrozumienia Subversion w zakresie
pozwalającym na korzystanie z repozytorium wtyczek. Wszystko odbywa się
za pomocą wiersza poleceń. Większość twórców wtyczek będzie używała
Subversion do pobierania lub umieszczenia (dodawania bądź uaktualniania)
plików wtyczek. Istnieją programy klienckie Subversion, które oferują
łatwe w użyciu interfejsy użytkownika pozwalające na stosowanie
Subversion.

Dla różnych systemów operacyjnych istnieje wiele klientów Subversion.
Poniżej wymieniono dwa najpopularniejsze programy dostępne na
platformach Windows i Mac. Warto jednak poeksperymentować samodzielnie z
innymi klientami i znaleźć program najlepszy dla siebie.

-   TortoiseSVN (Windows) — http://tortoisesvn.net/
-   Versions (Mac) — http://www.versionsapp.com/

W tym punkcie nie mamy zamiaru nauczenia Cię używania Subversion. W
internecie na stronie http://svnbook.red-bean.com/nightly/en/index.html
znajduje się bezpłatna książka, dzięki której można poznać Subversion.
Poznanie przynajmniej podstaw Subversion jest wymagane, aby obsługiwać
repozytorium wtyczki.

Wszystkie wtyczki w repozytorium otrzymują unikalny adres URL
Subversion: http://plugins.svn.wordpress.org/nazwa-wtyczki, gdzie
nazwa-wtyczki oznacza nazwę katalogu zawierającego wtyczkę. W ten sposób
otrzymujesz dostęp do wskazanego katalogu w repozytorium. W celu dodania
plików i katalogów za pomocą ulubionego klienta Subversion, przy
przeprowadzaniu uwierzytelnienia musisz podać nazwę użytkownika i hasło
do konta założonego na witrynie WordPress.org.

Utworzenie pliku readme.txt

Wtyczki w repozytorium WordPress muszą zawierać plik readme.txt
umieszczony w katalogu głównym wtyczki. Informacje z wymienionego pliku
są używane przez repozytorium do utworzenia strony wtyczki w
repozytorium. Informacje zostaną udostępnione publicznie, więc powinny
być jak najbardziej jasne i użyteczne dla potencjalnych użytkowników.

Plik readme.txt tworzy na stronie wtyczki sekcje, co pokazano na rysunku
17.3.

W pliku readme.txt należy stosować składnię Markdown. Jest to narzędzie
służące do konwersji tekstu na kod HTML, w którym zastosowano
odpowiednie znaczniki. Więcej informacji na temat składni Markdown można
znaleźć na stronie projektu znajdującej się pod adresem
http://daringfireball.net/​projects/markdown/syntax.

Poniżej przedstawiono przykładowy szkielet pliku readme.txt dla wtyczek,
który można modyfikować i dostosowywać do własnych potrzeb.

    === Example Plugin Name ===
    Contributors: nazwa użytkownika
    Donate link: http://przyklad.pl
    Tags: przyklad, przyklad-2, przyklad-3
    Requires at least: 3.0
    Tested up to: 3.1
    Stable tag: 1.0
    Miejsce na krótki opis wtyczki, maksymalnie 150 znaków.
    == Description ==
    Miejsce na dłuższy opis wtyczki, który będzie wyświetlany na stronie głównej wtyczki.

[]

Rysunek 17.3. Umieszczone na stronie wtyczki informacje pochodzące z
pliku readme.txt

    == Installation ==
    Informacje dotyczące instalacji wtyczki.
    == Frequently Asked Questions ==
    = Przykładowe pytanie? =
    Odpowiedź na przykładowe pytanie.
    == Screenshots ==
    1. Opis dla rysunku screenshot-1.png.
    2. Opis dla rysunku screenshot-2.png.
    == Changelog ==
    = Wersja 1.0 =
    * Zmiana w stosunku do poprzedniej wersji.
    * Inna zmiana w stosunku do poprzedniej wersji.
    * Jeszcze jedna zmiana w stosunku do poprzedniej wersji.
    == Extra ==
    Wszelkie sekcje dodatkowe dotyczące wtyczki, o ile są niezbędne.

------------------------------------------------------------------------

Powyższy fragment kodu pochodzi z pliku readme.txt.

------------------------------------------------------------------------

Najważniejsza jest pierwsza sekcja pliku readme.txt, w której znajdują
się podstawowe informacje dotyczące wtyczki:

    === Example Plugin Name ===
    Contributors: nazwa użytkownika
    Donate link: http://przyklad.pl
    Tags: przyklad, przyklad-2, przyklad-3
    Requires at least: 3.0
    Tested up to: 3.1
    Stable tag: 1.0

W wierszy pierwszym powinna znajdować się nazwa wtyczki. Każdy z
kolejnych wierszy również ma określone znaczenie i trzeba się upewnić,
że podane tam informacje są poprawne.

-   Contributors — rozdzielona przecinkami lista nazw użytkowników
    zarejestrowanych w witrynie WordPress.org, którzy powinni mieć
    dostęp w celu aktualizacji wtyczki. Jeżeli jesteś jedynym twórcą
    wtyczki, w tym wierszu podaj tylko swoją nazwę użytkownika. Jeśli
    natomiast nad wtyczką pracujesz z innymi, każda osoba będzie musiała
    mieć swoje konto w witrynie WordPress.org, a jego nazwę użytkownika
    trzeba podać w tym wierszu.
-   Donate link — własny odnośnik prowadzący na stronę, na której
    użytkownicy mogą składać datki, w ten sposób wynagradzając Ci ciężką
    pracę nad wtyczką.
-   Tags — rozdzielona przecinkami lista tagów określających
    funkcjonalność wtyczki. Listę popularnych tagów można znaleźć na
    stronie http://wordpress.org/extend/plugins/tags/.
-   Requires at least — minimalna wersja platformy WordPress, którą
    użytkownik musi mieć zainstalowaną, aby korzystać z danej wtyczki.
-   Tested up to — najnowsza wersja platformy WordPress, z którą dana
    wtyczka została przetestowana.
-   Stable tag — wersja najnowszej, stabilnej wersji wtyczki.

Pozostałe sekcje pliku readme.txt są mniej ważne od pierwszej, ale
również zawierają istotne informacje, które pozwolą na utworzenie w
repozytorium doskonałej strony poświęconej wtyczce i umożliwią
użytkownikom pobranie wtyczki oraz zapoznanie się ze szczegółowymi
informacjami na jej temat. W przeciwieństwie do pierwszej, te sekcje
pozwalają już na znacznie większą dowolność w zakresie podawanych tam
informacji.

-   Description — to prawdopodobnie najużyteczniejsza sekcja pliku
    readme.txt, ponieważ zawiera opis wtyczki, który będzie wyświetlony
    na stronie głównej wtyczki w repozytorium. Informacje znajdujące się
    w tej sekcji powinny przyciągnąć uwagę użytkownika poprzez opis
    wtyczki, przedstawienie jej funkcji oraz wszelkich innych
    informacji, które użytkownik powinien poznać.
-   Installation — w tej sekcji można zamieścić szczegółowe informacje
    dotyczące instalacji wtyczki. Większość użytkowników potrafi
    instalować wtyczki, ale można przedstawić tutaj wszystkie dodatkowe
    kroki, które muszą być wykonane podczas instalacji lub aktualizacji
    wtyczki.
-   Frequently Asked Questions — kiedy zauważysz pojawianie się wciąż
    tych samych pytań dotyczących wtyczki, możesz je umieścić w tej
    sekcji wraz z odpowiedziami na nie. To rodzaj zapewnienia pomocy
    technicznej użytkownikom.
-   Screenshots — nie dla wszystkich wtyczek są dostarczane rysunki
    pokazujące wtyczkę w działaniu. Jeśli jednak istnieje taka
    możliwość, zawsze warto pokazać użytkownikom działającą wtyczkę.
    Rysunki muszą znajdować się w katalogu głównym wtyczki i być
    ponumerowane w następujący sposób: screenshot-1.png,
    screenshot-2.png itd. (Oczywiście, można podać rysunki w formacie
    .png, .jpg, .jpeg i .gif).
-   Changelog — w tej sekcji należy podać zmiany, które zostały
    wprowadzone we wtyczce względem jej poprzedniej wersji. Podawanie
    tego rodzaju informacji pokazuje użytkownikom jasną historię
    wprowadzanych zmian.
-   Extra — jeśli trzeba, w tym miejscu pliku readme.txt można utworzyć
    dodatkowe, dowolne sekcje, które dostarczą użytkownikom informacje
    dodatkowe o wtyczce.

Rozsławienie wtyczki

Różnica pomiędzy dobrym i doskonałym programistą często sprowadza się do
jednego: pasji. Jeżeli tworzysz wtyczkę lub wykonujesz pracę, która nie
jest Twoją pasją, brak wspomnianej pasji będzie dostrzegalny w Twojej
pracy i jej promocji. Gdy jesteś pasjonatem, bardzo łatwo zaangażujesz
się w społeczność i działania marketingowe.

Jednak na samym początku pasja nie wystarczy, musisz podjąć pewne kroki
w celu wypromowania swojej wtyczki. Czytając ten podrozdział, poznasz
podstawowy zestaw narzędzi i metod pozwalających na rozsławienie
wtyczek. Trzeba pamiętać o jednym — musisz chcieć wypromować swoją
wtyczkę.

W tym podrozdziale nie znajdziesz nieprawdziwych obietnic, wskazówek lub
recept na szybkie wypromowanie wtyczki. Przedstawione tutaj metody i
techniki są stosowane każdego dnia przez twórców wtyczek — każdy może je
zastosować, wystarczy tylko chcieć.

Nadawanie nazwy wtyczce

Określenie nazwy wtyczki może być jednym z najtrudniejszych zadań w
procesie jej tworzenia. Nie istnieją żadne zdefiniowane reguły dotyczące
nadawania nazw. Można jednak stosować pewne ogólne reguły dotyczące
nazewnictwa.

Gdy rozpoczynasz pracę na wtyczkami, doskonała nazwa może im pomóc na
wiele różnych sposobów. Kiedy Ty, Twoja firma lub utworzone przez was
rozwiązania pozostają nieznane, wykorzystaj tę okazję i wybierz
doskonałą nazwę, która może pomóc w publicznym zaistnieniu.

Wskazówki dotyczące tworzenia nazwy wtyczki

Podczas wymyślania nazwy wtyczki trzeba pamiętać o czterech aspektach.
Nazwa wtyczki powinna więc być:

-   jednoznaczna — upewnij się, że nazwa wtyczki faktycznie
    odzwierciedla jej przeznaczenie i wykonywane zadanie;
-   chwytliwa — unikalna nazwa wtyczki może przyciągnąć uwagę
    użytkowników, ponieważ jest nietypowa, zachowaj jednak umiar w
    chwytliwości, jednoznaczność jest znacznie ważniejsza;
-   prosta — pamiętaj, aby nazwa wtyczki była krótka, prosta i łatwa do
    wymówienia, zapewne chcesz, aby informacje o Twoim dziele były
    przekazywane dalej — nie wybieraj więc nazwy trudnej do wymówienia;
-   łatwa do zapamiętania — nazwa wtyczki powinna być łatwa do
    zapamiętania. Nie używaj w niej skomplikowanych słów lub wyrażeń.

Najważniejszym aspektem jest wybór jednoznacznej nazwy. Jeżeli nadasz
wtyczce nazwę zupełnie niezwiązaną z jej przeznaczeniem, użytkownicy
mogą nie dać jej drugiej szansy, nawet jeśli wtyczka ma im do
zaoferowania dokładnie te funkcje, których szukają.

Załóżmy, że utworzyłeś wtyczkę integrującą funkcje serwisu Twitter z
polami komentarza we wpisie bloga. Jak sądzisz, która z poniższych nazw
prawdopodobnie przyciągnie uwagę użytkownika jako najlepiej oddająca
przeznaczenie wtyczki?

-   Narzędzia formularza komentarza.
-   Komentarze serwisu Twitter.
-   Wspaniałe, rewelacyjne komentarze serwisu Twitter.

Możesz wierzyć lub nie, każda nazwa wtyczki ma swoje zalety. Tylko od
Ciebie zależy, która najlepiej pasuje do utworzonej wtyczki oraz do
przewidzianego sposobu wypromowania wtyczki.

-   Narzędzia formularza komentarza — jeżeli planujesz rozbudowę wtyczki
    w przyszłości o funkcje niezwiązane z serwisem Twitter, wówczas
    warto rozważyć użycie bardziej ogólnej nazwy dla wtyczki.
-   Komentarze serwisu Twitter — ta nazwa jest krótka i jednoznaczna.
    Prawdopodobnie stanowi najlepszy wybór z trzech tutaj
    przedstawionych, a jej użycie na pewno nie będzie błędem.
-   Wspaniałe, rewelacyjne komentarze serwisu Twitter — ta nazwa łamie
    regułę mówiącą o krótkiej nazwie, ale jednocześnie jest chwytliwa.
    Użytkownicy mogą ją pobierać tylko ze względu na samą nazwę.

Jakich nazw nie używać dla wtyczek?

Jedną z najgorszych rzeczy, jaką można zrobić podczas nadawania nazwy
wtyczce, jest zmylenie potencjalnych użytkowników. Dla platformy
WordPress dostępne są tysiące wtyczek, więc nie chcesz, aby nazwa Twojej
wtyczki była podobna do nazwy innego produktu. Przed wydaniem wtyczki
warto poświęcić chwilę i spróbować wyszukać wtyczki o podobnej nazwie,
aby upewnić się, że nie występują potencjalne konflikty nazw.

Ponadto w nazwach wtyczek nie należy stosować pewnych słów. Oto one.

-   WordPress — utworzyłeś przecież wtyczkę dla WordPress, więc nie ma
    potrzeby używania w nazwie słowa "WordPress". Prawdopodobnie warto
    również unikać używania "WP".
-   Wtyczka — nie trzeba powtarzać, że wtyczka to wtyczka. Taka nazwa na
    pewno nie pomoże wtyczce.
-   Wersja — w nazwie nie należy podawać informacji o wersji wtyczki.
    Jak wspomniano w rozdziale 2., platforma WordPress oferuje
    odpowiednie miejsce pozwalające na podanie wersji wtyczki.
-   Słowa kontrowersyjne — to wydaje się oczywiste, ale warto o tym
    wspomnieć. Nie obrażaj innych użytkowników poprzez użycie w nazwie
    wtyczki słów, które potencjalnie mogą zostać uznane za obraźliwe lub
    co najmniej kontrowersyjne.

Słowa, których nie powinno się używać w nazwach wtyczek, można bardzo
łatwo określić po chwili zastanowienia. Ponadto do nazwy nie dołączaj
informacji znanych użytkownikowi lub mogących go urazić.

Branding wtyczki

Ogólnie rzecz biorąc, w nazwie wtyczki nie powinny znajdować się nazwa
firmy lub Twoje imię. Jak już wspomniano w rozdziale 2., istnieją
odpowiednie miejsca we wtyczce, w których można znaleźć te informacje.
Jednak tego typu dane w nazwie mogą być użytecznymi technikami brandingu
pozwalającymi użytkownikom na łatwą identyfikację wtyczek utworzonych
przez Twoją firmę. Jeżeli zbudowana przez Ciebie wtyczka jest dobra (a
powinna, skoro czytasz tę książkę), nazwa Twojej firmy może stanowić
dodatkowy czynnik przyciągający użytkowników i wskazujący produkt dobrej
jakości.

Załóżmy, że nazwa Twojej firmy to Radioactive. Dobrym sposobem brandingu
wtyczki jest użycie prefiksu nazwy wtyczki w postaci nazwy firmy.
Poniżej wymieniono listę fikcyjnych nazw wtyczek, które mogą zostać
wykorzystane do brandingu:

-   Radioactive Komentarze serwisu Twitter,
-   Radioactive Powiązane wpisy bloga,
-   Radioactive Kolekcja muzyczna,
-   Radioactive Widget profilowania.

Technika ta oddala także niebezpieczeństwo zmylenia użytkownika podczas
przeglądania listy wtyczek o podobnej nazwie. Wątpliwe jest, aby inny
programista użył słowa "Radioactive" w nazwie utworzonej przez siebie
wtyczki.

Zbudowanie witryny internetowej

Jeżeli nie posiadasz bloga lub witryny internetowej, tracisz jedną z
najłatwiejszych metod promocji. Twoja witryna również powinna działać na
bazie platformy WordPress. Oczywiście, istnieją witryny oferujące
rozwiązania dla platformy WordPress, ale utworzone na bazie innych
systemów zarządzania treścią. Uruchomienie własnej witryny na bazie
innej niż WordPress nie pomoże w uwiarygodnieniu oferowanych usług i
produktów dla platformy WordPress. Nie możesz oczekiwać od użytkowników,
aby ufali oferowanym przez Ciebie wtyczkom dla platformy WordPress,
skoro nawet Ty sam nie używasz tej platformy do obsługi własnej witryny.

Utworzenie strony lub witryny dla wszystkich Twoich wtyczek

Na swojej witrynie powinieneś zbudować stronę przedstawiającą wszystkie
opracowane przez Ciebie wtyczki. Zachowujesz w ten sposób kontrolę nad
sposobem ich zaprezentowania światu w jednym miejscu. W celu
przedstawienia swoich wtyczek możesz podjąć szereg działań, m.in.:

-   wymienić nazwy wtyczek, przedstawić ich opisy oraz podać odnośniki
    prowadzące do stron poświęconych poszczególnym wtyczkom;
-   utworzyć i pokazać miniatury przedstawiające wtyczki w działaniu;
-   utworzyć chwytliwe komunikaty informujące użytkowników o zaletach
    używania danych wtyczek.

Możesz nawet przygotować oddzielną witrynę przeznaczoną do
przedstawienia pojedynczej wtyczki lub wszystkich Twoich wtyczek. Jedną
z najlepszych witryn internetowych poświęconych całkowicie jednej
wtyczce jest Gravity Forms (http://www.gravityforms.com/), którą
pokazano na rysunku 17.4. Na stronie głównej wymienionej witryny
znajdują się przyciągające wzrok rysunki pokazujące wtyczkę w działaniu,
a poniżej użyteczne informacje na jej temat.

Przygotowanie doskonałego projektu

Niestety, nie wszyscy programiści są zarazem doskonałymi projektantami.
Jednak projekt bez wątpienia odgrywa ważną rolę w marketingu. Nie musisz
mieć przesadnie krzykliwego lub najbardziej kreatywnego projektu witryny
w internecie. Czasami prosty projekt wraz ze wszystkimi niezbędnymi
informacjami może być lepszy od krzykliwego. Doskonały projekt na
pierwszym miejscu stawia treść witryny.

[]

Rysunek 17.4. Witryna Gravity Forms

Jeżeli nie masz absolutnie żadnych umiejętności w zakresie
projektowania, warto rozważyć zatrudnienie profesjonalnego projektanta,
który przygotuje witrynę internetową oraz strony dla wtyczek. W zamian
za pracę nad projektem możesz zaproponować swoje usługi. Zatrudnienie
profesjonalisty pochodzącego ze społeczności WordPress może nawet
przysporzyć Ci przyjaciela w społeczności, który mógłby pomóc w promocji
wtyczki. Zawsze należy szukać możliwości nawiązywania kontaktów z innymi
członkami społeczności.

Blogowanie na temat WordPress

Witryny nie musisz budować jedynie w celu promowania wtyczek. Doskonałym
sposobem zyskania większej popularności jest publikowanie wpisów bloga
dotyczących platformy WordPress. Na pewno podczas tworzenia wtyczek
opracowałeś pewne użyteczne fragmenty kodu i pewnie wpadłeś na ciekawe
pomysły bądź rozwiązania. Podzielenie się tymi informacjami na blogu z
innymi użytkownikami może przyczynić się do powiększenia bazy
użytkowników. Jeżeli jakość publikowanych wpisów bloga będzie wysoka,
inni szybko to zauważą. To może znacznie ułatwić przygotowanie gruntu
dla Twoich wtyczek. Pomagając innym, pośrednio przyczynisz się do
promowania swojej pracy i produktów.

Jeśli chcesz się oderwać od kodu, zawsze możesz uruchomić blog
poświęcony platformie WordPress, ale bez prezentowania w nim rozwiązań
technicznych zawierających kod. Tematem może być sama platforma,
planowane wydarzenia, informacje o nowościach, prowokowanie dyskusji
itd. Celem prowadzenia bloga dotyczącego platformy WordPress jest
zaangażowanie się w społeczność poprzez dzielenie się pomysłami i
wiedzą. Członkowie społeczności WordPress uwielbiają czytać doskonałe
blogi poświęcone platformie. Warto więc przypomnieć raz jeszcze,
utworzenie własnego bloga poświęconego WordPress może pomóc w promocji
własnej pracy i produktów.

Utworzenie strony dla wtyczki

Omówiono już przygotowanie strony wtyczki wyświetlanej w repozytorium
wtyczek na witrynie WordPress.org. To użyteczne rozwiązanie, które może
pomóc w promocji. Nie zapominaj jednak, że musisz konkurować z tysiącami
innych wtyczek dostępnych w repozytorium. Utworzona przez Ciebie wtyczka
bardzo szybko może zniknąć pod wieloma innymi opcjami, co utrudni
użytkownikom jej wyszukanie.

Dedykowana wtyczce strona na Twojej witrynie internetowej może pomóc w
marketingu. Podczas budowy tego rodzaju strony na witrynie internetowej
najważniejsze jest dostarczenie istotnych i jasnych informacji
dotyczących wtyczki, a także przedstawienie funkcji oferowanych przez
wtyczkę. Wspomniane informacje powinny być łatwo dostępne.

-   Umieść na stronie łatwo dostępny odnośnik pozwalający na pobranie
    wtyczki. Wielu programistów tworzy doskonałe strony poświęcone
    wtyczkom, ale zapomina o tym najważniejszym elemencie.
-   Przygotuj jasny opis funkcji i możliwości oferowanych przez funkcję.
-   Przygotuj dokumentację i samouczki.
-   Użyteczne będzie umieszczenie odnośnika do dokumentacji WordPress
    powiązanej z wtyczką.
-   Nie zapominaj o bieżącym uaktualnianiu informacji o zmianach
    wprowadzonych we wtyczce.
-   Jeśli to możliwe, umieść rysunki pokazujące wtyczkę w działaniu.
-   Jeżeli Twoja wtyczka jest umieszczona w repozytorium WordPress, na
    swojej stronie umieść odnośnik prowadzący do strony wtyczki w
    repozytorium.

Ogłoszenie wydania wtyczki

Ogłoszenie wydania wtyczki to jedno z najważniejszych zadań. Inni muszą
dowiedzieć się, że utworzyłeś nową wtyczkę dla platformy WordPress.
Jeżeli nie posiadasz bloga lub witryny internetowej, czym prędzej
powinieneś uzupełnić ten brak. Własna witryna lub blog to pierwsze
miejsce, w którym można ogłosić utworzenie i wydanie wtyczki. Czytelnicy
prawdopodobnie będą tę informację przekazywać dalej. Niektórzy z nich
prowadzą własne blogi, mogą więc opublikować na ten temat własny wpis. Z
kolei inni mogą w serwisach społecznościowych podawać odnośniki
prowadzące do Twojej wtyczki.

Pierwszym krokiem w promocji nowej wtyczki zawsze powinno być ogłoszenie
na blogu. Podczas ogłaszania wydania wtyczki zawsze powinieneś
ograniczyć się jedynie do informacji dotyczących wtyczki. Rzucenie od
niechcenia informacji na jej temat na końcu wpisu bloga poświęconego
innemu zagadnieniu może nie wzbudzić zbyt dużej uwagi czytelników. Wpis
bloga powinien być w całości poświęcony wtyczce. W ten sposób zyskujesz
doskonałą możliwość przedstawienia czytelnikom informacji o samej
wtyczce, jej możliwościach i korzyściach, jakie mogą uzyskać dzięki jej
używaniu.

Przygotowując wpis bloga z ogłoszeniem wydania nowej wtyczki, możesz
wykonać jeszcze kilka innych kroków.

-   Poproś inną osobę piszącą na temat WordPress o przygotowanie
    recenzji wtyczki.
-   Ogłoś wydanie wtyczki w serwisach społecznościowych, takich jak
    Twitter.
-   Informację o wydaniu wtyczki możesz zamieścić na forach poświęconych
    platformie WordPress.

------------------------------------------------------------------------

Uwaga

Ogłoszenie na swoim blogu informacji o wydaniu nowej wtyczki to także
pewna niepisana tradycja w społeczności WordPress. Programiści tak
postępują, ponieważ tego rodzaju zachowania oczekują od nich
użytkownicy. Podobne oczekiwania dotyczą także nowo wydawanych wtyczek.

------------------------------------------------------------------------

Pomoc techniczna dla użytkowników wtyczki

W idealnym świecie wtyczka jest doskonale przygotowana, łatwa w użyciu,
więc nie trzeba zapewniać użytkownikom pomocy technicznej. Jednak zawsze
znajdą się użytkownicy, u których wtyczka nie będzie działała, którzy
nie rozumieją podanych poleceń lub chcą ją dostosować do własnych
potrzeb. Zaoferowanie pomocy technicznej użytkownikom wtyczki daje Ci
możliwość zdobycia większej popularności.

Jeżeli profesjonalnie zajmujesz się opracowywaniem wtyczek, powinieneś
rozważyć utworzenie w witrynie internetowej oddzielnego kanału
poświęconego pomocy technicznej. To może być system przyjmowania
informacji o błędach, forum lub inny rodzaj systemu pomocy. Inną
możliwością jest nawet zaoferowanie płatnej pomocy technicznej. E-mail
może się sprawdzić jako system pomocy technicznej po rozpoczęciu
działalności, ale kiedy Twoje wtyczki staną się popularniejsze,
zarządzanie wiadomościami e-mail bardzo szybko stanie się uciążliwe.

Jeżeli utworzyłeś wtyczkę dla rozrywki lub w celach niekomercyjnych,
uruchamianie kanału pomocy technicznej w swojej witrynie może być
zabójcze. Wszystkie wtyczki umieszczone w repozytorium WordPress.org
(omówione we wcześniejszej części rozdziału) są automatycznie łączone z
udostępnianymi przez WordPress forami pomocy technicznej
(http://wordpress.org/support/). Wspomniane fora możesz wykorzystać do
zaoferowania pomocy technicznej użytkownikom Twoich wtyczek i nie
trudzić się otwieraniem kanału pomocy technicznej we własnej witrynie.

Poniżej wymieniono kilka korzyści płynących z oferowania pomocy
technicznej użytkownikom Twoich wtyczek.

-   Budowa relacji z użytkownikami. Z kolei użytkownicy mogą
    poinformować o Twojej wtyczce przyjaciół bądź zamieścić na ten temat
    informacje na swoim blogu.
-   Wyszukiwanie błędów w Twoich wtyczkach. Nie ma wtyczek bezbłędnych.
    Sprawdzanie zgłoszeń użytkowników może Ci pomóc w wyszukiwaniu
    błędów.
-   Jeżeli utworzysz własny system pomocy technicznej, zachowujesz
    kontrolę nad regułami i możesz oferować pomoc techniczną w
    najwygodniejszy dla Ciebie sposób.

Zbieranie informacji od użytkowników

Zbieranie informacji od użytkowników oraz innych programistów ma istotne
znaczenie podczas tworzenia doskonałych wtyczek. To Ty jesteś twórcą
wtyczki, więc prawdopodobnie znasz jej kod na wylot i nie masz żadnych
problemów z jej używaniem. Jednak nie każdy patrzy na wtyczkę z Twojego
punktu widzenia. Zbieranie informacji od użytkowników to doskonały
sposób sprawdzenia, jak inni używają Twoich wtyczek i co o nich sądzą.

Wiele problemów zgłaszanych w ramach pomocy technicznej wiąże się z tym,
że użytkownicy nie rozumieją sposobu działania wtyczki, a nie z
problemami dotyczącymi samego kodu źródłowego. Wysłuchanie użytkowników
umożliwia poprawienie napotykanych przez nich problemów, które nie są
oczywiste dla twórcy programisty.

Zbieranie informacji od użytkowników to ważny aspekt przyczyniający się
do poprawy jakości platformy WordPress. Poniżej wymieniono stosowane na
platformie WordPress różne sposoby, na jakie można zbierać informacje od
użytkowników. Zaprezentowana lista to doskonały przykład przedstawienia
realizacji takiego zadania.

-   Pomysły (http://wordpress.org/extend/ideas/) — forum pozwalające na
    przedstawienie, dyskusję oraz ocenę pomysłów dotyczących jądra
    platformy WordPress.
-   Kvetch! (http://wordpress.org/extend/kvetch/) — anonimowy system
    pozwalający użytkownikom na składanie skarg dotyczących platformy
    WordPress.
-   Propozycje nowych funkcji i informacje od użytkowników
    (http://wordpress.org/support/forum/​requests-and-feedback) — forum
    dedykowane zgłaszaniu propozycji nowych funkcji oraz pozwalające na
    przekazywanie innych informacji od użytkowników.
-   Sondy — czasami są publikowane publicznie dostępne sondy i ankiety,
    które mają na celu umożliwienie użytkownikom oddania głosu na
    propozycje nowych funkcji lub realizacji innych pomysłów.

Baza użytkowników platformy WordPress jest liczona w milionach, więc
posiadanie odpowiednio przygotowanego systemu zbierania informacji od
użytkowników ma znaczenie krytyczne. Ogólnie rzecz biorąc, pojedyncze
wtyczki nie mają aż tak wielu użytkowników, ale popularne mogą być
używane przez tysiące osób. Jeżeli budujesz wtyczki dla siebie, bez
zastosowania odpowiedniego systemu zbieranie informacji od użytkowników
bardzo szybko stanie się uciążliwe.

Informacje od użytkowników można otrzymywać na wiele sposobów.

-   Wiadomości e-mail — na stronie internetowej należy przygotować
    formularz, za pomocą którego użytkownicy będą mogli bezpośrednio
    przekazywać informacje.
-   Komentarze na blogu — pozwól użytkownikom na zamieszczanie
    komentarzy pod wpisami bloga informującymi o wydaniu wtyczek.
-   Pomysły zgłaszane na forum — jeśli uruchomiłeś własne forum jako
    jeden z kanałów pomocy technicznej, utwórz dodatkowe forum
    przeznaczone do zgłaszania nowych pomysłów oraz przekazywania innych
    informacji przez użytkowników.
-   Sondy — dobrym pomysłem jest okresowe publikowanie sond w celu
    zebrania informacji od użytkowników. PollDaddy
    (http://polldaddy.com/) to doskonała usługa pozwalająca na
    konfigurację sond czy ankiet i śledzenie wyników.
-   Pomoc techniczna — jak już wspomniano wcześniej, zapewnienie pomocy
    technicznej użytkownikom wtyczek może przynieść pewne korzyści.
    Wszystkie pytania zgłaszane w ramach pomocy technicznej oraz
    informacje przekazywane przez użytkowników powinieneś traktować jako
    podpowiedzi wskazujące możliwości dalszego usprawnienia danego
    produktu.

Zbieranie informacji od użytkowników to tylko część procesu. Aby
usprawnić wtyczkę i powiększyć bazę jej użytkowników, konieczne jest
jeszcze podjęcie działania. Nie wszystkie pomysły i propozycje zgłaszane
przez użytkowników są doskonałe. Mimo wszystko, to Ty jesteś programistą
i do Ciebie należy podjęcie ostatecznej decyzji. Jeśli nawet nie
wykorzystasz pomysłu przedstawionego przez użytkownika, nadal powinieneś
traktować zarówno pomysł, jak i samego użytkownika całkiem poważnie.
Jeśli to konieczne, wyjaśnij użytkownikowi, dlaczego nie możesz wdrożyć
jego pomysłu.

Największą korzyścią płynącą ze słuchania użytkowników i zbierania od
nich informacji, poza poprawą wtyczki, jest budowa społeczności. Na
budowie relacji z użytkownikami zyskujesz i Ty, ponieważ zadowoleni
użytkownicy sami będą promowali Twój produkt.

Wyjście z piwnicy

Często spotykany stereotyp programisty to mężczyzna żyjący i pracujący w
piwnicy u rodziców bądź w garażu. Oczywiście, nie wszyscy programiści są
samotnikami. Pochwalenie się swoją piwnicą w internecie na pewno nie
pomoże w promocji wtyczki. Na szczęście, internet oferuje każdemu
możliwość zaprezentowania się z jak najlepszej strony.

Skuteczny marketing Twoich wtyczek, Ciebie samego i Twojej firmy wymaga
aktywnego uczestnictwa w społeczności WordPress. To oznacza
zaangażowanie się w prace nad samą platformą WordPress, pomoc innym
programistom, udzielanie się na forum i czacie, komentowanie na blogach
innych użytkowników, a także podejmowanie wszelkich innych form
aktywności.

Jedną z najgorszych rzeczy, jaką możesz zrobić, jest pozostawienie na
blogu innej osoby komentarza w stylu "Cześć, zobacz moją nową wtyczkę.
To najlepsza utworzona dotąd wtyczka!". Tego rodzaju komentarz to po
prostu odpowiednik spamu. Pozwól, aby Twoja praca stała się znana dzięki
Tobie i Twoim wartościowym komentarzom. Większość blogów posiada pole
komentarza, w którym można podać m.in. odnośnik do własnej witryny. To
otwiera możliwość do pokazania swoich produktów innym użytkownikom, a
nawet pozwala na ich promowanie.

Aktywność społeczna to nie tylko promocja samego siebie. Zaangażowanie
się w społeczność powinno być przyjemnością. Znajdź więc witryny i
blogi, których częścią chciałbyś się stać. Jeżeli zaangażowanie się w
społeczność nie sprawia Ci radości, bardzo szybko poddasz się i
zakończysz proces aktywności społecznej.

Inne metody promocji

Jak już prawdopodobnie zauważyłeś, promocja swojej pracy to w mniejszym
stopniu promocja utworzonego produktu, czyli wtyczki, a bardziej
promocja siebie i własnej firmy. Kiedy budujesz firmę, powinieneś się
skoncentrować na budowie obrazu marki w społeczności WordPress. Jeśli
działasz sam, to Ty jesteś marką, więc powinieneś dążyć do tego, aby
inni Cię poznali.

Istnieje także kilka innych sposobów, dzięki którym możesz promować
swoją pracę.

-   Pisz na innych blogach poświęconych platformie WordPress. Jeżeli nie
    jesteś jeszcze dobrze znany w społeczności, zapytaj prowadzących
    inne witryny poświęcone platformie WordPress o możliwość napisania
    kilku artykułów. Tego rodzaju witryny na końcu wpisów bloga zwykle
    mają sekcje "O autorze", w których można podać np. odnośnik do
    własnej witryny.
-   Zaangażuj się, wykorzystując serwisy społecznościowe, takie jak
    Twitter i Facebook. Ponieważ i tak prawdopodobnie jesteś członkiem
    wymienionej społeczności, nie zmarnuj okazji, aby się pokazać. W
    serwisach stań się przyjacielem innych członków społeczności
    WordPress.
-   Publikuj na forach powiązanych z WordPress. Pozwól, aby inni
    członkowie Cię poznali. Doskonałym miejscem dla programistów
    WordPress jest WP Tavern: http://www.wptavern.com/forum/.
-   Poświęć trochę czasu i zaoferuj bezpłatnie swoje usługi nowym
    użytkownikom WordPress za pomocą forów pomocy technicznej platformy:
    http://wordpress.org/support/. W ten sposób powiększysz swoją wiedzę
    i zdobędziesz wdzięczność użytkowników, którzy mieli problemy.
-   Twórz poprawki i zgłaszaj błędy dotyczące kodu jądra platformy
    WordPress (http://core.trac.wordpress.org/). Dzięki temu staniesz
    się lepszym programistą, a jeśli będziesz dobry, inni Cię zauważą.
-   Weź udział w spotkaniu WordCamp. Wspomniany WordCamp to jedno- lub
    dwudniowe spotkania odbywające się na całym świecie, podczas których
    uczestnicy po prostu rozmawiają o platformie WordPress, spożywają
    świetne posiłki i biorą udział w prezentacjach. Informacje o
    spotkaniach WordCamp znajdziesz na witrynie internetowej WordCamp
    pod adresem http://wordcamp.org/.

Wszystkie pozycje wymienione na powyższej liście to proste zadania,
dzięki którym staniesz się lepszym programistą i bardziej zaangażujesz
się w prace społeczności. Liczą się nie tylko techniki czysto
marketingowe, ale również rzeczy, które po prostu lubisz robić.

Nie musisz wykonać wszystkich zadań wymienionych na powyższej liście.
Jednak im więcej sposobów, na jakie staniesz się zaangażowany w
społeczność, tym więcej możliwości promowania własnych wtyczek
otrzymasz.

Podsumowanie

Wprawdzie do wypromowania własnych produktów najlepiej byłoby, gdybyś
mógł zatrudnić eksperta ds. marketingu, ale to nie jest konieczne.
Naprawdę nie musisz być specjalistą marketingu, aby wypromować swoje
produkty. Kiedy Twoja praca sprawia Ci przyjemność i sądzisz, że
tworzone przez Ciebie produkty mogą przydać się innym, to możesz bardzo
łatwo je wypromować.

Najważniejsze, co trzeba zapamiętać z tego rozdziału, to aktywność w
społeczności WordPress w celu promowania tworzonych wtyczek. Społeczność
WordPress to ogromna i różnorodna grupa osób, więc masz ogromną rzeszę
użytkowników, wśród których możesz się wypromować. Pamiętaj, że nie
powinieneś zaangażować się jedynie w promocję własnych produktów.
Udzielaj się, ponieważ stanie się częścią społeczności powinno sprawić
Ci przyjemność. Jeśli tak będzie, Twoja praca sama będzie się promować.

Rozdział 18 Narzędzia programisty

W tym rozdziale:

-   Używanie jądra platformy WordPress jako punktu odniesienia
-   Zrozumienie dokumentacji osadzonej na platformie
-   Poznanie popularnych plików tworzących platformę oraz zdefiniowanych
    w nich funkcji
-   Wykorzystanie witryn internetowych oraz zasobów społeczności
-   Narzędzia oferowane przez zewnętrzne witryny internetowe
-   Przygotowanie zestawu narzędzi programisty

W trakcie tworzenia wtyczek dla WordPress musisz mieć przygotowaną dobrą
listę zasobów, dzięki którym prace będą postępowały we właściwym
kierunku. Wspomniana lista to po prostu zestaw narzędzi programisty. W
tym rozdziale zostaną przedstawione najpopularniejsze i
najużyteczniejsze zasoby dostępne dla twórcy wtyczek. Ponadto zapoznasz
się z narzędziami, których każdy programista powinien używać, aby
zoptymalizować proces tworzenia wtyczek.

Jądro platformy jako punkt odniesienia

Podczas tworzenia wtyczek dla platformy WordPress najlepszym punktem
odniesienia jest kod jądra samej platformy. Jaki może być lepszy sposób
poznania i odkrycia funkcji niż przeglądanie kodu używanego do
uruchamiania Twoich wtyczek? Nauczenie się poruszania po kodzie
tworzącym jądro platformy WordPress to nieoceniona umiejętność przydatna
w trakcie tworzenia profesjonalnych wtyczek. Poza tym, w przeciwieństwie
do zasobów dostępnych w internecie oraz w witrynie Codex, jądro tworzące
platformę zawsze pozostaje aktualne.

Dokumentacja osadzona na platformie

W wielu plikach tworzących jądro platformy osadzono dokumentację.
Wspomniana dokumentacja w postaci komentarzy umieszczonych w kodzie
zawiera szczegółowe informacje dotyczące sposobu działania funkcji i
kodu. Cała dokumentacja osadzona w kodzie jest sformatowana za pomocą
standardu PHPDoc określającego stosowanie komentarzy w PHP.
Przedstawiony poniżej przykład komentarza to standardowy szablon PHPDoc
używany do dokumentowania funkcji WordPress:

    /**
     * Krótki opis funkcji.
     *
     * Znacznie dłuższy i dokładniejszy opis funkcji.
     *
     * @package WordPress
     * since wersja
     *
     * @param   typ    $zmienna1   Opis
     * @return  typ                          Opis
    */

Dokumentacja osadzona w kodzie to nieoceniony zasób wiedzy podczas
przeglądania funkcji dostępnych na platformie WordPress. Komentarz
zawiera krótki i długi opis funkcji, szczegółowo omawiający
przeznaczenie danej funkcji. W komentarzu znajdują się także informacje
o wersji platformy, w której została dodana funkcja. W ten sposób można
bardzo łatwo określić, które funkcje zostały dodane w poszczególnych
wydaniach platformy WordPress.

Komentarz zawiera także parametry używane przez funkcję wraz z ich
typami danych oraz szczegółowym opisem przeznaczenia. Kolejne informacje
zawarte w komentarzu to dane wyjściowe funkcji oraz ich opis. To pozwala
na zrozumienie, jaka wartość powinna być zwracana przez daną funkcję.
Jeśli przykładowo operacja tworzenia nowego wpisu bloga na platformie
WordPress zakończy się powodzeniem, wartością zwrotną może być
identyfikator nowo utworzonego wpisu bloga.

Spójrz teraz na rzeczywisty przykład osadzonej dokumentacji dla funkcji
delete_option():

    /**
    * Usuwa opcję, używając jej nazwy. Uniemożliwia usunięcie chronionych opcji WordPress. *
    * @package WordPress
    * @subpackage Option
    * @since 1.2.0 
    *
    * @uses do_action() Wywołuje zaczep 'delete_option' przed usunięciem opcji.
    * @uses do_action() Wywołuje zaczepy 'deleted_option' i 'delete_option_$option', gdy operacja zakończy się powodzeniem.
    *
    * @param string $option Nazwa opcji przeznaczonej do usunięcia.
    * @return bool W przypadku powodzenia operacji wartością zwrotną jest true, w przeciwnym razie false. 
    */
    function delete_option( $option ) {

Dokumentacja osadzona w kodzie zawiera jasny opis przeznaczenia danej
funkcji. Z powyższego komentarza jasno wynika, że wymieniona funkcja
jest częścią pakietu WordPress i została dodana w wersji 1.2.0. W
komentarzu wymieniono także zaczepy akcji uruchamiane podczas
wywoływania tej funkcji — delete_option, deleted_option i
delete_option_$option.

Jedynym wymaganym parametrem tej funkcji jest $option, który określa
nazwę opcji przeznaczoną do usunięcia. Wartością zwrotną funkcji jest
true w przypadku operacji zakończonej powodzeniem i false w przeciwnym
razie.

Tworzenie dokumentacji osadzonej w kodzie to proces, który trwa
nieustannie. Wszystkie nowe funkcje dodawane na platformie WordPress są
dokumentowane w taki właśnie sposób. Pomoc w tworzeniu dokumentacji dla
istniejących funkcji to doskonały sposób zaangażowania się w prace nad
platformą WordPress.

Wyszukiwanie funkcji

Skoro dowiedziałeś się, w jaki sposób używać osadzonej dokumentacji w
celu rozpoznawania funkcji WordPress, powinieneś także nauczyć się
sposobów wyszukiwania funkcji. Na początek upewnij się o pobraniu
najnowszej platformy WordPress. W jej kodzie będziesz wyszukiwał
funkcje.

Każdy plik tworzący jądro platformy, z wyłączeniem plików graficznych,
może być wyświetlony w zwykłym edytorze tekstowym. Podczas wyboru
edytora tekstowego upewnij się, że wyposażono go w funkcję wyszukiwania
w plikach. Obszerna lista edytorów tekstowych znajduje się w witrynie
Codex pod adresem http://codex.wordpress.org/Glossary#Text_editor.

Podczas przeszukiwania plików tworzących jądro platformy WordPress w
celu znalezienia określonej funkcji musisz upewnić się, że wywołania
szukanej funkcji zostaną odfiltrowane. W przeciwnym razie otrzymasz
setki wyników. Najłatwiejszym sposobem odfiltrowania jest użycie słowa
function na początku szukanego wyrażenia. Aby przykładowo znaleźć
definicję funkcji wp_insert_post(), należy użyć wyrażenia
function wp_insert_post.

------------------------------------------------------------------------

Uwaga

Pamiętaj, że na platformie WordPress wykorzystuje się nie tylko funkcje.
Jeżeli nie otrzymasz żadnych wyników wyszukiwania, usuń słowo function z
podanego wyrażenia. Nie zapomnij także o przeprowadzaniu wyszukiwania we
wszystkich plikach (*.*), a nie jedynie w plikach .txt, co domyślnie ma
miejsce w wielu edytorach tekstowych.

------------------------------------------------------------------------

Najważniejsze pliki tworzące jądro platformy

Wiele funkcji używanych we wtyczkach znajduje się w określonych plikach
tworzących jądro platformy. Przeglądanie tych plików to doskonały sposób
wyszukiwania nowych, ciekawych funkcji, które będzie można wykorzystać
we własnych wtyczkach.

Katalog wp-includes zawiera wiele plików służących do zdefiniowania
publicznie dostępnych funkcji, czyli funkcji używanych na publicznie
dostępnej części danej witryny internetowej.

formatting.php

W pliku formatting.php znajdują się wszystkie funkcje obsługujące
formatowanie na platformie WordPress, m.in.:

-   esc_*() — wszystkie funkcje odpowiedzialne za oczyszczanie danych
    wejściowych użytkownika;
-   is_email() — weryfikacja poprawności adresu e-mail;
-   wp_strip_all_tags() — oczyszczanie wszystkich znaczników HTML
    (łącznie ze script i style) w ciągu tekstowym.

functions.php

W pliku functions.php znajdują się główne funkcje platformy WordPress.
Opisane niżej funkcje są wykorzystywane przez wtyczki, motywy oraz jądro
platformy WordPress:

-   *_option() — dodawanie, uaktualnianie, usuwanie i pobieranie opcji;
-   current_time() — pobranie bieżącej godziny na podstawie strefy
    czasowej zdefiniowanej na platformie WordPress;
-   wp_nonce_*() — tworzenie unikalnych wartości dla formularzy i
    adresów URL;
-   wp_upload_dir() — pobranie tablicy zawierającej ścieżkę dostępu i
    adres URL do bieżącego katalogu przekazywania danych do serwera.

pluggable.php

W pliku pluggable.php są zdefiniowane podstawowe funkcje, które mogą być
ponownie zdefiniowane (nadpisane) we wtyczce. Plik jest wypełniony
użytecznymi funkcjami gotowymi do wykorzystania we wtyczkach:

-   get_userdata() — pobieranie wszystkich danych użytkownika o
    wskazanym identyfikatorze;
-   get_currentuserinfo() — pobieranie wszystkich danych aktualnie
    zalogowanego użytkownika;
-   get_avatar() — pobieranie awatara użytkownika;
-   wp_mail() — główna funkcja pozwalająca na wysyłanie wiadomości
    e-mail na platformie WordPress;
-   wp_redirect() — przekierowanie na inną stronę;
-   wp_rand() — wygenerowanie liczby losowej.

plugin.php

Plik plugin.php zawiera funkcje API Plugin platformy WordPress, m.in.:

-   add_action() — wykonanie danego zaczepu w pewnym zdefiniowanym
    momencie działania platformy WordPress;
-   add_filter() — dany zaczep będzie użyty do filtrowania danych przed
    ich zapisaniem w bazie danych lub wyświetleniem na ekranie;
-   plugin_dir_*() — funkcje pozwalające na określenie ścieżki dostępu i
    adresu URL wtyczki;
-   register_activaction_hook() — funkcja wywoływana podczas aktywacji
    wtyczki;
-   register_deactivation_hook() — funkcja wywoływana podczas
    dezaktywacji wtyczki;
-   register_uninstall_hook() — funkcja wywoływana podczas dezinstalacji
    wtyczki, gdy w katalogu wtyczki nie istnieje plik o nazwie
    uninstall.php.

post.php

Plik post.php zawiera funkcje dotyczące wpisów bloga na platformie
WordPress, m.in.:

-   wp_*_post() — funkcje odpowiedzialne za tworzenie, uaktualnianie i
    usuwanie wpisów bloga;
-   get_posts() — zwraca listę wpisów bloga wygenerowaną na podstawie
    podanych parametrów;
-   get_pages() — zwraca listę stron wygenerowaną na podstawie podanych
    parametrów;
-   *_post_meta() — funkcje odpowiedzialne za tworzenie, uaktualnianie i
    usuwanie metadanych wpisów bloga;
-   register_post_type() — rejestracja własnych typów wpisu bloga;
-   get_post_types() — pobranie listy wszystkich zarejestrowanych typów
    wpisów bloga.

To tylko krótka lista najpopularniejszych funkcji i miejsca ich
zdefiniowania. Podczas tworzenia wtyczek programista ma do dyspozycji
znacznie większą liczbę funkcji. Po wydaniu nowej wersji platformy
WordPress prawdziwą radość sprawia przeglądanie plików tworzących
platformę w poszukiwaniu dodanych funkcji, które można wykorzystać we
własnych wtyczkach.

Codex

Dla twórcy wtyczek na platformę WordPress jednym z najważniejszych
zasobów dostępnych w internecie jest WordPress Codex. Codex to po prostu
witryna typu wiki zawierająca dokumentację WordPress i dostępna pod
adresem http://codex.wordpress.org/pl:Strona_główna.

Witryna Codex jest wypełniona po brzegi informacjami dotyczącymi
używania i programowania na platformie WordPress. Zawiera wyczerpujące
opisy funkcji, przydatne samouczki oraz przykłady pokazujące możliwości
najczęściej używanych funkcji WordPress.

Przeszukiwanie witryny Codex

Witrynę Codex można przeszukiwać na wiele różnych sposobów. Najczęściej
stosowanym jest po prostu użycie pola wyszukiwania znajdującego się w
prawym górnym rogu strony. W polu należy podać szukane wyrażenie.
Domyślnie przeszukiwana jest dokumentacja na witrynie Codex, ale
istnieje także możliwość przeszukania forum pomocy technicznej, blogów
WP oraz bazy danych błędów (zobacz rysunek 18.1).

[]

Rysunek 18.1. Pole pozwalające na przeszukiwanie witryny Codex

Na witrynie Codex znajdziesz również wyczerpujący słownik, który okaże
się pomocny podczas poznawania pojęć i wyrażeń stosowanych zarówno w
witrynie Codex, jak i na platformie WordPress. Słownik jest dostępny pod
adresem http://codex.wordpress.org/Glossary.

Na stronie głównej Codex znajduje się indeks artykułów pogrupowanych
tematycznie. Same artykuły są ułożone w kolejności ich poziomu
trudności, a artykuły dotyczące najnowszej wersji platformy znajdują się
na samym początku. Wspomniane artykuły zawierają m.in. szczegółowe
omówienie nowych funkcji i zmian wprowadzonych w najnowszej wersji
WordPress. Zapoznanie się z tym artykułem zawsze jest dobrym pomysłem,
gdyż znajdują się w nim informacje o ostatnio wprowadzonych zmianach w
funkcjach i metodach tworzenia wtyczek dla platformy WordPress.

Opis funkcji

Z punktu widzenia twórcy wtyczek, największą zaletą witryny Codex jest
strona zawierająca opis funkcji, która znajduje się pod adresem
http://codex.wordpress.org/Function_Reference. Na stronie zostały
wymienione wszystkie funkcje dla najpopularniejszych API WordPress. Ta
strona powinna znaleźć się na liście ulubionych stron każdego twórcy
wtyczek dla WordPress.

Na każdej stronie poświęconej funkcji znajduje się jej szczegółowy opis,
przykład pokazujący jej użycie, parametry wymagane przez funkcję oraz
wartości zwrotne. Tego rodzaju stronę można potraktować jako łatwo
dostępną i czytelną dokumentację dla funkcji. Na większości stron
znajdują się również przykłady pokazujące praktyczne wykorzystanie
omawianej funkcji.

------------------------------------------------------------------------

Uwaga

Witryna Codex to doskonały zasób, ale nie gwarantuje, że wszystkie
przedstawione tam informacje będą odpowiednie i aktualne. Pamiętaj, że
jądro platformy WordPress to jedyny zasób, który zawsze jest w 100%
aktualny.

------------------------------------------------------------------------

Narzędzia oferowane przez inne witryny internetowe

Wiele innych witryn internetowych oferuje zasoby przydane podczas
szukania i poznawania określonych funkcji platformy WordPress.
Wspominane witryny mogą okazać się pomocne po wydaniu nowej wersji
platformy wraz z nowymi funkcjami, które można wykorzystać we własnych
wtyczkach.

PHPXref

PHPXref to wszechstronny generator dokumentacji. Całkiem proste
narzędzie programisty, które może przeskanować katalog projektu i na
podstawie znalezionych tam plików wygenerować łatwe w odczycie pliki
HTML. Narzędzie automatycznie przetwarza komentarze zapisane w stylu
PHPDoc i na ich podstawie tworzy dokumentację funkcji omówionych w tych
komentarzach.

Pod adresem http://phpxref.ftwr.co.uk/wordpress/ dostępna jest również
internetowa wersja PHPXref przeznaczona szczególnie dla platformy
WordPress.

Przejście na tę stronę powoduje wyświetlenie interfejsu przypominającego
układ programu Windows Explorer (zobacz rysunek 18.2).

Jak możesz zobaczyć na rysunku, po lewej stronie jest wyświetlona
zawartość standardowego katalogu WordPress wraz z podstawowymi
podkatalogami i plikami. Kliknij katalog wp-includes, a następnie plik
plugin.php. Kliknięcie pliku spowoduje wyświetlenie jego podsumowania, w
tym przypadku plugin.php. W podsumowaniu znajduje się wiele użytecznych
informacji, m.in. lista wszystkich funkcji zdefiniowanych w klikniętym
pliku (zobacz rysunek 18.3).

Możliwość wyświetlenia listy wszystkich funkcji zdefiniowanych w pliku
tworzącym jądro platformy WordPress to doskonały sposób odkrywania
nowych funkcji, a nawet wyszukiwania już istniejących w celu ich
dokładniejszego poznania. Kliknięcie dowolnej z wymienionych na liście
funkcji spowoduje przejście do sekcji strony przedstawiającej informacje
szczegółowe na temat danej funkcji. Informacje są wyodrębnione i
wygenerowane na podstawie dokumentacji osadzonej w pliku zawierającym
definicję tej funkcji. Jeżeli dla danej funkcji platforma WordPress nie
zawiera dokumentacji, wspomniana sekcja będzie pusta. Równie łatwo
możesz także wyświetlić kod źródłowy dowolnego pliku: kliknij po prostu
łącze Source View znajdujące się na początku strony.

[]

Rysunek 18.2. Interfejs internetowej wersji narzędzia PHPXref

[]

Rysunek 18.3. Podsumowanie wyświetlane po kliknięciu pliku plugin.php

Jak widać, WordPress PHPXref to bardzo użyteczna witryna dla programisty
wtyczek WordPress. Stanowi kolejne narzędzie, które powinno znajdować
się w arsenale twórcy wtyczek.

Baza danych zaczepów platformy WordPress

Baza danych zaczepów platformy WordPress — utworzona i obsługiwana przez
Adama Browna — to podstawowy zasób pozwalający na odkrywanie zaczepów
WordPress. Adam zbudował system, który analizuje wszystkie pliki
tworzące jądro platformy i wyodrębnia każdy zaczep akcji oraz filtru
istniejący w WordPress. Wartości są indeksowane, począwszy od wersji
1.2.1 platformy WordPress, i uaktualniane po wydaniu każdej głównej
wersji.

Jedną z największych zalet tej bazy danych jest możliwość wyświetlenia
wszystkich nowych zaczepów dodanych w poszczególnych wersjach platformy
WordPress. Dla twórcy wtyczek zaczepy to funkcje oferujące najbardziej
użyteczne możliwości, które można wykorzystać podczas opracowywania
wtyczek WordPress. Kliknięcie nazwy zaczepu powoduje wyświetlenie strony
z informacjami szczegółowymi, m.in. o miejscu zdefiniowania danego
zaczepu w kodzie tworzącym jądro WordPress.

Aby przejrzeć bazę danych zaczepów WordPress, przejdź na stronę
http://adambrown.info/p/wp_hooks.

Zasoby oferowane przez społeczność

Społeczność WordPress również oferuje wiele różnych zasobów, które mogą
pomóc podczas programowania na platformie. Wspomniane zasoby pomogą w
poszerzeniu wiedzy na temat tworzenia wtyczek, rozwiązywaniu związanych
z tym problemów, a także w poznawaniu i wykorzystywaniu nowych funkcji
wprowadzonych na platformie WordPress.

Fora pomocy technicznej

W witrynie WordPress.org znajduje się ogromne forum, na którym poruszane
są różne tematy, od używania platformy aż po tworzenie wtyczek dla
WordPress. Fora znajdują się pod adresem http://wordpress.org/support/.

Dla twórcy wtyczek kilka forów może być szczególnie użytecznych i pomóc
w poszerzeniu wiedzy z tego zakresu. Fora pozwalają także na świadczenie
pomocy technicznej użytkownikom Twoich wtyczek. Poniżej wymieniono fora
powiązane z wtyczkami:

-   http://wordpress.org/​support/forum/hacks — dyskusje poświęcone
    tematom tworzenia wtyczek, kodu i różnym związanym z tym sztuczkom;
-   http://wordpress.org/​support/forum/wp-advanced — dyskusje poświęcone
    bardziej zaawansowanym i skomplikowanym tematom;
-   http://wordpress.org/​support/forum/multisite — dyskusje poświęcone
    wszystkiemu, co dotyczy sieci Multisite na platformie WordPress;
-   http://wordpress.org/​support/forum/plugins-and-hacks — forum służące
    do świadczenia pomocy technicznej użytkownikom wtyczek. Jeśli
    umieścisz wtyczkę w oficjalnym repozytorium, na tym forum
    użytkownicy mogą zadawać pytania dotyczące Twojej wtyczki.

Listy dyskusyjne

Istnieje wiele list dyskusyjnych przeznaczonych do prowadzenia rozmów na
wiele różnych tematów dotyczących projektu WordPress. Listy dyskusyjne
pozwalają na szybkie i łatwe uzyskanie informacji i porad od innych
programistów udzielających się w społeczności. Lista dyskusyjna działa
na zasadzie komunikacji dwukierunkowej. Swój problem lub pytanie
zadajesz na liście, a jej członkowie udzielają odpowiedzi. Wszystkie
wiadomości e-mail wysłane na listę są archiwizowane, co pozwala na ich
późniejsze przeglądanie.

Lista skierowana do twórców wtyczek nosi nazwę Hackers mailing list.
Jest to doskonałe miejsce do prowadzenia zaawansowanych dyskusji
poświęconych rozbudowie platformy WordPress.

-   Adres e-mail listy: wp-hackers@lists.automattic.com.
-   Strona, na której można się przyłączyć do listy:
    http://lists.automattic.com/​mailman/listinfo/wp-hackers.
-   Archiwum listy: http://lists.automattic.com/pipermail/wp-hackers/.

Inna potencjalnie użyteczna lista dyskusyjna to Trac. Jest to
oprogramowanie typu open source pozwalające na śledzenie błędów w
oprogramowaniu oraz używane do śledzenia prac rozwojowych nad jądrem
platformy WordPress. Lista pozwala na poznanie nowych funkcji, które
zostały zaimplementowane w najnowszych wersjach platformy. Trzeba w tym
miejscu dodać, że to jest bardzo aktywna lista.

-   Adres e-mail listy: wp-trac@lists.automattic.com.
-   Strona, na której można się przyłączyć do listy:
    http://lists.automattic.com/​mailman/listinfo/wp-trac.
-   Archiwum listy: http://lists.automattic.com/pipermail/wp-trac/.

Czat WordPress

Szukając pomocy lub informacji dotyczących programowania na platformie
WordPress, warto przeprowadzić rozmowę na żywo. WordPress udostępnia
kilka kanałów IRC pozwalających na prowadzanie takich rozmów. Aby
przyłączyć się do kanału WordPress, trzeba posiadać klienta IRC
(http://codex.wordpress.org/​IRC#IRC_Client_Applications). Wszystkie
kanały WordPress znajdują się w serwerze Freenode:
http://irc.freenode.net/.

-   #wordpress — podstawowy kanał rozmów dotyczących platformy
    WordPress. Poruszane kwestie mogą być bardzo różne, od podstaw aż po
    zaawansowane tematy dotyczące tworzenia wtyczek. Wielu programistów
    jądra platformy WordPress i ich współpracowników udziela się na tym
    kanale i chętnie pomaga potrzebującym.
-   #wordpress-dev — ten kanał został poświęcony tematowi tworzenia
    programowania na platformie WordPress. Kanał nie jest przeznaczony
    na ogólne dyskusje, ale służy do prowadzenia rozmów dotyczących
    programowania lub błędów znalezionych w jądrze platformy.

Wymienione kanały stanowią doskonałe zasoby pozwalające na uzyskanie
niemal natychmiastowej pomocy podczas tworzenia wtyczek dla platformy
WordPress. Wielu ekspertów udziela się na tych kanałach i czerpie
prawdziwą przyjemność z pomagania innym.

Więcej informacji na temat czatu WordPress oraz pobierania klienta IRC i
łączenia się z serwerem Freenode można znaleźć na stronie
http://codex.wordpress.org/IRC.

Informacje dotyczące prac rozwojowych nad WordPress

Podczas tworzenia wtyczek i ich publicznego udostępniania warto na
bieżąco monitorować pojawianie się nowych funkcji w kolejnych wydaniach
platformy WordPress. Dzięki temu zapewniasz nie tylko zgodność wtyczki z
najnowszymi wydaniami platformy, ale również masz możliwość
wykorzystania nowo wprowadzanych funkcji. Jednym z najlepszych sposobów
śledzenia informacji o postępie prac rozwojowych nad platformą WordPress
jest przeglądanie witryny WordPress Development Updates dostępnej pod
adresem http://wpdevel.wordpress.com/.

Witryna używa popularnego motywu P2, który przypomina wygląd serwisu
Twitter. Na niej możesz dowiedzieć się o cotygodniowych spotkaniach
odbywających się na kanale IRC #wordpress-dev. Spotkania pozwalają na
omówienie bieżącego stanu prac nad nadchodzącymi wydaniami platformy,
dyskusje o funkcjach itd.

Zgłaszanie pomysłów dla WordPress

W witrynie WordPress.org znajduje się sekcja pozwalająca na zgłaszanie i
ocenianie pomysłów dotyczących przyszłych wydań platformy WordPress. Tak
naprawdę to doskonały zasób pozwalający na zebranie pomysłów na nowe
wtyczki. Większość zgłaszanych tutaj pomysłów może być zrealizowanych w
postaci wtyczek. Im większą popularność zyskuje pomysł, tym większą
popularność zyska wtyczka realizująca dany pomysł.

Strona z pomysłami dla platformy WordPress znajduje się pod adresem
http://wordpress.org/extend/ideas/.

Obsługiwane przez społeczność witryny z nowościami

W internecie można znaleźć doskonałe witryny internetowe koncentrujące
się na nowościach i artykułach poświęconych programowaniu na platformie
WordPress. W wielu tych witrynach znajdziesz interesujące samouczki i
podpowiedzi, które można wykorzystać podczas prac nad własnymi
wtyczkami. Poniżej wymieniono najużyteczniejsze z dostępnych tego
rodzaju witryn.

WordPress Planet

Ta witryna jest agregatorem działającym w ramach WordPress.org. Zbiera
wpisy bloga opublikowane przez współpracowników pracujących nad jądrem
WordPress oraz aktywnych członków społeczności. Kanał wiadomości tej
witryny znajduje się domyślnie w kokpicie każdej witryny bazującej na
WordPress.

Adres WordPress Planet to http://planet.wordpress.org/.

Planet WordPress

Tej witryny nie należy mylić z WordPress Planet. Planet WordPress to
także witryna, będąca agregatorem nowości, ale obsługiwana przez Ozha
Richarda. Witryna zbiera wpisy blogów opublikowane przez twórców wtyczek
oraz programistów budujących jądro platformy, a następnie dostarcza je w
postaci pojedynczego kanału. Dzięki temu nowości i tematy dotyczące
WordPress można bardzo łatwo śledzić za pomocą pojedynczego źródła.

Adres Planet WordPress to http://planetwordpress.planetozh.com/.

WPEngineer.com

WPEngineer to doskonały zasób dla twórców wtyczek. Witryna zawiera wiele
dokładnych samouczków, wskazówek, podpowiedzi, wiadomości itd. Wiele z
dostępnych artykułów prezentuje obszerne fragmenty kodu demonstrujące
uzyskanie określonego efektu na platformie WordPress. Twórcy wtyczek na
pewno docenią techniczną naturę tej witryny.

Adres WPEngineer to http://wpengineer.com/.

WeblogToolsCollection.com

Weblog Tools Collection (WLTC) to witryna koncentrująca się na
nowościach w blogach, choć kieruje się bardziej w stronę artykułów
poświęconych platformie WordPress. Witryna udostępnia co tydzień nowe
wydanie wpisu bloga "Plugin and Theme", który stanowi doskonałe źródło
informacji o nowych wtyczkach. WLTC przeprowadza również co roku konkurs
WordPress Plugin Competition wraz z nagrodami przyznawanymi przez
ekspertów (do których zalicza się także Ozh!).

Adres WLTC to http://weblogtoolscollection.com/.

Twitter

Twitter to serwis pozwalający na śledzenie poczynań m.in. twórców
platformy WordPress, współpracowników oraz ogólnie członków całej
społeczności. Konto o nazwie @wpdevel zawiera informacje o każdej
operacji umieszczenia kodu jądra platformy WordPress w repozytorium SVN.
To szybki i łatwy sposób dowiadywania się o postępie prac rozwojowych
nad platformą WordPress.

Wydarzenia lokalne

Inny doskonały zasób to wydarzenia lokalne dotyczące WordPress. Podczas
nauki tworzenia wtyczek dla WordPress warto w pobliżu znaleźć innych
entuzjastów, z którymi można się uczyć i pracować.

Spotkania WordCamp są organizowane lokalnie i dotyczą wszystkiego, co
jest związane z platformą WordPress. Wiele tego rodzaju spotkań oferuje
prezentacje poświęcone określonym zagadnieniom w programowaniu
WordPress, prowadzone przez uznanych programistów społeczności. Takie
prezentacje to dobry sposób poznawania nowych i zaawansowanych technik,
które później można wykorzystać we własnych wtyczkach. Aby znaleźć
najbliższą grupę organizującą spotkanie WordCamp, odwiedź witryny
http://central.wordcamp.org/ i http://wordcamp-polska.pl/.

WordPress Meetup to również doskonały sposób spotkania programistów
WordPress działających w Twojej okolicy. Spotkania WordPress Meetup z
reguły odbywają się raz w miesiącu i gromadzą lokalnych entuzjastów
platformy WordPress. Spotkania gromadzą mniejszą liczbę uczestników niż
WordCamp i bardziej koncentrują się na rozmowach między uczestnikami.
Aby znaleźć lokalną grupę WordPress Meetup zajrzyj na witrynę
http://wordpress.meetup.com/.

Narzędzia

Podczas prac nad wtyczkami dla WordPress będziesz korzystał z narzędzi,
które ułatwią Ci pracę.

Przeglądarka internetowa

Platforma WordPress to oprogramowanie sieciowe. Dlatego też, usuwając
błędy z wtyczki, sporo czasu spędzisz w przeglądarce internetowej.
Niektóre przeglądarki internetowe są wyraźnie lepsze, kiedy chodzi o
zaoferowanie funkcji dla programisty. Dwie najpopularniejsze to Firefox
i Google Chrome. Obie oferują narzędzia programistyczne i mogą być
rozbudowane za pomocą narzędzi dodatkowych, które jeszcze bardziej
ułatwią usuwanie błędów i rozwiązywanie problemów podczas tworzenia
wtyczek.

Dla przeglądarki Firefox powstało prawdopodobnie najpopularniejsze
narzędzie programisty — Firebug. Rozszerzenie udostępnia w przeglądarce
Firefox zaawansowane narzędzia programistyczne pozwalające na łatwą
edycję, monitorowanie i usuwanie błędów z kodu HTML, CSS, a nawet
JavaScript. Rozszerzenie Firebug samo pozwala na obsługę rozszerzeń,
dzięki którym można jeszcze bardziej zwiększyć możliwości tego
narzędzia. Jednym z popularniejszych rozszerzeń narzędzia Firebug jest
YSlow, które analizuje witrynę internetową w celu znalezienia przyczyn
jej wolnego wczytywania. Rozszerzenie Firebug dla przeglądarki Firefox
można pobrać z witryny http://getfirebug.com/.

Google Chrome zawiera wbudowany zestaw narzędzi programistycznych. To
również doskonała przeglądarka internetowa dla programisty. Wspomniane
narzędzia pozwalają na edycję i usuwanie błędów z kodu HTML, CSS i
JavaScript w czasie rzeczywistym. Przeglądarka Chrome umożliwia także
instalację rozszerzeń wzbogacających ją o funkcje dodatkowe. Chrome
możesz pobrać z witryny http://www.google.com/chrome.

Edytor tekstu

Tworzenie wtyczek dla przeglądarki WordPress jest równie proste, jak
tworzenie plików PHP. Wspomniane pliki PHP to zwykłe pliki tekstowe z
rozszerzeniem .php. Z tego powodu pliki PHP można pisać za pomocą
dowolnego edytora tekstowego. Wprawdzie zwykły edytor tekstowy będzie
sprawdzał się doskonale, ale z reguły nie oferuje funkcji
zaawansowanych, takich jak kolorowanie składni, wyszukiwanie funkcji,
sprawdzanie pisowni itd.

NetBeans IDE

NetBeans IDE to popularne zintegrowane środowisko programistyczne typu
open source, które zostało utworzone w Javie. Z tego powodu może być
uruchamiane na każdej platformie obsługującej wirtualną maszynę Javy,
czyli m.in. Windows, Mac OS, Linux i Solaris. NetBeans obsługuje PHP,
zapewnia kolorowanie składni i usuwanie błędów PHP za pomocą Xdebug,
umożliwia zdalną i lokalną pracę nad projektami oraz wiele innych.
Więcej informacji na temat NetBeans IDE oraz odnośnik pozwalający na
pobranie oprogramowania można znaleźć na witrynie http://netbeans.org/.

Notepad++

Notepad++ to popularny edytor typu open source przeznaczony dla
platformy Windows. Edytor jest niewielki i podobny do standardowego
Notatnika dostępnego w Windows. W przeciwieństwie do Notatnika oferuje
jednak wiele użytecznych funkcji, m.in. kolorowanie składni, obsługę
makr i wtyczek, automatyczne uzupełnianie kodu, obsługę wyrażeń
regularnych podczas operacji wyszukiwania i zastępowania i wiele innych.
Więcej informacji na temat edytora Notepad++ oraz odnośnik pozwalający
na pobranie aplikacji można znaleźć na witrynie
http://notepad-plus-plus.org/.

TextMate

TextMate to edytor tekstu przeznaczony dla platformy Mac OS X. Stał się
popularny wśród programistów ze względu na zestaw funkcji przygotowanych
pod ich kątem. Niektóre z użytecznych funkcji to m.in. zagnieżdżone
zakresy, obsługa tzw. bundles (jest to rodzaj bibliotek zawierających
fragmenty kodu, makra, polecenia i szablony), zarządzanie projektem i
wiele innych. Więcej informacji na temat TextMate oraz odnośnik
pozwalający na pobranie edytora można znaleźć na witrynie
http://macromates.com/.

Coda

Coda to kolejny edytor dostępny na platformie Mac OS X, oferujący
funkcje przydatne podczas programowania sieciowego. To nie tylko edytor,
aplikacja oferuje wbudowanego klienta FTP oraz zapewnia obsługę
repozytorium SVN. Celem firmy Panic było utworzenie jednego programu, z
którego będziesz korzystał podczas tworzenia aplikacji sieciowych.
Więcej informacji na temat aplikacji Coda oraz odnośnik pozwalający na
pobranie oprogramowania można znaleźć na witrynie
http://www.panic.com/coda/.

Obsługa plików za pomocą FTP, SFTP i SSH

Podczas tworzenia wtyczki trzeba zdecydować, czy platforma WordPress
będzie zainstalowana na komputerze lokalnym, czy będzie używany
zewnętrzny serwer WWW. W przypadku używania zewnętrznego serwera WWW
trzeba zastosować odpowiednią metodę pozwalającą na umieszczenie plików
w serwerze. Najpopularniejszą będzie zastosowanie klienta FTP.

Protokół FTP (ang. File Transfer Protocol) to standardowy protokół
używany do kopiowania plików z komputera lokalnego do innego, w tym
przypadku serwera WWW. Bezpłatnym klientem FTP typu open source
działającym na platformach Windows, Mac i Linux jest FileZilla. Więcej
informacji na temat klienta FileZilla oraz odnośnik pozwalający na jego
pobranie można znaleźć w witrynie http://filezilla-project.org/.

Protokół SFTP (ang. Secure File transfer Protocol) to również popularny
protokół używany w celu umieszczania plików na serwerze WWW. Podstawowa
różnica między FTP a SFTP polega na tym, że SFTP stosuje szyfrowanie.
Oznacza to zaszyfrowanie transmisji, a tym samym informacji o koncie,
nazwy użytkownika, hasła oraz plików przekazywanych do serwera.
Większość popularnych klientów FTP obsługuje także protokół SFTP.

SSH (ang. Secure Shell) to trzecia możliwość przekazania plików do
serwera WWW. SSH to więcej niż tylko sposób przekazywania plików.
Przykładowo za pomocą SSH można pracować z bazą danych MySQL działającą
na zdalnym serwerze. Popularnym klientem SSH działającym na platformach
Windows i Linux jest PuTTY (http://www.putty.org/). Użytkownicy systemu
Mac OS X do pracy z SSH mogą wykorzystać powłokę dostępną za pomocą
narzędzia systemowego o nazwie Terminal.

phpMyAdmin

Czasami trzeba bezpośrednio pracować z bazą danych platformy WordPress.
Najczęstszym rozwiązaniem jest wówczas użycie narzędzia o nazwie
phpMyAdmin. To zupełnie bezpłatne, utworzone w języku PHP narzędzie,
które dostarcza prosty interfejs pozwalający na przeglądanie bazy danych
MySQL i zarządzanie nią. W większości serwerów WWW narzędzie to jest
dostępne standardowo.

Za pomocą phpMyAdmin można bardzo łatwo przeglądać dane umieszczane w
tabelach WordPress przez Twoją wtyczkę. Dzięki temu wyraźnie skraca się
czas, który trzeba poświęcić na usuwanie błędów z wtyczki. Narzędzie
phpMyAdmin działa również w komputerze lokalnym. Odpowiedni pakiet do
pobrania znajduje się na stronie
http://www.phpmyadmin.net/home_page/downloads.php.

------------------------------------------------------------------------

Uwaga

Bazą danych MySQL można zarządzać przy użyciu SSH. Warto jednak
pamiętać, że SSH oznacza korzystanie z interfejsu wiersza poleceń, który
jest znacznie trudniejszy w obsłudze niż interfejs graficzny oferowany
przez phpMyAdmin.

------------------------------------------------------------------------

Podsumowanie

Jako twórca wtyczek potrzebujesz solidnego zestawu narzędzi. Zestaw
narzędzi każdego programisty jest inny i dostosowany do jego potrzeb,
przyzwyczajeń i konfiguracji serwera. Przygotowanie sobie wygodnego
zestawu narzędzi znacznie ułatwia tworzenie profesjonalnych wtyczek dla
platformy WordPress. Jeżeli jeszcze nie masz ulubionego zestawu
narzędzi, zapytaj innych programistów, z jakich narzędzi korzystają.
Rozmowa z innymi programistami na temat używanych i polecanych przez
nich narzędzi zawsze dostarcza wiele radości.

Podczas tworzenia wtyczek równie ważne jak narzędzia są informacje o
nowościach i pracach społeczności. Wymienione w rozdziale witryny
internetowe pomogą Ci poszerzyć wiedzę z zakresu programowania wtyczek.
Ponadto dostarczą informacji dotyczących nowych funkcji i prawidłowego
sposobu ich używania. Nie można zapomnieć o jeszcze jednym aspekcie
korzystania z wymienionych witryn: staniesz się członkiem jednej z
najwspanialszych społeczności w internecie — społeczności WordPress. A
teraz nadszedł czas na tworzenie kodu!

[Okładka]

Spis treści

Podziękowania

O autorach

Wstęp

Wprowadzenie

Dla kogo jest przeznaczona ta książka?

Co jest potrzebne, by dobrze wykorzystać tę książkę?

Jaki materiał przedstawiono w książce?

W jaki sposób zorganizowana jest ta książka?

Konwencje

Kod źródłowy

Errata

Rozdział 1 Wprowadzenie do wtyczek

Co to jest wtyczka?

W jaki sposób wtyczki współdziałają z platformą WordPress?

Kiedy wtyczki są wczytywane?

Dostępne wtyczki

Oficjalny katalog wtyczek

Przykłady popularnych wtyczek

Popularne tagi wtyczek

Zalety wtyczek

Brak konieczności modyfikacji jądra platformy

Nie trzeba wyważać otwartych drzwi

Oddzielenie wtyczek i motywów

Łatwe uaktualnienia

Łatwiejsze dzielenie się wtyczkami i ich ponowne używanie

Wtyczki są oddzielone od siebie

Społeczność tworząca wtyczki

Instalacja wtyczek i zarządzanie nimi

Instalacja wtyczki

Zarządzanie wtyczkami

Edycja wtyczek

Katalog wtyczek

Typy wtyczek

Testowanie funkcji wtyczek

Podsumowanie

Rozdział 2 Podstawy wtyczek

Utworzenie pliku wtyczki

Nadanie nazwy wtyczce

Używanie katalogu

Stosowanie rozsądnych praktyk

Stosowanie prefiksu w każdej sytuacji

Organizacja pliku

Struktura katalogów

Wymagania dotyczące nagłówka

Utworzenie nagłówka

Licencja wtyczki

Określanie ścieżek dostępu

Ścieżki dostępu wtyczki

Lokalne ścieżki dostępu

Adresy URL

Aktywacja i dezaktywacja funkcji

Funkcja aktywacji wtyczki

Utworzenie ustawień domyślnych podczas aktywacji

Funkcja dezaktywacji wtyczki

Dezaktywacja to nie dezinstalacja wtyczki

Metody dezinstalacji

Dlaczego dezinstalacja wtyczki jest konieczna?

Plik uninstall.php

Zaczep uninstall

Standardy tworzenia kodu

Twórz dokumentację kodu

Nazwy zmiennych, funkcji i plików

Apostrof i cudzysłów

Wcięcia

Styl stosowania nawiasów

Używanie spacji

Skrócone znaczniki PHP

Polecenia SQL

Lista rzeczy do sprawdzenia podczas prac nad wtyczkami

Podsumowanie

Rozdział 3 Zaczepy

Akcje

Czym jest akcja?

Funkcje zaczepu akcji

do_action_ref_array()

remove_action()

remove_all_actions()

has_action()

did_action()

register_activation_hook i register_deactivation_hook

Najczęściej używane zaczepy akcji

plugins_loaded

init

admin_menu

template_redirect()

wp_head

Filtry

Czym jest filtr?

Funkcje zaczepu filtru

apply_filters_ref_array()

remove_filter()

remove_all_filters()

has_filter()

current_filter()

Funkcje szybko zwracające wartość

Najczęściej używane zaczepy filtru

the_content

the_title

comment_text

template_include

Używanie zaczepów z poziomu klasy

Tworzenie własnych zaczepów

Zalety utworzenia własnego zaczepu

Przykład utworzenia własnego zaczepu akcji

Przykład własnego zaczepu filtru

W jaki sposób wyszukiwać zaczepy?

Wyszukiwanie zaczepów w kodzie tworzącym jądro WordPress

Zaczepy zmienne

Listy zaczepów

Podsumowanie

Rozdział 4 Integracja z platformą WordPress

Dodawanie menu i podmenu

Utworzenie menu najwyższego poziomu

Dodawanie podmenu

Dodawanie elementu menu do już istniejącego menu

Tworzenie widgetów

Utworzenie widgetu

Widget zaawansowany

Tworzenie widgetów kokpitu

Utworzenie widgetu kokpitu wraz z opcjami

Pola użytkowników

Dodawanie własnego pola użytkownika

Zapis danych pola użytkownika

Zaawansowane pole użytkownika

Plik boj-meta-box.php:

Plik boj-meta-image.js:

Zachowanie spójności

Korzystanie z interfejsu użytkownika platformy WordPress

Nagłówki

Ikony

Wiadomości

Przyciski

Odnośniki

Pola formularza

Tabele

Stronicowanie

Podsumowanie

Rozdział 5 Internacjonalizacja

Internacjonalizacja i tłumaczenie na inne języki

Dlaczego warto przeprowadzać internacjonalizację?

Zrozumienie zagadnienia internacjonalizacji w profesjonalnej pracy

Przygotowanie wtyczki do tłumaczenia na inne języki

Wyświetlanie i zwracanie ciągów tekstowych

Funkcja __()

Funkcja _e()

Funkcja esc_attr__()

Funkcja esc_attr_e()

Funkcja esc_html__()

Funkcja esc_html_e()

Funkcja _x()

Funkcja _ex()

Funkcja esc_attr_x()

Funkcja esc_html_x()

Funkcja _n()

Funkcja _nx()

Funkcja _n_noop()

Funkcja _nx_noop()

Używanie miejsc zarezerwowanych

Internacjonalizacja kodu JavaScript

Tworzenie plików tłumaczenia

Pliki MO i PO

Narzędzia służące do tłumaczenia

W jaki sposób utworzyć plik POT?

Gdzie przechowywać pliki tłumaczeń?

Podsumowanie

Rozdział 6 Bezpieczeństwo wtyczki

Zabezpieczenie wtyczki

Czym jest zapewnienie bezpieczeństwa wtyczce?

Czym nie jest zapewnienie bezpieczeństwa wtyczce?

Uprawnienia użytkownika

W jaki sposób używać funkcji current_user_can()?

Nie sprawdzaj zbyt wcześnie

Unikalne identyfikatory

Uprawnienia kontra zamiary

Czym jest unikalny identyfikator?

Jak tworzyć i weryfikować unikalne identyfikatory?

Utworzenie unikalnego identyfikatora dla adresu URL

Utworzenie unikalnego identyfikatora dla formularza

Weryfikacja unikalnego identyfikatora

Przygotowanie całości: pełny kod wtyczki Nieużywane tagi

Unikalne identyfikatory w skryptach Ajax

Weryfikacja i oczyszczenie danych

Potrzeba weryfikacji i oczyszczania danych

Dobra praktyka: identyfikacja potencjalnie niebezpiecznych danych

Weryfikacja czy oczyszczanie danych wejściowych?

Przykłady weryfikacji i oczyszczania danych

Liczby całkowite

Zwykłe ciągi tekstowe

Mieszane ciągi tekstowe

Wewnętrzne ciągi tekstowe identyfikatorów

Wzorce ciągu tekstowego

Przykład 1.: numer telefonu

Przykład 2.: numer seryjny produktu

Przykład 3.: daty

Ciąg tekstowy adresu e-mail

HTML (lub XML)

Fragment kodu HTML

Węzeł HTML

Adresy URL

Adresy URL w bazie danych

Adresy URL w przekierowaniach

JavaScript

Zmienne serwera lub środowiska

Pliki cookies

Tablice danych

Dane pochodzące ze zdefiniowanego zbioru

Zapytania do bazy danych

Formatowanie poleceń SQL

Obiekt $wpdb

Dlaczego metody obiektu wpdb są lepsze?

Metody typu "wszystko w jednym"

$wpdb->update()

$wpdb->insert()

Najczęściej stosowane metody

Pobranie zmiennej

Pobranie rekordu

Pobranie kolumny

Pobranie ogólnych wyników

Dowolne zapytania

Ochrona zapytań przed atakami typu SQL Injection

Różne metody i właściwości obiektu wpdb

Włączenie wyświetlania błędów

Śledzenie liczby zapytań

Inne zmienne klasy

Dobre nawyki bezpieczeństwa

Podsumowanie

Rozdział 7 Ustawienia wtyczki

API Options

Zapisywanie opcji

Zapisywanie tablicy opcji

Pobieranie opcji

Wczytywanie tablicy opcji

Usuwanie opcji

Parametr autoload

Rozdzielanie opcji wtyczki

Włączanie i wyłączanie parametru autoload

API Settings

Zalety API Settings

Funkcje API Settings

Utworzenie strony administracyjnej dla wtyczki

Rejestracja nowych ustawień

Zdefiniowanie sekcji i ustawień

Weryfikacja danych wejściowych użytkownika

Wygenerowanie formularza

Wszystko gotowe!

Zebranie całości: pełna strona zarządzania wtyczką

Usprawnienie reakcji funkcji i weryfikacja błędów

Dodawanie pól na istniejącej stronie

Jak to działa?

Dodawanie sekcji na istniejącej stronie

Dodawanie jedynie pól

Sekcja WordPress i pola ustawień

Rozważania dotyczące interfejsu użytkownika

API Transients

Zapisywanie opcji, która ma utracić ważność

Pobieranie opcji, która ma utracić ważność

Usunięcie opcji, która utraciła ważność

Praktyczny przykład użycia krótkotrwałych danych

Szczegółowe informacje techniczne

Idea krótkotrwałych danych

Zapisywanie ustawień poszczególnych użytkowników

Tworzenie wtyczki

Metadane użytkownika

Zapisywanie metadanych użytkownika

Uaktualnianie metadanych użytkownika

Pobieranie metadanych użytkownika

Usunięcie metadanych użytkownika

Pobieranie identyfikatora użytkownika

Dodawanie pól na stronie profilu

Wtyczka BOJ Admin Lang

Ustawienia dla poszczególnych użytkowników — najlepsze praktyki

Przechowywanie danych we własnych tabelach

Typy danych

Standardowe tabele WordPress

Tworzenie własnej tabeli

Sprawdzenie istnienia tabeli

Uaktualnienie struktury własnej tabeli

Podpowiedzi dotyczące używania funkcji dbDelta()

Obserwowanie składni i stylu poleceń SQL

Sprawdzenie wartości zwrotnej w przygotowanym środowisku

Uruchomienie testowego polecenia SQL

Uzyskanie dostępu do własnej tabeli

Podsumowanie

Rozdział 8 Użytkownicy

Praca z użytkownikami

Funkcje użytkownika

is_user_logged_in()

get_users()

get_users_of_blog()

count_users()

Tworzenie, uaktualnianie i usuwanie użytkowników

wp_insert_user()

wp_create_user()

wp_update_user()

wp_delete_user()

Dane użytkownika

get_userdata()

wp_get_current_user()

get_currentuserinfo()

count_user_posts()

count_many_users_posts()

Metadane użytkownika

add_user_meta()

get_user_meta()

update_user_meta()

delete_user_meta()

user_contactmethods

Utworzenie wtyczki z metadanymi użytkownika

Role i możliwości

Czym są role i możliwości?

Role domyślne

Własne role

Ograniczanie dostępu

Sprawdzanie uprawnień użytkownika

current_user_can()

current_user_can_for_blog()

author_can()

user_can()

map_meta_cap()

Czy użytkownik jest administratorem?

is_super_admin()

Nadanie własnych uprawnień

Dostosowanie ról do własnych potrzeb

Tworzenie roli

add_role()

Usunięcie roli

remove_role()

Dodanie możliwości do roli

get_role()

Usuwanie możliwości z roli

Wtyczka obsługująca własne role i możliwości

Podsumowanie

Rozdział 9 API HTTP

Szybki kurs wykonywania żądań HTTP

Czym jest żądanie HTTP?

Koncepcje żądania HTTP

Szczegółowa analiza transakcji HTTP

Klient wysyła żądanie

Serwer udziela odpowiedzi

Wykorzystywanie żądań HTTP

Jak wykonywać żądania HTTP w PHP?

Użycie rozszerzenia HTTP

Użycie strumienia fopen()

Użycie standardowej funkcji fopen()

Użycie funkcji fsockopen()

Użycie rozszerzenia CURL

Zbyt wiele sposobów?

Funkcje obsługi HTTP oferowane przez WordPress

Funkcje rodziny wp_remote_*

Parametry wejściowe funkcji wp_remote_*

Wartości zwrotne funkcji wp_remote_*

Żądania HTTP zakończone niepowodzeniem

Żądania HTTP zakończone powodzeniem

Funkcje pomocnicze wp_remote_*

Konfiguracja zaawansowana i wskazówki

Obsługa proxy

Filtrowanie żądań i odpowiedzi

Przykład: modyfikacja parametru domyślnego

Przykład: rejestracja żądań HTTP i udzielanej odpowiedzi na żądanie

Przykład: zaawansowane filtrowanie

Pewne ograniczenia dotyczące sprawdzania odpowiedzi HTTP

Ćwiczenie praktyczne: odczyt formatu JSON zzewnętrznego API

Pobieranie i odczytywanie danych JSON

Funkcjonująca wtyczka

Ćwiczenie praktyczne: wysyłanie danych dozdalnegoAPI

Formatowanie parametrów dla żądań POST

Gotowa wtyczka

Ćwiczenie praktyczne: odczyt dowolnej treści

Utworzenie własnego repozytorium wtyczki

Jak działa proces uaktualnienia wtyczki naplatformieWordPress?

Wykonywanie żądań do alternatywnego API zpoziomuwtyczki

Utworzenie alternatywnego API

Kilka ostrzeżeń dotyczących własnych API

Przypadek specjalny: pobieraniezdalnychwiadomości RSS

Podsumowanie

Rozdział 10 API Shortcode

Tworzenie skrótu

Czym jest skrót?

Rejestracja własnego skrótu

[ksiazka]

[ksiazki tytul="xkcd"]

[amazon asin="12345"]tytuł książki[/amazon]

Podsumowanie: funkcja add_shortcode() i funkcja odpowiedzialna za
zastąpienie znacznika

Wskazówki dotyczące skrótów

Pomyśl o prostocie

Pamiętaj o dynamiczności

Wewnętrzny sposób działania

$shortcode_tags

remove_shortcode()

remove_all_shortcodes()

strip_shorcodes()

shortcode_atts()

do_shortcode()

Skróty rekurencyjne

Kod BBCode we wtyczce obsługującej komentarze

Ograniczenia skrótów podczas obsługi struktur zagnieżdżonych

Integracja z usługą Google Mapy

Uzyskanie dostępu do API Google Geocoding

Przechowywanie wyników

Uzyskanie dostępu do API Google Maps

Koncepcje API

Implementacja wtyczki

Więcej pomysłów dotyczących skrótów

Wyświetlanie treści jedynie dla zalogowanych użytkowników

Wyświetlenie treści ograniczonej czasowo

Zaciemnienie adresu e-mail

Podsumowanie

Rozdział 11 Rozbudowa wpisów bloga: metadane, własne typy wpisów bloga i
taksonomie

Tworzenie własnych typów wpisów bloga

Możliwe typy wpisów bloga

Rejestracja typu wpisu bloga

register_post_type()

public

show_ui

publicly_queryable

exclude_from_search

supports

labels

capability_type

capabilities

hierarchical

has_archive

query_var

rewrite

taxonomies

menu_position

menu_icon

show_in_nav_menus

can_export

register_meta_box_cb

permalink_epmask

Rejestracja własnego typu wpisu bloga

Ustawianie etykiet we własnym typie wpisu bloga

Wykorzystanie własnych możliwości

Dołączanie istniejących taksonomii

Używanie własnych typów wpisów bloga

Utworzenie pętli własnego typu wpisu bloga

Pobieranie treści własnego typu wpisu bloga

the_title()

the_content()

the_excerpt()

the_permalink()

Sprawdzenie istnienia typu wpisu bloga

post_type_exists()

Metadane wpisu bloga

Dodawanie metadanych wpisu bloga

add_post_meta()

Pobieranie metadanych

Uaktualnienie metadanych wpisu bloga

update_post_meta()

Usuwanie metadanych

delete_post_meta()

Tworzenie własnych taksonomii

Zrozumienie taksonomii

Rejestracja własnej taksonomii

register_taxonomy()

public

show_ui

hierarchical

query_var

rewrite

update_count_callback

show_tagcloud

show_in_nav_menus

labels

capabilities

Rejestracja taksonomii gatunku i artysty

Przypisanie taksonomii do typu wpisu bloga

register_taxonomy_for_object_type()

Używanie własnych taksonomii

Pobieranie taksonomii

get_taxonomy()

Używanie taksonomii wraz z wpisami bloga

the_terms()

Tagi warunkowe taksonomii

taxonomy_exists()

is_taxonomy_hierarchical()

is_tax()

Wtyczka typu wpisu bloga oraz taksonomii

Podsumowanie

Rozdział 12 Technologie JavaScript i Ajax na platformie WordPress

Krótkie wprowadzenie do jQuery

Zalety wynikające z używania jQuery

Krótki kurs jQuery

Obiekt jQuery

Składnia i łączenie

Tryb bezkonfliktowy na platformie WordPress

Wykonanie kodu w gotowym dokumencie

Technologia Ajax

Czym jest Ajax?

Najlepsze praktyki dotyczące technologii Ajax

Dodawanie kodu JavaScript do WordPress

Prawidłowy sposób dołączania skryptów

Wprowadzenie do funkcji wp_enqueue_script()

Dodanie podstawowego skryptu

Dodanie własnego skryptu

Dodanie własnego skryptu wraz z zależnościami

Dodanie własnego skryptu wraz z numerem wersji

Dodanie skryptów w stopce dokumentu

Jednoczesne użycie wszystkich parametrów

Domyślne skrypty dostarczane przez platformę

Usunięcie zakolejkowanego skryptu

Zastąpienie skryptu standardowego własnym

Rejestrowanie skryptów i umieszczanie ich w kolejce

Zarządzanie stylami na platformie WordPress

Gdzie umieszczać skrypty?

W nagłówku? W stopce? Osadzać w kodzie?

W nagłówku

W pobliżu stopki dokumentu

W treści strony

Osadzony w kodzie

Wybór najlepszego rozwiązania

Dodawanie skryptów jedynie wtedy, gdy są potrzebne

Pobieranie położenia skryptów wtyczki

Dodawanie skryptu na stronach administracyjnych

Dodawanie skryptu na stronach publicznych

Skrypty dynamiczne na platformie WordPress

W jaki sposób tego nie robić i dlaczego?

Lepsze rozwiązanie

Rozwiązanie idealne

Technologia Ajax na platformie WordPress

Technologia Ajax na platformie WordPress: reguły

Strona klienta: wykonywanie żądania Ajax, otrzymywanie odpowiedzi

Strona serwera: otrzymanie żądania Ajax, udzielenie odpowiedzi

Kompletny przykład: natychmiastowe odnośniki "Czytaj dalej"

Wstawianie kodu JavaScript

Skrypt JavaScript działający po stronie klienta

Przetwarzanie żądania Ajax po stronie serwera

Kolejny przykład: usunięcie komentarza ze strony

Podstawowy kod wtyczki

Obsługa żądania Ajax po stronie serwera: zapewnienie bezpieczeństwa oraz
przetworzenie odpowiedzi XML

Zapewnienie bezpieczeństwa: unikalna wartość i uprawnienia

Klasa WP_Ajax_Response

Przetwarzanie odpowiedzi XML po stronie klienta

Usuwanie błędów podczas używania technologii Ajax

Podsumowanie

Rozdział 13 Cron

Czym jest cron?

W jaki sposób działa demon cron?

Tworzenie harmonogramu zadań cron

Utworzenie powtarzającego się zadania harmonogramu

Utworzenie jednorazowego zadania harmonogramu

Usunięcie zadania z harmonogramu

Zdefiniowanie własnych odstępów czasu

Wyświetlenie zadań harmonogramu cron

Prawdziwy cron

Przykłady praktyczne

Usuwanie co tydzień wcześniejszych wersji wpisu bloga

Wtyczka automatycznie wysyłająca wiadomość e-mail

Wtyczka usuwająca komentarze

Podsumowanie

Rozdział 14 API Rewrite

Dlaczego czasem trzeba zmieniać adresy URL?

Zasady dotyczące odnośników bezpośrednich

Przyjazny dla silnika wyszukiwarki internetowej

Przyjazny dla użytkownika

Moduł mod_rewrite serwera Apache

Zmiany adresów URL na platformie WordPress

W jaki sposób WordPress obsługuje zapytania?

Ogólny opis procesu wykonania zapytania

Obiekt rewrite

Obiekt query

Co można zrobić przy użyciu wtyczek?

Przykłady praktyczne

Zmiana adresu URL w celu utworzenia listy sklepów

Utworzenie reguły zmiany adresów

Rejestracja zmiennej ciągu tekstowego zapytania

Wyczyszczenie reguł zmiany adresów

Funkcjonalna wtyczka

Utworzenie strony sklepów, która może wygenerować strony potomne

Tworzenie nowej struktury odnośników bezpośrednich oraz integracja ze
stronami, które nie powstały w WordPress

Utworzenie znacznika zmiany adresów

Wyświetlanie produktów sklepu

Funkcjonująca wtyczka

Dodawanie punktu końcowego i zmiana formatu danych wyjściowych

Definicja punktu końcowego

Funkcjonująca wtyczka

Dodanie własnego kanału wiadomości informującego o ostatnio dodanych
obrazach

Rejestracja nowego kanału wiadomości

Funkcjonująca wtyczka

Podsumowanie

Rozdział 15 Sieć Multisite

Różnice

Standardowa konfiguracja WordPress kontra sieć Multisite

Zrozumienie terminologii sieci Multisite

Zalety sieci Multisite

Włączenie sieci Multisite na platformie WordPress

Funkcje sieci Multisite

Potęga identyfikatora bloga

Najczęściej używane funkcje

Przełączenie i przywracanie witryn internetowych

Przykłady skrótów uzyskania dostępu do treści sieci

Przykład widgetu z treścią sieciową

Utworzenie nowej witryny

Opcje witryny sieci Multisite

Użytkownicy w sieci

Rola Superadministratora w sieci Multisite

Sprawdzenie właściciela witryny

Dane statystyczne dotyczące sieci

Schemat bazy danych sieci Multisite

Tabele stosowane w sieci Multisite

Tabele przeznaczone dla konkretnych witryn

Podsumowanie

Rozdział 16 Usuwanie błędów i optymalizacja

Zapewnienie (lub nie) obsługi starszych wersji

Aktualizacja oprogramowania zgodnie z cyklem rozwojowym WordPress

Funkcje uznane za przestarzałe

Obsługa zbędnych instalacji

Usuwanie błędów

Włączenie trybu usuwania błędów

Wyświetlanie komunikatów związanych z usuwaniem błędów

Poprawianie błędów wskazywanych przez komunikaty

Rejestrowanie błędów

Włączenie rejestrowania błędów

Położenie pliku dziennika błędów

Plik dziennika błędów

Buforowanie

Zapisywanie, wczytywanie i usuwanie buforowanych danych

wp_cache_add()

wp_cache_replace()

wp_cache_set()

wp_cache_get()

wp_cache_delete()

Buforowanie danych we wtyczce

Podsumowanie

Rozdział 17 Działania marketingowe

Wybór licencji dla wtyczki

Różne opcje

Dlaczego licencja ma znaczenie?

Zarabianie pieniędzy pomimo stosowania licencji GPL

Udostępnienie wtyczki na witrynie WordPress.org

Utworzenie konta

Zgłoszenie wtyczki do oficjalnego repozytorium

Konfiguracja SVN

Utworzenie pliku readme.txt

Rozsławienie wtyczki

Nadawanie nazwy wtyczce

Wskazówki dotyczące tworzenia nazwy wtyczki

Jakich nazw nie używać dla wtyczek?

Branding wtyczki

Zbudowanie witryny internetowej

Utworzenie strony lub witryny dla wszystkich Twoich wtyczek

Przygotowanie doskonałego projektu

Blogowanie na temat WordPress

Utworzenie strony dla wtyczki

Ogłoszenie wydania wtyczki

Pomoc techniczna dla użytkowników wtyczki

Zbieranie informacji od użytkowników

Wyjście z piwnicy

Inne metody promocji

Podsumowanie

Rozdział 18 Narzędzia programisty

Jądro platformy jako punkt odniesienia

Dokumentacja osadzona na platformie

Wyszukiwanie funkcji

Najważniejsze pliki tworzące jądro platformy

formatting.php

functions.php

pluggable.php

plugin.php

post.php

Codex

Przeszukiwanie witryny Codex

Opis funkcji

Narzędzia oferowane przez inne witryny internetowe

PHPXref

Baza danych zaczepów platformy WordPress

Zasoby oferowane przez społeczność

Fora pomocy technicznej

Listy dyskusyjne

Czat WordPress

Informacje dotyczące prac rozwojowych nad WordPress

Zgłaszanie pomysłów dla WordPress

Obsługiwane przez społeczność witryny z nowościami

WordPress Planet

Planet WordPress

WPEngineer.com

WeblogToolsCollection.com

Twitter

Wydarzenia lokalne

Narzędzia

Przeglądarka internetowa

Edytor tekstu

NetBeans IDE

Notepad++

TextMate

Coda

Obsługa plików za pomocą FTP, SFTP i SSH

phpMyAdmin

Podsumowanie
