red line

Wordpress and WebSockets: A Primer

So you had the bright idea to implement WebSockets on a WordPress site, running on Nginx... running on Ubuntu...
idea to implement WebSockets on a WordPress site

Fantastic, we’re here to help!

Implementing WebSockets on a typical Node stack is easy. WebSockets with PHP… less easy. The way PHP executes is from the top down (or bottom up if you are in Australia), and once it reaches the bottom it stops. Unlike Node, it’s not a constantly running process. This requires us to create a process that can stay alive and listen to the front end.

If you’re developing a website with WordPress and want to push real time updates to the client, you might want to use WebSockets with PHP. We’re going to take a look at one way you could implement WebSockets on a WordPress / Nginx / Ubuntu stack.

High Level Overview

Here’s what were going to do:

  • Create a server script responsible for starting the backend socket server – using the ZeroMQ messaging library and the Thruway router – synergizing together.
  • Expose an endpoint from the server script which Nginx then proxies to a url that is accessible to the web client
  • A web client will open a Websocket connection to the proxied url
  • PHP code is triggered, and calls to ZeroMQ, which tells the socket library to send the message

Assumptions (lots of ’em)

For this quick tutorial, we’ll assume that:

  1. You have a WordPress site running on Nginx and Ubuntu
  2. You can access the Ubuntu server or environment that it runs on
  3. Your PHP version is >= 7.X.X,
  4. You know how to use Composer
  5. You can navigate on a server, configure server processes, understand client and server communication patterns, and provide expert advice on taxes.

Libraries we’ll be using

We are going to use some trusted and well known libraries to help us get this done quickly.

  • Thruway – PHP Client and Router Library for Autobahn and WAMP (Web Application Messaging Protocol) for Real-Time Application Messaging
  • ZMQ – An open-source universal messaging library
  • Autobahn – WAMP in JavaScript for Browsers and NodeJS (client)

Installing Dependencies

image of bash commands

Installing the ZeroMQ PHP extension

ZeroMQ is going to allow our socket connections to stay alive, whether they like it or not. To install the ZeroMQ PHP extension, so you can use it with PHP, use the following bash commands:

Note: Replace phpX.Y with your actual version

				
					sudo apt-get -y install libzmq3-dev
sudo bash -c "echo extension=zmq.so > /etc/phpX.Y-sp/conf.d/zmq.ini"
sudo service phpX.Y-fpm-sp restart 
				
			

Installing Thruway

Thruway is going to give us the WAMP 2.0 protocol which the Autobahn library also uses. To install Thruway with composer use the following:

				
					php composer.phar require voryx/thruway 
				
			

Installing Autobahn

Autobahn is the library we will be using to establish the client side connections to our Websocket enabled endpoint. You can install Autobahn with NPM . To do this use the following bash command:

				
					npm install autobahn 
				
			

Proxying with Nginx

We have to expose a way for our clients to easily open a Websocket connection with our server. So to do that we are going to use Nginx to proxy wss:example.com/socket to our socket router on the back end.

Edit your Nginx config file (most likely in /etc/nginx/sites-enabled/yours.conf) and add the following location block:

				
					location /socket/ {
    proxy_pass http://localhost:8888;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
} 
				
			

Reloading is safer than restarting, since configuration files are checked for syntax errors before changes are made. You will want to reload Nginx to safely apply the change by using the following bash command:

				
					sudo nginx -s reload 

				
			

The socket server script (socket-server.php)

We need to start up a socket server with a few configuration options before we can send messages.
socket-server.php script

Start by creating the file socket-server.php – I chose to create this script in the root directory of my WordPress installation because that’s just the way I am. Add the following to the socket-server.php file:

				
					<?php
 // it just needs to match what is used on the client side as well
    $pusher = new \Thruway\Peer\Client("SuperCoolRealmName", $loop); 

    $pusher->on('open', function ($session) use ($loop) {
        // Bind to ZMQ so we can use it to send messages through socket server
        $context = new React\ZMQ\Context($loop);
        $pull = $context->getSocket(ZMQ::SOCKET_PULL);
        $pull->bind('tcp://127.0.0.1:5555');
        $pull->on('message', function ($entry) use ($session) {
            $entryData = json_decode($entry, true);
            // $entryData['category'] will be whatever key you use from your php code
            if (isset($entryData['category'])) {
                $session->publish($entryData['category'], [$entryData]);
            }
        });
    });

    $router = new Thruway\Peer\Router($loop);
    $router->addInternalClient($pusher);
    // Make sure you use the same value here as you did in the Nginx config (port 8888)
    $router->addTransportProvider(new Thruway\Transport\RatchetTransportProvider("0.0.0.0", 8888));
    // Start'er up
    $router->start();
				
			

To run the script, navigate to it and use the following bash command:

				
					php socket-server.php 

				
			

We now have a socket server instance running on our web server.  Before publishing a message from the WordPress back end, we need to open a client connection. Let’s jump over to the front-end.

Establishing the client side connection

Ok! Now we have a socket server running, we’re proxying it with Nginx to a url, and now we can start listening for messages. Look at us go!

In your front-end javascript code you will at least need to:

  • Open a socket connection to a url
  • Perform an action upon receiving the socket message

To do this add the following lines to your front-end JavaScript:

				
					setupSocketListeners() {
    // Create a new autobahn connection
    let connection = new autobahn.Connection({
        url:”wss://example.com/socket/”, // <- wss:// is https only while ws:// can do http, all depends on your nginx config
        realm: "SuperCoolRealmName" // <- Matches realm name in server code }); connection.onopen = session => {
        // Subscribe to an incoming message event and bind to onSocketMessage
        session.subscribe("message", this.onSocketMessage);
    };
    // Open the connection
    connection.open();
}

onSocketMessage(args) {
    let msg = args[0];

    if (msg.category && msg.category == "message") {
        // console.log(msg);
        // do something with the received message!
    }
}
// Don't forget to call your code, dude!
setupSocketListeners(); 
				
			

If you updated your Nginx config with the proxy location and reloaded Nginx you should have no issues establishing this connection.

Now that the client can receive messages, it’s time to send it one from your WordPress or general PHP code. Locate the file or class you want to use to send a message, and cast the following spell:

				
					<?php
// Use ZMQ to send messages through your socket server
 $context = new ZMQContext();
 $socket = $context->getSocket(ZMQ::SOCKET_PUSH);
 // Connect to localhost:5555 which is the port you bound your instance to
 $socket->connect("tcp://localhost:5555");
 $socket->send(json_encode(['message'=> 'Magical socket message!'])); 
				
			

If that code runs –  it should publish a message to your client instance listening at .com/socket/

Final Thoughts

This tutorial is a great starting place for implementing some form of WebSockets on a WordPress site or really any PHP site. You may need to dive into the library documentation to do more than just broadcast messages to your front-end. Running the socket-server.php script can be a pain, and I recommend you turn it into a system service on your server, so that restarting and running the script is simple and reliable. While you’re doing that you may also want to check out our Security Tips We LOVE to Keep Your WordPress Site Safe.

With that being said, and like my friend Peter always says, “There’s more than one way to skin a cat, Cooper.”

Related resources