Créer un CPT
Custom Post Type
Générer un nouveau type de contenu
Pour créer un nouveau Custom Post Type dans Elementum, utilisez la commande suivante :
php dobby make:post MyPost
Configuration interactive
La commande vous posera quelques questions pour configurer votre type de contenu :
- Nom du menu : Le nom qui apparaîtra dans le menu d'administration
- Nom au singulier (en minuscule) : Utilisé pour les boutons et les libellés (ex: "article")
- Nom au pluriel (en minuscule) : Utilisé pour les intitulés au pluriel (ex: "articles")
Toutes ces questions sont optionnelles. Si vous ne répondez pas, des valeurs par défaut seront générées automatiquement à partir du nom de la classe.
Structure générée
La commande crée automatiquement :
- Un fichier
app/PostTypes/MyPost.php - Le type de contenu est automatiquement enregistré dans WordPress
- Toutes les méthodes publiques de la classe sont exécutées lors de l'enregistrement
Exemple complet
1. Création du type de contenu
php dobby make:post Recipes
2. Fichier généré
<?php use Carbon_Fields\Field; use Elementum\Abstract\PostType; class Recipes extends PostType { /** * @var string */ const string SLUG = "recipes"; public function __construct() { /** * Définition des propriétés du PostType */ $this->slug = self::SLUG; $this->menuName = 'Recettes'; $this->labels = [ 'plural' => 'recettes', 'singular' => 'recette', ]; $this->isMale = false; /** * @see https://developer.wordpress.org/resource/dashicons/ */ $this->icon = 'dashicons-food'; $this->options['position'] = 3; $this->setTitlePlaceholder('Nom de la recette'); /** * Gestion des colonnes */ $this->columns = [ "remove" => ["date"], "add" => [ "recipes_duration" => "Durée (min.)", "date" => "Date", ], ]; $this->makeSortable("recipes_duration"); /** * Appel du constructeur de la class parente * ! Doit être appelé en dernier */ parent::__construct(); } }
Récupérer les éléments
Dans un contrôleur
#[Template('post_type_archive', params: [Recipes::SLUG])] public function recipesArchive() { // Récupère une instance WP_Query des recettes $recipesQuery = $this->getPostType(Recipes::SLUG)->getQuery(); return $this->render('archive-recipes.html.twig', compact('recipesQuery')); }
Dans un template Twig
<div class="recipes-list"> {% wp_query recipesQuery %} <article class="recipe"> <h2><a href="{{ post.link }}">{{ post.title }}</a></h2> {% if post.thumbnail %} <img src="{{ post.thumbnail.src|resize(300, 200) }}" alt="{{ post.thumbnail.alt }}"> {% endif %} <div class="excerpt"> {{ post.get_preview(25, true, 'Voir la recette') }} </div> </article> {% endwp_query %} </div>
Propriétés de configuration
$active
Permet de désactiver complètement un CPT sans le supprimer. Quand false, le post type n'est pas enregistré dans WordPress et aucun hook n'est déclenché.
public bool $active = false; // Le CPT est désactivé
Utile pour conditionner l'activation d'un CPT selon une licence, un réglage d'administration, ou l'environnement.
$gutenbergEditor
Contrôle l'éditeur utilisé pour ce post type. Par défaut, Gutenberg est activé. Mettre à false bascule sur l'éditeur classique (TinyMCE).
public bool $gutenbergEditor = false; // Force l'éditeur classique
Méthodes de configuration fluides
Ces méthodes retournent $this et peuvent être chaînées. Elles doivent être appelées avant parent::__construct().
setSupports(string ...$args)
Définit les fonctionnalités supportées par le CPT. Remplace $this->options['supports'].
$this->setSupports('title', 'editor', 'thumbnail', 'excerpt');
Valeurs possibles : title, editor, thumbnail, excerpt, trackbacks, custom-fields, comments, revisions, page-attributes, post-formats.
setOption(string $key, mixed $value)
Surcharge n'importe quel argument WP passé à register_post_type().
$this->setOption('public', false) ->setOption('show_in_rest', true) ->setOption('menu_icon', 'dashicons-portfolio') ->setOption('has_archive', true);
setLabel(string $key, string $label)
Surcharge un label spécifique du CPT. Les pronoms et l'ensemble des labels sont recalculés automatiquement.
$this->setLabel('add_new', 'Rédiger un article') ->setLabel('not_found', 'Aucune recette trouvée');
Contrôle de l'éditeur Gutenberg
gutenbergEditorActivation(bool $enabled)
Active ou désactive Gutenberg pour ce CPT de manière programmatique, via le filtre use_block_editor_for_post_type. Utile si la décision doit être prise dynamiquement (ex : selon une option).
// Dans le constructeur, après parent::__construct() $this->gutenbergEditorActivation(false); // Désactive Gutenberg pour ce CPT
Définir $this->gutenbergEditor = false avant parent::__construct() appelle automatiquement cette méthode. Utilisez gutenbergEditorActivation() directement uniquement si vous avez besoin d'une logique conditionnelle.
Accès au post courant dans l'admin
getCurrentPost()
Retourne le WP_Post en cours d'édition dans l'interface d'administration, en lisant $_GET['post']. Retourne null hors contexte.
public function createFields() { $current = $this->getCurrentPost(); $this->addContainerFields('Détails', [ Field::make('text', 'my_field', 'Champ') ->set_default_value($current?->post_title ?? ''), ]); }
Exemple complet avec les nouvelles options
class Project extends PostType { const string SLUG = 'project'; public bool $gutenbergEditor = false; // Éditeur classique public function __construct() { $this->slug = self::SLUG; $this->menuName = 'Projets'; $this->labels = ['plural' => 'projets', 'singular' => 'projet']; $this->icon = 'dashicons-portfolio'; $this->setSupports('title', 'thumbnail', 'excerpt') ->setOption('has_archive', true) ->setOption('menu_position', 5) ->setLabel('add_new', 'Nouveau projet'); parent::__construct(); } }
Bonnes pratiques
- Utilisez des noms de classes en PascalCase
- Les noms de types de contenu doivent être en minuscules et utiliser des underscores
- Appelez toujours
parent::__construct()en dernier dans le constructeur - Préférez
setOption()etsetSupports()à la manipulation directe de$this->optionspour plus de lisibilité - Placez la logique métier dans des contrôleurs dédiés