Automate your Workflow: Local WordPress Install

Lately, I’ve been pretty obsessed with streamlining my workflow, which means writing scripts (read: building tools to do stuff for me). They say that the best programmers are the laziest; I can’t vouch for being a great programmer, but I can proudly say that I am pretty lazy.

So, I’ve decided to start cleaning up my tools and posting them here as I make them. Use at your own risk!

We do a lot of WordPress sites, and downloading the latest WordPress install can be tedious. Navigating to http://wordpress.org/download/, clicking the “Download” link… Agh!! Too many clicks. Even if you’re awesome and use wget, it’s still a pain to move all those files around. So I made a script.

\#!/bin/bash

if [ -z "$1" ]; then
    echo "Usage: $0 "
    exit 1
fi

if [ -e "$1" ]; then
    echo "Pathspec '$1' exists."
    exit 1
fi

wordpresstemp="wordpress-latest-$RANDOM"
zipfile="$wordpresstemp.zip"

echo "Downloading latest WordPress..."

curl "http://wordpress.org/latest.zip" > $zipfile
unzip $zipfile -d "$wordpresstemp"/ > /dev/null
rm $zipfile

mv "$wordpresstemp"/wordpress "$1"

rm -r "$wordpresstemp"

echo "Created a new WordPress install in '$1'!"

Just save this in a file called wp_install, and put it in your $PATH directory of choice.

Also available as a gist.

Super simple:

$ cd webroot
$ wp_install new-wordpress

Done!

The AppleLanguages switch

The Google Chrome(tm) title bar in English, Japanese, Russian, and Chinese

In the past few weeks, I’ve found myself demonstrating how to do things on my computer for other people. You know, screenshots, screencasts, the like.

I ran into a small problem: Most of the people I need to teach don’t understand English.

And my default user interface is in English.

So, I ran into this little trick:

$ [path to app]/Contents/MacOS/[app name] -AppleLanguages '([language code])'

That little bit of Terminal code will launch that app in the specified language code you entered, if supported by that application. For those of you who don’t have 10 terminal windows open at any given time, don’t worry! I’ve made something for you too. 🙂

langchooser.app

Drop an app onto “langchooser”, and it will show you all the languages that app supports. Choose the language, then click “OK”.

Now, I can continue with my screenshots and screencasts without having to switch user accounts! やったー!

Anchor Links inside Facebook Apps

If you haven’t noticed, you can’t use anchor links:

<a href="#hello">Go to id="hello"</a>

Inside Facebook Apps (Page tab, Canvas app, etc). So I wrote a little snippet that emulates this behaviour by using FB.Canvas.scrollTo(x, y);

/*
anchorlinks-fbcanvas.js

Enables anchor links (<a href="#hello">Go to id="hello"</a>) in
Facebook Canvas (page tabs, canvas app, etc)

Requires: jQuery, Facebook JS SDK
*/

jQuery(function($) {
  $('a').filter(function() {
    return $(this).attr('href').match(/^#/);
  }).each(function(i, el) {
    $(el).click(function(e) {
      e.preventDefault();
      var elementId = $(el).attr('href').replace(/^#(.*)/, '$1');
      var $goTo = $(document.getElementById(elementId));
      FB.Canvas.scrollTo(0, $goTo.offset().top);
    });
  });
});

謎WordPress Part 1

There’s a Japanese word I like, “謎” – the dictionary defines it as “a mystery”, “riddle”, or “enigma” – I like to define it as “something that makes no logical sense whatever”.

Here is a part of WordPress that I think makes no logical sense whatever.

Inconsistent Naming Convention

In The Loop, as WordPress likes to call it, you are given some functions that will output information for you. Handy!

the_title(); // outputs the title of the blog post
the_content(); // outputs the content of the blog post
the_time(); // outputs the timestamp of the blog post
the_permalink(); // a "permalink" to the blog post

You get the idea. Now, you don’t want to output them? You want them in a variable? Fine:

$title = get_the_title();
$content = get_the_content();
$time = get_the_time();

BUT WAIT A SECOND.

$permalink = get_permalink();

WHAT?

WordPress, you had a great, consistent naming scheme up until then. Come on.

Thoughts about App.net

I’m sure you have heard of App.net by now. The paid, non-advertisement-supported “live social stream” (read: Twitter). They set a $500,000 goal, and raised more than $800,000 – a clear indicator that some level of demand is there for such a service.

There are two levels of membership, the $50 “User” level and the $100 “Developer” level. A developer account will give you the necessary API keys to build apps that connect to App.net. I was very interested in how these prices were chosen, and thankfully App.net published their logic (“How did you come up with the pricing tiers?” in the FAQ).

I agree with Marco Arment that $50 a year is too expensive for regular users, but he didn’t have anything to say about the developer tier. Here’s an excerpt from the FAQ that irks me:

The developer price is inspired by the amount charged by the Apple Developer Program, $99. We think this demonstrates that developers are willing to pay for access to a high quality development platform.

The decision using the Apple iOS Developer Program as inspiration for the App.net developer tier is, I believe, fundamentally flawed – there are too many differences and not enough parallels:

  • The iOS Developer Program includes hosting of your app.
  • The iOS Developer Program introduces your app to all iOS users
  • Et cetera..

For App.net to convincingly (using their present argument) charge $99 for their developer tier, I believe that the following services are necessary:

  • A central repository of App.net-enabled apps (this looks like a beta)
  • A much larger user base – there were approximately 8,000 “User” tier backers. At $1.99 (revenue of $1.40) of 20% of these users, you can expect $2,240 of gross income. With over 2,000 registered developer accounts, 20% is extremely optimistic.

Of course, if you believe that App.net will balloon, the developer tier is moderately priced. Otherwise, it’s just another lucrative investment.

(Yes, I did back App.net)

Becoming a better PHP developer

There’s no denying that PHP is not the optimal language. But at least code in good PHP. Here’s my pet peeve for the day:

Relative paths in include(_once)? or require(_once)? statements.

// WRONG
require_once("./include_me.php");
// RIGHT
require_once(dirname(__FILE__) . "/include_me.php");

Why? Basically, performance. PHP doesn’t look through all its search paths for absolute paths, saving those precious system calls. This effect is compounded when you’re using the APC cache with apc.stat = 0 (it won’t even cache files that are referred to with a relative path)