WordPress Development Recipe: Real-time custom event triggers using WebSockets and Shortcode API
Leveraging WebSockets for Real-time WordPress Event Triggers via Shortcode
This recipe details a robust method for implementing real-time event triggers within WordPress, specifically by integrating WebSockets with the Shortcode API. This approach is ideal for dynamic content updates, live notifications, or interactive elements that require immediate feedback without constant page reloads. We’ll focus on a server-side PHP implementation for the WebSocket server and a client-side JavaScript integration for the WordPress frontend.
Prerequisites and Setup
Before diving into the code, ensure you have the following:
- A working WordPress installation.
- PHP 7.4+ with the
pcntlandsocketsextensions enabled for the WebSocket server. - Composer for managing PHP dependencies.
- Basic understanding of WebSockets, PHP, JavaScript, and the WordPress Shortcode API.
WebSocket Server Implementation (PHP)
We’ll use a simple, non-blocking WebSocket server implemented in PHP. For production environments, consider a more mature library like Ratchet or Swoole, but this example illustrates the core concepts.
First, set up a new PHP project for your WebSocket server. Navigate to a directory outside your WordPress root (e.g., /var/www/websocket-server) and initialize Composer:
cd /var/www/websocket-server composer init
Now, install the necessary dependencies. We’ll use the cboden/ratchet library for a more structured WebSocket implementation, which simplifies handling connections and messages.
composer require cboden/ratchet
Create a file named server.php in your WebSocket server directory:
<?php
require dirname(__DIR__) . '/vendor/autoload.php';
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
class WordPressEventComponent implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
echo "Message received: {$msg}\n";
// In a real application, you'd parse $msg to identify event types
// and potentially interact with your WordPress backend.
// For this example, we'll just broadcast back.
$data = json_decode($msg, true);
if ($data && isset($data['event'])) {
$response = json_encode(['status' => 'received', 'event' => $data['event'], 'message' => 'Event acknowledged']);
$from->send($response); // Acknowledge receipt to sender
// Broadcast to all other clients
foreach ($this->clients as $client) {
if ($from !== $client) {
// You might want to filter which clients receive which events
// based on subscriptions or user roles.
$client->send(json_encode(['type' => 'event_trigger', 'event' => $data['event'], 'payload' => $data['payload'] ?? null]));
}
}
} else {
$from->send(json_encode(['status' => 'error', 'message' => 'Invalid message format. Expected JSON with an "event" key.']));
}
}
public function onClose(ConnectionInterface $conn) {
// The connection is closed, remove it, as we're not sending an echo
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
// Method to trigger an event from the server-side (e.g., from a WP hook)
public function triggerEvent($event, $payload = null) {
$message = json_encode(['type' => 'event_trigger', 'event' => $event, 'payload' => $payload]);
echo "Broadcasting event: {$event}\n";
foreach ($this->clients as $client) {
$client->send($message);
}
}
}
// Start the WebSocket server
$server = IoServer::factory(
new HttpServer(
new WsServer(
new WordPressEventComponent()
)
),
8080 // Port to listen on
);
echo "WebSocket server started on port 8080...\n";
$server->run();
To run the server, execute:
php server.php
Keep this terminal window open. For production, you’ll need to run this process as a service (e.g., using systemd or supervisor) and ensure it’s accessible from your WordPress frontend.
WordPress Plugin for Shortcode Integration
Now, let’s create a WordPress plugin to manage the WebSocket connection and expose a shortcode. Create a new directory realtime-events in your wp-content/plugins/ directory. Inside it, create a main plugin file, e.g., realtime-events.php.
<?php
/**
* Plugin Name: Realtime Events
* Description: Integrates WebSockets for real-time event triggers via shortcode.
* Version: 1.0
* Author: Your Name
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
class Realtime_Events_Plugin {
private $websocket_server_url = 'ws://localhost:8080'; // Change if your server is elsewhere
public function __construct() {
add_shortcode( 'realtime_trigger', array( $this, 'render_shortcode' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
// Example: Hook into a WordPress action to trigger an event
// add_action('save_post', array($this, 'trigger_post_save_event'), 10, 3);
}
public function enqueue_scripts() {
wp_enqueue_script(
'realtime-events-js',
plugin_dir_url( __FILE__ ) . 'js/realtime-events.js',
array( 'jquery' ), // Dependency on jQuery
'1.0',
true // Load in footer
);
// Pass WebSocket server URL to the JavaScript
wp_localize_script(
'realtime-events-js',
'realtimeEventsConfig',
array(
'websocket_url' => $this->websocket_server_url,
)
);
}
public function render_shortcode( $atts ) {
// Shortcode attributes can be used to customize event names or payloads
$atts = shortcode_atts( array(
'event' => 'generic_event',
'payload' => '',
), $atts, 'realtime_trigger' );
// We'll use this shortcode primarily to enqueue the JS and establish the connection.
// The actual triggering will be handled by JS or server-side hooks.
// For demonstration, we can output a placeholder or a button.
ob_start();
?>
<div id="realtime-event-listener" data-event="" data-payload="">
Real-time events listener initialized.