El desarrollo de WordPress ha superado las subidas por FTP y los paneles de alojamiento compartido. En 2026, los equipos profesionales tratan WordPress como cualquier otro proyecto de software, con dependencias versiónadas, entornos containerizados y pipelines de despliegue automatizados. Si todavia esta editando archivos directamente en un servidor en producción, esta guía cambiara su forma de trabajar.
Este tutorial cubre dos enfoques complementarios para el desarrollo moderno de WordPress: Docker Compose para entornos de servidor reproducibles y Composer con Bedrock para la gestión de dependencias. Obtendra archivos de configuración completos y listos para copiar, configuración de Xdebug para depuracion PHP adecuada y un flujo de despliegue que lleva su código desde la maquina local hasta producción de forma segura.
Por que la configuración tradicional de WordPress le esta frenando
El enfoque clásico de descargar un archivo ZIP de wordpress.org y subirlo via FTP crea varios problemas que se acumulan con el tiempo:
- Desviacion de entorno - su configuración local MAMP o XAMPP nunca coincide exactamente con el servidor de producción, lo que lleva a errores del tipo “funciona en mi maquina”.
- Sin seguimiento de dependencias - los plugins y temas se descargan y actualizan manualmente, haciendo imposible reproducir exactamente el mismo sitio en otra maquina.
- Sin control de versiones para el nucleo - los archivos del nucleo de WordPress estan en su repositorio (o peor, no se rastrean en absoluto), mezclando código de aplicación con código de framework.
- Despliegues manuales - copiar archivos por FTP es propenso a errores y no proporciona mecanismo de reversión.
Docker y Composer resuelven cada uno de estos problemas de forma sistemática.
Configurar WordPress con Docker Compose
Docker Compose le permite definir toda su pila de servidor en un único archivo YAML. Cada desarrollador del equipo obtiene exactamente la misma versión de PHP, versión de MySQL y configuración de servidor ejecutando un solo comando.
Prerrequisitos
Instale Docker Desktop para su sistema operativo. Docker Desktop incluye tanto el motor Docker como el plugin CLI docker compose. Verifique la instalación:
docker --versión
docker compose versión
Estructura del proyecto
Cree un directorio de proyecto limpio:
mkdir wordpress-docker && cd wordpress-docker
mkdir -p wp-content/themes wp-content/plugins wp-content/uploads
El docker-compose.yml completo
Cree un archivo docker-compose.yml en la raiz de su proyecto:
versión: "3.9"
services:
db:
image: mysql:8.0
container_name: wp_mysql
restart: unless-stopped
environment:
MYSQL_DATABASE: ${DB_NAME:-wordpress}
MYSQL_USER: ${DB_USER:-wpuser}
MYSQL_PASSWORD: ${DB_PASSWORD:-wppassword}
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootpassword}
volumes:
- db_data:/var/lib/mysql
ports:
- "3306:3306"
networks:
- wp_network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
wordpress:
image: wordpress:6.7-php8.3-apache
container_name: wp_app
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_NAME: ${DB_NAME:-wordpress}
WORDPRESS_DB_USER: ${DB_USER:-wpuser}
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD:-wppassword}
WORDPRESS_DEBUG: ${WP_DEBUG:-1}
WORDPRESS_CONFIG_EXTRA: |
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
define('SCRIPT_DEBUG', true);
define('DISALLOW_FILE_EDIT', true);
volumes:
- ./wp-content/themes:/var/www/html/wp-content/themes
- ./wp-content/plugins:/var/www/html/wp-content/plugins
- ./wp-content/uploads:/var/www/html/wp-content/uploads
- ./php-custom.ini:/usr/local/etc/php/conf.d/custom.ini
ports:
- "8080:80"
networks:
- wp_network
phpmyadmin:
image: phpmyadmin:5
container_name: wp_phpmyadmin
restart: unless-stopped
depends_on:
- db
environment:
PMA_HOST: db
PMA_PORT: 3306
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootpassword}
ports:
- "8081:80"
networks:
- wp_network
mailhog:
image: mailhog/mailhog:latest
container_name: wp_mailhog
ports:
- "1025:1025"
- "8025:8025"
networks:
- wp_network
volumes:
db_data:
networks:
wp_network:
driver: bridge
Esta configuración le proporciona cuatro servicios:
- MySQL 8.0 con verificación de salud para que WordPress espere a que la base de datos este lista antes de iniciar.
- WordPress 6.7 en PHP 8.3 con Apache, montando solo sus temas, plugins y subidas personalizados.
- phpMyAdmin para gestión visual de la base de datos en
http://localhost:8081. - MailHog para capturar correos electronicos salientes durante el desarrollo en
http://localhost:8025.
Variables de entorno con .env
Cree un archivo .env en la raiz del proyecto:
# Base de datos
DB_NAME=wordpress
DB_USER=wpuser
DB_PASSWORD=secure_local_password_2026
DB_ROOT_PASSWORD=secure_root_password_2026
# WordPress
WP_DEBUG=1
# Sitio
SITE_URL=http://localhost:8080
Docker Compose lee automáticamente archivos .env del directorio del proyecto. Agregue .env a su .gitignore inmediatamente y haga commit de una plantilla .env.example en su lugar.
Configuración PHP personalizada
Cree php-custom.ini para ajustes PHP amigables con el desarrollo:
upload_max_filesize = 128M
post_max_size = 128M
memory_limit = 512M
max_execution_time = 300
max_input_vars = 3000
display_errors = On
error_reporting = E_ALL
Iniciar el entorno
docker compose up -d
Abra http://localhost:8080 y complete la instalación de WordPress. Sus directorios de temas y plugins estan montados desde la maquina anfitriona, por lo que cualquier cambio que haga en su editor aparece instantaneamente en la instancia de WordPress en ejecucion.
Comandos Docker utiles para el trabajo diario
# Ver registros de todos los contenedores
docker compose logs -f
# Ver registros solo de WordPress
docker compose logs -f wordpress
# Abrir una shell dentro del contenedor WordPress
docker compose exec wordpress bash
# Ejecutar comandos WP-CLI dentro del contenedor
docker compose exec wordpress wp plugin list --allow-root
# Detener todos los contenedores (preserva datos)
docker compose stop
# Detener y eliminar contenedores (preserva datos de volumenes)
docker compose down
# Reinicio completo incluyendo base de datos
docker compose down -v
WordPress basado en Composer con Bedrock
Mientras Docker maneja el entorno de servidor, Bedrock de Roots reestructura WordPress en si mismo como una aplicación correctamente gestionada por Composer. Bedrock trata el nucleo de WordPress como una dependencia, no como la raiz del proyecto, lo que cambia todo sobre como gestiona y despliega WordPress.
Por que Bedrock importa
WordPress estándar mezcla código de aplicación (su tema, plugins) con código de framework (wp-admin, wp-includes) en el mismo directorio. Bedrock separa estas preocupaciones:
project-root/
config/ # Configuración específica del entorno
application.php
environments/
development.php
staging.php
production.php
web/ # Raiz del documento (publica)
app/ # Equivalente a wp-content
themes/
plugins/
uploads/
wp/ # Nucleo de WordPress (gestionado por Composer)
wp-config.php # Cargador minimo
vendor/ # Dependencias de Composer
.env # Variables de entorno
composer.json # Manifiesto de dependencias
El nucleo de WordPress reside en web/wp/ y nunca se modifica. Su código personalizado reside en web/app/. El directorio vendor/ y web/wp/ estan ambos en el gitignore porque Composer los recrea a partir de composer.json.
Instalar Bedrock
composer create-project roots/bedrock my-wordpress-project
cd my-wordpress-project
La estructura de composer.json
El composer.json de Bedrock gestiona el nucleo de WordPress, plugins y temas como paquetes:
{
"name": "your-agency/clientes-project",
"type": "project",
"license": "MIT",
"description": "WordPress project managed with Bedrock and Composer",
"require": {
"php": ">=8.1",
"composer/installers": "^2.3",
"vlucas/phpdotenv": "^5.6",
"oscarotero/env": "^2.1",
"roots/bedrock-autoloader": "^1.0",
"roots/bedrock-disallow-indexing": "^2.0",
"roots/wordpress": "6.7.*",
"roots/wp-config": "1.0.0",
"roots/wp-password-bcrypt": "1.1.0",
"wpackagist-plugin/wordpress-seo": "^23.0",
"wpackagist-plugin/wp-super-cache": "^1.12",
"wpackagist-plugin/wordfence": "^7.11"
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.10",
"roave/security-advisories": "dev-latest"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"allow-plugins": {
"composer/installers": true,
"roots/wordpress-core-installer": true
}
},
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org",
"only": [
"wpackagist-plugin/*",
"wpackagist-theme/*"
]
}
],
"extra": {
"installer-paths": {
"web/app/mu-plugins/{$name}/": [
"type:wordpress-muplugin"
],
"web/app/plugins/{$name}/": [
"type:wordpress-plugin"
],
"web/app/themes/{$name}/": [
"type:wordpress-theme"
]
},
"wordpress-install-dir": "web/wp"
}
}
El punto clave: WordPress Packagist replica todo el repositorio de plugins y temas de WordPress.org como paquetes Composer. Agregar un plugin es tan simple como:
composer require wpackagist-plugin/advanced-custom-fields
Eliminarlo es igualmente limpio:
composer remove wpackagist-plugin/advanced-custom-fields
Configuración de entorno Bedrock
Bedrock usa archivos .env en lugar de codificar valores directamente en wp-config.php:
# Archivo .env para Bedrock
DB_NAME=wordpress
DB_USER=wpuser
DB_PASSWORD=secure_local_password_2026
DB_HOST=db:3306
DB_PREFIX=wp_
WP_ENV=development
WP_HOME=http://localhost:8080
WP_SITEURL=${WP_HOME}/wp
# Genere estos en https://roots.io/salts.html
AUTH_KEY='generate-unique-key-here'
SECURE_AUTH_KEY='generate-unique-key-here'
LOGGED_IN_KEY='generate-unique-key-here'
NONCE_KEY='generate-unique-key-here'
AUTH_SALT='generate-unique-salt-here'
SECURE_AUTH_SALT='generate-unique-salt-here'
LOGGED_IN_SALT='generate-unique-salt-here'
NONCE_SALT='generate-unique-salt-here'
Cada entorno (desarrollo, staging, producción) tiene su propio archivo .env en su respectivo servidor. La misma base de código se ejecuta en todas partes, con el comportamiento controlado completamente por variables de entorno.
Combinar Docker y Bedrock
El verdadero poder surge al ejecutar Bedrock dentro de Docker. Modifique el docker-compose.yml para montar su proyecto Bedrock en lugar de la imagen WordPress predeterminada:
services:
wordpress:
build:
context: .
dockerfile: Dockerfile
volumes:
- .:/var/www/html
environment:
- WP_ENV=development
Con un Dockerfile personalizado:
FROM php:8.3-apache
RUN apt-get update && apt-get install -y \
libzip-dev \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
libicu-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install \
mysqli \
pdo_mysql \
zip \
gd \
intl \
opcache
RUN a2enmod rewrite
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
ENV APACHE_DOCUMENT_ROOT /var/www/html/web
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' \
/etc/apache2/sites-available/*.conf \
/etc/apache2/apache2.conf
WORKDIR /var/www/html
Esto le da un entorno Bedrock completamente containerizado donde composer install se ejecuta dentro del contenedor y la raiz del documento apunta al directorio web/ de Bedrock.
Configuración de Xdebug para depuracion PHP
La depuracion paso a paso reemplaza var_dump y error_log con un depurador adecuado que le permite pausar la ejecucion, inspeccionar variables y recorrer el código linea por linea.
Agregar Xdebug a su contenedor Docker
Cree un archivo xdebug.ini:
[xdebug]
zend_extensión=xdebug
xdebug.mode=debug,develop
xdebug.start_with_request=yes
xdebug.clientes_host=host.docker.internal
xdebug.clientes_port=9003
xdebug.discover_client_host=0
xdebug.log=/tmp/xdebug.log
xdebug.idekey=VSCODE
Agregue la instalación de Xdebug a su Dockerfile:
RUN pecl install xdebug-3.3.2 \
&& docker-php-ext-enable xdebug
COPY xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
Configuración de VS Code
Cree .vscode/launch.json en la raiz de su proyecto:
{
"versión": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug (Docker)",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
},
"log": true
}
]
}
Instale la extensión PHP Debug de Xdebug en VS Code, establezca un breakpoint en cualquier archivo PHP, presione F5 para comenzar a escuchar y recargue su página WordPress. El depurador se detendra en su breakpoint.
Configuración de PhpStorm
PhpStorm maneja las conexiónes Xdebug de Docker de forma nativa:
- Vaya a Settings > PHP > Debug y verifique que el puerto 9003 esta configurado.
- Vaya a Settings > PHP > Servers, agregue un nuevo servidor con
localhosten el puerto8080y configure el mapeo de rutas de/var/www/htmla la raiz de su proyecto. - Haga clic en el boton Start Listening for PHP Debug Connections en la barra de herramientas.
Flujo de despliegue: de local a staging a producción
Una pipeline de despliegue profesional asegura que los cambios de código fluyan predeciblemente desde el desarrollo hasta producción sin copia manual de archivos.
El modelo de tres entornos
- Local (Docker) - donde escribe y prueba código.
- Staging - un servidor que refleja producción para pruebas finales.
- Producción - el sitio en vivo.
Despliegue basado en Git con GitHub Actions
Su repositorio debe contener el código del tema, plugin y configuración de Bedrock. No debe contener el nucleo de WordPress, vendor/ ni uploads/.
Ejemplo .github/workflows/deploy.yml:
name: Deploy to staging
on:
push:
branches: [staging]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-versión: "8.3"
- name: Install dependencies
run: composer install --no-dev --optimize-autoloader
- name: Run code quality checks
run: vendor/bin/phpcs --standard=WordPress web/app/themes/
- name: Deploy via rsync
uses: burnett01/rsync-deployments@7.0
with:
switches: -avz --delete --exclude='.env' --exclude='web/app/uploads/'
path: ./
remote_path: /var/www/staging.example.com/
remote_host: ${{ secrets.STAGING_HOST }}
remote_user: ${{ secrets.STAGING_USER }}
remote_key: ${{ secrets.STAGING_SSH_KEY }}
Sincronizacion de base de datos y archivos subidos
El código se despliega a través de Git, pero las bases de datos y los archivos multimedia requieren un manejo separado:
# Exportar base de datos de producción
wp db export production-backup.sql --ssh=user@production
# Importar en staging
wp db import production-backup.sql --ssh=user@staging
# Buscar y reemplazar URLs
wp search-replace 'https://example.com' 'https://staging.example.com' --ssh=user@staging
# Sincronizar subidas de producción a staging
rsync -avz user@production:/var/www/html/web/app/uploads/ \
user@staging:/var/www/html/web/app/uploads/
Para el desarrollo local, use los comandos WP-CLI wp db export y wp db import a través de Docker:
docker compose exec wordpress wp db export /tmp/backup.sql --allow-root
docker cp wp_app:/tmp/backup.sql ./backups/
Comparación: Docker vs Composer vs LocalWP vs MAMP
| Funcionalidad | Docker Compose | Composer (Bedrock) | LocalWP | MAMP/XAMPP |
|---|---|---|---|---|
| Reproducibilidad del entorno | Excelente - definida en código | N/A (solo gestión de código) | Limitada - por maquina | Limitada - por maquina |
| Consistencia de equipo | Paridad total entre maquinas | Paridad total para dependencias | Configuración manual por desarrollador | Configuración manual por desarrollador |
| Control de versión PHP | Versión exacta en Dockerfile | Requiere servidor separado | Intercambiable por sitio | Configuración global |
| Gestión de dependencias | N/A (solo servidor) | Excelente - composer.lock | Ninguna | Ninguna |
| Paridad con producción | Coincide exactamente con producción | Coincide con dependencias de producción | Aproximada | Aproximada |
| Curva de aprendizaje | Moderada - requiere comodidad con CLI | Moderada - conocimiento del ecosistema PHP | Baja - basada en GUI | Baja - basada en GUI |
| Integración CI/CD | Nativa | Nativa | Ninguna | Ninguna |
| Aislamiento multiproyecto | Aislamiento completo de contenedores | Separado por proyecto | Separado por sitio | Servidor compartido |
| Configuraciónes de servidor | Control total | N/A | Limitadas | Limitadas |
| Velocidad de arranque | Moderada (el primer pull es lento) | Rápida (composer install) | Rápida | Rápida |
La conclusion principal: Docker y Composer son complementarios, no competidores. Docker reemplaza a MAMP/XAMPP como entorno de servidor, mientras que Composer reemplaza la gestión manual de plugins/temas. LocalWP sigue siendo una opción válida para prototipado rápido, pero carece de la reproducibilidad e integración CI/CD que los equipos profesionales necesitan.
Consejos de rendimiento para Docker en macOS
Docker en macOS sufrio historicamente de un rendimiento lento del sistema de archivos debido a la capa de virtualizacion. En 2026, Docker Desktop usa VirtioFS por defecto, lo que mejora dramaticamente las velocidades de E/S. Si todavia experimenta lentitud:
- Verifique que VirtioFS esta habilitado en Docker Desktop > Settings > General.
- Limite los volumenes montados solo a lo que necesita (temas, plugins, subidas), no a toda la instalación de WordPress.
- Use las directivas de cache integradas de Docker si es necesario:
volumes: - ./wp-content:/var/www/html/wp-content:cached. - Asigne recursos suficientes en Docker Desktop > Settings > Resources (al menos 4 GB de RAM y 2 CPUs).
Consideraciones de seguridad para el desarrollo local
Incluso en entornos locales, los habitos de seguridad importan porque las configuraciónes a menudo se filtran a producción:
- Nunca haga commit de archivos
.enven Git. Use.env.examplecomo plantilla. - Use contrasenas fuertes y únicas en su
.envincluso localmente, para nunca desplegar accidentalmente credenciales debiles. - Mantenga
DISALLOW_FILE_EDITconfigurado comotrueen todos los entornos. - Ejecute
composer auditregularmente para verificar vulnerabilidades conocidas en sus dependencias. - Fije versiones específicas en
composer.jsonpara despliegues en producción en lugar de usar restricciones de versión flexibles.
Solución de problemas comunes
El contenedor MySQL se cierra inmediatamente
Verifique los registros con docker compose logs db. La causa más comun es un volumen existente con datos incompatibles. Ejecute docker compose down -v para eliminar volumenes y comenzar de nuevo.
WordPress no puede conectarse a la base de datos
Verifique que el valor WORDPRESS_DB_HOST coincide con el nombre del servicio en docker-compose.yml (tipicamente db:3306). Asegurese de que el contenedor de la base de datos esta saludable antes de que WordPress inicie, usando la condicion depends_on mostrada en la configuración anterior.
Xdebug no se conecta
Confirme que host.docker.internal se resuelve correctamente dentro del contenedor. En Linux, puede necesitar agregar extra_hosts: - "host.docker.internal:host-gateway" a la definicion del servicio WordPress.
Errores de permisos de archivos
Si WordPress no puede escribir en wp-content/uploads, ajuste los permisos dentro del contenedor:
docker compose exec wordpress chown -R www-data:www-data /var/www/html/wp-content/uploads
Proximos pasos para su flujo de trabajo
Una vez que tenga Docker y Composer funcionando, considere estas adiciones para profesionalizar aun más su configuración:
- WP-CLI como dependencia de Composer para gestión de WordPress mediante scripts.
- PHPStan o Psalm para análisis estatico del código PHP de sus temas y plugins.
- GitHub Actions o GitLab CI para pruebas automatizadas en cada pull request.
- Redis o Memcached como servicio Docker adicional para cache de objetos durante el desarrollo.
- Traefik o Nginx Proxy para gestionar multiples proyectos WordPress locales con dominios personalizados en lugar de números de puerto.
La ingenieria WordPress moderna significa tratar su sitio como un producto de software, con builds reproducibles, pruebas automatizadas y despliegues seguros. Las herramientas cubiertas en esta guía, Docker Compose para entornos y Composer con Bedrock para gestión de dependencias, forman la base que todo equipo WordPress serio necesita en 2026.
En wppoland.com, construimos y mantenemos proyectos WordPress usando exactamente estos flujos de trabajo. Si su equipo necesita ayuda para modernizar su proceso de desarrollo WordPress, configurar pipelines CI/CD o migrar de configuraciónes heredadas a entornos containerizados, nuestro equipo de ingenieria esta disponible para consultoria e implementación. Los precios son siempre individuales y dependen del alcance de su proyecto.


