# Créer des pages par défaut à l’activation d’un thème, sans jamais les dupliquer

> Un thème qui insère automatiquement ses pages de démonstration peut vite les recréer en double. La parade tient en une vérification par le slug.

- Auteur : Clément Hadrot
- Publié le : 2023-12-17
- Mis à jour le : 2023-12-17
- Catégorie : Tips
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tips/creer-pages-defaut-activation-sans-doublon/

## L’essentiel

- Vérifier l'existence par le slug avant d'insérer
- register_activation_hook n'est pas fait pour les thèmes
- after_switch_theme est le bon hook côté thème

Un studio pour lequel je maintiens plusieurs thèmes maison m'a signalé un comportement bizarre : chaque fois qu'un client désactivait puis réactivait leur thème (souvent en testant un autre thème avant de revenir), il se retrouvait avec deux, puis trois pages « Accueil de démonstration » dans sa liste de pages. Le code d'origine créait bêtement les pages à chaque activation, sans jamais vérifier si elles existaient déjà.

C'est une erreur fréquente sur les thèmes qui livrent un jeu de pages de démarrage (page d'accueil type, page de contact, mentions légales). Le correctif est simple une fois qu'on a identifié le bon hook et la bonne vérification, mais il faut être rigoureux sur l'ordre des opérations.

## Le bon hook, côté thème

Première précision utile : `register_activation_hook()` est réservé aux extensions, pas aux thèmes. Pour un thème, l'équivalent est l'action `after_switch_theme`, déclenchée juste après le changement de thème actif. Elle reçoit en paramètre le nom de l'ancien thème, ce qui peut d'ailleurs servir à distinguer une vraie première activation d'un simple retour en arrière.

```
add_action( 'after_switch_theme', 'studio_creer_pages_defaut' );

function studio_creer_pages_defaut() {
    $pages = array(
        array(
            'slug'    => 'accueil-demo',
            'title'   => 'Accueil de démonstration',
            'content' => '<!-- wp:paragraph --><p>Contenu de démarrage.</p><!-- /wp:paragraph -->',
        ),
        array(
            'slug'    => 'mentions-legales-modele',
            'title'   => 'Mentions légales (modèle)',
            'content' => '<!-- wp:paragraph --><p>À compléter par le client.</p><!-- /wp:paragraph -->',
        ),
    );

    foreach ( $pages as $page ) {
        studio_inserer_page_si_absente( $page );
    }
}
```

## La vérification qui évite les doublons

> L'essentiel à retenir : Vérifier l'existence par le slug avant d'insérer ; register_activation_hook n'est pas fait pour les thèmes ; after_switch_theme est le bon hook côté thème

Le cœur du sujet est là : avant d'insérer quoi que ce soit, il faut chercher une page existante avec exactement ce slug, quel que soit son statut (publiée, brouillon, ou même dans la corbeille). C'est la fonction `get_page_by_path()` qui fait ce travail, en acceptant un troisième argument pour le type de post.

```
function studio_inserer_page_si_absente( array $page ) {
    $existante = get_page_by_path( $page['slug'], OBJECT, 'page' );

    if ( $existante instanceof WP_Post ) {
        return; // La page existe déjà, on ne touche à rien.
    }

    wp_insert_post( array(
        'post_type'    => 'page',
        'post_status'  => 'publish',
        'post_title'   => $page['title'],
        'post_name'    => $page['slug'],
        'post_content' => $page['content'],
    ) );
}
```

Un détail qui a son importance : `get_page_by_path()` ne filtre pas par statut par défaut, ce qui veut dire qu'une page déplacée en brouillon par le client sera quand même détectée, et ne sera pas recréée. C'est exactement le comportement voulu : on ne veut pas ressusciter une page que le client a volontairement mise de côté.

### Le cas de la corbeille

Si la page a été supprimée puis mise à la corbeille, `get_page_by_path()` ne la trouve pas par défaut (le statut `trash` n'est pas inclus dans la recherche standard). Résultat : le thème recréerait une page identique. Pour éviter ce cas précis, ajoutez une requête complémentaire avec `get_posts()` et l'argument `post_status => array( 'trash' )` si vous voulez respecter la décision de suppression du client :

```
function studio_page_existe_meme_en_corbeille( $slug ) {
    $resultats = get_posts( array(
        'name'        => $slug,
        'post_type'   => 'page',
        'post_status' => array( 'publish', 'draft', 'trash', 'pending' ),
        'numberposts' => 1,
    ) );

    return ! empty( $resultats );
}
```

## Distinguer une vraie activation d'un aller-retour

Sur un projet où deux thèmes maison cohabitent pour des tests A/B, on ne veut recréer les pages que lors de la toute première activation, jamais ensuite. On peut s'appuyer sur une option qui garde la trace du provisioning déjà effectué :

```
function studio_creer_pages_une_seule_fois() {
    if ( get_option( 'studio_pages_provisionnees' ) ) {
        return;
    }

    studio_creer_pages_defaut();
    update_option( 'studio_pages_provisionnees', true );
}
add_action( 'after_switch_theme', 'studio_creer_pages_une_seule_fois' );
```

Cette option-drapeau est complémentaire à la vérification par slug, pas un substitut : elle évite de relancer toute la boucle de vérifications à chaque activation, ce qui est plus rapide, mais la vérification par slug reste la garantie de fond contre les doublons si l'option venait à disparaître (migration, changement de base).

- Toujours vérifier par le `slug`, jamais par le titre : deux pages peuvent porter le même titre affiché avec des slugs différents.
- Ne jamais utiliser `wp_insert_post()` sans contrôle préalable dans un hook d'activation.
- Documenter dans le thème la liste des slugs « protégés » que le client ne doit pas renommer, sous peine de recréation involontaire.

> Un conseil que je donne à toute équipe qui livre des thèmes en série : le provisioning de contenu par défaut doit toujours être idempotent, c'est-à-dire qu'exécuter la fonction une fois ou dix fois doit produire exactement le même résultat.

## Pour aller plus loin

Cette logique de vérification avant insertion dépasse largement le cas des pages : elle s'applique de la même façon aux catégories par défaut, aux menus de démonstration, ou aux options de personnalisation initiales. Le principe reste identique : chercher avant de créer, et ne jamais supposer qu'un hook d'activation n'est déclenché qu'une seule fois dans la vie d'un site.
