Event management in Textpattern

Kevin Potts 28 May 2013

Learn how to easily create calendars in Textpattern using smd_calendar, and use Textpattern functionality to manage event information in different ways. Very useful for clubs, churches, event companies and any other organization who depends on highly fluent event information.

We’ve all seen calendars on websites for clubs, churches, bands, resorts, event spaces and more. They’re plainly common, but still notoriously difficult to manage without an intelligent content management system driving the backend.

Plug-and-play options like embeddable Google calendars make a lot of sense for smaller websites, or for calendars requiring little information. But we’re Textpattern builders, and we need Textpattern solutions.

This tutorial will cover event management tactics. The majority of the discussion will be around the creation, customization, and management of a calendar, but we’ll touch on some other sophisticated things Textpattern enables us to do (nearly) out of the box.

Starting Ingredients

Advanced Preferences

  • Ensure your timezone is correct. You’ve probably already done this, but just in case. Also, I typically enable Automatically adjust DST setting?.
  • Enable “Publish expired articles?”. This will ensure past events don’t magically disappear.
  • At least four available custom fields, but almost assuredly more than that.


  • smd_calendar. This is the alpha and omega of calendar plugins. This wildly expands Textpattern’s core functionality in this area, and will pretty much be a one-stop shop during this tutorial.
  • chh_if_data. This is one of the indispensable socket wrenches that may come in handy as you test for certain information.
  • glz_custom_fields. Not critical, but it’s helpful in managing the custom fields needed, especially if your site is using more than ten, and definitely if you’re establishing structured choices like a dropdown menu or checkboxes.


  • Create a new section called “calendar”.
  • Bookmark the PHP strftime() page. You will undoubtedly reference it before your project is out.
  • Become familiar with the Event module of schema.org, and be prepared to use this pattern for your markup. It is what the Google wishes.

Define the Event Schema

As you plan your calendar and event management functionality, it’s important to do a little schema-mapping. This ensures you have enough programmatic hooks to parse, sort, and present the information in all the ways the site requires.

Let’s map out an example. Let’s say I’m developing a calendar for a popular club in New York. We’ve got a blend of regular house bands, one-off concerts, DJ nights, special events, private parties and more. Some nights may have more than one thing; other nights might be empty. The calendar won’t get too crazy, but it also won’t be consistent week to week.

Core fields:

  • Title. For, you know, the title of the event. In this example, it will most likely be the performer’s name.
  • Body. This will be for the description of the event.
  • Category 1. We will want to have a few clearly defined “event types” here. Using our night club example, these will get us started: Live Music, Comedy, DJ Night, Private Party, Special Event.
  • Posted and Expires. This tutorial will use both fields.

Custom fields, required:

  • “Repeat Pattern”. This is what smd_calendar refers to as the “stepfield”, and is mandatory to set up repeating events like a weekly show.
  • “Omit Dates”. For dates where the event is not going to happen.
  • “Cancel Dates”. For dates where a recurring event is cancelled.
  • “Extra Dates”. For additional event dates.

Custom fields, optional:

  • “All-Day Event”. This is a boolean choice for events that are all-day. If you’re using glz_custom_fields, then it can be a checkbox or dropdown.
  • “Day”. Even though an event’s weekday can be implied from its Posted value, I have found this extra field to be an invaluable hook for sorting/parsing events in more straightforward ways. This is most likely a result of me being an utter hack at programming, but it works brilliantly and I’ll show an example later. Again, if you’re using glz_custom_fields, make this a dropdown: “Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday”.

Custom fields to think about:

  • Does an event have a specific room or location? An extra field to dictate that would be good.
  • Do you want an abbreviated title for displaying on the calendar, or an alternative title for search results?
  • Do you have consistent performers or staff or individuals associated with an event? For instance, when I built a calendar for a fitness club, each group fitness, yoga class, or swimming class had an instructor and their name was built into the schema so people could sort events by that instructor.

The more data we have that is structured in a consistent way, the more ways we can collate events. The more events you have, the more important this becomes.

Setting Up the Calendar

Getting a calendar up and running is remarkably simple. Once smd_calendar is installed, simply drop the tag code into a page template, or an article:

<txp:smd_calendar />

Plain calendar without events

Figure 1: Plain calendar without controls or events

This will give you a blank, bare-bones calendar. (See figure 1.) While this is sexy, it’s not quite functional, so let’s get some core attributes out of the way:

  • dayformat. This attribute is useful for explicitly naming the days of the week at the top of the table, and also useful if you want to start the calendar on a day other than Sunday. This is also an opportunity to use localised day names.
  • yearwidth. This attribute dictates how far in time a visitor can traverse the calendar. For instance, using yearwidth=“1,3” would allow someone to see up to 12 previous months (one year) and 36 forthcoming months (three years). While someone could still get to March 2025 or June 1945 by manipulating the URL query string, they would not be able to access them from the calendar’s controls, which we’ll discuss next …
  • select. For a user to traverse the calendar, we need to enable dropdowns for months and/or years. select=“month,year” will do just that.
  • selectbtn. By default the dropdowns activate after selection, but I personally prefer all of my forms have manual controls to minimize mistakes and provide a better handle for alternative browsing devices. By giving a value to this attribute, you enable that button.
  • id. If you want your calendar to have an ID. Not explicitly required, but if you have more than one calendar on a page, necessary to avoid crossing the streams.
  • section. This is the section from where you’d like to pull events. You can also filter by categories and sub-categories, authors, expiration and more.

With these, our tag might look something like this:

<txp:smd_calendar dayformat="Sun,Mon,Tue,Wed,Thu,Fri,Sat" select="month,year" selectbtn="Select" id="calendar" yearwidth="1,3" />

Plain calendar without events

Figure 2: Calendar with month and year controls

The most notable visual difference will be the month and year controls in place. (See figure 2.)

A few more mechanics and then we can add events. First, we need to dictate from where we’ll pull event information; in this case, we’ll use the section of “Calendar”. Then we need to tell the plugin the ID of the custom field used for the stepfield, which controls repeating events. Our tag now looks like this:

<txp:smd_calendar dayformat="Sun,Mon,Tue,Wed,Thu,Fri,Sat" select="month,year" selectbtn="Select" id="calendar_2" yearwidth="1,3" section="calendar" stepfield="custom_7" />

Now we need to populate the calendar. Let’s go ahead and add some events, populating as much as we can. For the sake of testing, we’ll add a single one-off concert, a weekly DJ night, and then a multi-day event. You can see these in figure 3.

  1. Our single event, the “Big Concert” will take place on 2013-02-09 at 7 pm. We just need to make sure the Timestamp field shows this.
  2. Our weekly DJ event is every Wednesday night at 6 pm. Two important notes with recurring events. First, make sure the stepfield is populated (we called this custom field “Repeat Pattern”, noted in our schema); in our case, we’ll use “7 days” to indicate frequency. Second, we’ll leave the Expires fields blank because this event has no scheduled end. If we had a recurring event and wanted to dictate an end-date (say, for instance, a run of eight weeks), simply indicate the last date in the Expires fields.
  3. Our multi-day event starts on 2013-02-17 and goes to 2013-02-21. In order to establish a multi-day event, populate both the Timestamp and Expires fields.

Plain calendar without events

Figure 3: Calendar populated with events

Many Forms, Much Control

Now that we have some of the base engine up and running, it’s time to start tinkering. Part of that is CSS, of course, because tables need a lot of help to look good. But the real fun comes in manipulating the actual parsing of data. We won’t cover a huge amount of CSS because this article is already too long, so let’s dig into what we can do with smd_calendar.


This controls the actual layout of the cell — not the events inside the cell. For instance, the date is, by default, wrapped in an <h4>. You can change this markup. Inside a form called “cal_cell-layout” (or whatever), use replacement tags like this:

<span class=”date”>{day}</span>

You can all also show just cancelled events, or just recurring events, or only standard events, or any combination of those and other things. Also useful is generating classes for CSS hooks or a unique ID inside each cell for JavaScript manipulation. For instance:

<div id=”day-{year}-{monthzeros}-{dayzeros}” class=”{weekdayfull} {monthname}”>
<span class=”date”>{day}</span>

Which would produce:

<div id="day-2013-02-09" class="saturday february">
<span class="date">9</span>
… events get parsed here …

Keep in mind smd_calendar already provides a host of class names to the table and table cells so much styling can be done without this level of customization to the cell layout. (And in fact, those class names can be changed through other attributes in smd_calendar.)


The standard “form” attribute is our familiar place to use Textpattern article tags to control the output of each event inside the cell. By default, we get a simple < span> and <a> like this:

<span class="smd_cal_standard">
<a title="Big Concert" href="https://domain.com/calendar/big-concert">Big Concert</a>

This may be sufficient. But what if we don’t want to link event names? Or what if we need to display their category, or maybe the performer’s name, or the location, or the time of the event? Or what if we want to use schema.org microdata? In a new article-type form called “cal_event-layout”, we’ll do just that and more:

<div id="event-<txp:article_id />" class="cal_event <txp:category1 />" itemscope itemtype="https://schema.org/Event">
    <span itemprop="additionalType" class="cal_event-category"><txp:category1 title="1" /></span>
    <span itemprop="name" class="cal_event-name"><txp:title /></span>
    <span itemprop="startDate" class="cal_event-date" content='<txp:posted format="iso8601" />'><txp:posted format="%l %P" /></span>
    <span itemprop="location" class="cal_event-location"><txp:custom_field name="Location" /></span>

This would produce something like:

<div id="event-12" class="cal_event live-music" itemscope itemtype="https://schema.org/Event">
    <span itemprop="additionalType" class="cal_event-category">Live Music</span>
    <span itemprop="name" class="cal_event-name">Big Concert</span>
    <span itemprop="startDate" class="cal_event-date" content="2013-02-09T20:00">8 pm</span>
    <span itemprop="location" class="cal_event-location">Main Stage</span>

Inside each event, we can test for custom fields (like an all-day event) or categories, test if there is an expires time using <txp_if_expired> (so we could show 8 pm – 11 pm, for instance), decide if we want to link to a bigger description, and more.

recurform and spanform

These also control event output with article tags like the form attribute above, but are targeted for recurring events and events that span multiple days, respectively.


If you want to construct your own header using the active date information in the calendar. This one, like cellform, also uses replacement tags to output the data. This is especially handy when localizing the calendar to different languages.

More Ways to Present Event Information

Over the years I’ve had the need to do a few different things with event data that didn’t involve a calendar user-interface. Here are a few alternative ideas to get the most use from your data.

Count Future Events by Category

Let’s say you want to output a list of categories for events, like Live Music, Comedy, DJ Night, Private Party, and Special Event. Next to each, we want a count of upcoming events. While this seems simple, out-of-the-box Textpattern does not help us here, nor do standard counting plugins like mdn_count because they only count current articles, not future articles. Instead, we have to get our hands dirty with MySQL.

Our five categories are all children under the parent category “Event Type”. We’ll start with a simple category_list tag:

<txp:category_list parent="event-type" children="1" form="nav_event-type_each" exclude="event-type" wraptag="ul" break="li" />

Next, we need a category-type form called “nav_event-type_each”. We’re going to use the plugin rah_function which magically enables native PHP functions inside Textpattern.

<a href="/?c=<txp:category />"><txp:category title="1" /> <em>(<txp:rah_function call="safe_count" table="textpattern" where='Status=4 and Posted > now() and (Category1="<txp:rah_function call="doSlash"><txp:category /></txp:rah_function>" or Category2="<txp:rah_function call="doSlash"><txp:category /></txp:rah_function>")' />)</em> </a>

This will all output:

<li><a href="/?c=comedy">Comedy <em>3</em></a>
<li><a href="/?c=dj-night">DJ Night <em>5</em></a>
<li><a href="/?c=live-music">Live Music <em>5</em></a>
<li><a href="/?c=private-party">Private Party <em>5</em></a>
<li><a href="/?c=special-event">Special Event <em>5</em></a>

List Today’s Events

This is the simple script I use to output a list of today’s events:

<h2>Today's Events (<txp:php>echo date("F j, Y");</txp:php>)</h2>
<txp:smd_article_event section="calendar" extrafield="custom_3" stepfield="custom_7" omitfield="custom_5" skipfield="custom_6" time=”today” form="calendar_daylist_homepage" limit="9999">
    <p><txp:title /> - <txp:posted format="%l %P" /></p>

List Events by Weekday

If you have lots of recurring events, listing a regular weekly schedule is very handy. When I built a website for a health club, they had over a hundred weekly classes, so it was imperative in the Swimming, Yoga and Pilates pages to display just those events’ days and times.

Unfortunately, this requires a bit of manual work to force Textpattern into presenting the data reliably. Assuming we want to pull all events with the category of “Live Music”, start with this:

<txp:variable name="category" value="live-music" />
<txp:output_form for=”cal_weekly-schedule” />

Here is the contents of the misc-type form “cal_weekly-schedule”:

<txp:article_custom section="calendar" category=’<txp:variable name="category" />’ limit="9999" sort="Posted asc" Day="Monday" form="cal_weekly-schedule_each" />
<txp:article_custom section="calendar" category=’<txp:variable name="category" />’ limit="9999" sort="Posted asc" Day="Tuesday" form="cal_weekly-schedule_each" />
<txp:article_custom section="calendar" category=’<txp:variable name="category" />’ limit="9999" sort="Posted asc" Day="Wednesday" form="cal_weekly-schedule_each" />
<txp:article_custom section="calendar" category=’<txp:variable name="category" />’ limit="9999" sort="Posted asc" Day="Thursday" form="cal_weekly-schedule_each" />
<txp:article_custom section="calendar" category=’<txp:variable name="category" />’ limit="9999" sort="Posted asc" Day="Friday" form="cal_weekly-schedule_each" />
<txp:article_custom section="calendar" category=’<txp:variable name="category" />’ limit="9999" sort="Posted asc" Day="Saturday" form="cal_weekly-schedule_each" />
<txp:article_custom section="calendar" category=’<txp:variable name="category" />’ limit="9999" sort="Posted asc" Day="Sunday" form="cal_weekly-schedule_each" />

Separating the category name in a variable enables us to re-use this code for any category, anywhere. We’re also taking advantage of the hard-coded day names we captured via the custom field “Day” as part of our original event schema by using that custom field as an explicit filter.

The contents of the article-type form “cal_weekly-schedule_each”:

<h2><txp:posted format="%A" /></h2>
<p><txp:title /> - <txp:posted format="%l %P" /></p>

RSS Feed for Future-Dated Content

Textpattern’s feed_link tag cannot handle future-dated content at all. Luckily, there is a very detailed tutorial by yours truly on how to roll your own RSS over at txptips.com.

comments powered by Disqus