Interested how Laravel works under the hood? → Check my Laravel Core Adventures Course

Build a newsletter chatbot in PHP - Part 3

#chatbots #laravel

In part one and two we created a Facebook Messenger chatbot that let your users subscribe to your newsletter. We stored that information in the database and sent out our first newsletter. In the last third part, we integrate this bot to a website and write our first tests.

Screenshot showing the chatbot integrated to a website

If you haven't read the first articles of this series, check part 1 and part 2 first.

Website integration

You probably have already seen that my bot is integrated into my book's landing page. This way, people can subscribe to my Messenger newsletter, without the need to visit Facebook. Everything happens on my site. This is possible due to the new Facebook Customer Chat Plugin.

Note: Be aware that this plugin is still in a beta test, and not all Messenger features are supported yet.

To integrate this plugin, you need to follow these three steps:

1. Include the Facebook JavaScript SDK

The plugin depends on this script, so you will need to include it into your site. Check the Facebook JavaScript SDK Quickstart for further instructions on that.

2. Whitelist your website's domain

For security reasons, we need to tell Facebook about our domain. It must be served over HTTPS, and IP addresses or localhost are not allowed. There are two ways to whitelist a domain for Facebook. First, you can add it from within your Facebook Page settings. Got to the Messenger Platform menu and then look for the "Whitelisted Domains" section.

Second, and my preferred way to accomplish the same thing, is with BotMan. Inside your config/BotMan/Facebook.php file you can list domains which should be whitelisted. Just add your domain there and use as BotMan command to approve it.

php artisan botman:facebookWhitelistDomains

3. Include the plugin

Finally, include the plugin's markup to your website's HTML. I have put it into my footer, but it doesn't matter. It will always be shown at the bottom right corner.

<div class="fb-customerchat"
 page_id="<PAGE_ID>"
 ref="<OPTIONAL_WEBHOOK_PARAM>"
 theme_color="<HEX_COLOR_CODE>"
 logged_in_greeting="<GREETING_MESSAGE_FOR_LOGGED_IN_USERS>"
 logged_out_greeting="<GREETING_MESSAGE_FOR_LOGGED_OUT_USERS>">
</div>

As you can see, we can define some options here. First, provide your Facebook Page ID. You will find it inside the About section of your page.

Screenshot of the about section of a Facebbok page which holds the ID

We don't need the ref value for now. It will be sent to your BotMan application besides the GET_STARTED value. As a result, we can detect if the conversation was started from the plugin or not. We could use that to handle the conversation differently, but it doesn't make sense for us. So leave it empty.

Through the theme_color you can decide the main highlight color of the chat. I am using the one from my landing page.

And last we can add two greetings here. One is for users who are already logged into Facebook in the current browser. And the other one is for those who are not. I am using the same text here, but this up to you again.

Screenshot showing the chat plugins greetings text and color

The plugin should now be visible on your page. Play around with the settings to see the different customization possibilities.

BotMan Tests

As good PHP developers, we always think about good ways to test our application. The same goes for chatbots. But we haven't written any test yet. Especially when building chatbots is still new to you, I think it is better to concentrate on the implementation first. But I don't want to leave you without creating any tests. This is why we will add some basic tests now.

Testing chatbots are quite different from other web applications. With chats, we have lots of conversations and text to test. When the user says this, we assert that reply and so on. Let's start with the fallback test.

Fallback Test

Under tests/BotMan you will find a basic BotMan example test. Here you can see how we test a chatbot. First, we define the message the bot receives and then we set what we expect as the reply.

public function testBasicTest()
{
    $this->bot
        ->receives('Hi')
        ->assertReply('Hello!');
}

Copy the example test file and name the file and class FallbackTest. Remove the given code and replace it with this:

<?php

namespace Tests\BotMan;

use Tests\TestCase;
use BotMan\Drivers\Facebook\Extensions\ElementButton;
use BotMan\Drivers\Facebook\Extensions\ButtonTemplate;

class FallbackTest extends TestCase
{
    /**
     * @return void
     * @test
     */
    public function it_triggers_the_fallback_message()
    {
        $this->bot->receives('What is your name?')
            ->assertReply('Hey!')
            ->assertReply('I see those words of yours, but I have no idea what they mean. πŸ€”')
            ->assertReply('Christoph said I need to focus on telling you about his book development for now. Maybe later he will train me to understand your messages as well. I hope so ☺️');

        $template = ButtonTemplate::create('Here is how I can help you:')->addButtons([
            ElementButton::create('πŸ’Œ Edit subscription')->type('postback')->payload('subscribe'),
            ElementButton::create('πŸ‘‰ Christoph\'s Blog')->url('https://christoph-rumpel.com/')
        ]);

        $this->bot->assertTemplate($template, true);
    }
}

The bot doesn't know what What is your name? means. We haven't implemented it yet, so the fallback message is triggered. Since we return multiple messages to the fallback method, we can also check for multiple ones in our test. This is why we can use multiple assertReply methods. This is great for basic text messages. But for template messages, we need to check the template with assertTemplate. Now run the test with:

phpunit tests/BotMan/FallbackTest.php
Screenshot showing the result of the Fallback test

Everything should be green.

Subscription Conversation Test

Now we move on the subscription process. Create another test file and name it SubscribeConversationTest.php. We will create three tests here. First one is for the welcome message.

/**
 * @test
 */
public function it_welcomes_user_at_start()
{
    $this->bot->receives('GET_STARTED')
        ->assertReply('Hey and welcome! πŸ‘‹')
        ->assertReply('I help Christoph to spread some news about his book development. πŸ“˜');
}

The bot receives the get_started button payload GET_STARTED and we assert two replies. Essentially, the bot sends more than these two replies. But for this test, it's just fine. I want to keep this test as simple as possible. Run it with:

phpunit tests/BotMan/SubscribeConversationTest.php

Besides, we can trigger the other messages with the subscribe keyword as well. First, we take care of the subscribe process with an affirmative answer.

/**
 * @test
 **/
public function it_subscribes_a_user()
{
    $this->bot->receives('subscribe')
		->assertReply('I help Christoph to spread some news about his book development. πŸ“˜')
		->assertReply('If you like, I can keep you updated about it here on Facebook Messenger. (1-2 times a month)')
		->assertReply("In order to work I will store your name and Facebook ID. Please make sure to read the short and easy to read privacy policy for more information(1-2min): \nhttps://christoph-rumpel.com/policy-newsletterchatbot")
		->assertQuestion('Are you in?')
		->receives('yes')
		->assertReply('Woohoo, great to have you on board! πŸŽ‰')
		->assertReply('I will message you when there is something new to tell ✌️')
		->assertReply("Christoph also likes to blog a lot. Make sure to check out his site for more chatbot stuff: \n ✨ https://christoph-rumpel.com/ ✨ ")
		->assertReply('See you! πŸ‘‹');
}

Here we listen to the subscribe message, then assert some messages as well as a question. Additionally, we chain another incoming user message and assert the rest of the replies. yes is the value of our Yes please button. We can just use it as a trigger for the other messages. To test the negative reply, let's create another test method.

/**
 * @test
 **/
public function it_unsubscribes_a_user()
{
    $this->bot->receives('subscribe')
		->assertReply('I help Christoph to spread some news about his book development. πŸ“˜')
		->assertReply("If you like, I can keep you updated about it here on Facebook Messenger. (1-2 times a month)")
		->assertReply("In order to work I will store your name and Facebook ID. Please make sure to read the short and easy to read privacy policy for more information(1-2min): \nhttps://christoph-rumpel.com/policy-newsletterchatbot")
		->assertQuestion('Are you in?')
		->receives('no')
		->assertReply('Ok no problem. If you change your mind, just type "subscribe" or use the menu.')
		->assertReply("Christoph also likes to blog a lot. Make sure to check out his site for more chatbot stuff: \n ✨ https://christoph-rumpel.com/ ✨ ")
		->assertReply('See you! πŸ‘‹');
}

It's the same, just with the users' negative response and our replies to this case. Now, rerun the tests, and everything should be green as well.

Screenshot showing the result of the subscription conversation test

Here is the whole test file now.

<?php

namespace Tests\BotMan;

use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class SubscribeConversationTest extends TestCase
{
    use DatabaseTransactions;

    /**
     * @test
     */
    public function it_welcomes_user_at_start()
    {
        $this->bot->receives('GET_STARTED_NOW')
            ->assertReply('Hey and welcome! πŸ‘‹')
            ->assertReply('I help Christoph to spread some news about his book development. πŸ“˜');
    }

    /**
     * @test
     **/
    public function it_subscribes_a_user()
    {
        $this->bot->receives('subscribe')
            ->assertReply('I help Christoph to spread some news about his book development. πŸ“˜')
            ->assertReply('If you like, I can keep you updated about it here on Facebook Messenger. (1-2 times a month)')
            ->assertReply("In order to work I will store your name and Facebook ID. Please make sure to read the short and easy to read privacy policy for more information(1-2min): \nhttps://christoph-rumpel.com/policy-newsletterchatbot")
            ->assertQuestion('Are you in?')
            ->receives('yes')
            ->assertReply('Woohoo, great to have you on board! πŸŽ‰')
            ->assertReply('I will message you when there is something new to tell ✌️')
            ->assertReply("Christoph also likes to blog a lot. Make sure to check out his site for more chatbot stuff: \n ✨ https://christoph-rumpel.com/ ✨ ")
            ->assertReply('See you! πŸ‘‹');
    }

    /**
     * @test
     **/
    public function it_unsubscribes_a_user()
    {
        $this->bot->receives('subscribe')
            ->assertReply('I help Christoph to spread some news about his book development. πŸ“˜')
            ->assertReply("If you like, I can keep you updated about it here on Facebook Messenger. (1-2 times a month)")
            ->assertReply("In order to work I will store your name and Facebook ID. Please make sure to read the short and easy to read privacy policy for more information(1-2min): \nhttps://christoph-rumpel.com/policy-newsletterchatbot")
            ->assertQuestion('Are you in?')
            ->receives('no')
            ->assertReply('Ok no problem. If you change your mind, just type "subscribe" or use the menu.')
            ->assertReply("Christoph also likes to blog a lot. Make sure to check out his site for more chatbot stuff: \n ✨ https://christoph-rumpel.com/ ✨ ")
            ->assertReply('See you! πŸ‘‹');
    }
}


As you have probably noticed, we had to duplicate the beginning of the subscribe conversation. This is something that bothers me a lot, and I am already figuring out with Marcel how to create a better solution. Still, these few tests are beneficial and useful examples.

Conclusion

We are done! Wow, that was quite a journey. I'm glad I could show you a new and real chatbot use case of mine. We covered everything from planning the bot to implementing and testing it. I hope you enjoyed this tutorial and it helps you with your next messenger newsletter. Visit me on Twitter and check out my book for more chatbot content.

Do you enjoy my posts?

Sign up for my newsletter to receive updates on my latest content.

You will receive monthly updates on my latest articles and products. I do care about the protection of your data. Read my Privacy Policy.