API

Routes HTTP d'admin et publiques, et fonctions serveur importables pour lire des posts sans aller-retour HTTP.

Le module expose ses posts de deux façons : des routes HTTP pour le navigateur, et des fonctions serveur pour les composants et scripts qui tournent dans le même processus.

Règle absolue : depuis un Server Component, un bloc ou un sitemap.js, ne jamais appeler les routes HTTP avec fetch. C'est un aller-retour réseau vers le processus courant. Importer les fonctions serveur.

Import

Sous-cheminRuntimeContenu
@lrvo/module-postsserveurmanifest, register, createTables, dropTables.
@lrvo/module-posts/publicserveurLes quatre fonctions de lecture ci-dessous, plus les adaptateurs du registre.
@lrvo/module-posts/clientclientEnregistrement de la page d'admin. Aucun export.

Le sous-chemin public exporte aussi resolvePostPublic, resolvePostMetadata et une vue par défaut PostPublicView({ postType, slug }). Ces trois-là servent le registre de contenu public, que le module alimente lui-même au boot : un projet n'a normalement pas à les toucher.

import { getPublicPosts, getPublicPostBySlug } from '@lrvo/module-posts/public';

Il n'existe aucun autre point d'entrée. Le CRUD d'admin, le parseur de configuration et le registre de templates ne sont pas exposés, et un import profond dans dist/ n'est pas une voie supportée.

API

SignatureRetourDescription
getPublicPosts(postType, options?)Promise<{ posts, pagination }>Liste paginée des posts publics d'un type.
getPublicPostBySlug(postType, slug)Promise<Post | null>Un post public par son slug.
getPublicTaxonomyTerms(postType, taxonomy)Promise<Term[]>Termes actifs d'une taxonomie.
getPublicPostsConfig()ConfigConfiguration des types, champs privés retirés.

Ces quatre fonctions filtrent sur la visibilité publique et retirent les champs privés. Elles ne vérifient aucune permission : elles servent le rendu public. Ne pas les exposer telles quelles dans une route sans contrôle d'accès.

getPublicPosts(postType, options?)

Renvoie { posts, pagination } où pagination porte page, limit, total et totalPages.

options accepte page (1 par défaut), limit (20), search, sortBy, sortOrder, withRelations, et un filtre par taxonomie de la forme taxonomy_<clé>.

search est la seule option que la route HTTP publique n'expose pas. Elle applique une recherche insensible à la casse sur le champ de titre, et sur lui seul.

Un type inconnu ne lève pas : la fonction renvoie une liste vide et une pagination à zéro.

import { getPublicPosts } from '@lrvo/module-posts/public';

const { posts, pagination } = await getPublicPosts('blogue', {
  limit: 12,
  taxonomy_categories: 3,
});

Le tri par défaut dépend du type : la colonne d'ordre en ascendant si le type est réordonnable, la date de création en descendant sinon.

sortBy accepte trois formes : le nom d'un champ déclaré, auquel cas le tri porte sur sa valeur avec le typage adapté pour date et datetime ; le jeton order, qui trie sur la colonne d'ordre et n'a d'effet que si le type est réordonnable ; ou l'un des noms de colonne created_at, updated_at et visibility. Une valeur inconnue retombe silencieusement sur la date de création.

withRelations charge les posts liés, au prix d'une requête par post. À réserver aux listes courtes.

getPublicPostBySlug(postType, slug)

Renvoie le post ou null, y compris quand il existe mais n'est pas public.

Ses champs editor sont enrichis de leurs métadonnées médias, donc directement rendables. Ses taxonomies, relations et parent sont résolus.

Ses champs média le sont aussi : image et thumbnail portent un objet { id, filename, alt_text, caption, mime_type }, gallery un tableau de ces objets dans l'ordre de la galerie. L'URL publique se construit à partir de filename, jamais stockée. Une référence dont le média a disparu apparaît comme { id, filename: null }.

import { getPublicPostBySlug } from '@lrvo/module-posts/public';

const post = await getPublicPostBySlug('blogue', 'mon-article');

La résolution est plate : elle interroge le slug seul, sans tenir compte de la hiérarchie. Pour un type hiérarchique, elle retrouve donc aussi bien un post racine qu'un post enfant.

getPublicTaxonomyTerms(postType, taxonomy)

Renvoie les termes actifs, triés par titre, sous la forme { id, title }. Un type ou une taxonomie inconnus renvoient une liste vide.

Utile pour construire un filtre de navigation, puis passer l'identifiant du terme à getPublicPosts.

getPublicPostsConfig()

Renvoie la configuration des types avec les champs privés retirés des listes de champs et de colonnes. Sert à un consommateur qui construit une interface générique, sans coder en dur la structure d'un type.

Routes HTTP

Toutes sont montées sous le préfixe /lrvo/api, comme le veut core/api.

Le type de post est toujours passé en paramètre de requête côté admin, et en segment d'URL côté public.

Admin

MéthodeCheminPermission
GET/admin/posts/configposts.view
GET/admin/posts/templatesposts.view
GET/admin/posts/postsposts.view
POST/admin/posts/postsposts.manage
PUT/admin/posts/postsposts.manage
DELETE/admin/posts/postsposts.manage
POST/admin/posts/posts/reorderposts.manage
GET/admin/posts/searchposts.view
GET/admin/posts/taxonomiesposts.view
POST/admin/posts/taxonomiesposts.manage
PUT/admin/posts/taxonomiesposts.manage
DELETE/admin/posts/taxonomiesposts.manage

GET /admin/posts/posts sert trois usages selon les paramètres : avec id ou slug, il renvoie un post unique ; sans, il renvoie une liste paginée acceptant page, limit, search, sortBy, sortOrder, withRelations et les filtres taxonomy_<clé>.

GET /admin/posts/config renvoie la configuration complète, champs privés compris. C'est ce qui permet au formulaire d'admin de les éditer.

POST /admin/posts/posts/reorder attend { parentId, ids } et refuse tout identifiant hors de la fratrie visée.

GET /admin/posts/search alimente les sélecteurs de relation et de parent. Elle accepte q et limit, et ne renvoie que id, slug, parent_id et le titre.

Les routes de taxonomies exigent toujours type et taxonomy, validés contre la configuration.

Public

MéthodeCheminContenu
GET/posts/configConfiguration des types, champs privés retirés.
GET/posts/:type/taxonomies/:taxonomyTermes actifs de la taxonomie.
GET/posts/:type/:slugUn post public.
GET/posts/:typeListe paginée des posts publics du type.

L'ordre de déclaration compte : le routeur du core retient la première correspondance, sans préférer un segment fixe à un paramètre. La route des taxonomies est donc déclarée avant celle du slug, sans quoi taxonomies serait pris pour un slug.

GET /posts/:type accepte page, limit, sortBy, sortOrder, withRelations et les filtres taxonomy_<clé>. Elle n'accepte pas search, contrairement à son équivalent d'admin.

Toutes les réponses passent par le retrait des champs privés et de visibility.

Notes

  • Les routes d'admin vérifient la permission avant d'atteindre le handler. Ne jamais court-circuiter cette vérification.
  • Un module activé sans type déclaré enregistre quand même ses routes. Elles répondent alors en erreur sur tout type, puisqu'aucun n'est connu. Un module désactivé, lui, n'enregistre rien : il n'apparaît pas dans le manifeste généré par lrvo-modules sync.
  • Les deux familles de routes ne codent pas les erreurs de la même façon. Côté admin, un type ou une taxonomie inconnus remontent en 400, comme un slug invalide, un parent inexistant ou un cycle dans la hiérarchie ; seul un post ou un terme absent remonte en 404. Côté public, un type ou une taxonomie inconnus remontent en 404, au même titre qu'un post absent : rien ne distingue une ressource inexistante d'une ressource non exposée.
  • GET /posts/:type/:slug ne vérifie pas que le post est à la racine du type, alors que le rendu HTML le fait. Un post enfant est donc lisible par cette route à une URL que la page publique refuse. À garder en tête pour un consommateur externe.

Sur cette page