
Ostatnia rzecz jaką należy zrobić, żeby nasz szablon posiadał pełnię funkcjonalności, to dodanie możliwości zapisu danych kontaktowych, wysyłany przez formularz do bazy danych. Ponownie wykorzystamy plik functions.php do rozszerzenia funkcjonalności szablonu. Do obsługi formularza wykorzystamy AJAX. Załączony do tego wpisu kod powinien dobrze objaśnić mechanizm działania wysyłki i obsługi formularza oraz metody programowania serwerowych skryptów WordPress. Zapraszam do lektury.
~ Rafał, Learn2Code
Przygotowanie formularza
Przy programowaniu wysyłki i obsługi formularza będziemy się kierować wskazówkami wynikającymi z dobrych praktyk programistycznych i UX.
- Formularz powinien być wysyłany asynchroniczne, aby ograniczyć liczbę przekierowań. Oznacza to, że chcemy, aby po kliknięciu przycisku “Submit” (“Wyślij”), nie dochodziło do przeładowywania strony, ani przekierowywania.
- Dane z formularza powinny zostać sprawdzone (przed zapisaniem ich w bazie danych) pod kątem występowania zapytań, mogących stanowić atak hakerski na naszą stronę.
Wskazówki te narzucają rozwiązania programistyczne. Do wysyłania formularza zastosujemy AJAX (Asynchronous JavaScript and XML). Kod , który będzie dla nas wysyłał żądania do serwera asynchrocznicznie napiszemy korzystając z JavaScript i biblioteki jQuery.
Po stronie serwera musi pojawić się skrypt, który powyższe żądanie będzie potrafił obsłużyć (sprawdzić pod kątem ataku typy SQL injection) i zwrócić informację zwrotną o wyniku powodzenia zapisu. Taki kod znajdzie się w pliku functions.php
.
Zacznijmy implementowanie wysyłki formularza od zmodyfikowania szablonu, tak aby umieszczony na nim szkielet formularza nabrał funkcjonalności.
Pierwsze co przychodzi do głowy, to uzupełnienie atrybutów formularza o atrybut action, wskazujący docelowy adres wysyłki. Dokumentacja WP wyraźnie wskazuje, że wszystkie asynchroniczne żądania AJAX`owe muszą być kierowane na adres wp-admin/admin-ajax.php
. Kompletny adres jest jednak generowany automatycznie przez odpowiednią funkcję PHP. W przypadku WordPress tak wygenerowany kod jest następnie dodawany (w procesie lokalizacji) do globalnego obiektu jQuery. Dlatego zajmiemy się tym w dalej. W tym momencie zostawiamy ten atrybut bez zmian.
Żądania będą obsługiwane przez kod zapisany w functions.php
. Docelowy adres wp-admin/admin-ajax.php
nie wskazuje żadnej konkretnej docelowej metody. Co więcej, jeśli dodalibyśmy kolejny formularz wysyłany AJAX`em (np. wysłanie formularza zamówienia produktu), to w nim też musielibyśmy użyć tego samego adresu URL. Czy to oznacza, że jesteśmy skazani tylko na jedną funkcję obsługującą wszystkie formularze? Bynajmniej.
WordPress identyfikuje funkcje, którą mają obsłużyć konkretne żądanie na podstawie dodatkowego pola o nazwie “action“, wysyłanej razem z formularzem. Jest to to pole obowiązkowe dla wszystkich formularzy AJAX`owych. Należy więc do istniejącego już formularza dodać nowe pole o następujących atrybutach:
name = "action"
Atrybut name pomoże zidentyfikować odpowiednią zmienną z przypisaną jej wartością (value), w plikufunctions.php
.value = "form_handler"
Ten atrybut reprezentuje wartość pola przesyłaną wraz z formularzem. W tym przypadku wartość jest ustawiona na sztywno i będzie zawsze taka sama (czyli będzie ciągiem znaków o wartości “form_handler”).type = "hidden"
Chcemy, żeby to pole nie było widoczne na stronie. Zależy nam tylko na tym, aby znajdowało się w kodzie i było wysyłane razem z formularzem.
Zmodyfikowany kod formularza powinien teraz wyglądać następująco:
Jest to pierwszy element układanki. Do osiągnięcia pełnej funkcjonalności potrzebujemy jeszcze dwóch:
- Kodu JavaScript, który będzie odpowiedzialny za wykonanie asynchronicznego żądania zapisu danych z formularza w bazie.
- Kodu PHP po stronie serwera, który takie żądanie odbierze i przekaże przeglądarce informacje zwrotną.
JavaScript
Zacznijmy od kodu JavaScript. Dla czytelności i wygody, kod zostanie napisany przy użyciu biblioteki jQuery. jQuery to biblioteka języka JavaScript, oferująca szereg ułatwień, w tym możliwość pisania bardziej czytelnego kodu. jQuery jest częścią podstawowych bibliotek stosowanych przez WordPress, dlatego nie ma konieczności wykonywania dodatkowych instalacji.
Kod należy umieścić w osobnym pliku. Proponuję go nazwać main.js
i umieścić katalogu z pozostałymi plikami projektowymi. Trudność pojawia się w momencie dołączania pliku do strony. Niestety nie należy dodawać skryptów poprzez znacznik <script> samodzielnie w nagłówku strony, jak to było w przypadku stylów. Aby to zrobić trzeba utworzyć w pliku functions.php
funkcję, która na podstawie podanych ścieżek załaduje go automatycznie. Zacznijmy zatem od dokonania zmian w functions.php
.
Na uwagę zasługuje następujący fragment:
$title_nonce = wp_create_nonce( 'custom_nonce' );
wp_localize_script('ajax-script', 'ajax_object', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => $title_nonce,
)
);
Aby móc wysyłać żądania AJAX do WordPress potrzeba dwóch rzeczy po stronie przeglądarki.
- Po pierwsze żądanie musi zawierać tzw.
nonce
, czyli zmienną potwierdzającą, że żądanie przychodzi z zaufanego źródła. Wartość ta jest generowana przez metodęwp_create_nonce(...).
- Druga istotna wartość to adres URL, do którego wysyłane jest żądanie. Wszystkie żądania asynchroniczne muszą być kierowane na adres
wp-admin/admin-ajax.php
. Jednak do funkcji jQuery należy podać kompletny adres. Adres ten jest generowany przez metodęadmin_url('admin-ajax.php')
po stronie serwera i przekazywany do jQuery.
W ten sposób na serwerze, po załadowaniu plików ze skryptami, utworzyliśmy dwie zmienne, o których musi jeszcze zostać poinformowany klient, czyli JavaScript w przeglądarce. Za to odpowiedzialna jest tzw. lokalizacja, czyli metoda wp_localize_script
, tworząca globalny obiekt jQuery i ustawiająca wartość jego zmiennych, zgodnie z powyższym kodem. Dzięki temu po stronie klienta mamy dostęp do
- obiektu globalnego ajax_object
- zmiennej z nonce, czyli ajax_object.nonce
- zmiennej z adresem docelowym, czyli ajax_object.ajax_url
Aby poinformować WordPress, w którym miejscu na stronie ma załadować wskazany skrypt należy upewnić się, że w nagłówku strony, w pliku header.php
jest wywoływana funkcja wp_head()
(doda ona odpowiednie skrypty w nagłówku).
Następnie w pliku main.js
należy umieścić przedstawiony kod. Komentarz do niego znajduje się poniżej.
jQuery(document).ready(function($) { ... }
Ten fragment oznacza, że przypisanie funkcjonalności nastąpi dopiero po załadowaniu dokumentu. Gdyby nie .ready
, mogłoby dojść do sytuacji, w której skrypt zostanie uruchomiony przed załadowaniem całego dokumentu HTML i nie odnajdzie formularza.
$('#newsletter-form').on('submit', function(e) { ... }
$(“..”) odszukuje na stronie element o wskazanym w cudzysłowach id, a następnie przygotowuje się do sprawdzenia, czy następuje wysłanie formularza poprzez kliknięcie w przycisk.
e.preventDefault();
Przycisk typu submit
spowoduje wysłanie formularza i przekierowanie strony na adres wskazany w atrybucie “action”. Żeby to powstrzymać, musimy wprost napisać, że domyślna akcja musi zostać zatrzymana. W tym celu stosuje się e.preventDefault().
var $form = $(this), data;
Zapisujemy nasz formularz do zmiennej, aby w czytelny sposób wyciągać przechowywane w niej właściwości.
data = {
_ajax_nonce: my_ajax_obj.nonce,
title: this.value
action: this.action,
name: this.name,
email: this.email
};
Wartości zapisane w odpowiednich polach są umieszczane w zmiennej, która zostanie wysłana do serwera. Warto tutaj zwrócić uwagę, że oprócz 3 pól (name, email, action) pojawiły się dwa nowe _ajax_nonce i title. Są to pola obowiązkowe, wymagane przed WordPress. Każde zapytanie, które ma na celu dokonać zmian w bazie danych musi je posiadać.
$.post($form.attr('action'), data , function(data) {
console.log("Dane zwrócone przez serwer" + data)
}, 'json');});
Wysłanie żądania metodą post.
Wysyłanie formularza POST VS GET
Post i Get to dwie metody protokołu HTTP. Definiują one sposób, w jaki dane mają zostać przekazane serwerowi. Główna różnica pomiędzy nimi polega na tym, że GET wysyła informacje poprzez dodanie wartości do adresu url, a POST nie. W naszym przypadku POST wydaje się być naturalnym wyborem, bo nigdzie nie zależy nam na pracy z adresem url.
Efekt osiagnięty metodą GET: landing.php?name=123&email=3245
Efekt osiągnięty metodą POST: landing.php
PHP i aktualizacja bazy danych
Obsługa żądania odbywa się na serwerze. W przypadku WordPress’a odpowiedzialny za to kod musi znaleźć się w pliku functions.php
. W tym momencie można już zauważyć pewien schemat. Otóż każda nowa funkcjonalność składa się z dwóch elementów:
- deklaracji funkcji wraz z zaprogramowaną logiką
- metodą
add_action
przypisującą funkcję do konkretnej “akcji”, czyli jakiegoś zdarzenia znanego WordPressowi. W przypadku obsługi żądań AJAX, nie wymagających logowania tą akcją zawsze będziewp_ajax_nopriv_<nazwa_funkcji>
.<nazwa_funkcji> jest z kolei identyfikowana dzięki polu action, dodanym na wstępie.
Bazowa struktura takiej funkcji mogła by wyglądać następująco:
add_action( 'wp_ajax_nopriv_form_handler', 'form_handler' );
function form_handler() {
.....
}
My chcemy, żeby strona serwerowa potrafiła, w odpowiedzi na wysłanie formularza, wykonać kod zapisujący użytkownika do bazy danych i przekazała przeglądarce odpowiedź informującą o sukcesie lub porażce tej akcji.
Niestety na ten moment nie nie istnieje jeszcze tabela, do której moglibyśmy dopisać naszych użytkowników. Od jej dodania powinniśmy zacząć implementacje (czyli zaprogramowanie danej funkcjonalności).
Utworzymy ją według znanego już schematu: w pliku functions.php
przygotujemy funkcję, która utworzy, a następnie rozkażemy WP ją wykonać w odpowiedzi na zdarzenie. Proponuję wykorzystać akcję “after_switch_theme”, która zostanie uruchomiona, po zmianie szablonu strony w panelu administratora. Zatem należy na zmienić motyw na inny, aby ponownie włączyć nasz. Nasz szablon posiada kod dla akcji “after_switch_theme”, dlatego w tym momencie do bazy danych zostanie dodana nowa tabela. Kod dodający nową tabelę w pliku functions.php
:
W załączonym przykładzie przy kolumnie email pojawiło się słowo UNIQUE
. Gwarantuje ono, że dany adres email może występować tylko raz.
Teraz można dodać brakujący kod PHP obsługujący formularz i zapisujący go do bazy.
Wszystko wydaje się być na swoim miejscu i możemy sprawdzić, czy działa zgodnie z oczekiwaniami. W tym celu należy wejść na stronę i uruchomić narzędzia programistyczne dostępne w przeglądarce. W trakcie pisania tutoriala, korzystałem z przeglądarki Firefox, dlatego zademonstruje jak to zrobić właśnie na niej. Każda popularna przeglądarka oferuje możliwość z narzędziami deweloperskimi.
Naciśnij prawy przycisk myszy na stronie z szablonem i wybierz z menu, które się pojawiło “Zbadaj element”. Możesz też użyć skrótu klawiszowego CTR+SHIFT+I.

Po prawej stronie ekranu wyświetli się konsola deweloperska. Wybierz zakładkę “Sieć” (zgodnie z rysunkiem).

Wypełnij formularz danymi i kliknij “Submit”. Jeśli wszystko jest w porządku i podczas wysyłania formularza nie pojawił się komunikat błędu.

Na wszelki wypadek należy się upewnić, czy informacja została faktycznie zapisana w bazie danych.
Ja korzystam z Vagrant`a, więc moja baza danych działa na wirtualnym środowisku. Żeby się do niej dostać i wyświetlić listę użytkowników muszę:
- zalogować się do wirtualnej maszyny poprzez komendę
vagrant ssh
.
- zalogować się do bazy danych, stosując domyślne dane logowania:
mysql -u root -proot
- wybrać bazę danych mojego środowiska:
use wordpress-dev;
- wyświetlić wszystkie rekordy tabeli wp_newsletter_list.
select * from wp_newsletter_list;

Ostatnie szlify
Bazowa funkcjonalność została zaprogramowana i spełnia założenia projektu. Zanim jednak uznamy pracę za skończoną powinniśmy wykonać parę czynności.
Dobre praktyki UX zalecają, aby po wykonaniu akcji użytkownik był w czytelny sposób poinformowany o jej przebiegu. Dobrze by zatem było, gdyby po wysłaniu formularza i pomyślnego dodania rekordu do bazy danych pod formularzem pojawił się komunikat informujący o powodzeniu operacji lub o błędzie.
Funkcja obsługująca żądanie AJAX`owe w przypadku pomyślnego dodania adres zwróci w odpowiedzi obiekt typu JSON zawierającego pole o nazwie “error” z wartością false. Oznacza to, że nie wystąpił żaden błąd. Jest to dobry punkt wyjścia do zaprogramowania logiki odpowiedzialnej za zmiany po stronie klienta, czyli skrypt, w którym odczytujemy odpowiedź z serwera, wyświetlający element z odpowiednią treścią. Najlepiej, jeśli komunikat będzie wysyłany przez serwer razem z informacją o ewentualnym błędzie.
Aby to osiągnąć utworzymy przy użyciu JavaScript i jQuery nowy element, w funkcji odbierającej odpowiedź z serwera. Następnie w zależności od wartości pola error nadamy mu odpowiednie klasy. Należy zatem:
- W funkcji przyjmującej odpowiedź z serwera utworzyć nowy element. Na tym etapie jest dostępny tylko z poziomu kodu jQuery, bo nie dodaliśmy go jeszcze do struktury HTML naszej strony.
- Za pomocą instrukcji warunkowej if sprawdzić, czy odpowiedź z serwera zawiera w sobie informacje o wystąpieniu błędu. W zależności od wyniku funkcji dodana klasa spowoduje, że tło komunikatu będzie czerwone lub zielone.
- Wypełnić nowy element o treść komunikatu zwróconą z serwera.
- Element z dodaną klasą i zawierający tekst dodać do struktury HTML pod formularzem, dzięki czemu pojawi się na stronie.
Widoczne w kodzie klasy alert, alert-success i alert-danger są częścią biblioteki Bootstrap i są wykorzystywane właśnie w takich przypadkach jak nasz, gdzie trzeba w widoczny sposób wyświetlić komunikat. Treść komunikatu otrzymujemy w odpowiedzi pochodzącej z serwera i jest to lepsze rozwiązanie niż umieszczanie go w pliku ze skryptami JavaScript.
Kwestie bezpieczeństwa
Dobre praktyki programowania aplikacji internetowych wyraźnie nakazują sprawdzanie przesyłanych formularzy przed zapisaniem zawartych w nich danych do bazy i usunięcie potencjalnie niebezpiecznych znaków. Dzięki temu ochronimy naszą aplikację przed złośliwościami, które mogą nas doprowadzić do utraty wszystkich danych!
Takie zapobiegawcze działanie nazywa się sanitaryzacją. WordPress oferuje kilka przydatnych funkcji, które pomogą nam zabezpieczyć dane, które chcemy zapisać. W formularzu przesyłamy dwie wartości email i nazwę użytkownika. Możemy więc zastosować następujące metody:
sanitize_text_field( ... )
Usunie białe znaki, sprawdzi tekst pod kątem poprawności kodowania UTF-8 i pozbędzie się niebezpieczne znaki, odpowiednio je modyfikując.sanitize_email( )
Sprawdzi tekst pod kątem poprawności adresu email.
Funkcji należy użyć na wartościach przesyłanych w zmiennej $_POST, w funkcji obsługującej formularz.
Podsumowanie
Zabezpieczenie bazy danych przed potencjalnymi atakami było ostatnim krokiem do przygotowania kodu pod pracę z własnym szablonem. Na przestrzeni 6 krótkich wpisów przeszliśmy od przygotowania struktury HTML, po zaprogramowanie back-endu oraz obsługę formularzy i asynchroniczny JavaScript. Celem tego tutorialu było przekazanie minimum wiedzy potrzebnej do samodzielnego kodowania motywów WordPress, zrozumienia jego mechaniki i natury oraz języka aplikacji internetowych. Jeśli udało mi się wzbudzić ciekawość i zainteresować tego typu rozwiązaniami, to gorąco zapraszam na stacjonarne kursy Learn2Code z obszaru webdevelopmentu i projektowania stron w WordPress, które pojawią się już niebawem!