Menús y Páginas de Admin
Construye interfaces de administración profesionales. Agrega menús principales, submenús y páginas de opciones personalizadas manteniendo la coherencia visual con el ecosistema.
La creación de una interfaz en el panel de administración es el hito más visible al desarrollar un plugin. En este capítulo, adoptaremos los estándares estrictos del núcleo de WordPress para construir experiencias profesionales. Aprenderemos a registrar menús y submenús mediante la API nativa, asegurando una correcta jerarquía y un riguroso control de acceso basado en roles. Asimismo, dominaremos el encolado condicional de scripts y estilos para proteger el rendimiento global del backend. Finalmente, estructuraremos nuestras vistas empleando las clases CSS nativas del Core, garantizando una experiencia de usuario (UX) coherente, accesible y adaptable.
7.1 Agregar menús principales
El ecosistema de administración de WordPress expone un flujo de inicialización específico para la interfaz de usuario del backend. La inserción de un elemento en la raíz del menú de navegación lateral del panel de control se gestiona de manera centralizada mediante el hook de acción admin_menu. Durante esta fase de ejecución, WordPress instancia y puebla las variables globales $menu y $submenu, que son arrays bidimensionales encargados de estructurar el árbol de navegación interno.
Modificar estas variables directamente es una práctica desaconsejada que rompe la compatibilidad hacia adelante. En su lugar, el Core proporciona la API de Páginas de Administración, cuyo componente principal para menús raíz es la función add_menu_page().
Flujo de Ejecución e Inicialización
El siguiente esquema ilustra el ciclo de vida de una petición en el backend y el punto exacto en el que se deben registrar los menús personalizados:
TEXT
Registrar un menú fuera del gancho admin_menu (por ejemplo, en init o plugins_loaded) causará fallos de consistencia, provocando que las funciones de verificación de capacidades fallen o que el menú no se renderice debido a que las estructuras globales aún no han sido inicializadas.
Anatomía de add_menu_page()
La función se define en el núcleo de WordPress (wp-admin/includes/plugin.php) bajo la siguiente firma técnica:
PHP
Análisis Quirúrgico de los Parámetros
$page_title(string): El texto que se introducirá dentro de la etiqueta<title>del documento HTML cuando el usuario navegue a esta página de administración. Es crítico para la accesibilidad y el SEO interno.$menu_title(string): El texto legible que se mostrará directamente en el menú de navegación izquierdo del panel de control de WordPress.$capability(string): El permiso o rol mínimo requerido para que este menú sea visible y accesible para un usuario. WordPress realiza una comprobación automática mediantecurrent_user_can(). Si el usuario no posee esta capacidad, el menú se oculta automáticamente y los intentos de acceso directo devuelven un error HTTP 403 (No autorizado).$menu_slug(string): El identificador único para este menú. Debe ser una cadena sanitizada (caracteres alfanuméricos, guiones o guiones bajos). Si no se proporciona un parámetro$callback, este slug debe coincidir con el nombre de un archivo PHP dentro del plugin, aunque la arquitectura limpia dicta que se utilice un slug semántico y se maneje el renderizado mediante un callback explícito.$callback(callable): La función o método de clase encargado de renderizar la interfaz HTML de la página de administración.$icon_url(string): Define el aspecto visual del icono del menú. Admite tres variantes:
- El nombre de una clase de Dashicons (ej.
'dashicons-admin-generic'). - Una URL absoluta hacia una imagen rasterizada o SVG.
- Una cadena codificada en Base64 con un esquema de datos SVG (Data URI), idóneo para evitar peticiones HTTP adicionales.
$position(int|float): El orden numérico en el que aparecerá el menú dentro de la barra lateral. WordPress utiliza un sistema de ordenación basado en enteros de menor a mayor.
Valores de Posición Estándar del Core
Para evitar colisiones con elementos nativos, es imprescindible comprender la distribución numérica del array $menu:
| Posición | Elemento del Menú Nativo |
|---|---|
| 2 | Escritorio (Dashboard) |
| 4 | Primer separador de la barra |
| 5 | Entradas (Posts) |
| 10 | Medios (Media) |
| 15 | Enlaces (Links - Obsoleto) |
| 20 | Páginas (Pages) |
| 25 | Comentarios (Comments) |
| 59 | Segundo separador de la barra |
| 60 | Apariencia (Appearance) |
| 65 | Plugins |
| 70 | Usuarios (Users) |
| 75 | Herramientas (Tools) |
| 80 | Ajustes (Settings) |
| 99 | Tercer separador de la barra |
Si dos plugins registran un menú en la misma posición exacta utilizando valores enteros, el último en cargarse sobrescribirá al anterior en la variable global, ocultándolo del panel. Para mitigar este riesgo, la API permite el uso de números flotantes decimales (por ejemplo, 25.32), reduciendo drásticamente la probabilidad de colisión.
Implementación Orientada a Objetos Bajo Estándares Estrictos
A continuación se detalla una implementación robusta utilizando Tipado Estricto (PHP 8.0+) y una estructura encapsulada en una clase controladora dentro de la arquitectura de un plugin.
PHP
Consideraciones Críticas de Seguridad y Arquitectura
- Aislamiento del Callback: Nunca se debe ejecutar lógica de negocio pesada, mutaciones de la base de datos o procesamiento de formularios directamente dentro del método
$callbacksin una verificación explícita de Nonces y sanitización previa. El callback debe ser tratado exclusivamente como una capa de presentación (Vista). - Uso Correcto de Capabilities: Evite asignar nombres de roles (ej.
'administrator') al parámetro$capability. El framework requiere capacidades abstractas ('manage_options','edit_posts','activate_plugins') para asegurar la compatibilidad con plugins de gestión de roles personalizados y arquitecturas Multisite. - Internacionalización (i18n): Tanto el título de la página como el del menú deben pasarse por las funciones de localización (
__()o_e()). No obstante, el parámetro$menu_slugjamás debe ser traducido, ya que sirve como identificador estático de la ruta URL (wp-admin/admin.php?page=custom-plugin-dashboard). Si se traduce el slug, el enrutamiento se romperá al cambiar el idioma del perfil del usuario.
7.2 Creación de submenús
Una vez establecido el punto de anclaje principal en la interfaz de administración, es frecuente que los plugins complejos requieran ramificar sus opciones para evitar sobrecargar una única pantalla. WordPress gestiona esta jerarquía mediante la función add_submenu_page(), la cual vincula nuevas interfaces a un menú padre existente, ya sea un menú nativo del Core o uno personalizado creado por tu plugin.
Jerarquía y Enrutamiento
El ecosistema de menús de WordPress es estrictamente de dos niveles. No existe soporte nativo para sub-submenús. El árbol de navegación interno se construye vinculando el parámetro $menu_slug de un menú padre con el parámetro $parent_slug de sus elementos hijos.
TEXT
Anatomía de add_submenu_page()
La firma de la función introduce variaciones clave respecto a la creación de menús principales:
PHP
El parámetro crítico aquí es $parent_slug. Dependiendo de dónde desees ubicar el submenú, este valor cambiará drásticamente.
Vinculación a Menús Nativos
Si tu plugin es de propósito único o no requiere un menú raíz propio, es una excelente práctica de UX anclar su configuración en los menús nativos existentes. WordPress proporciona el slug de los archivos PHP internos del administrador como $parent_slug, así como funciones contenedoras (wrappers) para facilitar el proceso:
| Menú Nativo Destino | Valor de $parent_slug | Función Wrapper Equivalente |
|---|---|---|
| Ajustes | options-general.php | add_options_page() |
| Herramientas | tools.php | add_management_page() |
| Apariencia | themes.php | add_theme_page() |
| Plugins | plugins.php | add_plugins_page() |
| Usuarios | users.php | add_users_page() |
| Entradas | edit.php | add_posts_page() |
| Páginas | edit.php?post_type=page | add_pages_page() |
| Custom Post Type | edit.php?post_type=mi_cpt | N/A (Usar add_submenu_page) |
El Comportamiento del "Primer Submenú"
Cuando registras un menú principal con add_menu_page(), WordPress automáticamente crea un primer submenú subyacente con el mismo nombre y slug que el menú padre. Si deseas que este primer enlace actúe como una vista general y tenga un título diferente en el submenú (por ejemplo, cambiar el título "Mi Plugin" del menú padre por "Vista General" en el submenú), debes registrar un submenú explícito donde el $parent_slug y el $menu_slug sean idénticos al slug del padre.
Implementación Práctica Orientada a Objetos
Extendiendo la arquitectura de la lección anterior, a continuación se detalla cómo registrar múltiples submenús: uno vinculado a nuestro menú personalizado y otro inyectado en el menú nativo de Ajustes de WordPress.
PHP
Patrón Arquitectónico para Menús Ocultos
En el desarrollo de plugins, surge a menudo la necesidad de crear páginas de administración que no deben aparecer listadas en la barra de navegación lateral (por ejemplo, una pantalla temporal para mostrar un registro de errores o un proceso de onboarding tras la activación).
Para registrar una página sin que genere un elemento visible en el menú, se utiliza un "truco" de la API pasando un valor null al parámetro $parent_slug:
PHP
La página será completamente funcional y segura, pero solo se podrá acceder a ella navegando directamente a su URL correspondiente: wp-admin/admin.php?page=custom-plugin-welcome.
7.3 Encolado de scripts y estilos
La inyección directa de etiquetas <script> o <link> en el código HTML es una de las peores prácticas en el desarrollo para WordPress. Este enfoque destruye la modularidad, impide la minificación centralizada, genera conflictos de dependencias (por ejemplo, cargar múltiples versiones de jQuery) y anula los mecanismos de caché del navegador.
Para resolver esto, WordPress implementa la API de Encolado (Enqueue API), un sistema de gestión de dependencias que asegura que los recursos (assets) se carguen en el orden correcto, solo cuando son necesarios y respetando las versiones en caché.
El Gancho admin_enqueue_scripts
En el entorno de administración, el hook designado para registrar y encolar recursos es admin_enqueue_scripts. A diferencia de su contraparte del front-end (wp_enqueue_scripts), este gancho pasa un parámetro de suma importancia a la función callback: el $hook_suffix (también conocido como $hook o simplemente el identificador de la pantalla actual).
Cargar los scripts de tu plugin en todas las páginas del panel de administración (como en la pantalla de edición de entradas o ajustes generales) es una infracción de rendimiento y seguridad. Debes condicionar la carga de tus recursos exclusivamente a las interfaces que tu plugin genera.
El Flujo de Carga Condicional
El siguiente esquema ilustra el proceso de validación para encolar recursos de forma quirúrgica:
TEXT
Funciones Principales de la API
La API separa conceptualmente el "registro" del "encolado", aunque se pueden realizar simultáneamente.
wp_register_style()/wp_register_script(): Avisa a WordPress de la existencia de un archivo, sus dependencias y su versión, pero no lo inserta en el HTML. Ideal para recursos que podrían cargarse bajo demanda mediante shortcodes o bloques.wp_enqueue_style()/wp_enqueue_script(): Inserta efectivamente el recurso en el<head>o justo antes de cerrar el<body>. Si el archivo no fue registrado previamente, esta función lo registra y encola en un solo paso.
Implementación Orientada a Objetos: Captura del Suffix
Para encolar condicionalmente, necesitamos conocer el identificador único que WordPress asigna a nuestra página al crearla. Funciones como add_menu_page() y add_submenu_page() no solo crean el menú, sino que devuelven un string que representa el $hook_suffix de esa interfaz.
El siguiente patrón arquitectónico captura ese string en una propiedad de la clase para utilizarlo posteriormente en la validación del encolado:
PHP
El Puente de Datos: wp_localize_script()
Como se observa en el método $this->localizeScriptData(), los archivos JavaScript externos son estáticos y no pueden interpretar código PHP directamente. Para pasar configuraciones de rutas dinámicas (como la URL de AJAX), tokens de seguridad (Nonces) o cadenas de texto traducibles, se utiliza wp_localize_script().
WordPress inyectará un bloque <script> embebido justo encima de tu archivo admin-script.js con el siguiente resultado en el HTML del panel:
HTML
Dentro de tu archivo admin-script.js, el objeto ahora estará disponible de forma nativa para consumir de forma segura:
JavaScript
(Nota: En WordPress 4.5+ se introdujo wp_add_inline_script que permite inyectar JavaScript en línea más complejo, y en WP 5.0+ wp_set_script_translations para usar los sistemas de localización basados en JED/JSON estándar de Gutenberg, pero wp_localize_script se mantiene como la forma más rápida, segura y retrocompatible de transferir arrays multidimensionales de configuración desde el backend al frontend).
7.4 Diseño con clases CSS nativas
El mayor error en el diseño de interfaces de administración para WordPress es intentar reinventar la rueda. Un plugin profesional debe sentirse como una extensión natural del núcleo, no como un software de terceros incrustado a la fuerza.
WordPress provee un framework CSS interno (cargado automáticamente a través de los estilos del administrador) compuesto por decenas de clases utilitarias. Utilizar estas clases garantiza que tu interfaz respetará los esquemas de color elegidos por el usuario en su perfil, mantendrá la accesibilidad (contraste y navegación por teclado) y se adaptará automáticamente a los rediseños futuros del Core sin requerir mantenimiento por tu parte.
Contenedores y Estructura Base
Todo el contenido de una página de administración debe estar encapsulado para alinearse correctamente con la barra superior y el menú lateral.
.wrap: Es el contenedor principal obligatorio. Otorga los márgenes y el relleno necesarios para separar tu contenido de los bordes de la pantalla..wp-heading-inline: Se aplica a la etiqueta<h1>. Permite que otros elementos (como botones de acción) se coloquen a su lado en la misma línea..page-title-action: Convierte un enlace estándar<a>en un botón posicionado justo al lado del título principal (ideal para acciones como "Añadir nuevo")..wp-header-end: Se aplica a una etiqueta<hr>. Actúa como un separador invisible que limpia los elementos flotantes del encabezado (clearfix) y marca el inicio del contenido real.
Sistema de Notificaciones (Admin Notices)
Las alertas de estado son fundamentales para informar al usuario sobre el resultado de una acción (como guardar configuraciones). Todas comparten una clase base y se modifican mediante clases de estado.
TEXT
-
Clase Base:
.notice -
Modificadores de Estado:
-
.notice-success(Borde verde): Operaciones exitosas. -
.notice-error(Borde rojo): Fallos, validaciones incorrectas. -
.notice-warning(Borde naranja): Acciones destructivas o actualizaciones pendientes. -
.notice-info(Borde azul): Información general o estado del sistema. -
Comportamiento:
.is-dismissibleinyecta automáticamente mediante JavaScript un botón (X) para que el usuario pueda cerrar la alerta.
Estructuración de Formularios
Para el desarrollo de páginas de opciones, WordPress utiliza un diseño tabular estandarizado.
.form-table: Transforma una etiqueta<table>en una cuadrícula responsiva perfecta para formularios de configuración, donde la columna izquierda contiene los<label>y la derecha los inputs.- Clases de campos de texto: Regulan la anchura de los inputs para mantener consistencia.
.regular-text: Anchura estándar (recomendada para la mayoría de campos)..small-text: Para campos numéricos o de códigos cortos..large-text: Ocupa el 100% del ancho del contenedor..code: Cambia la tipografía a monoespaciada (ideal para URLs, slugs o fragmentos de código).
Componentes de Interfaz: Botones y Tarjetas
-
Botones: WordPress unifica el diseño de los botones (sean etiquetas
<button>,<input type="submit">o<a>) a través de la clase base.button. -
.button-primary: Fondo azul sólido. Úsalo solo para la acción principal de la pantalla (como "Guardar cambios"). -
.button-secondary(o solo.button): Fondo gris claro. Para acciones secundarias (cancelar, previsualizar). -
.button-large/.button-small: Modificadores de tamaño. -
.button-link: Texto con apariencia de enlace puro pero comportamiento de botón. -
.card: Crea una caja blanca con un ligero sombreado, ideal para tableros de resumen (dashboards) o para agrupar información que no pertenece a un formulario.
Implementación Completa: Una Interfaz Nativa
El siguiente código HTML ilustra cómo combinar estas clases para construir una página de ajustes con un diseño idéntico al del Core, sin escribir una sola línea de CSS personalizado:
HTML
Resumen del capítulo
En este capítulo hemos construido los cimientos de la experiencia de usuario en el panel de administración. Exploramos cómo interactuar con el árbol de navegación interno usando add_menu_page() para establecer un punto de entrada central y add_submenu_page() para jerarquizar las opciones, garantizando en todo momento la protección mediante capacidades y permisos estandarizados.
Abordamos la vital importancia del rendimiento y la prevención de conflictos mediante el uso quirúrgico de la API de Encolado (admin_enqueue_scripts), asegurando que nuestros recursos estáticos y traducciones dinámicas con wp_localize_script() se carguen exclusivamente en nuestras propias pantallas. Finalmente, descubrimos cómo estructurar HTML utilizando las clases CSS nativas de WordPress, permitiéndonos crear interfaces que son responsivas, accesibles y visualmente coherentes con el entorno en el que residen, reduciendo nuestra deuda técnica al mínimo.
© 2026 Esdocu. Contenido bajo licencia MIT.
Editar esta página