I’m quite sure you’re familiar with the Shortcode API. If you’re not, it’s a simple set of functions used by theme and plugin developers to create certain macro codes that can be used throughout the post content. [ gallery ] is one example, meaning you’ll see [ gallery ] when editing the post content, but when actually viewing the post, it generates a full-blown picture gallery out of your uploaded files.
Today we’ll create our own shortcode that will generate a list of authors/contributors with their names, avatars, bios and social media links. We’ll first define a few custom fields to hold our social links in user profiles, then create the shortcode itself and make it generate some basic markup. Finally we’ll quickly go through styling the output and as a bonus I’ll show you how to order the output the way you might need to.
Custom User Fields
The default API and interface for working with users in WordPress is not only good enough for most common setups, but also flexible. This means that with a few actions and filters, you can add your own custom fields to the Edit Profile page and store them in the user meta for later use.
There are four actions that we’ll use to add new fields to the edit user form and to process the input when the form is submitted. These are:
show_user_profileruns at the end of the profile form when editing the current user’s profile, i.e. your ownedit_user_profilesame as the above, but runs when editing a different user’s profile (admins only should be allowed to do this)personal_options_updateruns when the profile form is submitted (on your own profile)edit_user_profile_updateruns when form is submitted on a different user’s profile (for admins)
Adding the Fields
We’ll keep it quite simple in our tutorial and we’ll use one callback function per pair. Let’s start with the first one to add the fields to the profile screen:
add_action( 'show_user_profile', 'my_user_profile_fields' );
add_action( 'edit_user_profile', 'my_user_profile_fields' );
And the callback function itself would print some extra fields in simple HTML and a table layout. We do miss the Settings API here, but okay:
function my_user_profile_fields( $user ) {
?>
<h3>Social</h3>
<table class="form-table">
<tr>
<th><label for="twitter_url">Twitter URL</label></th>
<td>
<input type="text" name="twitter_url" /><br />
</td>
</tr>
</table>
<?php
}
I added only one field to hold the Twitter URL for brevity but you can go ahead and add one for Facebook, Linked In and Google+. Just make sure you don’t user reserved and too generic meta names. To be on the safe side you can even prefix them with your theme or plugin name.
This will result in the extra section created in the edit profile page, but as it is, it won’t work. The Twitter field will remain empty, that is because you’re not catching the input and WordPress won’t do it for you automatically (which is a good thing).
Catching and Saving the Input
Back to the actions I wrote about earlier, we’ll now hook to the update ones and have them read our POST data and save the field (or fields if you added more than one) into our user meta. So register the hooks:
add_action( 'personal_options_update', 'save_my_user_profile_fields' );
add_action( 'edit_user_profile_update', 'save_my_user_profile_fields' );
And write the callback function (again, one function for both actions):
function save_my_user_profile_fields( $user_id ) {
if ( ! current_user_can( 'edit_user', $user_id ) )
return false;
update_user_meta( $user_id, 'twitter_url', $_POST['twitter_url'] );
// Update your own fields here
}
First of all we run a quick check to see if the current user can really edit the user’s fields. Next, with one or more calls to the update_user_meta function we write our values into the database and that’s pretty much all there is to it. Here’s where we’re at:
Now you’ve got some extra fields in your edit profile screen. So what? Well first of all you can use the meta anywhere in your template files now when dealing with the post author like a signature at the end of posts or perhaps on the author archives pages, but we’re working on a shortcode to list them all, remember?
Creating the Shortcode
If this is your first time creating a shortcode in WordPress, I suggest you read the Shortcode API Codex entry first. Our new shortcode won’t have any attributes and won’t have any content. We’ll call it authors-list so you’ll use [ authors-list ] in your post content to generate the output.
One quick note, throughout the article I’m writing the shortcodes with extra spaces. This way WordPress doesn’t recognize it as a shortcode so it gets printed as is instead of being parsed. To actually use the shortcodes you have to remove the extra space symbols.
add_shortcode('authors-list', 'my_authors_list_shortcode');
function my_authors_list_shortcode( $atts = array() ) {
global $wpdb;
$users = $wpdb->get_results( "SELECT ID, display_name FROM {$wpdb->users}" );
$content = "<ul class='authors-list'>";
foreach( $users as $user ) {
$content .= "<li>";
$content .= get_avatar( $user->ID, 70 );
$content .= "<h3>" . $user->display_name . "</h3>";
$content .= "<p class='author-description'>" . get_user_meta( $user->ID, 'description', true ) . "</p>";
$content .= "<p><a href='". get_user_meta( $user->ID, 'twitter_url', true ) . "' class='twitter-icon' target='_blank'>Twitter</a><!-- add more here --></p>";
$content .= "</li>";
}
$content .= "</ul>";
return $content;
}
Quote lengthy, eh? Let’s go through step by step. First we add a shortcode called authors-list with the add_shortcode function using the my_authors_list_shortcode as the callback function. Inside the callback function we’re accepting an $atts array but we’re not actually using it, although you might extend the shortcode to make use of some extra attributes later on.
Next we fire an SQL query to the global $wpdb object which is our WordPress database. We ask for all the users IDs and their display names, then loop through them after opening an unordered list. Note that all the output happens through the $content variable, not echo or print. This is because shortcodes have to return the values, not print them.
Inside the users loop we create a list item containing the user avatar, the display name, bio (user description) and the Twitter URL as a link. I gave the Twitter URL anchor the twitter-icon class so we can use some CSS to style it and give it a nice-looking Twitter icon later on. Here’s what we have so far:
You can add more conditionals to make sure the Twitter URL actually exists before print it out as a link, same with the author description. I left it out for brevity, assuming that all users will have bios and Twitter profiles ;) Let’s move on to some styling.
Styling the Output
This is the fun part. You can go ahead and inspect what has been generated by the shortcode using Chrome’s developer tools or Firebug. You can add more classes to the shortcode itself if you need more control, but the basics are these:
ul.authors-list {
list-style: none;
margin: 0;
padding: 0;
}
ul.authors-list li {
margin-bottom: 30px;
clear: both;
}
ul.authors-list img.avatar {
float: left;
}
ul.authors-list p,
ul.authors-list h3 {
display: block;
margin-left: 80px;
margin-bottom: 0;
}
ul.authors-list a.twitter-icon {
background: url(twitter_icon.gif) 0 0 no-repeat;
display: inline-block;
width: 30px;
height: 20px;
text-indent: -3000px;
}
Note how I replaced the Twitter text in the anchor with a Twitter bird image. With a little more fine tuning to the styles above here’s what I have been able to achieve:
But that’s not all.
Sorting/Ordering and Filtering
It’s cool if you’re running a blog with 5 contributing users and the shortcode will output them all ordered by their IDs. Sometimes you’d want to order by their names, sometimes you’d want a custom order and what if you’ve got 20 users 5 of which actually write the content? So you’d want to filter them out too.
For the best control you’d want a custom order. Of course a drag-n-drop interface would be cool and awesome, perhaps when you’re writing a neat plugin out of this. I like to keep thing as simple as possible, so what I did was create an extra meta field called Order and gave it a number. I filtered out all the users who’s order number is 0 or empty and ordered the rest by the numeric.
The filtering trick is quite straightforward, all you have to do is create an extra condition in the my_authors_list_shortcode function, while ordering is a tiny bit more complex. Suppose your ordering meta field is stored as my_order, here’s how you would replace the SQL query:
$users = $wpdb->get_results("SELECT ID, display_name FROM {$wpdb->users} JOIN
{$wpdb->usermeta} ON {$wpdb->usermeta}.user_ID = {$wpdb->users}.ID WHERE
{$wpdb->usermeta}.meta_key = 'my_order' ORDER BY CAST({$wpdb->usermeta}.meta_value AS DECIMAL);");
Monsterous, eh? Well it’s quite simple actually, it just JOINs on the user meta table and filters out with the my_order meta key, then CASTs the value as a decimal (meta values are stored as character strings) and then finally hands it over to the ORDER BY clause.
If you’re dealing with thousands of users and millions of page visits, you might want to add an extra index on the ( user_id, meta_key ) fields and of course move any filtering conditions from the shortcode function into the SQL query too. This way you won’t be querying for all your thousands of users just to output three of them. Also check your slow query log and if needed tune your MySQL query cache (or maybe as a Transient) to cache the whole result of the query.
Conclusion
This is the same (or very close to the) technique we use on our about page. Of course most things come with a little bit of trial and error, but once you get it right you’ll understand exactly how this works. Watch out for privileges too, by adding extra fields to the profile screen all your users (including subscribers) will be able to see them and edit them for their profile, so you might want to introduce a few extra current_user_can calls before going into a live environment.
Hope you learned something new today and let us know if you have any questions or suggestions. Use the comment form below to share your thoughts and don’t forget that we’re tweeting about WordPress too ;) Enjoy your day!






Dude, how did you know exactly what I was working on? Haha – very nice with the sort, that will come in handy.
Aaron, I can read your thoughts hehe, glad it came in handy! Cheers! :)
He must’ve read my todo.txt file for the WordPress theme I was working on too! Crikey!
Tony, you should try keeping your todo’s in Google Calendar or iCal on Mac hehe :) Thanks for your comment! Glad the post was helpful.
I did something like this as a plugin but I created a button in the visual editor with a popup where you can optionally select which authors to display. I also added a Title and Company field along with the social media profiles. An example can be seen here: http://hubspot-wp.bishport.com/team-page/
Jon, looks great, we’ll have to dig into the code, thanks! If anyone else is interested it’s part of a plugin called HubSpot which is available here for free. Cheers!
Nice tutorial.
Thanks AJ, your comment went to spam for some reason :)
Hey, thank you for this tutorial. I was able to re work your example to show a list of social networking buttons based on a specific user id. I’d added extra profile fields and needed to be able to call these specific fields in a shortcode, in a sidebar widget…but I didn’t want to use yet another plugin in order to do it.Thanks!
Good choice McCormicky and thanks for your comment! :)
Pingback: Best WordPress Resources Websites Part1
I love this website Konstantin! Great post as well. reviewed web site and added link to this post here: http://blog.tarakbrahmi.com/2012/01/best-wordpress-resources-websites-part1/
Keep up the great work!