Aller au contenu principal
Version: Next

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")
remarque

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 :

  1. Un fichier app/PostTypes/MyPost.php
  2. Le type de contenu est automatiquement enregistré dans WordPress
  3. 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é

app/PostTypes/Recipes.php
<?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

app/Controller/RecipesController.php
#[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

views/archive-recipes.html.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
remarque

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() et setSupports() à la manipulation directe de $this->options pour plus de lisibilité
  • Placez la logique métier dans des contrôleurs dédiés