Archive for the ‘WordPress’ Category.

One of the new things in 3.1 that hasn’t got a lot of discussion yet is the new Advanced Taxonomy Queries mechanism. At the moment, this is still being actively developed, but the basic structure is finalized enough to give at least a semi-coherent explanation on how to use it. Since 3.1 is now going into beta, it’s unlikely to change much.

What’s a Query?

In WordPress land, a “query” is anything that gets Posts. There’s a lot of ways to do this.

  • You can use query_posts to modify the main query of the page being displayed.
  • You can create a new WP_Query, to get some set of posts to display in its own custom Loop.
  • You can do a get_posts to get some limited set of posts for display in some special way.

Regardless of the method, you have to pass parameters to it in order to specify which posts you want. If you’ve used this at all before, then you’ve used parameters like cat=123, or tag=example, or category_name=bob and so forth. When custom taxonomies were developed, you were eventually able to specify things like taxonomy=foo and term=bar and so on.

Querying for Posts

The problem with these is that people sometimes want to specify more than one of these parameters, and not all parameters worked well together. Things like cat=a and tag=b, or cat=a and tag is not b, and so forth. This is because cat and tag are both forms of taxonomies, and the code didn’t handle that well. Sure, some of it worked, for specific cases, but those were mostly there by accident rather than by design. In other words, those cases worked because the system just happened to get it right for that particular instance.

Well, all these old methods still work, but they have been made into a more comprehensive system of generically specifying arbitrary taxonomies to match against. When you specify cat=123, it’ll actually be converting it to this new method internally.

Query Strings are for Suckers

One side effect of this new system is that it doesn’t really work with query strings very well. It can be done, but it’s a lot easier and more sensible if you just start getting into the array method of doing things instead. What’s the array method? I’ll explain:

Imagine you used to have a query that looked like this:

query_posts('cat=123&author=456');

A simple query, really. The problem with it is that WordPress has to parse that query before it can use it. But there is another way to write that query as well:

query_posts(array(
  'cat' => 123,
  'author' => 456,
) );

Essentially, you separate out each individual item into its own element in an array. This actually saves you some time in the query because it doesn’t have to parse it (there’s very little savings though).

The advantage of this is that you can build your arrays using any method of array handling you like. Here’s another way to do it:

$myquery['cat'] = 123;
$myquery['author'] = 456;
query_posts($myquery);

Simple, no? But what if you have to deal with the $query_string? The $query_string is that old variable that is built by WordPress. It comes from the “default” query for whatever page you happen to be on. One of the main uses for it was to deal with “paging”. A common method of doing it was like this:

query_posts($query_string . '&cat=123&author=456');

If you use arrays, you have to deal with that yourself a bit. There’s a couple of possible ways to do it. The easiest is probably to just parse the query string yourself, then modify the result as you see fit. For example:

$myquery = wp_parse_args($query_string);
$myquery['cat'] = 123;
$myquery['author'] = 456;
query_posts($myquery);

I started out with the $query_string, used wp_parse_args to turn it into an array, then overwrote the bits I wanted to change and performed the query. This is a handy technique I’m sure a lot of people will end up using.

On to Advanced Taxonomies

Advanced Taxonomy queries use a new parameter to the query functions called “tax_query”. The tax_query is an array of arrays, with each array describing what you want it to match on.

Let’s lead by example. We want to get everything in the category of “foo” AND a tag of “bar”. Here’s our query:

$myquery['tax_query'] = array(
	array(
		'taxonomy' => 'category',
		'terms' => array('foo'),
		'field' => 'slug',
	),
	array(
		'taxonomy' => 'post_tag',
		'terms' => array('bar'),
		'field' => 'slug',
	),
);
query_posts($myquery);

Here we’ve specified two arrays, each of which describes the taxonomy and terms we want to match it against. It’ll match against both of them, and only return the results where both are true.

There’s two things of note here:

First is that the “field” is the particular field we want to match. In this case, we have the slugs we want, so we used “slug”. You could also use “term_id” if you had the ID numbers of the terms you wanted.

Second is that the “terms” is an array in itself. It doesn’t actually have to be, for this case, as we only have one term in each, but I did it this way to illustrate that we can match against multiple terms for each taxonomy. If I used array(‘bar1′,’bar2′) for the post_tag taxonomy, then I’d get anything with a category of foo AND a tag of bar1 OR bar2.

And that second item illustrates an important point as well. The matches here are actually done using the “IN” operator. So the result is always equivalent to an “include” when using multiple terms in a single taxonomy. We can actually change that to an “exclude”, however, using the “operator” parameter:

$myquery['tax_query'] = array(
	array(
		'taxonomy' => 'category',
		'terms' => array('foo', 'bar'),
		'field' => 'slug',
		'operator' => 'NOT IN',
	),
);
query_posts($myquery);

The above query will get any post that is NOT in either the “foo” or “bar” category.

But what about terms across multiple taxonomies? So far we’ve only seen those being AND’d together. Well, the “relation” parameter takes care of that:

$myquery['tax_query'] = array(
	'relation' => 'OR',
	array(
		'taxonomy' => 'category',
		'terms' => array('foo'),
		'field' => 'slug',
	),
	array(
		'taxonomy' => 'post_tag',
		'terms' => array('bar'),
		'field' => 'slug',
	),
);
query_posts($myquery);

This gets us anything with a category of foo OR a tag of bar. Note that the relation is global to the query, so it appears outside the arrays in the tax_query, but still in the tax_query array itself. For clarity, I recommend always putting it first.

Useful Gallery Example

By combining these in different ways, you can make complex queries. What’s more, you can use it with any taxonomy you like. Here’s one I recently used:

$galleryquery = wp_parse_args($query_string);
$galleryquery['tax_query'] = array(
	'relation' => 'OR',
	array(
		'taxonomy' => 'post_format',
		'terms' => array('post-format-gallery'),
		'field' => 'slug',
	),
	array(
		'taxonomy' => 'category',
		'terms' => array('gallery'),
		'field' => 'slug',
	),
);
query_posts($galleryquery);

This gets any posts in either the gallery category OR that have a gallery post-format. Handy for making a gallery page template. I used the wp_parse_args($query_string) trick to make it able to handle paging properly, among other things.

Speed Concerns

Advanced taxonomy queries are cool, but be aware that complex queries are going to be slower. Not much slower, since the code does attempt to do things smartly, but each taxonomy you add is the equivalent of adding a JOIN. While the relevant tables are indexed, joins are still slower than non-joins. So it won’t always be a good idea to build out highly complex queries.

Still, it’s better than rolling your own complicated code to get a lot of things you don’t need and then parsing them out yourself. A whole lot easier too.

Shortlink:

Saw a few tweets by @lastraw today, asking Matt and others if they could make the Add Audio function in the WordPress editor work.

Well, @lastraw, the audio function does actually work, it just doesn’t do what you expect it to do.

Basically, the WordPress uploader does provide a few different kinds of uploader buttons: image, video, audio, and media. All of these buttons behave in different ways. The Audio button in particular lets you upload an audio file, and then insert a link to that file in your post.

WordPress upload buttons in the post editor

However, the link it inserts is just a bare link. This is because WordPress doesn’t come with a flash audio player, and HTML 5 hasn’t gotten standard enough to allow sane use of the <audio> tags.

Still, plugins can modify things to make audio files embed. I just wrote a quick plugin to take those bare audio links and turn them into embedded audio players using Google’s flash audio player. This is the same player they use on Google Voice and in several other locations in the Google-o-sphere.

Example:

Example Audio File

How did I do that? Easy, I activated my plugin, then used the Add Audio button to just insert the plain link to my audio file (which I uploaded). Naturally, this audio player will only show up on your site. People reading through an RSS reader or some other method won’t see it, they’ll just see the plain audio link and can download the file.

Couple limitations on this: It only handles MP3 formats. You could conceivably use a player that could handle more formats, I only made this as an example. MP3 is the most common format in use anyway, and I didn’t want to go searching for a more complicated player to use. Also, I made it only handle links on lines by themselves. If you put an audio link inline into a paragraph or something, it won’t convert it.

Here’s the plugin code if you want to use it or modify it or whatever. It’s not the best code in the world, but then it only took 5 minutes to create, so what do you expect? ;)

<?php
/*
Plugin Name: Google MP3 Player
Plugin URI: http://ottodestruct.com/
Description: Turn MP3 links into an embedded audio player
Author: Otto
Version: 1.0
Author URI: http://ottodestruct.com
*/

add_filter ( 'the_content', 'googlemp3_embed' );
function googlemp3_embed($text) {
	// change links created by the add audio link system
	$text = preg_replace_callback ('#^(<p>)?<a.*href=[\'"](http://.*/.*\.mp3)[\'"].*>.*</a>(</p>|<br />)?#im', 'googlemp3_callback', $text);

	return $text;
}

function googlemp3_callback($match) {
	// edit width and height here
	$width = 400;
	$height = 27;
	return "{$match[1]}
<embed src='http://www.google.com/reader/ui/3523697345-audio-player.swf' flashvars='audioUrl={$match[2]}' width='{$width}' height='{$height}' pluginspage='http://www.macromedia.com/go/getflashplayer'></embed><br />
<a href='{$match[2]}'>Download MP3 file</a>
{$match[3]}";
}

This is mainly intended as a demo. There’s more full featured plugins for this sort of thing in the plugins directory. If you need to embed audio, using one of them might be a better way to go.

Shortlink:

A lot of people have been debating back and forth lately about post formats and custom post formats. This discussion also gets all confused with post types, and custom taxonomies, and categories, and tags… It’s time for some clarity. Mark had a really good post on the topic, but I think this needs to be explored in more detail.

Also, can’t have a good explanation without a bad analogy. I mean, this is the internet, right? So I should probably try to relate it to cars somehow.

A Post Type as a Car

Okay, so let’s say we have a post type. It’s called “car”. Anything that even vaguely resembles a car (including trucks, SUVs, jeeps, fire engines) gets lumped together in this post type.

We can categorize cars by type: Truck. Van. Hummer. Ford. Whatever.

We can add tags to cars: Four-door. Premium-sound. 6-disc-changer. Etc.

We can come up with custom taxonomies for them: A Color taxonomy could contain red, blue, black, silver, white, brown, etc.

The point here is that the post type is the thing itself, the various taxonomies are merely descriptions of it. You wouldn’t have both a “car” and a “truck” post type, because those are the same type of thing. If you prefer to be generic, you could make your post_type into “automobile”, which sorta fits both. That’s just a matter of naming choice.

Post types are NOUNS. Taxonomy terms are ADJECTIVES. Taxonomies themselves are related groups of adjectives.

This is why people using post types for things like Podcasts or Comic Strips or Video or something else are just fundamentally wrong. They’re using different nouns to describe the same thing, when they should be using the adjectives to sort out what those things are.

Displaying Different Things Differently

Historically with WordPress, categories have been used for more than just ways to classify posts. They’ve often been used to define different ways of displaying something.

The classic example is an “aside”. An aside has been traditionally defined as, basically, a short form post. Matt loves asides and he uses them far more often than long format posts:

A couple of aside posts on ma.tt

A couple of aside posts on ma.tt

Matt also uses a special format for his gallery posts:

One of ma.tt's gallery posts

One of ma.tt's gallery posts

Compare these to his normal long format posts:

A normal long format post on ma.tt

A normal long format post on ma.tt

You can easily see some of the differences. Asides don’t display a title. Galleries display a photo on the left hand side and the title is shortened and to the right. Long format posts have that double line underneath them, and also show the categories (essays in the above case).

The way he does these, and the way they have traditionally been done in WordPress in the past, is to co-opt categories. So he has an “Asides” category, and a “Gallery” category. In the code for his theme, he then has code that looks kinda like this:

if (in_category('asides')) {
   // stuff to display the aside format post here
} else if (in_category('gallery')) {
   // stuff to display the gallery format post here
} else {
   // code to display the normal format post here
}

Then, when he makes a post, he just picks the right category for it and that changes how it shows up on the site.

The problem is that this is a bit lame. Categories should be adjectives describing the post, not sorting them into functionally different buckets for use by the theme. Sure, you can use them that way, but that’s confusing to some users. You could use tags in the exact same way with the has_tag() function, but that doesn’t make it a good idea.

Post Formats (coming soon to a WordPress 3.1 near you)

Enter Post Formats. Tumblr has had these for a long time:

Tumblr's post formats

Tumblr's post formats

Basically they just define a format for a post to fit into at display time. So the theme could say “asides won’t have a title displayed for them”, and voila. A theme can do something like this to define what formats it supports:

add_theme_support( 'post-formats', array( 'aside', 'gallery' ) );

And it can do something like this when displaying things differently:

if ( has_post_format( 'aside' ) ) {
   // display the aside format
}

So there we go. Theme authors can define what formats they support, and they can style those formats appropriately. And we didn’t use categories at all.

Additional: For those people trying to implement this in themes, post formats also add new styles to the post_class() call. You can use .format-XXX to style based on post formats on a post.

Custom Post Formats and why you don’t need them

As soon as this was announced, naturally theme authors got up in arms, because theme authors are a rowdy bunch of folks. They like to do things their own way. So there was instantly the question of “how do I add my own format”? The answer is: you don’t, nor should you even think about it.

Why? Why prevent customization? Think of it from the perspective of the user:

  • They’ve got an existing set of posts.
  • Those posts have formats.
  • They switch to your theme, which uses some custom formats.
  • Now their own posts don’t display properly with the new theme, because it’s using a whole different set of formats.
  • Bad user experience, that is.

Now, from the perspective of a theme author, I understand the reasoning here. You want to be able to display things differently.

The problem is that you were already able to do that before.

Custom taxonomies have been around a long time. All you had to do was to a) create a custom taxonomy (call it “mytheme_formats”), b) allow users to sort posts into your taxonomy, and c) display things differently in the theme based on the terms in that taxonomy.

Post Formats is just a taxonomy. It’s a set of adjectives, describing the nouns that are the posts. So now we have “aside posts” and “gallery posts” and “chat posts” and “video posts” and so on. If you want to make your own formats, then you’ve had that ability forever. Why have you not already used it?

The answer to why you didn’t do it before is because there was no standard set of formats.

Without a standard set to work with, users won’t have any idea what your formats mean. You have to write documentation. You have to educate the user. You have to explain what this weirdness in your theme is.

Post formats changes that. Now you have a standard set of formats, and the user, having used other themes that support those formats too, will have some idea of what they mean already. But in order for this to work, themes must all use the same basic formats. There has to be a standard set of adjectives to describe the posts.

If you want to create your own set, then create your own taxonomy and box to have your set in it. But don’t complain when users don’t understand why your theme’s formats don’t mesh with the formats of every other theme that does support them.

The point of standards is to be standard. You don’t have to support the standard, but you also will have to deal with the consequences of being non-standard.

Summing up

In the end, you want to present things to your users in a method that causes the least confusion. If your user wants to display things in a single stream, then those things need to be Posts. If the user wants different things in that stream to display in different ways, then you should use a taxonomy to do that, and the post format taxonomy provides a nice and easy way to standardize that and be compatible with other themes.

If you want to go it alone with custom things, feel free, but be aware of the risk.

Shortlink:

Update: Forget this plugin. Go install Jetpack instead.

WordPress.com rolled out a nifty new feature called “Gravatar Hovercards” today. Basically it changes gravatar images into popups showing more info when the user hovers over them. In the comments, Andy Peatling mentioned bringing them to self-hosted WordPress blogs soon.

I didn’t feel like waiting.

<?php
/* 
Plugin Name: Gravatar Hovercards
*/
function gravatar_hovercards() {
	wp_enqueue_script( 'gprofiles', 'http://s.gravatar.com/js/gprofiles.js', array( 'jquery' ), 'e', true );
}
add_action('wp_enqueue_scripts','gravatar_hovercards');

This is not official.
It’s not supported.
It may not even work for you.
It certainly won’t work if they change things.

Still, this blog is about fun things I do with WordPress, so I saw no reason not to post it. I expect they’ll come out with their own plugin soon, but I’d be rather surprised if it’s much more than this. Maybe some extra options or something. I dunno. Switch to that script when it comes out.

But for those people who like experimenting and playing with WordPress on the edge, here you go.

And for you Javascript inclined people, take a look at their code. It’s got some tricks in it that are pretty neat.

Enjoy. :)

(Updated as per several comments)

Shortlink:

I recently acquired a short domain name, otto42.com (the otto.com domain is owned by a German company, and I use Otto42 as my alias a lot on sites as “Otto” is usually already taken). So I decided to use it to make my own URL shortener.

I looked at various methods for this, including simply writing my own (honestly, it ain’t that hard), but I wanted to see what was already available first.

First thing I looked at was the shortlinks system built into Google Apps. I’ve used it before, and it’s fairly nifty. They even have an API available for interfacing it to other things. And hey, the redirections would be served up by Google’s servers, which you can’t beat for reliability. Sadly, after screwing around with this for a while, and trying out some example code, I was totally unable to get their API to work. The whole thing is written in Python, which I have an intense dislike of (whitespace my ass!), and when trying to access the thing via direct calls, it gave me nothing but errors and annoyances.

So I searched around a bit more, and was relegated to building my own, when a tweet by @ozh mentioned that he’d put a blog up on yourls.org. This looked promising, as I know Ozh is active in WordPress, and so of course it would have a plugin. After investigating, I went with it. It works pretty well, actually.

How to do it

First thing I did was to point my short domain at a directory on my hosting account. If it’s going to run code, it needs to have a place to do it from. So I made a yourls directory and pointed the domain to it using my hosting control panel.

Next, I grabbed a copy of the yourls code and installed it there. 300+ files to FTP? Yikes. Complex. A quick bit of reading told me that it needed a database and a config file. Very similar to WordPress in this respect, except the config file resides in the includes subdirectory for some reason. Not so obvious, but whatever.

I toyed with the idea of using the same database for yourls that I already use for WordPress, but ended up creating another one for it. I’m now thinking that it might be worth merging them though, as that way, VaultPress would probably back up the yourls tables too.

After some hosting weirdness, the thing was up and running.

Plugin

Installing the WordPress plugin is a snap. Just find it in the Add New Plugin interface and hit install. After Network Activating it for all my sites, I went to configure it. I had to configure it on each site separately, but no big deal.

Configuration is fairly straightforward. Tell it URL of the API interface, give it my username and password, and voila. Worked first try.

There’s a bunch of Twitter stuff there as well which I only set up to make it stop bothering me about it. I don’t want this plugin to send out my tweets on new posts, as I already use my own Simple Twitter Connect for that. Still, it bugs you with an error message if you don’t set it up, so I did. Thankfully, there’s checkboxes to turn the autotweeting on and off, so I just leave these turned off. Honestly, I think this whole Twitter thing should be removed from the plugin, but I can understand the “easy” factor here for new users. Making them totally optional would be a nice enhancement though.

At first, I was confused because when I turned it on, I saw no way to make it back-populate my old posts into the shortener. Turns out I didn’t need to, it started doing it all by itself shortly afterwards. I think it actually does shortening on an on-demand basis, creating a shortlink whenever there isn’t one already there for a post.

The plugin also hooks into the Shortlink API, meaning that my Twitter plugin will automagically use the new shortlink. You can see that the shortlink box below this post has the otto42.com shortlink in it. I had to make zero changes to make that work. Isn’t interoperability fun?

One other thing I did have to do was to turn off the old wp.me shortlinks I used. These are provided by the WordPress.com Stats plugin, and there’s a checkbox in its options page to turn them off. No big deal.

Final thought

So yeah, if you have a short domain and want to make your own shortlinks, then YOURLS is a pretty good choice. I haven’t played with the stats gathering part of it yet, for the simple reason that I only just turned it on and thus have no stats to view. Still very easy to do, on the whole. Of course, if it could be entirely a WordPress plugin, then I might think it much cooler. :)

Update: There is a minor problem in the way the YOURLS plugin handles the WP Shortlink API. I’ve reported it upstream, hopefully it can be fixed soon. Still, it’s a minor issue. The workaround for now is to call wp_get_shortlink(get_the_ID()) when you want to get the shortlink for a post inside the Loop.

Shortlink:

Clearly, I am not a photographer. My set of pictures is laughable. Spent too much time talking to people and such, and virtually no time photographing them. :)

Shortlink:

A while back, I wrote a post detailing why it was a bad idea to generate Javascripts using PHP in WordPress plugins. In that post, I mentioned a couple of better ways to do it.

At the time, I didn’t know about the third, and best way, to accomplish this. Mike’s comment over there reminded me of it. WordPress has it built in.

If you already know about wp_localize_script, you can stop reading now.

The wp_localize_script function was made in order to allow for WordPress translations to be able to also translate some of the JS files inside WordPress. Thus the name “localize”. The way it works is to load up the translated versions of text from the translation files and then include them into the resulting HTML output as a Javascript object. The scripts then use that object to produce any text output they need to produce.

Turns out that’s really similar to our goal of sending arbitrary parameters from WordPress to be used by Javascript code.

How to do it:

1. Make your script static (instead of generated) and enqueue your script as per normal. Example:

wp_enqueue_script('my-script','/path/to/whatever.js',…);

No real changes there. You’ll have to come back and modify your script to use these parameters it’s getting passed, but we’ll get to that in a minute.

2. Build an array of your parameters that you want to send to the script.

$params = array(
  'foo' => 'bar',
  'setting' => 123,
);

Note that my parameters are simple examples, but this is PHP code. You can get your parameters however you like. Such as get_option to pull them from the database, perhaps.

3. Call wp_localize_script and give your parameters a unique name.

wp_localize_script( 'my-script', 'MyScriptParams', $params );

What this will do is make WordPress output an inline script with your parameters (properly encoded) just before the enqueue outputs the script tag that loads your script in the first place. So then those parameters will be available to your script as an instance of an object with “MyScriptParams” (from my example).

This means that Javascript code can now reference them as attributes of the name you gave.

So, step 4. Modify your script to use those parameters. In my example, I used “MyScriptParams” and the parameter names are “foo” and “setting”. In my Javascript code I can use them as “MyScriptParams.foo” and “MyScriptParams.setting”.

Much cleaner. One static and unchanging JS file to cache. Parameters get put into your HTML itself as a one-liner. You can deal with the parameters using a normal PHP array before passing them over. No need to screw around with generating Javascript from PHP or looking for wp-load or even messing with tricky actions.

Perfect.

Shortlink: