Changing Roles’ Capabilities
If you need to change one or two capabilities, it’s relatively easy to do so with a few lines of code in a plugin or your theme functions file. For example, if we wanted to allow any logged-in user to view our private posts and pages, we would need to grant them two additional capabilities.
<?php
// allow subscribers to view private posts and pages
$PrivateRole = get_role('subscriber');
$PrivateRole -> add_cap('read_private_pages');
$PrivateRole -> add_cap('read_private_posts');
?>
The first line fetches the existing subscriber role (as an object) and assigns to it a variable. In the next two lines, we add the capabilities to read private posts and pages to our variable. That’s it! Any subscribers can now read your private content – and so can authors and contributors, whose roles include all the capabilities of subscribers. (Remember that editors and administrators already had these particular capabilities.)
Adding capabilities by hand, one at a time, will be a pain if you need to make a lot of changes. If that’s the case, I recommend Justin Tadlock’s Members plugin, which provides an elegant user interface for modifying roles, and also includes some great features for managing content permissions.
Creating a user directory, part 2: Building the page template
In the first installment, we added some contact fields for our users. Now we’re going to build the page template that displays the user directory.
Make a copy of your theme’s page template (page-users.php) and give it a distinct name (“User Directory Template”). Replace its loop with this:
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
<div class="post" id="post-<?php the_ID(); ?>">
<h2 class="pagetitle"><?php the_title(); ?></h2>
<?php
$blogusers = get_users_of_blog(); //get all registered users
foreach ($blogusers as $bloguser) {
$user = get_userdata($bloguser->user_id); //get data about each user as an object
// create a flat array with only the fields we need
$allusers[$user->ID] = array(
'last' => $user->last_name,
'first' => $user->first_name,
'nicename' => $user->user_nicename,
'title' => $user->title,
'phone' => $user->phone,
'email' => $user->user_email
);
}
asort($allusers); // sort the users by last name
?>
<table id="staff-directory" class="sortable">
<thead>
<tr>
<th>Name</th>
<th>Title</th>
<th>Phone</th>
<th>Email</th>
<th class="unsortable">Add</th>
</tr>
</thead>
<tbody>
<?php
foreach ($allusers as $auser) { ?>
<tr class="vcard" id="<?php echo $auser['nicename']; ?>">
<td class="fn uid"><?php echo $auser['last'].", ".$auser['first']; ?></td>
<td class="title"><?php echo $auser['title']; ?></td>
<td class="tell"><?php echo $auser['phone']; ?></td>
<td class="email"><a href="mailto:<?php echo $auser['email']; ?>"><?php echo $auser['email']; ?></td>
<td><a href="http://h2vx.com/vcf/YOUR-URL/?p=<?php echo $post->ID.'#'.$auser['nicename']; ?>">
<img src="/images/vcard.gif" title="Add <?php echo $auser['first'].' '.$auser['last']; ?> to your address book"
alt="Add <?php echo $auser['first'].' '.$auser['last']; ?> to your address book" /></a></td>
</tr>
<?php } ?>
</tbody>
</table>
</div>
<?php comments_template(); ?>
<?php endwhile; endif; ?>
Be sure to replace YOUR-URL with your site’s URL (without the http://) in the last table cell.
Let’s break that down a little.
First, you’ll see that we’re starting a typical loop. This lets us get the page title and comment settings. If you want some introductory content, you could add the_content(); after the title.
Here, instead of using the page’s content, we’re grabbing a list of users and looping through them to create a table. We use the get_users_of_blog() and get_userdata() WordPress functions to build an array of users. (I’ve included the user ID as the array key, but it’s not really needed unless you’re debugging something.) Once we have our array, we can use a simple asort() function to sort by last name, since that’s the first element in our array.
From here, everything should be straightforward — except, perhaps, those classes on the table rows and cells. If you haven’t worked with microformats before, this might look a little strange. The extra classes make up the hCard specification. With a little help from the H2VX service, each of those table rows can be turned into downloadable vCards that you can add to almost any address book application — and that’s exactly what the links in the last column do.
The sortable class on the table allows us to use the sortable, striped table script we wrote about a few days ago. You’ll notice that I added an unsortable class to the last column, since it wouldn’t make sense to sort the vCard links.
Here’s what the table looks like:

The completed directory
You’re not quite finished! You have to create a page in WordPress that uses this template. Add a new page. If you decided to use the_content(), go ahead an fill it in; otherwise, leave the content blank. In the Page Attributes area, choose the page you just created from the dropdown menu. Publish your post and view it. The table should appear.
And there you have it! With two loops and a little strange-looking HTML, we’ve created a complete directory of our site’s users, and even provided visitors with a way to add us to their address books.
Creating a user directory, part 1: changing user contact fields
This is the beginning of a three-part series on building a user directory.
Part 1: Changing the contact fields on the user profile pages
Part 2: Building the user directory page template
Part 3: Building author templates and linking them in the directory
First, we’ll add some new fields: Twitter username, phone number, and job title. Then, we’ll remove the built-in fields we don’t want (all the IM handles). Finally, we add the filter that makes it all work. Here’s the code:
// change user contact fields
function change_contactmethod( $contactmethods ) {
// Add some fields
$contactmethods['twitter'] = 'Twitter Name (no @)';
$contactmethods['phone'] = 'Phone Number';
$contactmethods['title'] = 'Title';
// Remove AIM, Yahoo IM, Google Talk/Jabber
unset($contactmethods['aim']);
unset($contactmethods['yim']);
unset($contactmethods['jabber']);
// make it go!
return $contactmethods;
}
add_filter('user_contactmethods','change_contactmethod',10,1);
Put that in your theme’s functions.php file and have your users fill in the new fields! In the next installment, we’ll build the page template that displays the information.
Add sortable, striped table script — only when needed
Ever wondered how I dressed up the tables on this site? I’ll show you! We’ll use the code for adding stylesheets and scripts conditionally to include Yoast’s improved sortable.js only when a post or page contains a table.
// enqueue sortable.js on pages containing tables
function add_sortable ($posts) {
if (empty($posts)) return $posts;
$found = false;
foreach ($posts as $post) {
if (stripos($post->post_content, '<table')) {
$found = true;
break;
}
}
if ($found) {
wp_enqueue_script('sortable', get_bloginfo('template_url').'/js/sortable.js');
}
return $posts;
}
add_filter('the_posts', 'add_sortable');
Add this to your functions.php file. Then add class="sortable" and a unique ID to your tables and view your post or page. If it worked, your table headings should be clickable, and your table rows should be alternating colors (assuming your stylesheet includes .odd and/or .even classes).
Create private categories
Have you ever tried to create a category consisting entirely of private posts? It’s a pain to have to remember to set the visibility for each post before publishing it. One of my users simply couldn’t remember to do it, resulting in a lot of accidentally public posts on that site.
To solve the problem, I created this little function that catches posts as they’re being saved. It checks to see if the post is in the right categories, and if it’s being published — that is, it leaves draft, pending, and scheduled statuses alone. (It’ll automatically catch the scheduled posts when they go live.) If the post is being published, it gets set to private.
Here’s the code you can put in your theme’s functions.php file:
//update_option('private_categories', array(79,34,75,73), '', 'yes');
add_action('save_post', 'set_private_categories');
function set_private_categories($postid) {
global $wpdb;
if ($parent_id = wp_is_post_revision($postid))
$postid = $parent_id;
$privatecats = get_option('private_categories');
if (!is_array($privatecats))
$privatecats = array($privatecats);
foreach ($privatecats as $cat) {
if (in_category($cat, $postid)) {
// wp_update_post() calls the save_post action again and could create an infinite loop, so we'll use the brute force method...
$wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET `post_status` = %s WHERE ID = %d AND `post_status` = %s", 'private', (int)$postid, 'publish') );
}
}
}
For the sake of simplicity, I haven’t included the code you would need to create an option panel, although you could do so yourself if you like. (I’ll go over it in a later post.) To select your categories using this code alone, uncomment the first line (update_option…). Replace the numbers in the array (79,34,75,73) with the IDs of your private categories. Then view your site. You can view any post or page — on the public side, not from the dashboard — and functions.php will execute, setting your option for you. Then comment out the line again (there’s no need to reset the option every time someone visits your site!) and save functions.php. When you need to add a category, repeat this step.
The private category feature now included in the Private Suite plugin, which includes a number of things related to private and password-protected posts and pages.
Hidden feeds: categories, tags, authors, search terms, links
WordPress generates a number of other feeds in addition to those for posts and comments. There’s a feed for each of your categories and tags. You can also get feeds of posts written by an individual author. You can even get feeds for search results!
Since WordPress doesn’t advertise these hidden feeds, you’ll have to do a little URL manipulation to find them. Of course, once you’ve located them, you can place the links somewhere in your theme so your visitors can find them too.
Since RSS 2.0 and Atom 1.0 are the most popular formats, I’ve given those as the examples for the hidden feeds. However, all four formats are available for all the feeds listed below (except Links). If you want RSS 0.92 or RDF feeds, just replace the appropriate acronyms in the URLs.
Are there any more that I’ve overlooked? Let me know!
Using categories and tags as meta keywords
Your categories and keywords are valuable bits of metadata, but WordPress doesn’t use them in its meta tags. Even the popular All in One SEO Pack plugin uses only categories, not tags.
To use both, add this to the head section of your theme:
<?php if (is_single()) {
foreach((get_the_tags()) as $tag) {
$keywords[] = strtolower($tag->name);
}
foreach((get_the_category()) as $category) {
$keywords[] = strtolower($category->cat_name);
}
?>
<meta name="keywords" content="<?php echo implode(", ", array_unique($keywords)); ?>" />
<?php } ?>
The last line removes duplicates and joins the keywords with a comma — just the way search engines like them.
Sharing notes among users
Dashboard Notepad is the simplest way to share notes on your Dashboard. The widget is configurable, so you can choose the minimum role that can edit the notes and the minimum role to be able to read them.
Including external links in WordPress navigation menus
Sometimes you need to link to something other than a WordPress page in your navigation menu. Perhaps you’ve built a photo gallery in ZenPhoto. How do you get it into your menu without hand-coding all your links?
The Page Links To plugin allows you to do just that. Install the plugin, then create a blank post or page with the title of your desired menu item. Scroll down to the Page Links To section of the edit screen and enter the URL of your external page.
Listing child pages
The Codex offers a way to list the children of the current page by adding this to your theme: Read the rest of this entry »




