Administration

Tuile du tableau de bord, écrans du module, liste paginée et arborescente, réordonnancement par glisser-déposer, formulaire dérivé du type et gestion des termes de taxonomie.

Le module ajoute une section d'admin par type déclaré, et en dérive l'interface d'édition. Un formulaire de post n'est donc jamais écrit à la main : il est reconstruit à chaque chargement depuis la déclaration du type. Cette page décrit ce que fait l'interface, y compris les quelques comportements qui surprennent.

La structure du formulaire vient de Types et champs. Ce qui suit couvre le rendu, pas la déclaration.

Écrans

CheminÉcran
/admin/postsIndex des types déclarés.
/admin/posts/<type>/listListe des posts d'un type.
/admin/posts/<type>/newCréation.
/admin/posts/<type>/edit/<id>Édition.
/admin/posts/<type>/taxonomies/<taxonomie>Liste des termes.
/admin/posts/<type>/taxonomies/<taxonomie>/newCréation d'un terme.
/admin/posts/<type>/taxonomies/<taxonomie>/edit/<id>Édition d'un terme.

L'accès demande posts.view. Créer, modifier, supprimer et réordonner demandent posts.manage, pour les posts comme pour les termes. Voir Configuration.

L'index des types n'a pas d'entrée dans la barre latérale : celle-ci pointe directement sur la liste de chaque type. Il reste atteignable à son URL, et affiche une carte par type avec son nombre de champs. Sans type déclaré, il affiche à la place un rappel de la variable à renseigner.

Panneau du tableau de bord

Le module pose une tuile sur /admin, à l'ordre 70, donc derrière celle de @lrvo/module-billing et devant celles de @lrvo/module-drive. Elle disparaît pour qui n'a pas posts.view, et sa donnée n'est même pas collectée dans ce cas.

Une seule tuile, quel que soit le nombre de types. Le tableau de bord mêle les tuiles de tous les modules dans la même maçonnerie : un site qui déclare cinq types y poserait cinq cartes jumelles. Ce sont les lignes qui portent les types, une par type, dans l'ordre de LRVO_MODULE_POSTS_TYPES. Sans type déclaré, la tuile ne s'enregistre pas.

Inventaire

Une ligne par type déclaré, avec son icône de barre latérale, son total et un lien vers sa liste. Un type sans contenu garde sa ligne, à zéro : la liste des types est celle de la barre latérale, et un type qui disparaîtrait de la tuile le jour où on vide sa corbeille se lirait comme une panne.

Le compte des privés ne s'affiche qu'au-dessus de zéro. Il compte les posts dont la visibilité vaut private, c'est-à-dire ceux que le rendu public refuse de servir. Il n'y a pas d'état de brouillon dans ce module : un post est public ou privé. Voir Modèle de données.

Les posts d'un type retiré de LRVO_MODULE_POSTS_TYPES restent en base mais ne sont comptés nulle part : sans libellé ni section de navigation, ils n'ont ni ligne où se compter ni page où mener.

Dernières modifications

Les deux derniers posts touchés, tous types confondus, chacun lié à son écran d'édition. La date est celle de updated_at, donc de la dernière écriture, pas de la publication : un post ancien remonte en tête si on le corrige.

Un post est nommé comme la liste d'admin le nomme. Pour un type sans champ title, c'est donc un extrait de son premier champ editor, sinon de son premier champ text, et à défaut #<id>. Voir Types et champs.

Le badge Privé ne marque que les lignes qui le sont : une colonne de « Public » répétés n'apprendrait rien et mangerait la largeur dont le titre a besoin.

Ce qui fait disparaître la tuile

Une tuile dont les chiffres ne peuvent pas être calculés disparaît au lieu d'afficher des zéros : un décompte auquel on ne peut pas se fier est pire qu'un décompte absent. C'est aussi ce qui se passe sur une installation dont les tables ne sont pas encore créées.

Liste

La liste est paginée et triée côté serveur, 20 posts par page par défaut, la taille du lot étant réglable depuis le pied de tableau. Cliquer un en-tête de colonne triable relance la requête plutôt que de réordonner l'affichage.

C'est la différence de fond avec la liste de @lrvo/module-pages, qui charge un lot fixe et trie dans le navigateur. Une liste de posts peut donc grandir sans que l'interface décroche.

Pour un type déclarant un champ parent, les lignes de la page courante sont ensuite réordonnées en arbre : chaque post apparaît sous son parent, décalé d'un cran par niveau. Le chemin public complet n'est pas affiché sous le titre, seulement le slug.

Une conséquence de la pagination : un post dont le parent est resté sur une autre page apparaît au niveau racine. Le post existe, son parent aussi, seul l'affichage est aplati. Le cas se produit aussi quand un parent a été supprimé, puisque ses enfants voient alors leur parent_id passer à vide.

Colonnes

Les colonnes suivent LRVO_MODULE_POSTS_TYPE_<CLÉ>_LIST quand la variable est renseignée. Sinon, l'admin affiche tous les champs déclarés du type, sauf les champs slug et editor : le slug est déjà rendu sous le titre, et un tableau de blocs n'a pas de rendu tabulaire utile.

Type de champRendu
titleLien vers l'écran d'édition, slug en dessous, indentation selon la profondeur.
text, linkValeur tronquée, l'URL étant rendue cliquable pour link.
date, datetimeDate formatée en français.
created, updatedDate et heure de la colonne correspondante.
colorPastille de couleur et valeur hexadécimale, affichées telles que saisies : une couleur de contenu ne suit pas le thème.
taxonomyUne étiquette par terme classé.
image, thumbnailVignette de 40 pixels.
galleryLes trois premières vignettes, puis le nombre d'images restantes.
visibilityÉtiquette Public ou Privé.
seoPastille de score, seulement si LRVO_SEO est actif.
orderPoignée de glisser-déposer.

Les champs relation et parent n'ont aucun rendu de colonne. Les lister dans _LIST ne produit rien du tout, sans message d'erreur. Pour exposer un lien dans le tableau, passer par un autre champ.

Un type qui ne déclare pas de champ title n'a plus aucune colonne cliquable. L'admin ajoute alors d'office, en tête du tableau, une colonne « Contenu » qui reprend le rôle de la colonne titre : lien vers l'écran d'édition, slug en dessous, indentation selon la profondeur. Elle affiche les premiers mots du premier champ editor du type, à défaut la valeur de son premier champ text, à défaut le numéro du post. Cette colonne n'est pas triable, sa valeur étant calculée à l'affichage et non en base.

Les colonnes triables sont celles adossées à une valeur triable en base : titre, dates, visibilité. Une colonne de taxonomie ou de média ne l'est pas.

Réordonnancement

Le glisser-déposer demande deux conditions réunies : le type porte le drapeau orderable, et le tri courant est celui de l'ordre. Sur un type réordonnable, l'admin sélectionne ce tri au chargement, la poignée est donc active d'emblée ; trier sur une autre colonne la grise, avec une infobulle qui indique comment la réactiver.

Un post ne se déplace qu'à l'intérieur de sa fratrie. Le lâcher sur une ligne d'un autre parent est refusé avec un message, sans requête.

Le déplacement est appliqué immédiatement à l'affichage, puis persisté. Si le serveur refuse, la liste est rechargée pour se resynchroniser avec la base. Voir Taxonomies et relations pour la portée de l'ordre.

Actions de ligne

ActionDisponibilité
Ouvrir la page publiqueSeulement si le type a un champ slug et que le post est public. S'ouvre dans un nouvel onglet, à l'URL imbriquée pour un type hiérarchique.
ModifierToujours.
SupprimerToujours, après confirmation.

Il n'y a pas d'action de duplication, contrairement à la liste des pages CMS.

Formulaire

Le formulaire est construit champ par champ à partir de la déclaration du type. Chaque champ va dans la colonne principale, ou dans la colonne latérale s'il porte le drapeau sidebar.

La colonne latérale est créée dès qu'un template est enregistré pour le type, même si aucun champ n'y est placé : c'est là que vit le sélecteur de template. Un type sans champ sidebar et sans template enregistré n'a pas de colonne latérale du tout.

Quand LRVO_SEO est actif, la zone SEO du core apparaît sous la zone de contenu. Son aperçu d'URL utilise le chemin public du post, ou le chemin reconstruit depuis le slug en cours de saisie à la création.

Laissées vides, la méta description et l'image de partage retombent sur le contenu du post. La zone SEO montre alors la valeur héritée en filigrane, et la compte dans son score, pour refléter ce que la page publique émettra. La pastille de la liste applique le même calcul. Voir Repli SEO automatique.

Titre et slug

Tant que le champ slug n'a pas été touché, il suit le titre à la frappe. Le toucher fige la valeur saisie.

Sur un type sans champ title, il n'y a rien à suivre : le champ slug reste vide et le serveur y pose post-<id> à l'enregistrement. Vous pouvez toujours saisir la valeur de votre choix.

À l'édition, le slug est considéré comme touché dès le chargement. Renommer le titre d'un post existant ne change donc jamais son slug, ce qui reflète exactement la règle appliquée par le serveur. Voir Modèle de données.

Le slug saisi est renormalisé à l'enregistrement, et suffixé s'il entre en collision avec celui d'un autre post du même type.

Sélecteur de template

Le sélecteur liste les templates enregistrés pour ce type, jamais ceux d'un autre. Voir Templates.

Si le post porte un template qui n'existe plus, le sélecteur se réaligne sur le premier disponible, et l'enregistrement suivant écrit cette valeur. Le rendu public, lui, ne réécrit rien : il retombe sur default tant que le champ n'a pas été enregistré.

Sélecteur de parent

Le sélecteur charge jusqu'à 500 posts du type et liste toutes les options en arbre, chaque niveau étant indenté par un connecteur textuel. Le post courant et toute sa descendance sont retirés de la liste, un cycle est donc impossible à créer depuis l'interface. Le serveur revérifie de son côté, en remontant toute la chaîne d'ascendants.

La première option remet le post à la racine du type.

Sélecteur de relation

Le champ ouvre une autocomplétion sur la route de recherche du type cible, avec un délai de 250 millisecondes après la frappe et 20 résultats par requête. Les posts déjà sélectionnés en sont retirés.

Les éléments retenus s'affichent en étiquettes, dans l'ordre de sélection. Cet ordre est celui qui est persisté puis restitué à la lecture.

Sélecteur de taxonomie

Une taxonomie en mode single rend une liste déroulante avec une option vide ; en mode multi, un champ à étiquettes.

Les termes proposés sont les termes actifs de la taxonomie, chargés par lot de 1000. Désactiver un terme le retire donc du sélecteur sans toucher aux posts qui le portent déjà.

Champs média

Un champ image ou thumbnail affiche l'aperçu du média choisi, son nom de fichier, et deux actions : remplacer et retirer.

Un champ gallery affiche ses images en grille, dans leur ordre. Chaque vignette porte au survol deux actions, modifier et retirer, et se déplace par glisser-déposer pour changer l'ordre. Modifier ouvre la fiche du média : le texte alternatif et la légende y appartiennent au média, les corriger les change donc partout où il est utilisé.

Le bouton d'ajout rouvre le sélecteur sur la sélection courante. Les images déjà retenues y apparaissent cochées, en ajouter une la place en fin de galerie sans défaire l'ordre existant, et la décocher l'enlève. Le sélecteur accepte plusieurs fichiers en un seul téléversement et ajoute d'office les médias créés à la sélection, dans l'ordre où la grille les présente.

Une image dont le média a été supprimé de la médiathèque reste visible dans la grille, signalée comme introuvable, pour que le champ puisse être corrigé.

Sans @lrvo/module-medias installé et activé, le bouton de sélection est remplacé par un message qui rappelle le paquet à installer et la variable à poser. Le champ reste dans le formulaire, il n'est simplement pas utilisable. Voir Module Médias.

Dates

« Modifié le » est en lecture seule et reflète le dernier enregistrement.

« Créé le » s'affiche en texte, et devient un sélecteur de date et heure au clic. Le champ est borné à l'instant présent, et le serveur refuse à son tour toute date future. Le contrôle n'apparaît pas à la création, la date n'existant qu'une fois le post enregistré.

Termes de taxonomie

Chaque taxonomie déclarée a son propre écran, atteignable depuis la barre latérale. La liste est paginée à 20 termes, triable sur le titre, les dates et le statut.

Deux colonnes méritent l'attention : le nombre de posts qui portent le terme, et son statut actif ou inactif. Un terme utilisé par au moins un post ne peut pas être supprimé ; le désactiver est la façon de le retirer de la circulation sans perdre les classements. Voir Taxonomies et relations.

Un terme porte un titre, une description facultative et son drapeau d'activité. Il n'a pas de slug.

Enregistrement

Une barre de modifications non enregistrées apparaît dès qu'un champ change. Annuler restaure l'état du dernier chargement, enregistrer envoie le formulaire complet.

Le seul contrôle bloquant côté navigateur est le titre, qui ne peut pas être vide. Il ne s'applique qu'aux types qui déclarent un champ title : les autres n'ont aucun contrôle bloquant. Tout le reste est validé par le serveur.

À la création, l'enregistrement redirige vers l'écran d'édition du post créé. Le slug définitif y est visible, suffixe compris s'il y en a eu un.

Notes

  • Les deux plafonds de l'interface, 500 posts dans le sélecteur de parent et 1000 termes dans un sélecteur de taxonomie, ne sont pas réglables.
  • La recherche n'est pas exposée dans la liste d'admin, bien que la route la supporte. Passer par l'API pour l'utiliser.
  • Un post privé reste éditable dans l'admin, mais son URL publique répond une page introuvable. Le bouton de lien disparaît alors de la ligne et de l'en-tête. Il n'y a pas de prévisualisation des posts privés.
  • Supprimer un post ne supprime pas ses enfants. Ils remontent à la racine du type, et leur URL publique change en conséquence.
  • Modifier une variable de déclaration demande un redémarrage du serveur : l'admin lit la configuration analysée au boot, pas le fichier d'environnement.

Sur cette page