Gutenberg is de standaard editor voor WordPress. Met de editor kun je inhoud maken en stylen met behulp van afzonderlijke blokken voor tekst, afbeeldingen, video en andere site-elementen via een drag-and-drop interface. Deze aanpak vergroot de flexibiliteit en ontwerpmogelijkheden van WordPress.

Deze handleiding legt uit hoe je Gutenberg inhoud als HTML kunt parsen met behulp van de WordPress REST API in een statische Next.js site.

Vereisten

Om mee te kunnen volgen, heb je nodig:

Gutenberg inhoud ophalen met behulp van een REST API

Om programmatisch te communiceren met je WordPress site en inhoud op te halen die is gestructureerd in Gutenberg blokken, gebruik je de WordPress REST API of de WPGraphQL plugin. Met deze tools kun je je WordPress inhoud ophalen in JSON format.

Om JSON gegevenstoegang via de REST API mogelijk te maken, pas je de instellingen van je WordPress permalink aan, weg van “Gewoon” Hierdoor krijg je toegang tot de API via een gestructureerde URL, zoals hieronder:

https://yoursite.com/wp-json/wp/v2

Door API verzoeken te doen aan deze URL, kun je programmatisch verschillende informatie ophalen en bewerkingen uitvoeren op je WordPress site. Je kunt bijvoorbeeld een lijst met berichten ophalen door een GET verzoek te sturen naar:

https://yoursite.com/wp-json/wp/v2/posts

Dit retourneert een JSON object met informatie over de berichten op je WordPress site, waaronder titels, inhoud, details van de auteur en meer.

Gutenberg blokken als HTML parsen

Bij het ophalen van berichten van een WordPress site die de Gutenberg editor gebruikt, kan de opgeslagen inhoud in de database een mix van HTML en JSON metadata bevatten om verschillende bloktypes te beschrijven, zoals citaten en galerijen. Bijvoorbeeld:

<!-- wp:quote {"className":"inspirational-quote","style":{"typography":{"fontSize":"large"}}} -->
<blockquote class="wp-block-quote inspirational-quote has-large-font-size"><p>“The journey of a thousand miles begins with one step.”</p><cite>Lao Tzu</cite></blockquote>
<!-- /wp:quote -->

<!-- wp:gallery {"ids":[34,35],"columns":2,"linkTo":"none","sizeSlug":"medium","className":"custom-gallery"} -->
<ul class="wp-block-gallery columns-2 is-cropped custom-gallery"><li class="blocks-gallery-item"><figure><img src="http://example.com/wp-content/uploads/2021/09/image1-300x200.jpg" alt="A breathtaking view of the mountains" class="wp-image-34"/></figure></li><li class="blocks-gallery-item"><figure><img src="http://example.com/wp-content/uploads/2021/09/image2-300x200.jpg" alt="Serene lakeside at dawn" class="wp-image-35"/></figure></li></ul>
<!-- /wp:gallery -->

Dit fragment illustreert twee Gutenberg blokken: een citaat en een galerij. Elk is aangevuld met JSON metagegevens die zijn ingekapseld in HTML-commentaren. De metadata definiëren attributen zoals klassenamen, stijlen en andere configuraties die relevant zijn voor de presentatie van het blok.

Wanneer je deze blokken ophaalt via de WordPress REST API of WPGraphQL, verwerkt WordPress ze en transformeert de combinatie van HTML en JSON metadata in volledig gerenderde HTML elementen die je direct in webpagina’s kunt opnemen. De getransformeerde HTML voor de bovenstaande blokken zou er als volgt uitzien:

<blockquote class="wp-block-quote inspirational-quote has-large-font-size"><p>“The journey of a thousand miles begins with one step.”</p><cite>Lao Tzu</cite></blockquote>

<ul class="wp-block-gallery columns-2 is-cropped custom-gallery">
  <li class="blocks-gallery-item"><figure><img loading="lazy" src="http://example.com/wp-content/uploads/2021/09/image1-300x200.jpg" alt="A breathtaking view of the mountains" class="wp-image-34" sizes="(max-width: 300px) 100vw, 300px" /></figure></li>
  <li class="blocks-gallery-item"><figure><img loading="lazy" src="http://example.com/wp-content/uploads/2021/09/image2-300x200.jpg" alt="Serene lakeside at dawn" class="wp-image-35" sizes="(max-width: 300px) 100vw, 300px" /></figure></li>
</ul>

Voor developers die ontkoppelde of headless toepassingen bouwen met behulp van JavaScript frameworks zoals Next.js, is dit een eenvoudige methode om inhoud weer te geven door de HTML direct in de pagina te injecteren met behulp van de property dangerouslySetInnerHTML om de opmaak weer te geven.

<div dangerouslySetInnerHTML={{ __html: <raw_html_string> }} />

Daarnaast moet je misschien verdere opmaak uitvoeren voor elementen zoals links en omgaan met overtollige newline-tekens (\n), wat later in deze handleiding wordt uitgelegd.

De inhoud van Gutenberg-blokken parsen in een statische site Next.js

In dit gedeelte gaan we WordPress content ophalen in een Next.js project en vervolgens de Gutenberg blokken als HTML parsen.

  1. Begin met het instellen van een functie om berichten van je WordPress site op te halen. Open het bestand src/page.js in je project en vervang de inhoud door het volgende codefragment:
    const getWpPosts = async () => {
    	const res = await fetch('https://yoursite.com/wp-json/wp/v2/posts');
      	const posts = await res.json();
    	return posts;
    };

    Deze asynchrone functie voert een API verzoek uit naar de WordPress REST API. Het haalt alle berichten op die beschikbaar zijn op je site en stuurt ze terug als een array.

  2. Laten we vervolgens de opgehaalde berichten gebruiken in een eenvoudige Next.js paginacomponent door de berichten naar de console te loggen en een basisbegroeting weer te geven:
    const page = async () => {
      const posts = await getWpPosts();
      console.log(posts);
      
      return (
        <div>
          <h1>Hello World</h1>
        </div>
      );
    };
    
    export default page;

    Wanneer je je project uitvoert met npm run dev, wordt het bericht “Hello World” weergegeven en worden de opgehaalde berichten naar de Terminal gelogd.

    [
      {
        "_links" : {
          "about" : [...],
          "author" : [...],
          "collection" : [...],
          "curies" : [...],
          "predecessor-version" : [...],
          "replies" : [...],
          "self" : [...],
          "version-history" : [...],
          "wp:attachment" : [...],
          "wp:term" : [...]
        },
        "author" : 1,
        "categories" : [...],
        "comment_status" : "open",
        "content" : {
          "protected" : false,
          "rendered" : "\n<p>Fire, a primal force, captivates with its <strong>flickering flames</strong>, evoking both awe and caution. Its <quote>dance</quote> symbolizes destruction and renewal, consuming the old to make way for the new. While it warms our homes and hearts, fire demands respect for its power to devastate.</p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"250\" height=\"148\" src=\"https://img.example.com/wp-content/uploads/2024/02/burningbuilding.jpg\" alt=\"\" class=\"wp-image-14\"/></figure>\n\n\n\n<p>In ancient times, fire was a beacon of light and warmth, essential for survival. Today, it remains a symbol of human ingenuity and danger. From the comforting glow of a hearth to the destructive fury of wildfires, fire’s dual nature reminds us of our fragile relationship with the elements.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https://img.example.com/premium-photo/painting-burning-building-illuminated-by-bright-flames-night_168058-249.jpg?w=1380\" alt=\"\"/></figure>\n\n\n\n<p>You can check out other articles on our blog:</p>\n\n\n\n<ul>\n<li><a href=\"https://yoursite.com/?p=6\">Lorem Ipsum: Beginnings</a></li>\n\n\n\n<li><a href=\"https://yoursite.com/?p=9\">Lorem Ipsum: Act 2</a></li>\n\n\n\n<li><a href=\"https://yoursite.com/?p=11\">Lorem Ipsum: Act 3</a></li>\n</ul>\n"
        },
        "date" : "2024-02-27T12:08:30",
        "date_gmt" : "2024-02-27T12:08:30",
        "excerpt" : {
          "protected" : false,
          "rendered" : "<p>Fire, a primal force, captivates with its flickering flames, evoking both awe and caution. Its dance symbolizes destruction and renewal, consuming the old to make way for the new. While it warms our homes and hearts, fire demands respect for its power to devastate. In ancient times, fire was a beacon of light and warmth, […]</p>\n"
        },
        "featured_media" : 0,
        "format" : "standard",
        "guid" : {
          "rendered" : "https://yoursite.com/?p=13"
        },
        "id" : 13,
        "link" : "https://yoursite.com/?p=13",
        "meta" : {
          "footnotes" : ""
        },
        "modified" : "2024-02-29T16:45:36",
        "modified_gmt" : "2024-02-29T16:45:36",
        "ping_status" : "open",
        "slug" : "fire-fire",
        "status" : "publish",
        "sticky" : false,
        "tags" : [],
        "template" : "",
        "title" : {
          "rendered" : "Fire"
        },
        "type" : "post"
       },
      },
      ...
    ]

    De JSON objecten die individuele Gutenberg berichtdata vertegenwoordigen, bevatten verschillende velden, waaronder de velden inhoud en excerpt die worden geretourneerd als Gutenberg blokken die zijn geparst als HTML strings.

  3. Om deze HTML inhoud correct weer te geven in Next.js, gebruiken we de property dangerouslySetInnerHTML:
    const page = async () => {
      const posts = await getWpPosts();
    
      return (
        <>
          <h1> Headless Blog </h1>
    
          <div>
            {posts.map((post) => (
              <Link href={'/blog/' + post.id} key={post.id}>
                <h2>
                  {post.title.rendered} <span>-></span>
                </h2>
                <div dangerouslySetInnerHTML={{ __html: post.excerpt.rendered }} />
              </Link>
            ))}
          </div>
        </>
      );
    };
    
    export default page;

    In dit bijgewerkte component mappen we over de opgehaalde posts array om een lijst van post uittreksels te genereren. Elk uittreksel is verpakt in een Link component voor navigatie, die de titel van het bericht en een stukje van de inhoud weergeeft.

    De property dangerouslySetInnerHTML wordt gebruikt om de HTML inhoud in het veld excerpt.rendered te parsen en te renderen.

  4. Maak vervolgens een bestand blog/[id]/page.js in de app directory. Je gebruikt mappen om routes te definiëren. Dus door een blogmap te maken, definieer je de blogroute. Je combineert dit met dynamische routing om routes te genereren voor elke post.
  5. Elke post heeft een ID. Je gebruikt deze ID om zijn unieke route te genereren, /blog/{post_id}in je applicatie. Voeg de volgende code toe:
    import Link from 'next/link';
    
    export async function generateStaticParams() {
        const res = await fetch('https://yoursite.com/wp-json/wp/v2/posts');
        const posts = await res.json();
        return posts.map((post) => {
            return {
                params: {
                    id: post.id.toString(),
                },
            };
        });
    }
    
    export async function getPost(id) {
        const response = await fetch('https://yoursite.com/wp-json/wp/v2/posts/' + id);
        const post = await response.json();
        return post;
    }

    De generateStaticParams() functie genereert statisch routes tijdens het bouwen op basis van de overeenkomstige ID die bij elke post wordt geretourneerd. De functie getPost() haalt Gutenberg gegevens op uit de REST API voor het bericht met een doorgegeven ID.

    Een eerdere sectie toonde een voorbeeld van Gutenberg gegevens die zijn teruggestuurd uit de REST API voor een bericht. Op dit moment houden we ons alleen bezig met het veld content.rendered:

    [
      {
        ...
        "content": {
          "rendered" : "\n<p>Fire, a primal force, captivates with its <strong>flickering flames</strong>, evoking both awe and caution. Its <quote>dance</quote> symbolizes destruction and renewal, consuming the old to make way for the new. While it warms our homes and hearts, fire demands respect for its power to devastate.</p>\n\n\n\n<figure> class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"250\" height=\"148\" src=\"https://img.example.com/wp-content/uploads/2024/02/burningbuilding.jpg\" alt=\"\" class=\"wp-image-14\"/></figure>\n\n\n\n<p>In ancient times, fire was a beacon of light and warmth, essential for survival. Today, it remains a symbol of human ingenuity and danger. From the comforting glow of a hearth to the destructive fury of wildfires, fire’s dual nature reminds us of our fragile relationship with the elements.</p>\n\n\n\n<figure> class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https://img.example.com/premium-photo/painting-burning-building-illuminated-by-bright-flames-night_168058-249.jpg?w=1380\" alt=\"\"/></figure>\n\n\n\n<p>You can check out other articles on our blog:</p>\n\n\n\n<ul>\n<li><a> href=\"https://yoursite.com/?p=6\">Lorem Ipsum: Beginnings</a></li>\n\n\n\n<li><a> href=\"https://yoursite.com/?p=9\">Lorem Ipsum: Act 2</a></li>\n\n\n\n<li><a> href=\"https://yoursite.com/?p=11\">Lorem Ipsum: Act 3</a></li>\n</ul>\n"
        },
        ...
      }
    ]

    Dit veld bevat de ruwe HTML van de post. Het kan direct worden gerenderd met behulp van de dangerouslySetInnerHTML property zoals dit, <div dangerouslySetInnerHTML={{ __html: <raw_html_string> }} />.

  6. Vervolgens kun je de gegevens verwerken door interne links te parsen en het formaat van afbeeldingen aan te passen. Installeer het pakket html-react-parser om het parsen van tags te vereenvoudigen:
    npm install html-react-parser --save
  7. Voeg de volgende code toe aan het bestand blog/[id]/page.js:
    import parse, { domToReact } from "html-react-parser";
    
    /*
     * We use a regular expression (pattern) to match the specific URL you want to replace.
     * The (\d+) part captures the numeric ID after ?p=.
     * Then, we use the replacement string 'data-internal-link="true" href="/blog/$1"',
     * where $1 is a placeholder for the captured ID.
     */
    export function fixInternalLinks(html_string) {
      const pattern = /href="https:\/\/yoursite.com\/\?p=(\d+)"/g;
      const replacement = 'data-internal-link="true" href="/blog/$1"';
    
      return html_string.replace(pattern, replacement);
    }
    
    export function parseHtml(html) {
      // Replace 2+ sequences of '\n' with a single '<br />' tag
      const _content = html.replace(/\n{2,}/g, '<br />');
      const content = fixInternalLinks(_content);
    
      const options = {
        replace: ({ name, attribs, children }) => {
          // Convert internal links to Next.js Link components.
          const isInternalLink =
            name === "a" && attribs["data-internal-link"] === "true";
    
          if (isInternalLink) {
            return (
              <Link href={attribs.href} {...attribs}>
                {domToReact(children, options)}
              </Link>
        	  );
          } else if (name === "img") {
            attribs["width"] = "250";
            attribs["height"] = "150";
            return (
              <img {...attribs}/>
            );
          }
        },
      };
    
      return parse(content, options);
    }

    De fixInternalLinks() functie gebruikt een reguliere expressie om links naar berichten op je WordPress site te vinden in de HTML string. In de ruwe HTML kun je zien dat het bericht een List tag bevat met links naar andere berichten op je site, waarbij die links worden vervangen door interne links naar routes op je statische site.

    De functie parseHTML() vindt meerdere reeksen van overtollige newlines, nen vervangt ze door <br /> tags. Het vindt ook interne links en zet de anchor tags om in Link tags. Vervolgens past deze functie de grootte van afbeeldingen aan met behulp van tag-attributen.

  8. Om de hoofd UI voor elke dynamische route te genereren, voeg je de volgende code toe:
    export default async function Post({ params }) {
      const post = await getPost(params.id);
    
      const content = parseHtml(post.content.rendered);
    
      return (
        <>
          <h1>
            {post.title.rendered}
          </h1>
     	 
          <div>{content}</div>
        </>
      );
    }

    Na het parsen van de ruwe HTML uit de Gutenberg gegevens, retourneert de code JSX die de opgemaakte UI van de pagina weergeeft.

Tot slot, wanneer je je project uitvoert, zal de startpagina een lijst met berichten op je WordPress weergeven. Als je op individuele berichten klikt, zie je ook de inhoud van Gutenberg op de juiste manier weergegeven.

Deploy je Next.js statische site op Kinsta

Wanneer je headless WordPress combineert met geavanceerde frameworks zoals Next.js, wordt het vinden van een kosteneffectieve deployment-oplossing, vooral wanneer je een krachtige WordPress Hosting zoals die van Kinsta gebruikt voor je WordPress site. De Statische Site Hosting service van Kinsta biedt een naadloze en betaalbare manier om je site online te brengen.

Met Kinsta kun je tot 100 statische websites gratis hosten. Eerst push je je code naar een Git provider van je voorkeur (Bitbucket, GitHub of GitLab). Zodra je repo klaar is, volg je deze stappen om je statische site te deployen naar Kinsta:

  1. Log in of maak een account aan om je MyKinsta dashboard te bekijken.
  2. Autoriseer Kinsta met je Git provider.
  3. Klik op Statische sites op de linker zijbalk, klik dan op Site toevoegen.
  4. Selecteer de repository en de branch van waaruit je wilt deployen.
  5. Geef je site een unieke naam.
  6. Voeg de bouwinstellingen toe in het volgende format:
    • Build commando: npm run build
    • Node versie: 18.16.0
    • Publish directory: out
  7. Klik ten slotte op Maak site.

En dat is het! Je hebt nu binnen een paar seconden een uitgerolde site. Je krijgt een link waarmee je naar de geïmplementeerde versie van je site kunt gaan. Als je wilt, kun je later je eigen domein en SSL certificaat toevoegen.

Als alternatief voor statische site hosting kun je ervoor kiezen om je statische site te implementeren met Kinsta’s Application Hosting service, die meer flexibiliteit biedt bij het hosten, een breder scala aan voordelen en toegang tot robuustere functies – zoals schaalbaarheid, aangepaste implementatie met behulp van een Dockerfile en uitgebreide analyses met real-time en historische gegevens. Je hoeft je Next.js project ook niet te configureren voor statische rendering.

Samenvatting

Deze handleiding heeft uitgelegd hoe je Gutenberg blokinhoud effectief kunt integreren en parsen als HTML via de WordPress API. Dit maakt het renderen van elk type content op je front-end mogelijk wanneer je headless WordPress gebruikt.

Je kunt je headless WordPress hosten op onze managed WordPress Hosting service en je statische site inzetten op onze Statische Site Hosting service. Dit betekent dat alles over je site in één dashboard staat: MyKinsta.

Door voor Kinsta te kiezen, profiteer je van een hostingprovider die prioriteit geeft aan optimale siteprestaties en schaalbaarheid, terwijl websites sterk worden versterkt met geavanceerde beveiligingsmaatregelen. Probeer Kinsta vandaag nog!

Wat vind jij van headless WordPress en de rendering ervan? Heb je een betere manier om Gutenberg blokken te integreren? Deel je ideeën in de commentsectie!

Jeremy Holcombe Kinsta

Content & Marketing Editor at Kinsta, WordPress Web Developer, and Content Writer. Outside of all things WordPress, I enjoy the beach, golf, and movies. I also have tall people problems ;).