Case Fixers – WordPressin käyttäminen sovellusalustana

WordPress on ollut kovassa muutoksessa lohkoteemojen ja Gutenbergin myötä, mikä on käytännössä avannut WordPressiin natiivisti paljon samoja temppuja ja työkaluja mitä käytetään perinteisemmässä sovelluskehityksessä. Olen pyöritellyt jo hetken tapoja millä tavoin React-pohjainen sovelluskehitys ja WordPress saadaan yhdistettyä mahdollisimman kehittäjäystävällisesti yhteen. Tämä on toiminut myös Kotisivu Block Theme toisen version pohjalla, jonka lopullinen julkaisu on kulman takana. Uudistus tuo mukanaan edistyneemmän tuen omien API-rajapintojen, Metaboxien, Custom Post Typejen ja tietokantojen määritykseen. Teeman asetukset on myös muutettu käyttämään WordPressin rajapintoja ja Reactia. Nämä toiminnallisuudet mahdollistavat WordPressin käyttämisen hyvin tehokkaasti käytännössä mihin vain.

Vähän aikaisempaa kehitysversiota pääsin käyttämään hyvinkin mielenkiintoisessa projektissa, jossa oli tarvetta luoda freelancereiden -kauppapaikka. Aluksi oli mietinnässä kehittää kauppa-ratkaisu NextJS tai Nuxt -pohjaisesti, mutta lopulta yksinkertaisuuden ja rajallisten resurssien vuoksi päädyimme WordPressiin. Sivustoon pääset tutustumaan täältä. Käytössä olevaan Kotisivu Block Theme -teemaan pääset tutustumaan täältä.

Moni saattaa nyt hätkähtää, mutta anna kun selitän miten alusta toteutettiin tavoilla, jotka mahdollistavat myös ketterän jatkokehityksen.

Pohjalle WordPressin oma tietomalli

Koska kyseessä oli puoliksi web-sovellus ja puoliksi verkkosivusto, ensimmäinen ongelma oli miettiä miten ja miten sovelluksen tietorakenteet toimivat. Olin aiemmin tehnyt hieman vastaavia WP:n laajennoksia nimikioski.fi verkkotunnuksien kauppapaikalle, mutta Fixersin tapauksessa ei ollut tarvetta sallia sivuston ulkopuolisia käyttäjiä, jolloin kokonaisuutta voitiin yksinkertaistaa yksinkertaisesti vain laajentamalla WordPressin omaa käyttäjähallintaa. Tämän avulla WordPressin harteille voitiin jättää käyttäjähallinta, kirjautuminen ja rekisteröityminen kokonaisuudessaan.

Toinen ongelma oli miten pystymme rajaamaan käyttäjän oikeuksia sillä tavalla, että hän ei pääse esimerkiksi muokkaamaan muiden kirjoituksia tai tekemään muita ei haluttuja toimenpiteitä. Tämä ratkaistiin uuden käyttäjätason rekisteröinnillä ja määrittämällä tälle halutut oikeudet. Uuden käyttäjätason lisääminen avasi myös oven alla olevan kaltaisille tarkistuksille:

if (in_array('freelancer', (array) $user->roles)) {
    return true;
}

Näiden lisäksi luomalla omat API-osoitteet käyttäjien datan hakemiseen ja päivittämiseen, suoraviivaisti muun sovelluksen suunnittelua, jolloin saatiin yhtenevät API-osoitteet kaikelle datan käsittelylle. Osoitteen rakenteessa noudatettiin WP:stä tuttua me -patternia eli käytännössä pistämällä me osoitteen perään, voidaan hakea sen hetkisen käyttäjän data.

Tämä tarkoittaa sitä, että osoitteista saadaan alla olevan muotoisia.

/* Haetaan kaikki käyttäjät */
<HOST>/wp-json/<SLUG>/v1/users

/* Haetaan nykyinen käyttäjä */
<HOST>/wp-json/<SLUG>/v1/users/me

Se missä GET -metodeilla saadaan haettua data, POST-metodeilla voidaan päivittää yksittäisen käyttäjän data.

Custom Post Type avuksi ilmoitusten hallintaan

WordPress tarjoaa out-of-the-box Custom Post Type toiminnallisuuden, jota voidaan hyödyntää erilaisten resurssien hallintaan. Yksittäinen resurssi voi olla mitä vain eli esimerkiksi kirja, henkilö ja miksi ei myös työilmoitus. Perus CPT:tä laajennettiin tarvittavilla lisäkentillä sekä myöskin ns. “taxonomeilla” kuten kaupunki tai toimiala. Vastaavasti kuten käyttäjien kohdalla, myös ilmoituksille tehtiin omat API-osoitteet, jotka mahdollistavat ilmoitusten muokkaamisen, luomisen, poistamisen ja päivittämisen. Ilmoitusten lisäämisessä pystyttiin helposti hyödyntämään WordPressin omaa oletuskäyttäytymistä eli kun luodaan uusi kirjoitus tai sivu, tämä lisätään luonnokseksi kyseiselle käyttäjälle.

Yksi ongelma mikä ilmeni aika nopeasti oli se, että miten ilmoituksen muokkaamiseen käytettävä osoite saadaan luotua dynaamisesti. Koska käyttäjät voivat itse lisätä ilmoituksia, pitää osoitteen toimia dynaamisesti, mutta miten määrätään mikä sivupohja ladataan kun osoitteessa on mukana esimerkiksi parametrit ?edit=true? Parin erilaisen ja aivan liian monimutkaisen kokeilun jälkeen löytyi template_include -hookki, joka mahdollisti tarkastuksen, että jos sivulataus sisältää määrätyt parametrit, voidaankin ladata täysin eri sivupohja. Tämä mahdollisti muokkaukseen käytettävän sivupohjan lataamisen, jos käyttäjä oli kyseisen ilmoituksen omistaja. Muussa tapauksessa käyttäjä ohjattiin saman postauksen varsinaiselle sivulle.

Lisään mallin koodista myös alle, jos joku kaipaa sattumoisin vastaavanlaista koodia.

/**
 * Load custom template for edit page
 */
add_filter('template_include', function ($template) {
    // Check if we are on a gig custom post type
    $is_edit = isset($_GET['edit']) && $_GET['edit'] == 'true';
    $is_post_type = get_post_type() === 'slug';

    // If edit parameter is set and on cpt page, return edit template
    if ($is_edit && $is_post_type) {
        $new_template = get_query_template('edit-cpt');

        if ('' !== $new_template) {
            add_filter('body_class', function ($classes) {
                $classes[] = 'edit-cpt;
                return $classes;
            });

            return $new_template;
        }
    }

    // If not on custom post type, return default template
    return $template;
});

Rich Text Editorin lisääminen

Ylläolevien ongelmien ratkaisemisen jälkeen sovelluksen perustoiminnallisuudet olivat käytännössä tehty, mutta näitä oli jäljellä vielä pari. Toinen näistä oli se miten käyttäjä pystyy muokkaamaan kirjoituksia? Koska sivuston peruskäyttäjää ei haluta päästää adminiin (ja se olisi myös todella ruma ratkaisu), täytyy näiden kahden välille luoda jokin käyttöliittymä, jolla asiakas voi hallinnoida omia ilmoituksia. Koska nykyinen WordPress on täynnä Reactia se tarkoittaa myös, että käytettävissä on tismalleen samat kirjastot mitä muussakin React -pohjaisessa kehityksessä. Ainoana erona on vain se, että React kannattaa ladata suoraan WP:n omista kirjastoista, jolloin tähän liittyvät riippuvuudet ladataan vain kerran.

Ennen kuin puhutaan Rich Text -editorin lisäämisestä, otetaan pari sanaa teeman rakenteesta.

Monimutkaisempia kokonaisuuksia varten teema muokkaa lohkoteemojen oletusrakennetta hieman, että .html -tiedostoissa ladataan kirjaimellisesti vain
ja pohjat, sekä sivun sisällön näyttämiseen käytettävä template-main -lohko. Edellä mainitun lohkon sisälle ladataan sen jälkeen dynaamisesti haluttu sivupohja.

Kokonaisuus näyttää kutakuinkin tältä:

index.html sisältö (Github)

<!-- wp:ksd/part-header /-->
<!-- wp:ksd/template-main { "templateSlug": "template-index", "className": "" } /-->
<!-- wp:ksd/part-footer /-->

template-main -lohkon render.php tiedosto (Github)

<div <?php echo $sanitized_attributes ?>>
    <main id="main" class="site-main">
        <?php echo do_blocks(
            sprintf('<!-- wp:ksd/%s /-->', $attributes['templateSlug'])
        ); ?>
    </main>
</div>

template-index -lohkon render.php tiedosto (Github)

<?php the_content(); ?>

Yllä olevan kaltainen lähestyminen mahdollistaa muutaman asian:

  1. Varsinaisen kehitys ei ole enää Gutenbergin html-pohjaisten sivupohjien tai muiden rajapintojen varassa, vaan voidaan käyttää helpommin ja monipuolisemmin React ja PHP -pohjaista lähestymistä. Tämä ei tietenkään ole WordPressin omainen tapa tehdä asioita, mutta mielestäni tässä kontekstissa kohtuullisen toimiva ja selkeä.
  2. Varsinaiset sivupohjat voidaan tehdä yhdistäen PHP:ta ja Reactia täysin kehitettävän sovelluksen tarpeen mukaisesti. Yksi sivupohja (tai lohko) on teoriassa pienimuotoinen React applikaatio. Jos lohkojen rakenne ei ole tuttu, render.php pitää sisällään PHP-koodin ja view.js -tiedostoa voidaan käyttää React-applikaation pohjana (vastaava kuin App.js -tiedosto React projektissa). Render.php tiedoston sekaan lisätään myös html-tagi, jonne React koodi liitetään.
  3. Kaikki lohkot voidaan tarvittaessa muuntaa käyttämään myös WordPressin Interactivity rajapintaa ja perinteisiä html-pohjia, jolloin sivuston käyttäjälle on mahdollista luoda jonkinasteinen hallinta sivuston “koodiin”. Tässä käytännössä käyttää “incremental enhancement” -termiä, koska kehitys voidaan tehdä pala kerrallaan ja tarpeen vaatiessa. Hyvin tyypillisesti peruskäyttäjällä ei ole mitään tarvetta päästä muokkaamaan sivupohjia, jolloin React/PHP/JS -pohjainen lähestyminen riittää.

Koko Kotisivu Block Theme pohjaa yllä kuvattuun ajatukseen ja tarjoaakin tämän vuoksi hyvin monipuoliset mahdollisuudet myös web sovellusten kehitykseen.

Yllä oleva selitys avaa ehkä hieman kokonaisuutta ja helpoittaa ehkä artikkelin lähestymistä. Käytännön esimerkki React-sovelluksesta löytyy käytännössä src/admin -kansiosta, josta luodaan teeman asetussivut.

Mutta takaisin RichText -editorin määritykseen.

Koska käyttäjän piti pystyä muokkaamaan ilmoituksia mahdollisimman helposti, ensimmäinen asia oli integroida editoriin jonkinlainen RichText-editori. Kävin läpi pari mahdollista vaihtoehtoa kunnes päädyin käyttämään QuillJS -kirjastoa, joka oli juuri päässyt versionumeroon kaksi. Tämän avulla käyttäjä pystyvät lisäämään omia muotoiluita tekstin sekaan, tehden ilmoituksista rikkaampia ja tarjoten asiakkaalle paremman kokemuksen. Kirjasto mahdollistaa myös mahdollisuuden jatkokehitykselle, jos tätä halutaan jossain vaiheessa elinikää kehittää eteenpäin. Muut muokattavat kentät toteutettiin joko QuillJS:n pohjalle tai ihan webnatiivisti lomakekentillä. Frontendin ja backendin välinen keskustelu tehtiin käyttämällä samoja rajapintoja, jotka oltiin määritetty aiemmin, mutta tässä kohin täytyi tehdä hieman enemmän tarkistuksia mitä dataa käyttäjä voi syöttää palveluun ja miten sekä missä muodossa syötetty data tallennetaan.

Samoja periaatteita hyödynnettiin käyttäjän profiilin muokkauksessa.

Maksujen hallinta Stripen avulla

Yksinkertaisuuden vuoksi maksupalveluntarjoajaksi valikoitu Stripe ja integraatio toteutettiin vielä tavalla, joka mahdollisti ylläpitäjälle tuotehallinnan suoraan Stripesta. Integraatiot pyrittiin pitää vielä tässä kohdin mahdollisimman kevyenä ja hyödyntää Stripen omia palasia mahdollisimman paljon. Stripe esimerkiksi tarjoaa asiakkaan tilauksiin hallintaan liittyvän käyttöliittymän valmiina, jonka implementointi onnistuu Stripen omien kirjastojen kautta hyvinkin näppärästi. Tästä osasta ei käytännössä ole niin paljoa kerrottavaa, koska toteutus oli kohtuullisen yksinkertainen ja dokumentaatiot löytyvät Stripen päästä kohtuullisen hyvin.

Muu sivusto

Kun asiakkaan hallinta oli valmis ja palvelu integroitui Stripen kanssa, oli aika toteuttaa loppuosa sivustosta. Tämä oli hyvin tyypillistä lohkopohjaista websivuston kehittämistä ja samoja aiemmin tehtyä rajapintoja hyödynnettiin kaiken dynaamisen datan hakemisessa. Ennenkuin joku kysyy, käytössä ei ollut yhtäkään lisäosaa :). Kaikki luotiin hyödyntämällä WordPressin omia toiminnallisuuksia sekä kustomoidulla React + PHP koodilla.

Lopuksi

Näin ensimmäinen versio Fixers palvelusta oli valmis ja WordPressin avulla budjetti sekä palvelun ylläpito ja palvelinkustannukset kyettiin pitämään hyvinkin kevyenä sekä helppona. Palvelun pohja toteutettiin tavoilla, jotka mahdollistavat myös jatkokehityksen käytännössä mihin tahansa eli järjestelmä kestää varmasti aikaa. Kaikki osapuolet olivat tyytyväisiä toteutukseen sekä saavutettuun lopputulemaan eli tätä voidaan pitää onnistuneena projektina.

Disclaimer: toteutus ei noudata WordPressille ominaisia tapoja toteuttaa asioita, mutta mielestäni näin ei aina tarvitsekkaan. Tämän kirjoituksen tarkoituksena on avata hieman miten WordPressiä voidaan hyödyntää PHP + React -frameworkkinä, jolloin Gutenbergia käytetään vain sivuston sisällön hallintaan. Loppujen lopuksi, WordPress kuitenkin on äärimmäisen monipuolinen työkalu, joka mahdollistaa sivustojen luomisen täysin sivueditori pohjaisesti tai sitten sivusto voidaan toteuttaa tämän artikkelin mukaisilla tavoilla. Kehittäjäkokemus ja käyttökohteet eivät ole aivan täysin samat, mutta ei tarvitsekkaan olla. WordPress taipuu kuitenkin äärimmäisen moniin käyttötarkoituksiin tarjoten ketterän tavan toteuttaa verkkosivustoja ja sovelluksia.

Toivon hyvin lujasti, että opit tästä kirjoituksesta jotain ja ehkä se myös avasi silmiä WordPressiin liittyvistä mahdollisuuksista. Monesti WordPress mielletään no-code alustaksi, mutta todellisuudessa se on myös paljon enemmän ja käytännössä sana WordPress ei vielä kerro yhtään mitään sivuston toteutuksesta. Keskustelen aiheesta mieluusti lisää, jos sinulla tuli asiaan liittyviä ajatuksia tai kommentteja. Kiitos, että luit ja näkemiin!

Jaa kirjoitus