Types et champs

Syntaxe de déclaration d'un type de contenu, catalogue des types de champs, drapeaux, champs privés et colonnes de liste.

Un type de contenu se déclare entièrement en variables d'environnement. Le module en dérive le formulaire d'édition, le tableau d'admin, les colonnes de tri, les routes publiques et le rendu.

Règle absolue : la déclaration est analysée une seule fois au démarrage du processus. Toute modification demande un redémarrage du serveur.

Déclarer un type

LRVO_MODULE_POSTS_TYPES=blogue:Blogue:Moon02Icon|cve:CVE

Les types sont séparés par |, leurs propriétés par :.

PositionPropriétéObligatoireDéfaut
1Clé du typeoui
2Libellé affichénonClé capitalisée, tirets et soulignés remplacés par des espaces.
3Icône de la section d'adminnonBook02Icon

La clé est systématiquement ramenée en minuscules. Elle sert de valeur à la colonne post_type, de premier segment d'URL publique, et de suffixe aux noms de variables. Une clé déclarée Blogue devient blogue partout.

Les icônes sont celles de la bibliothèque hugeicons, référencées par leur nom exact. Voir Design system.

Déclarer les champs d'un type

Le nom de la variable est dérivé de la clé du type, en majuscules :

LRVO_MODULE_POSTS_TYPE_BLOGUE=title:title|slug:slug|date:date:now:sidebar|content:editor:Contenu

Chaque champ suit la forme nom:type[:segment[:segment]]. Les champs sont séparés par |, les segments par :, et tous les segments sont détourés des espaces qui les entourent.

  • nom est l'identifiant du champ dans les données et dans l'API. Un champ sans nom est ignoré.
  • type doit appartenir au catalogue ci-dessous. Un type inconnu est silencieusement ramené à text, sans erreur ni avertissement. Une faute de frappe se voit donc au comportement du champ, pas au démarrage.
  • Les segments suivants portent le libellé et les drapeaux, dans n'importe quel ordre.

Catalogue des types de champs

TypeÉditionStockage
titleChamp texte en grande taille, en tête de formulaireDonnées JSON
slugChamp texte compact, dérivé du titre si laissé videColonne slug
textZone de texte multiligne, trois lignesDonnées JSON
linkChamp de saisie d'URLDonnées JSON
editorBlockEditor completDonnées JSON, tableau de blocs
dateSélecteur de dateDonnées JSON
datetimeSélecteur de date et heureDonnées JSON
colorSélecteur de couleurDonnées JSON
taxonomySélecteur de termesTable de liaison
imageSélecteur de média, image dans le corpsDonnées JSON, identifiant du média
thumbnailSélecteur de média, image de mise en avantDonnées JSON, identifiant du média
gallerySélecteur de médias, plusieurs images ordonnéesDonnées JSON, tableau d'identifiants
relationSélecteur d'autres postsTable de relations
parentSélecteur d'un post du même typeColonne parent_id
createdDate de création, modifiable après créationColonne created_at
updatedDate de modification, lecture seuleColonne updated_at
visibilityBascule public ou privéColonne visibility

Sept de ces types ne passent pas par les données JSON : slug, taxonomy, relation, parent, created, updated et visibility pilotent une colonne ou une table dédiée. Déclarer un champ de ce type revient à faire apparaître dans le formulaire un contrôle sur une donnée structurelle qui existe déjà.

Les champs média, eux, vivent bien dans les données JSON : c'est l'identifiant du média qui y est écrit, ou son tableau d'identifiants pour une galerie.

Le champ title

Sa valeur sert de source au slug quand celui-ci est laissé vide, de libellé dans les listes, les fils d'Ariane et les sélecteurs de relation, et de titre de repli pour les métadonnées.

Il est facultatif. Un type qui ne le déclare pas porte du contenu seul : une note, un encart, un bloc réutilisable. Comme pour slug et parent, c'est l'absence du champ qui fait l'interrupteur, pas un drapeau à poser.

LRVO_MODULE_POSTS_TYPE_NOTES=slug:slug|contenu:editor:Contenu|date:date:now:sidebar

Déclarer le champ le rend en revanche obligatoire à la saisie : le formulaire refuse un titre vide et l'enregistrement échoue avec Title field is required. Ce que vous choisissez, c'est d'avoir un titre ou non, pas de le laisser vide au cas par cas.

Un type sans titre change trois choses :

  • le slug, s'il est déclaré, n'a plus de source à laquelle se rattacher. Il est généré sous la forme post-<id> et reste modifiable à la main. Voir Modèle de données ;
  • la liste d'admin affiche un extrait du contenu à la place du titre. Voir Administration ;
  • les métadonnées publiques retombent sur le slug. Renseignez le titre SEO du post pour en donner un vrai.

Combiné à l'absence de slug, vous obtenez un type sans titre ni URL, consommé uniquement par l'API ou par une relation depuis un autre post.

LRVO_MODULE_POSTS_TYPE_ENCARTS=contenu:editor:Contenu

Le champ slug

Un type sans champ slug n'est jamais rendu publiquement. Le résolveur public refuse de traiter une URL pour un type dépourvu de ce champ, et le module ne lui construit aucun chemin.

C'est l'interrupteur qui distingue un type destiné au site d'un type purement interne, par exemple une liste de références utilisée uniquement par des relations.

Les règles de génération et d'unicité du slug sont dans Modèle de données.

Le champ created

Il expose created_at en écriture. La valeur soumise est refusée si elle n'est pas une date valide, et refusée si elle est dans le futur. Utile pour importer des archives ou antidater une publication.

Il n'est modifiable qu'après coup : la création ignore toute valeur soumise et laisse la base poser l'horodatage courant. Le contrôle n'apparaît donc pas dans le formulaire de création, seulement dans celui d'édition. Voir Administration.

Les champs image et thumbnail

Les deux ouvrent le sélecteur du registre média. La différence est d'intention : thumbnail désigne l'image de mise en avant d'un post, image une image quelconque dans ses données.

La valeur stockée est l'identifiant du média. À la lecture, le module l'enrichit en { id, filename, alt_text, caption, mime_type }. Une référence orpheline renvoie { id, filename: null } plutôt qu'une erreur.

Voir Intégrer les médias.

Plusieurs images dans un seul champ, ordonnées à la main.

LRVO_MODULE_POSTS_TYPE_BLOGUE=title:title|slug:slug|galerie:gallery:Galerie

Le champ n'accepte que des images. Le formulaire affiche les vignettes dans leur ordre, un glisser-déposer les réorganise, et le bouton d'ajout rouvre le sélecteur sur la sélection courante : cocher une image supplémentaire l'ajoute sans défaire ce qui était rangé, et décocher une image l'enlève. Le sélecteur téléverse plusieurs fichiers en une fois et ajoute d'office les médias créés à la sélection, dans l'ordre où la grille les présente.

Chaque vignette ouvre la fiche du média pour corriger son texte alternatif ou sa légende. Ces valeurs appartiennent au média, pas au post : les modifier ici les change partout où le média est utilisé.

La valeur stockée est un tableau ordonné d'identifiants. C'est ce tableau qui porte l'ordre de la galerie. À la lecture, le module l'enrichit en tableau d'objets { id, filename, alt_text, caption, mime_type }, dans le même ordre, et une entrée orpheline y apparaît comme { id, filename: null }.

Chaque image de la galerie produit sa propre ligne de référence, toutes sous le nom du champ. Un média retenu par une galerie ne peut donc pas être supprimé de la médiathèque tant qu'il y figure.

Une colonne gallery dans ..._LIST affiche les trois premières vignettes, puis le nombre d'images restantes.

Libellés et drapeaux

Après le nom et le type, chaque segment est soit un drapeau réservé, soit le libellé du champ.

DrapeauEffetTypes concernés
sidebarPlace le champ dans la colonne latérale de l'éditeur au lieu de la zone principale.Tous
nowPréremplit la date courante à la création.date, datetime
singleLimite la sélection à un seul terme.taxonomy
multiAutorise plusieurs termes. Comportement par défaut.taxonomy
seoDésigne le champ comme source de repli SEO du type. Voir Repli SEO automatique.text, editor, thumbnail, image

Ces cinq mots sont réservés : ils ne peuvent jamais être pris pour un libellé. Un champ dont le libellé devrait être Single doit être renommé.

Le libellé est le premier segment qui n'est pas un drapeau réservé. Absent, l'éditeur retombe sur le nom du champ, sauf pour taxonomy qui capitalise son nom.

# Champ texte, libellé « Résumé », placé dans la colonne latérale
resume:text:Résumé:sidebar

# Date préremplie, dans la colonne latérale, libellé dérivé du nom
date:date:now:sidebar

# Taxonomie à choix unique, libellé « Sévérité »
severity:taxonomy:Sévérité:single

# Chapeau désigné comme source de la méta description
chapeau:text:Chapeau:seo

L'ordre des segments après le type n'a pas d'importance : date:date:now:sidebar et date:date:sidebar:now sont équivalents.

Repli SEO automatique

Quand LRVO_SEO est actif et que la zone SEO d'un post est laissée vide, le module dérive la méta description et l'image de partage des champs du type. Le rédacteur n'a pas à recopier ce qu'il vient d'écrire, et la page publique n'est jamais publiée sans description ni carte sociale.

Méta description, dans l'ordre :

  1. Le champ text ou editor portant le drapeau seo.
  2. Le premier champ text dont la valeur atteint 70 caractères.
  3. Un extrait du premier champ editor renseigné.

Le résultat est tronqué à 160 caractères, sur une frontière de mot.

Image de partage, dans l'ordre :

  1. Le champ thumbnail ou image portant le drapeau seo.
  2. Le premier champ thumbnail renseigné.
  3. Le premier champ image renseigné.

Un champ gallery n'est jamais utilisé : rien ne dit que sa première image représente le post.

Le seuil de 70 caractères de l'étape 2 écarte les champs texte courts, qui ne sont pas des descriptions. Dans ce type :

LRVO_MODULE_POSTS_TYPE_BLOGUE=title:title|slug:slug|lecture:text:Temps de lecture|chapeau:text:Chapeau|thumbnail:thumbnail:Miniature:sidebar|content:editor:Contenu

lecture vaut « 5 min » et est ignoré ; c'est chapeau qui sert de description. Quand cette déduction se trompe, le drapeau seo la remplace :

LRVO_MODULE_POSTS_TYPE_BLOGUE=title:title|slug:slug|chapeau:text:Chapeau:seo|couverture:image:Couverture:seo|thumbnail:thumbnail:Miniature:sidebar|content:editor:Contenu

Un champ marqué seo gagne même si sa valeur est courte, et même si un autre champ le précède dans la déclaration.

Ces valeurs restent des replis. Une méta description ou une image saisie à la main dans la zone SEO l'emporte toujours, et rien de dérivé n'est écrit en base : le calcul est refait à chaque rendu. La zone SEO de l'éditeur affiche la valeur héritée en filigrane et la compte dans son score, comme la pastille de la liste, pour que ces trois affichages reflètent exactement ce que la page publique émet.

Le drapeau seo est ignoré sur les autres types de champs : il n'y a rien à en dériver.

Champs privés

LRVO_MODULE_POSTS_TYPE_BLOGUE_PRIVATE=notes_internes|cout

Les champs listés sont retirés de toutes les réponses publiques : de l'objet post et de sa copie brute, ainsi que de la configuration exposée par la route publique de configuration. Ils restent pleinement éditables dans l'admin.

Deux garde-fous :

  • Les noms structurels sont ignorés silencieusement. id, post_type, slug, created_at, updated_at, visibility et _data ne peuvent pas être rendus privés, parce qu'ils portent le routage ou le filtrage public.
  • visibility est de toute façon toujours retiré des réponses publiques, déclaré privé ou non. L'API publique a déjà filtré sur cette colonne, exposer sa valeur ne ferait que révéler un détail d'implémentation.

Les termes de taxonomie ne sont jamais privés.

Colonnes du tableau d'admin

LRVO_MODULE_POSTS_TYPE_BLOGUE_LIST=title|categories|date|seo

Chaque nom est résolu d'abord contre les champs déclarés du type, puis contre les jetons méta. Un nom qui ne correspond à rien est écarté sans erreur.

Jeton métaColonne rendue
seoPastille de score SEO sur 100. N'apparaît que si LRVO_SEO est actif.
orderPoignée de glisser-déposer. N'apparaît que si le type est réordonnable.

Le jeton order sert uniquement à choisir la position de la poignée. Sur un type réordonnable qui ne le liste pas, la poignée est ajoutée d'office en tête de tableau ; sur un type qui ne l'est pas, le jeton est écarté même s'il est listé.

Variable absente ou vide, l'admin affiche tous les champs déclarés du type, à l'exception des champs slug et editor. Le détail du rendu de chaque colonne est dans Administration.

Ordre manuel

LRVO_MODULE_POSTS_TYPE_EXPERTISES_ORDERABLE=true

La comparaison est stricte : seule la chaîne true active le drapeau.

Voir Taxonomies et relations pour l'effet sur le tri et sur la hiérarchie.

Exemple complet

LRVO_MODULE_POSTS=true
LRVO_MODULE_POSTS_TYPES=blogue:Blogue:Moon02Icon|expertise:Expertises:Idea01Icon

LRVO_MODULE_POSTS_TYPE_BLOGUE=title:title|slug:slug|categories:taxonomy:Catégories:multi:sidebar|date:date:now:sidebar|thumbnail:thumbnail:Miniature:sidebar|content:editor:Contenu
LRVO_MODULE_POSTS_TYPE_BLOGUE_LIST=thumbnail|title|categories|date|seo

LRVO_MODULE_POSTS_TYPE_EXPERTISE=title:title|slug:slug|parent:parent:Parent:sidebar|content:editor:Contenu
LRVO_MODULE_POSTS_TYPE_EXPERTISE_ORDERABLE=true

Ce fichier déclare deux types : un blogue plat avec deux niveaux de classement et une image de mise en avant, et des expertises hiérarchiques réordonnables à la main.

Notes

  • Le champ template n'est pas déclarable. Il est ajouté d'office à chaque post, vaut default en l'absence de choix, et sélectionne le template de rendu. Voir Templates.
  • Le champ seo n'est pas déclarable non plus. Il est ajouté par le core quand LRVO_SEO est actif. Le drapeau seo d'un champ déclaré est autre chose : il désigne la source du repli automatique, il ne crée pas de champ.
  • Le manifeste du module décrit les types de champs disponibles dans sa propre documentation de variable, mais cette liste y est incomplète : elle omet link et parent, tous deux valides. Le catalogue de cette page fait foi.

Sur cette page