Ajax i WordPress – Wprowadzenie

Technologia Ajax okazuje się niezwykle przydatna podczas tworzenia motywów i wtyczek dla WordPress. Sprawdzanie błędów w formularzu w czasie rzeczywistym, wczytywanie nowych postów w tle, to tylko kilka przykładów, możliwości są znacznie większe! Tak naprawdę możemy wykonać dowolną czynność po stronie serwera, i to bez ponownego ładowania strony! Warto się więc zapoznać z tą technologią. Nasze wtyczki będą nie tylko bardziej “bajeranckie” ale również bardziej użyteczne dla ich użytkowników. :)

 

Jak to działa…

Na samym początku prześledźmy jak wygląda cały proces wysyłania i odbierania zapytania Ajax na platformie WordPress.
Na samym początku wysyłamy zapytanie za pomocą jQuery(funkcja .post() ) do pliku admin-ajax.php. Jest to plik który zajmuje się obsługą wszystkich zapytań Ajax, znajduje się on w katalogu /wp-admin. Gdy plik ten odbierze żądanie, wywołuje dwa zaczepy:

  • wp_ajax_action  ->  kiedy użytkownik jest zalogowany
  • wp_ajax_nonpriv_action  ->  kiedy użytkownik nie jest zalogowany

Zauważ, że nazwa zaczepu definiowana jest za pomocą wysłanego przez nas parametru action. Jest to parametr który służy do identyfikacji naszego zapytania(więc musi być on unikalny!). Jeśli więc parametr ten będzie się nazywał pobierz_wpisy, wtedy nasze zaczepy będą się nazywały:

  • wp_ajax_pobierz_wpisy  ->  dla zalogowanych użytkowników)
  • wp_ajax_nopriv_pobierz_wpisy  ->  dla niezalogowanych użytkowników).

Za pomocą tych zaczepów, wywołujemy dowolną funkcję w php. Na końcu takiej funkcji powinniśmy wysłać odpowiedź zwrotną, którą odbierzemy po stronie klienta.

Najprostszy praktyczny przykład

Załóżmy, że mamy formularz, za pomocą którego odwiedzający może zarejestrować się w naszym serwisie. Zaraz po tym jak wpisze swoją nazwę użytkownika, chcemy dyskretnie sprawdzić czy przypadkiem nie jest ona już zajęta. Nie będę przedstawiał kodu html i css formularza, chyba każdy wie jak to napisać. :)

Wiemy już, że zapytania Ajax wysyłamy do pliku admin-ajax.php. Będziemy więc potrzebować pełnego adresu url do tego pliku w JavaScript.

Skąd wziąć ten adres?

Statyczne „wklepanie” go np. http://domena.pl/wp-admin/wp-ajax.php odpada – to rozwiązanie będzie działać tylko na naszej witrynie. A co jeśli chcemy udostępnić naszą wtyczkę innym użytkownikom WordPress? Musimy pobrać adres tego pliku dynamicznie, po stronie serwera, a następnie przekazać go do JavaScript. Jak to zrobić? Bardzo prosto, wystarczy użyć funkcji wp_localize_script() która stworzy obiekt JavaScript zawierający parametry podane w php. Najprościej rzecz ujmując funkcja ta pozwala nam udostępnić zmienne z php plikom JavaScript. Warto ją sobie zapamiętać – przydaje się niejednokrotnie!

Oto kod który wczyta bibliotekę jQuery oraz nasz plik w którym wykonamy zapytanie AJAX. Pobierze on także adres do pliku admin-ajax.php za pomocą  oraz udostępni nam go po stronie przeglądarki.

add_action( 'wp_enqueue_scripts', 'jj_enqueue_ajax_scripts');
function jj_enqueue_ajax_scripts(){

	wp_enqueue_script('jquery');

	//nasz plik z którego wyślemy zapytanie
	wp_enqueue_script('ajax-main', plugins_url('/js/main.js' , __FILE__) );

	//ustalamy odpowiedni protokół
	if ( isset($_SERVER['HTTPS']) )
	   $protocol = 'https://';
	else
	   $protocol = 'http://';

   //pobieramy adres do pliku admin-ajax.php
   $admin_ajax_url = admin_url( 'admin-ajax.php', $protocol );

   //za pomocą tej funkcji przekazujemy zmienną zawierająca adres, do javascript
   wp_localize_script( 'ajax-main', 'ajax_options', array('admin_ajax_url' => $admin_ajax_url) );
}

Pierwszym parametrem funkcji wp_localize_script(), jest uchwyt pliku w którym będziemy korzystali ze zmiennej. Ten uchwyt, to inaczej pierwszy parametr funkcji wp_enqueue_script() która, jak pewnie wiesz, służy do wczytywania skryptów w WordPress. Drugi parametr to nazwa obiektu który będzie przechowywał nasze dane w JavaScript. Trzeci argument to tablica zawierająca parametry oraz ich wartości, my podajemy zmienną z adresem pliku admin-ajax.php.

Okej, mamy poprawny adres do pliku obsługującego zapytania Ajax, teraz wystarczy po stronie przeglądarki odwołać się do obiektu i jego parametru(ajax_options.admin_ajax_url).

Przejdźmy do napisania pliku JavaScript który pobierze wpisaną nazwę użytkownika, wyśle zapytanie Ajax, a na końcu odbierze wiadomość zwrotną od serwera.

jQuery(document).ready(function($){

	$( "#username-input" ).focusout(function() {

		var data = {
			action: 'check_username',
			username: $(this).val()
		}

		$.post(ajax_options.admin_ajax_url, data, function(response){

			//kod javascript który wykona się po ptrzymaniu odpoweidzi od serwera

			alert(response); //wyświetlamy odpowiedź
		});

	});

});

Kiedy użytkownik opuszcza pole nazwy użytkownika(event focusout), zaczynamy całą zabawę. Tworzymy obiekt data zawierający dane które chcemy przekazać do serwera. W naszym przypadku jest to obowiązkowy parametr action, oraz nazwa użytkownika.

Następnie używamy funkcji $.post() do wysłania zapytania. Pierwszym parametrem jest adres pliku do którego ma zostać wysłane zapytanie. U nas jest to oczywiście plik admin-ajax.php. Drugim parametrem jest obiekt z danymi(czyli nasz obiekt data). Trzeci parametr to funkcja odbierająca odpowiedź od serwera.

Skoro zapytanie zostało wysłane, pozostaje nam obsłużyć je po stronie serwera. Do głównego pliku naszej wtyczki dodajemy kod:

add_action( 'wp_ajax_nopriv_check_username', 'jj_check_username');
function jj_check_username(){

	$username = $_POST['username'];

	if (username_exists($username)) {
		echo 'Ta nazwa użytkownika jest już zajęta!';
	}else{ 
		echo 'Ta nazwa użytkownika jest wolna!';
	}	

	die();
}

Najpierw podczepiamy się pod zaczep wp_ajax_nopriv_ (ponieważ, chcę aby formularz dział tylko dla nie zalogowanych użytkowników). Tworzymy funkcję jj_check_username, a w niej odbieramy przekazany z JavaScript parametr username(wszystkie dane są w tablicy $_POST). Następnie sprawdzamy za pomocą funkcji username_exist(), czy dana nazwa użytkownika jest zajęta. Używając echo udzielamy stosownej odpowiedzi. Na końcu nie wolno nam zapomnieć o wywołaniu funkcji die(), która jest wymagana do prawidłowego zwrócenia odpowiedzi.

Oczywiście to tylko demonstracyjny kod, który ma na celu pokazać najprostsze użycie Ajax. W prawdziwej sytuacji, jeśli nazwa użytkownika jest wolna, niekoniecznie trzeba o tym informować rejestrującego się, a już na pewno nie za pomocą wkurzającego okienka, wywołanego przez alert() :) Dobra, to był prosty przykład. Teraz pora na coś fajniejszego!

Integracja wtyczki Gridster.js z WordPress

Gridster.js to wtyczka dla jQuery pozwalająca na tworzenie wielokolumnowych układów z tzw. widgetów, które możemy dowolnie przesuwać lub zmieniać ich rozmiar. Wewnątrz widgetów możemy umieścić dowolny kod html. Możemy także zapisać ich aktualne ustawienie i rozmiary. Wybrałem właśnie ten plugin, ponieważ jest niezbyt znany, a może mieć wiele zastosowań. Można za jego pomocą stworzyć np. tzw. „page builder”, które są ostatnio modne w szablonach premium :) Teraz polecę Wam krótko zapoznać się z tym pluginem, sposobem jego działania, oraz jego podstawowymi funkcjami na własną rękę.

Nasz plugin będzie automatycznie zapisywał nowy układ elementów(widgetów) w bazie danych, kiedy tylko któryś z nich zmieni rozmiar czy pozycję.

Zabierajmy się zatem do pracy. Tym razem nasz plugin będzie działał po stronie administracyjnej WordPressa. Stworzymy dla niego osobną stronę w panelu administracyjnym.

Najpierw dodajmy nasze pliki JavaScript i style css.

add_action( 'admin_enqueue_scripts', 'jj_add_gridster_scripts' );
function jj_add_gridster_scripts(){

	wp_enqueue_script( 'jquery' );
	wp_enqueue_script( 'gridster', plugins_url( '/js/jquery.gridster.min.js' , __FILE__ ) );
	wp_enqueue_script( 'main', plugins_url( '/js/main.js' , __FILE__ ) );

	wp_enqueue_style( 'gridster-css', plugins_url( '/css/jquery.gridster.min.css' , __FILE__ ) );

	$grid = get_site_option( 'gridster_order2' );

	wp_localize_script( 'main', 'gridster_options', array( 'grid_order' => $grid ) );
}

Używamy zaczepu admin_enqueue_scripts aby dołączyć pliki tylko na stronach administracyjnych. Dołączamy jQuery, następnie plik jquery.gridster.min.js czyli plugin Gridster.js, a także plik main.js, w którym umieścimy własne skrypty. Dołączamy też domyślne arkusze stylów pluginu, do których dopisałem odrobinę własnych reguł.

Następnie tworzymy zmienną grid do której pobieramy z bazy danych wcześniej zapisane ustawienie widgetów. Następnie przekazujemy ją do JavaScript za pomocą znanej nam już funkcji wp_localize_script(). A co jeśli nie mamy wcześniej zapisanych pozycji widgetów? Tym zajmiemy się już w JavaScript.

Zauważ też, że tym razem nie przekazujemy adresu do pliku admin-ajax.php. Dlaczego? Dlatego, że plugin działa na stronach administracyjnych, gdzie WordPress automatycznie udostępnia globalną zmienną JavaScript o nazwie ajaxurl, która zawiera ten adres i możemy jej używać we wszystkich skryptach. Nie ma więc sensu jeszcze raz go pobierać i przekazywać, skoro jest już to zrobione przez WP.

Teraz stwórzmy stronę administracyjną dla naszego pluginu.

add_action( 'admin_menu', 'register_gridster_page' );
function register_gridster_page(){
	add_menu_page( 'Gridster Demo', 'gridster', 'manage_options', 'gridster_demo', 'jj_display_gridster_page' );
}

function jj_display_gridster_page(){
?>
<h1>Gridster Demo</h1>

<hr />

<div class="gridster">
<ul>
    <li><button class="button delete">X</button></li>
    <li><button class="button delete">X</button></li>
    <li><button class="button delete">X</button></li>
    <li><button class="button delete">X</button></li>
    <li><button class="button delete">X</button></li>
    <li><button class="button delete">X</button></li>
    <li><button class="button delete">X</button></li>
    <li><button class="button delete">X</button></li>
</ul>
</div>
<form id="add-widget-form"><button class="button" id="add-widget" type="submit">Add Widget</button></form>

<?php
}

Funkcji add_menu_page chyba nie muszę przedstawiać, w razie czego odsyłam do dokumentacji. Elementy <li> to widgety gridster-a. Jeśli jeszcze tego nie zrobiłeś zapoznaj się z działaniem tego pluginu. Na końcu znajduje się formularz za pomocą którego będziemy dodawać nowe widgety.

Teraz przejdźmy do edycji pliku main.js, jego kod jest następujący:

jQuery(document).ready(function($){

	var serialization_grid = gridster_options.grid_order;

	var gridster = $(".gridster ul").gridster({
        widget_margins: [7, 7],
        widget_base_dimensions: [120, 120],
        max_cols: 6,
        resize: {
            enabled: true,
            stop: function(event, ui) {
            	jj_save_order();
            }
        },
        draggable: {
        	stop: function(event, ui) {
            	jj_save_order();
            }
        }
    }).data('gridster');

    if (serialization_grid){

		gridster.remove_all_widgets();

	    $.each(serialization_grid, function() {
	        gridster.add_widget('
<ul>
    <li><button class="button delete">X</button></li>
</ul>
', this.size_x, this.size_y, this.col, this.row);
	    });

    }

    $("#add-widget-form").submit(function( event ) {

    	var size_x = parseInt($(this).find("#size-x").val()),
    		size_y = parseInt($(this).find("#size-y").val());

    	if ( $.isNumeric(size_x) &&  $.isNumeric(size_y) ) {

    		gridster.add_widget('
<ul>
    <li><button class="button delete">X</button></li>
</ul>
', size_x, size_y);
    		jj_save_order();
    	}

		return false;
	});

    $(".delete").click(function(){

    	gridster.remove_widget( $(this).closest('.gs-w'), function(){
    		jj_save_order();
    	});

    	return false;
    });

    function jj_save_order(){

    	var data = {
    		action: 'update_grid',
    		grid_order: gridster.serialize()
    	}

    	$.post(ajaxurl, data, function(response){
    		console.log(response);
    	});

    }

});

Na początku tworzymy sobie zmienną serialization_grid, w niej trzymamy układ widegtów który udostępniła nam funkcji wp_localize_script(). Następnie inicjalizujemy plugin Gridster.js, podaję kilka opcji takich jak rozmiar widgetów, maksymalna ilość kolumn itd.  Włączam też możliwość zmieniania rozmiarów elementów( resize: { enabled: true … } ). Zauważ też, że nasłuchuje zdarzenia stop gdy widget zmieni rozmiar(resize) lub pozycję(draggable), a wtedy wywołuję funkcje jj_save_order() która wyśle nam zapytanie Ajax, mające na celu zapisanie nowego układu widgetów. Funkcję tą wywołuję również gdy element zostanie usunięty lub dodany.

Spójrzmy teraz na ten kawałek kodu:

if (serialization_grid){

	gridster.remove_all_widgets();

	$.each(serialization_grid, function() {
	   gridster.add_widget('
<ul>
    <li><button class="button delete">X</button></li>
</ul>
', this.size_x, this.size_y, this.col, this.row);
	});

}

Tutaj sprawdzamy czy mamy dostępny układ widgetów, jeśli tak usuwamy wszystkie widgety które obecnie mamy(czyli te standardowe dodane przez funkcję wyświetlającą stronę administracyjną).

Myślę nie muszę szczegółowo tłumaczyć kodu obsługi formularza dodającego widgety. W skrócie – pobieramy wartości z obu pól tekstowych konwertując je na liczby. Następnie sprawdzamy czy nasze wartości są rzeczywiście liczbami, i jeśli tak jest, dodajemy nowy widget. Zapisujemy zmiany w układzie za pomocą jj_save_order().

Zobaczmy teraz jak wygląda ta funkcja.

function jj_save_order(){

    var data = {
    	action: 'update_grid',
    	grid_order: gridster.serialize()
    }

    $.post(ajaxurl, data, function(response){
    	console.log(response);
    });

}

Jak widzisz funkcja ta tworzy obiekt który zawiera dwa parametry, action, oraz grid_order do którego przypisujemy aktualny układ elementów(uzyskany za pomocą funkcji serialize(), należącej do pluginu gridster).

Obiekt taki wysyłamy do serwera. Jako adres podajemy wspomnianą wcześniej zmienną ajaxurl, następnie obiekt z danymi, oraz funkcja odbierająca odpowiedź od serwera. Odpowiedź będzie w fromacie JSON. dlatego używamy funkcji $.parseJSON. Następnie badamy jaka odpowiedź do nas dotarła – czy zapisanie układu się powiodło czy też nie.

Pozostał na już tylko kod odbierający zapytanie po stronie serwera.

add_action('wp_ajax_update_grid', 'jj_update_grid' );
function jj_update_grid(){

	$grid = $_POST['grid_order'];

	$result = update_site_option('gridster_order2', $grid);

	if ($result) {
		echo json_encode(array('status' => 'updated', 'message' => _('Grid was successful updated!', 'gridster')));
	}else{
		echo json_encode(array('status' => 'error', 'message' => _('Cannot update grid!', 'gridster')));
	}

	die();
}

Funkcja nie jest skomplikowana. Zapisujemy interesujący nas parametr do zmiennej $grid. Następnie uaktualniamy(lub tworzymy jeśli nie istnieje) opcję gridster_order w bazie danych, a wynik tej operacji przypisujemy do zmiennej $result. Jeśli będzie ona zawierać wartość true oznacza to, że wszystko się udało i wysyłamy odpowiedź w formacie JSON, korzystając z funkcji json_encode() dostępnej w php. Na końcu nie zapomnijmy o funkcji die()!

Zakończenie

To tyle w tym artykule. Poznałeś podstawy współpracy Ajaxa z WordPressem. Jest to, jak sam widzisz, bardzo proste a może ułatwić życie nam programistom, a już na pewno końcowym użytkownikom. :) Mam nadzieję, że stworzysz wiele ciekawych Ajax-owych rozwiązań! Nie zapomnij o nich wspomnieć w komentarzach!


Opublikowano

w

, ,

przez

Komentarze

10 odpowiedzi na „Ajax i WordPress – Wprowadzenie”

  1. Awatar Krzysiek

    Tego mi trzeba było… świetny artykuł… pojawi się może materiał jak ładować strony i posty w czasie rzeczywistym na stronie…

  2. Awatar mariusz

    Dzięki za uporządkowanie wiedzy nt ajaxa ;)

  3. Awatar Grzegorz Kielar

    Bardzo fajny artykuł na pewno z niego skorzystam bo akurat zacząłem zabawę z page builderami :) jedyny co to $.post nie jest żądaniem ajaksowym ;p ale też z tego długo korzystałem; ale pewnego razu coś mi nie chciało działać i przerzuciłem się na $.ajax

    1. Awatar Jacek Jagiełło
      Jacek Jagiełło

      Cieszę się, że Ci się podoba :) Tak, racja – funkcja jQuery.post nie jest sama w sobie żądaniem ajaxowym, ale postanowiłem jej użyć, ponieważ jest używana w dokumentacji WordPressa i większości wtyczek z którymi się spotkałem.

  4. […] wykład na ten temat wykracza poza ramy tego poradnika. Akurat podczas pisania tego tekstu fajny poradnik wprowadzający do AJAXa pojawił się na blogu […]

  5. Awatar Marek / Wpinternals

    Fajny poradnik – od razu podlinkowałem go u mnie na WPinternals, w tekście który opublikowałem dzisiaj – pojawia się w nim wątek AJAXa i nie miałem do czego zlinkować po polsku – a teraz już mam :)

    1. Awatar Jacek Jagiełło
      Jacek Jagiełło

      Dziękuję za link!
      Nigdy wcześniej nie trafiłem na wpinternals, naprawdę dobry blog, zacznę go odwiedzać :)

  6. Awatar Krzysiek

    Jacku, a pojawi się artykuł z tego cyklu ale o załadowaniu stron i postów itp w czasie rzeczywistym na stronie…

    1. Awatar Jacek Jagiełło

      Tak, na pewno. Myślę, że to będzie dobre rozwinięcie tematu Ajaxa.

  7. Awatar slick

    Gratuluje obu artykułów o Ajaxie w WP Jacek! Przystępnie napisane! :-)