Nouveaux CMS, nouveaux process, nouvelles librairies; c’est facile de se sentir « en retard » dans les métiers du développement. Rien de plus gratifiant que de sentir qu’on est dans le bon courant… mais il est toujours bon de s’assurer d’y trouver son compte.

Apprendre un CMS est toujours très utile, et c’est souvent une étape incontournable lorsque l’on commence à travailler en agence ou en freelance. Personnellement, j’ai été de l’école de WordPress – rien de bien extravagant donc. J’ai découvert le CMS pendant mes années à l’université, avant de l’adopter au quotidien pour les projets clients (surtout en alternance).

L’idée de ce post n’est pas de louer les avantages de WordPress mais bien de mettre en lumière quelques-unes de ses limites; ce qui servira d’introduction pour ensuite mieux comprendre pourquoi j’ai fini par « aller voir ailleurs ».


Premièrement, quand on développe un thème sur-mesure avec WordPress, on signe à l’entrée pour développer selon l’architecture de… WordPress. Logique, vous allez me dire. Sauf qu’ici, on parle d’une architecture un peu vieillissante, un site tout en PHP, ou encore un scaffolding de projet qui donne la nausée dès que le projet prend de l’envergure.

Alors oui, on peut très vite me répondre sur ces sujets en dégainant tout un tas de solutions: « Avec Bedrock, le scaffolding du projet est totalement revu, toute l’installation et les plugins sont gérés avec Composer, et on peut facilement déployer le site en production… »
« Sans parler de Sage, avec lequel on a une meilleure organisation du thème, un accès aux templates Blade et à leur syntaxe, ou encore une super intégration de Webpack… »

Le truc, c’est que si je pointe du doigt une architecture vieillissante et un scaffolding qui me donne la nausée, je ne sais pas comment réagir face à une nouvelle couche supplémentaire qui se rajoute, et un scaffolding qui, cette fois, me donne le vertige. Des sous-dossiers dans tous les sens, une nouvelle doc à apprendre, et une impression de « repartir de zéro ».

Et puis, au détour d’une conversation avec mon chef de projet, il m’explique que WordPress a sa propre API. Une API qui contient les articles, custom post types, pages… tout, en fait. L’intégralité de son contenu accessible sur un endpoint; et les possibilités deviennent alors immenses: combiner du WordPress avec une architecture plus moderne (pourquoi pas React? Vue?). Et puis, en quelques recherches, je découvre qu’il existe même des CMS dits « API-first », qui sont spécialement conçus pour qu’un client consomme leur API. Un tout nouveau monde s’ouvre à moi en l’espace d’une discussion et de quelques clics.

Dès lors, je savais comment serait développé mon futur portfolio – celui sur lequel vous vous trouvez en ce moment.


J’ai fais le choix de rester sur WordPress puisque je connaissais déjà le back-office et la mise en place. Tout ce qu’il me restait à faire, c’était choisir entre utiliser l’API REST ou GraphQL, ainsi qu’un environnement de développement. Par souci de performance, j’ai tendance à penser que GraphQL est plus optimisé car on peut y écrire des requêtes très précises en ne pointant que certains « nœux » plutôt que de fetch() toute l’API;

query allPostsQuery {
  posts {
    nodes {
      id
      title
      date
      slug
      uri
      featuredImage {
        node {
          sourceUrl
          altText
        }
      }
    }
  }
}

Ensuite, le choix de la techno. En novembre 2020, j’apprenais à utiliser Vue.js et je développais mon premier projet avec (DVNTS.STUDIO); et depuis j’avais envie d’un second service avec ce framework – j’aime beaucoup l’environnement de dev et la syntaxe proposée par Vue! – et en faisant quelques recherches, je suis tombé sur un article détaillant tout le process pour faire du WordPress headless avec Nuxt (une stack supplémentaire pour Vue.js). Mon choix était fait!

Pour interagir avec l’API GraphQL de WordPress, il me manquait encore quelques éléments. Déjà, un accès concret à l’API WordPress: pour ça, une simple installation de WPGraphQL et c’était parti. Le plugin a une doc assez complète, et paraît plutôt actif.
Ensuite, un client pour interagir entre l’API et mon template. Là, les docs me redirigent très vite vers Apollo qui semble être la référence.


Le résultat m’a semblé très convaincant: la requête Apollo nous retourne un tableau contenant la donnée (ici, des projets) qui sont stockés dans l’instance Vue grâce au hook data(). Le vocabulaire est un peu barbare, mais il faut simplement comprendre par là qu’on a besoin de créer un tableau vide pour ensuite le remplir, une fois que la requête est effectuée: ainsi on a accès à notre variable d’instance au sein du template, et on peut donc boucler dessus, effectuer du rendu conditionnel, etc.

<div class="FeaturedProjects__wrapper">
  <NuxtLink
    :to="{ name: 'projets-id', params: { id: project.slug } }"
    v-for="project in projects"
    :key="project.id"
    class="ProjectCard"
  >
  <h2>{{ project.name }}</h2>
  <span>{{ project.date }}</span>
  </NuxtLink>
</div>

<script>
import { allProjectsQuery } from '~/plugins/graphql/allProjects'

export default {
  data() {
    return {
      projects: {},
    }
  },

  async fetch() {
    this.projects = await this.$apollo.query({ query: allProjectsQuery })
    this.projects = this.projects.data.projects.nodes
  },
}
</script>

Et… cela ne fonctionne pas. On me retourne une erreur comme quoi project.date n’est pas défini. Alors on reprend de la base: afficher l’intégralité de la data retournée dans projects… ça fonctionne. Mais dès que je rentre plus précisément à l’intérieur de projects, il n’y a plus moyen.

Je ne suis pas sûr de mon coup, mais il semble que cela vienne du comportement asynchrone de la requête: il semblerait que l’on tente d’afficher un noeud (projet.date) avant qu’il aie été fetched (si ça se trouve, il est fetched quelques microsecondes après qu’on souhaite l’afficher). Et ce problème risque d’arriver de plus en plus souvent à mesure qu’on fait des requêtes sur des nœuds enfouis profondément dans l’arborescence.

J’ai essayé pas mal de tricks pour régler le souci, mais la seule solution que j’ai trouvé pour le moment est d’utiliser une variable en guise de chargement et d’attendre que celle-ci change d’état avant d’afficher la donnée pour s’assurer que la data est prête.

<div class="FeaturedProjects__wrapper" v-if="!loading">
  ...
</div>

<script>
export default {
  data() {
    return {
      ...
      loading: true
    }
  },

  ...

  async fetch() {
    ...
    this.loading = false
  },
}
</script>

Et… ça fonctionne! GraphQL offre de très bonnes performances, et je trouve que le client Apollo s’intègre parfaitement avec Vue/Nuxt. Plus besoin d’utiliser toute l’arborescence WordPress, son scaffolding imposé, et sa base PHP. S’ouvre alors à nous un vaste champ de possibles, puisqu’on peut query à peu près tout ce qu’on veut – et même ajouter des extensions à WordPress pour supporter ACF, Gravity Forms…


La solution à tout?

Bien sûr, ça ne peut pas s’arrêter là – d’abord ce serait un peu fainéant. Et puis, cette solution d’utiliser l’API GraphQL WordPress reste une solution encore embryonnaire; au sens où une fois de plus, la communauté essaie de bidouiller et créer des moyens pour détourner un outil de son usage premier. WordPress est un CMS plutôt conçu pour du blog, à la base. Cela n’empêche que c’est une très bonne solution utilisée partout dans le monde pour sa versatilité, mais je ne peux m’empêcher de… « continuer à aller voir ailleurs ».

Comme je l’ai noté au début, des CMS API-first seraient peut-être mieux adaptés (Sanity, Strapi, Kirby…). Ils sont bien souvent payants contrairement à WordPress, mais j’ai espoir qu’ils soient moins « usine à gaz » et plus confortables aussi bien côté utilisateur que côté dev. C’est donc vers ces solutions que je vais maintenant me tourner; et assurez-vous que je vous partagerai mon retour d’expérience après les avoir utilisés… peut-être même avec d’autres technos!

Alors c’est reparti pour un tour.