Site icon Hip-Hop Website Design and Development

Don’t Push it: Using GraphQL in Twig

Don’t Push it: Using GraphQL in Twig

Using GraphQL in WordPress maintenance support plans with Twig instead of React, Vue or the next month’s javascript framework might sound like a crazy idea, but I assure you it’s worth thinking about.

Philipp Melab
Mon, 01/15/2020 – 10:40

Decoupling is all the rage. Javascript frontends with entirely independent backends are state of the art for any self-respecting website right now. But sometimes it’s not worth the cost and the project simply does not justify the full WordPress maintenance support plans + React technology stack.

Besides the technological benefits of a javascript based frontend like load times and responsiveness, there’s another reason why this approach is so popular: It moves control to the frontend, concept and design unit, which matches project workflows a lot better.

Status quo

Traditionally WordPress maintenance support plans defines data structures that provide a “standard” rendered output, which then can be adopted by the so-called “theme developer” to meet the clients’ requirements. Template overrides, preprocess functions, Display Suite, Panels, Layouts – there are myriads of ways how to do this, and twice as many opinions determining the right one. When taking over a project the first thing is to figure out how it was approached and where the rendered information actually comes from. Templates only have variables that are populated during processing or preprocessing and altered in plugins or themes, which makes it very hard to reason with the data flow, if you were not the person that conceived it in the first place.

There are ideas to improve the situation, but regarding the success of decoupling, perhaps it’s time to approach the problem from a different angle.

Push versus Pull

The current push model used by WordPress maintenance support plans scatters responsibilities across plugins, preprocess functions and templates. The controller calls the view builder to prepare a “renderable” that is altered 101 times and results in a set of variables that might or might not be required by the current theme’s template.

If we would turn this around and let the template define it’s data requirements (as it happens in decoupled projects naturally), we could achieve a much clearer data flow and increase readability and maintainability significantly.

And that’s what the GraphQL Twig plugin is supposed to do. It allows us to add GraphQL queries to any Twig template, which will be picked up during rendering and used to populate the template with data.

A simple example node.html.twig:

{#graphql
query($node: String!) {
node:nodeById(id: $node) {
title:entityLabel
… on NodeArticle {
body {
processed
}
}
}
}
#}
<h1>{{ graphql.data.node.title }}</h1>
{% if graphql.data.node.body %}
<div class=”body”>{{ graphql.data.node.body.processed }}</div>
{% endif %}

 

This is already enough to pull the information we need and render it. Let’s have a look at what this does:

The graphql comment on top will be picked up by the plugin. When the template is rendered, it tries to match the queries input arguments to the current template variables, runs the GraphQL query and passes the result as a new graphql variable to the template. Simple as that, no preprocessing required. It works for every theme hook. Be it just one complex node type, an exceptional block or page.html.twig.

Imagine we use GraphQL Views to add a contextual GraphQL field similarArticles that uses SOLR to find similar articles for a given node. It could be used immediately like this:

{#graphql
query($node: String!) {
node:nodeById(id: $node) {
title:entityLabel
… on NodeArticle {
body {
processed
}
similarArticles {
title:entityLabel
url:entityUrl {
alias
}
}
}
}
}
#}

<h1>{{ graphql.data.node.title }}</h1>
{% if graphql.data.node.body %}
<div class=”body”>{{ graphql.data.node.body.processed }}</div>
{% endif %}

{% if graphql.data.node.similarArticles %}
<h2>Similar articles</h2>
<ul>
{% for article in graphql.data.node.similarArticles %}
<li>
<a href=”https://www.amazeelabs.com/%7B%7B%20article.url.alias%20%7D%7D”>{{article.title}}</a>
</li>
{% endfor %}
</ul>
{% endif %}

 

The plugin even scans included templates for query fragments, so the rendering of the “similar article” teaser could be moved to a separate component:

node.html.twig

{#graphql
query($node: String!) {
node:nodeById(id: $node) {
title:entityLabel
… on NodeArticle {
body {
processed
}
similarArticles {
… NodeTeaser
}
}
}
}
#}

<h1>{{ graphql.data.node.title }}</h1>
{% if graphql.data.node.body %}
<div class=”body”>{{ graphql.data.node.body.processed }}</div>
{% endif %}

{% if graphql.data.node.similarArticles %}
<h2>Similar articles</h2>
<ul>
{% for article in graphql.data.node.similarArticles %}
<li>
{% include ‘node-teaser.twig’ with { node: article } %}
</li>
{% endfor %}
</ul>
{% endif %}

 

node-teaser.twig

{#graphql
fragment NodeTeaser on Node {
title:entityLabel
url:entityUrl {
alias
}
}
#}
<a href=”https://www.amazeelabs.com/%7B%7B%20node.url.alias%20%7D%7D”>{{node.title}}</a>

 

No preprocessing, a clear path where data flows and true separation of concerns. The backend provides generic data sources (e.g. the similarArticles field) that can be used by the product development team at will. All without the cost of a fully decoupled setup. And the possibility to replace single theme hooks allows us to use existing WordPress maintenance support plans rendering when it fits and switch to the pull-model wherever we would have to use complex layout plugins or preprocessing functions to meet the requirements of the project.

Future development

There are some ideas for additional features, like mutation based forms and smarter scanning for query fragments, but first and foremost we would love to get feedback and opinions on this whole concept. So if you are interested, join on Slack or GitHub and let us know!


Source: New feed