Brug Ajax i WordPress

Akronymet "Ajax" dækker dækker over en række teknikker der kan bruges til at opdatere dele af indholdet af en webside i browseren uden at man behøver genindlæse hele siden. I vores eget arbejde med WordPress websites har vi f.eks. brugt Ajax-kald til at implementere infinite scroll, hvor indlæg hentes ind på en side efterhånden som brugeren scroller ned på siden, og vi har lavet sider som loader hurtigere fordi det meste af indholdet først hentes når brugeren klikker på et indlæg for at læse mere.

WordPress kontrolpanelet bruger Ajax, og det er forholdsvis simpelt at bruge WordPress Ajax API i sit eget tema eller plugin. I denne artikel viser vi et simpelt eksempel hvor vi bruger Ajax til at hente en større version af et billede når brugeren klikker på en thumbnail. Vores demo er en simpel liste med 30 billeder: ajaxdemo.webthings.dk/foer/

Hvert billede er sat ind i indholdsfeltet i et WordPress indlæg, og det samme billede er brugt som thumbnail. Når siden loades udskrives billedets titel, vores thumbnail der også fungerer som link til indlægget, en billedtekst og endelig en div med den store version af billedet. Strukturen ser således ud:
<div class="postwrapper"> <h2>Titel</h2> <a href="permalink"><img src=.../></a> <p>Uddrag</p> <div class="detail" style="display:none;"> <p><img src=... /></p> </div> </div>

.detail div'en omkring den store version af billedet har fået en inline "display:none;" så billedet som udgangspunkt er skjult når siden åbnes. Ved hjælp af en lille smule jQuery kan vi lave en simpel toggle-funktion så billedet kan vises og skjules igen ved klik i .postwrapper div'en:

jQuery(document).ready(function ($) { $('.postwrapper a').click(function (event) { event.preventDefault(); }); $('div.postwrapper').click(function () { $('.detail', this).toggle(); }) });

Problemet med vores simple billedside er at den er tung at loade. En test med tools.pingdom.com viser at siden fylder 54,4MB og tager ca 6 sekunder at hente:

Uden Ajax

Med en langsommere internetforbindelse kan det nemt tage 30-60 sekunder at loade hele siden.

Her er den samme side implementeret med Ajax-kald: http://ajaxdemo.webthings.dk/efter/. Siden fungerer på samme måde som den foregående, men i denne version bliver de store billeder først hentet når der er brug for dem, dvs. når brugeren klikker på en thumbnail. En ny test viser at siden nu kun fylder knap 389 kb og at den loader på mindre end et sekund:

Med Ajax

De fire trin

Der er fire ting vi skal gøre for at bruge Ajax-kald i et WordPress tema:

1) WordPress' Ajax API er implementeret ved hjælp af filen wp-admin/admin-ajax.php. På vores eksempelsite er URL'en til denne fil http://ajaxdemo.webthings.dk/wp-admin/admin-ajax.php, og denne URL skal vi på en eller anden måde have gjort tilgængelig i vores JavaScript.

2) Vores side-markup skal modificeres så vi kan identificere det billede som skal hentes når brugeren klikker på en div. Vi får også brug for at gemme noget tilstands-information, så vi undgår at hente det samme billede flere gange.

3) Vi skal skrive noget PHP som svarer på Ajax kald og som henter det billede vi skal bruge

4) Endelig skal vi bruge noget JavaScript som håndterer Ajax-kaldene, og som indsætter det hentede materiale på siden i browseren.

Rækkefølgen ovenfor er lidt tilfældig, men alle fire punkter skal være på plads før det hele fungerer.

1. admin-ajax.php

Vi skal bruge URL'en http://ajaxdemo.webthings.dk/wp-admin/admin-ajax.php fra vores JavaScript, og vi vil helst ikke hardcode den. En simpel måde at gøre vores URL tilgængelig fra JavaScript er at bruge funktionen wplocalizescript() i functions.php:

wp_localize_script('med', 'ajaxDemo', array('ajaxurl' => admin_url('admin-ajax.php')));

Det første argument til wplocalizescript er et handle, dvs. en unik tekststreng - 'med' i dette eksempel. Herefter følger navnet på et JavaScript objekt, 'ajaxDemo' og til sidst dataindholdet af objektet, i vores tilfælde navnet 'ajaxurl" og selve URL'en som vi skal bruge. Resultatet af ovenstående er at følgende bliver indsat på siden:

<script type='text/javascript'> /* <![CDATA[ */ var ajaxDemo = {"ajaxurl":"http:\/\/ajaxdemo.webthings.dk\/wp-admin\/admin-ajax.php"};
/* ]]> */ </script>

Vi kan nu bruge følgende syntaks i vores JavaScript til at hente den URL vi skal bruge:

var url = ajaxDemo.ajaxurl;

2. markup

Vores markup ser således ud:

<div class="postwrapper"> <h2>Titel</h2> <a href="permalink"><img src=.../></a> <p>Uddrag</p> <div class="detail" style="display:none;"> </div> </div>

I forhold til den oprindelige version er den eneste forskel at vi ikke længere sætter den store version af billedet ind i .detail div'en når siden loades.

Når brugeren klikker i div'en .postwrapper vil vi gerne hente den store version af billedet ind i .detail div'en, og da billedet ligger som indholdet i en post får vi brug for at referere til en Post ID i vores JavaScript. Vi kan gemme den type information i en "data-" attribut på vores div, så vi modificerer vores WordPress loop så div'en får følgende udseende:

<div class="postwrapper" data-postid="90">

Ligesom på siden uden Ajax vil vi gerne skiftevis vise og skjule billedet når brugeren klikker i .postwrapper div'en. Vi behøver kun hente billedet ind i browseren første gang, ved de efterfølgende klik kan vi blot skiftevis skjule billedet og vise det igen. Vi kan bruge en ekstra "data-" attribut til at huske om et billede allerede er hentet:

<div class="postwrapper" data-postid="90" data-content="0">

Når siden loades første gang har alle data-content attributter værdien "0", dvs. den store version af billedet er endnu ikke indlæst i browseren. Første gang brugeren klikker på en .postwrapper div hentes billedet og data-content får sættes til "1" for at indikere at billedet er indsat i browseren.

Den modificerede markup ser således ud:

<div class="postwrapper" data-postid="90" data-content="0"> <h2>Titel</h2> <a href="permalink"><img src=.../></a> <p>Uddrag</p> <div class="detail" style="display:none;"> </div> </div>

3. PHP

Her skal vi gøre to ting:

  1. Skrive en php-funktion der henter billedet fra WordPress når den bliver kaldt via admin-ajax.php
  2. Binde vores funktion sammen med en WordPress action hook

Selve funktonen ser således ud:

function ajaxdemo_get_content() { $postID = $_REQUEST['postID']; $content = get_post_field('post_content', $postID); if (! is_wp_error($content)) { $result['content'] = $content; $result['count'] = 1; } else { $result['count'] = 0; } $result = json_encode($result); echo $result; exit(); }

Indholdet af vores post - det store billede - hentes med funktionen getpostfield(). Hvis kaldet lykkes gemmes billedet i et array, $result, sammen med et "count" element der får værdien "1" for at indikere success. Hvis indholdet af den pågældende post af en eller anden grund ikke kan hentes sættes "count" til 0.

Vi afslutter vores funktion med at json-encode indholdet af $result og bruger echo til at sende indholdet tilbage til vores JavaScript.

Vi afslutter scriptet med exit() så vi undgår at returnere kontrollen til admin-ajax.php når vores funktion er afsluttet. (Ellers får viet uønsket "0" tilføjet til vores output fordi admin-ajax.php terminerer med kaldet die(0).)

Dernæst tilføjer vi vores actions:

add_action("wp_ajax_get_content","ajaxdemo_get_content"); add_action("wp_ajax_nopriv_get_content","ajaxdemo_get_content");

De to action hooks, "wp_ajax_" og "wp_ajax_nopriv_",bruges til at håndtere ajax-kald fra henholdsvis anonyme brugere og brugere som er logget ind. Den sidste del af hook-strengen, "get_content", svarer til den "action" property som vi angiver i Ajax-kaldet i punkt 4.

I dette eksempel skelner vi ikke mellem anonyme brugere og brugere som er logget ind, og begge kald til add_action() peger derfor på den php-funktion som vi indsatte ovenfor, ajaxdemo_get_content().

4. JavaScript

Vi er nu klar til at binde det hele sammen med JavaScript. Vores script ser således ud:

jQuery(document).ready(function ($) {
    $('.postwrapper a').click(function (event) {
        event.preventDefault();
});

    $('div.postwrapper').click(function () {
        var content = $(this).data('content');

        if (content == 0) {
            var detail = $('div.detail',this);
            var postID = $(this).data('postid');

            $.ajax({
                url: ajaxDemo.ajaxurl,
                type: "GET",
                data: {
                    action: 'get_content',
                    postID: postID
                },
                dataType: "json",
                success: function (response) {
                    detail.html(response.content);
                    detail.show();
                }
            });

            $(this).data('content', 1);
        }

        else {
            $('.detail', this).toggle();
        }
    });
});

Når brugeren klikker på .postwrapper div'en henter vi først indholdet af data-content attributten ind i variablen content. Hvis værdien af denne variabel er forskellig fra 0, så er det store billede allerede hentet. Vi kan derfor springe Ajax-kaldet over og blot kalde jQuery's toggle() funktion for skiftevis at vise eller skjule billedet.

Hvis billedet ikke er hentet allerede, så henter vi post ID fra data-postid attributten i vores markup. Derefter kalder vi jQuery's ajax() funktion med et objekt med dette indhold:

url: den fulde URL til admin-ajax.php scriptet som vi gemte i ajaxDemo objektet i trin 1 ovenfor.

type: Vi bruger et GET request til at hente billedet

data: den action hook vi vil bruge, 'get_content' (se punkt 3 ovenfor) samt den post ID som vi vil hente billedet fra

dataType: vi bruger json formatet til at hente indholdet fra WordPress

Hvis Ajax-kaldet lykkes bruger vi jQuery's html() funktion til at indsætte billedet i browseren, og vi bruger show() for at gøre det nye indhold synligt.

Et voilà - vi er færdige med Ajax-versionen af vores billedvisning.