Adding custom sortable columns to your WordPress custom post type

With custom post types you often make more use of custom fields (meta data), and you want that to be part of the user interface. The traditional columns that come with blog posts just don’t meet your needs any more.

As of WordPress 3.0 the core now invokes filters based on your custom post type, which allows you to target your filters specifically for that post type. For example, if you want to filter the columns for your artists post type, the manage_edit-artists_columns filter is invoked. And if you want to make your columns sortable, then use the manage_edit-artists_sortable_columns filter.

I’ll add an example for my fictional artists post type. I have decided to add nationality to as a custom field, and I want it sortable.¬†There are four steps

1. Add the custom column.

add_filter('manage_edit-artists_columns', 'tcb_register_artists_columns');
function tcb_register_artists_columns($columns){
  $columns = array(
    'cb'              => '<input type="checkbox" />',
    'title'           => 'Name',
    'nationality'     => 'Nationality',
  );
  return $columns;
}

2. Handle the custom column – what to display.

add_action('manage_posts_custom_column', 'tcb_handle_artists_columns');
function tcb_handle_artists_columns( $column ){
  global $post;
  if( $post->post_type != 'artists' ) return;
  if( $column == 'nationality' )
    echo get_post_meta( $post->ID, 'nationality', true );
}

3. Make the custom column sortable.

add_filter('manage_edit-artists_sortable_columns', 'tcb_register_artists_sortable_columns');
function tcb_register_artists_sortable_columns( $columns ){
  $columns['nationality'] = 'nationality';
}

4. Handle how to sort your custom column.

add_filter('requests', 'tcb_handle_artists_column_sorting');
function tcb_handle_artists_column_sorting( $vars ){
  if( isset($vars['orderby']) && 'nationality' == $vars['orderby'] ){
    $vars = array_merge( $vars, array(
      'meta_key' => 'nationality',
      'orderby'  => 'meta_value'
    ));
  }
  return $vars;
}

Codex references:

WordPress – redirect traffic to your primary domain

This is a snippet that allows you to redirect all your incoming traffic to a single primary domain.

You may end up with web sites that have multiple domains. Most commonly, site owners will want both their www and non-www domain names to end up in the same place. Later version of WordPress handle this automatically. However, web sites can change domain name for many reasons (e.g company name change, development work on a sub-domain, site restructure and so on).

It generally, and usually, best to control your traffic by configuring your web server to handle any such change. There are times though when this is not possible, or simple that you want (as a WordPress developer) the speed and control that goes with managing it from with WordPress itself.

function tcb_redirect_to_primary_domain() {
  $schema           = is_ssl() ? 'https://' : 'http://';
  $requested_domain = strtolower($schema . $_SERVER['HTTP_HOST']);

  $primary_domain = get_bloginfo('siteurl');
  if( defined('WP_SITEURL') && '' != WP_SITEURL )
    $primary_domain = WP_SITEURL;

  if( empty($primary_domain) ) return; // Something is really wrong.

  $primary_domain = strtolower($primary_domain);

  // strip subdirectories.
  if( preg_match('|^(https?://)([^/]+)/.+|', $primary_domain, $matches) )
    $primary_domain = $matches[1] . $matches[2];

  $primary_domain    = rtrim($primary_domain, '/');
  $requested_domain  = rtrim($requested_domain, '/');

  if( $primary_domain !== $requested_domain ){
    $redirect = $primary_domain . $_SERVER['REQUEST_URI'];
    wp_redirect( $redirect, 302 );
    exit;
  }
}
add_action('template_redirect', 'tcb_redirect_to_primary_domain');

This is pretty much a follow up to Divy Dovy’s post on WordPress domain redirection.

After Dave asked me about it, I realised that what I use at work is at times more simple, and others more complex, but was never really relevant to any other company or person. So I thought I would strip out the irrelevant bits and see what was left. and as you can see it is really not much more than Dave’s excellent snippet. He should give himself more credit!

WordPress – Force the Kitchen Sink always on

The two most common questions that our WordPress clients ask us is “where has the colour selector gone?” and “why can I no longer chose which H1 – H6 tag to use?”. The answer is very easy, they need to switch the kitchen sink back on. Sometimes it is easy to forget that there’s a whole world of people out there who just don’t care about things like CMS or WordPress let alone The WYSIWYG content editor. And rightly too.

The answer was to add a short filter to the theme (or plugin) that forces the kitchen sink to always be on. Then there is no confusion.

/**
 * Force the kitchen sink to always be on
 */
add_filter( 'tiny_mce_before_init', 'tcb_force_kitchensink_open' );
function tcb_force_kitchensink_open( $args ) {
  $args['wordpress_adv_hidden'] = false;
  return $args;
}

[UPDATE 2013-04-02]
I have updated this to use WordPress TinyMCE filters. The old way would not work with more recent versions of WordPress (which is probably a good thing).

Why Apache .htaccess files are evil

Evil? Wow, that’s a bit strong. Besides, everybody loves Apache and their .htaccess files! Don’t they? Well, I’m not so keen. I think there are two important issues with Apache. Firstly, out of the box (as it were), it comes badly configured. For anyone wanting to dip their toes in server building and administration, they will soon find their server down and out for the count as it OOMs (Out Of Memory)¬†into oblivion. That’s a subject for another day.

Secondly, I believe that .htaccess files are bad. It’s like giving your three-year old the keys to your house. Yes, it certainly will be easier for you; your child can decide when to come and go without having to interrupt your day. But you really don’t know just when they will give the key to a dodgy so-and-on with thieving¬†intentions

Web servers form part of the host configuration and set up. They direct and manage traffic to and from the server. Who should tell it how it does that? The system administrator. Giving control of the w server to its applications is intrinsically wrong.

Allowing applications to control how the server works, can certainly make peoples’ live’s easier. The pay off, though, is that it makes the sever less secure. To make a simile, it would be like getting rid of passports and border control, or being more exact, it would be like letting every individual person decide what the border controls are and what verifies their passport as being a document that uniquely identifies them. People could just make anything up. Well, on a server, that is what .htaccess files allow you to do.

Personally I no longer support .htaccess files. Just like border control and passports are worth the¬†encumbrance, so is disabling .htaccess (or just not using Apache at all). And I find that gradually, they aren’t missed. It is just a shame that I have to put the time and effort into effectively working around an issue that should not exist¬†in the first place.

jQuery AJAX enable your WordPress forms

I’m often building forms for client projects, and they nearly always prefer them have some AJAX goodness. To this end I’ve built a small jQuery file that gets added to all my projects. It depends on Malsup’s AjaxForm and Bassistance’s Form Validation.

/**
 * Generic *SIMPLE* Ajax Form handling
 */
jQuery(document).ready(function($){
 $('.simpleajaxform').each(function(){
  $(this).attr('method', 'post');
  var target = $(this).attr('target');
  var func   = $(this).attr('function');
  options    = {};
  if( target || func ){
   if( target ) $('#'+target).html('').hide();
   options = {
    success:      simpleajaxform_success,
    beforeSubmit: simpleajaxform_submit
   };
  }

  $(this).ajaxForm(options);
 });
});

/**
 * On submit: clear any previous update and tell the user
 *  that we're trying to update
 */
function simpleajaxform_submit(formData, jqForm, options) {
 if( !jqForm.valid() ) return false;
 target = jqForm.attr('target');

 if( target )
  jQuery('#'+target).html('Updating, please wait...').removeClass('updated').addClass('updating').show();
 return true;
}

/**
 * Response: show message in target div.
 */
function simpleajaxform_success(responseText, statusText, xhr, jQForm){
 if( jQForm === undefined )
  jQForm = xhr;
 if( jQForm === undefined ){
  alert('Cannot handle response properly');
  return;
 }
 target = jQForm.attr('target');
 if( target )
  jQuery('#'+target).removeClass('updating').addClass('updated').html(responseText);

 hide = jQForm.attr('hide');
 if( hide )
  jQuery('#'+hide).hide();

 handler = jQForm.attr('function');
 if( handler )
  eval( handler+'(responseText, jQForm)' );
}

Take any form that submits to an AJAX handler (see below for notes on WordPress and ‘action’), add the ‘simpleajaxform‘ class and either a ‘target‘ or ‘function‘ property. Job done.

Here’s a stripped down example using it:

<form class="simpleajaxform" action="<?php echo admin_url('admin-ajax.php');?>" target="targetdiv">
 <input type="hidden" name="action" value="my_wp_action" />
 <input class="required" type="text" name="message" value="" />
 <input type="submit" name="submit" value="DO STUFF" />
</form>

WordPress, Javascript (jQuery) and ACTION

If you add a field named ‘action‘ in a form, then jQuery can get a bit confused by the syntax ‘jQuery(‘#someformid’).attr(‘action’,ajaxurl)‘. I’ll leave figuring that out as an exercise for the reader (or for a later post).

Download showcase plugin here: simple-ajax-form