Messenger Bot For WordPress

In this tutorial we are going to build a facebook's messenger bot for our WordPress site. Our bot will send the recent posts whenever a user sends "posts" message.

Live demo of a bot which is built using the same technique can be found @ http://m.me/1580431432271151

First let's find out how the messenger api works. We will figure out the WordPress part later.

So for setting up our bot on facebook we need following things.

  1. Facebook Page
  2. Facebook APP
  3. Our Bot URL where facebook can post/get requests as they come.

So I just created a page and a facebook app, now let's give access to our app for handling messages of our page.

Open app dashboard and head on to messenger tab then click on the "Get Started" button.

alt

Now, we need access token for subscribing our app to the page and for our bot to reply to the user's messages to our page. Select your newly created page, this will open a permission window, select ok and it will generate the token. Save it! we are going to use it.

Subscribe the App to the Page using the Page Access Token generated in the previous step. The following call will subscribe our app to get updates for this specific Page.

curl -ik -X POST "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=<token>"  

We just gave permission to our app for managing messages for our page. Whenever a new message comes FB will post the data on the webhook(Just be with me, and read on).

Webhook is a simple URL which accepts post and get requests. We need to create one, so that facebook can send message's data and our bot can take it further. So let's create a plugin for WordPress.

Create a folder [bot-for-wp] in your plugins directory (You know the drill)

Let's start coding our plugin by creating a file [plugin.php] in bot-for-wp folder.

<?php  
/*
Plugin Name: Bot For WP  
Description: Messenger bot for WordPress  
Plugin URI: http://snypd.com/  
Author: Sunny Luthra  
Author URI: http://#  
Version: 1.0  
License: GPL2  
 */
if (!defined('ABSPATH')) {  
    exit;
}

class Bot_For_WP {  
    function __construct() {
        // Namespace of our plugin
        $this->namespace = "bot-for-wp";
        // Add route for facebook to post/get requests
        add_action('rest_api_init', array($this, 'register_routes'));
    }
    function register_routes() {
        register_rest_route($this->namespace, '/bot', array(
            array(
                'methods' => WP_REST_Server::READABLE,
                'callback' => array($this, 'get'),
            ),
        ));
    }
    function get($request) {
        return 'hello';
    }
}
new Bot_For_WP;  

The above code will create a URL http://localhost/wp-json/bot-for-wp/bot and on get request it will call get function. But we cannot add this url as a webhook for our app because it is not accessible via internet. So let's use nGrok, it will expose our local server to the internet. If you are already on a server which is accessible via internet then you don't need nGrok.

Now we can use the nGrok forwarding URL as webhook for our app. So, head on to your app dashboard, then click on Messenger tab and then click on Setup Webhooks and enter the nGrok URL which is https://19ccab5a.ngrok.io/wp-json/bot-for-wp/bot and a random string as verified token which is needed to verify the request is from facebook.

As you can see when I click on verify and save, I got an error because for verification, facebook calls the URL with three query parameters which are hub_challenge, hub_mode and hub_verify_token. To check the facebook request, head onto nGrok's web interface http://127.0.0.1:4040/inspect/http#

The job of our plugin is on get request check the verify_token is the same which we entered and echo the hub_challenge if true. So, let's do this.

We are going to add a permission_callback in our route and in that callback we are going to check for the token. Also, we are going update our get function too so that it can echo the hub_challenge.

<?php  
/*
Plugin Name: Bot For WP  
Description: Messenger bot for WordPress  
Plugin URI: http://snypd.com/  
Author: Sunny Luthra  
Author URI: http://#  
Version: 1.0  
License: GPL2  
 */
if (!defined('ABSPATH')) {  
    exit;
}

class Bot_For_WP {  
    function __construct() {
        // Verify Token
        $this->verify_token = 'SOME_RANDOM_STRING';
        // FB URL for posting
        $this->graph_api_url = 'https://graph.facebook.com/v2.6/me/messages?access_token=';
        // Page access token
        $this->access_token = 'SOME_TOKEN';

        // Add route for facebook to post/get requests
        add_action('rest_api_init', array($this, 'register_routes'));
    }
    function register_routes() {
        register_rest_route($this->namespace, '/bot', array(
            array(
                'methods' => WP_REST_Server::READABLE,
                'callback' => array($this, 'get'),
                'permission_callback' => array($this, 'verify_request'),
            ),
        ));
    }
    function get($request) {
        $params = $request->get_query_params();
        echo $params['hub_challenge'];
        die();
    }
    function verify_request($request) {
        $params = $request->get_query_params();
        if ($params && isset($params['hub_challenge']) && $params['hub_verify_token'] == $this->verify_token) {
            return true;
        }
        return false;
    }
}
new Bot_For_WP;  

Let's try to verify the webhook url again.

Verify Webhook URL Image

Yayyy!!

Let's send a message to our page and check the nGrok web interface for the request which facebook sends.

Here is what FB posted on our webhook URL.

{
    "object": "page",
    "entry": [
        {
            "id": "1726067357681160",
            "time": 1463572746913,
            "messaging": [
                {
                    "sender": {
                        "id": "1120722081323261"
                    },
                    "recipient": {
                        "id": "1726067357681160"
                    },
                    "timestamp": 1463572732259,
                    "message": {
                        "mid": "mid.1463572732248:54cdb65b96087ab911",
                        "seq": 8,
                        "text": "Hi"
                    }
                }
            ]
        }
    ]
}

Let's get into real business now. We are accepting only the GET request on our webhook url, so let's add POST verb too. Whenever FB posts data we will reply with hi to the sender.

I have updated the register_routes function and added two more functions post and send_message

Function - register_routes

function register_routes() {  
        register_rest_route($this->namespace, '/bot', array(
            array(
                'methods' => WP_REST_Server::READABLE,
                'callback' => array($this, 'get'),
                'permission_callback' => array($this, 'verify_request'),
            ),
            array(
                'methods' => WP_REST_Server::CREATABLE,
                'callback' => array($this, 'post'),
            ),
        ));
    }

Function - post

function post($request) {  
        $params = $request->get_params();
        if ($params && $params['entry']) {
            foreach ((array) $params['entry'] as $entry) {
                if ($entry && $entry['messaging']) {
                    foreach ((array) $entry['messaging'] as $message) {
                        $this->send_message($message);
                    }
                }
            }
        }
        die();
    }

Function - send_message

function send_message($message) {  
        // Facebook alos sends delivevery messages
        // so its better to check for text.
        if (!isset($message['message']['text'])) {
            return;
        }
        $sender_id = $message['sender']['id'];
        // Graph URL With Token
        $graph = $this->graph_api_url . $this->access_token;
        // Text Template
        $template = array('text' => 'hi');
        $data = array(
            'body' => array(
                'recipient' => array('id' => $sender_id),
                'message' => $template,
            ),
        );
        $response = wp_remote_post($graph, $data);
    }

This is what we have achieved so far.

Let's do one thing, whenever user sends 'posts' we will send the latest posts and will send hi if user sends hi.

Before that I want you to go through the Messenger template guidelines quickly
https://developers.facebook.com/docs/messenger-platform/send-api-reference#guidelines

We are going to use Structured Message - Generic Template for showing posts, so now I am going to update the send_message function and will add two helper functions get\_posts\_elements and 'truncate'

Function send_message

function send_message($message) {  
        // Facebook alos sends delivevery messages
        // so its better to check for text.
        if (!isset($message['message']['text'])) {
            return;
        }
        $sender_id = $message['sender']['id'];
        $text = strtolower($message['message']['text']);
        // Graph URL With Token
        $graph = $this->graph_api_url . $this->access_token;

        if ($text == 'posts') {
            $template = array(
                'attachment' => array(
                    'type' => 'template',
                    'payload' => array(
                        'template_type' => 'generic',
                        'elements' => $this->get_posts_elements(),
                    ),
                ),
            );
        } else {
            // Text Template
            $template = array('text' => 'hi');
        }
        $data = array(
            'body' => array(
                'recipient' => array('id' => $sender_id),
                'message' => $template,
            ),
        );
        $response = wp_remote_post($graph, $data);

    }

Function get_posts_elements

function get_posts_elements() {  
        $args = array(
            'posts_per_page' => 10,
            'post_type' => 'post',
        );
        $posts = get_posts($args);
        $elements = [];
        if ($posts) {
            foreach ($posts as $post) {
                $data = array(
                    'title' => $this->truncate($post->post_title, 45),
                    'image_url' => 'http://thecatapi.com/api/images/get?format=src&type=png',
                    'subtitle' => $this->truncate($post->post_content, 80),
                    'buttons' => array(
                        array(
                            'type' => 'web_url',
                            'url' => get_permalink($post),
                            'title' => 'View Story',
                        ),
                    ),
                );
                $elements[] = $data;
            }
        }
        return $elements;
    }

Function truncate

function truncate($text, $length) {  
        // This is for truncating title and subtitles
        $length = abs((int) $length);
        $text = trim(preg_replace("/&#?[a-z0-9]{2,8};/i", "", $text));
        if (strlen($text) > $length) {
            $text = preg_replace("/^(.{1,$length})(\s.*|$)/s", '\\1...', $text);
        }
        return ($text);
    }

Let's try this out.

Aha... Looking good.

Now try coding a bot by yourself and do let me know if you hit any roadblocks.

Complete code can be downloaded from here https://github.com/sunnyluthra/bot-for-wp

For live demo of a bot which is built using the same technique can be found @ http://m.me/1580431432271151

comments powered by Disqus