Dodano 2018-10-13 13:06:36 przez Daniel
Witaj ponownie, w tej części dowiesz się jak ulepszyć swoje wtyczki o technologie Ajax, dzięki czemu poszczególne części strony będą mogły się wczytywać samodzielnie bez konieczności ponownego załadowywania całości.
Nasz czat, który tworzyliśmy w poprzednich dwóch częściach może mógłby funkcjonować ze dwadzieścia lat temu lecz dzisiaj taka aplikacja jest niedopuszczalna. Obecnie przy każdym wysłaniu posta cała strona musi się ładować ponownie a żeby zobaczyć czy nie ma nowych postów trzeba odświeżyć stronę i kolejne przeładowanie.
W tej części naprawimy tę kwestię dodając Ajaxowe rozwiązanie przy wysyłaniu posta oraz sprawdzania czy nie ma nowych wiadomości. Wszystko będzie się odbywać w tle dzięki czemu unikniemy przynajmniej częściowej frustracji użytkownika.
Ok, skoro już sobie wyjaśniliśmy co jest do zrobienia bierzmy się do pracy. Na początku trzeba dołączyć plik js, tę procedurę opisałem już w kursie poświęconym tworzeniu szablonu Tutaj teraz tylko zwrócę uwagę (tak jak w poprzedniej lekcji) na trochę inną ścieżkę do naszego pliku. Ale najpierw stwórzmy plik z kodem js o nazwie main.js. Plik powinien być umieszczony w podkatalogu katalogu głównego naszej wtyczki o nazwie js czyli js ../main.js. W świeżo utworzonym pliku umieszczamy prosty kod:
console.log('test');
Wcześniej stworzyliśmy funkcję dodawania skryptów i arkuszy stylów o nazwie zwpc_add_scripts_and_styles() w tym momencie wykorzystamy tę funkcję aby dołączyć świeżo utworzony plik ze skryptem.
function zwpc_add_scripts_and_styles() { wp_enqueue_style('zwpc-main-css', plugins_url('zwp_czat/css/main.css')); wp_enqueue_script( 'zwpc-script-main', plugins_url('zwp_czat/js/main.js') , array(), '1.0.0', true ); }
W efekcie po odświeżeniu strony testowej w konsoli otrzymamy komunikat
Jeśli komunikat już tam jest oznacza to że prawidłowo podpięliśmy plik js i już możemy zacząć kodować dynamiczny czat.
JQuery to bez wątpienia najpopularniejsza biblioteka JavaScript. Za jej użyciem przemawia niezbyt duża waga oraz niezwykle funkcjonalna zawartość, dzięki niej można napisać więcej, pisząc mniej kodu. JQuery jest także prosta w użyciu a jej dokumentacja szeroka, przystępna i łatwodostępna. Co warto wiedzieć WordPress używa tej biblioteki wewnętrznie.
Pierwsza co musisz wiedzieć to że biblioteka jQuery używa znaku $ jako skrótu oznaczającego obiekt biblioteki.
Druga bardzo ważna rzecz jaką powinieneś wiedzieć nawet jeśli korzystałeś już z tej biblioteki jest fakt że są inne biblioteki wykorzystujące znak dolarka, z tego właśnie powodu WordPress aktywuje domyślnie tryb bezkonfliktowy, który pozwala innym bibliotekom na korzystanie z $. Kod jQuery z $ tak po prostu nie będzie działał. Są dwa sposoby używania jQuery:
Osobiście pierwszy sposób preferuję jeśli mam do napisania więcej jak kilkanaście linijek kodu z jQuery a drugi jeśli mam do użycia ze dwie funkcje, ale aby utrzymać konsekwencję w tym kursie będziemy używać drugiego sposobu.
Teraz dodajemy do naszego pliku .js następujący kod opakowania:
(function($) { //tutaj będzie kod z jQuery })(jQuery);
Teraz jak już wiemy jak używać jQuery, spróbujemy przekazać do naszego skryptu JS jakąś wartość wygenerowaną w PHP tak jak zostało to przewidziane w konstrukcji WordPressa. Po pierwsze wróćmy na chwilę do miejsca gdzie dodaliśmy do naszej wtyczki plik z kodem JavaScript. Była to funkcja wp_enqueue_script();, która jako pierwszy argument pobierała nazwę ‚zwpc-script-main‚, teraz użyjemy funkcji wp_localize_script( $handle, $name, $data ); gdzie:
$handle – To wymagany argument – uchwyt – czyli pierwszy argument z wp_enqueue_script.
$name – nazwa zmiennej javascript, jest to także wymagany argument i później będzie wykorzystany jako obiekt z wartościami, może to być też po prostu jakaś wartość
$data – dane, które chcemy przekazać
Teraz przykład użycia po stronie PHP, w którym przekażemy sobie tablicę zmiennych:
wp_enqueue_script( 'zwpc-script-main', plugins_url('zwp_czat/js/main.js') , array(), '1.0.0', true ); wp_localize_script( 'zwpc-script-main', 'zwp_data', array('value1' => 'test1', 'value2' => 'test2') );
A z drugiej strony w pliku main.js z kodem javascript spróbujemy wyświetlić w konsoli te dwa argumenty przekazanej tablicy:
(function($) { $(document).ready(function(){ console.log(zwp_data.value1); console.log(zwp_data.value2); }); })(jQuery);
W efekcie po załadowaniu strony (ctrl + f5) powinniśmy otrzymać dwa komunikaty jak na poniższym obrazku.
Teraz skoro już mamy przygotowany plik .js przechodzimy do zakodowania części, w której wyślemy post użytkownika do bazy z postami. Ale wcześniej trochę porządków z kodem bo zrobiło się nieco za dużo jak na jeden plik, a będzie więcej.
W naszym głównym pliku wtyczki powinna znajdować się teraz cała klasa o nazwie ZWP_czat zawierająca niewiele poniżej dwustu linijek kodu. Teraz w katalogu inc, który powinien już się znajdować w katalogu głównym wtyczki tworzymy plik o takiej samej nazwie jak klasa czyli ZWP_czat.php, następnie wycinamy cały kod klasy z pliku głównego wtyczki i wklejamy do nowo utworzonego pliku.
Teraz w miejscu, z którego przenieśliśmy kod wklejamy następującą funkcję:
require_once 'inc/ZWP_czat.php';
To powinno nieco uporządkować kod. Teraz wracamy do pliku ZWP_czat.php i odnajdujemy funkcję o nazwie show_zwpc_html() w tej właśnie funkcji wcześniej zawarliśmy kod odpowiedzialny za wyświetlenie całego czatu.
Na początek zmodyfikujemy trochę kod formularza do wysyłania wiadomości na czacie. Dodamy klasę zwp_czat_form do znacznika formularza a także klasę zwp_czat_input do znacznika pola, w które użytkownik wpisuje treść swojego posta.
echo ' <form method="POST" class="zwp_czat_form"> <input type="hidden" name="zwpc_action" value="add"/> <label for="post_content' . $place . '">Treść posta</label> <input type="text" name="post_content' . $place . '" value="" placeholder="Treść posta" class="zwp_czat_input"/> <input type="submit" value="Napisz" class="button-primary"/> </form> ';
Powyższy listing przedstawia fragment kodu odpowiedzialny za wyświetlenie formularza wysyłającego wiadomość na czacie. Teraz przechodzimy do naszego pliku z kodem JavaScript. Aby wykorzystać technologię ajax, musimy najpierw pobrać wiadomość za pomocą javascript.
Teraz najważniejsze czyli punkty wyjściowe, do których będziemy się odnosić.
Po pierwsze w WordPressie wszystkie ajaxowe zapytania wysyłany do admin-ajax.php, dlatego też na samym początku zmodyfikujemy kod przekazania wartości z PHP do JS w taki sposób aby był przekazywany link, pod który mają być słane zapytania.
$protocol = isset($_SERVER['HTTPS']) ? 'https://' : 'http://'; wp_localize_script( 'zwpc-script-main', 'zwp_data', array('ajax_url' => admin_url('admin-ajax.php', $protocol)) );
Warto tutaj zauważyć że został automatycznie określony protokół.
Mamy link, teraz czas stworzyć punkt do którego się odniesiemy. Mamy specjalnie do tego celu dwa rodzaje zaczepów:
wp_ajax_nopriv_towja_nazwa – wykorzystanie publiczne bez konieczności logowania
wp_ajax_twoja_nazwa – przeważnie wykorzystywane w panelu admina dla zalogowanego.
W miejsce „twoja_nazwa” należy wpisać nazwę własną „akcji”, którą będziemy przekazywać później za każdym zapytaniem.
Na początek utworzymy funkcję zwp_ajax_get_posts(), która będzie zwracać po prostu cokolwiek. Pobierzemy sobie to cokolwiek i wyświetlimy w konsoli dla przetestowania tego procesu.
add_action('wp_ajax_nopriv_zwp_get_posts','zwp_ajax_get_posts'); add_action('wp_ajax_zwp_get_posts','zwp_ajax_get_posts'); function zwp_ajax_get_posts(){ echo 'cokolwiek'; }
Z drugiej strony tworzymy sobie zapytanie w JavaScript
(function($) { $(document).ready(function(){ var data = { action: 'zwp_get_posts' }; $.get(zwp_data.ajax_url, data, function(res){ console.log(res); }); }); })(jQuery);
Tutaj trzeba zauważyć że przekazujemy obiekt data, w którym zawarte jest pole action, zawsze wykorzystujemy ten parametr żeby odnieść się do odpowiedniego punktu (tego co wcześniej utworzyliśmy). W tym przypadku pobieram to co wyświetlam w funkcji php zwp_ajax_get_posts();
W konsoli otrzymałem taki oto wynik:
I to w zasadzie tyle z najważniejszych rzeczy w tym temacie. Nic nie stoi nam na przeszkodzie żeby tak zmodyfikować kod żeby pobierane były ostatnie posty i ładowane do odpowiedniego miejsca na stronie za pomocą jQuery.
Żeby się upewnić że nie ma problemu zmodyfikujemy nasz kod, tak aby załadował te wszystkie posty przy załadowaniu strony.
Obecnie w naszej wtyczce pobieramy ostatnie 100 wiadomości za pomocą shortcode gdzie ładowane jest wszystko. Teraz napiszemy sobie kod AJAX, który będzie zapamiętywał id ostatniego posta i co pięć sekund odpytywał o nowe wiadomości.
Na początek dodajmy do naszej klasy ZWP_czat funkcję która na wejściu pobierze id posta a na wyjściu zwróci wszystkie posty o id większym od pobranego.
//pobieram ostatnie posty function get_zwpc_last_posts($last_id = 0, $limit = 20){ return $this->wpdb->get_results("SELECT * FROM $this->table_name WHERE id > $last_id ORDER BY create_date DESC LIMIT 0,$limit"); }
Teraz wykorzystamy tę funkcję w funkcji, którą utworzyliśmy wcześniej by pobrać ostatnie posty. Zakładamy w tym przypadku że za każdym razem będziemy przesyłać id ostatniego posta metodą POST. Otrzymany wynik konwertujemy do formatu JSON aby można było go później wygodnie odebrać i przetworzyć w skrypcie JavaScript.
function zwp_ajax_get_posts(){ $last_id = empty($_POST['last_id']) ? 0 : (int)$_POST['last_id']; global $ZWP_Czat; $res = $ZWP_Czat->get_zwpc_last_posts($last_id); echo json_encode($res); die(); }
W powyższym kodzie na końcu wykorzystujemy funkcję die(), aby nic się nie dokleiło na końcu i by zwrócony JSON był zwrócony poprawnie.
Teraz czas zmodyfikować nieco nasz kod JavaScript żeby było zgodnie z założeniem. Wrzucimy sobie odpytywanie w funkcję, którą następnie będziemy wywoływać co kilka sekund.
(function($) { var zwp_last_id = 0; $(document).ready(function(){ setInterval(function(){ zwp_get_posts(); },5000); }); function zwp_get_posts() { var data = { action: 'zwp_get_posts', last_id: zwp_last_id }; $.post(zwp_data.ajax_url, data, function (res) { if(res.length > 0){ var res_str = ''; res.forEach(function(value,index){ if(value.id > zwp_last_id){ zwp_last_id = value.id; } res_str += '<tr><td>'+ value.create_date + '</td></tr><tr><td>' + value.post_content + '</td></tr>'; }); $('.ZWPC_Widget table').prepend(res_str); } },'JSON'); } })(jQuery);
W powyższym kodzie na początku definiuję zmienną do której będę przypisywał id ostatniego pobranego posta. Następnie po załadowaniu strony definiuję interwał, w którym co 5 sek będzie się wykonywała funkcja zwp_get_posts(). Dalej jest nasza funkcja, w której oprócz przesyłania linku do zapytań przesyłamy również id ostatniej wiadomości. Zmieniła się tutaj także metoda wysyłki zgodnie z założeniem z GET na POST. Później sprawdzam czy zwrócony wynik zawiera jakieś elementy w tym przypadku wiadomości i jeśli tak to przelatuję pętlą po elementach generując kod html z wiadomościami, który ostatecznie dopisuję na początku listy wiadomości.
Teraz mamy praktycznie obsłużone pobieranie wiadomości, jeśli ktoś inny napisze coś na naszym czacie to najdalej po pięciu sekundach zostanie to wyświetlone.
W celu pobrania wiadomości z pola tekstowego na początek za pomocą jQuery pobieramy obiekt formularza za pomocą $(„.zwp_czat_form”), następnie dodajemy zdarzenie, który ma się wykonać podczas wysyłania formularza czyli w tym przypadku podczas wciśnięcia przycisku „Napisz”. Do tego właśnie służy .submit();. Ta metoda jest o tyle dobra że działa zarówno w przypadku kliknięcia buttona jak i po wciśnięciu entera.
Do obsługi całego zdarzenia umieszczamy funkcję pobierającą zdarzenie function(e){}. Pierwszą rzeczą jaką musimy zrobić jest zablokowanie typowego zachowania dla formularzy, czyli wysyłki poprzez przeładowanie strony. Do tego celu wykorzystujemy funkcję e.preventDefault(); dzięki niej strona się nie przeładuje.
Kolejnym krokiem jest utworzenie obiektu pola tekstowego, ja w tym miejscu przypisuję obiekt do zmiennej var post_content = $(„.zwp_czat_input”); ale ten etap można pominąć i działać bezpośrednio na obiekcie jQuery. Dalej sprawdzam czy użytkownik wpisał jakiś tekst przed wysłaniem formularza i jeśli tak to wyświetlam ten tekst w konsoli a następnie czyszczę pole tekstowe. Poniżej listing zawierający cały ten kod. Pamiętaj że aby działał musi być zawarty w opakowaniu opisanym wcześniej (tryb bezkonfliktowy).
(function($) { $(".zwp_czat_form").submit(function(e){ e.preventDefault(); var post_content = $(".zwp_czat_input"); if(post_content.val()){ console.log(post_content.val()); post_content.val(""); } }); })(jQuery);
Teraz dobrze byłoby przetestować ten etap, w tym celu otwieramy stronę, na której wcześniej wkleiliśmy shortcode. Powinien się tam znaleźć formularz, do którego dodaliśmy dwie klasy.
Wpisujemy jakąś testową wiadomość w polu i klikamy na „Napisz” albo wciskamy Enter. W obu przypadkach efekt powinien być podobny, formularz się nie wyśle, pole tekstowe się wyczyści a w konsoli powinna się pojawić nasza wiadomość z pola tekstowego. Jeśli tak się stało to znaczy że właśnie pobraliśmy odpowiednio tekst posta.
Teraz nadszedł czas aby wykorzystać technologię Ajax w celu dodanie wiadomości do bazy bez konieczności przeładowania strony.
Sprawa jest już dość prosta ponieważ mamy w naszej wtyczce odpowiedni event odpalany przy próbie wysłania formularza, który jednocześnie pobiera nam zawartość posta, z drugiej strony mamy dodawania posta do bazy, teraz pozostało tylko dodanie akcji w PHP i odniesienie się do niej w JS. Zacznijmy od dodania akcji zwp_add_post.
add_action('wp_ajax_nopriv_zwp_add_post','zwp_ajax_add_post'); add_action('wp_ajax_zwp_add_post','zwp_ajax_add_post'); function zwp_ajax_add_post(){ $post_content = empty($_POST['post_content']) ? 0 : strip_tags($_POST['post_content']); if(!empty($post_content)){ global $ZWP_Czat; $res = $ZWP_Czat->add_post($post_content); echo (int)$res; } else { echo '0'; } die(); }
Nie ma tu zbyt wiele do tłumaczenia analogicznie jak wcześniej dodaję akcje, do akcji podpinam funkcję w której wykorzystuję wcześniej napisaną klasę.
Pozostaje tylko fragment kodu JS odpowiedzialny za wywołanie tej akcji:
$(".zwp_czat_form").submit(function(e){ e.preventDefault(); var post_content = $(".zwp_czat_input"); if(post_content.val()){ var data = { action: 'zwp_add_post', post_content: post_content.val() }; $.post(zwp_data.ajax_url, data, function(res){ if(res == '0'){ console.log('Nie wysłano'); } else { console.log('Wysłano'); } zwp_get_posts(); }); post_content.val(""); } });
Tutaj dodatkowo sprawdzam czy dodaje się powiodło i wyświetlam w konsoli komunikat, ale równie dobrze zamiast wyświetlać komunikat w konsoli mógłbym podjąć inne kroki.
Na koniec tylko usuwam fragment kodu odpowiedzialny za wyświetlanie postów przy ładowaniu czatu, bo w przeciwnym wypadku na początku wyświetlają się podwójnie.
To by było na tyle w tym temacie. Zrobił się z tego niebywale długi wpis, który zajął mi półtora roku 😛 , jeszcze tylko aktualny kod wtyczki po tej części do pobrania zwp_czat