Banners Dinámicos en WordPress según la Canción: guía práctica
En la madrugada, mientras la pista de La MIX Radio seguía girando, necesitábamos que la página web mostrara un banner distinto según la canción en emisión.
Banners Dinámicos en WordPress según la Canción era la solución que buscábamos, pero no teníamos nada preparado.
En este artículo vemos cómo lo armamos con Python, n8n y la API REST de WordPress, todo dentro de nuestras VMs en Proxmox.
Banners Dinámicos en WordPress según la Canción: flujo de trabajo
Si no configuramos nada, el visitante ve siempre el mismo banner o, peor, un banner vacío.
El problema se hace evidente cuando el tráfico cae porque la presentación visual no refleja lo que está sonando.
Los síntomas típicos son: la zona del banner no cambia, la consola del navegador muestra 404 al intentar cargar la imagen y el registro de WordPress no tiene ninguna entrada de actualización.
Qué necesitas antes de empezar
- Una VM en Proxmox con Ubuntu 22.04 (usamos la VM 111).
- Icecast 2 funcionando y exponiendo la ruta
/status.xsl. - Acceso a la API REST de WordPress con un token de aplicación.
- Python 3.11 y los paquetes
requestsyxmltodictinstalados. - n8n instalado en un contenedor para orquestar la tarea.
- Un directorio
/home/lamix/banners/con imágenes nombradas por nombre de canción.
Cómo lo resolvimos, paso a paso
Primero creamos un script Python que consulta el XML de Icecast y extrae la canción actual.
El script escribe el nombre en un Custom Field de WordPress llamado current_track.
Después, n8n ejecuta el script cada minuto y, si el campo cambió, actualiza la meta‑etiqueta del post que muestra el banner.
# emily_gtts.py (parte del script)
import requests
import xmltodict
ICECAST_STATUS = 'http://localhost:8000/status.xsl'
WP_API = 'https://lamixradio.com/wp-json/wp/v2/posts/123'
WP_TOKEN = 'YOUR_WP_APPLICATION_TOKEN'
def get_current_song():
resp = requests.get(ICECAST_STATUS)
data = xmltodict.parse(resp.content)
# Ruta exacta según nuestro Icecast 2.4
return data['icestats']['source']['title']
def update_wp(song):
headers = {'Authorization': f'Bearer {WP_TOKEN}',
'Content-Type': 'application/json'}
payload = {'meta': {'current_track': song}}
requests.post(WP_API, json=payload, headers=headers)
if __name__ == '__main__':
song = get_current_song()
update_wp(song)
El script se lanza desde una tarea cron en la VM 111, pero también lo conectamos a n8n para mayor visibilidad. En n8n creamos un flujo con los nodos “Execute Command” (para Python) y “HTTP Request” (para la llamada a WordPress).
El nodo “If” comprueba si el título cambió y, sólo entonces, ejecuta la actualización.
# n8n flow (JSON abreviado)
{"nodes": [ { "name": "Run Python", "type": "n8n-nodes-base.executeCommand", "parameters": { "command": "python3 /home/lamix/emily_gtts.py"}
},
{"name": "Check Change", "type": "n8n-nodes-base.if", "parameters": { "conditions": { "string": [ { "value1": "{{$json[\"previous\"]}}", "operation": "notEquals", "value2": "{{$json[\"current\"]}}"}
]
}
}
},
{"name": "Notify Telegram", "type": "n8n-nodes-base.telegram", "parameters": { "chatId": "-123456789", "text": "Banner actualizado: {{$json[\"current\"]}}"}
}
],
"connections": {"Run Python": { "main": [ [ { "node": "Check Change", "type": "main", "index": 0}
]
]
},
"Check Change": {"main": [ [ { "node": "Notify Telegram", "type": "main", "index": 0}
]
]
}
}
}
En el tema de WordPress añadimos una pequeña función al archivo functions.php que muestra la imagen correspondiente al valor del custom field.
add_action('wp_head', function() {$track = get_post_meta(get_the_ID(), 'current_track', true); if (!$track) return; $banner_path = "/home/lamix/banners/{$track}.jpg"; if (file_exists($banner_path)) { echo "<style> .hero-banner { background-image: url('{$banner_path}'); } </style>";}
});
Con esto, cada vez que Icecast cambie la canción, el script actualiza el campo, n8n detecta el cambio y WordPress muestra el nuevo banner sin recargar la página.
Errores que nos costaron tiempo
- Síntoma: El banner nunca se actualizaba.
Causa: La ruta/status.xsldevolvía HTML en lugar de XML porque Icecast estaba en modo “admin”.
Solución: Cambiamos a/status-json.xsly ajustamosxmltodicta JSON. - Síntoma: WordPress rechazaba la petición con 401.
Causa: El token de aplicación había expirado después de 24 h.
Solución: Implementamos una renovación automática con la API de OAuth2 y guardamos el nuevo token en/home/lamix/token.txt. - Síntoma: El banner persistía aunque la canción cambiaba.
Causa: El archivo de imagen estaba en caché por Cloudflare.
Solución: Añadimos un parámetro de query aleatorio (?v=) al URL del banner para forzar la recarga.
Cómo saber que funciona
Abre la página principal y reproduce la pista “Midnight Swing”. El banner debe cambiar en menos de 60 segundos.
En la consola del navegador verás una petición GET /wp-json/wp/v2/posts/123 con el campo current_track actualizado.
Si el CSS se inserta sin errores, el .hero-banner mostrará la imagen correspondiente.
Con Banners Dinámicos en WordPress según la Canción conseguimos que la web refleje en tiempo real lo que suena en La MIX Radio.
Qué sigue
Integraremos una capa de fallback con imágenes genéricas y añadiremos análisis de clics mediante Google Analytics para medir el impacto de cada banner.

