Sur les projets menés en agence, il arrive régulièrement de vouloir un petit outil de diagnostic accessible uniquement par l’équipe technique : un bouton pour vider un cache applicatif spécifique, un état des lieux des tâches cron en attente, ou un export ponctuel réservé à la maintenance. Le client n’a aucune raison de voir cette page, et il n’a surtout pas à s’inquiéter d’une entrée de menu mystérieuse qu’il ne comprendrait pas.
WordPress permet justement d’enregistrer une page d’administration fonctionnelle sans qu’elle apparaisse dans aucun menu, en s’appuyant sur une astuce peu documentée mais parfaitement stable de la fonction add_submenu_page().
Le principe : un parent_slug qui n’existe pas
add_submenu_page() attend normalement un slug de menu parent existant, comme tools.php ou options-general.php, pour rattacher la nouvelle page à un menu visible. En lui fournissant un slug de parent qui ne correspond à aucun menu réel, la page est enregistrée, son routage fonctionne, mais aucune entrée cliquable n’apparaît nulle part dans l’interface :
function agence_enregistrer_page_diagnostic() {
add_submenu_page(
null, // aucun parent réel : la page reste invisible
'Diagnostic technique',
'Diagnostic technique',
'manage_options',
'agence-diagnostic',
'agence_afficher_page_diagnostic'
);
}
add_action( 'admin_menu', 'agence_enregistrer_page_diagnostic' );
Depuis WordPress 5.3, passer explicitement null en premier paramètre est la syntaxe recommandée pour ce cas précis ; sur des versions plus anciennes, un slug inventé et jamais enregistré ailleurs produisait le même effet.

Le rendu de la page elle-même
Rien de spécifique ici : la fonction de rendu suit les mêmes règles que n’importe quelle page d’administration classique, avec vérification explicite de la capacité avant tout affichage sensible :
function agence_afficher_page_diagnostic() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( 'Accès non autorisé.' );
}
echo '<div class="wrap"><h1>Diagnostic technique</h1>';
$taches_cron = _get_cron_array();
echo '<p>' . count( $taches_cron ) . ' créneaux de tâches planifiées enregistrés.</p>';
echo '</div>';
}
Cette double vérification, à la fois dans add_submenu_page() via la capacité requise et explicitement dans la fonction de rendu, reste indispensable : masquer une page du menu ne dispense jamais de contrôler les droits d’accès à son contenu.
Retrouver l’URL de la page
Puisqu’aucun lien de menu n’existe, l’URL doit être communiquée directement à l’équipe technique concernée, généralement sous cette forme :
https://exemple-client.fr/wp-admin/admin.php?page=agence-diagnostic
Il est possible de générer cette URL dynamiquement dans le code avec add_query_arg( 'page', 'agence-diagnostic', admin_url( 'admin.php' ) ), utile par exemple pour l’ajouter dans un lien envoyé par un canal de support interne, sans jamais l’exposer dans l’interface du site lui-même.
Où s’arrêter avec cette astuce
- Cette technique masque une page de l’interface, elle ne remplace en rien une restriction de rôle ou de capacité.
- Elle ne convient pas à un écran de réglages destinés à être configurés régulièrement : sans entrée de menu, un futur développeur risque de l’oublier complètement.
- Pour un outil voué à durer, documenter son existence et son URL dans la documentation technique du projet reste indispensable.
Une page cachée du menu n’est pas une page secrète : n’importe quel utilisateur disposant de la capacité requise peut y accéder s’il devine ou reçoit l’URL. Ce n’est qu’un confort d’interface, jamais une mesure de sécurité.
En résumé
Passer null comme parent à add_submenu_page() reste la méthode la plus propre pour obtenir un écran fonctionnel sans polluer le menu d’administration d’un client. Cette technique se distingue nettement de la construction d’un écran de réglages complet, avec ses propres champs et sa propre logique de sauvegarde, qui relève d’un sujet séparé côté extensions.