Build an SMS "Takeaways" System

  • By Michael Garrison 7 Months Ago

One of the most popular features that the Spark team built for RX2017 was the "Takeaways" system. This allowed the attendees to text keywords to a Text-To-Workflow number, and end up with a list of articles on the Takeaways website that gave deeper information into that subject.

With the advent of version 7 of Rock, now you too have everything you need to build a takeaways system!

Set up a Content Channel

The first thing you're going to need is a content channel for all of your takeaways. Start at Admin Tools -> CMS Configuration and go to the "Content Channels" page. Click the button at the bottom of the grid to create a new Content Channel.


I used the Universal No Date Channel Type, but you can use any type that suits you. Having dates which would only provide certain times that each keyword would be valid is entirely possible using other types, but is beyond what I'll cover in this article.

The critical thing in this setup screen, is that we add a few attributes under Item Attributes. This example will use the name and key of Keyword for the first item, but you can change that if you'd like to use something else (just remember to change it everywhere we will use Keyword here, and remember that the key is case-sensitive. I like setting this attribute as Show in Grid so I can quickly see what keywords I've got set up right from the channel. Likewise, add a second attribute called "Response" - we'll use this to send a confirmation back to the user. But this one doesn't need to be shown in the grid.


Now, Save your channel and add a few items to it. The Title and Content fields will be what actually show up on the takeaways page, so format those nicely for the user. Use the Keyword box to specify what word should be used to add this item to the person's list. This should only be one word, for best reliability. Then provide a response in the Response box. A basic example of a response would be "OK! I've added information about our Children's Ministry to your takeaway page," but feel free to have a little fun with it.

That's about it for the channel - once the rest of this process is set up, this channel page is the only one you'll have to interact with to add or remove available keywords.

Oh, but before you leave the channel page, take note of the ContentChannelId number listed in the URL. You'll need this in the workflow

Set Up Your Workflow

If you're familiar with other workflows I've documented before, you're going to love how easy this one is.


Name the workflow and provide a description as usual. There's probably no need to change much else, except you probably don't want it to be automatically persisted.


Assuming you're going to use this with Text-To-Workflow, let's set up FromPerson and MessageBody like you're used to. Include any other other standard TTW attributes you'd like to, as well.

Add another attribute now: Target. This should be a Text type attribute (we're going to use it to store the GUID of the Content Channel Item the person has requested to follow).

Finally, one final attribute: SMSResponse. Make this a Memo type attribute. This is a special Attribute key that the Text-To-Workflow module uses to auto-send a reply once it's done with its initial processing.


Under the Start activity, add an Action of type Lava Run. Here's the Lava to copy and paste into the action:

{%- capture test -%}(?i){{- Workflow | Attribute:'MessageBody' -}}{%- endcapture -%}
    {%- contentchannelitem where:'ContentChannelId == "1004"' -%}
    {%- for item in contentchannelitemItems %}
        {%- assign match = item | Attribute:'Keyword' | RegExMatch:{{test}} -%}
        {%- if match -%}
            {{- item.Guid -}}
            {%- break -%}
        {%- endif -%}
    {%- endfor -%}
{%- endcontentchannelitem -%}

Now, see that red 1004 at the top of the Lava? Replace that with the ContentChannelId that we noted in the last section. Then select your Target attribute in the Attribute field on this action.

This is an incredibly cool action. It's going to search through all the items you've added to your Content Channel, and use Regular Expressions to look for a case-insensitive match between the keyword and the item, and when one's found, it will provide us the GUID for that item.

Moving on, let's add another Action in the same activity. Click the filter button in the top right corner, and tell it to only run this action If Target Is Not Blank

This action will be of type Person Follow Add. Select FromPerson in the "Person" field, and set "Entity Type" to Content Channel Item. Finally, set the "Entity To Follow" using the "Attribute Value" control; select Target from its list. This is where that GUID that our Lava found gets used.

At its core, these two actions are all you MUST have in this workflow. But it's a nice touch to go ahead and let the person know whether it worked, so let's move on.

The next action should be another Lava Run action, and have the same If Target Is Not Blank filter set as the last filter. Set this one to complete the Activity when it's run. Here's the Lava this time around:

{%- contentchannelitem where:'Guid == "{{ Workflow | Attribute:'Target','RawValue' }}"' -%}
    {%- for item in contentchannelitemItems %}
        {{- item | Attribute:'Response' -}}
    {%- endfor -%}
{%- endcontentchannelitem -%}
To view your takeaways, visit {{ 'Global' | Attribute:'PublicApplicationRoot' }}Takeaways

This will take the per-item response and add a link to your takeaways page at the end. So store this output in SMSResponse. Once this processes, the Text To Workflow module will send this string back to the sender.

OK, but what if they sent a keyword that doesn't match any of your items? Let's let them know that.

The final action will be another Lava Run action, and it should ALSO mark the Activity Complete when it's done. Set this filter to run this action If Target Is Blank (the opposite of the above filters). Set this output to be stored in SMSResponse and provide a nice message like "Sorry! I couldn't find a takeaway matching the keyword you sent! Please try again."

Save your workflow, and let's move on.


Remember your Text-to-Workflow Triggers

Now, in order for the workflow to actually run when someone texts you, you need to configure the text-to-workflow module. This is covered pretty well in the documentation, but in this case you only need to pass FromPerson and MessageBody. If you've got a single phone number devoted to your takeaways, you can also leave the keyword expression blank, which will ensure that your workflows responds to any message texted to that number.

Set Up Your Takeaways Page

Hop over to your External Site, and figure out where you want your Takeaways page to live. This will be the personalized page that people can visit to see a list of all of the takeaways they've subscribed to. Add a new page there using the Child Pages button on the Admin Toolbar, then click on the page in the Child Pages menu to go there.

You only need one block on this page: the magical Following By Entity block. So add that to your Main zone using the button on the Admin Toolbar.

Once your page refreshes and contains that block, use the button on the admin toolbar and the button on the fly-out menu at the top left of your block to configure the block.

Set the Entity Type to "Content Channel Item", and set the Max Results as you wish.

Now, there's already a Lava Template provided to you, and it's pretty close to working. But there are two places the template lists {{ item.Name }}, and you'll need to change both of those occurrences to {{ item.Title }}. I also changed class="fa fa-pencil" to class="fa fa-times" in two locations; this represents a link that will let the user "unfollow" a particular item, and an x seems more indicitive of that than a pencil, to me.

You can, of course, edit this template as heavily as your desire and HTML skills would like. But for the demo, that's all we really need to do to get this page working.

One more setting: change the Link URL to /takeawayitem/[id] - this will provide the route for someone clicking on one of the takeaways.


Save the block configuration and you should see an empty list of Content Channel Items you've followed (since you haven't followed any yet). One thing remains: Click the Page Properties button on the Admin Toolbar, then flip over to the Advanced Settings tab. Under Page Routes type Takeaways. That will let them get to this page using the friendly /Takeaways URL on your external site, rather than /Page/whatever.

Set Up Your Takeaways Item Page

Now, we provided a /takeawayitem/[Id] style link from the list of takeaways, but that page doesn't exist yet. We need to take them to a page which will actually show the article you've provided in the Content Channel Item. So create a child page of the Takeaways page.

Set the Page Routes setting (remember it's under Page Properties -> Advanced Settings) to takeawayitem/{item}.

Now add a Content Channel View block to your Main zone. Get into its settings.

Again, you can get as fancy as you'd like, but the minimum template you'll want here is:

{% for item in Items %}
    <h1>{{ item.Title }}</h1>
    {{ item.Content }}
{% endfor %}

If you've got other attributes, such as images, that you've added to the channel's items, you'd access them in this template using tags like {{ item | Attribute:'Image' }}.

Check Set Page Title and Enable Query/Route Parameter Filtering. That should be all you need to get this page working.


Go Forth

OK, that's all it should take! Send a text to your designated takeaways Twilio number with one of your takeaway keywords. You should get the response back that you programmed for that particular takeaway. Now visit the /takeaways page (while logged in as yourself) and you should see that item show up on the page. Click on it and you'll go to your detail page where you can get the full contents you provided for that takeaway.

Rock on!

Spark Development Network
Flagstaff, AZ

Michael Garrison recently left his job in Architecture to become one of the "new guys" at Spark (the "Core Team"), but he's still helping out Christ's Church of Flagstaff and other non-profits with tech needs in his off-hours, trying to make computers do what computers do best, so that people are freed to do what we do best: relate with people!