Introduction
This article drives through slack API by using a worpdress plugin that receives messages from slack and posts it as an article. This is quite an interesting showcase that explains how it is easy to implement a real world application that interacts with slack. Moreover, we will discover how to develop in a local dockerized wordpress environment and expose it on the internet.
Spoil: See It in Action
Don’t want to way the end? Ok, let's see it in action! You can find the code here.
This plugin is very simple. You will find an app in slack, you can speak to it.
All messages you send to it will be published as wordpress posts, converting slack formatting syntax into HTML.
All this, done using ngrok
and docker
, can work into your PC and interact with slack.
Slack API Overview
When I started studying the slack API to enter the context, I was very impressed by the quality of work done on it. The remarkable aspect is the coverage of all possible development use cases. Anything you can imagine to do it is possible. This is not enough? Well, APIs are designed for developers. I tested many other API systems – I’m speaking about big players, of course – and in this case, I found it so easy to create an app and deploy to user that I was surprised. It was very funny to see the possibility to create an app for your space, then promote as public, hiding sensitive information like clientid
and client secret making it configurable during installation that I told myself, “I have all to start.”
Many Options to Cover All Case
As I mentioned, all development cases are covered by different capabilities. To give an idea about what we can do:
- Add a button to the interface, showing custom form on dialogs (web, desktop, mobile)
- Being notified when something happens using event (something like other call “
webhook
”) - Manipulate data (CRUD) on behalf of the user (regular API, when making http request, things happens)
Great! So let's explore all possibilities:
-
Web API: This is the way we image API. Think about this as the classic set of REST action that can be invoked to get\set informations.
-
WebHook: Incoming Webhooks are a simple way to post messages from apps into Slack. This is managed by a REST call. Creating an Incoming Webhook gives you a unique URL that you can call to do actions like post messages.
-
Commands: Let users trigger an interaction with your app directly from the message box in Slack. When a slash command is invoked, Slack sends an HTTP POST to the Request URL you entered in command configuration. This request contains a standard the payload with user data and context information.
-
UI: It is possible to create an extension that customizes the UI. In the example, when a user hits a button, you can open a dialog. Inside dialogs, you can collect information or show information.
-
Event API: This is similar to WebHook but in the opposite way. When an event on your slack happens, your URL can be triggered and you can manage data. This is the one used for this project and explained later.
How to Combine Slack Extension Capabilities to Win the Game
In our simple application, we need something very basic: just send the message to our wordpress instance. So the API application will be hosted into wordpress itself, a very easy and practical solution. We will discuss about wordpress application later, if you are curious, I would just reveal that it’s no more than a plugin. Of course, due to privacy and security consideration, from API, you cannot read all messages of all users. Just operate on behalf of the user or manage configuration settings, never invade the private life of people. So the good solution for it is to use a BOT. When you add a bot on a conversation, it’s explicit that the bot can hear what you tell.
That’s transparent to everyone. So my solution was to implement a simple bot that:
- Will be added by user to some conversation or channel
- All message of the channel will be read from the bot, that never sleeps (typical of all robots 😉).
- The bot is no more than a http endpoint, so just run the code having the message as input.
Basically, we can divide this work in two phases:
- The funny slack configuration when all shine
- The same standard http API development using PHP
I don’t like too much working on PHP. I think that’s because I always worked with well structured languages, really object oriented, before starting to play with it. Nothing to say against PHP, just a personal feeling and probably who join the platform nowadays will have a better impact due to big improvement done. Anyway, feelings are feelings and I don't like to experiment where I miss something funny or interesting so… I decided to put some pepper on it by deciding to use a local docker environment for dev exposed to the internet. Nothing revolutionary, but enough to convince me that I will enjoy the work.
Part 1: Slack Configuration
Slack configuration is very easy. I don’t want, and it is not the purpose of this article to show a wizard to create a slack from scratch. You can see this great article if you need that. Since we have the app, we must enable the events. This is very simple, just navigate event section and turn it on. The settings page of event is very very simple. We need to set only two parts: the url to invoke and the permission. For this app, we need just the possibility to be notified about messages, so configuration is something very similar to:
Then the interesting part, the url. This could be considered simple, just put the url and stop, but there is more. The interesting part about this is the trust mechanism between slack and you. This is because you have to prove your identity and slack must prove its identity when sending data. Otherwise, we could fall in a bad situation where slack may send data to the wrong (or malicious) app, or some hacker sends artificial payload to your app and plays on behalf of slack.
To avoid such a situation, no fear, slack API implemented a very simple and complete thrust mechanism. A simpler solution is to send all data to one endpoint, this makes communication easier, even it may create a small extra effort on the called endpoint. You can also have multiple endpoints if you want to keep things more fragmented (maybe like one endpoint per info type) with a more complex configuration.
As you type the url into textbox, a challenge call was done to the endpoint. Challenge will send token and a random string
, called challenge. The endpoint will return the challenge to prove to be able to manage slack calls. In my implementation, the endpoint accepts challenge only once, storing token into database. This, as we will see, allows the plugin to check the request and avoid a situation where somebody can connect itself on behalf of slack.
Request doing:
Request doesn't match challenge:
Request verified correctly:
The authentication token is the same you find in app credential:
Part 2: The Wordpress Plugin
Do you remember we wanted to experiment exposed local environment with docker? Well, we started from this and then the real job was the remaining annoying part. Just adding some easy copy and paste from stackoverflow to insert a post on wordpress and that’s all… or better, that was what I thought before starting.
Expose Your Local Ports
First funny thing is about exposing local port on internet. I was sure it was possible using some reverse proxy tools but I never tried before. After a quick search on the internet, I found a great service, called ngrock
, that opened a local port to the web. Free tier has some limitations (es. url change each time you run), but basically can be used without friction with http and https.
Ngrock supports the possibility to save some config file to avoid remember settings each time, just run something “ngrock start projectname
”. The question is that the 99% of the settings I may be interested in are not in the free tier so I use the plain raw format “ngrock http localport
” where of course localport
is binded to the port number exposed from docker.
Dockerize Wordpress Environment
The docker part was also very easy. I already deployed wordpress application on docker or kubernetes so I was already an expert with the image itself. Because I like a written configuration that can be shared into the team (yes, I was the only member of this team, but I’m trained to think as a team, not an individual), I set up a docker compose file. This have just two nodes (mysql+wordpress
). Mysql data folder is mapped to an external folder, good to avoid data was lost if container is dropped and in case you want to start from scratch, just remove the folder and restart all. For wordpress instead, I mapped externally only the plugin folder, not the “plugins” folder where all plugins belong, but the specific slack-pusher plugin. (I already told how I named this project yet?) In this way, we have a simple file system structure where:
- Volumes contain volume data for mysql, this is ignored by git
- Docker-compose.yaml the container and service definition
- Slack-pusher the folder that contains the plugin
Easy? Quite. To run all, just run a docker-compose up and then ngrock http 8055
to expose your dev wordpress to the internet.
Next step? Well, connect it to slack and then start developing.
version: '3.3'
services:
db:
#db settings is omitted
wordpress:
depends_on:
- db
image: wordpress:latest
volumes:
- ./slack-pusher-plugin:/var/www/html/wp-content/plugins/slack-pusher-plugin:ro
ports:
- "8055:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
WORDPRESS_CONFIG_EXTRA: "define('WP_HOME','https://'.$$_SERVER['HTTP_HOST']);
define('WP_SITEURL','https://'.$$_SERVER['HTTP_HOST']); error_reporting(E_ALL);
ini_set('display_errors', 1);"</span>
Implementing the Plugin
This is the very easy part. Just create bootstrap.php file with some definition and something will move into admin area.
Implement Settings Form
I’m a prevident guy so, even not necessary to start, at some point we will need a settings form to insert some parameter like apikey
, clientid
, client secret, or everything else needed to connect with the slack part. In our case, as we just need events, it is very simple.
We need configuration to store the trusted token and a flag that tells if we can link the application with slack or not. The flag is called wait_challenge
and start false. This forces the user to explicitly turn on when ready for linking slack with wordpress. In this phase (just few seconds we hope), wordpress accepts slack challenge. As the first challenge is received, slack is linked and the token stored internally on wordpress. The settings form is very easy to implement, as for so few parameters the “vanilla” php was enough:
function spp_options_page()
{
?>
<div class="wrap">
<h1>Slack Pusher</h1>
<form method="post" action="options.php">
<?php settings_fields( 'spp-settings-group' ); ?>
<?php do_settings_sections( 'spp-settings-group' ); ?>
<table class="form-table">
<tr valign="top">
<th scope="row">Wating for challange</th>
<td><input type="checkbox" name="wait_challange" value="1"
<?php checked( '1', get_option( 'wait_challange' ) ); ?> /></td>
</tr>
<tr valign="top">
<th scope="row">Token</th>
<td><input type="text" name="token" value="<?php echo esc_attr
( get_option('token') ); ?>" disabled /></td>
</tr>
<!--
</table>
<?php submit_button(); ?>
</form>
</div>
<?php }
The good news is that data is saved automatically by default wordpress option implementation.
Implement BOT Endpoint
This endpoint manages payload in this way:
- It is a challenge
- if
wait_challenge
is enabled, store token, turn off wait_challenge
and reply with challenge payload - otherwise it is an unwanted attempt, return unauthorized
- It is a regular message hook
- if token is good, message is processed
- otherwise return unauthorized
The code is very simple. This piece of code adds the REST endpoint.
add_action( 'rest_api_init', function () {
register_rest_route( 'slack-pusher/v1', '/postmessage', array(
'methods' => 'POST',
'callback' => 'spp_post_message',
) );
} );
This function implements the algorithm:
function spp_post_message( $data ) {
$enabled=get_option('wait_challange');
if(isset($data['challenge']))
{
if($enabled==TRUE)
{
update_option('wait_challange',FALSE);
update_option('token',$data["token"]);
return sendChallangeResponse($data);
}
else
{
return sendUnauthorized();
}
}
else
{
if(get_option("token") != $data['token'])
{
return sendUnauthorized();
}
$newpost=im2post($data);
wp_insert_post($newpost);
}
return;
}
Adding Post to Wordpress
Adding post to wordpress is very very simple. The wordpress API accepts an array where we really need to set author, title and text, no more. The title is assumed by convention as the first line in the message. The other part is assumed to be the content. Slack allow formatting using special characters, like *text*
for bold or _text_
for italic. This is managed converting slack syntax into HTML. This first version has some limitation (only basic formatting is managed) but there is the same conversion library to use and may be easily improved in future.
This snippet converts slack messages in HTML:
function renderHtml($text)
{
$rendermap=array(
'/((?<!\\*)\\*(?!\\*))(.*)((?<!\\*)\*(?!\\*))/i'=> '<b>$2</b>',
'/((?<!_)_(?!_))(.*)((?<!_)_(?!_))/i'=>'<i>$2</i>',
'/((?<!\\~)\\~(?!\\~))(.*)((?<!\\~)\\~(?!\\~))/i'=> '<strike>$2</strike>',
);
foreach($rendermap as $wrapper=>$html_tag)
{
$text=preg_replace($wrapper,$html_tag,$text);
}
return $text;
}
Finally, this other snippet adds the post to wordpress:
$newpost=im2post($data);
wp_insert_post($newpost);
Points of Interest
Using Slack API was very funny and tells me all the possibilities we have when integrating with this product. Moreover, I had the proof that implementing a good set of extension capabilities can drive the product to success, nowadays. I tried to summarize the most important topics of this article.
Slack API
Using Event API, we have been able to send instant message to an external app and process it. This is done in a secure way thrusting the endpoint with slack. The configuration part was very simple, but having parametric endpoint (our wordpress url changes case by case), we cannot deliver the application as-is, but we need to ask the final user to set up it manually. This is not a problem if we had developed a Saas paid solution, when we receive all call and make things.
Wordpress Module
It was easy to create a wordpress plugin. Wordpress is functional based, widely used, so with a very short learning curve. I used it vanilla as we don’t need much more from what we had just by implementing it in the simple way. To transform this demo to a real world plugin, some refactoring can be helpful to separate logical part (settings, API, bootstrap). Even in the real world, it may be convenient to have an app that acts as broker to the cms end. Doing so, we could have a slack app (paid Saas product?) that posts message on my destination like facebook, medium, linkedin, wordpress, drupal… this will be useful also to reduce friction with the user for first installation and centralize business logic.
Future Works
The existent plugin may be extended in many ways:
- Adding plugin to wordpress marketplace
- Adding possibility to pick the right user basing on the slack user
- Improving slack formatting to support links, images, list and all the stuff
- Adding commands or syntax to configure many options (tag where the post belong, status, etc.)
The idea can be reused to:
- Do the same with other CMS, or wiki
- Create a dispatcher app that can be configured to post into many destinations
- Create a Saas application that can be resold (maybe a dream)
History
- 2019-01-24: Article published
- 2019-01-09: Repo & project created