Advanced Power Tips for WordPress Template Developers: Reloaded
Two weeks ago we published the first part of this article, covering multiple column content techniques and associating pages with post content; we discussed how to use the “More”-tag, hide standalone categories from the category list and retain the page layout for post views within a category page. This article presents the second part of the article; it covers customizing basic content administration and adding features to the post and page editor in WordPress. You would like to see more similar articles in the future? Let us know in the comments to this post!
Customizing Basic Content Administration
Many template developers have learned the art of making beautiful, highly customized front end templates for WordPress. But the real wizards know how to tailor the WordPress administrative console to create a tailored, customized experience for content managers.
Customizing the Dashboard Widgets
The dashboard is the first screen presented to registered visitors when they visit WordPress administration (/wp-admin). Tailoring the dashboard to a client can be the difference between a great first impression and a confused one, particularly if the theme customizes the administrative experience.
The dashboard is comprised of a number of widgets that can be repositioned and toggled using the “screen options” tab. WordPress has a hook – wp_dashboard_setup – that can be used to customize the dashboard widgets, as well as a function – wp_add_dashboard_widget – that allows developers to easily add new widgets.
The WordPress codex documents the process of adding and removing widgets.
Here is a practical use case based on that documentation: let’s remove all of the default widgets that don’t pertain to managing a typical site, and add one simple widget that welcomes the administrator and reminds them how to contact the developer for support.
add_action('wp_dashboard_setup', 'my_custom_dashboard_widgets');
function my_custom_dashboard_widgets() {
global $wp_meta_boxes;
unset($wp_meta_boxes['dashboard']['normal']['core']['dashboard_plugins']);
unset($wp_meta_boxes['dashboard']['side']['core']['dashboard_primary']);
unset($wp_meta_boxes['dashboard']['side']['core']['dashboard_secondary']);
wp_add_dashboard_widget('custom_help_widget', 'Help and Support', 'custom_dashboard_help');
}
function custom_dashboard_help() {
echo '<p>Welcome to your custom theme! Need help? Contact the developer <a href="http://mytemplates.com">here</a>.</p>';
}

Customizing the Contextual Help Dropdown
Throughout its administrative panel, WordPress has a small “Help” tab just below the administrative header. Clicking this tab rolls down contextual help for the current administrative page.

If your theme has some special functionality that might not be intuitive, it’s a good practice to add some additional contextual help. For example purposes, let’s assume that the theme has been customized to use the “more divider” to separate content into two columns, as described in the first tip. That’s probably not an obvious feature for your average content editor. To accomplish this, hook the contextual help text when on the “new page” and “edit page” administrative pages, and add a note about that feature.
//hook loading of new page and edit page screens
add_action('load-page-new.php','add_custom_help_page');
add_action('load-page.php','add_custom_help_page');
function add_custom_help_page() {
//the contextual help filter
add_filter('contextual_help','custom_page_help');
}
function custom_page_help($help) {
//keep the existing help copy
echo $help;
//add some new copy
echo "<h5>Custom Features</h5>";
echo "<p>Content placed above the more divider will appear in column 1. Content placed below the divider will appear in column 2.</p>";
}

Dropping in Your Own Logo
Providing the client some administrative branding can be quick and easy. Here’s how to replace the default WordPress “W” logo in the administrative header with a custom alternative.
First, create an image that fits the allocated space. As of WordPress 2.8, the logo is a 30 pixels wide and 31 pixels tall transparent GIF. When using a transparent GIF or 8-bit PNG, ensure that the image matte matches the header background color: hex value 464646.
A logo named “custom_logo.gif” inside the template directory’s image subfolder can substitute the default WordPress logo with the following code inside the theme’s “functions.php” file.
//hook the administrative header output
add_action('admin_head', 'my_custom_logo');
function my_custom_logo() {
echo '
<style type="text/css">
#header-logo { background-image: url('.get_bloginfo('template_directory').'/images/custom-logo.gif) !important; }
</style>
';
}

Hiding Fields Based on User Role
Basic contributors might be confused or distracted by some of the boxes that surround the page or post editor, particularly if there are a handful of plug-ins that have added their own meta boxes. Alternatively, the content editor might simply want to keep author and contributor hands off of some special fields or features.
Let’s say the content editor wants to keep authors and contributors way from the “custom fields” box. We can use the “remove_meta_box” function – regardless of user role – to remove that from all post editing screens like so:
//hook the admin init
add_action('admin_init','customize_meta_boxes');
function customize_meta_boxes() {
remove_meta_box('postcustom','post','normal');
}
The “remove_meta_box” function takes three parameters. The first is the ID of the box. The easiest way to discover the ID of the meta box is to look for the ID attribute of the corresponding DIV “postbox” in the source code. The second parameter determines which the context the function applies to: page, post, or link. Finally, the context attribute determines the position within its context: normal, or advanced (in most cases, just setting this to “normal” will work fine).

The next step is to extend the “customize_meta_boxes” function so that the “custom fields” box – ID “postcustom” – is only hidden from users with author role or lower. We’ll use get_currentuserinfo to retrieve the user level. According to the WordPress codex, authors represent level 2.
//hook the admin init
add_action('admin_init','customize_meta_boxes');
function customize_meta_boxes() {
//retrieve current user info
global $current_user;
get_currentuserinfo();
//if current user level is less than 3, remove the postcustom meta box
if ($current_user->user_level < 3)
remove_meta_box('postcustom','post','normal');
}
Adding Features to the Post & Page Editor
WordPress provides a “custom fields” box that makes it quick and easy to start adding new metadata to your pages and posts. For a tech-savvy client or low budget customization, this is a great, inexpensive method to start adding some unique fields for a custom implementation.

But there are plenty of times when something more specialized than a generic “custom fields” box may be appropriate. A less savvy client may be confused by the generic fields that lack any documentation. A checkbox for a Boolean field may be more intuitive for a client than instructions to choose the custom field name from a drop down and type in “1” or “true” under the value. column Or maybe the field should be limited, in select box like fashion, to a few different choices.
The WordPress API can be used to add custom meta boxes to pages and / or posts. And with WordPress 2.8, adding new, tag-like taxonomies is a cinch.
Adding a Custom Meta Box
Let’s say a hyper-local journalist has hired us to build a news blog that covers politics in New York City. The journalist has a few writers on her team, none of whom are particularly tech-savvy, but they will all be set up as authors and posting their reports directly in WordPress. Our imaginary client wants each article associated with a single borough, in addition to a “city-wide” option. Articles will never be associated with 2 boroughs, and the staff is prone to typos.
A developer accustomed to basic WordPress administrative customization would probably go to “categories” first. Make a “city-wide” category, with sub-categories for each borough. However, categories are multi-select, and there’s no obvious way to prevent authors from selecting several. Furthermore, the client wants the borough named at the beginning of the article, and if categories are used in other ways (like news topics), extracting the borough name would be a bit tricky.
So how about a “custom field” for “borough”? The authors never remember to look in that generic custom fields box, and in their rush to meet deadlines, occassionally spell the borough wrong, breaking the “filter by borough” feature on the front end.
The right answer is a new custom “meta box,” with a drop down “Borough” field. The WordPress Codex documents the “add_meta_box” function in detail.
Let’s apply the code discussed in the codex to this use case, assuming we want the “Borough” field to only appear on posts (not pages), and be shown on the top-right of the post editor page.
/* Use the admin_menu action to define the custom boxes */
add_action('admin_menu', 'nyc_boroughs_add_custom_box');
/* Adds a custom section to the "side" of the post edit screen */
function nyc_boroughs_add_custom_box() {
add_meta_box('nyc_boroughs', 'Applicable Borough', 'nyc_boroughs_custom_box', 'post', 'side', 'high');
}
/* prints the custom field in the new custom post section */
function nyc_boroughs_custom_box() {
//get post meta value
global $post;
$custom = get_post_meta($post->ID,'_nyc_borough',true);
// use nonce for verification
echo '<input type="hidden" name="nyc_boroughs_noncename" id="nyc_boroughs_noncename" value="'.wp_create_nonce('nyc-boroughs').'" />';
// The actual fields for data entry
echo '<label for="nyc_borough">Borough</label>';
echo '<select name="nyc_borough" id="nyc_borough" size="1">';
//lets create an array of boroughs to loop through
$boroughs = array('Manhattan','Brooklyn','Queens','The Bronx','Staten Island');
foreach ($boroughs as $borough) {
echo '<option value="'.$borough.'"';
if ($custom == $borough) echo ' selected="selected"';
echo '>'.$borough.'</option>';
}
echo "</select>";
}
/* use save_post action to handle data entered */
add_action('save_post', 'nyc_boroughs_save_postdata');
/* when the post is saved, save the custom data */
function nyc_boroughs_save_postdata($post_id) {
// verify this with nonce because save_post can be triggered at other times
if (!wp_verify_nonce($_POST['nyc_boroughs_noncename'], 'nyc-boroughs')) return $post_id;
// do not save if this is an auto save routine
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return $post_id;
$nyc_borough = $_POST['nyc_borough'];
update_post_meta($post_id, '_nyc_borough', $nyc_borough);
}
Take another look at the second to last line in that code block, where the post metadata is updated (update_post_meta will also add the meta if it does not exist). That function stores the field key and value (second and third parameters), assigned to the designated post (first parameter) in the same generic “way” that custom fields are stored. Notice that the field key name was prefaced with an underscore: “_nyc_borough”. Meta fields with keys beginning with an underscore are not shown in the generic “custom fields” box. All other meta fields are shown in that box.

We can use this field value in our template just as we would embed generic custom fields.
echo get_post_meta($post->ID, '_nyc_borough', true);
If we want to do a post query that only includes posts in the “Queens” borough, we can execute the query with the following code:
query_posts('meta_key=_nyc_borough&meta_value=Queens');
Adding Custom Taxonomies
A taxonomy, generically defined, is a “classification.” Post tags and categories in WordPress are both types of taxonomies, one of which – categories – has a “hierarchical” proprietary: categories can have child and parent categories. The ability to define new taxonomies has actually been around in some basic form since WordPress 2.3 – but WordPress 2.8 ups the ante, making it incredibly easy for template developers to add and manage tag-like taxonomies.
At the core API level, taxonomies may be hierarchical (or not, a la “tags”) , associated with pages or posts, and have a few other more esoteric properties related to allowing post queries and permalink structures. The potential for custom taxonomies is considerable – posts could easily have two types of categories, pages could have multiple tags, and sites could have multiple tag clouds based on groupings more specific that a generic “tag.”
While the architecture for all of this is all there, the real magic of custom taxonomies – introduced in 2.8 – has only been enabled for posts and non-hierarchical types. But if those qualifications aren’t a show stopper, a developer can get a lot of value out of just a few lines of code: a new tag-like meta box added to posts, a new “posts menu” option for managing those values, and the ability to easily output clouds, filter by taxonomies, design taxonomy templates, and do just about anything one could do with generic “tags” on the front end.
The WordPress Codex outlines the “register_taxonomy” function.
Let’s go back to that hyper-local New York City politics blog. Say the editor wants authors to be able to “tag” articles with a distinct “people” taxonomy, but still wants to retain generic tagging. The new “people” taxonomy will highlight the names of political leaders mentioned in articles. On the front end the editor envisions a “tag cloud” that will help the most active politicians get recognized (for better or worse!). Clicking on a leader’s name in the cloud should bring up a list of articles “tagged” with the given politician.
The following few lines of code will add the new “people” meta box to posts and add a new option to the “posts” menu where the taxonomy values can be managed.
//hook into the init action to add the taxonomy
add_action( 'init', 'create_nyc_people_taxonomy');
//create nyc people taxonomy
function create_nyc_people_taxonomy() {
register_taxonomy('people', 'post', array('hierarchical' => false, 'label' => 'people'));
}

To output a cloud for this custom taxonomy highlighting the 40 most-tagged politicians, the generic “wp_tag_cloud” function can be used with a few parameters.
wp_tag_cloud(array('taxonomy' => 'people', 'number' => 40));
To list the highlighted leaders in a single post:
echo get_the_term_list($post->ID, 'people', 'People: ', ', ');
Clicking on a person’s name will automatically take the visitor to an archive for that taxonomy. Custom template files can also be built for the custom taxonomy. A “taxonomy.php” template file in the theme folder can be used for all custom taxonomies. A “taxonomy-people.php” template file could be used for the “people” taxonomy in the example. As with all archives, if no taxonomy-specific template files are available, WordPress will fall back to the generic “archive” and “index” template files.


Mirza Aliyev
December 14th, 2009 7:30 amUseful. Thank you. Liked dropping own logo into admin panel :)
Thomas Evangelista
December 14th, 2009 3:52 pmOhh man your amazing, thanks so much for this post Jacob!!
Andre
December 14th, 2009 11:46 pmYeah, thats what I’m searching for… very nice =)
Keven Bouchard
December 14th, 2009 7:30 amReally nice article! seriously!
It’s fun having admin customization tips instead of the redundant template stuffs.
Joel G Goodman
December 14th, 2009 7:38 amAwesome. Posts like these get my mind working on a bunch of possibilities for future projects. Thanks for mixing this kind of stuff in with the rest of your creative content.
Lourens
December 14th, 2009 7:47 amThank you soooo much, great article and great examples!!
codee47
December 14th, 2009 8:01 amGreat articles, thanks. I love wordpress :)
Paul
December 14th, 2009 8:02 amVery useful, indeed. More like this please!
Steven Rossi
December 14th, 2009 8:05 amUsing meta boxes with underscore-named fields is one of my favorite things about the WP backend. I wish more people would make use of it.
Nathan Barry
December 14th, 2009 8:31 amGreat article. I am enjoying the advanced tips. Though could you please work on a title that is actually descriptive of the post content?
HERO
December 14th, 2009 9:17 amWell written and extremely useful. There aren’t a lot of resources on this topic, making this article even more valuable. Kudos Jacob.
Kawsar Ali
December 14th, 2009 9:22 amThis is really great. Useful for creating customized back end
Chris Robinson
December 14th, 2009 9:24 amReally nice article, definitely going to use some of this in my next WP theme.
Darfuria
December 14th, 2009 10:07 amVery informative post, thanks!
Matt
December 14th, 2009 10:25 amWith the popularity of WordPress being used as a CMS for clients customizing the admin area is a must. Good post.
Design Informer
December 14th, 2009 10:34 amI personally love these types of posts from Smashing Magazine. I’m not a developer but I am a huge fan of WordPress and what it’s capabilities are, and these types of articles/tutorials really show us the power of WordPress.
I’m personally going to try that logo branding on my next client WordPress project. Thanks Smashing Magazine, and I look forward to more articles from this series.
dmantra
December 14th, 2009 10:50 amthis is really going to help!! gr8 post
Shaun
December 14th, 2009 11:24 amThese tips are going to be so useful, thank you. The screenshots really help too. More and more articles like this please!
Brian
December 14th, 2009 11:38 amWordPress posts by Smashing Mag are the best. I enjoyed learning how to replace the default WordPress admin logo with a custom logo.
Montia Garcia
December 14th, 2009 11:49 amExcellent post.
FrankieB
December 14th, 2009 12:05 pmI love this post, very informative. How would all of these types of changes affect WordPress updates?
Steffen Jørgensen
December 14th, 2009 6:35 pmUnless WP changes the names on the functions in the core it shouldn’t change after an update, as these changes are writtes into the theme functions.php.
Jason
December 14th, 2009 12:33 pmGood stuff, will come in handy with the theme I am developing at the moment.
Kharismatic
December 14th, 2009 12:57 pmThis is an awesome post! I’ve always wanted to do a little customization in the WordPress back-end. This tutorial gives me enough confidence to go back there to make it my own! Thanks!
BigM75
December 14th, 2009 1:21 pmwow – better works whit that
Level Level
December 14th, 2009 1:23 pmgreat article! more of these please
redwall_hp
December 14th, 2009 1:51 pmThis is hardly exclusive to theme developers. It’s a great article for us plugin developers, too!
Mike
December 14th, 2009 2:59 pmGreat, ty so much
Crystal
December 14th, 2009 3:55 pmAwesome article. I’ve done a few WordPress themes, but I love constantly learning more ‘tricks of the trade’ when it comes to premium theme design. Great collection of techniques here, and very well explained. Thank you Jacob!
The Lone Grainger
December 14th, 2009 4:18 pmGreat article! Thank you so much for all your work!
Anjum nawab
December 14th, 2009 10:06 pmOkay seems pretty Good. Guys i am new to CMS’s can you please tell me which CMS is good Joomla or WP as both are open source. If joomla then please write some stuff for it because I can find many help/ resources for WP but i dont for Joomla..
Thanks a lot its very interesting/Informative post :)
jan
December 15th, 2009 7:11 amWell, as you say wordpress is highly featured everywhere :p
There’s a reason for that I think, but also drupal is really nice still wordpress is so easy to use and customize nothing can’t change it for me :)
Keep up the good work both smashing and wordpress :)
spritzstuhl
December 15th, 2009 12:28 amSounds interesting and seems to be appreciated by the audience. But WP still needs to much of coding to spice it up (personal opinion). Anyway I’ll try it out. Promised!!
Jonas
December 15th, 2009 12:42 amThanks for the tips!
Murali Kumar
December 15th, 2009 12:57 amWOW, great tips.
Thanks a ton.
Jonathan Downin
December 15th, 2009 2:05 amThe custom taxonomy stuff is a revelation for me, but after implementation, when a link is clicked in a custom taxonomy tag list, it goes to a “not found” page instead of rolling back to using an archive or index page. Can anyone point me to a taxonomy.php template?
Also, any easy way to move the tags of 1000+ posts worth of tags in new taxonomies in a “mass edit” sort of way?
Marta
December 15th, 2009 3:04 pmThe ‘no found’ page is a common problem after registering a new taxonomy. A simple fix is to go to your settings – permalinks and change the permalinks to custom structure like: /%postname%/
(even if you already have them set up, you need to ‘reset’ permalinks for taxonomies pages to work)
Jonathan Downin
December 18th, 2009 11:00 pmThat totally fixed the problem, thanks. Now onto figuring out the 1000+ posts problem.
charm
December 15th, 2009 2:48 amThese tips are going to be so useful, thank you. The screenshots really help too. More and more articles like this please!
thx
my blog Pepitup
sergio
December 15th, 2009 4:32 amVery clear and useful, thanks!
Shiraz
December 15th, 2009 4:55 amGreat write up – thanks! Still being quite new to WP, I’m wondering if these changes would be retained once you perform an upgrade?
fldtrace
December 16th, 2009 12:04 pmas long you have your function file intact, I would say that yes. However, I am unsure that the code will be compatible with WordPress ver X.X, but no worries until than.
paul
December 15th, 2009 7:42 amnice, some stuff i didnt know about wordpress… and some new ideas… thanks smashing magazine, your awsome.
Bestie
December 15th, 2009 7:57 amNice tips! I Love WordPress!
Sebastian Oxide
December 15th, 2009 11:59 amThanks for a great post!
Is there a way you can put a condition on “Adding a custom meta box”?
So if I for example select in the drop down menu “New York” and save, a new custom meta box appears specific for that selection?
Manet
December 15th, 2009 4:45 pmNice work for the Author. Think twice for the developer.
All I can say is “think changes, think upgrade”.
Gold Rush
December 16th, 2009 9:38 amGuys, anybody can help me? I create two taxonomy. I can see them in the post. I added tags – stll work. But then i create tag cloud it doesnt work – only 404 page like this _gamequote.ru/game/planescape-tournament or _gamequote.ru/character/glados . What i do wrong?
ec
December 17th, 2009 6:25 amAmazing post – really useful and detailed.
Jill
December 17th, 2009 10:37 amThis is great. I’ve been wondering how to use custom taxonomies but hadn’t found time to do any research. It’s all right here. Thanks!
Jauhari
December 21st, 2009 6:51 amWonderful tricks
palPalani
January 6th, 2010 10:25 amayo. superb tips.. each line is very usefull!!
Thiago A. Villa Menezes
January 9th, 2010 9:39 amIn which file do I put that code? O.o
_Tristan
January 24th, 2010 8:56 amYea! Good stuff even if its a bit old!
Dave Y.
February 5th, 2010 7:41 pmWhenever I cut & paste the code in from the “Add meta box” section, I start having redirect errors in the admin section where it just goes to the blank page. Is that because it’s supposed to be in a file other than the theme’s functions.php file or is it something else? Anyone else experience this problem?
Zach
February 23rd, 2010 4:22 pmGreat tips! Thanks.
josemanuel
February 24th, 2010 1:19 pmbrilliant
timani
March 10th, 2010 9:50 amgood read especially the logo on the admin even though it may be a simple one and definitely the taxonomies!
davide
March 23rd, 2010 1:38 amIs there any way to sort all the box in a custom way? The ‘priority’ argument in add_meta_box seems too weak to me
Bilal Ahmed
April 8th, 2010 10:20 pmreally nice article, especially custom meta box portion
devashish
April 24th, 2010 10:01 amVery useful article.. i was looking for sumthing similar to “Remove dashboard widgets”. Can the code be update so the widgets are not removed for administrator and editor role users?
Keith
April 27th, 2010 2:25 amI tried for ages to work out which file I needed to edit. It isn’t until ‘Dropping in your own Logo’ that ‘functions.php’ is mentioned. Could you edit this into the first section?
XLCowBoy
May 16th, 2010 11:04 pmit would be nice to be able to have user-edit comments natively
UnfaincUlcefe
June 9th, 2010 2:23 amHi-ya i am fresh to this, I stumbled upon this message board I find It vastly helpful and it’s helped me out tons. I should be able to contribute and support others like its helped me.
Thanks a load, Catch You Later.
Jamie Brewer
June 14th, 2010 6:27 amReally Great article! I’m sure I’ll use a couple of these techniques! Anyway I came here looking to add a custom meta box with an upload field (so users can upload images). Anyone have any idea where I could find a tut or article on that?
UnfaincUlcefe
June 18th, 2010 5:46 amAloha i’m fresh on here, I came upon this chat board I find It positively helpful & it’s helped me so much. I should be able to give something back & aid other people like it has helped me.
Thanks a load, Catch You About.
UnfaincUlcefe
June 20th, 2010 12:16 amHiya i’m fresh here, I hit upon this message board I find It vastly accessible & its helped me alot. I hope to contribute & support other users like it has helped me.
Thanks a load, See Ya About.
UnfaincUlcefe
June 20th, 2010 2:49 amHeya im new on here. I hit upon this board I find It truly accommodating and its helped me alot. I should be able to contribute & guide others like it has helped me.
Cheers, See You About.
GemHeisse
June 22nd, 2010 9:01 amAloha everybody, brilliant site I find It absolutely accessible & its helped me tons
I hope to give something back & guide other users like this message board has helped me
chaliaDadly
June 22nd, 2010 3:56 pmHiya i’m new here, I came upon this chat board I have found It very helpful & its helped me out a lot. I hope to contribute & assist others like it has helped me.
Thanks, See You Later
Tyar
August 12th, 2010 11:12 pmamazing tips.. tengkiu..
helpin
September 2nd, 2010 5:16 amWhere do I add code to include “help widget ” in dash board?In theme’s functions.php or admin-functions.php in installation folder?
DAN
October 16th, 2010 10:52 amWhen adding a custom meta box to posts, is nonce verification really necessary for each meta box?
I think only one nonce value per form tag is needed which WordPress already generates for posts automatically.
Killer tips – thanks!
Kuldeep
November 10th, 2010 9:58 amNice ones. I was actually looking for these tutorials. Thanks again
sabarinathan
November 28th, 2010 10:58 pmreally a nice article……..
масла
December 19th, 2010 10:27 amthanks ….very amazing tips
El garch
March 11th, 2011 9:01 amVery useful thanks a lot keep postin’ :D
Marko
July 23rd, 2011 4:35 amin 3.2 WP generates it as:
how can we go about it?
Rich
November 3rd, 2011 1:36 pmHi
Thanks for the post. I am trying to add some of the code to a functions plugin rather than functions.php. I have started with the custom logo in the admin area but it is not showing up. Do I need to change something for a plugin please?
Thanks
Rich
Sam Greensted
November 24th, 2011 1:58 amGreat post, thanks for the handy collection.
Sam
Somavieva
February 12th, 2012 1:54 amHello, I am new here, from Canada, want to learn more knowledge.
Peeplycyboala
January 30th, 2013 4:22 amI really enjoy reading articles but this has been so nice.
Keep it up!