So here’s something odd that I’ve just discovered over the past couple days.

(TL;DR: A WordPress plugin had a bug in the code. I successfully debugged it, just to realize that the author had done the same (in a different way) a few days ago. But I still get to feel good about what I did! Plus, I made another small change.)

Since my blog turns 20 in November of this year, I’m running daily “on this day” posts that include a list of all posts made on that date in previous years. To do this, I’ve installed the posted today plugin, and I pre-schedule the posts with a template that includes the correct shortcode (this is the body text for the Jan 2 post, using curly brackets instead of straight to avoid triggering the shortcode):

Since I'll hit 20 years of blogging this November, this year I'm posting a daily list of anything I published on this day in the past. Here are my past posts for January 2…

{postedtoday month="1" day="2"}

The posts have been showing up on my blog just fine (Jan. 1, Jan. 2)…but I noticed that they weren’t showing up in my feed in NetNewsWire, nor were they getting captured by IFTTT and pushed through to my Twitter feed, though they were showing up in my micro.blog feed (which only parses titles and links, not body content).

I verified that the post information existed in my site’s RSS feed, and included the full text of the post with all past posts from the proper date rather than just the text as shown above (so the shortcode was being processed as the RSS feed was generated). Here’s a somewhat redacted (to include only one past post entry) version of the item entry for the Jan 2 post:

        <item>
    <title>On This Day: Jan 2</title>
    <link>http://michaelhans.com/eclecticism/2020/01/02/on-this-day-jan-2/</link>
            <comments>http://michaelhans.com/eclecticism/2020/01/02/on-this-day-jan-2/#respond</comments>
            <pubDate>Thu, 02 Jan 2020 16:00:47 +0000</pubDate>
    <dc:creator><![CDATA[Michael Hanscom]]></dc:creator>
            <category><![CDATA[blog]]></category>

    <guid isPermaLink="false">http://michaelhans.com/eclecticism/?p=16448</guid>
            <description><![CDATA[Recognizing 20 years of blogging, here are my past posts from January 2]]></description>
                            <content:encoded><![CDATA[Since I&#8217;ll hit 20 years of blogging this November, this year I&#8217;m posting a daily list of anything I published on this day in the past. Here are my past posts for January 2…
<p>There are <strong> </strong> posts previously published on January 2nd</p><ul class="todaypost"><li><strong>2019</strong><ul><li><a href="http://michaelhans.com/eclecticism/2019/01/02/12723/"></a> <span class="today_excerpt">“Sen. Romney&#8217;s statement is not a profile in courage. Rather it is another example of the emptiness of the #nevertrump movement &#8212; all talk and no action.”</span> (<a href="http://michaelhans.com/eclecticism/2019/01/02/12723/">&#x27A1;</a>)</li></ul></li></ul>
]]></content:encoded>
                        <wfw:commentRss>http://michaelhans.com/eclecticism/2020/01/02/on-this-day-jan-2/feed/</wfw:commentRss>
    <slash:comments>0</slash:comments>
                        </item>

I had a guess as to what was going on, but wasn’t sure…yet.

I’d noticed earlier that the “There are X posts previously published on [DATE]” line that Posted Today includes wasn’t working properly, and was omitting the number that’s supposed to be where the X is, so the line just read, “There are  posts previously published on [DATE]”. I hadn’t worried too much about that just yet, filing it away into the “figure out later” bucket.

However, when looking at the XML data for my RSS feed, I noticed that there appeared to be a garbage character at that point in the data:

Screen shot of XML data

This made me think that there was something in the plugin that wasn’t working properly, and the garbage character may have been choking the RSS parsers that NetNewsWire and Twitter use, so they ended up discarding those items.

I took a look at the PHP code for the plugin to see if this was something I could tweak myself, and the answer seemed to be…kind of.

Here’s the plugin code that generated that line:

    // get the grammar right for a result of 1
    $singular = sprintf(
        _x('There is <strong>1</strong> post previously published on %s', 'Single post found', 'postedtoday'),
        $the_date
    );
    $multiple = sprintf(
        _x('There are <strong>%c</strong> posts previously published on %s', 'Multiple posts found', 'postedtoday'),
        $posts_from_today->found_posts,
        $the_date
    );

I don’t really know PHP, but it was pretty obvious that the %c argument should be replaced by the integer for however many posts Posted Today found to display, but for some reason, was instead outputting a garbage character.

I figured I’d just tweak that line to not output a post count, and changed the code to this:

    // get the grammar right for a result of 1
    $singular = sprintf(
        _x('There is <strong>1</strong> post previously published on %s', 'Single post found', 'postedtoday'),
        $the_date
    );
    $multiple = sprintf(
        _x('These are all the posts previously published on %s', 'Multiple posts found', 'postedtoday'),
        $posts_from_today->found_posts,
        $the_date
    );

Unfortunately, while that fixed that error, it then resulted in the %s argument outputting an integer instead of a date; instead of the expected “These are all the posts previously published on January 2nd”, I got, “These are all the posts published on 27”. Well, that wasn’t right…however, the “27” was the correct number of past posts for Jan. 2, and was what should have been showing up instead of the garbage character. Which got me thinking…

As it turned out, according to the PHP manual, the %c argument “is treated as an integer and presented as the character with that ASCII” — and ASCII 27 is the ‘escape’ character! So the plugin was checking to see how many posts were made, coming up with 27, and dropping the number in the right place–but was using the incorrect argument for PHP’s sprintf function, so that instead of outputting the integer, it was outputting an escape character. Similarly, for my Jan. 1 entry, it came up with 26 posts, and ASCII 26 is the ‘substitute’ character, so that also acted as a garbage character in the XML RSS feed.

With that in mind, I tweaked the code to be this:

    // get the grammar right for a result of 1
    $singular = sprintf(
        _x('There is <strong>1</strong> post previously published on %s', 'Single post found', 'postedtoday'),
        $the_date
    );
    $multiple = sprintf(
        _x('There are <strong>%s</strong> posts previously published on %s', 'Multiple posts found', 'postedtoday'),
        $posts_from_today->found_posts,
        $the_date
    );

And just like magic, it worked!

Well, at least, I now get the correct phrase in my post: “There are 27 posts previously published on January 2nd”. I’ll find out the next time NetNewsWire refreshes as to whether this fixes my RSS feed so that those posts aren’t mysteriously disappearing. Fingers crossed!

Update: The mysteriously missing posts have appeared in my feed in NetNewsWire. Success!


And then, after going through all this and writing it up, I realized that the plugin’s author had updated the plugin to correct for this error three days ago, and all I really needed to do was upload the latest version of the plugin. So I’m amused, but I also get to feel accomplished for successfully debugging and solving the problem, so yay!

Plus, I’ve made one other tweak to the plugin, so that it adds a link to the end of the excerpt to better handle “microblog” style entries that don’t have titles, so I still get to feel good about that part, as well. :) My coding skills may be underdeveloped and rusty from lack of regular use, but they’re not entirely atrophied!

Here’s the change I made to accomplish that:

Original code:

        // display excerpt if we want it
        if ( $excerpt ) $output .= ' <span class="today_excerpt">' . get_the_excerpt() .   '</span>';

        $output .= '</li>';

My code:

        // display excerpt if we want it
        if ( $excerpt ) $output .= ' <span class="today_excerpt">' . get_the_excerpt() .   '</span>';

        $output .= ' (<a href="' . get_permalink() . '">&#x27A1;</a>)</li>';

Mischief managed!

Sometime between April 27th and May 17th, I thought this stuff was interesting. You might think so too!

  • The Case of the Stolen Source Code: Last week, for about three days, the macOS video transcoding app HandBrake was compromised. One of the two download servers for HandBrake was serving up a special malware-infested version of the app, that, when launched, would essentially give hackers remote control of your computer. // In a case of extraordinarily bad luck, even for a guy that has a lot of bad computer luck, I happened to download HandBrake in that three day window, and my work Mac got pwned. // Long story short, somebody, somewhere, now has quite a bit of source code to several of our apps.
  • JSON Feed: Announcing JSON Feed: We — Manton Reece and Brent Simmons — have noticed that JSON has become the developers’ choice for APIs, and that developers will often go out of their way to avoid XML. JSON is simpler to read and write, and it’s less prone to bugs. So we developed JSON Feed, a format similar to RSS and Atom but in JSON. It reflects the lessons learned from our years of work reading and publishing feeds.
  • Let’s discuss the Linguistic & Pragmatic use of the [“N-word”]: No matter what your intentions, the word WILL mean something different depending on your relative status. Language is circumstancial.
  • The neural network writes the episode list for next season’s Dr. Who: I’ve trained this open-source neural network framework on a variety of datasets, including recipes, Pokemon, knock-knock jokes, pick up lines, and D&D spells. Now I give you: training a neural network on the complete list of Dr. Who episodes.
  • What we really need is an adaptation of the original 1740 The Beauty and the Beast: So were you aware that the The Beauty and the Beast story we all know is a heavily abridged and rewritten version of a much longer novella by Gabrielle-Suzanne Barbot de Villeneuve?  And that a lot of the plot holes existing in the current versions exist because the 1756 rewrite cut out the second half of the novella, which consisted entirely of the elaborate backstory that explains all the weird shit that happened before?  And that the elaborate backstory is presented in a way that’s kind of boring because the novel had only just been invented in 1740 and no one knew how they worked yet, but contains a bazillion awesome ideas that beg for a modern retelling?  And that you are probably not aware that the modern world needs this story like air but the modern world absolutely needs this story like air?

Just a quick little tip for OS X users. Nothing fancy, and others may have figured this out already, but a quick Google search didn’t come up with answers, just questions…so here we are.

For the uninitiated, one of the default screensavers in OS X is the RSS Visualizer, which shows a slick ‘floating text’ presentation of the text from any RSS feed against a cloudy blue background.

I wanted to put my Twitter timeline in, so that even when my ‘puter’s not doing anything, and I’m across the room reading on the couch, I can keep an eye out for updates. Seems simple, but on first blush, it didn’t seem to work, as I just got the background, and no tweets.

That’s an easy fix, though. Twitter password protects your RSS feed, so that other people can’t ‘hack’ into your feed and see updates from those of your contacts who have protected their feed from public view — and the screensaver options don’t give a way to enter your Twitter username/password combination.

Twitter does, however, respect RSS-embedded passwords. So, in order to get the screensaver to work correctly, change the RSS feed from the default

http://twitter.com/statuses/friends_timeline.rss

to a customized

https://USERNAME:PASSWORD@twitter.com/statuses/friends_timeline.rss

format, and you’re off and running.

Note that I’ve changed the protocol from http to https to avoid transmiting my Twitter username and password in cleartext. With the standard http protocol, in theory, if someone was really determined, there’s a chance that they could intercept the TCP stream between your computer and Twitter and see your Twitter login credentials. Using https (the ‘s’ stands for ‘secure’), the information between your computer and Twitter is encrypted, so that packet sniffers wouldn’t get anything.

And that’s it! One Twitter-enabled RSS screensaver.

I have no idea if anyone other than myself is currently subscribing to my ‘comments only’ RSS feed, but I’ve noticed an odd issue with it that I haven’t been able to troubleshoot yet. I’ve asked for help on the TypePad User Group, but I wanted to mention it here too, in case anyone else has been noticing this or might be able to point out what I’m doing wrong.

What I’ve been finding is that each item in my comment-only feed is being given the date of the original post that the comment is appended to, rather than the date that the comment was added to my site. For instance, a comment added today to a post from August shows up in my newsreader with the August date instead of today’s.

Here’s the code I’m using for each item in the RSS feed template (the full template code can be found in this post from last week):

<MTComments lastn="20">
<MTCommentEntry> 
<item> 
<title><$MTEntryTitle remove_html="1" encode_xml="1"$></title> 
<link><$MTEntryPermalink encode_xml="1"$>#c<$MTCommentID$></link> 
<description><$MTCommentBody remove_html="1" encode_xml="1"$></description> 
<guid isPermaLink="false"><$MTCommentID$>@<$MTBlogURL$></guid> 
<content:encoded><![CDATA[<MTCommentAuthorLink show_email="0"> on 
<MTCommentDate format="%b %e, %Y %l:%M %p">: <$MTCommentBody$>]]></content:encoded> 
<dc:date><$MTCommentDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></dc:date> 
</item>
</MTCommentEntry>
</MTComments>

Now, it all looks right to me, and the same basic code seems to be working in all the rest of my templates (for instance, in the ‘full posts plus comments’ RSS feed, each comment begins with a header that lists the correct date). For some reason, though, it’s not working here.

Any ideas?

Update: The issue has been fixed. Turns out that you can’t use an <MTCommentDate> tag inside an <MTCommentEntry> container (much thanks to Jamie Jamison for pointing me to the explanation).

The solution was fairly easy (and the code in my ‘how-to’ post has been updated): I just removed the date display from the body of the RSS item, and moved the closing <MTCommentEntry> tag up a couple lines. Here’s the new version of the above code:

<MTComments lastn="20">
<item> 
<MTCommentEntry> 
<title><$MTEntryTitle remove_html="1" encode_xml="1"$></title> 
<link><$MTEntryPermalink encode_xml="1"$>#c<$MTCommentID$></link> 
<description><$MTCommentBody remove_html="1" encode_xml="1"$></description> 
<guid isPermaLink="false"><$MTCommentID$>@<$MTBlogURL$></guid> 
<content:encoded><![CDATA[<MTCommentAuthorLink show_email="0">: <$MTCommentBody$>]]></content:encoded>
</MTCommentEntry>
<dc:date><$MTCommentDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></dc:date> 
</item>
</MTComments>

I just had someone ask how I was able to create the four RSS feeds for my site. Here’s a quick rundown, along with the templates themselves, should anyone else want to do the same thing. All the templates are RSS 2.0, and have been checked with the RSS Feed Validator.

TypePad users will need a Pro account, and will also need to be using an Advanced Template set, as you’ll need to create a new template for each RSS feed you want to add. I give each template a name that’s fairly indicative of which feed it is for, and I make sure that the output file is also named similarly.

Here are the templates I use:

####Default feed: Full text, no comments####

Template Name: RSS 2.0 Full
Output File: index.rdf

<?xml version="1.0" encoding="iso-8859-1"?> <rss version="2.0"      xmlns:dc="http://purl.org/dc/elements/1.1/"     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"     xmlns:admin="http://webns.net/mvcb/"     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"     xmlns:content="http://purl.org/rss/1.0/modules/content/"> 

<channel> 
<title><$MTBlogName remove_html="1" encode_xml="1"$></title> 
<link><$MTBlogURL$></link> 
<description><$MTBlogDescription remove_html="1" encode_xml="1"$></description> 
<dc:language>en-us</dc:language> 
<dc:creator><MTEntries lastn="1"><$MTEntryAuthorEmail$></MTEntries></dc:creator> 
<dc:rights>Copyright <$MTDate format="%Y"></dc:rights> 
<dc:date><MTEntries lastn="1"><$MTEntryDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></MTEntries></dc:date> 
<admin:generatorAgent rdf:resource="http://www.movabletype.org/?v=<$MTVersion$>" /> 
<admin:errorReportsTo rdf:resource="mailto:<MTEntries lastn="1"><$MTEntryAuthorEmail$></MTEntries>"/> 
<sy:updatePeriod>hourly</sy:updatePeriod> 
<sy:updateFrequency>1</sy:updateFrequency> 
<sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase> 

<MTEntries lastn="15"> 
<item> 
<title><$MTEntryTitle remove_html="1" encode_xml="1"$></title> 
<link><$MTEntryLink encode_xml="1"$></link> 
<description><$MTEntryExcerpt remove_html="1" encode_xml="1"$></description> 
<guid isPermaLink="false"><$MTEntryID$>@<$MTBlogURL$></guid> 
<content:encoded><![CDATA[<$MTEntryBody$><MTEntryIfExtended><p><a href="<$MTEntryLink$>" title="Continue Reading: <$MTEntryTitle$>">Continue reading <$MTEntryTitle$>...</a></p></MTEntryIfExtended>]]></content:encoded> 
<dc:subject><MTEntryCategories glue=" | "><$MTCategoryLabel remove_html="1" encode_xml="1"$></MTEntryCategories></dc:subject> 
<dc:date><$MTEntryDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></dc:date> 
</item> 
</MTEntries> 

</channel> 
</rss> 

####Enhanced Feed: Full posts with comments####

Template Name: RSS 2.0 full plus comments
Output File: fullposts.rdf

<?xml version="1.0" encoding="iso-8859-1"?> <rss version="2.0"      xmlns:dc="http://purl.org/dc/elements/1.1/"     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"     xmlns:admin="http://webns.net/mvcb/"     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"     xmlns:content="http://purl.org/rss/1.0/modules/content/"> 

<channel> 
<title><$MTBlogName remove_html="1" encode_xml="1"$>: With Comments</title> 
<link><$MTBlogURL$></link> 
<description><$MTBlogDescription remove_html="1" encode_xml="1"$></description> 
<dc:language>en-us</dc:language> 
<dc:creator><MTEntries lastn="1"><$MTEntryAuthorEmail$></MTEntries></dc:creator> 
<dc:rights>Copyright <$MTDate format="%Y"></dc:rights> 
<dc:date><MTEntries lastn="1"><$MTEntryDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></MTEntries></dc:date> 
<admin:generatorAgent rdf:resource="http://www.movabletype.org/?v=<$MTVersion$>" /> 
<admin:errorReportsTo rdf:resource="mailto:<MTEntries lastn="1"><$MTEntryAuthorEmail$></MTEntries>"/> 
<sy:updatePeriod>hourly</sy:updatePeriod> 
<sy:updateFrequency>1</sy:updateFrequency> 
<sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase> 

<MTEntries lastn="15"> 
<item> 
<title><$MTEntryTitle remove_html="1" encode_xml="1"$></title> 
<link><$MTEntryLink encode_xml="1"$></link> 
<description><$MTEntryExcerpt remove_html="1" encode_xml="1"$></description> 
<guid isPermaLink="false"><$MTEntryID$>@<$MTBlogURL$></guid> 
<content:encoded><![CDATA[<$MTEntryBody$><MTEntryIfExtended><p><a href="<$MTEntryLink$>" title="Continue Reading: <$MTEntryTitle$>">Continue reading <$MTEntryTitle$>...</a></p></MTEntryIfExtended><MTEntryIfAllowComments><p>Comments on this Entry:</p><MTComments><h4><MTCommentAuthorLink show_email="0"> on 
<MTCommentDate format="%b %e, %Y %l:%M %p">:</h4><MTCommentBody></MTComments></MTEntryIfAllowComments>]]></content:encoded> 
<dc:subject><MTEntryCategories glue=" | "><$MTCategoryLabel remove_html="1" encode_xml="1"$></MTEntryCategories></dc:subject> 
<dc:date><$MTEntryDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></dc:date> 
</item> 
</MTEntries> 

</channel> 
</rss> 

####Short Feed: Excerpts Only####

Template Name: RSS 2.0 Excerpts
Output File: excerpts.rdf

<?xml version="1.0" encoding="iso-8859-1"?> <rss version="2.0"      xmlns:dc="http://purl.org/dc/elements/1.1/"     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"     xmlns:admin="http://webns.net/mvcb/"     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"     xmlns:content="http://purl.org/rss/1.0/modules/content/"> 

<channel> 
<title><$MTBlogName remove_html="1" encode_xml="1"$>: Excerpts</title> 
<link><$MTBlogURL$></link> 
<description><$MTBlogDescription remove_html="1" encode_xml="1"$></description> 
<dc:language>en-us</dc:language> 
<dc:creator><MTEntries lastn="1"><$MTEntryAuthorEmail$></MTEntries></dc:creator> 
<dc:rights>Copyright <$MTDate format="%Y"></dc:rights> 
<dc:date><MTEntries lastn="1"><$MTEntryDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></MTEntries></dc:date> 
<admin:generatorAgent rdf:resource="http://www.movabletype.org/?v=<$MTVersion$>" /> 
<admin:errorReportsTo rdf:resource="mailto:<MTEntries lastn="1"><$MTEntryAuthorEmail$></MTEntries>"/> 
<sy:updatePeriod>hourly</sy:updatePeriod> 
<sy:updateFrequency>1</sy:updateFrequency> 
<sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase> 

<MTEntries lastn="15"> 
<item> 
<title><$MTEntryTitle remove_html="1" encode_xml="1"$></title> 
<link><$MTEntryLink encode_xml="1"$></link> 
<description><$MTEntryExcerpt remove_html="1" encode_xml="1"$></description> 
<guid isPermaLink="false"><$MTEntryID$>@<$MTBlogURL$></guid> 
<content:encoded><![CDATA[<$MTEntryExcerpt$>]]></content:encoded> 
<dc:subject><MTEntryCategories glue=" | "><$MTCategoryLabel remove_html="1" encode_xml="1"$></MTEntryCategories></dc:subject> 
<dc:date><$MTEntryDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></dc:date> 
</item> 
</MTEntries> 

</channel> 
</rss> 

####Comments only feed####

Template Name: RSS 2.0 Comments
Output File: comments.rdf

Update: The code here has been slightly altered since the original posting to account for an issue with incorrect dates.

<?xml version="1.0" encoding="iso-8859-1"?> <rss version="2.0"      xmlns:dc="http://purl.org/dc/elements/1.1/"     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"     xmlns:admin="http://webns.net/mvcb/"     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"     xmlns:content="http://purl.org/rss/1.0/modules/content/"> 

<channel> 
<title><$MTBlogName remove_html="1" encode_xml="1"$>: Comments</title> 
<link><$MTBlogURL$></link> 
<description><$MTBlogDescription remove_html="1" encode_xml="1"$></description> 
<dc:language>en-us</dc:language> 
<dc:creator><MTEntries lastn="1"><$MTEntryAuthorEmail$></MTEntries></dc:creator> 
<dc:rights>Copyright <$MTDate format="%Y"></dc:rights> 
<dc:date><MTEntries lastn="1"><$MTEntryDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></MTEntries></dc:date> 
<admin:generatorAgent rdf:resource="http://www.movabletype.org/?v=<$MTVersion$>" /> 
<admin:errorReportsTo rdf:resource="mailto:<MTEntries lastn="1"><$MTEntryAuthorEmail$></MTEntries>"/> 
<sy:updatePeriod>hourly</sy:updatePeriod> 
<sy:updateFrequency>1</sy:updateFrequency> 
<sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase> 

<MTComments lastn="20">
<item> 
<MTCommentEntry> 
<title><$MTEntryTitle remove_html="1" encode_xml="1"$></title> 
<link><$MTEntryPermalink encode_xml="1"$>#c<$MTCommentID$></link> 
<description><$MTCommentBody remove_html="1" encode_xml="1"$></description> 
<guid isPermaLink="false"><$MTCommentID$>@<$MTBlogURL$></guid> 
<content:encoded><![CDATA[<MTCommentAuthorLink show_email="0">: <$MTCommentBody$>]]></content:encoded> 
</MTCommentEntry>
<dc:date><$MTCommentDate format="%Y-%m-%dT%H:%M:%S"$><$MTBlogTimezone$></dc:date> 
</item>
</MTComments> 

</channel> 
</rss>