W drugiej części kursu „Tworzenie wtyczek WordPress” dodamy niestandardowe pola (miejsce, data i czas wydarzenia). Zarejestrujemy również nowy widget, który będzie wyświetlał wydarzenia.

Niestandardowe pola

W poprzedniej części kursu utworzyliśmy nowy typ postów – Events. Właśnie tam będziemy dodawać nowe wydarzenia. Pojawia się jednak pewien problem. Jeśli spróbujesz teraz dodać nowe wydarzenie, to zauważysz, że zwyczajnie nie mamy gdzie dodać informacji takich jak miejsce wydarzenia, data i czas.

Na szczęście WordPress umożliwia nam prosty sposób na dodanie potrzebnych pól. Przejdźmy do pliku menu.php i dodajmy nowy parametr do funkcji register_post_type():

function devcorner_events_create_posttype()
{
  register_post_type( 'events',
        array(
            'labels' => array(
                'name' => __( 'Events' ),
                'singular_name' => __( 'Event' )
            ),
            'public' => true,
            'has_archive' => true,
            //'rewrite' => array('slug' => 'events'),
            'supports' => array( 'title', 'editor', 'excerpt' ),
            'register_meta_box_cb' => 'devcorner_events_metaboxes' // ten parametr został dodany
        )
    );
}

Dodaliśmy parametr register_meta_box_cb, który wskazuje funkcję dodającą nowe pola (devcorner_events_metaboxes). Tę funkcję musimy teraz utworzyć na końcu pliku:

function devcorner_events_metaboxes()
{
  add_meta_box('devcorner_events_location', 'Event Location', 'devcorner_events_location', 'events', 'normal', 'default');
  add_meta_box('devcorner_events_date', 'Event Date', 'devcorner_events_date', 'events', 'side', 'default');
  add_meta_box('devcorner_events_time', 'Event Time', 'devcorner_events_time', 'events', 'side', 'default');
}

Wewnątrz funkcji devcorner_events_metaboxes() trzykrotnie używamy funkcji add_meta_box(). Znaczenie parametrów wyjaśnię na przykładzie pierwszej z nich:

  • devcorner_events_location – ID boxa
  • Event Location – tytuł, który jest wyświetlany nad inputem.
  • devcorner_events_location – funkcja, która wyświetla zawartość boxa.
  • events – typ posta, do którego dodajemy box
  • normal – umieszcza box pod edytorem (side umieszcza go w bocznym panelu)
  • default – priorytet pozycji boxa (high/low/default)

Zapisz plik i spróbuj dodać nowe wydarzenie:

add-meta-box

Jak widzisz, boxy są już na miejscu.Wyświetlają jednak ostrzeżenie „Warning: call_user_func() expects parameter 1 to be a valid callback, function ‚devcorner_events_date’ not found or invalid function name”.

Musimy oczywiście dodać funkcje podane w trzecim parametrze funkcji add_meta_box(). To one odpowiadają za zawartość utworzonych boxów. Są to kolejno: devcorner_events_locationdevcorner_events_datedevcorner_events_time. Dodajmy je w menu.php:

function devcorner_events_location()
{
   global $post;
   $value = get_post_meta($post->ID, '_location', true);
   echo '<input type="text" name="_location" value="' . $value  . '" class="widefat" />';
}

function devcorner_events_date()
{
   global $post;
   $value = get_post_meta($post->ID, '_date', true);
   echo '<input type="date" name="_date" value="' . $value  . '" class="widefat" />';
}

function devcorner_events_time()
{
   global $post;
   $value = get_post_meta($post->ID, '_time', true);
   echo '<input type="time" name="_time" value="' . $value  . '" class="widefat" />';

   wp_nonce_field( plugin_basename(__FILE__), 'eventmeta_field' );
}

Wszystkie funkcje wyglądają bardzo podobnie. Do zmiennej $value trafia wartość zwrócona przez funkcję get_post_meta(). Jak sama nazwa wskazuje, ta funkcja pobiera dane meta z posta. Pierwszym parametrem jest ID wpisu. Drugim klucz (nazwa inputa). Trzeci parametr ustawiony na true pozwala nam zwrócić wartość. W skrócie: do zmiennej $value trafia miejsce/data/czas wydarzenia.

Następnie wyświetlamy pola input o type zależnym od typu pola (lokalizacja -> text, data -> date, czas -> time). W value umieszczamy zawartość utworzonej wcześniej zmiennej. Dzięki temu użytkownik zawsze będzie znał aktualnie ustawione dane. Klasa widefat jest zdefiniowana przez WordPressa i umożliwia nam ujednolicenie stylów w panelu administratora.

Wewnątrz funkcji devcorner_events_time() umieszczona jest dodatkowa funkcja – wp_nonce_field(). Tworzy ona ukryty input, który pozwala nam upewnić się, że żądanie zapisu pochodzi z obecnej strony. Korzystanie z tego zabezpieczenia jest bardzo ważne. Zabezpieczenie obejmie wszystkie pola, a nie tylko _time.

Jeśli spróbujesz dodać teraz nowe wydarzenie, to zobaczysz, że pola wyświetlają się już poprawnie. Możesz dodać do nich przykładowe dane i opublikować wydarzenie.

opublikuj post

Wydarzenie zostało opublikowane, ale nasze 3 pola są puste. Jest tak dlatego, ponieważ WordPress nie zapisuje domyślnie wszystkich meta boxów. Musimy napisać funkcję zapisującą, aby wartości nowych pól były umieszczane w bazie danych podczas publikacji/aktualizacji wydarzenia. Zróbmy to poniżej:

function devcorner_events_save_meta($post_id, $post)
{
	if (isset($_POST['eventmeta_field'])) {

		// sprawdzamy upoważnienie do zapisania danych
		if (!wp_verify_nonce($_POST['eventmeta_field'], plugin_basename(__FILE__))) {
			return $post->ID;
		}

		// upewniamy się, że użytkownik może edytować post
		if (!current_user_can('edit_post', $post->ID)) return $post->ID;

		// dodajemy wartości do tablicy
		$events_meta['_location'] = $_POST['_location'];
		$events_meta['_date'] = $_POST['_date'];
		$events_meta['_time'] = $_POST['_time'];

		foreach($events_meta as $key => $value) { // pętla przechodząca przez tablicę
			if ($post->post_type == 'revision') return; // unikamy podwójnego zapisania
			if (get_post_meta($post->ID, $key, FALSE)) { // jeśli pole posiada już wartość, to aktualizujemy
				update_post_meta($post->ID, $key, $value);
			}
			else { // jeśli pole nie posiada wartości, to tworzymy
				add_post_meta($post->ID, $key, $value);
			}

			if (!$value) delete_post_meta($post->ID, $key); // jeśli wartość jest pusta, to usuwamy pole
		}
	}
}

add_action('save_post', 'devcorner_events_save_meta', 1, 2);

Poszczególne części funkcji są opisane komentarzami. W skrócie funkcja devcorner_events_save_meta() dzieli się na 3 części:

  • zabezpieczenie
  • dodanie do tablicy danych wprowadzonych przed użytkownika
  • pętla, która przechodzi przez tablicę i aktualizuje/dodaje wartości do bazy danych

Na końcu standardowo dodajemy nową akcję i podpinamy ją pod akcję save_post (wykonuje się podczas zapisywania postów). Warto zaznaczyć, że dodajemy tutaj 2 opcjonalne parametry. Jest to priorytet (niższe numery oznaczają wcześniejsze wywołanie funkcji) i ilość przyjmowanych przez funkcję argumentów.

Możesz teraz zapisać plik i sprawdzić działanie kodu dodając nowe wydarzenie:

dzialajacy zapis

Tym razem wszystko działa już poprawnie. Wartości nie znikają po odświeżeniu, co oznacza, że są pobierane z bazy danych. Możemy je też dowolnie modyfikować i zapisywać.

Tworzenie widgetu

Widgety umożliwiają dodawanie treści do sidebarów. Można nimi zarządzać w menu Wygląd -> Widgety.

widgety

Tak wygląda sekcja widgetów w motywie Shapely. Skorzystamy z sekcji Sidebar, w której obecnie znajduje się 6 widgetów. Możesz je teraz usunąć, nie będą nam potrzebne.

Zajmijmy się teraz utworzeniem nowego widgetu. Za jego pomocą wyświetlimy listę wydarzeń. Stwórzmy nowy plik wewnątrz katalogu includes o nazwie widget.php. Możemy go od razu podpiąć do głównego pliku devcorner-events.php:

include_once( plugin_dir_path( __FILE__ ) . 'includes/widget.php');

Wewnątrz pliku widget.php umieścimy kod:

<?php
class Devcorner_Events_Widget extends WP_Widget
{
	function __construct()
	{
		parent::__construct('devcorner_events_widget', 'Devcorner Events', array(
			'description' => 'Widget pokazuje zaplanowane wydarzenia.'
		));
	}

	function widget($args, $instance)
	{
		echo $args['before_widget'];
		$title = apply_filters('widget_title', $instance['title']);
		echo $args['before_title'] . $title . $args['after_title'];
		echo $args['after_widget'];
	}

	function form($instance)
	{
		$defaults = array(
			'title' => 'Events'
		);
		$instance = wp_parse_args((array)$instance, $defaults);
   ?>

      <p>
        <label for="title">Tytuł</label>
        <input type="text" id="<?php
      		echo $this->get_field_id('title'); ?>" name="<?php
      		echo $this->get_field_name('title'); ?>" value="<?php
      		echo $instance['title']; ?>"/>
      </p>

  <?php
	}

	function update($new_instance, $old_instance)
	{
		$instance = $old_instance;
		$instance['title'] = strip_tags($new_instance['title']);
		return $instance;
	}
}

function devcorner_events_load_widget()
{
	register_widget('devcorner_events_widget');
}

add_action('widgets_init', 'devcorner_events_load_widget');

Widgety tworzymy poprzez dodanie klasy Devcorner_Events_Widget rozszerzającej (obowiązkowo) klasę WP_Widget. Przyjrzyjmy się teraz kolejnym metodom wewnątrz klasy:

1. __construct() – unikalne id widgetu pisane małymi literami

2. widget() – wewnątrz tej funkcji generujemy strukturę, którą zobaczy użytkownik. Funkcja posiada dwa parametry. Pierwszym z nich jest $args – tablica zdefiniowana przez motyw, która zawiera elementy takie jak: before_widget (elementy HTML umieszczane przed widgetem np. div z określoną klasą), after_title (element umieszczony po tytule np. zamknięcie nagłówka) itd.

Musimy pamiętać, że często plugin będzie musiał działać pod różnymi motywami. Każdy z nich może wyświetlać widgety w nieco inny sposób. Dlatego zawsze warto korzystać z elementów dostarczanych przez tablicę $args.

Drugim parametrem funkcji widget() jest $instance, czyli tablica zawierająca opcje widgetu np. tytuł.

Na ten moment wyświetlamy tylko kilka tagów i tytuł. W kolejnej części kursu wrócimy do tej funkcji, aby wyświetlić wydarzenia.

3. form() – ta funkcja tworzy zawartość widoczną dla admina w panelu widgetów. Funkcja wp_parse_args() scala dynamicznie generowaną tablicę $instance z ustawieniami domyślnymi (w naszym przypadku tylko tytuł ustawiony na Events).

Poniżej generujemy jeden input. Atrybuty id i name są generowane przez WordPressa i tylko je wyświetlamy. Wewnątrz value dodajemy aktualny tytuł. Dzięki temu użytkownik będzie zawsze znał wartość tego pola.

4. update() – ta funkcja zostaje wywołana podczas zapisywania danych wprowadzonych do widgetu. Tablica $new_instance zawiera nowe opcje, a $old_instance stare. Aktualizujemy tytuł (usuwając wcześniej tagi HTML/PHP przy użyciu strip_tags()) i zwracamy tablicę z opcjami.

Następnie tworzymy funkcję devcorner_events_load_widget(), która rejestruje widget. Parametrem funkcji register_widget() jest klasa tworząca widget.

Standardowo add_action() pozwala nam podpiąć utworzoną funkcję pod odpowiednią akcję. W przypadku rejestrowania widgetów jest to widgets_init.

Przejdźmy teraz do panelu widgetów aby upewnić się, że wszystko zadziałało poprawnie:

widget

W sidebarze na stronie głównej możemy teraz podejrzeć widget.

widget front

W tym momencie jest to tylko tytuł ustawiony w opcjach, ale w kolejnej części kursu umieścimy tutaj wydarzenia. Dodamy również stronę ustawień i będziemy kontynuować pracę nad wtyczką.

Pobierz paczkę z wtyczką >>

Bądź pierwszą osobą, która skomentuje ten wpis.