Tip Jar Archives, page 2

Posts so helpful you might be compelled to tip me.

Random Custom Fields

The latest version is 1.0, released February 24, 2009, compatible with WordPress v2.7 (and probably 2.6)

WordPress logoThis is an esoteric WordPress plugin (and widget) that will randomly extract one or more custom fields from your posts and display them in a format of your choosing.

For example if you’ve stored geographic coordinates (longitude and latitude) for your posts in a custom field, you can use this plugin to randomly generate a link to Google Maps. Perhaps you could even generate a random embedded Google Map centered on that spot. I know that some people use Custom Fields to store images with special meanings. They could use this plugin to randomly display an image linking back to the post it came from, similar to my Random Image Plugin.


This is not a sexy plugin, but it just might save the day. Here’s a screenshot of the admin interface.

Random Custom Fields screenshot


  1. Download and unzip random-custom-fields-1.0.zip (v1.0)
  2. Upload the file random-custom-fields.php to your plugins directory:


  3. Activate the plugin (don’t forget!)
  4. If your theme is widget-enabled, goto Design > Widgets and add “Random Custom Fields” to your sidebar
  5. If your theme is not widget-enabled, edit the index.php or sidebar.php template file in your theme’s directory:


    and add the following line of code where you want a random custom fields to appear:

    <?php random_custom_fields(); ?>

  6. Configure the plugin from within WordPress under Settings > Random Custom Fields


The <?php random_custom_fields(); ?> function can take 9 optional parameters in between its parentheses. If you specify any parameters this way, all settings made through the configuration interface will be ignored. Note: this behavior could be useful if you wanted to have several different random custom fields each with different settings appearing throughout your site.

<?php random_custom_fields(custom_field_name,
                           category_filter); ?>
  1. custom_field_name is a required string that determines which custom field name to display.
  2. include_posts is a boolean (default is true) that determines whether to pull custom fields from posts.
  3. include_pages is a boolean (default is false) that determines whether to pull custom fields from pages.
  4. sort_randomly is a boolean (default is true) that determines whether to pull custom fields from posts in random order, or in date descending order.
  5. count is an integer (default is 1) that determines how many custom fields to display.
  6. value_separator is a string (default is newline) that allows you to break up the custom field value into multiple pieces for use in the html_template.
  7. html_template is a string (default is %0) that determines how the plugin should display the custom field. There are several variables that the plugin can output by default, including %title, %permalink, and %excerpt, all from post of the custom field. The variable %0 will be replaced with the entire custom field value. If you’ve entered a custom value_separator (default is a newline) the variables %1, %2, %3, etc will be replaced with each piece of the custom field value divided by the value_separator delimiter.
  8. html_between_templates is a string (default is <br /><br />) that gets printed between custom fields if the count parameter is greater than 1.
  9. category_filter is a comma-separated list of category or tag ids (default is blank) that limits the custom fields posts within certain categories or tags.

Questions, comments, and suggestions are always welcome. If you’re interested in contributing to the code behind Random Custom Fields, it’s hosted on GitHub.

Ubuntu Home Server FAQ

Basically this is the stuff I can’t remember how to do when I’m setting up Ubuntu as a backup server. Tested with Ubuntu Server 8.04.1 (Hardy Heron).

How do I turn off the dang bell (aka PC speaker beep)?

sudo rmmod pcspkr
sudo vi /etc/modprobe.d/blacklist

Then add:

blacklist pcspkr

How do I make arrow keys work in vi?

sudo apt-get install vim

How do I configure Ubuntu to have a static IP address?

sudo vi /etc/network/interfaces

Then replace:

auto eth0
iface eth0 inet dhcp


auto eth0
iface eth0 inet static

Note: This assumes your router’s (aka gateway’s) IP address is and you want to assign a static IP of

Finally run:

sudo /etc/init.d/networking restart

How do I install an SSH server?

sudo apt-get install openssh-server

How do I find out information about my processor (CPU)?

cat /proc/cpuinfo

How do I find out my external USB drive’s device location?

sudo fdisk -l

How do I manually mount an external USB drive?

sudo mkdir /media/usb0
sudo mount /dev/sdb1 /media/usb0

Note: Your USB drive may have been assigned a different device location than /dev/sdb1. Use sudo fdisk -l to find out.

How do I format an external USB drive?

sudo mkfs.ext3 /dev/sdb1

Note: Be very careful with this command. Make sure you have the correct device location.

Broken blog = man obsessed

Databases are supposed to be these monolithic paragons of correctness and uniformity. So it’s a little unsettling to discover a database that returns grossly incorrect results. At least I wouldn’t expect WordPress to put version 5 of MySQL through its paces.

Here’s the scenario. Dreamhost, my webhost, is running MySQL Server v5.0.24a, released in August 2006. On my laptop I’m running MySQL Server v5.0.51a, released in January 2008. The difference between the two is a year and a half of bugfixes and performance improvements.

On each I’ve got a copy of the same database table, wp_posts, from my WordPress 2.5.1 install for Justinsomnia. And on each system I’ve got a copy of the giant SQL select statement generated by WordPress that returns the first 8 blog posts that should appear on my homepage. The unusual thing about this particular query is that it contains an insanely long NOT IN () list to filter out my neatlinks from the main column.

FROM wp_posts  
WHERE 1=1  
AND wp_posts.ID NOT IN ('876', '877', '878', '879', '880'...'5456', '5458', '5460', '5461', '5462', '5463') 
AND wp_posts.post_type = 'post' 
AND (wp_posts.post_status = 'publish') 
GROUP BY wp_posts.ID 
ORDER BY wp_posts.post_date DESC 
LIMIT 0, 8

The problem is that running the same SQL statement on each server returns different results—and I wanted to figure out why.

So I prefixed the query with EXPLAIN, to see what each version of MySQL would tell me about how they were dealing with the same query. I expected the results to be the same. They turned out to be quite different.

MySQL 5.0.24a:
| id | select_type | table    | type  | possible_keys                        | key     | key_len | ref  | rows | Extra                                        |
|  1 | SIMPLE      | wp_posts | range | PRIMARY,post_status,type_status_date | PRIMARY | 4       | NULL |  611 | Using where; Using temporary; Using filesort |

MySQL 5.0.51a:
| id | select_type | table    | type | possible_keys                        | key              | key_len | ref         | rows | Extra       |
|  1 | SIMPLE      | wp_posts | ref  | PRIMARY,post_status,type_status_date | type_status_date | 25      | const,const | 5350 | Using where | 

As you scroll to the right, you can see that v5.0.24a chose the PRIMARY key to find the most recent posts, while v5.0.51a opted for type_status_date. I’m not quite sure what that means, except that v5.0.24a obviously made the wrong choice. Which gave me an idea for an interim solution (while I wait for Dreamhost to upgrade MySQL): index hints.

If I could force MySQL to ignore the PRIMARY key, maybe it would “fix” my blog. So I added IGNORE INDEX (PRIMARY) to the query that selects posts, and voila, my blog homepage started working again! Here’s the diff of the code change I made. Luckily I have WordPress “installed” via Subversion, so any changes I make to core files get carried over with each upgrade.

Index: wp-includes/query.php
--- wp-includes/query.php	(revision 7987)
+++ wp-includes/query.php	(working copy)
@@ -1424,7 +1424,7 @@
 		if ( !empty($limits) )
 			$found_rows = 'SQL_CALC_FOUND_ROWS';
-		$request = " SELECT $found_rows $distinct $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits";
+		$request = " SELECT $found_rows $distinct $fields FROM $wpdb->posts IGNORE INDEX (PRIMARY) $join WHERE 1=1 $where $groupby $orderby $limits";
 		$this->request = apply_filters('posts_request', $request);
 		$this->posts = $wpdb->get_results($this->request);

Hopefully I haven’t inadvertently broken some other aspect of my blog. If anyone sees anything out of order, please leave a comment, mmmk?

Update: for Nate, here’s the EXPLAIN on 5.0.24a with the IGNORE INDEX:

| id | select_type | table    | type | possible_keys                | key              | key_len | ref         | rows | Extra                                        |
|  1 | SIMPLE      | wp_posts | ref  | post_status,type_status_date | type_status_date | 25      | const,const | 5351 | Using where; Using temporary; Using filesort |

The WordPress SQL Executioner

WordPress logoIf I had a dime for every time someone said “WordPress Suicide is great, but I only want to delete posts that are more than a year old,” I’d probably have 50¢. Which is about when I start to think about solving the problem with a new plugin.

The programmer/database jockey in me knows the request above is insanely easy. Just open up a terminal, connect to my WordPress database with the MySQL client, and fire off the following query:

delete from wp_posts 
where post_date < date_sub(curdate(), interval 1 year)

Of course knowing SQL takes experience, but the first barrier for most people is just getting command line access to their WordPress database (especially on shared hosts). I figured if it was easier for the average WordPress user to gain direct access to their database from within the admin interface, it’d be a whole lot easier for me to help them, by giving them custom one-off SQL queries to run. And oh by the way, this would be pretty awesome for the power user.

So that’s what I did, I built a stripped-down phpMyAdmin in the form of a WordPress plugin—“wpMyAdmin”, if you will—though in the end I opted to name it the more ominous-sounding: SQL Executioner. Here’s a screenshot to give you an idea of what I’m talking about:

Screenshot of the SQL Executioner for WordPress

Screenshot of the SQL Executioner

Simply enter your SQL query and click “Execute SQL”. It behaves a lot like a web-based version of the MySQL command line client. If you enter a SELECT, DESCRIBE, SHOW, or EXPLAIN query, an HTML table will be returned with your results. If it’s any other command that modifies the data or structure of your database, you’ll get a message about the number of rows affected. You’ll have one chance to confirm that you want to execute an INSERT, UPDATE, DELETE, or ALTER, but after that, your blog’s fate is in your hands. Good luck.

The tables listed above the SQL textbox are shortcut references to all the tables in your database. This makes it possible to write a generic SQL query with variables in place of the actual table names so that it’ll work on any WordPress install, regardless of the table prefix (it’s usually wp_). Of course the actual table names with prefixes are accepted. For example, the query above could be rewritten as:

delete from $posts 
where post_date < date_sub(curdate(), interval 1 year)

Finally one handy bonus feature, if you click on any of the table names in the list, it will automatically describe the table for you.


  1. Download SQL Executioner v1.2 from the WordPress.org Plugin Directory (or from me here)
  2. Unzip the file and upload the sql-executioner folder to your wp-content/plugins/ directory
  3. Activate the plugin
  4. Go to Tools > SQL Executioner and have fun querying!

Questions, comments, and suggestions are always welcome. If you’re interested in contributing to the code behind the SQL Executioner, it’s hosted on GitHub.

I can never remember how to create a new MySQL user

Anyway, here’s the mother-lovin’ SQL all in one place:

create database db_name;
grant all on db_name.* to 'user_name'@'localhost' identified by 'password';
flush privileges;

For simple, personal projects, db_name = user_name = password, just to make life a little easier.

Carry on.