Automatización de CI/CD para WordPress con GitHub Actions y Deployments
Imagina que lanzas una actualización crítica de seguridad en tu sitio WordPress y, en lugar de hacerlo manualmente a las 3 a.m., un flujo automatizado lo despliega en segundos con solo hacer git push. Eso es el CI/CD WordPress. La integración continua (CI) y el despliegue continuo (CD) son la columna vertebral de cualquier flujo de trabajo moderno de WordPress DevOps.
Tradicionalmente, actualizar un WordPress implicaba FTP, plugins de terceros o scripts caseros frágiles. Hoy, con GitHub Actions, puedes construir pipelines robustos que comprueben la calidad del código, ejecuten tests, construyan assets y desplieguen tu sitio en producción o staging sin intervención manual. Este artículo te guiará paso a paso para implementar un sistema de deployment automatizado que transformará tu forma de trabajar.
¿Por qué Automatizar el CI/CD en WordPress?
WordPress no es solo un CMS; es un ecosistema complejo con temas, plugins, archivos de configuración (wp-config.php) y una base de datos. Automatizar su ciclo de vida aporta beneficios concretos:
- Elimina el error humano: Olvídate de subir archivos incorrectos o perder cambios.
- Velocidad de entrega: Cada commit puede convertirse en un deploy en minutos.
- Calidad asegurada: Ejecuta linters (PHPCS, ESLint) y tests unitarios antes de tocar producción.
- Rollback sencillo: Si algo falla, revertir es tan simple como restaurar un commit en Git.
- Entornos consistentes: Desarrollo, staging y producción se mantienen sincronizados.
[INFO] El CI/CD no reemplaza los backups de base de datos. El pipeline se enfoca en archivos de código (temas, plugins, mu-plugins). La base de datos debe gestionarse con herramientas como WP-CLI o migraciones de plugins especializados.
Conceptos Clave Antes de Empezar
Antes de escribir el primer workflow, necesitas tener claros estos conceptos:
GitHub Actions
Es la plataforma de CI/CD integrada en GitHub. Se basa en workflows (archivos YAML dentro de .github/workflows/) que se activan por eventos (push, pull request, schedule).
Artefactos y Secrets
- Artefactos: Archivos generados durante el pipeline (por ejemplo, un tema compilado con Webpack).
- Secrets: Variables de entorno cifradas (claves SSH, tokens de API, credenciales de servidor). Nunca las pongas en el código.
Estrategias de Deploy para WordPress
No todas las estrategias sirven para WordPress. Las más comunes son:
- Deploy por Git (Git push): Ideal si el servidor tiene Git instalado. Usas un hook post-receive.
- Deploy via SFTP/SSH: El pipeline se conecta al servidor y sube los archivos mediante
rsyncoscp. - Deploy a través de APIs: Si usas plataformas como Kinsta, WP Engine o Pantheon, tienen APIs específicas.
- Deploy con Docker: Más avanzado, para entornos containerizados.
Para este artículo, nos centraremos en la opción más universal y segura: deploy mediante SSH + rsync.
Configurando el Entorno de WordPress DevOps
Tu repositorio debe estar bien estructurado. Un ejemplo de estructura para un tema personalizado:
/
├── .github/
│ └── workflows/
│ └── deploy.yml
├── wp-content/
│ ├── themes/
│ │ └── mi-tema/
│ │ ├── assets/
│ │ ├── src/
│ │ ├── package.json
│ │ └── style.css
│ └── plugins/
│ └── mi-plugin/
└── .gitignore
[TIP] Mantén tu WordPress core fuera del repositorio. Solo versiona tu
wp-content(temas, plugins, uploads si es necesario) y archivos de configuración comowp-config.php(sin credenciales reales).
Preparando el Servidor
- Crea un usuario SSH dedicado (ej:
github-actions) con permisos solo sobre la carpetawp-content. - Genera un par de llaves SSH (sin passphrase) en tu máquina local:
ssh-keygen -t ed25519 -C "github-actions-wordpress". - Agrega la llave pública al
~/.ssh/authorized_keysdel usuario en el servidor. - Guarda la llave privada como un secret en GitHub:
Settings > Secrets and variables > Actions > New repository secret. NómbralaSSH_PRIVATE_KEY.
También necesitarás otros secrets:
SSH_HOST(IP o dominio del servidor)SSH_USER(el usuario creado)SSH_PORT(normalmente 22)DEPLOY_PATH(ruta absoluta awp-contenten el servidor, ej:/var/www/mi-sitio/wp-content)
Creando el Workflow de Integración Continua (CI)
El primer paso es la integración continua. Se ejecutará en cada push a la rama develop o en cada Pull Request.
Crea el archivo .github/workflows/ci.yml:
name: CI WordPress
on:
push:
branches: [ develop ]
pull_request:
branches: [ develop, main ]
jobs:
quality-check:
runs-on: ubuntu-latest
defaults:
run:
working-directory: wp-content/themes/mi-tema
steps:
- name: Checkout del código
uses: actions/checkout@v4
- name: Configurar PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
tools: composer, wp-cli
- name: Configurar Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: wp-content/themes/mi-tema/package-lock.json
- name: Instalar dependencias
run: |
npm ci
composer install --no-dev --optimize-autoloader
- name: Lint PHP (PHPCS)
run: |
vendor/bin/phpcs --standard=WordPress .
- name: Lint JavaScript (ESLint)
run: |
npx eslint assets/js/
- name: Compilar assets
run: |
npm run build
- name: Tests unitarios (si aplica)
run: |
# Aquí irían tests con PHPUnit o Jest
echo "Tests ejecutados correctamente"
Este workflow asegura que el código cumple con los estándares de WordPress antes de ser desplegado. Si falla, el proceso se detiene.
Construyendo el Pipeline de Deploy (CD)
Ahora, el despliegue continuo. Cuando se fusione un PR a main (producción) o a develop (staging), se ejecutará el deploy.
Crea el archivo .github/workflows/deploy.yml:
name: Deploy WordPress a Producción
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout del código
uses: actions/checkout@v4
- name: Configurar Node.js y compilar assets
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: wp-content/themes/mi-tema/package-lock.json
- name: Instalar y compilar tema
working-directory: wp-content/themes/mi-tema
run: |
npm ci
npm run build
# Eliminar node_modules para no subirlos
rm -rf node_modules
- name: Configurar SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts
- name: Sincronizar archivos con rsync (modo seco primero)
run: |
rsync -avz --dry-run \
-e "ssh -p ${{ secrets.SSH_PORT }}" \
--exclude 'node_modules' \
--exclude '.git' \
--exclude '.github' \
--delete \
./wp-content/ \
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ secrets.DEPLOY_PATH }}/
- name: Deploy real
run: |
rsync -avz \
-e "ssh -p ${{ secrets.SSH_PORT }}" \
--exclude 'node_modules' \
--exclude '.git' \
--exclude '.github' \
--delete \
./wp-content/ \
${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:${{ secrets.DEPLOY_PATH }}/
- name: Limpiar cachés en servidor (post-deploy)
run: |
ssh -p ${{ secrets.SSH_PORT }} ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \
"cd ${{ secrets.DEPLOY_PATH }} && wp cache flush --allow-root || echo 'WP-CLI no disponible'"
[WARNING] El flag
--deletede rsync eliminará archivos en el servidor que no existan en el repositorio. Úsalo con cuidado. Siempre ejecuta primero un--dry-runpara verificar qué se va a borrar.
Estrategias Avanzadas de Deployment Automatizado
Despliegues por Etapas (Staging + Producción)
Puedes tener dos workflows diferentes o uno solo con condicionales. Por ejemplo:
on:
push:
branches:
- develop
- main
jobs:
deploy:
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
steps:
- name: Determinar entorno
id: env
run: |
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
echo "ENV=production" >> $GITHUB_OUTPUT
else
echo "ENV=staging" >> $GITHUB_OUTPUT
fi
# ... usar secrets diferentes según el entorno
Deploy con Artefactos y Liberación (Release)
Para proyectos más grandes, puedes generar un artefacto comprimido (zip del tema o plugin) y subirlo a GitHub Releases. Luego, otro workflow se encarga de descargar la última release y desplegarla.
# En el workflow de CI
- name: Subir artefacto
uses: actions/upload-artifact@v4
with:
name: mi-tema-build
path: wp-content/themes/mi-tema/dist/
Notificaciones Post-Deploy
Integra Slack, Discord o correo para saber si el deploy fue exitoso.
- name: Notificar éxito
if: success()
uses: slackapi/slack-github-action@v1.24.0
with:
payload: |
{
"text": "✅ Deploy exitoso de mi-tema a producción"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Buenas Prácticas y Seguridad en WordPress DevOps
Gestión de Secrets
- Nunca expongas
wp-config.phpcon credenciales reales en el repositorio. Usa variables de entorno en el servidor o secrets de GitHub. - Rota las llaves SSH periódicamente.
Pruebas en Entorno Aislado
Antes de hacer deploy a producción, ejecuta el mismo workflow contra un entorno de staging. GitHub Actions permite usar matrices para probar contra múltiples versiones de PHP o WordPress.
strategy:
matrix:
php: [7.4, 8.0, 8.2]
wordpress: [6.0, 6.4]
Monitoreo Post-Deploy
Agrega un paso que verifique que el sitio responde con HTTP 200 después del deploy:
- name: Health check
run: |
curl -sSf -o /dev/null -w "%{http_code}" https://tusitio.com/wp-content/themes/mi-tema/style.css
Solución de Problemas Comunes
Error: Permission denied (publickey)
- Verifica que la llave privada en GitHub Secrets esté completa (incluye
-----BEGIN OPENSSH PRIVATE KEY-----). - Asegúrate de que la llave pública esté en
authorized_keysdel usuario correcto en el servidor.
rsync no encuentra archivos
- Revisa las rutas relativas. En el workflow,
./wp-content/es relativo al directorio raíz del repositorio. - Usa
ls -laen un paso de depuración para verificar la estructura.
El deploy es lento
- Excluye más carpetas:
--exclude 'uploads'(si las imágenes se manejan aparte). - Usa
--compressen rsync. - Considera usar un mirror o CDN para assets estáticos.
Conclusión: El Futuro de WordPress es DevOps
Implementar CI/CD WordPress con GitHub Actions no es un lujo, es una necesidad para cualquier proyecto que busque escalar con calidad. La integración continua te protege de errores tontos, y el deployment automatizado te libera de tareas repetitivas.
Empieza con un pipeline simple para un tema y ve añadiendo complejidad: tests de regresión visual, migraciones de base de datos con WP-CLI, o incluso despliegues blue-green. La inversión inicial en configurar estos workflows se amortiza la primera vez que un deploy nocturno falla y te despiertas con el sitio intacto.
[TIP] No intentes abarcar todo de golpe. Automatiza primero lo que más dolor te cause: el deploy manual. Luego añade los linters. Y finalmente, los tests. El WordPress DevOps es un viaje, no un destino.
Tu flujo de trabajo ha cambiado para siempre. Ahora, cada git push es una oportunidad para mejorar, no un riesgo.
