About Me

Migrating to Hugo

I have been meaning to move away from Wordpress to a static site generator for a very long time, due to:

  • The slowness of WP, since every page request makes multiple database calls due to the spaghetti code nature of WP and its plugin architecture. Caching can help somewhat, but it has brittle edge cases.
  • Its record of security holes. I mitigated this somewhat by isolating PHP as much as possible.
  • It is almost impossible to follow front-end optimization best-practices like minimizing the number of CSS and JS files because each WP plugin has its own

My original plan was to go with Acrylamid, but about a year ago I started experimenting with Hugo. Hugo is blazing fast because it is implemented in Go rather than a slow language like Python or Ruby, and this is game-changing. Nonetheless, it took me over a year to migrate. This post is about the issues I encountered and the workflow I adopted to make it work.

Wordpress content migration

There is a migration tool, but it is far from perfect despite the author’s best efforts, mostly because of the baroque nature of Wordpress itself when combined with plugins and an old site that used several generations of image gallery technology.

Unfortunately, that required rewriting many posts, specially those with photos or embedded code.

Photo galleries

Hugo does not (yet) support image galleries natively. I started looking at the HugoPhotoSwipe project, but got frustrated by bugs in its home-grown YAML parser that broke round-trip editing, and made it very difficult to get galleries with text before and after the gallery proper. The Python-based smartcrop for thumbnails is also excruciatingly slow.

I wrote hugopix to address this. It uses a simpler one-way index file generation method, and the much faster Go smartcrop implementation by Artyom Pervukhin.

Broken asset references

Posts with photo galleries were particularly broken, due to WP’s insistence on replacing photos with links to image pages. I wrote a tool to help me find broken images and other assets, and organize them in a more rational way (e.g. not have PDFs or source code samples be put in static/images).

It also has a mode to identify unused assets, e.g. 1.5GB of images that no longer belong in the hugo tree as their galleries are moving elsewhere.

Password-protected galleries

I used to have galleries of family events on my site, until an incident where some Dutch forum started linking to one of my cousin’s wedding photos and making fun of her. At that point I put a pointed error message for that referrer and controlled access using WP’s protected feature. That said, private family photos do not belong on a public blog and I have other dedicated password-protected galleries with Lightroom integration that make more sense for that use case, so I just removed them from the blog, shaving off 1.5GB of disk in the bargain.

There are systems that can provide search without any server component, e.g. the JavaScript-based search in Sphinx, and I looked at some of the options referenced by the Hugo documentation like the Bleve-based hugoidx but the poor documentation gave me pause, and I’d rather not run Node.js on my server as needed by hugo-lunr.

Having recently implemented full-text search in Temboz using SQLite’s FTS5 extension, I felt more comfortable building my own search server in Go. Because Hugo and fts5index share the same Go template language, this makes a seamless integration in the site’s navigation and page structure easy.


There is no avoiding this, moving to a new blogging system requires a rewrite of a new theme if you do not want to go with a canned theme. Fortunately, Hugo’s theme system is sane, unlike Wordpress’, because it does not have to rely on callbacks and hooks as much as with WP plugins.

One pet peeve of mine is when sites change platform with new GUIDs or permalinks in the RSS feeds, causing a flood of old-new articles to appear in my feed reader. Since I believe in showing respect to my readers, I had to avoid this at all costs, and also put in place redirects as needed to avoid 404s for the few pages that did change permalinks (mostly image galleries).

Doing so required copying the embedded RSS template and changing:

<guid>{{ .Permalink }}</guid>


<guid isPermaLink="false">{{ .Params.rss_guid | default .Permalink }}</guid>

The next step was to add rss_guid to the front matter of the last 10 articles in my legacy RSS feed.

Racking up the miles

In November, I have flown from San Francisco to London, back to San Francisco, on to Auckland, Queenstown, Wellington, Auckland, back to San Francisco, Houston, back to Oakland. When combined with my upcoming trip to Bombay, I will have traveled 70,000 kilometers, or nearly twice the circumference of the Earth…

Breakfast of Popes

When I was a kid living in the forsaken wasteland that is Saudi Arabia, my father’s company would pay for one trip back to France each year. One treat my parents would give us on those trips back home, my brother and I, would be to take us to a café and get us each one of those old-fashioned teardrop-shaped bottles of Orangina. To this day, I still associate it with the taste of home.

At one point ten years ago, the owners of Orangina had agreed to sell it to Coca-Cola. This naturally raised an uproar and the deal was axed on antitrust grounds. Unfortunately, the brand has not been very well managed or marketed since and has lost much of its market share in France.

The chief quality of Orangina is that it is made with 14% fruit, unlike the synthetic garbage Coca-Cola or Pepsi sell, e.g. Fanta. It is interesting to note that in Italy, all fruit sodas are required by law to have at least 12.5% fruit content, so even Fanta is actually drinkable there.

One Italian resident who was a fan of Orangina is Mgr Ratzinger, now known as Pope Benedict XVI. At the end of his day’s work, prior to being elevated as Pope, he used to walk back home, stopping for the odd photo pose at the request of passing tourists, return to his apartment, enjoy a glass of Orangina and play Mozart on the piano for half an hour.

She said Yes

I flew into London today. I took the adorable Shaheen B. to dinner at The Ledbury.

Between courses, I asked her to marry me. She said Yes. The only plausible explanation for this lapse in judgement is temporary insanity. I couldn’t be happier.

P.S. the ring is guaranteed to be De Beers-free and not a blood diamond, courtesy of the nice folks at Brilliant Earth, who by the greatest of coincidences are just across the street from my office.

Acxiom acquires Kefta

Acxiom + KeftaI guess it’s official now. Acxiom acquired my company, Kefta, last week. Acxiom is very discreet, but influential company, with a strong technical focus — how many public company CEOs do you know who are listed as inventors on their company’s patents? The other founders and myself came to the conclusion a merger will allow us to serve our customers better, ramp up our sales to capitalize on an exploding market and enhance our infrastructure, something that would have beeen much harder if we stayed independent.

Due to confidentiality reasons, I cannot give much more specifics, but Kefta was my first startup. I thought I would have mixed feelings letting it go (I am staying on board, of course, but in a different role now). That has not turned out to be the case, however. We started in 2000, a mere two months before the bottom fell out of the market, and managed not just to survive, but to recover and thrive. At the moment, I am too excited considering the possibilities to wax nostalgic. There might be a few bumps down the road for this blog as I now have to extricate my personal web presence from Kefta’s machines (my new hosting platform is a Solaris-powered Joyent accelerator).

Update (2007-05-16):

It seems I was acquired again. Once is good fortune, twice is negligence…