<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>BigSmoke &#187; Ruby</title>
	<atom:link href="http://blog.bigsmoke.us/tag/ruby/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.bigsmoke.us</link>
	<description>Smokes your problems, coughs fresh air.</description>
	<lastBuildDate>Sat, 04 Feb 2012 18:03:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Ytec, WordPress and Aihato.nl</title>
		<link>http://blog.bigsmoke.us/2010/11/09/www.aihato.nl</link>
		<comments>http://blog.bigsmoke.us/2010/11/09/www.aihato.nl#comments</comments>
		<pubDate>Tue, 09 Nov 2010 15:29:26 +0000</pubDate>
		<dc:creator>Rowan Rodrik</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Aihato]]></category>
		<category><![CDATA[ContentFlow]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[FancyBox]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Make]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[XML-RPC]]></category>

		<guid isPermaLink="false">http://blog.bigsmoke.us/?p=1632</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p>On Oktober, the 25th, in what will be known to future generations as a historical move, Wiebe changed the A record of <a href="http://www.aihato.nl/">www.aihato.nl</a> to point to the new production site running at Ytec. The new site, a collaboration by <a href="http://www.ytec.nl/">Ytec</a> and <a href="http://www.bigsmoke.us/">me</a>, based on WordPress, has been in development since May. At least, that&#8217;s when I started <a href="http://blog.bigsmoke.us/2010/05/04/aihato-wordpress-dev-notes">taking notes</a>. There had been some discussion, wire-framing and design done before that time.</p>

<p>The graphical design for the new Aihato website was created in Photoshop by a Ytec employee, building on a wire-frame created by Ying Hao (good friend and owner of Ytec). Another Ytec employee freed me of the burden of slicing the design into HTML/CSS, so that I could concentrate on the WordPress programming work involved. I liked not having to worry too much about design for once.</p>

<div id="attachment_1652" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/comfortably-installed-at-ytec1.jpg"><img src="http://blog.bigsmoke.us/uploads/2010/11/comfortably-installed-at-ytec1-300x225.jpg" alt="Comfortably Installed at Ytec" title="Comfortably Installed at Ytec" width="300" height="225" class="size-medium wp-image-1652" /></a><p class="wp-caption-text">Comfortably Installed at Ytec</p></div>

<h2>Initial development setup</h2>

<p>Because I had decided to put WordPress in its <a href="http://blog.bigsmoke.us/2009/01/30/separating-wordpress-factory-files-from-custom-files">own subdirectory</a> to keep my custom stuff separate from the factory default stuff, I needed my own vhost at Ytec, something I had gotten used to with all my previous web development projects. Initially, I tried to make things work in my own ~subdirectory on a shared vhost, but this wreaked havoc with the rewrite voodoo that I needed to make WordPress live comfortably in its own subdir. Maybe, it would have been better to use <a href="http://blog.bigsmoke.us/2009/09/20/svn-vendor-branches-wordpress">vendor branches</a>; but decisions, decisions&#8230;</p>

<h2 id="makefile">A Makefile for deployment, sychronisation and backups</h2>

<p>On many of my recent projects, I&#8217;ve used Rake instead of GNU Make. This time, I took it oldschool to pimp up my Make skills a bit. This proved pretty necessary, because I&#8217;ve spent ages on a bug in a previous version of the Makefile were I defined a variable after a make target without realizing that I had to put this in a separate rule from the instructions to make that target.</p>

<p>Why I even need a Makefile? Because when you&#8217;ve had your fair share of deployment, synchronisation and backup problems, you like to define rules to avoid these problems. Makefiles are ideal for that purpose, because they consist of <em>rules</em>.</p>

<p>I&#8217;m publishing the Makefile here because it&#8217;s one of the prettier Makefiles I&#8217;ve made and I like to brag and remember myself of some of the new things that I learned during its creation.</p>

<pre class="php">RSYNC_OPTIONS := --verbose --progress --recursive --delete --links --times --filter=<span style="color: #ff0000;">'merge ./rsync-upload-filters'</span>
WORKING_COPY_ROOT := $<span style="color: #66cc66;">&#123;</span>HOME<span style="color: #66cc66;">&#125;</span>/www.aihato.nl/
LIVE_PRODUCTION_ROOT := ytec.nl:/too/much/info/aihato.nl/
LIVE_DEVELOPMENT_ROOT := ytec.nl:/too/much/info/aihato-dev/
MYSQL_LOGIN := --user=aihato --password=InYourDreamsIdForgetToChangeThis
&nbsp;
&nbsp;
deploy-production:
    <span style="color: #808080; font-style: italic;"># First, I sync everything except the symlink to the current WP version</span>
    rsync $<span style="color: #66cc66;">&#40;</span>RSYNC_OPTIONS<span style="color: #66cc66;">&#41;</span> --filter=<span style="color: #ff0000;">&quot;exclude /wp&quot;</span>  $<span style="color: #66cc66;">&#40;</span>WORKING_COPY_ROOT<span style="color: #66cc66;">&#41;</span> $<span style="color: #66cc66;">&#40;</span>LIVE_PRODUCTION_ROOT<span style="color: #66cc66;">&#41;</span>
    <span style="color: #808080; font-style: italic;"># Now, if the symlink's target has changed, we've atomically upgraded all WP files</span>
    rsync $<span style="color: #66cc66;">&#40;</span>RSYNC_OPTIONS<span style="color: #66cc66;">&#41;</span> $<span style="color: #66cc66;">&#40;</span>WORKING_COPY_ROOT<span style="color: #66cc66;">&#41;</span> $<span style="color: #66cc66;">&#40;</span>LIVE_PRODUCTION_ROOT<span style="color: #66cc66;">&#41;</span>
&nbsp;
backup-production: 
    rsync $<span style="color: #66cc66;">&#123;</span>RSYNC_OPTIONS<span style="color: #66cc66;">&#125;</span> $<span style="color: #66cc66;">&#40;</span>LIVE_PRODUCTION_ROOT<span style="color: #66cc66;">&#41;</span>uploads/ $<span style="color: #66cc66;">&#40;</span>HOME<span style="color: #66cc66;">&#41;</span>/aihato-uploads/
    ssh ytec.nl <span style="color: #ff0000;">&quot;mysqldump $(MYSQL_LOGIN) aihato&quot;</span> &gt; aihato.sql
&nbsp;
update-development: 
    rsync $<span style="color: #66cc66;">&#40;</span>RSYNC_OPTIONS<span style="color: #66cc66;">&#41;</span> $<span style="color: #66cc66;">&#40;</span>WORKING_COPY_ROOT<span style="color: #66cc66;">&#41;</span> $<span style="color: #66cc66;">&#40;</span>LIVE_DEVELOPMENT_ROOT<span style="color: #66cc66;">&#41;</span>
    rsync $<span style="color: #66cc66;">&#40;</span>RSYNC_OPTIONS<span style="color: #66cc66;">&#41;</span> $<span style="color: #66cc66;">&#40;</span>LIVE_PRODUCTION_ROOT<span style="color: #66cc66;">&#41;</span>uploads/ $<span style="color: #66cc66;">&#40;</span>LIVE_DEVELOPMENT_ROOT<span style="color: #66cc66;">&#41;</span>uploads/
    ssh ytec.nl <span style="color: #ff0000;">&quot;mysqldump $(MYSQL_LOGIN) aihato | mysql $(MYSQL_LOGIN) dev_aihato&quot;</span>
&nbsp;
backup-development: mysql-dump-development
    rsync $<span style="color: #66cc66;">&#123;</span>RSYNC_OPTIONS<span style="color: #66cc66;">&#125;</span> $<span style="color: #66cc66;">&#40;</span>LIVE_DEVELOPMENT_ROOT<span style="color: #66cc66;">&#41;</span>uploads/ $<span style="color: #66cc66;">&#40;</span>HOME<span style="color: #66cc66;">&#41;</span>/aihato-uploads/
&nbsp;
mysql-dump-development:
    ssh ytec.nl <span style="color: #ff0000;">&quot;mysqldump $(MYSQL_LOGIN) dev_aihato&quot;</span> &gt; dev_aihato.sql
&nbsp;
.PHONY: update-development backup-production deploy-production mysql-dump-development</pre>

<div id="attachment_1645" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-front-page-top.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-front-page-top-300x170.png" alt="www.aihato.nl – Front page – top portion" title="www.aihato.nl – Front page – top portion" width="300" height="170" class="size-medium wp-image-1645" /></a><p class="wp-caption-text">Top portion of the front page</p></div>

<div id="attachment_1664" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-instellingen-lezen.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-instellingen-lezen-300x168.png" alt="www.aihato.nl – Settings – Reading" title="www.aihato.nl – Settings – Reading" width="300" height="168" class="size-medium wp-image-1664" /></a><p class="wp-caption-text">www.aihato.nl – Settings – Reading</p></div>

<h2>Front page</h2>

<p>The front page, after the header with the navigation and logo, starts with of a little snippet of text to welcome visitors. The rest of the page is filled with some selected stuff from the rest of the website: the latest news excerpts (plus a link to the full archive and the news feed and the Aihato hyve), clickable sponsor logos, some upcoming agenda items, a promotional movie clip, the latest video from the video gallery, a carousel with the latest photos, another carousel with all the fighter profiles and the latest fight results.</p>

<p>In WordPress, when you want the home page to be a static page, you have to change a setting in the <cite><a href="http://codex.wordpress.org/Settings_Reading_SubPanel">Settings / Reading</a></cite> subpanel. You will then have to choose another page to be the “posts” page. The other page will than use the template hierarchy the same way the home page would without this setting. The only custom page template you can use for it is <tt>home.php</tt>, which might cause confusion with the <em>actual</em> home page.</p>

<h2>Template entanglement</h2>

<p>The start page is one of a number of pages for www.aihato.nl that needed a custom template. To associate a custom template with the start page, I had two choices: I could either name the template file <tt>page-3.php</tt>, according to the <cite><a href="http://codex.wordpress.org/Template_Hierarchy">Template Hierarchy</a></cite>, or I could create a <cite><a href="http://codex.wordpress.org/Pages#Page_Templates">Page Template</a></cite>. The difference between the two options is that with the latter option, the association with the custom template happens from the Edit Page screen, whereas the first option relies on the naming of a template file in my theme. I chose the first option, which is a bit ugly, because after setting a page as start page, editing the page slug is no longer possible. (Normally you can name the template file <tt>page-&lt;slug&gt;.php</tt>, which is clearer and doesn&#8217;t depend on database state.) Both solutions are ugly in a sense because there&#8217;s just too much stuff in the database to my taste, but that&#8217;s another story which I&#8217;ll probably tell in reference to Drupal one day, since Drupal is way uglier than WordPress in this sense.</p>

<p>I&#8217;ve ended up with a bit of a random mix of page-targeted templates and templates targeted from pages. The highlight is a template which does both: <tt>page-sportschool.php</tt> targets the page with the “sportschool” slug, but also has the following comment so that I can select it from the Page Edit screen for the subpages of “sportschool”:</p>

<pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #808080; font-style: italic;">/*
Template Name: Sportschool 
 */</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre>

<div id="attachment_1665" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-events.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-events-300x170.png" alt="Aihato Events mangement interface" title="Aihato Events mangement interface" width="300" height="170" class="size-medium wp-image-1665" /></a><p class="wp-caption-text">Aihato Events mangement interface</p></div>

<h2>Events</h2>

<p>It was decided that the new website, like the old website, would have an agenda. The old website&#8217;s agenda was never up-to-date, so the new agenda should be easier to edit. To that end, I created an aihato-events plugin.</p>

<p>The plugin is quite simple. It adds two tables to the database – one to record (and announce) events and another to store fight results for these events (wins, losses, etc.). The second table links to a fighter profile by post ID (but more about that later). </p>

<div id="attachment_1666" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-events-contestants.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-events-contestants-300x170.png" alt="Aihato Event Contestants" title="Aihato Events – Contestants" width="300" height="170" class="size-medium wp-image-1666" /></a><p class="wp-caption-text">Aihato Event Contestants</p></div>

<div id="attachment_1667" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-agenda.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-agenda-300x170.png" alt="Agenda page" title="Aihato – Agenda" width="300" height="170" class="size-medium wp-image-1667" /></a><p class="wp-caption-text">Agenda page</p></div>

<p>The event management interface is pretty decent. It includes a few darlings, which I wouldn&#8217;t like to kill, except that I <em>will</em> probably overhaul the whole Aihato Events UI at some unspecified time in the future. The darlings are small touches such as the “Add new” buttons above and below the table which add a new row through AJAX at the top or the bottom of the table depending on which button is clicked. I&#8217;m also always a sucker for the in-place AJAX editing of the rows. The reason why I&#8217;ll probably still overhaul the UI at some future time is that I don&#8217;t like the same simple tabular interface for the Contestants panel. I had predicted that fight events would generally first be placed in the agenda before the event takes place, untill after the event, the results would be added. So far, nothing has been placed in the agenda before it takes place. Only after, to be able to link it to the results to be added. And even if this wasn&#8217;t true, the two screens should still become one I think.</p>

<p>The homepage contains the first few upcoming events. Sadly, there aren&#8217;t any yet. <img src='http://blog.bigsmoke.us/wp-factory/wp-includes/images/smilies/icon_confused.gif' alt=':-?' class='wp-smiley' />  Below that short (and empty) list, there&#8217;s a big button which links to the complete agenda. This page has a design that somewhat deviates from the rest. Of course, it also has some custom template programming (in a template called <tt>page-agenda.php</tt>).</p>

<div id="attachment_1668" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-uitslagen.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-uitslagen-300x170.png" alt="Page with fight results" title="Aihato – Uitslagen" width="300" height="170" class="size-medium wp-image-1668" /></a><p class="wp-caption-text">Page with fight results</p></div>

<h2>Event results</h2>

<p>The homepage also contains all the fight results for the latest event in a nice little table at the bottom right. Consistent with all the other areas on the homepage, this one is also followed by a link to the results for all recorded events in the form of a nice big button. The page with the complete results is powered by <tt>page-uitslagen.php</tt>.</p>

<p>This is one of the templates which I should really clean up by moving some code into nice and clean helper functions that live in the theme&#8217;s <tt>functions.php</tt> instead of all over the place.</p>

<h2>I18n</h2>

<p>My interest in internationalization for this website extends only as far as that I want the visitor to be talked to in Dutch as much as possible. For the rest, I don&#8217;t really care. How much I don&#8217;t care can be summed up by the total absence of <tt>__()</tt>-encapsulated strings in my theme. What&#8217;s worse: my custom plugins also lack these l10n hooks, although, because I always feel like a sinner when working directly in what is considered a translation <em>target</em> by me and the rest of the English-oriented development world, the event management stuff that I added to the management interface is in English (although, again, without l10n hooks, so what&#8217;s the point?).</p>

<div id="attachment_1670" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-profiel-tobias.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-profiel-tobias-300x170.png" alt="Aihato – Profile – Tobias" title="Aihato – Profile – Tobias" width="300" height="170" class="size-medium wp-image-1670" /></a><p class="wp-caption-text">Fighter profile for Tobias</p></div>

<div id="attachment_1674" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-profiel-bewerken.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-profiel-bewerken-300x170.png" alt="Aihato – Edit fighter profile" title="Aihato – Edit fighter profile" width="300" height="170" class="size-medium wp-image-1674" /></a><p class="wp-caption-text">Editing a fighter profile now</p></div>

<div id="attachment_1672" class="wp-caption alignright" style="width: 243px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-profiel-djura.jpg"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-profiel-djura-233x300.jpg" alt="Aihato – Profile – Djura" title="Aihato – Profile – Djura" width="233" height="300" class="size-medium wp-image-1672" /></a><p class="wp-caption-text">Fighter profile for Djura</p></div>

<h2>Fighter profiles</h2>

<p>Fighter profiles play a dominant role in the new design. Implementation took some time, and still I&#8217;m not entirely satisfied. During development, <a href="http://codex.wordpress.org/Custom_Post_Types">custom post types</a> were introduced in WordPress. I had already implemented the fighter profiles using a page template and a whole heap of <a href="http://codex.wordpress.org/Custom_Fields">custom fields</a>. Adding new profiles this way, however, is far from user-friendly. The user has to:</p>

<ul>
<li>Set the page parent to “Vechters” (Dutch for “Fighters”);</li>
<li>set the page template to “Vechter”;</li>
<li>add new custom fields for Discipline, Fight record, Weight, Class, Age, Length and City while making sure that the values are entered correctly since these don&#8217;t have a type;</li>
<li>and set a featured image for display in the fighter carousel on the front page and above the profiles.</li>
</ul>

<p>This is a lot of work, none of which is very obvious, so I hoped that custom post types would save the day. Theoretically they could, but there were a few issues, some of which I only encountered when I was quite far with development of an aihato-profiles plugin which implemented the <tt>aihato_fighter</tt> custom post type.</p>

<p>I started out by fooling with some plugins to do some of the heavy lifting. I wasn&#8217;t particularly charmed by these for reasons which I&#8217;ve sadly forgotten because I haven&#8217;t commented on it at the time. One reason I <em>can</em> think of is that I never like defining stuff in the database which I feel belongs in a file.</p>

<p>There seemed to be a bug in the custom post type admin interface created by WordPress in that, even though I had enabled thumbnail support for my post type, the UI for this was lacking. Another bug related to images was that clicking the <i>Insert image</i> button replaced the current page with the upload dialog instead of loading it in a modal dialog through AJAX. These two bugs were show-stoppers. I won&#8217;t comment any further on the whole custom post type development process until I actually continue this process.</p>

<p>Anyway, it all works now and I don&#8217;t mind doing some work on new fighter profiles myself. Editing existing ones is easy enough, and at the visitor end, it all looks sexy enough. <img src='http://blog.bigsmoke.us/wp-factory/wp-includes/images/smilies/icon_cool.gif' alt='8-)' class='wp-smiley' /> </p>

<h2>Guest-book</h2>

<p>Implementing the guest book was pretty easy. What was less easy was importing all the entries from the old guest-book. Although, even that was incredibly easy compared with extracting (exporting is too expensive a verb) the entries from the old guest-book. The old guest-book was basically impossible to spider, because the pagination depended on <tt>POST</tt>. If it were only the page number in the <tt>POST</tt> request, it wouldn&#8217;t have been too bad (and quite hackable for my purpose), but there was all sorts of session-related crap and other ugly stuff that smelled like a bunch of Microsoft Monkeys had gone all out in a HTTP obfuscation contest.</p>

<p>My initial import strategy consisted of a simple PHP script (with a function adapted from <a href="http://wordpress.org/extend/plugins/facebook-comments/">some plugin</a>) to be ran from the command-line, that accepted the author and date as arguments and the post body over STDIN.</p>

<pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
<span style="color: #b1b100;">require_once</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'wp-config.php'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> guestbook_new_comment <span style="color: #66cc66;">&#40;</span> <span style="color: #0000ff;">$commentdata</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
  <span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'comment_post_ID'</span><span style="color: #66cc66;">&#93;</span> = <span style="color: #cc66cc;">19</span> <span style="color: #808080; font-style: italic;"># This is the Aihato guestbook page</span>
  <span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'user_ID'</span><span style="color: #66cc66;">&#93;</span>         = <span style="color: #cc66cc;">0</span> <span style="color: #808080; font-style: italic;"># These people don't have accounts</span>
&nbsp;
  <span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'comment_author_IP'</span><span style="color: #66cc66;">&#93;</span> = <span style="color: #ff0000;">'127.0.0.1'</span> <span style="color: #0000ff;">$_SERVER</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'REMOTE_ADDR'</span><span style="color: #66cc66;">&#93;</span>;
  <span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'comment_agent'</span><span style="color: #66cc66;">&#93;</span>     = <span style="color: #ff0000;">'Hacked together import scripts (by BigSmoke)'</span>;
&nbsp;
  <span style="color: #808080; font-style: italic;">// We want to use the original comment date, not the time now.</span>
  <span style="color: #808080; font-style: italic;">//$commentdata['comment_date']     = current_time('mysql');</span>
  <span style="color: #808080; font-style: italic;">//$commentdata['comment_date_gmt'] = current_time('mysql', 1);</span>
&nbsp;
  <span style="color: #808080; font-style: italic;">// Automatically approve these comments.</span>
  <span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'comment_approved'</span><span style="color: #66cc66;">&#93;</span> = <span style="color: #cc66cc;">1</span>;
&nbsp;
  <span style="color: #808080; font-style: italic;">// Actually add to the database</span>
  <span style="color: #0000ff;">$comment_ID</span> = wp_insert_comment<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
  do_action<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'comment_post'</span>, <span style="color: #0000ff;">$comment_ID</span>, <span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'comment_approved'</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
  <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$comment_ID</span>;
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'comment_author'</span><span style="color: #66cc66;">&#93;</span> = <span style="color: #0000ff;">$ARGV</span><span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#93;</span>;
<span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'comment_date'</span><span style="color: #66cc66;">&#93;</span> = <span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'comment_date_gmt'</span><span style="color: #66cc66;">&#93;</span> = <span style="color: #0000ff;">$ARGV</span><span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#93;</span>;
<span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'comment_content'</span><span style="color: #66cc66;">&#93;</span> = <a href="http://www.php.net/trim"><span style="color: #000066;">trim</span></a><span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/readfile"><span style="color: #000066;">readfile</span></a><span style="color: #66cc66;">&#40;</span>STDIN<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #0000ff;">$new_comment_id</span> = guestbook_new_comment<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$commentdata</span><span style="color: #66cc66;">&#41;</span>;
<a href="http://www.php.net/echo"><span style="color: #000066;">echo</span></a> <span style="color: #ff0000;">&quot;Inserted new comment $new_comment_id to post 19.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre>

<p>The script would be called from a Ruby script that parsed the ugly-ass HTML-like tag soup also known as the old guest-book. I have to admit that the script is as ugly as the shit it&#8217;s supposed to make sense of. Fuck it! One-of scripts don&#8217;t need to look good; it&#8217;s already been deleted from svn 75 revisions ago.</p>

<p>However, I never could call the PHP script from the Ruby script because I <a href="http://blog.bigsmoke.us/2010/06/21/rubygems">couldn&#8217;t</a> get the necessary gems to install on the development server where the import needed to happen, so I ran the script locally and modified it to use WordPress&#8217; XML-RPC interface. To make this work, I only had to install a <a href="http://www.thepicklingjar.com/code/anonymous-xmlrpc-comments/">WordPress plugin to allow anonymous comments through XML-RPC</a>. (See my <a href="http://blog.bigsmoke.us/2010/05/04/aihato-wordpress-dev-notes#comment-95789">previous notes</a> on this subject, if you&#8217;re interested.)</p>

<p>[By the way, I just copied this script to the clipboard using “<tt>svn cat https://svn.ytec.nl/svn/aihato/trunk/import-guestbook.rb@37|xsel --clipboard</tt>”; see my <a href="http://blog.bigsmoke.us/2010/01/31/xsel">post on xsel</a> if you want to learn more.]</p>

<div id="attachment_1681" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-gastenboek.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-gastenboek-300x170.png" alt="Aihato - Guestbook" title="Aihato - Guestbook" width="300" height="170" class="size-medium wp-image-1681" /></a><p class="wp-caption-text">The finished guestbook, complete with all the old and new enties</p></div>

<pre class="ruby"><span style="color:#008000; font-style:italic;">#!/usr/bin/ruby</span>
&nbsp;
<span style="color:#CC0066; font-weight:bold;">require</span> 'scrapi'
<span style="color:#CC0066; font-weight:bold;">require</span> 'open3'
<span style="color:#CC0066; font-weight:bold;">require</span> 'xmlrpc/client'
&nbsp;
&nbsp;
guestbook_entry = Scraper.<span style="color:#9900CC;">define</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  process <span style="color:#996600;">&quot;td &gt; div.GB_Head &gt; div.GB_Date&quot;</span>, :date =&gt; :text
  process <span style="color:#996600;">&quot;td &gt; div.GB_Head &gt; div.GB_Name&quot;</span>, :name =&gt; :text
  process <span style="color:#996600;">&quot;td &gt; div.GB_Body &gt; div.GB_BodyText&quot;</span>, :body =&gt; :element
&nbsp;
  result :date, :name, :body
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
guestbook = Scraper.<span style="color:#9900CC;">define</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  <span style="color:#CC0066; font-weight:bold;">array</span> :entries
&nbsp;
  process <span style="color:#996600;">&quot;table.GB_MainGrid tr&quot;</span>, :entries =&gt; guestbook_entry
&nbsp;
  result :entries
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># I need to do this because the document has at least 3 &lt;html&gt; tags,</span>
<span style="color:#008000; font-style:italic;"># so it's impossible to parse, even for Tidy</span>
fake_document = <span style="color:#996600;">&quot;&lt;html&gt;&lt;body&gt;&quot;</span>
reading_guestbook_table = <span style="color:#0000FF; font-weight:bold;">false</span>
STDIN.<span style="color:#CC0066; font-weight:bold;">readlines</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |line|
  <span style="color:#9966CC; font-weight:bold;">if</span> line =~ /&lt;table <span style="color:#9966CC; font-weight:bold;">class</span>=<span style="color:#996600;">&quot;GB_MainGrid&quot;</span>/
    reading_guestbook_table = <span style="color:#0000FF; font-weight:bold;">true</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
  
  <span style="color:#9966CC; font-weight:bold;">if</span> reading_guestbook_table
    fake_document += line
    reading_guestbook_table = <span style="color:#0000FF; font-weight:bold;">false</span> <span style="color:#9966CC; font-weight:bold;">if</span> line =~ %r<span style="color:#006600; font-weight:bold;">&#123;</span>&lt;/table&gt;<span style="color:#006600; font-weight:bold;">&#125;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
fake_document += <span style="color:#996600;">&quot;&lt;/body&gt;&lt;/html&gt;&quot;</span>
&nbsp;
entries = guestbook.<span style="color:#9900CC;">scrape</span><span style="color:#006600; font-weight:bold;">&#40;</span>fake_document<span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
entries.<span style="color:#9900CC;">delete_at</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
entries.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |entry|
  <span style="color:#9966CC; font-weight:bold;">next</span> <span style="color:#9966CC; font-weight:bold;">unless</span> entry<span style="color:#006600; font-weight:bold;">&#91;</span>'body'<span style="color:#006600; font-weight:bold;">&#93;</span>
&nbsp;
  date_parts_in_proper_order = entry<span style="color:#006600; font-weight:bold;">&#91;</span>'date'<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#CC0066; font-weight:bold;">split</span><span style="color:#006600; font-weight:bold;">&#40;</span>/-/<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">reverse</span>
  date_string_with_proper_zeroes = <span style="color:#996600;">&quot;%d%02d%02dT00:00:00&quot;</span> % date_parts_in_proper_order
  entry<span style="color:#006600; font-weight:bold;">&#91;</span>'date'<span style="color:#006600; font-weight:bold;">&#93;</span> = XMLRPC::Convert.<span style="color:#9900CC;">dateTime</span><span style="color:#006600; font-weight:bold;">&#40;</span> date_string_with_proper_zeroes <span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
  server = XMLRPC::Client.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;aihato.dev.ytec.nl&quot;</span>, <span style="color:#996600;">&quot;/wp/xmlrpc.php&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
  entry<span style="color:#006600; font-weight:bold;">&#91;</span>'body'<span style="color:#006600; font-weight:bold;">&#93;</span> = entry<span style="color:#006600; font-weight:bold;">&#91;</span>'body'<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">to_s</span>
  entry<span style="color:#006600; font-weight:bold;">&#91;</span>'body'<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#CC0066; font-weight:bold;">gsub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>%r<span style="color:#006600; font-weight:bold;">&#123;</span>&lt;div <span style="color:#9966CC; font-weight:bold;">class</span>='GB_BodyText'&gt;<span style="color:#006600; font-weight:bold;">&#40;</span>.<span style="color:#9900CC;">*</span><span style="color:#006600; font-weight:bold;">&#41;</span>&lt;/div&gt;<span style="color:#006600; font-weight:bold;">&#125;</span>m, '\<span style="color:#006666;">1</span>'<span style="color:#006600; font-weight:bold;">&#41;</span>
  entry<span style="color:#006600; font-weight:bold;">&#91;</span>'body'<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#CC0066; font-weight:bold;">gsub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>%r<span style="color:#006600; font-weight:bold;">&#123;</span>&lt;/p&gt;\s*&lt;p&gt;<span style="color:#006600; font-weight:bold;">&#125;</span>, <span style="color:#996600;">&quot;<span style="color:#000099;">\n</span><span style="color:#000099;">\n</span>&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  entry<span style="color:#006600; font-weight:bold;">&#91;</span>'body'<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#CC0066; font-weight:bold;">gsub</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>%r<span style="color:#006600; font-weight:bold;">&#123;</span>&lt;/?p&gt;<span style="color:#006600; font-weight:bold;">&#125;</span>, <span style="color:#996600;">&quot;&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  entry<span style="color:#006600; font-weight:bold;">&#91;</span>'body'<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#CC0066; font-weight:bold;">chomp</span>!
&nbsp;
  new_comment_id = server.<span style="color:#9900CC;">call</span><span style="color:#006600; font-weight:bold;">&#40;</span>'wp.<span style="color:#9900CC;">newComment</span>', <span style="color:#006666;">1</span>, '', '', <span style="color:#006666;">19</span>, <span style="color:#006600; font-weight:bold;">&#123;</span>'comment_parent' =&gt; <span style="color:#006666;">0</span>, 'content' =&gt; entry<span style="color:#006600; font-weight:bold;">&#91;</span>'body'<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">to_s</span>, 'author' =&gt; entry<span style="color:#006600; font-weight:bold;">&#91;</span>'name'<span style="color:#006600; font-weight:bold;">&#93;</span>, 'author_url' =&gt; '', 'author_email' =&gt; 'dummy@example.<span style="color:#9900CC;">com</span>'<span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
  <span style="color:#CC0066; font-weight:bold;">puts</span> new_comment_id.<span style="color:#9900CC;">inspect</span>
  
  <span style="color:#008000; font-style:italic;"># Change date and approval status</span>
  server.<span style="color:#9900CC;">call</span><span style="color:#006600; font-weight:bold;">&#40;</span>'wp.<span style="color:#9900CC;">editComment</span>', <span style="color:#006666;">1</span>, 'myuser', 'nottherealpassword', new_comment_id, <span style="color:#006600; font-weight:bold;">&#123;</span>'status' =&gt; 'approve', 'date_created_gmt' =&gt; entry<span style="color:#006600; font-weight:bold;">&#91;</span>'date'<span style="color:#006600; font-weight:bold;">&#93;</span>, 'author' =&gt; entry<span style="color:#006600; font-weight:bold;">&#91;</span>'name'<span style="color:#006600; font-weight:bold;">&#93;</span>, 'author_email' =&gt; 'dummy@example.<span style="color:#9900CC;">com</span>'<span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
  <span style="color:#008000; font-style:italic;">#Open3.popen3(&quot;php -q import-guestbook.php '#{entry['name']}' #{entry['date']}&quot;) do |stdin, stdout, stderr|</span>
  <span style="color:#008000; font-style:italic;">#  stdin &lt;&lt; entry['body']</span>
  <span style="color:#008000; font-style:italic;">#end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre>

<p>Because I was too stupid to write a spider function to download the old guest-book, I ended up simply clicking through all the pages and feeding the page source to my import script one page at the time.</p>

<p>The new guest book is the only page on the website with comments enabled. For the rest it&#8217;s like any other page with its own custom template (<tt>page-gastenboek.php</tt>).</p>

<div id="attachment_1682" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-contact.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-contact-300x170.png" alt="Aihato – Contact" title="Aihato – Contact" width="300" height="170" class="size-medium wp-image-1682" /></a><p class="wp-caption-text">The contact form</p></div>

<h2>Contact form</h2>

<p>In my <a href="http://blog.bigsmoke.us/2010/05/04/aihato-wordpress-dev-notes">notes</a> made during the development process, I have made a few comments (<a href="http://blog.bigsmoke.us/2010/05/04/aihato-wordpress-dev-notes#comment-95459">1</a>, <a href="http://blog.bigsmoke.us/2010/05/04/aihato-wordpress-dev-notes#comment-95854">2</a>, <a href="http://blog.bigsmoke.us/2010/05/04/aihato-wordpress-dev-notes#comment-95855">3</a>, <a href="http://blog.bigsmoke.us/2010/05/04/aihato-wordpress-dev-notes#comment-95856">4</a>) about the troubles I had when looking for a simple plugin to create a simple contact form. I would have saved quite some time if I had skipped the search and wrote my own code to handle it. In the end I did use a plug-in. Well, I forked it, but that&#8217;s just another way of using it, isn&#8217;t it?</p>

<div id="attachment_1683" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-nieuws-2010.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-nieuws-2010-300x170.png" alt="Aihato - News - 2010" title="Aihato - News - 2010" width="300" height="170" class="size-medium wp-image-1683" /></a><p class="wp-caption-text">The news archive</p></div>

<h2>News</h2>

<p>The actual news section (where I could use WordPress&#8217; core strength – its blogging engine) is maybe the foremost reason why I let myself be suckered into another web project despite my many vows to never program for money again. (Well, this being a club project, means that I could somewhat sidestep my many promises to myself, because there was hardly money involved in the process. (I train for free for a year.))</p>

<p>The old website&#8217;s news page was just a very long list of all the news since 2003. This was pretty suck-ass. What was much worse, though, was that there was no RSS feed. This new website being WordPress based means that I have a whole slew of feeds to chose from. It gave me quite a kick when the first news item posted by someone else hit my feed reader. Now, there are no longer any sites left that I have to manually check for updates. Yay!</p>

<p>An interesting choice I made for the news archive is that I skipped pagination altogether and instead presented a list of years all the way back to 2003 where you&#8217;d normally expect to see pagination. Personally, I don&#8217;t mind long pages. In fact, I often find clicking “Next” and “Previous” infinitely much more annoying.</p>

<p>Commenting on the news isn&#8217;t allowed by request of the Aihato boys. They gave some pretty good reasons not to do this mostly related to the intentional abuse by club members and members of competing clubs that they&#8217;ve seen on the website of a friendly club.</p>

<p>The news section is just one of the many places where I&#8217;ve made thankful use of WordPress&#8217; new <a href="http://codex.wordpress.org/Post_Thumbnails">Post Thumbnails</a> feature. I like it when stuff that&#8217;s only available through clumsy hacks and plugins makes it into core. By the way: when working with post thumbnails, the <a href="http://wordpress.org/extend/plugins/regenerate-thumbnails/">regenerate-thumbnails</a> plugin proved to be an enormous aid.</p>

<div id="attachment_1684" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-foto-albums.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-foto-albums-300x170.png" alt="Aihato – Photo albums" title="Aihato – Photo albums" width="300" height="170" class="size-medium wp-image-1684" /></a><p class="wp-caption-text">Overview of all photo albums</p></div>

<div id="attachment_1685" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-foto-album-ede.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-foto-album-ede-300x170.png" alt="Aihato – Photo album – Ede" title="Aihato – Photo album – Ede" width="300" height="170" class="size-medium wp-image-1685" /></a><p class="wp-caption-text">Photo album of a grappling competition</p></div>

<h2>Media gallery</h2>

<p>Even on the old website, the foto gallery played an important role. Thinking of the best way how to do this in WordPress was quite a <a href="http://blog.bigsmoke.us/2010/05/04/aihato-wordpress-dev-notes#comment-96142">headache</a>.</p>

<p>To start with, the design requirements were pretty steep. Ying had included a coverflow-like effect in his wire-frame for viewing individual albums. Luckily, the list of photo albums wasn&#8217;t too difficult (a simple grid-view) and made easier still by the HTML/CSS guy. I also skipped a few requirements such as highest rated photos and videos. (I skipped the rating feature altogether.) Still, I spent a lot of time looking through available plug-ins and into different ways to solve the most challenging requirement: there had to be a separate section for the photo albums and the videos, where intuitively I&#8217;d simply include it all in the news as is customary with a blog. In the end, I did exactly this but with a twist.</p>

<p>The process of publishing a new photo album has become extremely straight-forward: the user has to upload the images using the <i>Add image</i> link, insert the gallery in the post (<em>if</em> they want a clear link from the news item view to the gallery) and check the “Fotogalerij” (Dutch for “photo gallery”) category (if they want the album to appear in the list of albums).</p>

<p>Since I&#8217;ve chosen not to make photo albums a separate entity in the back-end, I had to work a little magic to make them appear as such to the visitor. But I didn&#8217;t want to make the separation go too far; I don&#8217;t like websites (such as the old Aihato website) where the photo gallery seems bolted on as an afterthought and the user has to upload an album and then create a link to the album in the news.</p>

<h3>The gallery view</h3>

<p>You know how WordPress makes a comments feed available for every post? It accomplishes this using something it calls a <em>rewrite endpoint</em> (“feed” for feeds). For example:</p>

<pre class="php">http:<span style="color: #808080; font-style: italic;">//www.example.com/blog/2010/11/08/post-with-interesting-comments/feed/atom/</span>
http:<span style="color: #808080; font-style: italic;">//www.example.com/blog/2010/11/08/post-with-interesting-comments/feed/rss/ </span></pre>

<p>You can add such a rewrite endpoint yourself using the <tt><a href="http://codex.wordpress.org/Rewrite_API#add_rewrite_endpoint.28.29">add_rewrite_endpoint()</a></tt> function. The code below shows how I created an alternative view for my posts and pages called “gallery”. It also shows what I need to do to make an extra query variable available with the name of the endpoint. The part after the slash after the endpoint in the URL become the new query variable&#8217;s value.</p>

<pre class="php">add_rewrite_endpoint<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'gallery'</span>, EP_PERMALINK | EP_PAGES<span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$wp_rewrite</span>-&gt;<span style="color: #006600;">flush_rules</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
add_filter<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'query_vars'</span>, <span style="color: #ff0000;">'aihato_queryvars'</span><span style="color: #66cc66;">&#41;</span>;
add_action<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'template_redirect'</span>, <span style="color: #ff0000;">'aihato_special_gallery_template'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> aihato_special_gallery_template<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
  <a href="http://www.php.net/global"><span style="color: #000066;">global</span></a> <span style="color: #0000ff;">$wp_query</span>;
&nbsp;
  <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span> is_category<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'fotogalerij'</span><span style="color: #66cc66;">&#41;</span> or is_category<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'filmgalerij'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">include</span><span style="color: #66cc66;">&#40;</span>TEMPLATEPATH . <span style="color: #ff0000;">'/galleries.php'</span><span style="color: #66cc66;">&#41;</span>;
    <a href="http://www.php.net/exit"><span style="color: #000066;">exit</span></a>;
  <span style="color: #66cc66;">&#125;</span>
&nbsp;
  <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span> <a href="http://www.php.net/isset"><span style="color: #000066;">isset</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$wp_query</span>-&gt;<span style="color: #006600;">query_vars</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'gallery'</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">include</span><span style="color: #66cc66;">&#40;</span>TEMPLATEPATH . <span style="color: #ff0000;">'/gallery.php'</span><span style="color: #66cc66;">&#41;</span>;
    <a href="http://www.php.net/exit"><span style="color: #000066;">exit</span></a>;
  <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">function</span> aihato_queryvars<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$qvars</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
  <span style="color: #0000ff;">$qvars</span><span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#93;</span> = <span style="color: #ff0000;">'gallery'</span>;
  <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$qvars</span>;
<span style="color: #66cc66;">&#125;</span></pre>

<p>The code above creates an alternative “view” of posts that I can use to view all the images attached to that post. When the user inserts the gallery into a post, the following code makes it so that instead of the images, the visitor will see a link to the gallery view of that post.</p>

<pre class="php">add_filter<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'post_gallery'</span>, <span style="color: #ff0000;">'aihato_gallery_filter'</span>, <span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #808080; font-style: italic;">/**
 * Modifies the behaviour of the [gallery] shortcode.
 */</span>
<span style="color: #000000; font-weight: bold;">function</span> aihato_gallery_filter<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$null</span>, <span style="color: #0000ff;">$attr</span> = <a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
<span style="color: #808080; font-style: italic;">// Snipped: code to generate a nice link</span>
<span style="color: #66cc66;">&#125;</span></pre>

<h3>ContentFlow / FancyBox integration</h3>

<p>To make the gallery view look cool, I implemented the CoverFlow effect using the <a href="http://www.jacksasylum.eu/ContentFlow/index.php">ContentFlow</a> jQuery plugin. It&#8217;s pretty cool. It supports reflection, scrolling with a scroll wheel and it just <em>feels right</em>™. I hooked it up to <a href="http://fancybox.net/">FancyBox</a>, a very slick Lightbox clone for jQuery. The result was, I must say, immensely pleasing. <img src='http://blog.bigsmoke.us/wp-factory/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Both effects support scrolling and the FancyBox effects make it look like the images in the ContentFlow are really blown up and shrunk. (I&#8217;ve made it so that the FancyBox appears when you click the active image in the ContentFlow.)</p>

<p>This is some of the spaghetti code that made the two effects play nicely together:</p>

<pre class="javascript"><span style="color: #009900; font-style: italic;">// Returns the offset of the item to start showing</span>
<span style="color: #003366; font-weight: bold;">function</span> albumFlowStartItem<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
  <span style="color: #003366; font-weight: bold;">var</span> hashNumber = window.<span style="color: #006600;">location</span>.<span style="color: #006600;">hash</span>;
&nbsp;
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #66cc66;">&#40;</span> hashNumber &amp;&amp; hashNumber.<span style="color: #006600;">match</span><span style="color: #66cc66;">&#40;</span><span style="color: #0066FF;">/^#\d+$/</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    hashNumber = hashNumber.<span style="color: #006600;">replace</span><span style="color: #66cc66;">&#40;</span><span style="color: #0066FF;">/^#<span style="color: #66cc66;">&#40;</span>\d+<span style="color: #66cc66;">&#41;</span>$/</span>, <span style="color: #3366CC;">'$1'</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #000066; font-weight: bold;">return</span> jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'#album_flow a#attachment-'</span>+hashNumber<span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">prevAll</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">size</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
&nbsp;
  <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">'center'</span>;
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #009900; font-style: italic;">// My own custom state variable</span>
jQuery.<span style="color: #006600;">fancybox</span>.<span style="color: #006600;">remainActiveUntilClosed</span> = <span style="color: #003366; font-weight: bold;">false</span>;
&nbsp;
jQuery<span style="color: #66cc66;">&#40;</span>document<span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">ready</span><span style="color: #66cc66;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
  jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'#album_flow a'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">fancybox</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span>
    transitionIn: <span style="color: #3366CC;">'elastic'</span>,
    transitionOut: <span style="color: #3366CC;">'elastic'</span>,
    speedIn: <span style="color: #CC0000;">600</span>,
    speedOut: <span style="color: #CC0000;">200</span>,
    overlayShow: <span style="color: #003366; font-weight: bold;">false</span>,
    cyclic: <span style="color: #003366; font-weight: bold;">true</span>,
    onStart: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span>selectedArray, selectedIndex, selectedOpts<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
      element = selectedArray<span style="color: #66cc66;">&#91;</span>selectedIndex<span style="color: #66cc66;">&#93;</span>;
&nbsp;
      <span style="color: #000066; font-weight: bold;">return</span> jQuery.<span style="color: #006600;">fancybox</span>.<span style="color: #006600;">remainActiveUntilClosed</span> || element.<span style="color: #006600;">hasClassName</span><span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'active'</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span>,
    onComplete: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
      jQuery.<span style="color: #006600;">fancybox</span>.<span style="color: #006600;">remainActiveUntilClosed</span> = <span style="color: #003366; font-weight: bold;">true</span>;
    <span style="color: #66cc66;">&#125;</span>,
    onClosed: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
      jQuery.<span style="color: #006600;">fancybox</span>.<span style="color: #006600;">remainActiveUntilClosed</span> = <span style="color: #003366; font-weight: bold;">false</span>;
    <span style="color: #66cc66;">&#125;</span>
  <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
  <span style="color: #003366; font-weight: bold;">var</span> albumFlow = <span style="color: #003366; font-weight: bold;">new</span> ContentFlow<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'album_flow'</span>, <span style="color: #66cc66;">&#123;</span>
    reflectionHeight: <span style="color: #CC0000;">0.3</span>,
    flowSpeedFactor: <span style="color: #CC0000;">0.7</span>,
    startItem: albumFlowStartItem<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>,
    onclickActiveItem: <span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
      <span style="color: #003366; font-weight: bold;">var</span> itemOffset = jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #000066; font-weight: bold;">item</span>.<span style="color: #006600;">element</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">prevAll</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">size</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
      jQuery.<span style="color: #006600;">fancybox</span>.<span style="color: #006600;">pos</span><span style="color: #66cc66;">&#40;</span>itemOffset<span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span>,
  <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;</pre>

<h3>Categories for photo/video galleries</h3>

<p>To make a post appear in the photo gallery, you just have to check that category. Making posts appear in the video gallery works the same. These listings are displayed using the <tt>galleries.php</tt> template thanks to a little bit of code in <tt>aihato_special_gallery_template()</tt>. I redirected these archive views to that template because otherwise I&#8217;d have had to make a symlink to use the same file for the video category and the photo category. (I&#8217;d have needed two files: <tt>category-fotogalerij.php</tt> and <tt>category-filmgalerij.php</tt>.)</p>

<p>I like how I simply used a custom view of both a post and of two different category archives to achieve all my media gallery requirements. There&#8217;s no wild database customizations or heavy plug-ins involved. It&#8217;s low-fat and carb-free.</p>

<div id="attachment_1687" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-filmgalerij.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-filmgalerij-300x170.png" alt="Aihato - Film gallery" title="Aihato - Film gallery" width="300" height="170" class="size-medium wp-image-1687" /></a><p class="wp-caption-text">The film gallery</p></div>

<h3>YouTube is king</h3>

<p>Because I was too lazy to find a good playback solution and I&#8217;m a bit reluctant to self-host video files anyway, I decided to put together something that relies solely on embedding videos hosted elsewhere. To be completely honest, although WordPress is quite flexible in this sense, “elsewhere” means just YouTube here.</p>

<p>The idea is simple: WordPress already allows you to just paste a YouTube URL into the post editor and all the embedding code is created for you. Building on this, to show the latest video on the homepage, I just perform a search for posts which contain a YouTube URL. Then I parse the content a bit, and include the YouTube ID in my own low-res embed code. (The latest video area on the homepage is smaller than the default embed created by WordPress.)</p> 

<p>When generating the film gallery overview, my theme goes through all the YouTube URLs in all posts categorized as “Filmgalerij”. For each of these URLs, it uses the YouTube API to retrieve the movie title and the URL of an adequately sized thumbnail. That means that, for thumbnails to appear in the gallery, the associated posts don&#8217;t need a featured image, just one or more YouTube URLs. This approach also makes it so that you can embed as much YouTube URLs in each post as you like, since the gallery will cope beautifully.</p>

<p>When a visitor clicks a movie thumbnail, a YouTube embed pops up using FancyBox. Did I mention how cool FancyBox is? Pretty damn cool:</p>

<pre class="javascript">jQuery<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">'a.youtube'</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">click</span><span style="color: #66cc66;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span>
  jQuery.<span style="color: #006600;">fancybox</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#123;</span>
    <span style="color: #3366CC;">'padding'</span>: <span style="color: #CC0000;">0</span>,
    <span style="color: #3366CC;">'autoScale'</span>: <span style="color: #003366; font-weight: bold;">false</span>,
    <span style="color: #3366CC;">'transitionIn'</span>: <span style="color: #3366CC;">'none'</span>,
    <span style="color: #3366CC;">'transitionOut'</span>: <span style="color: #3366CC;">'none'</span>,
    <span style="color: #3366CC;">'title'</span>: <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">title</span>,
    <span style="color: #3366CC;">'width'</span>: <span style="color: #CC0000;">680</span>,
    <span style="color: #3366CC;">'height'</span>: <span style="color: #CC0000;">495</span>,
    <span style="color: #3366CC;">'href'</span>: <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #006600;">href</span>.<span style="color: #006600;">replace</span><span style="color: #66cc66;">&#40;</span><span style="color: #003366; font-weight: bold;">new</span> RegExp<span style="color: #66cc66;">&#40;</span><span style="color: #3366CC;">&quot;watch<span style="color: #000099; font-weight: bold;">\\</span>?v=&quot;</span>, <span style="color: #3366CC;">&quot;i&quot;</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #3366CC;">'v/'</span><span style="color: #66cc66;">&#41;</span>,
    <span style="color: #3366CC;">'type'</span>: <span style="color: #3366CC;">'swf'</span>,
    <span style="color: #3366CC;">'swf'</span>: <span style="color: #66cc66;">&#123;</span>
      <span style="color: #3366CC;">'wmode'</span>: <span style="color: #3366CC;">'transparent'</span>,
      <span style="color: #3366CC;">'allowfullscreen'</span>: <span style="color: #3366CC;">'true'</span>
    <span style="color: #66cc66;">&#125;</span>
  <span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
  <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">false</span>;
<span style="color: #66cc66;">&#125;</span><span style="color: #66cc66;">&#41;</span>;</pre>

<h2>Menus and navigation</h2>

<p id="main-menu-hack">A downside of my view-oriented media gallery solution is the insanely ugly hack I had to do to make the top horizontal menu behave naturally:</p>

<pre class="php"><span style="color: #808080; font-style: italic;">// This is the ultimate in ugly hacks. Enjoy! :-)</span>
<span style="color: #000000; font-weight: bold;">function</span> aihato_main_menu_filter<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$items</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
  <a href="http://www.php.net/global"><span style="color: #000066;">global</span></a> <span style="color: #0000ff;">$wp_query</span>;
&nbsp;
  <span style="color: #808080; font-style: italic;">// menu-item-639 = Nieuws</span>
  <span style="color: #808080; font-style: italic;">// menu-item-643 = Foto/Video (connected to the fotogalerij category)</span>
&nbsp;
  <span style="color: #808080; font-style: italic;">// This conditional makes it the current-menu-item also when we're in the filmgalerij category,</span>
  <span style="color: #808080; font-style: italic;">// and when we're looking at the gallery view of a post (through the gallery rewrite endpoint).</span>
  <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span> is_category<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'filmgalerij'</span><span style="color: #66cc66;">&#41;</span> or <a href="http://www.php.net/isset"><span style="color: #000066;">isset</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$wp_query</span>-&gt;<span style="color: #006600;">query_vars</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'gallery'</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0000ff;">$items</span> = <a href="http://www.php.net/preg_replace"><span style="color: #000066;">preg_replace</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'!(menu-item-643)!'</span>, <span style="color: #ff0000;">'<span style="color: #000099; font-weight: bold;">\\</span>1 current-menu-item'</span>, <span style="color: #0000ff;">$items</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
  <span style="color: #808080; font-style: italic;">// This conditional ensures that the Nieuws menu item is active when we don't want to be in the gallery.</span>
  <span style="color: #808080; font-style: italic;">// At the same time, it makes sure that the the Foto/Video menu item is inactive.</span>
  <span style="color: #b1b100;">elseif</span> <span style="color: #66cc66;">&#40;</span> !<a href="http://www.php.net/isset"><span style="color: #000066;">isset</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$wp_query</span>-&gt;<span style="color: #006600;">query_vars</span><span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'gallery'</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span> and <span style="color: #66cc66;">&#40;</span>is_archive<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> or is_single<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0000ff;">$items</span> = <a href="http://www.php.net/preg_replace"><span style="color: #000066;">preg_replace</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'!(menu-item-639)!'</span>, <span style="color: #ff0000;">'<span style="color: #000099; font-weight: bold;">\\</span>1 current-menu-parent'</span>, <span style="color: #0000ff;">$items</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #0000ff;">$items</span> = <a href="http://www.php.net/preg_replace"><span style="color: #000066;">preg_replace</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'!current-menu-parent current-post-parent (menu-item-643)!'</span>, <span style="color: #ff0000;">'<span style="color: #000099; font-weight: bold;">\\</span>1'</span>, <span style="color: #0000ff;">$items</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
&nbsp;
  <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$items</span>;  
<span style="color: #66cc66;">&#125;</span></pre>

<p>As soon as <a href="http://codex.wordpress.org/Version_3.0">WordPress 3.0</a> was released somewhere during the development of this website, I started to use its new <a href="http://codex.wordpress.org/Appearance_Menus_SubPanel">Custom Menu Management</a> feature.</p>

<p>Before the change:</p>

<pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span> wp_list_pages<span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">'depth'</span> =&gt; <span style="color: #cc66cc;">1</span>, <span style="color: #ff0000;">'title_li'</span> =&gt; <span style="color: #ff0000;">''</span>, <span style="color: #ff0000;">'sort_column'</span> =&gt; <span style="color: #ff0000;">'menu_order, post_title'</span> <span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre>

<p>After the change:</p>

<pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span> wp_nav_menu<span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">'menu'</span> =&gt; <span style="color: #ff0000;">'main'</span>, <span style="color: #ff0000;">'depth'</span> =&gt; <span style="color: #cc66cc;">1</span> <span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre>

<p>As you can see, the change wasn&#8217;t difficult, but, more importantly, it gave me some useful powers that I could use for good. For the main menu, I could include a category, which I used to add the Fotogalerij category. I could also change the label of that item to be different from the category name so that it also seems to apply to the Filmgalerij category. That, together with the <a href="#main-menu-hack">ugly hack</a> above, gave me my illusionary Photo/Video category.</p>

<div id="attachment_1686" class="wp-caption alignright" style="width: 310px"><a href="http://blog.bigsmoke.us/uploads/2010/11/aihato-sportschool.png"><img src="http://blog.bigsmoke.us/uploads/2010/11/aihato-sportschool-300x170.png" alt="Aihato – Sportschool" title="Aihato – Sportschool" width="300" height="170" class="size-medium wp-image-1686" /></a><p class="wp-caption-text">Putting custom menus to good use in this section</p></div>

<p>Another place where I could put the custom menus to good use was the Sportschool section. There I had to <em>design</em> a submenu, because designers always forget a few vital pieces in their design, such as how submenus should look. However, the submenu shouldn&#8217;t just include links to pages, but also links to two different subscription forms (uploads). The new menu system allows me to do this quite easily.</p>

<p>So, again, I could replace something that didn&#8217;t do exactly what I wanted:</p>

<pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span> wp_list_pages<span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">'title_li'</span> =&gt; get_the_title<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">'child_of'</span> =&gt; <span style="color: #cc66cc;">11</span>, <span style="color: #ff0000;">'include'</span> =&gt; <a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #000000; font-weight: bold;">?&gt;</span></pre>

<p>With something simpler that did:</p>

<pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span> wp_nav_menu<span style="color: #66cc66;">&#40;</span><a href="http://www.php.net/array"><span style="color: #000066;">array</span></a><span style="color: #66cc66;">&#40;</span> <span style="color: #ff0000;">'menu'</span> =&gt; <span style="color: #ff0000;">'school'</span> <span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></pre>

<p>It is a curious aspect of this website that every section has its own means of navigating within that section.</p>

<ol>
<li>The fighter profiles section uses a carousel at the top to select fighters. In the future, some form controls to filter the carousel will also be added.</li>
<li>The Photo/Video gallery is divided into two subsections (one for photos and one for videos). These subsections are subsequently navigated using a grid view of the individual photo albums or videos. When viewing a photo album, navigation is further refined using the ContentFlow UI.</li>
<li>The news section is subdivided in yearly archives which are presented as a sort of pagination interface.</li>
<li>The Sportschool (“Over Aihato”) section sports a simple “submenu” in the left column. This is in fact a separate menu defined in the theme and managed using the new menu editor.</li>
<li>Finally, the guestbook uses WordPress&#8217; default comment pagination.</li>
</ol>

<h2>Conclusion</h2>

<p>This turned out to be a pretty long post taking a ridiculous amount of time to write. But, hey, this way I have at least documented the project. I don&#8217;t think that such detailed documentation would have happened otherwise. In my experience, “in-house” documentation sucks donkey ass. It&#8217;s never complete. It&#8217;s never up-to-date and – worst of all – it doesn&#8217;t invite comments. It&#8217;s just not part of big WWW.</p>

<p>I&#8217;m glad that the new website is on-line. I love how it turned out (even though I still hate web development). The enthusiastic reception of this project even compensates for some of my previous web development traumas. <img src='http://blog.bigsmoke.us/wp-factory/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  I find myself quite enjoying the after-work because of the laid-back attitude of the guys. What&#8217;s worse: I&#8217;m actually looking forward to implementing some of the planned improvements. That&#8217;s strange. Maybe it&#8217;s the complete lack of hysterics about the shape of a particular icon (“I want the trash can back!”)  or the phrasing of a particular sentence (“How could this have happened?! You should have quadruple-checked this first! Aaarggh! Now our company will die because we look unprofessional!”). Some people are just more fun to work <del>for</del><ins>with</ins> than other people I guess.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigsmoke.us/2010/11/09/www.aihato.nl/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>RubyGems nuisances</title>
		<link>http://blog.bigsmoke.us/2010/06/21/rubygems</link>
		<comments>http://blog.bigsmoke.us/2010/06/21/rubygems#comments</comments>
		<pubDate>Mon, 21 Jun 2010 15:05:13 +0000</pubDate>
		<dc:creator>Rowan Rodrik</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[Gems]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[scrAPI]]></category>

		<guid isPermaLink="false">http://blog.bigsmoke.us/?p=1442</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p>Because I <a href="http://blog.bigsmoke.us/tag/scrapi">used it successfully before</a>, I decided to use scrAPI to scrape the entries from the old Aihato guestbook. After preprocessing the HTML a bit, I finally got beyond an endless debugging sessions (which cumulated in me discovering a whole collection of nested <tt>&lt;html&gt;</tt> tags, which forbad any type of sensible parsing of the page).</p>

<p>The scrAPI script calls a simple PHP script to add the extracted comment to the WordPress DB. The next step was copying the script to the development server (which has command-line PHP and the MySQL daemon running). Of course, the development server (which runs Debian Lenny) didn&#8217;t have the scrapi package installed. So, I thought I&#8217;d install the rubygems package and be done after <q><tt>gem install scrapi</tt></q>.</p>

<p>It seemed to install just fine, but&#8230; it just won&#8217;t fucking work! Adding <q><tt>require 'rubygems'</tt></q> to the script doesn&#8217;t work either.</p>

<p>This whole thing reminded of a similar occasion a while back when RubyGems kept fucking up everything until we discovered through Google that the version of RubyGems shipped with Debian simply couldn&#8217;t handle the whole dependency graph we had to deal with (or something). We had to grab a newer version from Debian backports to make the whole thing work. Another couple of hours wasted on a botched up package management system.</p>

<p>This time I&#8217;ve already wasted enough time. I&#8217;m ready to change my PHP guestbook comment import code to some XML-RPC hack instead so that I can run it on my laptop.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigsmoke.us/2010/06/21/rubygems/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PostgreSQL back-end for Ruby on Rails confusion</title>
		<link>http://blog.bigsmoke.us/2008/08/28/postgresql-back-end-for-ruby-on-rails-confusion</link>
		<comments>http://blog.bigsmoke.us/2008/08/28/postgresql-back-end-for-ruby-on-rails-confusion#comments</comments>
		<pubDate>Thu, 28 Aug 2008 14:02:09 +0000</pubDate>
		<dc:creator>halfgaar</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[postgres]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.bigsmoke.us/?p=148</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p>
I just need to add a quick summary of what postgres back-end tool our Ruby on Rails application uses, and how we&#8217;ve configured it, because it&#8217;s quite confusing&#8230;
</p>

<p>
There are four postgresql backends:
</p>

<ul>
<li>ruby-postgres. This version is no longer maintained. This is the version we used when the project began.</li>
<li>postgres-pr. This is a pure ruby implementation, which is not interesting for us.</li>
<li>postgres. This is the continuation of the unmaintained ruby-postgres. This version includes such fixes as that it can be compiled against libpg-8.3.</li>
<li>ruby-pg. It is said that this one is <a href="http://people.planetpostgresql.org/jdavis/index.php?/archives/5-ruby-pg-is-now-the-official-postgres-ruby-gem.html">now the official postgres back-end</a>, but when I install it, the application still can&#8217;t find &#8220;postgres&#8221;.</li>
</ul>

<p>
Because the aforementioned article states that the pg extension is unstable, &#8220;postgres&#8221; seems to be what we should use. The article states that it is included in the ruby-pg package, but it doesn&#8217;t work when I install it, so I had to install &#8220;postgres&#8221;. I uninstalled ruby-pg, because it doesn&#8217;t seem necessary.
</p>

<p>
To continue, we once used a patched postgresql adapter, because we needed more accurate timestamps (the standard connection adapter rounded everything off to whole seconds), but if I recall correctly, this patch was only necessary on the connection adapter in Rails, not the back-end. We never commissioned the functionality that required this, so this existed only in the workdir of one of the devs.
</p>

<p>
As a final note; on our production server, we have a version of ruby-postgres installed in /usr/local. I can&#8217;t remember why&#8230;
</p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigsmoke.us/2008/08/28/postgresql-back-end-for-ruby-on-rails-confusion/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Moved from Mnemosyne to FlashcardDB</title>
		<link>http://blog.bigsmoke.us/2008/01/14/moved-from-mnemosyne-to-flashcarddb</link>
		<comments>http://blog.bigsmoke.us/2008/01/14/moved-from-mnemosyne-to-flashcarddb#comments</comments>
		<pubDate>Mon, 14 Jan 2008 22:26:33 +0000</pubDate>
		<dc:creator>Rowan Rodrik</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[CSV]]></category>
		<category><![CDATA[flashcard]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://blog.bigsmoke.us/2008/01/14/moved-from-mnemosyne-to-flashcarddb</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p>When I was studying Spanish last year, I had to <a href="http://blog.bigsmoke.us/2007/03/02/making-flash-cards-on-line">choose a flashcard program</a> to memorize new words. At the time, I couldn&#8217;t find any on-line program that just did the job and did it well. In a <a href="http://blog.bigsmoke.us/2007/03/02/making-flash-cards-on-line#comment-7086">comment</a> on my <a href="http://blog.bigsmoke.us/2007/03/02/making-flash-cards-on-line">blog post</a> from last year, however, I was pointed by Jeff to his amazing <a href="http://flashcarddb.com/">FlashcardDB</a>.</p>

<p>The program I ended up with last year was <a href="http://mnemosyne-proj.sourceforge.net/">Mnemosyne</a>. Mnemosyne is not based on your regular <a href="http://en.wikipedia.org/wiki/Flashcard">Leitner system</a>, but rather on a concept where, after each card, you have to indicate yourself <q>how well</q> you have remembered it. I found that, in the end, having to tell the system in which box to put the card instead of just saying if my answer was right or wrong was taking me more effort than the actual recollection of the information. Also, as someone who rarely remains at one place for very long, a desktop program just isn&#8217;t as practical for me as an online program.</p>

<p style="width: 400px;"><a title="With Mnemosyne, I had to constantly remind myself of a complicated grading system." href="http://blog.bigsmoke.us/uploads/2008/01/mnemosyne-full.jpg" rel="lightbox"><img src='http://blog.bigsmoke.us/uploads/2008/01/mnemosyne1.jpg' alt='Mnemosyne' /></a><br /><small class="caption">With Mnemosyne, I had to constantly remind myself of a complicated grading system.</small></p>

<p>Now to FlashcardDB. The site is pretty social, which means that you can study (and sometimes even edit) card sets made by other users. When you sign up, you can also create card sets yourself. Card sets can be tagged and you can study these tags instead of individual card sets if you wish. If you already have cards somewhere else, import is easy as well.</p>

<p>The user interface is very slick, especially for such a new program. Thoughtful usage of AJAX means that you&#8217;re never distracted by page reloads when this would interrupt your flow of thought. Simple key bindings making studying an easier affair than in most desktop programs. The right arrow is used to show the answer, the up arrow (thumbs up) to mark the answer as correct, the down arrow (thumbs down) to mark the answer incorrect and the left arrow to go back to the previous card. Also the interface for adding cards is very pleasant. It&#8217;s just a matter of filling in the front of the card, pressing Tab, filling in the back of the card, pressing Tab, then Enter and on the next card.</p>

<p>Before going on to the conclusion, I want to add that also the Leitner system is very well implemented in FlashcardDB, including pretty diagrams to make it instantly clear to everyone how the system works. Now for my conclusion: My advice if you ever need to make flashcards yourself is that you really should take a look at <a href="http://flashcarddb.com/">FlashcardDB</a> before looking at anything else.</p>

<p>Finally, the following Ruby code is a quick hack I used to convert Mnemosyne&#8217;s XML export to CSV data which can be imported by FlashcardDB:</p>

<pre class="ruby"><span style="color:#008000; font-style:italic;">#!/usr/bin/ruby</span>
&nbsp;
<span style="color:#CC0066; font-weight:bold;">require</span> 'rexml/document'
<span style="color:#CC0066; font-weight:bold;">require</span> 'csv'
&nbsp;
xmldoc = REXML::Document.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>$stdin<span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
CSV::Writer.<span style="color:#9900CC;">generate</span><span style="color:#006600; font-weight:bold;">&#40;</span>$stdout<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> |csv|
  xmldoc.<span style="color:#9900CC;">each_element</span><span style="color:#006600; font-weight:bold;">&#40;</span>'//item'<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> |el|
    csv &lt;&lt; <span style="color:#006600; font-weight:bold;">&#91;</span>  el.<span style="color:#9900CC;">elements</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span>,'Q'<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">text</span>, el.<span style="color:#9900CC;">elements</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span>,'A'<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">text</span>  <span style="color:#006600; font-weight:bold;">&#93;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre>

]]></content:encoded>
			<wfw:commentRss>http://blog.bigsmoke.us/2008/01/14/moved-from-mnemosyne-to-flashcarddb/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Web scraping in Ruby: why I had to use scrAPI instead of WWW::Mechanize and Hpricot</title>
		<link>http://blog.bigsmoke.us/2007/05/02/scrapi-wins-over-mechanize-and-hpricot-for-web-scraping-in-ruby</link>
		<comments>http://blog.bigsmoke.us/2007/05/02/scrapi-wins-over-mechanize-and-hpricot-for-web-scraping-in-ruby#comments</comments>
		<pubDate>Wed, 02 May 2007 12:53:32 +0000</pubDate>
		<dc:creator>Rowan Rodrik</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[CSV]]></category>
		<category><![CDATA[Hpricot]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[scrAPI]]></category>
		<category><![CDATA[XPath]]></category>

		<guid isPermaLink="false">http://blog.bigsmoke.us/2007/05/02/scrapi-wins-over-mechanize-and-hpricot-for-web-scraping-in-ruby</guid>
		<description><![CDATA[Thursday evening: so, I had written myself a nice little script using Aaron Patterson's <a href="http://rubyforge.org/projects/mechanize/">WWW::Mechanize</a> and why's <a href="http://code.whytheluckystiff.net/hpricot/">Hpricot</a> to extract some data from a popular web-based airport directory.]]></description>
			<content:encoded><![CDATA[<p>Thursday evening: so, I had written myself a nice little script using Aaron Patterson&#8217;s <a href="http://rubyforge.org/projects/mechanize/">WWW::Mechanize</a> and why&#8217;s <a href="http://code.whytheluckystiff.net/hpricot/">Hpricot</a> to extract some data from a popular web-based airport directory.</p>

<img style="float: right; margin-left: 1ex; margin-bottom: .5em;" src='http://blog.bigsmoke.us/uploads/2007/04/hpricot-small.png' alt='Hpricot logo' />

<p>I was warmed up for Hpricot by the promise of XPath and CSS selector support (and a very cool logo, of course). As a long time XPath user, I started banging out some crispy XPath expressions until I realized that XPath support was only <a href="http://code.whytheluckystiff.net/hpricot/wiki/SupportedXpathExpressions"><em>very</em> partial</a>. I kept on trying expressions that <em>would</em> work, even bowing down to expressions that, according to the Wiki, would work, but <q>differently</q>. Come on guys, either support a standard or just plainly ignore it, please! <img src='http://blog.bigsmoke.us/wp-factory/wp-includes/images/smilies/icon_mad.gif' alt=':-x' class='wp-smiley' />  Because I couldn&#8217;t figure out how I&#8217;d have to integrate why&#8217;s fork of the XPath spec in my expressions, I decided to stick with why&#8217;s fork of the <a href="http://code.whytheluckystiff.net/hpricot/wiki/SupportedCssSelectors">CSS selectors</a> instead.</p>

<p>Then, it became time to execute my code. I had estimated that it would take about two hours to finish downloading and parsing the approximately 10.000 pages which contained the data in which I was interested. So, I executed my script, detached my screen session and went to bed, trusting that I would find a nice, handy CSV file in the morning.</p>

<p>Friday morning, I was disappointed to find that my script had been killed. I was left wondering what could have killed the script. I decided to restart the script at the countries starting with the letter <q>b</q> (it had died somewhere halfway the list of countries starting with a <q>b</q>). Soon the script was happily appending data again to the existing CSV file.</p>

<p class="sidenote"><b>Disclaimer:</b> why is a much more prolific Ruby coder than I&#8217;ll ever be, so please take my comments with a grain of salt. No, actually, rather take them with a few spoonfuls of salt.</p>

<p>Later, I talked about the spontaneous death of the script with <a href="http://www.halfgaar.net/">Wiebe</a>. Curious, he looked at the memory usage of my script and saw that it was happily munching away hundreds of megs of memory on our server. And memory usage was growing! With crucial server processes at the risk of running out of memory and with me having to build a circumference around the vegetable garden to protect it from a bunch of brawling chickens, Wiebe was friendly enough to drop in and take a look at my spaghetti code to see if he could fix the leak. He couldn&#8217;t, because the leak <a href="http://code.whytheluckystiff.net/hpricot/ticket/48">didn&#8217;t appear</a> to be in my code. I <a href="http://code.whytheluckystiff.net/hpricot/ticket/48">wasn&#8217;t the first</a> to be bugged by a leak in Hpricot.</p>

<p>That news didn&#8217;t make me very happy, because it implied I had to redo the script using different tools. I knew that WWW::Mechanize had been inspired by the <a href="http://search.cpan.org/dist/WWW-Mechanize/">Perl package by the same name</a>, so I started by looking at that. After installing <a href="http://search.cpan.org/dist/WWW-Mechanize/">WWW::Mechanize</a>, I explored CPAN&#8217;s <a href="http://search.cpan.org/modlist/World_Wide_Web/WWW">WWW</a> namespace a bit further and noticed that the Perl crowd also had two other good scrapers at their fingertips: <a href="http://search.cpan.org/dist/WWW-Extractor/">WWW::Extractor</a> and <a href="http://search.cpan.org/dist/Scraper/">WWW::Scraper</a>. Once again I was reminded that Perl, despite its funky syntax, is still the king of all scripting languages when it comes to the availability of quality modules. <img src='http://blog.bigsmoke.us/wp-factory/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' />   After a few deep breaths, I set my rusty Perl skill into (slow)motion. Hell, this was supposed to be a quick script. Why was this taking so much time? <small>(Yeah, yeah; cue all the jokes about developer incompetence. <img src='http://blog.bigsmoke.us/wp-factory/wp-includes/images/smilies/icon_confused.gif' alt=':-?' class='wp-smiley' />  )</small></p>

<p>I was almost stamped by a horde of camels, each with a name more syntactically confusing than the other. Just before I was crushed, I came across a reference to a Ruby scraper with decent support for CSS3 selectors: <a href="http://blog.labnotes.org/2006/07/11/scraping-with-style-scrapi-toolkit-for-ruby/">scrAPI</a>. Credits for this discovery go to the documentors of <a href="http://scrubyt.org/">scRUBYt</a>, a featurefull scraper layered on top of WWW::Mechanize. The documentation writers of scRUBYt where friendly enough to help their users by including a link to the competition.</p>

<p>It took me some time to rewrite the script using scrAPI, partially because it was hard to find any documentation that was more comprehensive than a few <a href="http://blog.labnotes.org/category/scrapi/">blog posts</a> and a <a href="http://cheat.errtheblog.com/s/scrapi/">cheat sheet</a> and less of a hassle than reading the source. But, when Assaf answered <a href="http://blog.labnotes.org/2006/07/11/scraping-with-style-scrapi-toolkit-for-ruby/#comment-137860">my need</a> by <a href="http://blog.labnotes.org/2006/07/11/scraping-with-style-scrapi-toolkit-for-ruby/#comment-137862">pointing me</a> to the online <a href="http://content.labnotes.org/rdoc/scrapi/">API docs</a>, I was happy.</p>

<p>Another reason why it was hard to migrate from WWW::Mechanize/Hpricot to scrAPI was that Hpricot starts element offsets for XPath predicates and CSS selectors at zero instead of one where they should start. And of course, I had to rid myself of the weird breed between CSS and XPath selectors.</p>

<p>I was surprised that the script using scrAPI ran about twice as fast as the Hpricot-based script. This was including a cumulative <tt>sleep()</tt> time between each request of almost an hour, because the speed during testing made me worry about over-exerting their web server. Knowing that one of the popular features of Hpricot is its speed, this was very unexpected, although I have to admit that Hpricot did fill my memory very quickly.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigsmoke.us/2007/05/02/scrapi-wins-over-mechanize-and-hpricot-for-web-scraping-in-ruby/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Nested hashes derail Rails&#8217; url_for helpers</title>
		<link>http://blog.bigsmoke.us/2007/02/19/nested-hashes-derail-rails-url-helpers</link>
		<comments>http://blog.bigsmoke.us/2007/02/19/nested-hashes-derail-rails-url-helpers#comments</comments>
		<pubDate>Mon, 19 Feb 2007 18:42:47 +0000</pubDate>
		<dc:creator>Rowan Rodrik</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[link_to]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[URL]]></category>
		<category><![CDATA[url_for]]></category>

		<guid isPermaLink="false">http://blog.bigsmoke.us/2007/02/19/nested-hashes-url-helpers-on-rails</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p>While working on the Sicirec PostgreSQL database front-end today, I had to pass a lot of nested parameters to a <tt><a href="http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#M000485">link_to</a></tt> helper in Rails. Software being what it is, this didn&#8217;t work.</p>

<p>There are a few patches awaiting acceptance. The <a href="http://dev.rubyonrails.org/ticket/4947">most promising</a> of these patches was part of an open Trac ticket. Because we use Rails as an svn external, applying the patch myself wouldn&#8217;t work when deploying unless I&#8217;d create a vendor branch for Rails in our own repository. Hoping that someone had forgotten to close the ticket, I first tried to upgrade to Rails 1.2.2, which was about time anyway because we were still in the 1.1 branch. The upgrade went fine but didn&#8217;t fix the problem.</p>

<p>Next, I tried to integrate the patch by redefining the methods changed by the patch in our <tt>lib/</tt> directory. When this didn&#8217;t work, I decided to simply do some flattening of the hash myself for this one particular case.</p>

<p>A bit of <a href="http://www.google.com/search?q=url_for+nested+hashes">googling around</a> gave me <a href="http://www.ruby-forum.com/topic/72705">many</a> <a href="http://www.railsweenie.com/forums/1/topics/131">clues</a> <a href="http://blog.bigsmoke.us/wp-admin/post.php?action=edit&#038;post=13">that</a> the problem has cost a lot of people lots of time already.</p>

<p>Eventually, I settled with a derivate of <a href="http://marklunds.com/articles/one/314">some code</a> by <a href="http://marklunds.com/">Peter Marklund</a> to flatten my hashes:

<pre class="ruby"><span style="color:#9966CC; font-weight:bold;">class</span> Hash
  <span style="color:#008000; font-style:italic;"># Flatten a hash into a flat form suitable for an URL.</span>
  <span style="color:#008000; font-style:italic;"># Accepts as an optional parameter an array of names that pretend to be the ancestor key names.</span>
  <span style="color:#008000; font-style:italic;">#</span>
  <span style="color:#008000; font-style:italic;"># Example 1:</span>
  <span style="color:#008000; font-style:italic;">#</span>
  <span style="color:#008000; font-style:italic;">#   { 'animals' =&gt; {</span>
  <span style="color:#008000; font-style:italic;">#       'fish' =&gt; { 'legs' =&gt; 0, 'sound' =&gt; 'Blub' }</span>
  <span style="color:#008000; font-style:italic;">#       'cat' =&gt; { 'legs' =&gt; 4, 'sound' =&gt; 'Miaow' }</span>
  <span style="color:#008000; font-style:italic;">#   }.flatten_for_url</span>
  <span style="color:#008000; font-style:italic;">#</span>
  <span style="color:#008000; font-style:italic;">#   # =&gt; { 'animals[fish][legs]'  =&gt; 0,</span>
  <span style="color:#008000; font-style:italic;">#          'animals[fish][sound]' =&gt; 'Blub',</span>
  <span style="color:#008000; font-style:italic;">#          'animals[cat][legs]'   =&gt; 4,</span>
  <span style="color:#008000; font-style:italic;">#          'animals[cat][sound]'  =&gt; 'Miaow'</span>
  <span style="color:#008000; font-style:italic;">#        }</span>
  <span style="color:#008000; font-style:italic;">#</span>
  <span style="color:#008000; font-style:italic;"># Example 2:</span>
  <span style="color:#008000; font-style:italic;">#</span>
  <span style="color:#008000; font-style:italic;">#   {'color' =&gt; 'blue'}.flatten_for_url( %w(world things) )  # =&gt; {'world[things][color]' =&gt; 'blue'}</span>
  <span style="color:#008000; font-style:italic;">#</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> flatten_for_url<span style="color:#006600; font-weight:bold;">&#40;</span>ancestor_names = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    flat_hash = Hash.<span style="color:#9900CC;">new</span>
&nbsp;
    each <span style="color:#9966CC; font-weight:bold;">do</span> |key, value|
      names = <span style="color:#CC0066; font-weight:bold;">Array</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>ancestor_names<span style="color:#006600; font-weight:bold;">&#41;</span>
      names &lt;&lt; key
&nbsp;
      <span style="color:#9966CC; font-weight:bold;">if</span> value.<span style="color:#9900CC;">is_a</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>Hash<span style="color:#006600; font-weight:bold;">&#41;</span>
        flat_hash.<span style="color:#9900CC;">merge</span>!<span style="color:#006600; font-weight:bold;">&#40;</span>value.<span style="color:#9900CC;">flatten_for_url</span><span style="color:#006600; font-weight:bold;">&#40;</span>names<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
      <span style="color:#9966CC; font-weight:bold;">else</span>
        flat_key = names.<span style="color:#9900CC;">shift</span>.<span style="color:#9900CC;">to_s</span>.<span style="color:#9900CC;">dup</span>
        names.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |name|
          flat_key &lt;&lt; <span style="color:#996600;">&quot;[#{name}]&quot;</span>
        <span style="color:#9966CC; font-weight:bold;">end</span>
        flat_key &lt;&lt; <span style="color:#996600;">&quot;[]&quot;</span> <span style="color:#9966CC; font-weight:bold;">if</span> value.<span style="color:#9900CC;">is_a</span>?<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#CC0066; font-weight:bold;">Array</span><span style="color:#006600; font-weight:bold;">&#41;</span>
        flat_hash<span style="color:#006600; font-weight:bold;">&#91;</span>flat_key<span style="color:#006600; font-weight:bold;">&#93;</span> = value
      <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
    flat_hash
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre>

<p>As you can see, I turned my code into a single method of the <tt>Hash</tt> class. It can be used simply in any <tt>url_for</tt> (based) call as in the following example:</p>

<pre class="ruby">url_for <span style="color:#006600; font-weight:bold;">&#123;</span>
    :controller =&gt; 'post',
    :action =&gt; 'new',
    'author' =&gt; <span style="color:#006600; font-weight:bold;">&#123;</span>'name' =&gt; 'Rowan', 'gender' =&gt; 'm'<span style="color:#006600; font-weight:bold;">&#125;</span>
  <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">flatten_for_url</span>
  <span style="color:#008000; font-style:italic;"># =&gt; /post/new?author[name]=Rowan&amp;author[gender]=m </span></pre>

<p>Now if only some Rails developer would commit <a href="http://dev.rubyonrails.org/ticket/4947">the patch</a> already.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.bigsmoke.us/2007/02/19/nested-hashes-derail-rails-url-helpers/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

