La instalación de cinco minutos te deja un sitio en marcha. No te deja un puesto de desarrollador. En 2026 una configuración WordPress sólida es un stack local que se puede recrear, un pipeline de lint alineado con el core, depuración segura que nunca pinta errores en el frontend y tooling de bloques que envía los mismos assets que pruebas.
Esta guía es la checklist que usamos al provisionar un nuevo repositorio de tema o plugin: tipo de entorno, wp-env, @wordpress/scripts, constantes de debug y una capa fina de blindaje en wp-config.php y mu-plugins. En proyectos con equipos en Madrid o Barcelona, el mismo .wp-env.json en git corta el debate de “en mi máquina funciona”.
Cómo instalar WordPress en local con wp-env
Las instalaciones manuales de Apache y PHP divergen. Una máquina corre PHP 8.2, otra sigue en 8.1, y los builds de bloques fallan solo en CI. El camino oficial es wp-env: contenedores Docker para WordPress, MySQL y herramientas opcionales, controlados por un .wp-env.json en la raíz del proyecto.
Instala una vez de forma global o como dependencia del proyecto:
npm install --save-dev @wordpress/env
npx wp-env startConfiguración mínima para un plugin en desarrollo:
{
"core": "WordPress/WordPress#6.7",
"plugins": [ "." ],
"config": {
"WP_DEBUG": true,
"WP_DEBUG_LOG": true,
"WP_DEBUG_DISPLAY": false,
"SCRIPT_DEBUG": true
}
}Por qué gana a un stack genérico en trabajo de plugins:
- La versión de core queda fijada en git, así que “funciona en mi máquina” deja de ser una discusión.
wp-env run clite da WP-CLI dentro de los mismos contenedores que ve el navegador.- Los tests y scripts e2e de
@wordpress/scriptsesperan este layout.
Combínalo con la documentación del entorno de desarrollo del editor de bloques cuando necesites notas de Node, create-block y extensiones de editor recomendadas.
Para trabajo de agencia que sigue en temas PHP clásicos, puedes mantener un binario PHP en el host para scripts puntuales, pero deja el sitio en wp-env para que media, cron y rewrites coincidan con staging.
Comandos útiles del día a día cuando el stack está arriba:
npx wp-env run cli wp plugin list
npx wp-env run cli wp cache flush
npx wp-env logs
npx wp-env stopMapea un dominio propio en el archivo hosts solo cuando el proyecto necesita cookies o SSO que localhost rompe. Si no, la URL por defecto basta y simplifica certificados.
Cuando un compañero clona el repo, la nota de onboarding debe tener tres líneas: instalar Docker, npm install, npx wp-env start. Cualquier cosa más larga suele significar que el entorno escapó a paquetes de host sin documentar.
WP_ENVIRONMENT_TYPE y constantes de seguridad en wp-config
Desde WordPress 5.5, WP_ENVIRONMENT_TYPE es el interruptor que debería leer cada plugin. Defínelo pronto en wp-config.php:
define( 'WP_ENVIRONMENT_TYPE', 'local' ); // local | development | staging | productionLuego ramifica el comportamiento sin inventar constantes propias:
if ( wp_get_environment_type() === 'production' ) {
// Caché activa, logging verboso apagado.
} else {
define( 'SCRIPT_DEBUG', true );
}Constantes de blindaje que van en cada boilerplate de producción:
define( 'DISALLOW_FILE_EDIT', true );
define( 'FORCE_SSL_ADMIN', true );
define( 'WP_POST_REVISIONS', 5 );
define( 'AUTOMATIC_UPDATER_DISABLED', true ); // cuando el deploy gestiona updates de coreUsa DISALLOW_FILE_MODS solo cuando el árbol entero es inmutable y las actualizaciones llegan por CI. En hosts gestionados que aún parchean plugins desde el escritorio, esa constante peleará con el host.
Las claves de autenticación y las sales no son decoración. Rótalas tras un compromiso; todas las sesiones terminan al instante. Guarda la rotación en el runbook de deploy, no en una nota adhesiva.
Linting con @wordpress/scripts
El linting es cómo te mantienes compatible con Gutenberg sin memorizar cada regla de ESLint. El paquete @wordpress/scripts envuelve webpack, Babel, ESLint, Stylelint, Jest y Playwright detrás de scripts npm familiares.
Superficie típica de package.json para un plugin de bloques:
{
"scripts": {
"start": "wp-scripts start",
"build": "wp-scripts build",
"lint:js": "wp-scripts lint-js",
"lint:css": "wp-scripts lint-css",
"lint:pkg-json": "wp-scripts lint-pkg-json",
"format": "wp-scripts format",
"packages-update": "wp-scripts packages-update"
}
}Ejecuta npm run lint:js en CI en cada pull request. Formatea con Prettier vía wp-scripts format para que los diffs hablen de lógica, no de comillas.
PHP sigue necesitando su propia puerta. Instala WordPress Coding Standards (WPCS) con Composer y corre PHPCS en temas y plugins. No esperes que @wordpress/scripts lo sustituya; cubre la mitad JS y CSS del stack.
Orden práctico de CI que atrapa la mayoría de regresiones:
composer phpcs(o tu wrapper de PHPCS)npm run lint:jsynpm run lint:cssnpm run buildpara que un webpack roto falle antes de la review- Opcional:
wp-env starty luego PHPUnit del plugin o Playwright del paquete de scripts
Ignora el output generado en build/ en las reviews de git, salvo que el proyecto commit’tee assets compilados a propósito para hosts sin Node. Prefiere build en CI o en el deploy. EditorConfig más la config Prettier por defecto del paquete scripts saca las guerras de indentación de los pull requests.
Si un tema legacy aún envía scripts de admin de la era jQuery, introduce @wordpress/scripts primero para bloques nuevos en lugar de reescribir cada enqueue el día uno. Stacks mixtos están bien; reglas mixtas no. Una config ESLint por directorio de paquete.
Cómo activar WP_DEBUG sin mostrar errores
Nunca muestres errores PHP a los visitantes. Regístralos.
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true ); // escribe en wp-content/debug.log por defecto
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );Mejor: apunta WP_DEBUG_LOG a una ruta fuera del document root y deniega acceso HTTP a cualquier debug.log residual bajo wp-content. En producción, deja WP_DEBUG en false salvo en pleno incidente. Activa SAVEQUERIES solo para sesiones cortas de profiling; cuesta memoria y no debería quedarse encendido de noche.
Complementa las constantes con herramientas que expliquen qué pasó:
- Query Monitor para hooks, llamadas HTTP y consultas lentas en la barra de admin
- Xdebug enganchado al contenedor PHP de wp-env cuando necesitas paso a paso
- DevTools del navegador con
SCRIPT_DEBUGpara cargar scripts de core sin minificar al cazar un conflicto
Cuando el staging muestra pantalla blanca, mira debug.log, el log de errores del host y wp-env logs (si es local) antes de instalar otro plugin de “debug”. La mayoría de caídas de producción por mala configuración aparecen como un fatal único en el log, no como una función que falta.
Reproduce el bug en una instancia wp-env desechable con el mismo conjunto de plugins antes de tocar constantes en producción. Si el problema solo aparece con object cache o CDN, anótalo en el ticket; Docker local no inventa Redis por ti salvo que lo añadas a la config del env.
Cómo crear bloques de WordPress con create-block
Los bloques interactivos ya no son proyectos laterales. La ruta por defecto actual es:
- Genera con
npx @wordpress/create-block my-block --variant dynamic(o static, según la estrategia de render) - Desarrolla contra wp-env para que el registro vía
block.jsoncoincida con un admin real - Usa
npm startpara watch builds ynpm run buildpara assets de producción - Registra el bloque en PHP con
register_block_type( __DIR__ . '/build' )cuando la metadata vive enblock.json
Mantén scripts de editor y frontend separados en block.json para no enviar React solo de editor a cada visitante. Prefiere viewScript / viewStyle para interactividad en el frontend en lugar de volcar todo en un bundle.
En temas que aún hacen enqueue de assets clásicos, migra piezas interactivas nuevas a bloques de forma incremental. Un tema híbrido puede enviar block patterns y unos pocos bloques custom mientras el resto de plantillas sigue en PHP. Eso es normal en 2026; un rewrite completo del Site Editor es decisión de producto, no requisito de tooling.
Cuando las dependencias se desvían, npx wp-scripts packages-update refresca paquetes @wordpress/* dentro de la toolchain de scripts. Fija majors en package-lock.json y revisa el lockfile en los PRs igual que las actualizaciones de Composer.
Desactivar emojis y XML-RPC con un mu-plugin
No necesitas un plugin “desactivar todo” del directorio. Un must-use pequeño mantiene las reglas en control de versiones:
<?php
/**
* Plugin Name: Lean core
*/
remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
remove_action( 'wp_print_styles', 'print_emoji_styles' );
remove_action( 'wp_head', 'wp_generator' );
add_filter( 'xmlrpc_enabled', '__return_false' );Desactiva XML-RPC solo cuando estés seguro de que ningún cliente remoto lo necesita. Desactiva scripts de emoji cuando controlas iconos de marca y quieres menos peticiones en el frontend. Deja RSS en sitios de contenido; sitios brochure pueden cerrar feeds con un hook intencional, no con un snippet aleatorio de un foro.
Cómo configurar Composer 2 para dependencias y plugins de WordPress
Composer 2 gestiona paquetes PHP, plugins, temas y herramientas de desarrollo de forma determinista en todo el equipo de ingeniería. En el desarrollo profesional de WordPress, las dependencias nunca deben subirse directamente al control de versiones como archivos zip sin versionar descargados a mano del repositorio de plugins. Usar Composer permite declarar versiones exactas, automatizar parches de seguridad en pipelines de CI y mantener el repositorio git limpio.
Los plugins y temas disponibles en WordPress.org se pueden instalar directamente mediante Composer utilizando el repositorio público de WPackagist (wpackagist.org). El paquete composer/installers asegura que los paquetes de tipo wordpress-plugin se ubiquen en wp-content/plugins/ y los de tipo wordpress-muplugin en wp-content/mu-plugins/, en lugar de terminar en el directorio estándar vendor/.
Un archivo composer.json probado en batalla para un proyecto WordPress moderno define restricciones estrictas de plataforma PHP, configura los instaladores requeridos e integra dependencias clave de desarrollo:
{
"name": "wppoland/proyecto-wordpress",
"description": "Configuración para desarrolladores WordPress con Composer 2",
"type": "project",
"license": "GPL-2.0-or-later",
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org"
}
],
"require": {
"php": ">=8.2",
"composer/installers": "^2.3"
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.11",
"wp-coding-standards/wpcs": "^3.1",
"phpstan/phpstan": "^1.12",
"szepeviktor/phpstan-wordpress": "^1.3",
"roave/security-advisories": "dev-latest"
},
"config": {
"allow-plugins": {
"composer/installers": true,
"dealerdirect/phpcodesniffer-composer-installer": true
},
"optimize-autoloader": true,
"sort-packages": true
},
"scripts": {
"phpcs": "phpcs --standard=WordPress src/",
"phpcbf": "phpcbf --standard=WordPress src/",
"phpstan": "phpstan analyse --level=6 src/"
}
}Haz commit siempre de composer.lock en git. El archivo lockfile garantiza que cada desarrollador del equipo y cada runner de CI ejecuten exactamente las mismas versiones de paquetes hasta el hash de commit. En servidores de producción, ejecuta composer install --no-dev --optimize-autoloader durante el despliegue. Esto omite herramientas de desarrollo, genera un mapa de clases optimizado para acelerar la ejecución y mantiene paquetes de análisis fuera del servidor web público.
Análisis estático y estándares de código PHP con PHPCS y PHPStan
Mientras que @wordpress/scripts asegura la calidad de JavaScript y CSS, el código backend en PHP requiere el mismo rigor. Ejecutar análisis estático y comprobaciones de estilo en local evita que errores de sintaxis, consultas SQL inseguras, salidas sin escapar o nonces ausentes lleguen a la revisión de código.
Aplicar WordPress Coding Standards con PHPCS
WordPress mantiene estándares oficiales de codificación (WPCS) mediante PHP_CodeSniffer. Estas reglas verifican convenciones de nomenclatura del core, formato de arrays y vulnerabilidades críticas de seguridad como entradas sin limpiar en $_POST o funciones de sanitización ausentes como sanitize_text_field() y esc_html().
Crea un archivo phpcs.xml.dist en la raíz de tu repositorio para configurar las reglas con consistencia:
<?xml version="1.0"?>
<ruleset name="WordPress Project Standards">
<description>Reglas PHPCS para proyectos de WordPress.</description>
<file>./src</file>
<arg name="basepath" value="."/>
<arg name="colors"/>
<arg name="extensions" value="php"/>
<arg name="parallel" value="8"/>
<rule ref="WordPress-Core"/>
<rule ref="WordPress-Docs"/>
<rule ref="WordPress.Security.EscapeOutput"/>
<rule ref="WordPress.Security.ValidatedSanitizedInput"/>
<exclude-pattern>*/vendor/*</exclude-pattern>
<exclude-pattern>*/node_modules/*</exclude-pattern>
<exclude-pattern>*/build/*</exclude-pattern>
</ruleset>Ejecuta composer run phpcs en local antes de abrir una pull request. Cuando existan infracciones de formato, ejecuta composer run phpcbf para corregir automáticamente espacios en blanco, indentación y alineación de docblocks sin alterar la lógica de negocio.
Análisis estático profundo con PHPStan y phpstan-wordpress
PHPCS evalúa estructura y formato, pero no analiza seguridad de tipos ni coherencia del grafo de llamadas. PHPStan examina el código PHP sin ejecutarlo, detectando métodos inexistentes, tipos erróneos en parámetros y ramas de código muertas. Dado que WordPress utiliza ganchos de acción dinámicos y variables globales, la extensión szepeviktor/phpstan-wordpress aporta a PHPStan las firmas de funciones del core, propiedades de WP_Post y argumentos de hooks.
Configura phpstan.neon.dist en nivel de reglas 6:
includes:
- vendor/szepeviktor/phpstan-wordpress/extension.neon
parameters:
level: 6
paths:
- src/
excludePaths:
- vendor/
- node_modules/
- build/Ejecutar PHPStan en tu pipeline de integración continua asegura que refactorizar la firma de una función o renombrar un callback de hook no rompa la ejecución en producción de forma imprevista.
Cómo configurar Xdebug 3 para Docker y depuración paso a paso en el IDE
Depender exclusivamente de var_dump() o del archivo de log retrasa la resolución de incidencias al depurar filtros complejos, endpoints de la REST API o transacciones de base de datos. Xdebug 3 proporciona depuración paso a paso, inspección de la pila de llamadas y seguimiento de variables directamente en Visual Studio Code o PhpStorm.
En entornos Docker modernos como wp-env o configuraciones personalizadas de Docker Compose, Xdebug 3 corre dentro del contenedor de la aplicación y se conecta con tu IDE en la máquina anfitriona. Configura Xdebug utilizando directivas modernas en tu configuración de PHP:
[xdebug]
zend_extension=xdebug.so
xdebug.mode=debug,develop
xdebug.start_with_request=trigger
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.log=/tmp/xdebug.log
xdebug.discover_client_host=0Configurar xdebug.start_with_request=trigger es indispensable para la productividad del desarrollador. Si Xdebug se ejecuta en cada petición HTTP entrante, los tiempos de carga aumentan considerablemente. Con el modo trigger, Xdebug se activa únicamente cuando se envía una cookie XDEBUG_SESSION o un parámetro en la URL, lo cual puedes controlar desde extensiones de navegador como Xdebug Helper.
Para Visual Studio Code, configura el archivo .vscode/launch.json con el mapeo de rutas adecuado entre el sistema operativo local y el sistema de archivos del contenedor Docker:
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html/wp-content/plugins/mi-plugin": "${workspaceFolder}"
}
}
]
}El mapeo de rutas asegura que los puntos de interrupción colocados en tu editor coincidan con las líneas de ejecución dentro del contenedor. Nunca despliegues Xdebug en un entorno de staging o producción; su sobrecarga reduce el rendimiento y expone variables internas del servidor.
Constantes avanzadas de wp-config para seguridad y base de datos
El archivo wp-config.php gobierna el comportamiento del runtime antes de que WordPress cargue temas o plugins. Más allá de los interruptores básicos de depuración, un desarrollador con experiencia define límites de memoria, seguridad de cookies, ejecución de cron y rutinas de reparación de base de datos para blindar tanto entornos locales como de producción.
Límites de memoria y tareas en segundo plano
Por defecto, WordPress asigna 40 MB de memoria PHP para peticiones del frontend en sitios individuales. Tiendas de WooCommerce con tráfico alto, maquetaciones densas de bloques y llamadas a la REST API superan rápidamente ese umbral, provocando errores fatales de agotamiento de memoria. Define límites explícitos en wp-config.php:
define( WP_MEMORY_LIMIT, 256M );
define( WP_MAX_MEMORY_LIMIT, 512M );La constante WP_MAX_MEMORY_LIMIT entra en acción en peticiones del panel de administración y en operaciones pesadas como redimensionado de imágenes, importaciones masivas y migraciones de esquemas.
Desvincular WP-Cron del tráfico de visitas HTTP
Por defecto, WordPress ejecuta tareas de cron durante las cargas de página de los visitantes. En sitios de tráfico bajo, las publicaciones programadas y las tareas de mantenimiento pierden su hora de ejecución. En sitios de alto tráfico, múltiples peticiones simultáneas generan procesos duplicados de cron, disparando la concurrencia en la base de datos.
Desactiva el cron ejecutado por visitantes en wp-config.php:
define( DISABLE_WP_CRON, true );
define( WP_CRON_LOCK_TIMEOUT, 60 );A continuación, configura un cron real del sistema operativo en el servidor o en un contenedor dedicado para ejecutar WP-CLI cada cinco minutos:
*/5 * * * * wp cron event run --due-now --path=/var/www/html > /dev/null 2>&1Permisos del sistema de archivos y reparación de tablas
Cuando WordPress solicita credenciales FTP durante subidas de medios o actualizaciones, muchos desarrolladores cometen el error de aplicar chmod 777 a carpetas completas. La solución segura consiste en definir el método de sistema de archivos de forma explícita:
define( FS_METHOD, direct );
define( FS_CHMOD_DIR, 0755 );
define( FS_CHMOD_FILE, 0644 );En situaciones de corrupción grave de tablas, WordPress dispone de un asistente de reparación nativo ubicado en /wp-admin/maint/repair.php. Actívalo solo durante la ventana de recuperación:
define( WP_ALLOW_REPAIR, true );Elimina WP_ALLOW_REPAIR de inmediato una vez finalizado el mantenimiento. Mantenerlo activo permite a usuarios no autenticados ejecutar rutinas de reparación y optimización en la base de datos.
Checklist antes de lanzar una web WordPress
Antes de que un sitio de cliente salga a producción:
WP_ENVIRONMENT_TYPEesproduction.DISALLOW_FILE_EDITes true; SSL en admin está forzado.- Las revisiones están limitadas; el display de debug está apagado.
- Local y CI arrancan desde el mismo
.wp-env.jsony pasan lint y build de@wordpress/scripts. - Los assets de bloques son builds de producción, no restos del modo watch.
- Las sales son únicas;
debug.logno es accesible por HTTP.
Una configuración WordPress que se recrea desde git vale más que un wp-config.php ingenioso solo. Paridad local, puertas de lint y logging honesto son lo que evita que el trabajo de bloques y el PHP clásico se peleen.
¿Necesitas una revisión sénior de un stack existente o un plugin de bloques nuevo? Habla con un desarrollador WordPress en WPPoland.
Un setup de desarrollador sin higiene de secretos sigue fallando una auditoría de seguridad WordPress: claves locales, .env compartido y clones de staging son los agujeros habituales.







