Oook… Powiedzmy, że mam wolną chwilę, więc wrócę do niesłychanie fantastycznego zajęcia, jakim jest uczenie Was jak stać się moją konkurencją i tworzyć bombowe pluginy do WordPressa 😉 Ups, po napisaniu tego zdania nieco przeszła mi ochota na pisanie dalszej części, ale mówi się trudno. Lecimy.

Wszystkim nowicjuszom na naszym kursie przypominam, że jest to już trzecia lekcja. Więc jeśli ktoś wagarował, niech szybko leci najpierw przeczytać notatki z lekcji pierwszej i lekcji drugiej. Niestety znajomość lekcji poprzednich jest raczej bardzo wskazana, gdyż założyłem sobie, że każda kolejna część nie będzie omawiać dokładnie rzeczy już wcześniej omówionych. Założenie chyba logiczne?

Zaczynamy

Co dzisiaj mamy? Może zajmijmy się moim ulubionym darmowym pluginem (bo oczywiście najbardziej ulubiony jest płatny WP Sprzedawca), jakim jest Upgrade Notification by Email. Plugin jest bardzo króciutki ale nie dajcie się zwieść jego mikroskopijnym rozmiarom.

Przede wszystkim jego mikroskopijność to oznaka dość zaawansowanego programowania. W pierwszej wersji plugin był o wiele (wiele) dłuższy. Jednak z biegiem czasu nauczyłem się jak unikać tworzenia funkcji, które robią to samo co już robi jakaś ukryta funkcja WordPressa. I dlatego coś, co wcześniej potrzebowało napisania kilkunastolinijkowej funkcji, teraz zostało zastąpione prze odwołanie się do już istniejących funkcji w silniku tego systemu blogowego.

Założenia

Plugin w założeniach jest bardzo prosty: ma wysyłać na maila informację do administratora strony gdy pojawiła się nowsza wersja WordPressa. Ma tą informację wysyłać tylko i wyłącznie jeśli admin nie dokonał jeszcze aktualizacji. I tyle.

Proste? Proste. Zatem…

Zaczynamy (ponownie)

Czynność jest tutaj tylko jedna: wysłanie maila do administratora, więc i funkcja będzie tylko jedna. Funkcja ta ma się wykonać tylko i wyłącznie, jeśli zainstalowana wersja WordPressa jest starsza niż najnowsza, zatem funkcja na pewno jakoś sprawdzi instrukcją if czy ten warunek jest spełniony.

Pojawia się też kolejna zagadka: kiedy funkcja ma zostać uruchomiona? Do tej pory poznaliśmy dwa sposoby odwoływania się do naszych pluginowych funkcji:

– poprzez hak filtrujący wypluwaną treść
– poprzez hak reagujący na jakąś akcję na blogu

Od razu mówię, że nie zastosujemy tu żadnego z nich. Choć moglibyśmy. Na przykład hakiem filtrującym moglibyśmy w momencie wyświetlania użytkownikowi treści wpisu po kryjomu wywołać naszą funkcję i wysłać adminowi maila z powiadomieniem o konieczności instalacji nowszej wersji. Albo hakiem reagującym na jakąś akcję (na przykład dodanie komentarza do wpisu) zrobić to samo.

Da się, ale ma to w naszym wypadku dość sporą wadę: admin miałby na swojej skrzynce kilkadziesiąt maili (jeśli nie tysiące w przypadku gdy admin administruje popularnym blogiem) z upomnieniem o aktualizacje. Co prawda moglibyśmy dalej się upierać przy taki zastosowaniu, dodając do kodu rodzaj łatki, który by sprawdzał czy admin już dostał maila, ale… ale nie brnijmy w tym kierunku. Po pierwsze, że nie będzie to wydajne (tak czy owak nasza funkcja wywoływała by się setki razy dziennie), a po drugie jest gotowe rozwiązanie w samym wordpressie przygotowane specjalnie na takie okazje, a nazywa się ono

wp-cron

Tak. WordPress ma wbudowany mechanizm pseudo cronu czyli narzędzie do planowania wykonywania funkcji. Dzięki niemu możemy sobie zaplanować by dana funkcja wykonywała się raz na godzinę, raz na dzień itd.

Dobra, koniec z tymi teoretycznymi rozważaniami. Wszystko co chciałem wyjaśnić do tej pory, już wyjaśniłem. Czas zobaczyć kawałek kodu i krok po kroku zobaczyć jak nasz plugin działa.

(tradycyjnie pomijam nagłówek pliku plugina – to już poznaliście dawno)

register_activation_hook(__FILE__, 'wpu_my_activation');

function wpu_my_activation() {
wp_schedule_event(time(), 'daily', 'wpu_my_daily_event');
}

add_action('wpu_my_daily_event', 'wpu_do_this_daily');

Część rzeczy już znacie, część dopiero poznacie.

Linijka 28 jest już Wam znana z poprzedniej lekcji: tworzymy tutaj hak, jaki ma się wykonać w czasie instalacji pluginu. Informujemy tutaj aby w czasie instalacji została wykonana funkcja wpu_my_activation().

Owa funkcja znajduje się w linijce 30 i zawiera w sobie dwie funkcje wbudowane w WordPressa.

Pierwsza funkcja – wp_schedule_event() – służy do zanotowania przez WordPress funkcji, jaka ma się wykonywać cyklicznie (to ten właśnie pseudo-cron). Jako pierwszy argument pobiera czas w postaci uniksowego znacznika kiedy rejestrowana funkcja ma zostać wykonana po raz pierwszy (użyłem tu funkcji time() gdyż chciałem aby pierwsze wykonanie wysłania – lub nie wysłania – maila do admina nastąpiło od razu przy instalacji plugina). Drugi argument informuje wordpressa co ile czasu funkcja ma być powtarzana (niestety na razie może przyjmować tylko dwie wartości: daily i hourly). Trzeci argument to nazwa haka jaki ma zostać zarejestrowany.

W linii 34. widzimy dobrze nam znane już add_action(). Tutaj wiąże ono właśnie zarejestrowanego co dobowego haka wpu_my_daily_event z funkcją właściwą wpu_do_this_daily().

Do funkcji jeszcze dojdziemy, zobaczmy co teraz mamy:

register_deactivation_hook(__FILE__, 'wpu_my_deactivation');

function wpu_my_deactivation() {
wp_clear_scheduled_hook('wpu_my_daily_event');
}

Oho, tego chyba jeszcze nie było. Poznaliśmy już rejestrowanie haka aktywacyjnego, który się wykonuje gdy plugin jest aktywowany przez admina, czasem jednak trzeba też wykonać jakieś funkcje podczas odinstalowywania plugina. Służy do tego hak deaktywacyjny register_deactivation_hook, który podobnie do haka aktywacyjnego ma dwie zmienne: nazwę odinstalowywanego pliku z pluginem oraz nazwę funkcji, która ma się wykonać w czasie odinstalowywania.

Akurat tutaj trzeba coś wykonać w czasie deaktywacji plugina. Musimy wyłączyć codzienne zadanie sprawdzania aktualizacji i wysyłania maila. Służy do tego funkcja wp_clear_scheduled_hook() przyjmująca jako argument nazwę haka, który ma przestać działać.

Co by się stało gdybyśmy nie deaktywowali naszego haka? WordPress nadal by miał w swojej bazie zadań polecenie uruchomienia raz na dobę zadania wpu_my_daily_event. Zadanie to znajduje się w naszym pliku z pluginem, a plugin jest przecież odinstalowany… oj byłby problem.

Wyślij w końcu tego maila!

Ok, wszystko jest już porejestrowane i plugin jest już gotowy na ewentualne odrejestrowanie zadania. Czas napisać naszą ostateczną funkcję czyli wpu_do_this_daily()

function wpu_do_this_daily() {
$taken_transient = get_transient('update_core');
$za = $taken_transient->updates;
$zb = $za[0];
$zm = $zb->response;
if ($zm == "upgrade") {
$wpsender = get_option('admin_email');
$forwhom = get_option('admin_email');
$subject = "Your blog " . wp_specialchars( get_option('blogname') ) . " should be upgraded";
$headers = "From: " . wp_specialchars( get_option('blogname') ) . " <$wpsender>\n";
$headers .= "Content-Type: text/html\n";
$headers .= "Content-Transfer-Encoding: 8bit\n";
$mailtext = "The plugin Upgrade Notification by Email noticed that at WordPress server is available newer version of blogging software than this, which is installed at " . wp_specialchars( get_option('blogname') ) . ". Please upgrade it in your admin panel. You have ".$taken_transient->version_checked." and newest is " . $zb->current . ". You can download WordPress directly from " . $zb->package;
wp_mail($forwhom, $subject, $mailtext, $headers);
}
}

?>

Długie? Bywało dłuższe. Zobaczmy, może od końca, co ta funkcja robi.

Wysyłanie maila następuje po pozytywnym wykonaniu instrukcji if w linijce 47. Jeśli if zostanie spełniony (o nim za chwilę), to zostaną przygotowane dane do maila i zostanie wysłany ów mail. Dane do maila to:

Linijka 48.: adres email jaki ma się pojawić w polu ‚From:’ maila. Jest on wyciągany jak widać z mechanizmu opcji wordpressa (czy ja już o tym pisałem? Chyba coś było na ten temat w części drugiej).

Linijka 49.: w podobny sposób pobierany jest adres email pod jaki mail ma zostać wysłany (tak, adres jest ten sam).

Linijka 50. to temat listu, linijki 51-53 to niezbędne nagłówki listu, a linijka 54. to jego treść.

I w linijce 51. mamy wordpressową funkcję do wysyłania maili – wp_mail(). Składnia jej jest taka sama jak wbudowanej w PHP funkcji mail().

Wróćmy do naszego if-a, który ma powstrzymać wordpress przed wysłaniem maila lub kazać go wysłać. If musi sprawdzić czy wersja zainstalowana jest starsza niż aktualnie dostępna na serwerze.

Wcześniej w tym celu napisałem własną funkcję, która pobierała z $wp_version informację o zainstalowanej wersji wordpressa, łączyła się za pomocą curl z serwerem wordpressa, sprawdzała jaka jest nazwa najnowszej wersji pliku z wordpressem, wynajdowała w tej nazwie ciąg zawierający w sumie numer wersji i porównywała ze sobą. Działało to dość dobrze, ale coś mi nie grało.

Po pierwsze WordPress przecież sam w panelu admina wyświetla na górze informację o konieczności aktualizacji, zatem musi mieć gdzieś wbudowaną funkcję robiącą to samo co ja właśnie chcę zrobić. Po drugie takie korzystanie z curl i wyciąganie fragmentów urla może być zawodne, jeśli na przykład zmieni się schemat nazywania pliku z instalką wordpressa.

Oczywiście okazało się, że funkcja sprawdzająca wersję wordpressa faktycznie istnieje i nazywa się dość intuicyjnie bo wp_version_check().

Nie możemy się jednak do niej odwołać bezpośrednio, bo funkcja ta nie zwraca żadnej wartości, a jedynie wywołuje funkcje kolejne (tutaj akurat interesuje nas funkcja tworząca wartość ulotną (ang. transient) o nazwie ‚update_core’). Nie wgłębiajmy się za bardzo w te krwiste bebechy, najważniejsze jest, że musimy:

– pobrać do zmiennej obiektowej wartość przelotną ‚update_core’ za pomocą fukcji get_transient() (linijka 43.)

– z owej zmiennej obiektowej wyciągnąć wartość pola ‚updates’ (linijka 44.)

– i w kolejnych linijkach dojść do tego co odpowiedział serwer na pytanie o konieczność aktualizacji.

I teraz jeśli odpowiedział słowem ‚upgrade’, posłuchajmy go i wyślijmy wyżej opisany list do administratora.

Skomplikowane? Przyznaję, że tak. Na tyle skomplikowane, że nie chcę wnikać dokładnie w powyższy kod. Jak dokładnie przebiegło wyłuskiwanie słowa ‚upgrade’, jakie inne słowa zostałyby wysłuskane, może się przekonać każdy z Was po wnikliwej analizie kodu funkcji wp_version_check(). (przy okazji zwróćcie też uwagę, że w samej treści maila są odwołania do obiektu $zb przechowującego nieco informacji o aktualnej weresji WordPressa)

W każdym razie zapewniam Was, że to działa, o czym każdy może się przekonać pobierając opisany wyżej plugin ze strony WordPressa 🙂