Ir al contenido principal

Interface WP ⇄ Laravel

Prólogo

Esta arquitectura fue originalmente concebida, propuesta e implementada por el autor en el Sistema de Votaciones Online del Poder Judicial de Chile (PJUD), específicamente para el Área de Bienestar, con el objetivo de garantizar integridad, trazabilidad y seguridad en procesos electorales internos.

En dicho entorno —una intranet controlada, sin exposición a internet y con servidores dedicados— se descartó la comunicación vía APIs REST por considerarla innecesariamente compleja, con mayor superficie de ataque y dependiente de mecanismos de autenticación frágiles. En su lugar, se diseñó un canal de comunicación directo entre WordPress (frontend y autenticación) y Laravel (lógica de negocio), utilizando exclusivamente comandos CLI y el protocolo SSH como transporte cifrado.

El éxito operativo, la estabilidad y la facilidad de auditoría de dicha implementación validaron el enfoque. Hoy, este patrón se propone como solución genérica para cualquier integración entre WordPress y Laravel en entornos autohospedados donde el control total del sistema, la simplicidad y la seguridad son prioritarios.

Objetivo

Permitir la comunicación segura, eficiente y extensible entre WordPress (frontend, autenticación, UX) y Laravel (lógica de negocio, modelos, procesamiento) en entornos autohospedados, sin exponer APIs HTTP, usando exclusivamente comandos CLI (wp-cli + artisan) y canales IPC (stdin/stdout o SSH).

Alcance

  • Soporta cualquier operación delegable: sincronización de carritos, creación de cursos, votaciones, notificaciones, etc.
  • Funciona en:
    • Mismo servidor (IPC local)
    • Servidores distintos en red privada (SSH)
  • No requiere:
    • APIs REST
    • Bases de datos compartidas
    • Plugins de autenticación cruzada

Arquitectura

+----------------+ CLI Call +------------------+
|                | --------------------->     |
|  WordPress     | (wp-cli → artisan)         | Laravel |
| (Frontend)     | <---------------------     | (Business Logic) |
|                | JSON via stdout            |
+----------------+         +------------------+

Flujo de ejecución

  1. WordPress dispara un hook (ej. woocommerce_cart_updated).
  2. Plugin de WordPress ejecuta un comando wp-cli personalizado.
  3. wp-cli llama a artisan bridge:dispatch (local o vía SSH).
  4. Laravel ejecuta la acción registrada, procesa y devuelve JSON por stdout.
  5. WordPress recibe la respuesta y actúa (mostrar mensaje, log, etc.).

Componentes

1. WordPress: Plugin wp-laravel-bridge

Comando CLI
wp laravel:call --user= --data=

Función helper (PHP)
function wp_laravel_call(string $action, array $data, int $user_id = null): array;

Internamente

  • Usa proc_open() para ejecutar artisan.
  • Escapa parámetros con escapeshellarg().
  • Captura stdout y parsea JSON.
  • Maneja errores (timeout, comandos fallidos).

2. Laravel: Comando bridge:dispatch

Uso
php artisan bridge:dispatch --user= --payload=

Registro de acciones (routes/bridge.php)
return [
'cart.sync' => \\App\\Actions\\SyncCart::class,
'vote.register' => \\App\\Actions\\RegisterVote::class,
'course.enroll' => \\App\\Actions\\EnrollInCourse::class,
// ...
];

Contrato de acción
interface BridgeAction { public function handle(array $data): array; }

Salida

  • Éxito: echo json_encode($result);
  • Error: fwrite(STDERR, json_encode($error)); exit(1);

Seguridad

MedidaImplementación
AutenticaciónEl user_id lo provee WordPress (sesión validada). Laravel confía en él.
ValidaciónCada acción valida entrada con Laravel Validator o clases propias.
EjecuciónSolo comandos CLI permitidos. Nada de eval() ni ejecución dinámica.
RedSi es remoto, solo vía SSH con clave pública y ForceCommand.
PermisosUsuario del servidor (www-data) con acceso mínimo a rutas de Laravel/WordPress.

Ejemplo: Sincronización de carrito (WooCommerce)

WordPress (plugin)
add_action('woocommerce_cart_updated', function() {
if (!is_user_logged_in()) return;
$items = array_column(WC()->cart->get_cart(), 'product_id');
$result = wp_laravel_call('cart.sync', [
'items' => $items,
'total' => WC()->cart->get_total('numeric')
]);
if ($result['success'] ?? false) {
WC()->session->set('cart_tracked', true);
}
});

Laravel (SyncCart.php)
class SyncCart implements BridgeAction {
public function handle(array $data): array {
CartTracker::updateOrCreate(
['user_id' => $data['user_id']],
['items' => $data['items'], 'total' => $data['total']]
);
return ['success' => true, 'tracked_at' => now()];
}
}

Comunicación bidireccional (opcional)

Para notificaciones Laravel → WordPress:
// En Laravel shell_exec("wp --path=/var/www/wordpress user meta set {$userId} last_action " . time());
→ Requiere que Laravel pueda ejecutar wp-cli.

Requisitos del sistema

  • WordPress: con wp-cli instalado y accesible.
  • Laravel: >= 8.x, con comandos Artisan.
  • PHP: proc_open() habilitado.
  • Servidor: acceso SSH entre nodos (si es distribuido).
  • Permisos: usuario común con acceso a ambas rutas.

Escalabilidad

  • Para alta carga: reemplazar proc_open() por cola asíncrona (Redis, DB).
  • Para auditoría: loggear cada llamada en Laravel (bridge.log).
  • Para idempotencia: incluir request_id en el payload.

Anti-patrones a evitar

  • No usar shell_exec() sin sanitización.
  • No pasar credenciales en la línea de comandos
  • No pasar credenciales en la línea de comandos.
  • No asumir que Laravel y WordPress comparten base de datos.
  • No exponer el comando bridge:dispatch a HTTP.

Estructura de archivos sugerida

wordpress/
├── wp-content/
│   └── plugins/
│       └── wp-laravel-bridge/
│           ├── wp-laravel-bridge.php
│           ├── includes/
│           │   └── BridgeClient.php
│           └── commands/
│               └── CallLaravel.php

laravel/
├── app/
│   └── Actions/
│       ├── SyncCart.php
│       ├── RegisterVote.php
│       └── EnrollInCourse.php
├── routes/
│   └── bridge.php
├── app/
│   └── Console/
│       └── Commands/
│           └── BridgeDispatch.php

Licencia

Este patrón puede ser implementado libremente en cualquier sistema autohospedado. No se recomienda su uso en entornos compartidos, multisite o con exposición pública sin adaptaciones adicionales.

Autor

Benjamin Sánchez
Desarrollador y Analista de Sistemas
github.com/benjasanchez

Comentarios

Entradas más populares de este blog

Manual de Performance y Tuning Avanzado en WordPress

Introducción: Más allá del caché superficial En el ecosistema WordPress, la mayoría de los artículos sobre rendimiento se limitan a recomendar plugins de caché o CDN. Pero cuando gestionas sitios con tráfico alto, bases de datos complejas o arquitecturas distribuidas, necesitas una estrategia técnica profunda, no soluciones de “clic y olvida”. Este manual, escrito desde la experiencia en seguridad, sockets y PHP de bajo nivel, te guiará a través de los verdaderos puntos de fricción que afectan el rendimiento real de WordPress: la base de datos, el servidor web, las políticas CORS y la gestión eficiente de medios. Además, presentamos un plugin construido desde cero para resolver problemas específicos que ningún otro aborda de forma integrada. --- ## 1. Optimización de la Base de Datos: El Corazón del Rendimiento WordPress depende de MySQL (o MariaDB) como motor de persistencia. Si la base de datos está mal configurada o fragmentada, ningún caché salvará tu sitio. ### 1.1. Índices inteli...

WPDB Table Renderer

WPDB Table Renderer septiembre 28, 2025 La tabla que WordPress olvidó Por HOOKED / Investigación Técnica En el ecosistema WordPress, donde los plugins visuales dominan y los dashboards se multiplican, hay una necesidad que rara vez se aborda con rigor: mostrar datos de forma profesional . No hablamos de gráficos decorativos ni de interfaces sobrecargadas. Hablamos de algo más básico, más estructural: tablas que funcionen . Ahí entra en escena WPDB Table Renderer , una clase PHP que transforma cualquier resultado de $wpdb en una tabla interactiva, ordenable, filtrable y exportable. Sin dependencias externas. Sin frameworks. Sin adornos. Solo código limpio, funcional y 100 % nativo. El problema: datos sin forma WordPress ofrece acceso directo a su base de datos mediante $wpdb , pero lo que devuelve es crudo: arrays sin formato, sin interacción, sin contexto visual. Los desarrolladores deben construir desde cero interfaces para mostrar esos datos… o recurrir a soluciones...

Shopping Cart Analysis

En el comercio electrónico, comprender el recorrido del usuario no se limita a saber qué compró, sino cómo llegó a esa decisión. Este capítulo explora una estrategia de trazabilidad diseñada específicamente para capturar, registrar y relacionar cada acción que un visitante realiza en una tienda WooCommerce, ya sea que complete una compra o abandone su carrito. La solución se basa en un modelo dual de identificación que permite distinguir claramente entre: el ciclo de vida de un carrito y la identidad persistente del visitante ...incluso cuando este permanece anónimo . Dos dimensiones de la identidad del usuario La clave de esta arquitectura radica en reconocer que existen dos entidades distintas que deben rastrearse de forma independiente, pero relacionada: El carrito de compra como unidad de intento : Cada vez que un usuario inicia un proceso de compra —ya sea añadiendo un producto por primera vez o regresando tras ...