Category Archives: wordpress

I’m so sorry!

I got caught up in IBM’s Innovation Jam, and I hadn’t realized that my blog was somewhat broken.

Oops.

I’ve disabled a great number of third-party things, including the Twitter Tools feed that made everything go haywire.

Which widgets would you like back?

Summarizing my WordPress posts using XSLT; 2008 as a PDF

It’s the time of the year for annual updates. I was thinking of reviewing all the blog posts I’d written this year. My weekly and monthly posts are incomplete, though, and I want to make sure I cover everything. I also know a few people who are slowly working their way through my archives. So I thought I’d export all of my posts from 2008 into something that people can read with fewer clicks.

If you want to skip past all the geek details, you can get the files here: 2008 blog (4.6 MB, 307 pages(!)), 2008 mostly nongeek entries (3.8 MB, 195 pages).

After some tinkering around with wptex and other modules that are supposed to make this easier, I gave up and decided to do it myself. I toyed with the idea of writing a short Ruby program that either parsed the XML or read the database, but I eventually ended up taking it as an excuse to learn XSLT, a language for transforming XML. WordPress can export posts and comments as XML. After I scrubbed my WordPress of spam and raised my PHP execution times, I downloaded the XML file and started figuring out how to get it into the form I wanted: a document organized by month, with a table of contents listing all the posts.

Here’s the main stylesheet I used:

 <xsl:stylesheet version="1.0"
                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 xmlns:content="http://purl.org/rss/1.0/modules/content/"
                 xmlns:wp="http://wordpress.org/export/1.0/">
   <xsl:output method="html"/>
   <xsl:template match="/">
     <html><body>
       <h0>January 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'Jan 2008') and wp:status='publish']"/>
       <h0>February 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'Feb 2008') and wp:status='publish']"/>
       <h0>March 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'Mar 2008') and wp:status='publish']"/>
       <h0>April 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'Apr 2008') and wp:status='publish']"/>
       <h0>May 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'May 2008') and wp:status='publish']"/>
       <h0>June 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'Jun 2008') and wp:status='publish']"/>
       <h0>July 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'Jul 2008') and wp:status='publish']"/>
       <h0>August 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'Aug 2008') and wp:status='publish']"/>
       <h0>September 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'Sep 2008') and wp:status='publish']"/>
       <h0>October 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'Oct 2008') and wp:status='publish']"/>
       <h0>November 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'Nov 2008') and wp:status='publish']"/>
       <h0>December 2008</h0>
       <xsl:apply-templates select="/rss/channel/item[contains(pubDate, 'Dec 2008') and wp:status='publish']"/>
   </body></html>
   </xsl:template>
   <xsl:template match="//item">
     <h1><a>
       <xsl:attribute name="href">
         <xsl:value-of select="link"/>
       </xsl:attribute>
       <xsl:value-of select="title"/></a></h1>
     <div class="link"><xsl:value-of select="link"/></div>
     <div class="date"><xsl:value-of select="pubDate"/></div>
     <div class="content">
       <xsl:value-of select="content:encoded" disable-output-escaping="yes" />
     </div>
   </xsl:template>
 </xsl:stylesheet>

For the non-geek version, I replaced the template with:

   <xsl:template match="//item">
     <xsl:if test="not(category[@nicename='emacs']) and not(category[@nicename='drupal']) and not(category[@nicename='geek'])">
     <h1><a>
       <xsl:attribute name="href">
         <xsl:value-of select="link"/>
       </xsl:attribute>
       <xsl:value-of select="title"/></a></h1>
     <div class="link"><xsl:value-of select="link"/></div>
     <div class="date"><xsl:value-of select="pubDate"/></div>
     <div class="content">
       <xsl:value-of select="content:encoded" disable-output-escaping="yes" />
     </div>
     </xsl:if>
   </xsl:template>

I didn’t want to figure out how to demote all the headings in my blog posts (I have a few), so I used <h0> as my root element. I used xsltproc to transform the XML file I got from WordPress. Then I adjusted all the headings with the following bit of Emacs Lisp:

 (defun sacha/demote-all-headings ()
  (interactive)
   (while (re-search-forward "</?h\\([1-7]\\)>" nil t)
    (replace-match (number-to-string (1+ (string-to-number (match-string 1)))) nil t nil 1)))

It’s all held together with bubblegum and string, really.

2008 blog (4.6 MB, 307 pages(!)), 2008 mostly nongeek entries (3.8 MB, 195 pages)

I haven’t looked at these files much yet – I just scrolled through them quickly. No, don’t worry, I’m not going to send my 2008 update as 307 pages in the mail. ;) But it’s there so that we can flip through it or you borrow the code, and someday I’ll even figure out how to format the output neatly and everything.

Next step: I need to read all of that and highlight a couple of things that made my year.

(307 pages! Wow.)

RSS footers

I’ve noticed an increasing number of automated spam blogs (splogs) that syndicate my blog posts, usually with a teensy bit of attribution and a whole bunch of ads.

I will always offer full feeds, not summaries, because summary-only blogs drive me crazy. =)

So I thought I’d use the RSS Footer plugin to add a little context to my feed. If this is driving you crazy (too much text!) or if you want to suggest a change to the footer message, please leave a comment. Thanks! =)

Thinking about Planner/EmacsWiki versus WordPress

Was it really only less than two years ago that I shifted from my venerable Planner-based wiki/blog to my WordPress-powered one after experimenting with syndicating my entries into WordPress?

I miss writing in wiki markup on Emacs and knowing that publishing would Just Work. I miss being able to dynamically expand entries from my address book in a way that automatically links to people’s blogs. (Or Twitter accounts, if I were going to do this now.) ScribeFire is a pain on my Eee (needs more horizontal screen space), and I have a hard time marking up the occasional bit of HTML in weblogger.el. Windows Live Writer is pretty slick (particularly with the SnagIt Screen Capture plugin and the Amazon Book Linker), but I can live without it. Or maybe I can resurrect that WordPress Emacs client Ashish mentioned.

Let me think about the differences in experiences.

  • I wanted to support comments, but I didn’t want to spend a lot of time hacking on some custom commenting system. This was a big issue for me. I found some commenting scripts, but dealing with spam was a pain, so I switched to WordPress. If I switched back to Emacs for my blog, I’d probably use something like Disqus to handle the conversation, and just find some way of backing up the comments regularly.
  • I wanted to make it easy to navigate posts. I modified Planner to generate a more browsable blog index, but it’s still not as slick as what you’d see with WordPress. On this WordPress blog, I like offering people random blog posts (good for me too – great way to rediscover old posts and make serendipitous connections!), related posts, and posts on the same day. I can do posts on the same day in Planner with a custom hook, but the others would require some hacking. Also, Planner is very much day-based, while WordPress lists N posts per page and has good category lists.
  • I wanted to make it easy to edit posts. In my Emacs-based system, I published to RSS when I saved a note in the Remember window. I had a hack that made it possible to propagate changes from an already-published post to my WordPress blog, but it wasn’t completely reliable.
  • Scheduling posts is handy, too. I hadn’t gotten around to figuring out how to build a post scheduler for Emacs. I suppose if I wasn’t picky about the time it went out, I could simply write posts on different days and then publish notes conditionally, plus have some kind of hook to notice if any of the current page’s posts should be published in the RSS feed, plus some way to handle previous days, plus maybe a server-friendly way to do this for the times when I’m not going to be online every day. Right.

That said, I miss automatically sharing some details of what I’m working on (with details deleted before publishing so that they’re available offline), publicly crossing off tasks, and other cool things.

Planner’s model for task planning isn’t quite compatible with Org’s model, and I’ve been using Org + Toodledo more these days.

What am I really looking for here?

  • A quick, reliable way to post from a text editor, so that I can do it from the Eee. Hmm, the WP Postie plugin will probably do the trick.
  • Easy way to share/review tasks: Toodledo export of week’s tasks?
  • And maybe a custom plugin for weekly displays, org agendas, that sort of thing.

Hmm….

WordPress: Older posts, newer posts

I always get confused by “Previous page” and “Next page” on WordPress blogs. After only a little struggling, I finally got my navigation sorted out so that you can page through it using “Older posts” and “Newer posts”.

I added the following to my style.css:


.navigation { font-weight: bold; font-size: larger }
.navigation .right { float: right }
.navigation .left { float: left }

Then I added this to my theme’s index.php:

<div class="navigation">
  <div class="left">
    <?php next_posts_link('&laquo; Older posts'); ?>
  </div><div class="right">
    <?php previous_posts_link('Newer posts &raquo;'); ?>
  </div>
</div>

Result: yay!

image

WordPress tweak: Proper navigation for date.php

I can’t be the only person who’s ever wanted proper navigation on WordPress date.php archive pages. By this, I mean that if you’re browsing, say, http://sachachua.com/wp/2009 and you’re on the first page, there should be a way for you to get to 2008.

So I spent a couple of hours hacking that in. This even skips non-existent years/months/days. Tweak and enjoy.

Minor notes: It jumps to the first page of the other year/month/day, so the results aren’t strictly chronological. Going to 2008 from 2009 will show you the blog posts from January 1 instead of the last posts of 2008. Since I display a huge list of posts and I only use one page, that’s fine with me.

<?php
  $y = mysql2date('Y', $wp_query->posts[0]->post_date);
  $m = mysql2date('m', $wp_query->posts[0]->post_date);
  $d = mysql2date('d', $wp_query->posts[0]->post_date);
  $display = mktime(0, 0, 0, $m, $d, $y);
  if (is_year()) {
    $format = 'Y';
    $prev_display = mktime(23, 59, 59, 12, 31, $y - 1);
    $next_display = mktime(0, 0, 0, 1, 1, $y + 1);
    $url_format = 'Y';
  } elseif (is_month()) {
    $prev_display = mktime(23, 59, 59, $m, 0, $y);
    $next_display = mktime(0, 0, 0, $m + 1, 1, $y);
    $format = 'F Y';
    $url_format = 'Y/n';
  } elseif (is_day()) {
    $prev_display = mktime(23, 59, 59, $m, $d - 1, $y);
    $next_display = mktime(0, 0, 0, $m, $d + 1, $y);
    $format = 'F j, Y';
    $url_format = 'Y/n/j';
  }
  $paged = get_query_var('paged');
  if ($paged < 2) { // No previous pages; navigate by date instead
    $past = $wpdb->get_row("SELECT UNIX_TIMESTAMP(MAX(post_date)) AS post_date
FROM $tableposts WHERE post_date <= FROM_UNIXTIME($prev_display) AND post_status='publish'");
    if ($past->post_date) {
      $prev_text = '&laquo; ' . date($format, $past->post_date);
      $prev_link = get_bloginfo('url') . '/'
        . date($url_format, $past->post_date);
    }
  }
  if ($paged >= $wp_query->max_num_pages) { // No next pages
    $future = $wpdb->get_row("SELECT UNIX_TIMESTAMP(MIN(post_date)) AS post_date
FROM $tableposts WHERE post_date >= FROM_UNIXTIME($next_display) AND post_status='publish'");
    if ($future->post_date) {
      $next_text = date($format, $future->post_date) . ' &raquo;';
      $next_link = get_bloginfo('url') . '/'
        . date($url_format, $future->post_date);
    }
  }
  $title = date($format, $display);
  ?>
  <div class="navigation">
    <div class="left">
      <?php if ($prev_text) { ?>
        <a href="<?php print $prev_link ?>"><?php print $prev_text ?></a>
      <?php } else { ?>
        <?php previous_posts_link('&laquo; Older posts'); ?>
      <?php } ?>
    </div>
    <div class="right">
      <?php if ($next_text) { ?>
        <a href="<?php print $next_link ?>"><?php print $next_text ?></a>
      <?php } else { ?>
        <?php next_posts_link('Newer posts &raquo;'); ?>
      <?php } ?>
    </div>
    <div style="clear: both"></div>
  </div>
  <h1><?php print $title ?></h1>