🎨 Sysprovider Code
Sysprovider LogoWiki
🇪🇸Hosting español para ecommerce

Implementación de WebSockets en WordPress para Aplicaciones en Tiempo Real

Actualizado el 14 de junio de 2026

Introducción: El salto de WordPress a lo reactivo

WordPress, durante años, ha sido el rey del contenido estático y las arquitecturas petición-respuesta. Sin embargo, el ecosistema moderno demanda experiencias fluidas: notificaciones que aparecen sin recargar, chats de soporte instantáneos, dashboards de analíticas que se actualizan solos o subastas en vivo. Para lograr esto, necesitamos WebSockets.

La implementación de WebSockets en WordPress no es trivial. El CMS está construido sobre PHP, un lenguaje tradicionalmente sin estado, y sobre MySQL, que no gestiona bien las conexiones persistentes. Pero con las herramientas adecuadas —Ratchet, ReactPHP y un plugin personalizado— podemos convertir cualquier sitio en una plataforma en tiempo real.

Este artículo te guiará paso a paso en la arquitectura, instalación y puesta en producción de un sistema de WebSockets para WordPress, incluyendo ejemplos prácticos como un chat en vivo o un contador de usuarios online.

¿Por qué WebSockets y no AJAX o Long Polling?

Antes de ensuciarnos las manos, entendamos por qué merece la pena el esfuerzo.

  • AJAX tradicional: El cliente pregunta cada X segundos. Ineficiente, genera latencia y sobrecarga en el servidor.
  • Long Polling: Mantiene la conexión abierta, pero sigue siendo una simulación de tiempo real. Consume muchos recursos.
  • WebSockets: Conexión bidireccional y persistente. El servidor empuja datos al instante. Ideal para aplicaciones que requieren baja latencia.

[INFO] WordPress por sí solo no soporta WebSockets. Necesitas un servidor externo (basado en PHP con Ratchet o en Node.js) que gestione las conexiones. Aquí nos centraremos en la solución 100% PHP con Ratchet y ReactPHP, ideal para entornos donde no quieras introducir Node.js.

Requisitos previos y stack tecnológico

Para seguir este artículo necesitarás:

  • Un servidor con PHP 8.0+ y extensión pcntl, posix y sockets habilitadas.
  • Acceso SSH al servidor (para ejecutar el proceso en segundo plano).
  • Composer instalado globalmente.
  • Un WordPress funcional (preferiblemente con un plugin personalizado para la comunicación).

Nuestro stack será:

ComponenteFunción
RatchetBiblioteca PHP para WebSockets (basada en ReactPHP)
ReactPHPBucle de eventos asíncrono para PHP
Plugin personalizadoPunto de entrada desde WordPress al servidor WebSocket
Redis (opcional)Para escalar horizontalmente y compartir estado entre workers

Instalación del servidor WebSocket con Ratchet

1. Preparar el entorno

Conéctate por SSH a tu servidor y crea un directorio fuera del public_html (por seguridad):

mkdir /opt/websocket-server
cd /opt/websocket-server
composer require cboden/ratchet

Esto instalará Ratchet y ReactPHP como dependencias.

2. Crear el servidor WebSocket básico

Crea un archivo server.php:

<?php
require __DIR__ . '/vendor/autoload.php';

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;

class ChatServer implements MessageComponentInterface {
    protected $clients;

    public function __construct() {
        $this->clients = new \SplObjectStorage;
        echo "Servidor WebSocket iniciado.\n";
    }

    public function onOpen(ConnectionInterface $conn) {
        $this->clients->attach($conn);
        echo "Nueva conexión: {$conn->resourceId}\n";
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        $data = json_decode($msg, true);
        // Aquí procesaremos el mensaje y lo reenviaremos
        foreach ($this->clients as $client) {
            if ($from !== $client) {
                $client->send(json_encode([
                    'type' => 'chat',
                    'user' => $data['user'],
                    'message' => $data['message'],
                    'timestamp' => time()
                ]));
            }
        }
    }

    public function onClose(ConnectionInterface $conn) {
        $this->clients->detach($conn);
        echo "Conexión cerrada: {$conn->resourceId}\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "Error: {$e->getMessage()}\n";
        $conn->close();
    }
}

$server = IoServer::factory(
    new HttpServer(
        new WsServer(
            new ChatServer()
        )
    ),
    8080 // Puerto
);

$server->run();

[TIP] Usa un puerto alto (>1024) para evitar conflictos con Apache/Nginx. En producción, redirige desde el puerto 80/443 mediante proxy inverso.

3. Ejecutar el servidor

php server.php

Deberías ver: Servidor WebSocket iniciado. Para mantenerlo corriendo en segundo plano, usa nohup o screen:

nohup php server.php > /var/log/websocket.log 2>&1 &

Integración con WordPress: El plugin puente

Ahora necesitamos que WordPress se comunique con nuestro servidor WebSocket. Crearemos un plugin sencillo.

1. Estructura del plugin

Crea en wp-content/plugins/ws-integration/:

ws-integration/
├── ws-integration.php
├── includes/
│   └── class-ws-handler.php
└── assets/
    └── ws-client.js

2. Código principal del plugin (ws-integration.php)

<?php
/**
 * Plugin Name: WebSockets Integration
 * Description: Conecta WordPress con el servidor Ratchet.
 * Version: 1.0
 */

defined('ABSPATH') or die('Acceso directo no permitido.');

// Hook para cargar el JavaScript en el frontend
add_action('wp_enqueue_scripts', 'ws_enqueue_assets');
function ws_enqueue_assets() {
    wp_enqueue_script('ws-client', plugin_dir_url(__FILE__) . 'assets/ws-client.js', array(), '1.0', true);
    wp_localize_script('ws-client', 'ws_config', array(
        'server_url' => 'ws://tu-servidor.com:8080', // Cambia por tu dominio/puerto
        'user_id' => get_current_user_id(),
        'nonce' => wp_create_nonce('ws_nonce')
    ));
}

// Endpoint AJAX para enviar mensajes desde WordPress al servidor WebSocket
add_action('wp_ajax_ws_send_message', 'ws_send_message_handler');
function ws_send_message_handler() {
    check_ajax_referer('ws_nonce', 'nonce');
    
    $user_id = get_current_user_id();
    $message = sanitize_text_field($_POST['message']);
    
    // Enviar al servidor WebSocket mediante socket TCP
    $socket = @fsockopen('127.0.0.1', 8080, $errno, $errstr, 5);
    if (!$socket) {
        wp_send_json_error('No se pudo conectar al servidor WebSocket');
    }
    
    $data = json_encode([
        'type' => 'chat',
        'user' => get_userdata($user_id)->display_name,
        'message' => $message,
        'timestamp' => time()
    ]);
    
    // Enviar trama WebSocket (versión simplificada)
    $frame = chr(129) . chr(strlen($data)) . $data;
    fwrite($socket, $frame);
    fclose($socket);
    
    wp_send_json_success('Mensaje enviado');
}

[WARNING] Este ejemplo envía tramas WebSocket "a pelo". En producción, usa una librería como Textalk/websocket-php para manejar el handshake y enmascarado correctamente.

3. Cliente JavaScript (ws-client.js)

(function($) {
    'use strict';
    
    let ws;
    const serverUrl = ws_config.server_url;
    
    function connectWebSocket() {
        ws = new WebSocket(serverUrl);
        
        ws.onopen = function() {
            console.log('Conectado al servidor WebSocket');
            // Enviar autenticación
            ws.send(JSON.stringify({
                type: 'auth',
                user_id: ws_config.user_id,
                token: ws_config.nonce
            }));
        };
        
        ws.onmessage = function(event) {
            const data = JSON.parse(event.data);
            handleMessage(data);
        };
        
        ws.onclose = function() {
            console.log('Desconectado. Reconectando en 5 segundos...');
            setTimeout(connectWebSocket, 5000);
        };
        
        ws.onerror = function(error) {
            console.error('Error WebSocket:', error);
        };
    }
    
    function handleMessage(data) {
        // Ejemplo: mostrar en un chat
        if (data.type === 'chat') {
            const chatBox = $('#chat-messages');
            chatBox.append(`<p><strong>${data.user}:</strong> ${data.message}</p>`);
            chatBox.scrollTop(chatBox[0].scrollHeight);
        }
        
        // Disparar evento personalizado para otros scripts
        $(document).trigger('ws_message', [data]);
    }
    
    // Iniciar conexión
    $(document).ready(function() {
        connectWebSocket();
        
        // Enviar mensaje desde formulario
        $('#chat-form').on('submit', function(e) {
            e.preventDefault();
            const message = $('#chat-input').val();
            
            $.post(ajaxurl, {
                action: 'ws_send_message',
                message: message,
                nonce: ws_config.nonce
            });
            
            $('#chat-input').val('');
        });
    });
    
})(jQuery);

Caso práctico: Chat en vivo en WordPress

Con el servidor corriendo y el plugin activo, ya podemos implementar un chat en tiempo real.

1. Shortcode para mostrar el chat

Añade esto a tu plugin:

add_shortcode('ws_chat', 'ws_chat_shortcode');
function ws_chat_shortcode() {
    ob_start();
    ?>
    <div id="chat-container">
        <div id="chat-messages" style="height:300px; overflow-y:scroll; border:1px solid #ccc; padding:10px;">
            <!-- Los mensajes aparecerán aquí -->
        </div>
        <form id="chat-form">
            <input type="text" id="chat-input" placeholder="Escribe tu mensaje..." style="width:80%;" />
            <button type="submit">Enviar</button>
        </form>
    </div>
    <?php
    return ob_get_clean();
}

Ahora puedes insertar [ws_chat] en cualquier página o entrada.

2. Mejora: Autenticación y rooms

Para un chat más avanzado, modifica el servidor para manejar "rooms" (canales). Cada room es un array de conexiones. Así puedes tener chats privados, grupos, etc.

// En el servidor Ratchet
protected $rooms = [];

public function onMessage(ConnectionInterface $from, $msg) {
    $data = json_decode($msg, true);
    
    switch($data['type']) {
        case 'join':
            $room = $data['room'];
            $this->rooms[$room][] = $from;
            break;
        case 'chat':
            $room = $data['room'];
            foreach ($this->rooms[$room] as $client) {
                if ($from !== $client) {
                    $client->send($msg);
                }
            }
            break;
    }
}

Escalado y producción: Redis, Supervisord y proxy inverso

Un solo proceso PHP no escala bien. Para producción necesitas:

1. Múltiples workers con Redis

Instala Redis y usa la biblioteca predis/predis. Cada worker se suscribe a un canal Redis. Cuando un worker recibe un mensaje, lo publica en Redis y todos los workers lo reenvían a sus clientes.

composer require predis/predis

Ejemplo de worker con Redis:

use Predis\Async\Client as RedisClient;

$redis = new RedisClient('tcp://127.0.0.1:6379');
$redis->pubSubLoop('chat_messages', function ($event) use ($clients) {
    foreach ($clients as $client) {
        $client->send($event->payload);
    }
});

2. Supervisord para gestión de procesos

Crea /etc/supervisor/conf.d/websocket.conf:

[program:websocket]
command=php /opt/websocket-server/server.php
user=www-data
autostart=true
autorestart=true
stderr_logfile=/var/log/websocket.err.log
stdout_logfile=/var/log/websocket.out.log
numprocs=4
process_name=%(program_name)s_%(process_num)02d

Esto lanza 4 workers. Cada uno escucha en un puerto diferente o comparten el mismo puerto mediante un balanceador.

3. Proxy inverso con Nginx

Para que los clientes se conecten a wss://tudominio.com/ws (WebSocket seguro), configura Nginx:

upstream websocket {
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
    server 127.0.0.1:8082;
    server 127.0.0.1:8083;
}

server {
    listen 443 ssl;
    server_name tudominio.com;

    # SSL config...

    location /ws/ {
        proxy_pass http://websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_read_timeout 86400;
    }
}

Ahora los clientes se conectarán a wss://tudominio.com/ws/.

[TIP] Siempre usa WSS (WebSocket sobre TLS) en producción. Los navegadores modernos bloquean conexiones WS desde páginas HTTPS.

Consideraciones de seguridad

No puedes lanzar un servidor WebSocket sin pensar en seguridad:

  1. Autenticación: Valida tokens JWT o nonces de WordPress en cada conexión. El servidor debe rechazar conexiones no autorizadas.
  2. Rate limiting: Limita mensajes por segundo por IP/usuario para evitar spam.
  3. Validación de datos: Nunca confíes en el cliente. Sanitiza todo en el servidor.
  4. CORS: Configura orígenes permitidos en el servidor WebSocket.
  5. Aislamiento de procesos: Ejecuta el servidor con un usuario sin privilegios (nunca root).

Alternativas: Node.js vs Ratchet

Si tu equipo está más cómodo con JavaScript, puedes usar Socket.IO con Node.js. La integración con WordPress se haría mediante una API REST personalizada. Las ventajas de Ratchet son:

  • Todo en PHP, sin cambiar de stack.
  • Fácil integración con funciones nativas de WordPress (wpdb, wp_users, etc.).
  • Bajo consumo de memoria en procesos ligeros.

Las desventajas: la comunidad PHP en tiempo real es más pequeña, y el rendimiento puro es inferior a Node.js en conexiones masivas (>10k simultáneas).

Monitorización y debugging

Para ver qué ocurre en tu servidor WebSocket:

# Ver logs en tiempo real
tail -f /var/log/websocket.out.log

# Probar conexión con wscat (instalar con npm)
wscat -c ws://localhost:8080
> {"type":"chat","user":"test","message":"hola"}
< {"type":"chat","user":"test","message":"hola","timestamp":...}

También puedes usar herramientas como WebSocket King (extensión Chrome) para inspeccionar tráfico.

Conclusión: ¿Merece la pena?

Implementar WebSockets en WordPress con Ratchet y ReactPHP no es un paseo por el parque, pero los beneficios son enormes:

  • Experiencia de usuario instantánea.
  • Reducción de carga en el servidor (eliminas polling).

¿Necesitas ayuda?Son dos de nuestros técnicos, Agustín y Mikel, y están disponibles para resolver cualquier problema.

Hablar con ellos ahora
Agustín y Mikel