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: