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

Implementación de WebSockets en WordPress con React y Node.js

Actualizado el 31 de diciembre de 2025

Imagina un panel de administración de WordPress donde los cambios de estado de un pedido se reflejan al instante, sin necesidad de recargar la página. O un sistema de chat en vivo donde los mensajes llegan sin latencia. Esto es posible gracias a los WebSockets, una tecnología que permite comunicación bidireccional en tiempo real entre el servidor y el cliente. En este artículo, exploraremos cómo implementar una arquitectura de WebSockets WordPress utilizando React en el frontend y Node.js como servidor de eventos. El objetivo es construir un sistema de chat en vivo completamente funcional, integrado con las capacidades de autenticación y base de datos de WordPress.


¿Por qué WebSockets en WordPress?

WordPress, por defecto, funciona bajo el modelo HTTP request-response. Cada vez que necesitas actualizar datos, debes hacer una petición AJAX o recargar la página. Esto es ineficiente para aplicaciones que requieren tiempo real WordPress, como notificaciones, paneles de administración en vivo o chats.

WebSockets resuelven este problema estableciendo un canal de comunicación persistente. Con una arquitectura basada en Node.js WordPress, podemos externalizar la lógica de tiempo real, liberando al servidor de WordPress de mantener conexiones abiertas (algo para lo que no está optimizado).

[INFO] WordPress maneja las sesiones PHP de forma bloqueante. Los WebSockets requieren un proceso no bloqueante y asíncrono, por lo que Node.js es el compañero ideal para esta tarea.


Componentes de la solución

Para implementar WebSockets WordPress necesitaremos tres capas bien definidas:

  1. WordPress (Backend PHP): Actúa como fuente de verdad. Almacena usuarios, mensajes y gestiona autenticación mediante JWT.
  2. Node.js + Socket.IO: Servidor de WebSockets que maneja las conexiones, emite eventos y sincroniza datos con WordPress.
  3. React (Frontend): Cliente que se conecta al servidor Node.js y renderiza la interfaz de chat en vivo.

Flujo de datos típico

  1. Un usuario envía un mensaje desde la interfaz React.
  2. React envía el mensaje a Node.js mediante WebSocket.
  3. Node.js valida el token JWT (generado por WordPress) y guarda el mensaje en la base de datos de WordPress (vía REST API).
  4. Node.js emite el mensaje a todos los clientes conectados a la sala correspondiente.

Configuración inicial del entorno

Requisitos previos

  • WordPress 5.0+ con REST API habilitada.
  • Node.js 18+ y npm.
  • Un plugin de autenticación JWT para WordPress (recomendamos JWT Authentication for WP REST API).
  • React instalado (usaremos create-react-app).

Instalación de dependencias

En tu proyecto de React:

npm install socket.io-client

En tu servidor Node.js:

npm install express socket.io jsonwebtoken axios cors dotenv

Paso 1: Preparar WordPress para WebSockets

WordPress no manejará directamente las conexiones WebSocket, pero debe exponer endpoints para que Node.js pueda leer y escribir datos.

1.1 Crear un Custom Post Type para mensajes

Registra un CPT llamado chat_message en tu tema o plugin:

function register_chat_message_cpt() {
    $args = array(
        'public'       => true,
        'label'        => 'Mensajes de Chat',
        'show_in_rest' => true,
        'supports'     => array('title', 'editor', 'author', 'custom-fields')
    );
    register_post_type('chat_message', $args);
}
add_action('init', 'register_chat_message_cpt');

1.2 Configurar JWT Authentication

Instala y activa el plugin JWT Authentication for WP REST API. Luego añade estas constantes a tu wp-config.php:

define('JWT_AUTH_SECRET_KEY', 'tu-clave-secreta-aqui');
define('JWT_AUTH_CORS_ENABLE', true);

1.3 Endpoints REST personalizados

Crea un endpoint para que Node.js pueda validar tokens y obtener datos del usuario:

add_action('rest_api_init', function () {
    register_rest_route('chat/v1', '/validate-token', array(
        'methods' => 'POST',
        'callback' => 'validate_token_callback',
        'permission_callback' => '__return_true'
    ));
});

function validate_token_callback($request) {
    $token = $request->get_param('token');
    // Lógica para decodificar y validar el token
    // Devuelve datos del usuario si es válido
}

Paso 2: Construir el servidor Node.js con Socket.IO

Crearemos un servidor que escuche eventos WebSocket y se comunique con WordPress vía REST API.

2.1 Estructura del servidor

// server.js
const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const axios = require('axios');
const jwt = require('jsonwebtoken');

const app = express();
const server = http.createServer(app);
const io = socketIO(server, {
    cors: {
        origin: "http://tusitio.local",
        methods: ["GET", "POST"]
    }
});

const WP_API_URL = 'http://tusitio.local/wp-json';
const JWT_SECRET = 'tu-clave-secreta';

2.2 Autenticación vía middleware de Socket.IO

io.use((socket, next) => {
    const token = socket.handshake.auth.token;
    if (!token) {
        return next(new Error('Token no proporcionado'));
    }
    
    try {
        const decoded = jwt.verify(token, JWT_SECRET);
        socket.userId = decoded.data.user.id;
        socket.userName = decoded.data.user.display_name;
        next();
    } catch (err) {
        next(new Error('Token inválido'));
    }
});

2.3 Manejo de eventos de chat

io.on('connection', (socket) => {
    console.log(`Usuario conectado: ${socket.userName}`);
    
    // Unirse a una sala (por ejemplo, por ID de conversación)
    socket.on('join-room', (roomId) => {
        socket.join(roomId);
        socket.currentRoom = roomId;
    });
    
    // Recibir y reenviar mensajes
    socket.on('send-message', async (messageData) => {
        const message = {
            user_id: socket.userId,
            user_name: socket.userName,
            content: messageData.content,
            room_id: messageData.roomId,
            timestamp: Date.now()
        };
        
        // Guardar en WordPress
        try {
            await axios.post(`${WP_API_URL}/wp/v2/chat_message`, {
                title: `Mensaje de ${socket.userName}`,
                content: message.content,
                meta: {
                    room_id: message.room_id,
                    user_id: message.user_id
                }
            }, {
                headers: {
                    'Authorization': `Bearer ${socket.handshake.auth.token}`
                }
            });
            
            // Emitir a todos en la sala
            io.to(message.room_id).emit('new-message', message);
        } catch (error) {
            socket.emit('error', 'No se pudo guardar el mensaje');
        }
    });
    
    socket.on('disconnect', () => {
        console.log(`Usuario desconectado: ${socket.userName}`);
    });
});

server.listen(3000, () => {
    console.log('Servidor WebSocket corriendo en puerto 3000');
});

Paso 3: Integrar React con Socket.IO

Ahora construiremos el frontend que se conecta al servidor Node.js.

3.1 Configuración del contexto de Socket

// socketContext.js
import React, { createContext, useContext, useEffect, useState } from 'react';
import io from 'socket.io-client';

const SocketContext = createContext();

export const useSocket = () => useContext(SocketContext);

export const SocketProvider = ({ children, token }) => {
    const [socket, setSocket] = useState(null);
    
    useEffect(() => {
        const newSocket = io('http://localhost:3000', {
            auth: { token }
        });
        
        newSocket.on('connect', () => {
            console.log('Conectado al servidor WebSocket');
        });
        
        newSocket.on('connect_error', (err) => {
            console.error('Error de conexión:', err.message);
        });
        
        setSocket(newSocket);
        
        return () => newSocket.close();
    }, [token]);
    
    return (
        <SocketContext.Provider value={socket}>
            {children}
        </SocketContext.Provider>
    );
};

3.2 Componente de Chat en Tiempo Real

// ChatBox.js
import React, { useState, useEffect } from 'react';
import { useSocket } from './socketContext';

const ChatBox = ({ roomId }) => {
    const socket = useSocket();
    const [messages, setMessages] = useState([]);
    const [input, setInput] = useState('');
    
    useEffect(() => {
        if (!socket) return;
        
        socket.emit('join-room', roomId);
        
        socket.on('new-message', (message) => {
            setMessages(prev => [...prev, message]);
        });
        
        return () => {
            socket.off('new-message');
        };
    }, [socket, roomId]);
    
    const sendMessage = (e) => {
        e.preventDefault();
        if (!input.trim()) return;
        
        socket.emit('send-message', {
            content: input,
            roomId: roomId
        });
        
        setInput('');
    };
    
    return (
        <div className="chat-box">
            <div className="messages">
                {messages.map((msg, index) => (
                    <div key={index} className="message">
                        <strong>{msg.user_name}:</strong> {msg.content}
                    </div>
                ))}
            </div>
            <form onSubmit={sendMessage}>
                <input
                    type="text"
                    value={input}
                    onChange={(e) => setInput(e.target.value)}
                    placeholder="Escribe un mensaje..."
                />
                <button type="submit">Enviar</button>
            </form>
        </div>
    );
};

export default ChatBox;

Paso 4: Consideraciones de seguridad y rendimiento

4.1 Validación de tokens en cada evento

Nunca confíes ciegamente en el socket. Cada evento crítico (guardar, eliminar) debe verificar el token JWT contra WordPress.

// En Node.js, antes de guardar un mensaje
const isValid = await axios.post(`${WP_API_URL}/chat/v1/validate-token`, {
    token: socket.handshake.auth.token
});
if (!isValid.data.valid) {
    return socket.emit('error', 'Token expirado');
}

4.2 Escalabilidad con Redis

Si esperas muchos usuarios concurrentes, usa Redis como adaptador de Socket.IO para compartir eventos entre múltiples instancias de Node.js:

npm install @socket.io/redis-adapter redis
const { createAdapter } = require('@socket.io/redis-adapter');
const { createClient } = require('redis');

const pubClient = createClient({ url: 'redis://localhost:6379' });
const subClient = pubClient.duplicate();

io.adapter(createAdapter(pubClient, subClient));

4.3 Rate Limiting

Protege tu servidor Node.js contra abusos:

const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 minutos
    max: 100, // límite de peticiones por ventana
    message: 'Demasiadas peticiones, intente más tarde'
});

app.use('/api/', limiter);

[WARNING] No expongas el servidor Node.js directamente a Internet sin un proxy inverso (Nginx, Caddy) que maneje SSL y limitación de conexiones.


Paso 5: Despliegue y puesta en producción

5.1 Configuración de Nginx como proxy inverso

server {
    listen 443 ssl;
    server_name chat.tusitio.com;
    
    location / {
        proxy_pass http://localhost:3000;
        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;
    }
}

5.2 Usar PM2 para gestionar Node.js

npm install -g pm2
pm2 start server.js --name "websocket-server"
pm2 save
pm2 startup

Casos de uso avanzados

Notificaciones en tiempo real para WooCommerce

Conecta WebSockets a los hooks de WooCommerce para notificar a los administradores cuando un pedido cambie de estado:

// En WordPress
add_action('woocommerce_order_status_changed', function($order_id) {
    $order = wc_get_order($order_id);
    // Enviar datos a Node.js vía webhook
    wp_remote_post('http://localhost:3000/webhook/order-update', array(
        'body' => json_encode(array(
            'order_id' => $order_id,
            'status' => $order->get_status()
        ))
    ));
});

Sincronización de contenido editorial

Si varios editores trabajan en el mismo post, puedes usar WebSockets para bloquear ediciones concurrentes:

socket.on('editing-post', (postId) => {
    // Marcar post como en edición
    io.emit('post-locked', { postId, user: socket.userName });
});

Solución de problemas comunes

Error 101 (Switching Protocols) no se completa

Verifica que Nginx esté configurado para pasar el header Upgrade:

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

Mensajes duplicados

Esto suele ocurrir cuando el cliente se reconecta. Implementa un ID único por mensaje en el servidor:

const messageId = `${socket.userId}-${Date.now()}-${Math.random()}`;

Latencia alta

Usa WebSocket over TCP en lugar de HTTP long-polling. Socket.IO lo maneja automáticamente si configuras bien el transporte:

const socket = io('...', {
    transports: ['websocket'] // Forzar WebSocket puro
});

[TIP] Para pruebas en local, usa localhost en lugar de 127.0.0.1 para evitar problemas con CORS.


Conclusión

Implementar WebSockets WordPress con React y Node.js no solo es posible, sino que es una solución robusta y escalable para añadir funcionalidades de tiempo real WordPress a tu sitio. Hemos visto cómo:

  • WordPress actúa como backend de datos y autenticación.
  • Node.js + Socket.IO manejan la comunicación persistente.
  • React consume los eventos en tiempo real para construir interfaces como chat en vivo.

Esta arquitectura te permite mantener la seguridad y el ecosistema de WordPress mientras aprovechas la eficiencia de Node.js para conexiones simultáneas. El siguiente paso es adaptar este patrón a tus necesidades específicas: notificaciones push, dashboards en vivo o colaboración en tiempo real.


Recursos adicionales

¿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