PHP OOP interface for writing Slack Block Kit messages and modals

Overview

Slack Block Kit for PHP

👉 For formatting messages and modals for Slack using their Block Kit syntax via an OOP interface 👈

By Jeremy Lindblom (@jeremeamia)

Slack logo placed on top of blocks

Coded in PHP 7 Packagist Version Build Status


Introduction

From Slack's Block Kit documentation:

Block Kit is a UI framework for Slack apps that offers a balance of control and flexibility when building experiences in messages and other surfaces.

Customize the order and appearance of information and guide users through your app's capabilities by composing, updating, sequencing, and stacking blocks — reusable components that work almost everywhere in Slack.

This library provides an OOP interface in PHP for composing messages/modals using Slack Block Kit. It also does the reverse, meaning you can "hydrate" message/modal JSON into an object hierarchy.

Block Kit Concepts

This library helps you build Slack messages programmatically and dynamically in your code, but you need to know how they work generally first. The library does try to prevent you from doing things you are not permitted to do in Block Kit, but it does not validate or guard against every single rule.

You may want to review the following concepts in the Slack documentation:

In general, we refer to all of the different things in Block Kit collectively as "elements".

Installation

Install easily via Composer:

composer require slack-php/slack-block-kit

Then include the Composer-generated autoloader in your project's initialization code.

Note: This library is built for PHP 7.3+.

Basic Usage

This library supports an intuitive and fluid syntax for composing Slack surfaces (e.g., messages, modals). The Kit class acts as a façade to the library, and let's you start new messages/modals.

<?php

use SlackPhp\BlockKit\Kit;
use SlackPhp\BlockKit\Surfaces\Message;

// ...

// You can start a message from the `Kit` class.
$msg = Kit::newMessage();
// OR via the surface class's "new" method.
$msg = Message::new();

// Then you can add blocks using the surface's available methods.
$msg->text('Don\'t you just love XKCD?');
$msg->divider();
$msg->newImage()
    ->title('Team Chat')
    ->url('https://imgs.xkcd.com/comics/team_chat.png')
    ->altText('Comic about the stubbornness of some people switching chat clients');

// To convert to JSON (to send to Slack API, webhook, or response_url), use PHP's `json_encode` function.
echo json_encode($msg);
// OR you can use the surfaces's `toJson` method, which also includes a convenience parameter for pretty printing.
echo $msg->toJson(true);

Fluent Interface

When using the fluent interface, every method that sets a property or adds a sub-element returns the original element's object, so you can chain additional method calls.

$msg = Message::new()
    ->text('Don\'t you just love XKCD?');
    ->divider();

Methods with a new prefix will return the new element's object, so be careful with how you are using the fluent interface in those cases.

// Correctly renders the whole message.
$msg = Message::new()
    ->text('Don\'t you just love XKCD?')
    ->divider();
$msg->newImage()
    ->title('Team Chat')
    ->url('https://imgs.xkcd.com/comics/team_chat.png')
    ->altText('Comic about the stubbornness of some people switching chat clients');
echo json_encode($msg);
// YAY!

// INCORRECT: Renders just the image, because only that element gets stored in the variable.
$msg = Message::new()
    ->text('Don\'t you just love XKCD?')
    ->divider()
    ->newImage()
        ->title('Team Chat')
        ->url('https://imgs.xkcd.com/comics/team_chat.png')
        ->altText('Comic about the stubbornness of some people switching chat clients');
echo json_encode($msg);
// WHOOPS!

Tapping

Tapping is a way to keep the fluent interface going, but makes sure the whole message is preserved.

// Correctly renders the whole message, by using tap()
$msg = Message::new()
    ->text('Don\'t you just love XKCD?')
    ->divider()
    ->tap(function (Message $msg) {
        $msg->newImage()
            ->title('Team Chat')
            ->url('https://imgs.xkcd.com/comics/team_chat.png')
            ->altText('Comic about the stubbornness of some people switching chat clients');
    });
echo json_encode($msg);
// YAY!

Preview in Block Kit Builder

Slack provides an interactive Block Kit Builder for composing/testing messages and other surfaces. This is a great way to play around with and learn the Block Kit format.

The Kit::preview method allows you to render your message/surface as a Block Kit Builder URL, so you can link to a preview or your message/surface in the browser via their interactive tool. This will help you see how it would be rendered in a Slack client.

$msg = Kit::newMessage()
    ->text('Don\'t you just love XKCD?')
    ->divider()
    ->tap(function (Message $msg) {
        $msg->newImage()
            ->title('Team Chat')
            ->url('https://imgs.xkcd.com/comics/team_chat.png')
            ->altText('Comic about the stubbornness of some people switching chat clients');
    });

echo Kit::preview($msg);

Output

https://app.slack.com/block-kit-builder#%7B"blocks":%5B%7B"type":"section"%2C"text":%7B"type":"mrkdwn"%2C"text":"Don%27t%20you%20just%20love%20XKCD%3F"%7D%7D%2C%7B"type":"divider"%7D%2C%7B"type":"image"%2C"title":%7B"type":"plain_text"%2C"text":"Team%20Chat"%7D%2C"image_url":"https:%5C%2F%5C%2Fimgs.xkcd.com%5C%2Fcomics%5C%2Fteam_chat.png"%2C"alt_text":"Comic%20about%20the%20stubbornness%20of%20some%20people%20switching%20chat%20clients"%7D%5D%7D

And here's the actual Block Kit Builder link.

It will show up in the Block Kit Builder looking something like this:

Screenshot of rendered message in Block Kit Builder

Surface Hydration

Some Slack application integrations (such as with Modals) require receiving the JSON of an existing surface and then modifying or replacing that surface with another. You can "hydrate" the JSON of a surface (or element) into its object representation using its fromArray method (or fromJson).

$messageJson = <<<JSON
{
    "blocks": [
        {
            "type": "section",
            "block_id": "block1",
            "text": {
                "type": "mrkdwn",
                "text": "*foo bar*"
            }
        }
    }
}
JSON;

// Use fromArray to hydrate the message from parsed JSON data.
$decodedMessageJson = json_decode($messageJson, true);
$message = Message::fromArray($decodedMessageJson);

// OR... use fromJson to hydrate from a JSON string.
$message = Message::fromJson($messageJson);

Message Formatting

The Formatter class exists to provide helpers for formatting "mrkdwn" text. These helpers can be used so that you don't have to have the Slack mrkdwn syntax memorized. Also, these functions will properly escape <, >, and & characters automatically, if it's needed.

Example:

// Note: $event is meant to represent some kind of DTO from your own application.
$fmt = Kit::formatter();
$msg = Kit::newMessage()->text($fmt->sub(
    'Hello, {audience}! On {date}, {host} will be hosting an AMA in the {channel} channel at {time}.',
    [
        'audience' => $fmt->atHere(),
        'date'     => $fmt->date($event->timestamp),
        'host'     => $fmt->user($event->hostId),
        'channel'  => $fmt->channel($event->channelId),
        'time'     => $fmt->time($event->timestamp),
    ]
));

Example Result:

{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "Hello, <!here>! On <!date^1608322949^{date}|2020-12-18T20:22:29+00:00>, <@U12345678> will be hosting an AMA in the <#C12345678> channel at <!date^1608322949^{time}|2020-12-18T20:22:29+00:00>."
      }
    }
  ]
}

Virtual Elements

In addition to the standard Block Kit elements, the following are virtual/custom elements composed of one or more blocks:

  • TwoColumnTable - Uses Sections with Fields to create a two-column table with an optional header.

Class Structure

The Kit façade provides ways to create surfaces. Surfaces contain one or more blocks. Blocks are the primary element of the Block Kit. Blocks contain other elements, including other blocks, inputs (interactive elements), and partials (element parts that are not uniquely identifiable).

UML diagram for slack-block-kit

See the YUML
[Kit]-creates>[Surface]
[Surface]^[Message]
[Surface]^[Modal]
[Surface]^[AppHome]
[Surface]^[Attachment]
[Element]^[Surface]
[Element]^[Block]
[Element]^[Input]
[Element]^[Partial]
[Surface]<>->[Block]
[Message]<>->[Attachment]
[Block]<>->[Input]
[Block]<>->[Partial]
[Input]-[note:Examples: Button
DatePicker {bg:cornsilk}]
[Partial]-[note: Examples: Text
Fields {bg:cornsilk}]
[Block]-[note: Examples: Section
Actions {bg:cornsilk}]

Contributions

Contributions welcome to support new elements, add tests, improve, etc.

When implementing elements, to fit within the existing DSL, consider these points:

  • To set instantiated sub-element objects, provide a set-prefixed setter (e.g., setText(Text $text): self).
    • Should return self to support chaining.
    • Should set the parent (e.g., setParent()) of the sub-element to $this.
  • To set simple sub-element objects, provide a simple setter method (e.g., title(string $title): self).
    • Should be in addition to the set-prefixed setter.
    • Should be named after the property being set.
    • Should return self to support chaining.
    • Should have a maximum of 2 parameters.
    • Should call the regular setter (e.g., return $this->setText(new PlainText($title));).
  • To set other non-element properties, provide a simple setter method (e.g., url(string $url): self).
    • Should be named after the property being set.
    • Should return self to support chaining.
  • To create new sub-elements attached to the current one, provide a new-prefixed factory method (e.g., newImage(): Image).
    • Should return an instance of the sub-element.
    • Should set the parent (e.g., setParent()) of the sub-element to $this before returning.
    • Should support a $blockId parameter if it's a Block or an $actionId parameter if it's an Input element.
  • All element types should be defined in the Type class and registered in relevant constant lists to be appropriately validated.
  • If you implement a custom constructor for an element, make sure all the parameters are optional.
Releases(0.19.0)
  • 0.19.0(Jun 18, 2021)

    • Adds tapIf() to all Elements. Works the same as tap(), but allows you to specify a condition to decide if the tap is needed.
    • Adds blocks() methods to all Surfaces for adding arrays/iterables of blocks easily.
    • Adds support for callbackId, externalId, and privateMetadata to AppHome surfaces. This was previously missing.
      • This was done by creating a base View surface class that both Modal and AppHome extend.
    • Adds the encodePrivateMetadata(array $data) method to Modal and AppHome, which provides an easy way to set encoded private metadata from an array.
    • Adds support for the newInput() method to all surfaces, instead of just Modals.
    • Updates all VirtualBlocks to implement IteratorAggregate for emitting it's BlockElements.
    Source code(tar.gz)
    Source code(zip)
  • 0.18.0(Apr 30, 2021)

    • Adds support for using Blocks\Input in Surfaces\Message (new in Slack as of 4/20/2021)
    • Adds support for the new dispatch_action property in Blocks\Input
    • Adds support for the new dispatch_action_config property in Inputs\TextInput
      • Adds new Partials\DispatchActionConfig object
      • Adds setters in Inputs\TextInput: setDispatchActionConfig, triggerActionOnEnterPressed, and triggerActionOnCharacterEntered
    Source code(tar.gz)
    Source code(zip)
  • 0.17.0(Apr 15, 2021)

    • Moved repo from https://github.com/jeremeamia/slack-block-kit to https://github.com/slack-php org.
    • Updated root namespace from Jeremeamia\Slack\BlockKit to SlackPhp\BlockKit.
    • Updated composer package from jeremeamia/slack-block-kit to slack-php/slack-block-kit.
    Source code(tar.gz)
    Source code(zip)
Owner
Slack PHP Framework
PHP framework and libraries for building Slack apps
Slack PHP Framework
Moodle plugin to limit the access to course content according to the user level in Block Game.

Moodle plugin to limit the access to course content according to the user level in Block Game.

null 3 May 12, 2021
Rubix Server is a library for bringing your trained Rubix ML models into production.

Rubix Server is a library for bringing your trained Rubix ML models into production. Inference servers are stand-alone services that run on your private or public network and wrap your trained estimator in an API that can be queried locally or over the network in real-time using standard protocols. In addition, the library provides async-compatible client implementations for making queries to the server from your PHP applications.

Rubix 36 May 23, 2021
Optimizes class loading performance by generating a single PHP file containing all of the autoloaded files.

Class Preloader for PHP This tool is used to generate a single PHP script containing all of the classes required for a specific use case. Using a sing

Class Preloader 348 Jun 3, 2021
Sslurp is a simple library which aims to make properly dealing with SSL in PHP suck less.

Sslurp v1.0 by Evan Coury Introduction Dealing with SSL properly in PHP is a pain in the ass and completely insecure by default. Sslurp aims to make i

Evan Coury 62 Apr 29, 2021
The only way to implement the pipe operator in PHP.

Pipe Operator in PHP Introduction This package is based on the pipe operator RFC by Sara Golemon and Marcelo Camargo (2016), who explains the problem

BoostPHP 10 Mar 28, 2021
Pagination for PHP.

NB This project is no longer maintained; you may like to use https://github.com/BabDev/Pagerfanta instead. Pagerfanta This project is for PHP 7. If yo

White October 1.6k Jun 13, 2021
A framework agnostic, multi-gateway payment processing library for PHP 5.6+

Omnipay An easy to use, consistent payment processing library for PHP Omnipay is a payment processing library for PHP. It has been designed based on i

The League of Extraordinary Packages 5.3k Jun 20, 2021
PHP Lightweight Message Bus supporting CQRS.

Prooph Service Bus PHP 7.1+ lightweight message bus supporting CQRS and Micro Services Important This library will receive support until December 31,

null 437 Jun 5, 2021
A framework agnostic PHP library to build chat bots

BotMan If you want to learn how to create reusable PHP packages yourself, take a look at my upcoming PHP Package Development video course. About BotMa

BotMan 5.4k Jun 18, 2021
A set of utilities for working with vk api!

vk-utils Документация на русском языке Installation composer require labile/vk-utils How to use it? Simple example use Astaroth\VkUtils\Client; $api

null 3 Jun 14, 2021
A PocketMine/Altay Plugin to morph yourself into a block

BlockMorph A PocketMine/Altay Plugin to morph yourself into a block Command To morph yourself into a block use this command: /blockmorph [BlockID|Bloc

Matze 5 May 6, 2021
Command bus package for PHP

#Chief Chief is a powerful standalone command bus package for PHP 5.4+. Contents What is a command bus Installation Usage Class-based command handlers

Adam Nicholson 49 Apr 29, 2021
Take control of your users in PHP

Disciple Take control of your users Installation Install via Composer: composer require decodelabs/disciple PHP version Please note, the final v1 rele

Decode Labs 3 May 11, 2021
yii2 MinIO

yii2-minio Yii2 MinIO Installation php composer.phar require bevin1984/yii2-minio:^0.0.1 Or "bevin1984/yii2-minio": "^0.0.1" Configuration 'components

Bevin 4 May 26, 2021