WordPress challenge of the day: customizing The Events Calendar’s RSS feed and how it displays in a MailChimp RSS campaign

This one’s a doozy. I have a client who is using The Events Calendar, and they want to automate a weekly email blast listing that week’s events, using MailChimp.

The Events Calendar automatically generates an RSS feed of future events, inserting the event’s date and time in the RSS <pubDate> field. And MailChimp offers an RSS Campaign feature that can be scheduled to automatically send out emails with content pulled in from an RSS feed.

So far so good. But there were a few things the client wanted that were missing:

  1. Show exactly a week’s worth of events. The RSS feed just pulls in n events… whatever you have set in Settings > Reading > Syndication feeds show the most recent.
  2. Display the event’s featured image. Featured images aren’t included in WordPress RSS feeds, neither the default posts feed nor The Events Calendar’s modified feed.
  3. Show the event’s location. This is also not pulled into the RSS feed at all.

To make this happen, I had to first get the RSS feed to actually contain the right data. Then I had to modify the MailChimp campaign to display the information.

The problem in both cases surrounded documentation. RSS, though it’s still widely used, is definitely languishing if not dead. The spec is well-defined, but there’s not a lot of good information about how you can customize the WordPress RSS feed, and even less about how to customize The Event Calendar’s version. What info I could find was generally outdated or flat-out wrong — like the example in the official WordPress documentation (the old documentation, to be fair) that has at least three major errors in it. (I’m not even going to bother to explain them. Just trust that it’s wrong and you shouldn’t use it.)

Now that I’ve put in the hours of trial and error and futile Googling, I’ll save you the trouble and summarize my successful end result.

Problem 1: Show a week’s worth of events in the RSS feed

It took a surprising amount of effort to figure out how this is done, although in the end it’s a very small amount of code. Part of the problem was that I was not aware of the posts_per_rss query parameter, and therefore I wasted a lot of time trying to figure out why posts_per_page wasn’t working. Maybe that’s just my dumb mistake. I hope so.

I also spent a bunch of time trying to get a meta_query working before I realized that The Events Calendar adds an end_date query parameter which makes it super-easy to define a date-based endpoint for the query.

You need both of these. Depending on how full your calendar is, the default posts_per_rss value of 10 is possibly not enough to cover a full week. I decided to change it to 100. If this client ever has a week with more than 100 events in it, we’ll be in trouble… probably in more ways than one.

Here’s the modification you need. Put this in your functions.php file or wherever you feel is appropriate:

// Modify feed query
function my_rss_pre_get_posts($query) {
  if ($query->is_feed() && $query->tribe_is_event_query) {
    // Change number of posts retrieved on events feed
    $query->set('posts_per_rss', 100);
    // Add restriction to only show events within one week
    $query->set('end_date', date('Y-m-d H:i:s', mktime(23, 59, 59, date('n'), date('j') + 7, date('Y'))));
  return $query;

What’s happening here? The if conditional is critical, since pre_get_posts runs on… oh… every database query. This makes sure it’s only running on a query to retrieve the RSS feed and, specifically, The Events Calendar’s events query.

We’re changing posts_per_rss to an arbitrarily large value — the maximum number of events we can possibly anticipate having within the date range we’re about to set.

The change to end_date (it’s actually empty by default) sets a maximum event end date to retrieve. My mktime function call is setting the date to 11:59:59 pm on the date one week from the current date. You can just change the 7 to another number to set the query to that many days in the future. There are a lot of other fun manipulations you can make to mktime. Check out the official PHP documentation if you’re unfamiliar with it.

Every add_action() call can include priority as the third input parameter. Sometimes it doesn’t matter and you can leave it blank, but in this case it does matter. I’m not sure what the minimum value is that would work, but I found 99 does, so I stuck with that.

Problems 2 and 3: Add the featured image and event location to the RSS feed

RSS is XML, so it has a syntax similar to HTML, but with its own specific tags. (And with XML’s much stricter validation requirements.) WordPress uses RSS 2.0. This can get you into trouble later with the MailChimp integration, because MailChimp’s RSS Merge Tags documentation gives an example of the RSS 1.5 <media:content> tag for inserting images, but you’ll actually need to use the <enclosure> tag… which MailChimp also mentions, but not in conjunction with images. Still with me?

All right, so the first thing we’re going to need to modify in the RSS output is the images. And don’t believe that official WordPress documentation I mentioned earlier. It. Is. Wrong. My way works.

The next thing we want to do, and we’ll roll it into the same function (because I want to contain the madness), is to add in the event’s location. There’s no RSS tag to account for something like this. You could add it to the <description> tag, although I found that since the WordPress rss2_item hook seems to be directly outputting RSS XML as it goes, I didn’t track down a way to modify any of the output, just add to it.

There’s another standard RSS tag that WordPress doesn’t use — or at least doesn’t seem to use — the <source> tag. This is supposed to be used to provide a link and title of an external reference for the item, but I’m going to take the liberty of misusing it to pass along the location name instead. In my particular case I’m not using it as a link; I just need the text of the location name. But the url attribute is required, so I just stuck the event’s URL in there. (I also added a conditional so this is only inserted on events, not on other post types. But for images I figured it would be a nice bonus to add the featured image across all post types on the site. You may want to add your own conditionals to limit this.)

Here we go:

function my_rss_modify_item() {
  global $post;
  // Add featured image
  $uploads = wp_upload_dir();
  if (has_post_thumbnail($post->ID)) {
    $thumbnail = wp_get_attachment_image_src(get_post_thumbnail_id($post->ID), 'thumbnail');
    $image = $thumbnail[0];
    $ext = pathinfo($image, PATHINFO_EXTENSION);
    $mime = ($ext == 'jpg') ? 'image/jpeg' : 'image/' . $ext;
    $path = $uploads['basedir'] . substr($image, (strpos($image, '/uploads') + strlen('/uploads')));
    $size = filesize($path);
    echo '<enclosure url="' . esc_url($image) . '" length="' . intval($size) . '" type="' . esc_attr($mime) . '" />' . "\n";
  // Add event location (fudged into the <source> tag)
  if ($post->post_type == 'tribe_events') {
    if ($location = strip_tags(tribe_get_venue($post->ID))) {
      echo '<source url="' . get_permalink($post->ID) . '">' . $location . '</source>';

You might be able to find a more efficient way of obtaining the $path value… to be honest I was getting a bit fatigued by this point in the process! But it works. You really only need that value anyway in order to fill in the length attribute, and apparently that value doesn’t even need to be correct, it just needs to be there for the XML to validate. So maybe you can try leaving it out entirely.

Put it in MailChimp!

OK… I’m not going to tell you how to set up an RSS Campaign in MailChimp. I already linked to their docs. But I will tell you how to customize the template to include these nice new features you’ve added to your RSS feed.

Edit the campaign, and once you’re in the Campaign Builder, place an RSS Items block, then click on it to open the editor on the right side. Set the dropdown to Custom, which will reveal a WYSIWYG editor full of a bunch of special tags that dynamically insert RSS content into the layout. For the most part you can edit everything here… except for the image. You’re going to have to insert one of these tags into the src attribute of the HTML <img> tag. That requires going into the raw code view, which you can access by clicking the <> button in the WYSIWYG editor’s toolbar.

A few key tags:

This is your code for the URL of the image. Yes, it has to be put into the src attribute of the <img> tag directly. There’s not a way that I could find to get MailChimp to recognize an <enclosure> as being an image and display it inline.

This will display the location name, if you added it to the <source> tag.

*|RSSITEM:DATE:F j - g:i a|*
I just though I’d point this out: you can customize the way MailChimp shows an event date by inserting a colon and a standard PHP date format into the *|RSSITEM:DATE|* tag. Nice!

If you’re interested in a nice layout with the featured image left aligned and the event info next to it, here’s something you can work with. Paste this in its entirety into the WYSIWYG editor’s raw code view in place of whatever you have in there now. Yes, inline CSS… welcome to HTML email!

<div style="clear: both; padding-bottom: 1em;">
<img src="*|RSSITEM:ENCLOSURE_URL|*" style="display: block; float: left; padding-right: 1em; width: 100px; height: 100px;" />
<h2 class="mc-toc-title" style="text-align: left;"><a href="*|RSSITEM:URL|*" target="_blank">*|RSSITEM:TITLE|*</a></h2>

<div style="text-align: left;"><strong>*|RSSITEM:DATE:F j – g:i a|*</strong><br />

<div style="clear: both; content: ''; display: table;">&nbsp;</div>

Update! I have encapsulated this functionality, along with some configuration options, into a plugin. You can download it from the WordPress Plugin Directory.

Sneak peek at a new design

Sneak peekYes, it’s only been about 10 days since my last redesign, but I’m already at it again. I always knew that the current design was little more than a palate cleanser… or a rebound relationship.

Ultimately, what it came down to for me was that I just hadn’t put the kind of care and attention to detail into the design that I really want. With blogs it’s easy to put 99% of your design energy into the header, and then kind of just let the rest of it fall together in the default structure provided by the blog software. In other words, a long, undifferentiated stream of posts on the home page.

Well, I’m trying to give things more structure, as well as making the new design both more functional and more fun. And yes, I’m reusing every design trend from 2007. Is it too soon for the shiny floor effect to seem “retro”? Hopefully the sparkles convey an adequate level of irony. No, they won’t be animated.

Due to the level of attention I’m giving this design, I’m not going to be able to finish it in an evening like most of my past redesigns. But I’m too excited about it to hold back just a teaser (the screenshot detail shown here). Plus maybe this will keep the pressure on me to actually finish it.

Update: “Is this it?” Yes and no. I’ve gone ahead and rolled out the new look and feel with the old page structure. So it looks like the new site design, but it’s not. The changes that remain to be made are mostly on the home page, and involve significant modifications to the WordPress theme templates. It’s another level of tinkering under the hood than the superficial design changes I’ve rolled out up to this point. And I want to take the time to get it right. I’d also like to see if I can really implement Helvetica Neue Condensed Black as my headline font, without having to embed it. So, for now, it looks different but acts the same. More changes to come…

Don’t be fooled by all of that red territory

America does not vote by the square mile. The electoral college is fundamentally flawed, but it does at least approach an accurate representation of the will of the American populace, as much as the will of 305 million people can be evenly divided amongst 538 electoral votes.

As it stands, the vote is weighted slightly, and unfairly, in favor of states with small populations. I’ll spare you the civics lesson on how the number of votes per state is determined (if you don’t already know, shame on you, Sarah Palin), but suffice to say that each state has at least 3 electoral votes. The inequality here is best summed up in the comparison between Wyoming, our least populous state, and California, our most populous state. Wyoming’s 3 electoral votes reflect the will of its 522,380 residents at a rate of 1 vote per 174,127 people. California’s 55 electoral votes, in contrast, are divided amongst its 36,553,215 residents at a rate of 1 vote per 664,604 people. In other words, a person’s vote in Wyoming counts 3.8 times as much towards the electoral total as a person’s vote in California.

That’s unfair. But there it is. So in short, the will of the citizens of Wyoming is disproportionately represented by almost four times as much as that of the citizens of California, per person.

Nonetheless, it’s worth considering the mass of California’s 55 electoral votes when contemplating a speculative map such as the one below (from Yahoo’s Election Dashboard) — based on the likely outcome as determined by the “prediction markets” — a.k.a. the bookmakers who take bets on who will win the election. Of course, betting on the outcome of the presidential race by an American citizen is illegal. But that doesn’t keep residents of other countries from taking a sporting interest in the outcome. And, given bookmakers’ need for an accurate prediction of the outcome of any wager-worthy event like this, they’re probably more reliable than the latest polls, or even the kind of meta analysis we’re seeing out of FiveThiryEight.com.

As an Obama supporter, I often look at maps like this and am dismayed to see so much red. Geez, I think, Obama may end up squeaking by on this but just look at it — that’s a whole lotta McCain territory out there. But again, the land isn’t voting. The people are. It helps to pay attention to those little numbers on each state. I did a quick tally and found that large, snakelike swath of the west, consisting of Arizona, Utah, Idaho, Montana, Wyoming, North Dakota, South Dakota, Nebraska, Kansas, Oklahoma and Arkansas all together comprises 55 electoral votes. The same as California.

In fact, the only big red state is Texas, and the only other reasonably big state among them is Georgia. So McCain has two 15-or-more-electoral-votes states, compared with Obama’s nine (California, Illinois, Michigan, Ohio, Pennsylvania, New York, New Jersey, North Carolina and Florida), and Virginia and Massachusetts are also larger than any other McCain states.

So there you have it. Remember that land doesn’t vote — people do. And even if, thanks to the electoral college, people’s votes count relatively more if there’s more land between them, ultimately the proportion of voters favoring one candidate or another is not accurately indicated by the amount of red or blue space you see on the map, but by how big those little numbers on the map are.

Ben Affleck as Keith Olbermann

I like Keith Olbermann, but I can recognize how over-the-top he is. He’s not quite as unpleasantly antagonistic towards the right as Bill Maher, but he sometimes comes close.

Ben Affleck did a pretty good skewering of him last night on SNL, culminating in an absolutely brilliant “Special Comment” in defense of… “Miss Precious Perfect.” Watch…

Now, I just wish they’d post the Giraffes video by the Staten Island Technical High School A/V club.