Custom URLs for post formats

Warning: The content of this article is not to be taken lightly. I'll be covering advanced WordPress code, so please understand the code before implementing it on your site.

A reader, Cecilio, asked in my comments if he could translate the URLs of post format archives into Spanish. Of course, I thought, “Why not?”

You can actually convert post format slugs in the URL to anything you want. I’m not referring to changing the slug in the database. The change would be to the public-facing slug.

In this article, I’ll be covering two things:

  • How to change the post format rewrite base.
  • How to change the post format slug in the URL.

All code in this tutorial belongs in a plugin file. Please do not add it to your theme.

Post format rewrite base

In the WordPress admin, you’re allowed to alter the tag and category base from the permalinks settings page. There’s no such option for post formats in the admin. However, it can be done.

WordPress registers post formats just like any other taxonomy using the register_taxonomy() function. Fortunately, it offers a filter hook called post_format_rewrite_base that allows you to overwrite the base.

In the core code, this hook looks like the following.

$post_format_base = apply_filters( 'post_format_rewrite_base', 'type' );

You’ll notice that the default base is type, which will give you post format archive URLs like mydomain.com/type/post-format-slug.

With the filter hook, it’s extremely easy to change this to something new. Suppose you wanted type to be types instead. Your plugin code would look like the following.

add_filter( 'post_format_rewrite_base', 'my_post_format_rewrite_base' );

function my_post_format_rewrite_base( $slug ) {
	return 'types';
}

You could change it to pretty much anything you want. Just replace types with your preferred base.

You'll need to flush your rewrite rules for the change to take place. The easiest way to do this is to simply visit your "Settings > Permalinks" screen in the WordPress admin.

Custom post format slug in the URL

This is where things get a little tricky. You only need to look at the core WordPress code for a solution. Since post formats are non-standard compared to the other default taxonomies (all post format slugs are prefixed with post-format-), the core developers had to implement some custom code to make them “pretty” on the front end. The good thing about this is that you can borrow the core code for your purposes.

The first step is you need a function for all of your custom slugs. I’ve chosen to just make plural versions of the slugs, but you can do anything with this. For example, you might want to change the slugs to match up with your language.

function my_get_post_format_slugs() {

	$slugs = array(
		'aside'   => 'asides',
		'audio'   => 'audio',
		'chat'    => 'chats',
		'gallery' => 'galleries',
		'image'   => 'images',
		'link'    => 'links',
		'quote'   => 'quotes',
		'status'  => 'status-updates',
		'video'   => 'videos'
	);

	return $slugs;
}

Remember, these are slugs, so don’t do anything crazy. Just use lowercase letters and hyphenate instead of using spaces.

The next step in the process is filtering post format links to use your custom slugs.

/* Remove core WordPress filter. */
remove_filter( 'term_link', '_post_format_link', 10 );

/* Add custom filter. */
add_filter( 'term_link', 'my_post_format_link', 10, 3 );

/**
 * Filters post format links to use a custom slug.
 *
 * @param string $link The permalink to the post format archive.
 * @param object $term The term object.
 * @param string $taxnomy The taxonomy name.
 * @return string
 */
function my_post_format_link( $link, $term, $taxonomy ) {
	global $wp_rewrite;

	if ( 'post_format' != $taxonomy )
		return $link;

	$slugs = my_get_post_format_slugs();

	$slug = str_replace( 'post-format-', '', $term->slug );
	$slug = isset( $slugs[ $slug ] ) ? $slugs[ $slug ] : $slug;

	if ( $wp_rewrite->get_extra_permastruct( $taxonomy ) )
		$link = str_replace( "/{$term->slug}", '/' . $slug, $link );
	else
		$link = add_query_arg( 'post_format', $slug, remove_query_arg( 'post_format', $link ) );

	return $link;
}

The final step is to filter the request hook. The reason for this is that WordPress sees the custom slug you’ve used, which doesn’t technically exist. Since all post formats are saved as post-format-slug in the database, you’ll need to let WordPress know the correct term slug.

/* Remove the core WordPress filter. */
remove_filter( 'request', '_post_format_request' );

/* Add custom filter. */
add_filter( 'request', 'my_post_format_request' );

/**
 * Changes the queried post format slug to the slug saved in the database.
 *
 * @param array $qvs The queried variables.
 * @return array
 */
function my_post_format_request( $qvs ) {

	if ( !isset( $qvs['post_format'] ) )
		return $qvs;

	$slugs = array_flip( my_get_post_format_slugs() );

	if ( isset( $slugs[ $qvs['post_format'] ] ) )
		$qvs['post_format'] = 'post-format-' . $slugs[ $qvs['post_format'] ];

	$tax = get_taxonomy( 'post_format' );

	if ( !is_admin() )
		$qvs['post_type'] = $tax->object_type;

	return $qvs;
}

There you have it: custom post format URLs.

Proceed with caution

I’ve only run the code through a few tests after writing it. I just thought it’d be something fun to do after being asked if it was possible.

Have fun with the code and try out some variations on it.