Updating the Manage Posts Filtering for WordPress 2.5
- Adding custom columns to the WordPress manage posts screen
- Manage Pages Custom Columns plugin released
- Adding custom columns to the WordPress manage pages screen
- Custom filtering in the WordPress Manage Posts screen
- Updating the Manage Posts Filtering for WordPress 2.5
Since the last post on Custom Filtering in the Manage Posts Screen, WordPress 2.5 has been released to the world. While the techniques discussed in that article are still valid, due to the big admin interface rewrite, the results don’t look as pretty as they could. In this post, I’ll discuss updating the code from the previous post so that it works and looks good through all modern WordPress versions.
One quick note
It appears that something changed in Version 2.5 that breaks the way that the posts_where hook was being attached. Initially, the admin_head hook was being used to attach it. This isn’t that great because it means the hook is loaded on all admin pages, which isn’t really necessary. Also, as I said, it just doesn’t work in the new version of WordPress. A better way, which replaces lines 21—24 in the code below is:
add_action('load-edit.php', 'scompt_load_edit_page');
function scompt_load_edit_page() {
add_filter('posts_where', 'scompt_posts_where');
}
What we’re starting with
Below is the code that we ended up with in the last post. To the right, you’ll see a screenshot of how it looks in the WordPress 2.3 and 2.5. WordPress 2.2 should look the same as 2.3, but it’s old enough that we’re not concerned with it. There are a couple things worth noting in the image.
In WordPress 2.3, the dropdown fits with the other dropdowns. That’s good. Notice that there’s two ‘Filter’ buttons. That’s bad, but was necessary because the restrict_manage_posts hook is called outside of the form element. In WordPress 2.5, there’s a stylish light-blue bar where the filters should go, and there’s our filter sitting out in the middle of nowhere. Also, there’s no longer a border with label surrounding the dropdown. The last thing to notice is that the text inside of the dropdown is different: “Any” compared to “Show all Dates” in the case of the date filter. This leaves us with a nice TODO list of things to accomplish in this post:
- Get rid of the extra ‘Filter’ button
- Put the dropdown in the filter bar
- Get rid of the border and label surrounding the dropdown
- Make the text shown in the dropdown fit better with the other filters
- Make sure it still works and looks good in WordPress 2.3
add_action('restrict_manage_posts', 'scompt_restrict_manage_posts');
function scompt_restrict_manage_posts() {
global $wpdb;
$has_count = $wpdb->get_var("SELECT COUNT(*) FROM wp_posts WHERE post_type='post' ".
"AND ID IN (SELECT post_parent FROM wp_posts WHERE post_type='attachment')");
$hasnt_count = $wpdb->get_var("SELECT COUNT(*) FROM wp_posts WHERE post_type='post' ".
"AND ID NOT IN (SELECT post_parent FROM wp_posts WHERE post_type='attachment')");
?>
<form name="scompt_attachmentform" id="scompt_attachmentform" action="" method="get">
<fieldset style="margin: 0pt 1em 1em 1.5em; padding: 0pt; float: left;">
<legend><?php _e('Attachments'); ?>…</legend>
<select name='scompt_attachments' id='scompt_attachments' class='postform'>
<option value=""><?php _e('All'); ?></option>
<option value="has" <?php if( isset($_GET['scompt_attachments']) && $_GET['scompt_attachments']=='has') echo 'selected="selected"' ?>><?php _e('Has attachments'); ?> (<?php echo $has_count ?>)</option>
<option value="hasnt" <?php if( isset($_GET['scompt_attachments']) && $_GET['scompt_attachments']=='hasnt') echo 'selected="selected"' ?>><?php _e('Has no attachments'); ?> (<?php echo $hasnt_count ?>)</option>
</select>
</fieldset>
<input type="submit" name="submit" value="<?php _e('Filter »'); ?>" class="button" style="float:left;margin:14px 0pt 1em;position:relative;top:0.35em;"/>
</form>
<?php
}
add_action('admin_head', 'scompt_admin_head');
function scompt_admin_head() {
add_filter('posts_where', 'scompt_posts_where');
}
function scompt_posts_where($where) {
global $wpdb;
if( $_GET['scompt_attachments'] == 'has' ) {
$where .= " AND ID IN (SELECT post_parent FROM {$wpdb->posts} WHERE post_type='attachment' )";
} else if( $_GET['scompt_attachments'] == 'hasnt' ) {
$where .= " AND ID NOT IN (SELECT post_parent FROM {$wpdb->posts} WHERE post_type='attachment' )";
}
return $where;
}
Getting down to work
I would suggest that we just head straight down our TODO list. The first point is to get rid of the ‘Filter’ button. Luckily, the restrict_manage_posts hook is called inside the form in version 2.5, eliminating the need for it. This also means that we can leave out the form tag that was previously necessary. In summary, cut out lines 9, 18, and 19.
The second point and third points can be solved together. The reason the dropdown is getting shoved outside the filter bar is actually because of the border and label that we wanted to get rid of anyway. This means not printing the fieldset and label tags, so we can get rid of lines 10, 11, and 17. You’ll notice that out code is getting whittled away pretty quickly. That’s what I call progress.
The fourth point is a logical consequence of the previous one. There’s no longer a label describing what the dropdown does, so now the text inside the dropdown has to do so. Previously, our label was “Attachments” and the dropdown text was “All”. Now, we need to come up with a phrase that captures the essence of the two former phrases. The best I could come up with is “View with/without attachments”, which needs to be changed in line 13. Leave a comment if you have a better idea. This label will go inside the default first option in the dropdown.
At this point, having addressed the first four points, we have a working chunk of code for WordPress 2.5. Below is the updated copy of the scompt_restrict_manage_posts function and to the right a screenshot of the results. We’ll hit the last point in the next section.
function scompt_restrict_manage_posts() {
global $wpdb, $wp_version;
$has_count = $wpdb->get_var("SELECT COUNT(*) FROM wp_posts WHERE post_type='post' ".
"AND ID IN (SELECT post_parent FROM wp_posts WHERE post_type='attachment')");
$hasnt_count = $wpdb->get_var("SELECT COUNT(*) FROM wp_posts WHERE post_type='post' ".
"AND ID NOT IN (SELECT post_parent FROM wp_posts WHERE post_type='attachment')");
?>
<select name='scompt_attachments' id='scompt_attachments' class='postform'>
<option value="0"><?php _e('View with/without attachments') ?></option>
<option value="has" <?php if( isset($_GET['scompt_attachments']) && $_GET['scompt_attachments']=='has') echo 'selected="selected"' ?>><?php _e('Has attachments'); ?> (<?php echo $has_count ?>)</option>
<option value="hasnt" <?php if( isset($_GET['scompt_attachments']) && $_GET['scompt_attachments']=='hasnt') echo 'selected="selected"' ?>><?php _e('Has no attachments'); ?> (<?php echo $hasnt_count ?>)</option>
</select>
<?php
}
Backwards Compatibility
Now that we’ve shrunk our code down to it’s 2.5 essentials, it’s time to balloon it back up again to make it backward-compatible with 2.3. If you’re running 2.5 and don’t plan on looking back anytime soon, you can skip this section and still live a happy life.
The first step is being able to differentiate between version 2.3 and 2.5. To do this, we’ll take advantage of the PHP function version_compare and the WordPress global $wp_version which comes from wp-includes/version.php. Putting those together, we get the following useful bit:
if( version_compare( $wp_version, '2.5', '<' ) ) {
// Versions before 2.5
} else {
// Version 2.5 and later
}
Because our 2.5 code is essentially the 2.3 code wrapped in a couple tags (form and fieldset) with a couple extras thrown in at the beginning and end (legend and input), I would suggest making variables to hold these extra $before and $after bits. For version 2.5, these variables will be empty. The only other difference is the verbage in the dropdown. Here’s the final code that will work well and look good for WordPress versions 2.2 — 2.5.
function scompt_restrict_manage_posts() {
global $wpdb, $wp_version;
$has_count = $wpdb->get_var("SELECT COUNT(*) FROM wp_posts WHERE post_type='post' ".
"AND ID IN (SELECT post_parent FROM wp_posts WHERE post_type='attachment')");
$hasnt_count = $wpdb->get_var("SELECT COUNT(*) FROM wp_posts WHERE post_type='post' ".
"AND ID NOT IN (SELECT post_parent FROM wp_posts WHERE post_type='attachment')");
if( version_compare( $wp_version, '2.5', '<' ) ) {
$before = '<form name="scompt_attachmentform" id="scompt_attachmentform" action="" method="get">';
$before .= '<fieldset style="margin: 0pt 1em 1em 1.5em; padding: 0pt; float: left;">';
$before .= '<legend>'. __('Attachments') .'…</legend>';
$all = __('All');
$after = '</fieldset>';
$after .= '<input type="submit" name="submit" value="'. __('Filter »') .'" class="button" style="float:left;margin:14px 0pt 1em;position:relative;top:0.35em;"/>';
$after .= '</form>';
} else {
$before = "";
$all = __('View with/without attachments');
$after = "";
}
echo $before;
?>
<select name='scompt_attachments' id='scompt_attachments' class='postform'>
<option value="0"><?php echo $all; ?></option>
<option value="has" <?php if( isset($_GET['scompt_attachments']) && $_GET['scompt_attachments']=='has') echo 'selected="selected"' ?>><?php _e('Has attachments'); ?> (<?php echo $has_count ?>)</option>
<option value="hasnt" <?php if( isset($_GET['scompt_attachments']) && $_GET['scompt_attachments']=='hasnt') echo 'selected="selected"' ?>><?php _e('Has no attachments'); ?> (<?php echo $hasnt_count ?>)</option>
</select>
<?php
echo $after;
}
add_action('load-edit.php', 'scompt_init_attachments');
function scompt_init_attachments() {
add_filter('posts_where', 'scompt_posts_where');
add_action('restrict_manage_posts', 'scompt_restrict_manage_posts');
}
function scompt_posts_where($where) {
global $wpdb;
if( $_GET['scompt_attachments'] == 'has' ) {
$where .= " AND ID IN (SELECT post_parent FROM {$wpdb->posts} WHERE post_type='attachment' )";
} else if( $_GET['scompt_attachments'] == 'hasnt' ) {
$where .= " AND ID NOT IN (SELECT post_parent FROM {$wpdb->posts} WHERE post_type='attachment' )";
}
return $where;
}
Conclusion
We’ve now successfully updated the Manage Posts filtering code for WordPress 2.5. In the process, we even made it backward compatible. This has been another post in my series on Pimping your Manage Panel. Keep an eye peeled here for when I present my ever-promised technique of filtering in the Manage Pages panel.
Update!
One thing I forgot to mention. In WordPress 2.5, the restrict_manage_posts hook is also used on the upload screen. To make sure your dropdown code doesn’t appear on the upload screen, make sure you add the restrict_manage_posts action inside the scompt_init_attachments hook. This will make sure it only gets loaded when edit.php is called. I’ve made the change on the above code snip

