# Rewrite API : créer des URL personnalisées avec add_rewrite_rule

> /annuaire/region/bretagne/artisan/12 : une URL métier que WordPress ne sait pas router nativement. La Rewrite API permet de la créer proprement, sans page statique bricolée.

- Auteur : Clément Hadrot
- Publié le : 2021-01-05
- Mis à jour le : 2021-01-05
- Catégorie : Extensions
- URL : https://wpmoderne.dev.wordpress-developpement.fr/extensions/rewrite-api-url-personnalisees-add-rewrite-rule/

## L’essentiel

- Une règle de réécriture doit toujours être associée à une ou plusieurs query vars enregistrées
- flush_rewrite_rules ne s'exécute qu'à l'activation, jamais à chaque chargement
- template_redirect est le bon endroit pour intercepter la requête finale

Un annuaire professionnel régional m'a demandé une URL de la forme `/annuaire/bretagne/plombier/`, filtrable par région et par métier, sans passer par des paramètres de requête classiques du type `?region=bretagne&metier=plombier`. Une bonne partie des extensions bricolent ce genre de besoin avec des pages statiques et du contenu généré dynamiquement en PHP. La Rewrite API de WordPress permet une solution bien plus propre, directement intégrée au système de permaliens.

## Déclarer la règle de réécriture

`add_rewrite_rule()` associe une expression régulière à une URL interne exploitable par WordPress, sous la forme d'une chaîne de requête classique. Elle doit être enregistrée sur le hook `init`.

```
add_action( 'init', 'annuaire_ajouter_regles_reecriture' );

function annuaire_ajouter_regles_reecriture() {
    add_rewrite_rule(
        '^annuaire/([^/]+)/([^/]+)/?$',
        'index.php?annuaire_region=$matches[1]&annuaire_metier=$matches[2]',
        'top'
    );
}
```

Le troisième argument, `'top'`, place la règle en tête de la liste plutôt qu'à la fin. C'est important : WordPress évalue les règles dans l'ordre, et une règle générique du cœur pourrait sinon intercepter l'URL avant que la vôtre ne soit testée.

## Enregistrer les query vars associées

Une règle de réécriture qui pointe vers des variables de requête non enregistrées ne fonctionne pas : WordPress ignore silencieusement toute variable de `$_GET` qui ne figure pas dans sa liste blanche de query vars publiques.

> L'essentiel à retenir : Une règle de réécriture doit toujours être associée à une ou plusieurs query vars enregistrées ; flush_rewrite_rules ne s'exécute qu'à l'activation, jamais à chaque chargement ; template_redirect est le bon endroit pour intercepter la requête finale

```
add_filter( 'query_vars', 'annuaire_ajouter_query_vars' );

function annuaire_ajouter_query_vars( $vars ) {
    $vars[] = 'annuaire_region';
    $vars[] = 'annuaire_metier';
    return $vars;
}
```

C'est l'erreur numéro un sur ce type de développement : la règle semble correcte, l'URL ne renvoie pas de 404, mais les valeurs de `get_query_var( 'annuaire_region' )` restent obstinément vides. Neuf fois sur dix, c'est parce que le filtre `query_vars` a été oublié.

## Intercepter la requête sur template_redirect

Une fois les query vars disponibles, il reste à décider quoi afficher. Deux approches possibles : rediriger vers un template personnalisé via `template_include`, ou construire la sortie directement sur `template_redirect`.

```
add_action( 'template_redirect', 'annuaire_afficher_page_filtree' );

function annuaire_afficher_page_filtree() {
    $region = get_query_var( 'annuaire_region' );
    $metier = get_query_var( 'annuaire_metier' );

    if ( empty( $region ) || empty( $metier ) ) {
        return;
    }

    $professionnels = annuaire_rechercher_professionnels( $region, $metier );

    if ( empty( $professionnels ) ) {
        global $wp_query;
        $wp_query->set_404();
        status_header( 404 );
        return;
    }

    annuaire_charger_template_resultats( $region, $metier, $professionnels );
    exit;
}
```

Gérer explicitement le cas d'une combinaison région/métier sans résultat avec `set_404()` évite d'afficher une page vide avec un code HTTP 200, ce qui serait trompeur autant pour les visiteurs que pour les moteurs de recherche.

## Le piège du flush prématuré ou répété

Pour que les nouvelles règles soient prises en compte, WordPress doit régénérer sa table de règles de réécriture, une opération réalisée par `flush_rewrite_rules()`. C'est une fonction coûteuse, à réserver strictement à l'activation et à la désactivation de l'extension.

- Ne jamais appeler `flush_rewrite_rules()` sur le hook `init` à chaque chargement de page : c'est l'erreur de performance la plus fréquente sur ce sujet
- À l'activation, appeler d'abord la fonction qui enregistre les règles, puis `flush_rewrite_rules()`, jamais l'inverse
- À la désactivation, appeler `flush_rewrite_rules()` seul suffit à nettoyer les règles devenues obsolètes

```
register_activation_hook( __FILE__, function () {
    annuaire_ajouter_regles_reecriture();
    flush_rewrite_rules();
} );

register_deactivation_hook( __FILE__, 'flush_rewrite_rules' );
```

> Un flush systématique à chaque chargement masque un bug de développement plutôt qu'il ne le résout : si une règle ne fonctionne qu'après un flush manuel répété, c'est probablement qu'elle n'est pas enregistrée au bon moment.

## Pour aller plus loin

La Rewrite API reste, huit ans après ses débuts, l'outil de référence pour créer des URL métier propres sans dépendre d'un plugin tiers de gestion de permaliens. Elle demande de la rigueur sur l'ordre des opérations — règle, query vars, puis flush une seule fois — mais offre en échange des URL lisibles, indexables, et parfaitement intégrées au reste du système de permaliens de WordPress.
