WordPress widget tutorial – piszemy własny widget, witajcie w drugiej części kursu dla początkujących dotyczącego tworzenia widgetów dla WordPress zupełnie od zera.
W części pierwszej tego kursu przygotowaliśmy środowisko do śledzenia postępów, utworzyliśmy klasę rozszerzającą WordPressową klasę bazową – WP_Widget, nadaliśmy unikalny identyfikator, nazwę i opis, oraz go zainicjowaliśmy tak by był widoczny z poziomu kokpitu.
Część 2 – WordPress widget tutorial – piszemy własny widget
W tej części zajmiemy się formularzem widget-u (backend-em), dzięki któremu możliwe będzie sterowanie widget-em z poziomu kokpitu. A przesłane opcje, walidować i zapisywać w bazie danych.
Produktem tego kursu będzie prosty widget wyświetlający najnowsze wpisy na blogu, zupełnie tak jak ten wbudowany w WordPress, ale nasz będzie miał trochę więcej opcji:
- możliwość wyboru kategorii
- opcja wyświetlenia wypisu
- ustawienie długości wypisu
- możliwość wyświetlania miniatur wpisu
Wstępne zapisywanie opcji widget-u w bazie WordPress
Dla ułatwienia sobie zadania, zanim zaczniemy pisać formularz z opcjami do widget-u możemy przedtem nieco zmodyfikować metodę klasy naszego widgetu, tak by od razu zapisywała wszystkie przesłane dane w bazie danych.
Otwieramy plik z ostatnio utworzoną klasą i przechodzimy do metody update()
i zamieniamy ją na:
public function update( $new_instance, $old_instance ) { return $new_instance; }
Jak to działa? W skrócie mówiąc, funkcja powinna zwracać tablicę asocjacyjną zawierającą już sprawdzone dane (opcje widgetu), które następnie są przez WordPress serializowane i zapisywane w bazie pod identyfikatorem widget-u.
Jako developerzy widget-ów, wiemy jakie niebezpieczeństwa mogą wiązać się z brakiem walidacji danych pobranych od użytkowników, ale nam w tym momencie chodzi tylko o to, by sprawdzać, czy pola dodawane do formularza są dobrze skonstruowane i czy będą później zaznaczać zapisane opcje, a samą walidacją zajmiemy się na końcu tej części kursu.
Dodajemy pola do formularza widget-u
Przechodzimy teraz do funkcji form()
, w której dodawać będziemy kolejne pola do formularza widget-u.
Zacznijmy od dodania pola nadającego nagłówek (nazwę) widget-u:
Na początku funkcji dodajemy linijkę:
$instance = wp_parse_args( (array) $instance, array( 'title' => 'Najnowsze Posty' ) );
Jak zapewne zauważyłeś metoda form()
przyjmuje jeden argument $instance
. W nim znajduje się tablica asocjacyjna z ustawieniami widgetu pobranymi z bazy danych. Teraz ta zmienna jest pusta.
Dodanie tej linijki sprawia, że w przypadku braku którejś opcji w bazie (jak teraz), do zmiennej $instance
zostaną dodane opcje domyślne, które definiujemy właśnie w tym miejscu. Jeżeli mielibyśmy w bazie zapisane już jakieś informacje, to domyślne dane zostaną nadpisane tymi z bazy.
W tym przypadku ustawiamy title na Najnowsze Posty, czyli zawsze, gdy w bazie będzie brakowało tej zmiennej, wyświetlony zostanie ciąg Najnowsze Posty.
I wreszcie, dodajemy kod html, uzupełniony o specjalne funkcje WordPress-a, dzięki którym pole formularza będzie zapisywać wartość opcji pod właściwym identyfikatorem, i później uzupełniać te pole zapisaną wartością z bazy danych:
<p> <!-- Widgets name --> <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($instance['title']); ?>" /> </p>
O ile etykieta (label) nie jest tutaj bardzo ważna, to musimy dokładnie przyjrzeć się w jaki sposób mamy nazwać pole input, oraz jak nadać mu wartość.
Myślę, że w tym momencie jest już w miarę jasne o co chodzi, dlatego nie będę opisywał każdego pola z osobna, tylko pokaże jak teraz wygląda mój pełny formularz:
public function form( $instance ) { //ustawiamy opcje domyslne $my_defaults = array( 'number' => 5, 'title' => 'Najnowsze Posty', 'categories' => array(), 'show_excerpt' => false, 'excerpt_length' => 200, 'show_thumbnail' => false ); //uzupelniamy opcje zapisane w bazie o opcje domyslne $instance = wp_parse_args( (array) $instance, $my_defaults ); ?> <p> <!-- Widgets name --> <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($instance['title']); ?>" /> </p> <p> <!-- Number of posts to show --> <label for="<?php echo $this->get_field_id( 'number' ); ?>"><?php _e( 'Number of posts to show:' ); ?></label> <input id="<?php echo $this->get_field_id( 'number' ); ?>" name="<?php echo $this->get_field_name( 'number' ); ?>" type="text" value="<?php echo $instance['number']; ?>" size="3" /> </p> <p> <!-- Get and display Categories checkbox options --> <label><?php _e('Categories:'); ?></label><br /> <?php $categories_list = get_categories('hide_empty=0&orderby=name'); foreach ($categories_list as $cat ): $cat_id = intval($cat->cat_ID); $cat_name = $cat->cat_name; $selected = ''; if(in_array($cat_id, $instance['categories'])) $selected=' checked="checked"'; ?> <input value="<?php echo $cat_id; ?>" class="radio" type="checkbox"<?php echo $selected; ?> id="<?php echo $this->get_field_id('categories'); echo $cat_id; ?>" name="<?php echo $this->get_field_name('categories'); ?>[]" /> <label for="<?php echo $this->get_field_id('categories'); echo $cat_id; ?>"><?php echo $cat_name; ?></label><br /> <?php endforeach; ?> </p> <p> <!-- Show excerpt --> <input class="checkbox" type="checkbox" name="<?php echo $this->get_field_name('show_excerpt'); ?>" id="<?php echo $this->get_field_id('show_excerpt'); ?>" value="true" <?php checked(true, $instance['show_excerpt']);?> /> <label for="<?php echo $this->get_field_id('show_excerpt'); ?>"> <?php _e( 'Display post excerpt' ); ?></label><br /> </p> <p> <!-- Excerpt length --> <label for="<?php echo $this->get_field_id( 'excerpt_length' ); ?>"><?php _e( 'Excerpt length:' ); ?></label> <input id="<?php echo $this->get_field_id( 'excerpt_length' ); ?>" name="<?php echo $this->get_field_name( 'excerpt_length' ); ?>" type="text" value="<?php echo $instance['excerpt_length']; ?>" size="5" /> </p> <p> <!-- Show excerpt --> <input class="checkbox" type="checkbox" name="<?php echo $this->get_field_name('show_thumbnail'); ?>" id="<?php echo $this->get_field_id('show_thumbnail'); ?>" value="true" <?php checked(true, $instance['show_thumbnail']);?> /> <label for="<?php echo $this->get_field_id('show_thumbnail'); ?>"> <?php _e( 'Display post thumbnail' ); ?></label><br /> </p> <?php }
Jeżeli brakuje wam jakiegoś pola i nie za bardzo wiecie jak ma wyglądać jego kod, czy jakie klasy dodać do tych pól, to bardzo dobrym źródłem wiedzy jest kod widgetów wbudowanych w WordPress. Plik z domyślnymi widgetami znajdziecie w katalogu wp-includes/default-widgets.php
, albo tutaj online. Można też sprawdzić widgety dodawane do innych motywów, albo pobrać z repozytorium WordPress-a w postaci pluginów, jest tego mnóstwo.
Listę checkbox można łatwo zamienić na pola typu radio – wystarczy zmienić typ input-ów na radio
– teraz zamiast listy wielokrotnego wyboru, otrzymamy listę z jedną opcją do wyboru.
Walidacja opcji widget-u i zapis w bazie WordPress
Ostatnią rzeczą, którą musimy się jeszcze zająć w tej części to walidacja przesłanych przez formularz opcji, ewentualna ich obróbka i zapis (uaktualnienie) w bazie danych. Spójrz na mój końcowy kod:
public function update( $new_instance, $old_instance ) { $instance = $old_instance; //tytul widgetu $instance['title'] = strip_tags($new_instance['title']); //ilosc wyswietlanych postow $instance['number'] = absint($new_instance['number']); //zaznaczone kategorie $instance['categories'] = (array) $new_instance['categories']; //czy pokazac wypis $instance['show_excerpt'] = isset($new_instance['show_excerpt']); //dlugosc wypisu $instance['excerpt_length'] = absint($new_instance['excerpt_length']); //czy pokazac miniaturke wpisu $instance['show_thumbnail'] = isset($new_instance['show_thumbnail']); return $instance; }
Sposób działania tej metody jest dosyć prosty – w argumentach podawane są dwie tablice asocjacyjne:
$new_instance
– jest to tablica nowych, właśnie przesłanych przez formularz opcji;$old_instance
, to tablica opcji aktualnie zapisanych w bazie danych.
A sama metoda powinna zwrócić kombinację tych dwóch tablic – przede wszystkim nowo-przesłane opcje, uzupełnione o stare, jeżeli nowe opcje nie będą spełniały stawianych im wymagań.
Nawet dla tych kilku opcji, metoda walidująca wprowadzone dane wydaje się być strasznie krótka, prawda? Myślę, że wytłumaczyć to można w ten sposób, że administracja widgetami należy do administratora witryny i jest raczej mało prawdopodobne, aby admin próbował sabotować własną witrynę. Dlatego mamy tutaj taką prostą, podstawową walidację.
Nie ma tutaj dużej filozofii, z pól tekstowych czyścimy wszelkie tagi, dla liczb całkowitych używamy funkcji absint()
, która zwróci 0, jeżeli liczba jest ujemna i/lub niecałkowita. Dla pól typu checkbox, sprawdzamy tylko czy pole jest ustawione.
Oczywiście można bawić się w dodatkowe „ify” i „regexy”, sprawdzać czy np. łańcuch jest pusty i ewentualnie wstawiać starą wartość, ale patrząc z przedstawionej wcześniej perspektywy nie ma to większego sensu.
Pełny kod:
<?php class Najnowsze_Posty extends WP_Widget { /** * Sets up the widgets name etc */ public function __construct() { $widget_id = 'najnowsze_posty'; $widget_name = __('Najnowsze Posty', 'NajnowszePosty'); $widget_opt = array('description'=>'Ten widget wyświetla najnowsze posty.'); parent::__construct($widget_id, $widget_name, $widget_opt); } /** * Outputs the content of the widget * * @param array $args * @param array $instance */ public function widget( $args, $instance ) { // outputs the content of the widget } /** * Outputs the options form on admin * * @param array $instance The widget options */ public function form( $instance ) { //ustawiamy opcje domyslne $my_defaults = array( 'number' => 5, 'title' => 'Najnowsze Posty', 'categories' => array(), 'show_excerpt' => false, 'excerpt_length' => 200, 'show_thumbnail' => false ); //uzupelniamy opcje zapisane w bazie o opcje domyslne $instance = wp_parse_args( (array) $instance, $my_defaults ); ?> <p> <!-- Widgets name --> <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($instance['title']); ?>" /> </p> <p> <!-- Number of posts to show --> <label for="<?php echo $this->get_field_id( 'number' ); ?>"><?php _e( 'Number of posts to show:' ); ?></label> <input id="<?php echo $this->get_field_id( 'number' ); ?>" name="<?php echo $this->get_field_name( 'number' ); ?>" type="text" value="<?php echo $instance['number']; ?>" size="3" /> </p> <p> <!-- Get and display Categories checkbox options --> <label><?php _e('Categories:'); ?></label><br /> <?php $categories_list = get_categories('hide_empty=0&orderby=name'); foreach ($categories_list as $cat ): $cat_id = intval($cat->cat_ID); $cat_name = $cat->cat_name; $selected = ''; if(in_array($cat_id, $instance['categories'])) $selected=' checked="checked"'; ?> <input value="<?php echo $cat_id; ?>" class="radio" type="checkbox"<?php echo $selected; ?> id="<?php echo $this->get_field_id('categories'); echo $cat_id; ?>" name="<?php echo $this->get_field_name('categories'); ?>[]" /> <label for="<?php echo $this->get_field_id('categories'); echo $cat_id; ?>"><?php echo $cat_name; ?></label><br /> <?php endforeach; ?> </p> <p> <!-- Show excerpt --> <input class="checkbox" type="checkbox" name="<?php echo $this->get_field_name('show_excerpt'); ?>" id="<?php echo $this->get_field_id('show_excerpt'); ?>" value="true" <?php checked(true, $instance['show_excerpt']);?> /> <label for="<?php echo $this->get_field_id('show_excerpt'); ?>"> <?php _e( 'Display post excerpt' ); ?></label><br /> </p> <p> <!-- Excerpt length --> <label for="<?php echo $this->get_field_id( 'excerpt_length' ); ?>"><?php _e( 'Excerpt length:' ); ?></label> <input id="<?php echo $this->get_field_id( 'excerpt_length' ); ?>" name="<?php echo $this->get_field_name( 'excerpt_length' ); ?>" type="text" value="<?php echo $instance['excerpt_length']; ?>" size="5" /> </p> <p> <!-- Show excerpt --> <input class="checkbox" type="checkbox" name="<?php echo $this->get_field_name('show_thumbnail'); ?>" id="<?php echo $this->get_field_id('show_thumbnail'); ?>" value="true" <?php checked(true, $instance['show_thumbnail']);?> /> <label for="<?php echo $this->get_field_id('show_thumbnail'); ?>"> <?php _e( 'Display post thumbnail' ); ?></label><br /> </p> <?php } /** * Processing widget options on save * * @param array $new_instance The new options * @param array $old_instance The previous options */ public function update( $new_instance, $old_instance ) { $instance = $old_instance; //tytul widgetu $instance['title'] = strip_tags($new_instance['title']); //ilosc wyswietlanych postow $instance['number'] = absint($new_instance['number']); //zaznaczone kategorie $instance['categories'] = (array) $new_instance['categories']; //czy pokazac wypis $instance['show_excerpt'] = isset($new_instance['show_excerpt']); //dlugosc wypisu $instance['excerpt_length'] = absint($new_instance['excerpt_length']); //czy pokazac miniaturke wpisu $instance['show_thumbnail'] = isset($new_instance['show_thumbnail']); return $instance; } }
Zakończenie
Po przerobieniu tej części, widget powinien się już ładnie wyświetlać, formularz zarządzający jego opcjami również jest już gotowy: zapisuje i odczytuje z bazy zapisane dane. Efekt widoczny jest na obrazku po lewej.
W kolejnej, ostatniej już części tego kursu, dowiecie się w jaki sposób pobrać z bazy danych posty, oraz jak je wyświetlić uwzględniając wszystkie zapisane opcje.
Już teraz zapraszam na kolejną część kursu WordPress widget tutorial – piszemy własny widget!
Pomogłem? Dodaj coś od siebie! Skomentuj ten wpis: