Members Plugin

I needed to figure out how to control who could add the different types of content to the site. The information in the WordPress codex on Roles and Capabilities isn’t too complete at the moment. It took a few readings to understand the system, but there was still not much clue on how to write code to customize it.

After trying a couple of different plugins, I finally found that the Members plugin by Justin Tadlock does what I want. This plugin can be used to manage roles and then assign them capabilities. It can also do other things like limit content from certain users, but I only want to control the types of content which the different roles can post.

My plan is to have a blogger role who will only post normal WordPress posts. These will appear on the blog page. Another role will take on the role of content manager. This role will be given control over the sermons and newsletters, but not the blog posts. The primary intention of all this is to make the admin interface less complex for the end users and only show them the things they can edit.

The blogger role is currently fulfilled by the default author role. By adding the ‘capability_type’ key to the custom post types, the default author can no longer see them.

Using the plugin, it was a simple task to add the role of content manager. I then gave it capabilities to edit and publish sermons and newsletters. The necessary capabilities are edit_sermons, edit_others_sermons, edit_published_sermons, publish_sermons, delete_sermons, delete_others_sermons for sermons. Replace ‘sermons’ with ‘newsletters’ and all all the capabilities for control over newsletters.

It is also necessary to grant manage_categories so category and taxonomy terms can be added and managed. To allow the role to assign terms in custom taxonomies, the key-value pair 'capabilities' => array('assign_terms' => 'edit_sermons') is needed when registering the custom taxonomy. Once again, replace ‘sermon’ with whatever capability_type you want.

To allow media to be managed, the edit_posts and *_posts capabilities also had to be added. * is a wildcard for all the other functions. This actually allows the content manager control over the blogger’s posts, but the problem is mitigated somewhat by hiding the posts menu from the interface.

While the author role currently fulfills the blogger role, it would be better to separate them. The default author role will then be given the combined capabilities of church_cm and blogger.

Add from Server plugin

Uploads through the admin interface go into the uploads folder with the structure year/month. This is usually fine, but what if I want to upload lots of past content? If I upload a lot of past content now, it’ll all end up in the 2011/03 folder, regardless of when the content was produced. This will be messy. The better solution is to upload each to its own year/month folder, a much neater solution.

However, manually placing the files into the desired folder structure does not cause them to show up in the admin interface. It turns out that WordPress doesn’t check the folders to see if anything is inside. A database entry is needed. This can be accomplished with the Add from Server plugin, which scans the directories and adds the required database entry.

This allows the files on the server to be added to the database and hence show up in the media library. The file will attach itself to the post which is currently being written, unless the checkbox “Do not add to current post gallery” is selected.

Custom Post Type Archives Part 4

Phew, custom post type archives are causing lots of problems. Three separate posts about them already, and the plugin was the one which broke WordPress 3.1. Well the updated version doesn’t. However, this led to a thought. Since it’s supposed to be built in, could I do it without using the plugin? After all, I was just after some very basic functionality. The answer turns out to be yes, well, almost.

Enabling the Feature

There is an attribute has_archive in the register_post_type() function which activates the archives feature, but it defaults to false. I added the code in to set this to true. This information was from Mark McWilliams, the same post also gave some hints on how the permalinks would look like.

Disabling the Plugin

The next step was to disable the plugin and see what stops working. Looks like the sidebar has some problems, which also prevents the admin bar from loading properly. The month listing from the custom widget wasn’t appearing at all.

Fixing the Widget

The widget depends on the custom get_post_type_archives() function, explained in Part 2, to do its magic.

Using a debug echo statement and commenting out suspect lines, I found the problem in one of the custom functions provided by the plugin. It returns the permalink of the post type. This can actually be generalized as

get_bloginfo('url') . '/' . $post_type . '/';

Now I get output with a link to the archives by date, but it wasn’t showing the correct number of months. Why??

Filter getarchives_where

Even the plugin just let the built in WordPress function wp_get_archives() do the hard work, so why did it work with the plugin activated? A closer look at the function itself, and the way it was used by the plugin, revealed that wp_get_archives() was insufficient to get archives by post type. It applies a filter to get the correct SQL Where clause. This was used by the plugin.

Since I only want that function, I copied the entire thing over to my own functions.php file.

function pta_wp_get_archives_filter($where, $options) {
	if(!isset($options['post_type'])) return $where; // OK - this is regular wp_get_archives call - don't do anything
	
	global $wpdb; // get the DB engine
	
	$post_type = $wpdb->escape($options['post_type']); // escape the passed value to be SQL safe
	if($post_type == 'all') $post_type = ''; // if we want to have archives for all post types
	else $post_type = "post_type = '$post_type' AND"; // otherwise just for specific one
	
	$where = str_replace('post_type = \'post\' AND', $post_type, $where);
	
	return $where;
}
add_filter('getarchives_where', 'pta_wp_get_archives_filter', 10, 2);

Now the archive links work and the correct number of links are displayed, depending on what the post type is!

Archive Templates

This approach led to my custom post types being displayed incorrectly as they now use the archive.php template file. It only displays the excerpts for archives, so the shortcodes and meta data no longer show up. As each post will be very short in length, I want the full content and meta data to show up, just like it does on the main page listings.

The solution to this was simply to copy archive.php to the child theme, rename it archive-{post-type}.php, and change the function call to the loop so that it calls my previously written custom loops.

Page Templates

{post-type}-template.php were previously used for both the display of the full listing as well as the archive pages. With WordPress 3.1, archives are handled by the archive template pages. Thus, the if-else conditions which handled query_posts() can be removed. The page templates will be used just for display of all the custom posts.

Conclusion

With all these changes, I can now use one less plugin and use more of the functionality available in WordPress Core.

Custom Post Type Archives Part 5

WordPress 3.1 Reinhardt Released

Looking through the forums this morning, I suddenly realised that there were lots of references to WordPress 3.1. I quickly checked the main page and discovered that it had been released while I was asleep. What would it mean for the site?

Having setup my site to use SVN, I just had to switch the working copy over to the latest version to update. After the update was complete, I visited the site to see an Internal Server Error. A quick bit of Google searching suggested that plugins should have been disabled before updating. Oops. I renamed the plugins folder and the site was up again.

One of the new features in WordPress 3.1 is Custom Post Type Archives, so maybe that clashes with the plugin I’m using. It was also the only one with an update. With the plugin disabled, the audio player didn’t work, and neither did the custom archives widget.

There didn’t seem to be any useful information on how to enable dated archives for custom post types, so I decided to try updating and activating the plugin.

Still one more problem. The archive pages were showing the wrong sidebar. A bit of investigation showed that the plugin provided function is_post_type_archive() had been renamed to pta_is_post_type_archive() because WordPress had used the old name. Since I was using that function in sidebar.php to check for the page type, I had to update its name. Everything seems to work now!

Shortcode for the Year

I wanted to get the current year using a shortcode. In addition to that, I wanted it to be usable in a text widget. This will allow me to put it in the footer with a text widget, which is much less troublesome than modifying the entire footer file to use a page.

The code for creating the shortcode is very simple and borrowed from the Thematic theme.

function shortcode_year() {
    return '<span class="the-year">' . date( 'Y' ) . '</span>';
}
add_shortcode('the-year', 'shortcode_year');

This tutorial on DigWP explains how to get shortcodes to work in widgets. It’s a very simple solution which involves filtering the widget text.

add_filter('widget_text', 'do_shortcode');

That’s it, putting [the-year] in a text widget will now result in the current year being displayed in the browser.

Custom Post Type Archives Part 3

Part 2 explained how to create a widget to show the chronological links for the sermon post type. This post will explain how I generalized the widget to show the chronological links for a custom post type specified in the the widgets administration panel.

It uses the same technique as described in the Custom Taxonomy widget post.

Widget function

Add the line $post_type = $instance['posttype']; after the line initializing the $title variable.

Change the hardcoded value of ‘sermon’ in the custom get_post_type_archives call to $post_type

Update function

Add the line $instance['posttype'] = strip_tags($new_instance['posttype']);

Form function

Add the line $post_type = strip_tags($instance['posttype']);

Copy the line for the title text field and paste it right below the original line. Modify all references to the title text field and set it to ‘posttype’. The value which should be echoed out is $post_type

Using the Widget

There will now be an extra field in the widget administration. Type in the name of the custom post type here.

Custom Post Type Archives Part 4

Adding a new Custom Post Type

As before, use the register_post_type() function to register a new custom post type. This will be named ‘newsletter’ and will be for the weekly messengers. The name ‘newsletter’ was chosen as it is the most generic description of this type of content. Using the specific name would make it more troublesome should I need to reuse this code in the future.

The key thing I wanted to do here is to let it use the built in categories. This is done by adding 'taxonomies' => array('category') to the array of arguments passed into the registration function. Additional taxonomies can be added to the array if necessary. This tip was found at deluxeblogtips

The rest of the steps are a repeat of what was done for the sermon post type. A custom loop file was created, the main feature in this loop is the code to get the memory verse from the custom fields and display it in a blockquote.

Similar to the sermon post type, all the newsletter entries will be displayed with a custom page template. This modifies the Query so that it only gets the newsletter post type. The same trick of checking for the existence of the pagename array key is used to check if the template is being used for the chronological archives or the normal display page.

A custom template file is also needed for single posts. It’s the same as the sermon one except that it calls a different loop.

I also had to enable post type archives in the Custom Post Type Archives plugin for my new custom post type.

Multiple Meta Boxes

The previous solution for meta boxes worked fine, until I realized that I needed another one for my newsletter custom post type too. The quick solution would have been to duplicate the code and just rename and edit the necessary sections, but most of the code would remain the same. This would cause problems if it has to be edited in the future.

The same website provides a tutorial for multiple meta boxes. The required fields and other details are first stored in a $meta_boxes array, then a loop is used to go through all of them.

As explained on the tutorial, this doesn’t quite work because the callback display function can only handle one meta box at a time. The solution is to put all the functions in a class. The class constructor will initialize each meta box and hook the add and save functions onto the WordPress hooks. The website has the full explanation and sample code.

Testing for Post Type Archives

The Custom Post Types plugin provides the function is_post_type_archive() which allows me to check if I’m on an archive page for a custom post type.

By using this, I can load different sidebars depending on whether I’m viewing custom post types or normal blog posts. The sermon post type is displayed with sermon-template.php, has views by taxonomy and also chronological archives. To cover these cases, the current code is

if(is_post_type_archive('sermon') || is_tax() || is_page_template('sermon-template.php'))

The is_tax() function will probably have to be made more specific when new post types and taxonomies are added. This line is placed in my own version of sidebar.php, which will override the default. The idea is to show the primary widget area for sermon types, and the secondary sidebar for other things. The widgets will be arranged so that this makes sense.

Custom Taxonomy Widget

The default Category widget lists categories and then shows all posts from a category when clicked on. What if I want something similar for custom taxonomies?

Nothing seems to exist for that yet. However, the wp_list_categories() function has been updated to accept a taxonomy name as an argument. That’s the main function which does the magic in the default widget, the only problem now is how to pass the desired taxonomy name into the function.

Once again, copy and paste comes to the rescue. I just needed to modify a relatively small part of the Category widget, so the easiest way is to copy and paste the whole code over then change the name, similar to what I did for custom post type archives.

In the widget() function, the variables to control the widget are specified. I added a new one to take the taxonomy name and added it to the category arguments array.

$tax = $instance['taxonomy'];
//some other code
$cat_args = array('orderby' => 'name', 'show_count' => $c, 'hierarchical' => $h,'taxonomy' => $tax);

In the update() function, add in code to update the taxonomy value. Since it will get input from a textbox, just like the title, the code is very similar.

$instance['taxonomy'] = strip_tags($new_instance['taxonomy']);

Copy whatever the Title textbox does in the form() function as well.

$tax = esc_attr( $instance['taxonomy']);
//html code to display the textbox, copy from the title textbox and modify name and values

Once again, remember to register this widget.

add_action('widgets_init', create_function('', 'return register_widget("WP_Widget_Custom_Taxonomies");'));

Now when you want to display terms from a custom taxonomy, just activate this widget and type in the registered name of the custom taxonomy. For better usability, type in a title too.