Wprowadzenie do tworzenia wtyczek WordPress na przykładzie formularza propozycji użytkownika
WordPress jest jednym z najpopularniejszych systemów zarządzania treścią. Jest tak między innymi dlatego, że umożliwia szybkie i łatwe rozszerzanie funkcjonalności poprzez plugin-y, czyli po polsku wtyczki. W sieci można znaleźć wiele dodatków dla tego CMSa. Jednaka co w przypadku, gdy żadna z nich nie spełnia wszystkich naszych oczekiwań? Wtedy warto pomyśleć o napisaniu swojej własnej.
Tworzenie rozszerzeń WordPress to temat rzeka, dlatego ten poradnik nie porusza wszystkich możliwych zagadnień z tym związanych, a jedynie wprowadza w świat wtyczek WP.
Jako, że najlepiej uczyć się na przykładach, w tym artykule przedstawię, w jaki sposób można napisać prostą wtyczkę dodającą formularz, przy pomocy którego użytkownik będzie mógł przekazać nam swoją sugestię, propozycję lub pomysł dotyczącą naszej strony lub bloga.
Podstawy tworzenia wtyczek
Miejsce, w którym piszemy wtyczki znajduje się w katalogu …/wp_content/plugins. Należy w nim utworzyć osobny katalog o nazwie pisanego rozszerzenia, a w nim plik .php, o takiej samej nazwie. Jest to główny plik, od którego system zacznie uruchamianie naszego kodu. Jeżeli będziemy chcieli w przyszłości opublikować wtyczkę, ważne jest żeby jej nazwa była unikalna, tzn. aby nie zdarzył się konflikt nazewnictwa z innymi dostępnymi wtyczkami.
Pierwsze linijki kodu to komentarz opisujący nasz plugin. Dostarcza systemowi takich informacji jak nazwa, opis, autor, wersja, strona projektu, informacje o licencji, itp. Informacje te będą pokazane w panelu administratora w dziale zarządzania wtyczkami.
1 2 3 4 5 6 7 8 9 10 |
<?php /* Plugin Name: Moja super wtyczka Plugin URI: http://www.moja-super-wtyczka.com Description: Więcej informacji Version: 1.0 Author: Jan Kowalski Author URI: http://www.jan-kowalski.com License: GPL2 */ |
WordPress dostarcza nam szereg narzędzi, przy pomocy których jesteśmy w stanie dodać lub zmodyfikować dowolną funkcjonalność i to bez ingerencji w kod samego systemu. Oczywiście istnieje możliwość rozszerzania kodu źródłowego CMSa o własne funkcje, jednak jest to bardzo złe rozwiązanie i do tego mocno niepraktyczne (tak zmodyfikowany kod byłoby ciężko kontrolować, aktualizować oraz udostępniać innym osobom). O wiele lepszym pomysłem jest oddzielenie swojego kodu od źródła WP, a następnie połączenie go z systemem przy pomocy „zaczepów” tzw. hook-ów.
Hook jest to właśnie słowo klucz i cała esencja tworzenia plugin-ów w systemie WordPress. Przy pomocy hook-ów zmieniamy funkcjonalność naszej strony lub dodajemy swoje rozwiązania. Rozróżniamy dwa podstawowe typy hooków:
- hook akcji – action – umożliwia dodanie własnej funkcjonalności, obok już istniejącej w systemie
- hook filtra – filter – umożliwia modyfikację funkcjonalności systemu
Działanie hooków najlepiej pokazać na przykładzie. Załóżmy, że chcielibyśmy w nagłówkach wpisów naszego bloga dołączyć znaczniki protokołu Open Graph, tak aby wskazać portalom społecznościowym jaką treść wpisu mają wyświetlać na swoich stronach.
W pierwszej kolejności piszemy funkcję, której zadaniem będzie wypisanie znaczników w szablonie bloga.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Function addOpenGraphTags() { if(is_single()) { echo '<meta property="og:title" content="'.the_title().'" />'; echo '<meta property="og:site_name" content="'.bloginfo('name').'" />'; echo '<meta property="og:url" content="'.the_permalink().'" />'; echo '<meta property="og:description" content="'.the_excerpt().'" />'; echo '<meta property="og:type" content="article" />'; if(has_post_thumbnail()) { $image = wp_get_attachment_image_src(get_post_thumbnail_id(), 'large'); echo '<meta property="og:image" content="'.$image[0].'" />'; } } } |
Funkcja wypisuje kolejno poszczególne znaczniki, korzystając przy tym z szeregu funkcji dostępnych w systemie WordPress. Następnie należy wskazać, w którym miejscu na stronie dana funkcja ma zostać uruchomiona.
1 |
add_action('wp_head', 'addOpenGraphTags'); |
Hook akcji dodajemy przy pomocą powyższej funkcji, której dwa główne parametry to tag hook-a (wskazuje miejsce uruchomienia, w tym przypadku nagłówek strony) oraz nazwa funkcji.
Teraz wystarczy jedynie w panelu administratora uruchomić wtyczkę i gotowe. Dodaliśmy całkiem nową funkcjonalność bez ingerencji w kod źródłowy WP lub szablonu. Co więcej, tak napisany plugin możemy wykorzystać w innych projektach.
Hook filtra używamy w podobny sposób. Załóżmy, że na końcu znacznika tytułu chcielibyśmy dopisać jakąś stałą treść. Najpierw piszemy funkcję, która będzie zwracała tytuł.
1 2 3 4 |
function changeTitle($title) { return $title. ' – jakaś stała treść :)'; } |
Dodajemy filtr, modyfikujący zawartość tytułu.
1 |
add_filter('the_title', 'changeTitle'); |
Po uruchomieniu wtyczki, przy każdy użyciu funkcji the_title w kodzie strony, treść wynikowa będzie dodatkowo zmieniana przez nasz plugin.
Funkcji, z których możemy korzystać podczas tworzenia naszych rozszerzeń jest masa i nie sposób je wszystkie przedstawić, a tym bardziej zapamiętać. Dlatego stałym źródłem wiedzy, podczas programowania w WP jest dokumentacja: https://codex.wordpress.org oraz oczywiście wujek Google.
Formularz propozycji użytkownika – plugin „Suggestion Box”
Zabieram się za napisanie mojej wtyczki, o której wspominałem na początku artykułu. Nazwałem ją „suggestion box”, czyli pudełko sugestii. Użytkownik będzie mógł wypełnić i wysłać prosty formularz, przedstawiając swoje pomysły na rozwój strony. Informacje te zostaną zapisane w bazie danych, po czym administrator będzie miał do nich dostęp z poziomu panelu zarządzania WP.
W pierwszej kolejności w katalogu …/wp_content/plugins tworzymy katalog suggestions-box, a w nim plik PHP o tej samej nazwie: suggestion-box.php, i dodajemy do niego komentarz opisujący.
1 2 3 4 5 6 7 8 9 10 |
<?php /* Plugin Name: Suggestion Box Plugin URI: http://www.blog.molitorys.pl Description: Plugin generates form which collects suggestions from users Version: 1.0 Author: Stanislaw Molitorys Author URI: http://www.molitortys.pl License: GPL2 */ |
Nasza wtyczka została utworzona i jest widoczna na liście w zakładce „Wtyczki” w panelu administratora.
Jak widać wszystkie informacje o rozszerzeniu są widoczne obok nazwy wtyczki, która jest gotowa do uruchomienia. Na razie jednak nie ma to większego sensu, ponieważ jest ona pusta. Zabierzmy się więc za napisanie jej podstawowej funkcjonalności.
W pierwszej kolejności stworzymy klasę, która będzie odpowiadała za komunikację z bazą wtyczki z bazą danych. W tym celu posłużymy się klasą wpdb, która jest zbiorem funkcji używanych do interakcji z bazą danych. Instancja tej klasy jest dostępna poprzez zmienną globalną $wpdb. W katalogu wtyczki stwórzmy kolejny katalog includes, a w nim skrypt SuggestionBox.php, zawierający model naszego rozszerzenia.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
<?php /** * Suggestion Box plugin model * * @author Stanislaw Molitorys <s.molitorys@gmail.com> */ class SuggestionBox { private $table; private $wpdb; /** * Constructor * - get global object to handle WordPress database * - set suggestion box table name * * @global object $wpdb */ public function __construct() { global $wpdb; $this->wpdb = $wpdb; $this->table = $wpdb->prefix.'suggestion_box'; } /** * Create suggestion box database table */ public function createTable() { $sql = 'CREATE TABLE IF NOT EXISTS '.$this->table.' (' . 'id int(11) NOT NULL AUTO_INCREMENT,' . 'date DATETIME,' . 'name varchar(255) NOT NULL,' . 'email varchar(255) NOT NULL,' . 'suggestion text NOT NULL,' . 'PRIMARY KEY (id)) ' . 'ENGINE=MyISAM AUTO_INCREMENT=1;'; $this->wpdb->query($sql); } /** * Remove suggestion box database table */ public function removeTable() { $sql = 'DROP TABLE IF EXISTS '.$this->table.';'; $this->wpdb->query($sql); } /** * Add new suggestion * * @param array $data */ public function addSuggestion($data) { $sql = $this->wpdb->prepare( 'INSERT INTO '.$this->table.' (date,name,email,suggestion) ' . 'VALUES (NOW(),%s,%s,%s);', $data['name'], $data['email'], $data['suggestion'] ); $this->wpdb->query($sql); } /** * Get all suggestions from database * * @return array */ public function getAllSuggestions() { $sql = 'SELECT id, date, name, email, suggestion FROM '.$this->table.' ORDER BY id DESC;'; return $this->wpdb->get_results($sql, ARRAY_A); } } |
Klasa zawiera dwie właściwości prywatne, konstruktor oraz cztery metody, które będą wykorzystywane podczas pisania głównego kodu plugin-u.
Właściwości:
- $table – nazwa tabeli w bazie danych
- $wpdb – instancja klasy, dostarczającej interfejs to komunikacji z bazą danych
Konstruktor – służy do ustawiania nazwy tabeli oraz obiektu wpdb. Do nazwy tabeli na początek doklejany jest prefix, który był podawany podczas instalacji WordPress-a na serwerze (domyślnie wp_).
Metody:
- createTable() – tworzy tabele sugestii w bazie danych
- removeTable() – usuwa tabele sugestii z bazy danych
- addSuggestion($data) – dodaje nową sugestię
- getAllSuggestions() – zwraca wszystkie sugestie z bazy danych
Przystępujemy do napisania wtyczki. Nie będzie ona bardzo rozbudowana więc cały kod spokojnie zmieści się w pliku głównym rozszerzenia.
W pierwszej kolejności dołączamy napisany przed chwilą model.
1 2 |
define('SUGGESTION_BOX_PATH', plugin_dir_path(__FILE__)); require_once SUGGESTION_BOX_PATH.'includes/SuggestionBox.php'; |
Następnie dodajemy funkcje, które będą uruchamiane podczas włączania i wyłączania wtyczki. Ich zadaniem będzie tworzenie i usuwanie tabeli w bazie danych.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/** * Activate plugin - create DB table */ register_activation_hook(__FILE__, 'activateSuggestionBox'); function activateSuggestionBox() { $suggestionBox = new SuggestionBox(); $suggestionBox->createTable(); } /** * Deactivate plugin - remove DB table */ register_deactivation_hook(__FILE__, 'deactivateSuggestionBox'); function deactivateSuggestionBox() { $suggestionBox = new SuggestionBox(); $suggestionBox->removeTable(); } |
Po włączeniu plugin-u w systemie widzimy, że nowa tabela została utworzona automatycznie w bazie danych.
Utwórzmy funkcję odpowiedzialną za wyświetlanie formularza dla użytkownika.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/** * Generate sugestion box form */ function suggestionBoxForm() { echo '<form method="post" action="'.esc_url($_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']).'">'; echo '<p>'; echo __('Name', 'suggestions-box').':<br />'; echo '<input type="text" name="user_name" value="'.((isset($_POST['user_name']) && !empty($_POST['user_name'])) ? $_POST['user_name'] : '').'" />'; echo '</p>'; echo '<p>'; echo __('E-mail', 'suggestions-box').':<br />'; echo '<input type="text" name="user_email" value="'.((isset($_POST['user_email']) && !empty($_POST['user_email'])) ? $_POST['user_email'] : '').'" />'; echo '</p>'; echo '<p>'; echo __('Suggestion', 'suggestions-box').': <span class="suggestion-box-asterisk">*</span><br />'; echo '<textarea name="user_suggestion"></textarea>'; echo '</p>'; echo '<input type="submit" value="'.__('Send suggestion', 'suggestions-box').'" name="suggestion_sent" />'; echo '</form>'; } |
Jak widać jest to zwykły kod HTML formularza, wyświetlającego na ekranie 3 pola do uzupełnienia przez użytkownika: imię, email oraz sugestię. Dane te, wraz z aktualną datą będą zapisywane do bazy danych.
Teraz napiszmy funkcję obsługującą formularz. Jej zadaniem będzie przechwycenie danych wysyłanych przez użytkownika, przeprowadzenie podstawowej walidacji (pole sugestii musi być uzupełnione) oraz zapisanie danych w tabeli.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/** * Handle suggestion request and response */ function suggestionBoxResponse() { if(isset($_POST['suggestion_sent'])) { $suggestion = trim(sanitize_text_field($_POST['user_suggestion'])); if(empty($suggestion)) { echo '<span class="suggestion-box-error">'.__('Suggestion field cannot be empty.', 'suggestions-box').'</span>'; return; } $name = sanitize_text_field($_POST['user_name']); $email = sanitize_email($_POST['user_email']); $suggestionBox = new SuggestionBox(); $suggestionBox->addSuggestion(array( 'name' => $name, 'email' => $email, 'suggestion' => $suggestion )); echo '<span class="suggestion-box-ok">'.__('Thank you for sending suggestion.', 'suggestions-box').'</span>'; $_POST = array(); } } |
Jeżeli pole sugestii nie zostało uzupełnione, użytkownik zobaczy komunikat błędu, natomiast jeżeli wszystko jest ok, to wpis zostanie dodany, dane formularza wyczyszczone, a użytkownik zobaczy potwierdzenie.
Jak widać w powyższych funkcjach, w miejscach które łączę się z bazą, wykorzystuje wcześniej napisany model. Jak widać wykorzystuję również funkcję __(), wszędzie tam gdzie wypisuje jakiekolwiek informacje dla użytkownika. Funkcja ta zwraca tekst automatycznie przetłumaczony przez system zgodnie z ustawieniami języka. Będzie ona przydatna w przyszłości, gdy wpadnę na pomysł wprowadzenia kilku wersji językowych.
Mamy już wszystkie potrzebne funkcje, dodajmy jeszcze style css, które odpowiednio zmienią wygląd niektórych elementów formularza. Utwórzmy nowy katalog css, a w nim plik style.css. Następnie do kodu wtyczki dopiszmy hook akcji i funkcję, których zadaniem będzie dodanie styli do nagłówka strony.
1 2 3 4 5 6 7 8 |
/** * Add style css file */ add_action('wp_enqueue_scripts', 'suggestionBoxStyle'); function suggestionBoxStyle() { wp_enqueue_style('suggestion-box-style', esc_url(plugins_url('suggestions-box/css/style.css', SUGGESTION_BOX_PATH)), array(), '1.0', 'all'); } |
Na uwagę zasługuje funkcja wp_enqueue_style, która przyjmuje kilka parametrów:
- nazwa identyfikująca styl
- ścieżka do pliku css
- tablica zależności
- wersja
- media, np. screen, print, All
W podobny sposób można dodać do strony dowolny skrypt JavaScript, wykorzystując funkcję wp_enqueue_script.
Ostatnim krokiem jest zebranie powyżej napisanych funkcji do kupy i pokazanie wstawienie formularza w wybrane miejsce na stronie. W tym celu dodam hook shortcode (nie był wcześniej wspomniany), którego zadaniem jest przypisanie wyniku wskazanej funkcji do specjalnego tagu, który później można użyć na dowolnej stronie.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/** * Shortcode */ function suggestionBoxShortcode() { ob_start(); suggestionBoxResponse(); suggestionBoxForm(); return ob_get_clean(); } add_shortcode('suggestionBox', 'suggestionBoxShortcode'); |
Powyższy kod łączy napisane wcześniej funkcje w jedną, dostępną pod Tagiem suggestionBox. Teraz wystarczy wybrać stronę, na której chcemy pokazać formularz i gotowe.
Po wejściu na wybraną stronę, pojawia się nasz formularz.
Oczywiście należy przetestować działanie nowo powstałej wtyczki. Po poprawnym wypełnieniu formularza, powinien pojawić się komunikat potwierdzający wysłanie wiadomości, a wpis powinien zostać dodany do tabeli.
Po wysłaniu:
A tak wygląda formularz, w przypadku gdy nie wypełnimy pola sugestii:
Jak widać po wysłaniu niepoprawnie wypełnionego formularza, wypełnione dane nie znikają, mimo przeładowania strony.
Panel administratora
Na sam koniec zostało stworzenie strony administratora, która będzie pokazywała listę wszystkich sugestii zapisanych w bazie danych.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
/** * Admin page */ add_action('admin_menu', 'suggestionBoxAdminMenu'); function suggestionBoxAdminMenu() { add_menu_page('User Suggestions', 'Suggestion Box', 'administrator', 'user-suggestions', 'suggestionBoxAdminPage', 'dishicons-admin-post'); } function suggestionBoxAdminPage() { echo '<div class="wrap">'; echo '<h2>'.__('User Suggestions', 'suggestions-box').'</h2>'; $suggestionBox = new SuggestionBox(); $suggestions = $suggestionBox->getAllSuggestions(); if(!empty($suggestions)) { echo '<table class="wp-list-table widefat fixed posts">'; echo '<thead>'; echo '<tr>'; echo '<th>ID</th>'; echo '<th>'.__('Date', 'suggestions-box').'</th>'; echo '<th>'.__('Name', 'suggestions-box').'</th>'; echo '<th>'.__('E-mail', 'suggestions-box').'</th>'; echo '<th>'.__('Suggestion', 'suggestions-box').'</th>'; echo '</tr>'; echo '</thead>'; echo '<tbody id="the-list">'; foreach($suggestions as $suggestion) { echo '<tr>'; echo '<td>'.$suggestion['id'].'</td>'; echo '<td>'.$suggestion['date'].'</td>'; echo '<td>'.$suggestion['name'].'</td>'; echo '<td>'.$suggestion['email'].'</td>'; echo '<td>'.$suggestion['suggestion'].'</td>'; echo '</tr>'; } echo '</tbody>'; echo '</table>'; } else { echo __('No suggestions sent', 'suggestions-box'); } echo '</div>'; } |
W pierwszej kolejności dodajemy hook akcji do nawigacji administratora. Wykorzystujemy funkcję add_menu_page, której zadaniem jest dodanie nowego odnośnika do paska nawigacji oraz podpięcie wskazanej funkcji odpowiedzialnej za wyświetlenie zawartości tej utworzonej strony. Funkcja ta pobiera wszystkie wpisy z bazy danych i wyświetla je w postaci tabeli.
Podsumowanie
W tym artykule starałem się przedstawić sposób działania wtyczek oraz pokazałem praktyczne wykorzystanie API WordPress-a do stworzenia swojego własnego rozszerzenia. Jak widać nie jest to szczególnie trudne zadanie. Oczywiście omówiony przykład można na różne sposoby rozszerzyć, np. rozbudować panel admina o możliwość sortowania i usuwania wpisów, rozszerzyć formularz o dodatkowe pola, dopisać wysyłanie danych asynchronicznie lub lepiej napisać walidacje przesyłanych danych.
Opisane funkcje stanowią jedynie ułamek możliwości, jakie niesie ze sobą ten CMS. Przy pomocy hook-ów i funkcji jakie dostarcza, można tworzyć naprawdę rozbudowane aplikacje. Oczywiście wymaga to o wiele lepszej organizacji kodu oraz dogłębne zapoznanie się z dokumentacją.
Zachęcam do nauki tworzenia własnych wtyczek. Nigdy nie wiadomo, kiedy taka umiejętność może nam się przydać. Pozdrawiam wszystkich czytających i oczywiście proszę o komentarze.