miércoles, 8 de octubre de 2025

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

No hay comentarios.:

Publicar un comentario

Shopping Cart Analysis

In e-commerce, understanding the user journey isn’t just about what they bought, but how they arrived at that decision. This cha...