Ruby/WordPress

Too long? tl;dr.

Situation: You’re migrating a big site to WordPress. You don’t want to make 1,000+ posts manually, do you?

Meet Ruby/WordPress. I’ve made a quick little Ruby gem that interfaces with your WordPress database, so you can manipulate it within Ruby. This opens up a whole world of possibilites – the most exciting being Nokogiri, of course.

Here’s a quick code sample that will create 100 new posts!

require 'wordpress'

# Configuration
wp = WordPress.new { host: '127.0.0.1',
                     port: 3306,
                     username: 'test',
                     password: 'test',
                     encoding: 'utf8',
                     database: 'wordpress',
                     wordpress_prefix: 'wp_' }

(1..100).each do |i|
  post = wp.new_post { post_name: "post-#{i}",
                       post_status: 'publish',
                       post_title: "Post #{i}" }
  post.post_content = "This is the content for post #{i}"
  post.save!
end

Note that the configuration must point to a valid WordPress database (and make sure you don’t use one with valuable data… I don’t take responsibility for any lost data. You should be backing up anyways.)

It’s at version 0.0.2, a very early beta at this point, but it can do basic tasks such as creating posts (as shown before) and post querying (albeit, very basic at this stage in development):

wp.query( post__in: [ 1, 5, 8] ).each do |post|
  puts "Post: #{ post.post_title }n"
end
wp.query( post_type: 'custom_post_type', post_parent: 10 ).each do |post|
  puts "Post: #{ post.post_title }n"
end

The ultimate goal of WordPress#query is to be fully compatible with the WP_Query API.

Another feature is post meta manipulation. After you get your post object (WordPress::Post), getting or setting post meta is very easy:

post.post_meta['hello'] = 'world'
puts post.post_meta['hello'] + "n"

Initial support for taxonomies is also included:

puts post.get_the_terms('category').join(', ') + "n"
post.set_post_terms ['love', 'WordPress'], 'category'

Note: WordPress::Post#set_post_terms will overwrite all terms of the given taxonomy, unless you supply the “append” flag:

post.set_post_terms ['love', 'WordPress'], 'category', true

As you can probably tell, this is not a very ideal API, and I am planning on changing it soon.

Contribution

Contributions are very welcome!! If you have an idea, or something that you would like to contribute, but don’t feel like you have something concrete enough for a pull request yet, please don’t hesitate to open an issue or contact me directly.

How to Install

Ruby/WordPress can be installed via RubyGems:

$ gem install ruby-wordpress

or, if you use Bundler:

gem 'ruby-wordpress', :require => 'wordpress'

Links:

Ruby 2.0.0 p195 PSA

In Ruby 2.0.0 patchlevel 195, you can no longer mix old- and new-style hash syntaxes in method arguments.

For example:

Wrong

method hello: 'there', :goodbye => 'goodnight'

Right

method { hello: 'there', :goodbye => 'goodnight' }

or

method :hello => 'there', :goodbye => 'goodnight'

Apparently this has been fixed in another patch to Ruby 2.0.0, but that doesn’t really matter, since p195 is out right now.

Source: https://gist.github.com/stephencelis/5595842

My Experiences with Rubinius

Rubinius is an implementation of the Ruby language spec. I’ve been using it recently for a project, and I’ve been liking it so far. Here’s a few thoughts I’ve been having while using it.

Philosophy

The Core

Rubinius, in its core, is written in C++ and uses LLVM (Low Level Virtual Machine). Without getting too technical, it translates the Ruby code that you write into efficient machine code, then executes the machine code directly on the CPU. This architecture is very similar to Google’s V8 (and one of the reasons that Google Chrome is a fast browser).

The Concept

Now for the concept of “Ruby”. “Ruby” is a programming language specification, not a program or compiler. The standard reference implementation is called MRI (Matz’s Ruby Interpreter, not magnetic resonance imaging). MRI is used in many production environments, and especially with the latest 2.0.0 release, introduces many performance improvements, and is very stable (all of our new Rails apps are on 2.0.0).

MRI is written mostly in C.

Rubinius’ tagline “Rubinius: Use Ruby™” summarizes the intent of Rubinius. Use Ruby! Because the Rubinius core is as fast as it is, and Ruby code is basically machine code (from the computer’s standpoint), standard libraries – the basic functions of the language – can be written in Ruby. Use Ruby!!

Speed

In development, Rubinius seems to be a little slower than MRI – especially in the first load. Rails is a big library.

In production, especially with a threaded app server (Rubinius has no “Global Interpreter Lock” and supports real threads), however, Rubinius is extremely fast. I’ve been using Puma.

You do need to write thread-safe code, but the payoffs are enormous.

Conclusion

This little project I’m working on will probably not see a “real production” environment anytime soon, so I really wanted to try out some alternative Rubies (there are a few). All in all, my experience with Rubinius has been very good. Can’t wait for the production release of Rubinius!

WordPress Install Script pt. 2

A week ago, I posted Automate your Workflow: Local WordPress Install with a script that helps you install new WordPress installations. I’ve been using it regularly, and have made some improvements:

  • Multi-language support (install a different language with the -l switch)
  • Nightly build support (-v nightly)
  • Multi-version (-v {code in the 'Version' column})
  • Arbitrary URL support (-u {URL})

As always, the script is available as a gist.

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 (langchooser.app)

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.