Google are now well into their roll out of the search results featuring the rel=”author” tag. The main benefit of this is that Google are able to assign posts and pages to specific authors. The secondary- and mainly vain
– benefit is that you could get your photo in the search results next to your article.
This tutorial assumes a number of things;
- you are comfortable with basic scripting and css,
- you are running Wordpress,
- your WordPress theme has a author archive page,
- you are using Register Plus Redux and user photo plugins,
- you have a Google profile.
The author rel mark up may be a new thing for Google but there is a lot of potential for both Google and you if it becomes established.
Putting rel=”author” into our WordPress theme.
First of all lets get the rel=”author” tags into place in WordPress. If you are running the latest version of WordPress then there should be no need to make any changes to the core files as rel=”author” was introduced in WordPress 3.2 and it was also introduced into the default TwentyTen and TwentyEleven themes.
While most of us would not have changed the core files a lot of us will be running non standard themes or at the very least child themes so lets do some checking that we are set up for the author mark up.
The easiest thing to do is to open up a post and look at the source file. If your link to your author archive page has the rel=”author” tag attached then you’re fine. If you don’t then do the following in your theme folder;
I’m assuming here you have an author box or some other link back to your author.php archive. I’m also concentrating on child themes of TwentyTen as this how I run web sites. You may need to change other files depending on the theme that you are running.
For TwentyTen and TwentyEleven the full list of files you need to change are given in the trac ticket here. If you are using default themes and have not made any changes then you will not need to do anything as the theme updates will have dealt with the issue but if you are using child themes and have made changes then you will need to update.
Open up loop-single.php and look for the line of code that says;
<a href="<?php echo get_author_posts_url( get_the_author_meta( 'ID' ) ); ?>">
All you need do is to add the rel=”author” tag to it giving;
<a href="<?php echo get_author_posts_url( get_the_author_meta( 'ID' ) ); ?>" rel="author">
If you reload you page (after clearing any caches) you will see that your link to the author.php page now has the author mark up assigned to it.
We could just keep our author archive page as the default version but to get maximum benefit of the author mark up we really need to develop the author.php page into a fully fledged author profile.
I’ve previously posted a bit about putting place tabs on an author.php page and I’ll expand on that a little here. If you don’t want to build the page yourself then you can download the skeleton of the page from the previous post for £20.00 all you need to do then is to add the Google profile field which is given later.
Tabbed author archive in WordPress.
I want to have three tabbed sections of my author page; Profile, blog postings, comments. You need to download the domtab javascript resource for the core code (though all the scripts needed are within this tutorial. For me domtab is the best way of dong tabs because if the browser does not support javascript then it downgrades nicely into named anchors.
Although it’s not the official way of calling javascript in WordPress because the author page is the only location that I’m using these tabs on my site I’m happy to call the javascript within the page. So I’ve added the following code just after the;
get_header(author); ?>
Add the domtab javascript:
<script type="text/javascript">
/* <![CDATA[ */
/*
DOMtab Version 3.1415927
Updated March the First 2006
written by Christian Heilmann
check blog for updates: http://www.wait-till-i.com
free to use, not free to resell
*/
domtab={
tabClass:'domtab', // class to trigger tabbing
listClass:'domtabs', // class of the menus
activeClass:'active', // class of current link
contentElements:'div', // elements to loop through
backToLinks:/#top/, // pattern to check "back to top" links
printID:'domtabprintview', // id of the print all link
showAllLinkText:'show all content', // text for the print all link
prevNextIndicator:'doprevnext', // class to trigger prev and next links
prevNextClass:'prevnext', // class of the prev and next list
prevLabel:'previous', // HTML content of the prev link
nextLabel:'next', // HTML content of the next link
prevClass:'prev', // class for the prev link
nextClass:'next', // class for the next link
init:function(){
var temp;
if(!document.getElementById || !document.createTextNode){return;}
var tempelm=document.getElementsByTagName('div');
for(var i=0;i<tempelm.length;i++){
if(!domtab.cssjs('check',tempelm[i],domtab.tabClass)){continue;}
domtab.initTabMenu(tempelm[i]);
domtab.removeBackLinks(tempelm[i]);
if(domtab.cssjs('check',tempelm[i],domtab.prevNextIndicator)){
domtab.addPrevNext(tempelm[i]);
}
domtab.checkURL();
}
if(document.getElementById(domtab.printID)
&& !document.getElementById(domtab.printID).getElementsByTagName('a')[0]){
var newlink=document.createElement('a');
newlink.setAttribute('href','#');
domtab.addEvent(newlink,'click',domtab.showAll,false);
newlink.onclick=function(){return false;} // safari hack
newlink.appendChild(document.createTextNode(domtab.showAllLinkText));
document.getElementById(domtab.printID).appendChild(newlink);
}
},
checkURL:function(){
var id;
var loc=window.location.toString();
loc=/#/.test(loc)?loc.match(/#(\w.+)/)[1]:'';
if(loc==''){return;}
var elm=document.getElementById(loc);
if(!elm){return;}
var parentMenu=elm.parentNode.parentNode.parentNode;
parentMenu.currentSection=loc;
parentMenu.getElementsByTagName(domtab.contentElements)[0].style.display='none';
domtab.cssjs('remove',parentMenu.getElementsByTagName('a')[0].parentNode,domtab.activeClass);
var links=parentMenu.getElementsByTagName('a');
for(i=0;i<links.length;i++){
if(!links[i].getAttribute('href')){continue;}
if(!/#/.test(links[i].getAttribute('href').toString())){continue;}
id=links[i].href.match(/#(\w.+)/)[1];
if(id==loc){
var cur=links[i].parentNode.parentNode;
domtab.cssjs('add',links[i].parentNode,domtab.activeClass);
break;
}
}
domtab.changeTab(elm,1);
elm.focus();
cur.currentLink=links[i];
cur.currentSection=loc;
},
showAll:function(e){
document.getElementById(domtab.printID).parentNode.removeChild(document.getElementById(domtab.printID));
var tempelm=document.getElementsByTagName('div');
for(var i=0;i<tempelm.length;i++){
if(!domtab.cssjs('check',tempelm[i],domtab.tabClass)){continue;}
var sec=tempelm[i].getElementsByTagName(domtab.contentElements);
for(var j=0;j<sec.length;j++){
sec[j].style.display='block';
}
}
var tempelm=document.getElementsByTagName('ul');
for(i=0;i<tempelm.length;i++){
if(!domtab.cssjs('check',tempelm[i],domtab.prevNextClass)){continue;}
tempelm[i].parentNode.removeChild(tempelm[i]);
i--;
}
domtab.cancelClick(e);
},
addPrevNext:function(menu){
var temp;
var sections=menu.getElementsByTagName(domtab.contentElements);
for(var i=0;i<sections.length;i++){
temp=domtab.createPrevNext();
if(i==0){
temp.removeChild(temp.getElementsByTagName('li')[0]);
}
if(i==sections.length-1){
temp.removeChild(temp.getElementsByTagName('li')[1]);
}
temp.i=i; // h4xx0r!
temp.menu=menu;
sections[i].appendChild(temp);
}
},
removeBackLinks:function(menu){
var links=menu.getElementsByTagName('a');
for(var i=0;i<links.length;i++){
if(!domtab.backToLinks.test(links[i].href)){continue;}
links[i].parentNode.removeChild(links[i]);
i--;
}
},
initTabMenu:function(menu){
var id;
var lists=menu.getElementsByTagName('ul');
for(var i=0;i<lists.length;i++){
if(domtab.cssjs('check',lists[i],domtab.listClass)){
var thismenu=lists[i];
break;
}
}
if(!thismenu){return;}
thismenu.currentSection='';
thismenu.currentLink='';
var links=thismenu.getElementsByTagName('a');
for(i=0;i<links.length;i++){
if(!/#/.test(links[i].getAttribute('href').toString())){continue;}
id=links[i].href.match(/#(\w.+)/)[1];
if(document.getElementById(id)){
domtab.addEvent(links[i],'click',domtab.showTab,false);
links[i].onclick=function(){return false;} // safari hack
domtab.changeTab(document.getElementById(id),0);
}
}
id=links[0].href.match(/#(\w.+)/)[1];
if(document.getElementById(id)){
domtab.changeTab(document.getElementById(id),1);
thismenu.currentSection=id;
thismenu.currentLink=links[0];
domtab.cssjs('add',links[0].parentNode,domtab.activeClass);
}
},
createPrevNext:function(){
// this would be so much easier with innerHTML, darn you standards fetish!
var temp=document.createElement('ul');
temp.className=domtab.prevNextClass;
temp.appendChild(document.createElement('li'));
temp.getElementsByTagName('li')[0].appendChild(document.createElement('a'));
temp.getElementsByTagName('a')[0].setAttribute('href','#');
temp.getElementsByTagName('a')[0].innerHTML=domtab.prevLabel;
temp.getElementsByTagName('li')[0].className=domtab.prevClass;
temp.appendChild(document.createElement('li'));
temp.getElementsByTagName('li')[1].appendChild(document.createElement('a'));
temp.getElementsByTagName('a')[1].setAttribute('href','#');
temp.getElementsByTagName('a')[1].innerHTML=domtab.nextLabel;
temp.getElementsByTagName('li')[1].className=domtab.nextClass;
domtab.addEvent(temp.getElementsByTagName('a')[0],'click',domtab.navTabs,false);
domtab.addEvent(temp.getElementsByTagName('a')[1],'click',domtab.navTabs,false);
// safari fix
temp.getElementsByTagName('a')[0].onclick=function(){return false;}
temp.getElementsByTagName('a')[1].onclick=function(){return false;}
return temp;
},
navTabs:function(e){
var li=domtab.getTarget(e);
var menu=li.parentNode.parentNode.menu;
var count=li.parentNode.parentNode.i;
var section=menu.getElementsByTagName(domtab.contentElements);
var links=menu.getElementsByTagName('a');
var othercount=(li.parentNode.className==domtab.prevClass)?count-1:count+1;
section[count].style.display='none';
domtab.cssjs('remove',links[count].parentNode,domtab.activeClass);
section[othercount].style.display='block';
domtab.cssjs('add',links[othercount].parentNode,domtab.activeClass);
var parent=links[count].parentNode.parentNode;
parent.currentLink=links[othercount];
parent.currentSection=links[othercount].href.match(/#(\w.+)/)[1];
domtab.cancelClick(e);
},
changeTab:function(elm,state){
do{
elm=elm.parentNode;
} while(elm.nodeName.toLowerCase()!=domtab.contentElements)
elm.style.display=state==0?'none':'block';
},
showTab:function(e){
var o=domtab.getTarget(e);
if(o.parentNode.parentNode.currentSection!=''){
domtab.changeTab(document.getElementById(o.parentNode.parentNode.currentSection),0);
domtab.cssjs('remove',o.parentNode.parentNode.currentLink.parentNode,domtab.activeClass);
}
var id=o.href.match(/#(\w.+)/)[1];
o.parentNode.parentNode.currentSection=id;
o.parentNode.parentNode.currentLink=o;
domtab.cssjs('add',o.parentNode,domtab.activeClass);
domtab.changeTab(document.getElementById(id),1);
document.getElementById(id).focus();
domtab.cancelClick(e);
},
/* helper methods */
getTarget:function(e){
var target = window.event ? window.event.srcElement : e ? e.target : null;
if (!target){return false;}
if (target.nodeName.toLowerCase() != 'a'){target = target.parentNode;}
return target;
},
cancelClick:function(e){
if (window.event){
window.event.cancelBubble = true;
window.event.returnValue = false;
return;
}
if (e){
e.stopPropagation();
e.preventDefault();
}
},
addEvent: function(elm, evType, fn, useCapture){
if (elm.addEventListener)
{
elm.addEventListener(evType, fn, useCapture);
return true;
} else if (elm.attachEvent) {
var r = elm.attachEvent('on' + evType, fn);
return r;
} else {
elm['on' + evType] = fn;
}
},
cssjs:function(a,o,c1,c2){
switch (a){
case 'swap':
o.className=!domtab.cssjs('check',o,c1)?o.className.replace(c2,c1):o.className.replace(c1,c2);
break;
case 'add':
if(!domtab.cssjs('check',o,c1)){o.className+=o.className?' '+c1:c1;}
break;
case 'remove':
var rep=o.className.match(' '+c1)?' '+c1:c1;
o.className=o.className.replace(rep,'');
break;
case 'check':
var found=false;
var temparray=o.className.split(' ');
for(var i=0;i<temparray.length;i++){
if(temparray[i]==c1){found=true;}
}
return found;
break;
}
}
}
domtab.addEvent(window, 'load', domtab.init, false);
/* ]]> */
</script>
We now need to tackle the css issue. You don’t need the full styling that is given with the domtab download, it’s a bit in your face. A slimmed down version is more than adequate for our needs. Originally I put the css in my main theme style file but that led to some minor conflicts with unordered listings on other pages. I tackled the issue with a custom author.php header file and put the css in that.
If you understand the template system of WordPress you’ll know if you make a copy of your header.php file and call it header-author.php then that file will be used everytime the author.php file is called.
So make a copy of your theme header.php file and rename it header-author.php. Open it and add the following css between the <head></head> tags.
<style type="text/css">
/* the author page styling */
*{
margin:0;
padding:0;
list-style:none;
border:none;
}
div.domtab{
padding:0 3em;
width:80%;
font-size:90%;
}
ul.domtabs{
float:left;
width:100%;
margin:2em 0 0 0;
}
ul.domtabs li{
float:left;
padding:0 .5em 0 0;
}
ul.domtabs a:link,
ul.domtabs a:visited,
ul.domtabs a:active,
ul.domtabs a:hover{
width:8em;
padding:.2em 1em;
display:block;
background:#666;
color:#ccc;
height:3em;
font-weight:bold;
text-decoration:none;
}</style>
You can style your tabs to look how you want by changing the css above. Be aware that any unordered lists that you may use on the author.php page may be influenced by this css styling.
That’s the technical aspects dealt with now let’s start to build those tabs.
Customising your author.php.
Your entire tabbed area including contents of the tab is enclosed in the
<div class="domtab"> </div>
It’s a bit like your main or content div tags in WordPress, anything within the domtab class will be part of your content. Anything placed outside the div – before or after will be seen whichever tab the visitor is viewing.
We now need to name our tabs, this tutorial will produce tabbed sections for an author bio, blog postings and comments on posts so;
<ul class="domtabs"> <li><a href="#bio">Author bio</a></li> <li><a href="#blog">Blog</a></li> <li><a href="#comments">Comments</a></li> </ul>
We now put in place the three named anchors section that we will fill out with content later. Each named anchor section in held within an UNNAMED <div> tag so;
<div> <a name="bio" id="bio">Author bio</a> </div> <div> <a name="blog" id="blog">Latest blogs</a> </div> <div> <a name="comments" id="comments">Last 10 comments</a> </div>
Filling out the latest blog section.
Let’s start by populating the easiest content which is the blogs. You can just add after the named anchor and before the closing </div> the standard bit of code from the author.php file which returns the latest blog posts so;
<div> <a name="blog" id="blog">Latest blogs</a> <?php /* Since we called the_post() above, we need to * rewind the loop back to the beginning that way * we can run the loop properly, in full. */ rewind_posts(); /* Run the loop for the author archive page to output the authors posts * If you want to overload this in a child theme then include a file * called loop-author.php and that will be used instead. */ get_template_part( 'loop', 'author' ); ?> </div>
Filling out the latest comments section.
The next easiest section to tackle is the comments that the author has made on the site. We can call that pretty easily with a query. In my example I’m calling the last 10 comments made by the author but you can change the number to however many you want by changing the LIMIT 10 line.
I’m also calling the excerpt of the comment rather than the full comment as this keeps the section looking nicer in respect of very long comments and can help tackle internal duplicate content. So our comments named anchor section will look like:
<div>
<a name="comments" id="comments">Last 10 comments</a>
<?
if(get_query_var('author_name')) :
$curauth = get_userdatabylogin(get_query_var('author_name'));
else :
$curauth = get_userdata(get_query_var('author'));
endif;
$querystr = "
SELECT comment_ID, comment_post_ID, post_title, comment_content
FROM $wpdb->comments, $wpdb->posts
WHERE user_id = $curauth->ID
AND comment_post_id = ID
AND comment_approved = 1
ORDER BY comment_ID DESC
LIMIT 10
";
$comments_array = $wpdb->get_results($querystr, OBJECT);
if ($comments_array): ?>
<ul>
<? foreach ($comments_array as $comment):
setup_postdata($comment);
echo "<li><a href='". get_bloginfo('url') ."/?p=".$comment->comment_post_ID."'>Comment on ". $comment->post_title. "</a><br />". get_comment_excerpt() . "</li>";
endforeach; ?>
</ul>
<? endif; ?>
</div>
Don’t forget we’re running each section within those unnamed div tags.
Filling out the author bio section.
The remaining section is a little more difficult to explain as each web site will have different ideas about what to include in the bio section but I’ll explain the basic outline of the one I use. While you can code in functions for extra information fields into the theme functions file I find it much easier and quicker to use a plugin for this. The one I use is the Register Plus Redux. For the author image I use the User Photo plugin.
Set the User Photo to override avatar and also set the avatar as fall back in the plugin settings.
For the Register Plus Redux decide on what information you want to get and display on the author.php page. In this tutorial I want to display an email, twitter account, google profile and enhanced bio. The email will be called from the default information so we need to add new fields called twitter – a text field, google profile – a text field and enhanced bio – a text box.
I like the default user description box as a short introduction to the user bio section so first lets call it.
We call it as in our previous two section between the unnamed divs tag and after the bio named anchor;
<?php // If a user has filled out their description, show a bio on their entries. if ( get_the_author_meta( 'description' ) ) : ?> <div id="entry-author-info"> <div id="author-avatar"> <?php echo get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'twentyten_author_bio_avatar_size', 60 ) ); ?> </div><!-- #author-avatar --> <div id="author-description1"> <h2><?php printf( __( 'About %s', 'twentyten' ), get_the_author() ); ?></h2> <?php the_author_meta( 'description' ); ?> </div><!-- #author-description --> </div>
I had to rename the standard div id author-description to author-description1 and do a bit of tweaking to get it to display correctly – just add the new div style to your main theme css style.
Calling meta author details.
The next item I want to call is the user email address – though I don’t want it to be a live link just to help reduce the amount of spam. We can call this easily enough through a template tag so add this below;
<b>Email:</b> <?php echo the_author_meta('email', $author->ID); ?><br />
Another of the standard fields we may want to call is the authors web page so we call it through the template tag;
<b>Website: </b><a href="<?php echo the_author_meta('user_url', $author->ID); ?>"><?php echo the_author_meta('user_url', $author->ID); ?></a><br />
Calling Register Plus Redux fields.
Now lets look at installing some custom fields that we created in the Register Plus Redux. Calling the information is very similar to calling the standard information. Let’s start by looking at displaying a link to the twitter account.
First we need to add the root web address that is used before the twitter account name with hard coding. We then call the twitter account name using the author meta call so;
<b>Twitter: </b><a href="http://twitter.com/<?php echo the_author_meta('twitter', $author->ID); ?>"><?php echo the_author_meta('twitter', $author->ID);?></a><br />
In the above you are calling the name of the field in the brackets after the_author_meta call. The first instance is adding the twitter user name to the web address the second call is printing out the name on our page. You can call whatever you want using this principle so if you have a facebook profile field you can call it by replacing ‘twitter’ with ‘facebook’ or if you want to include a flickr account then replace ‘twitter’ with ‘flickr’ (or whatever else you called the field in Register Plus Redux. Obviously you have to change the root address to the relevent domain.
Connecting your author profile to Google Profile.
Handling two word fields is just the same as single field names it’s just that you use an underscore when calling them. We’ll see this now as we add a Google Profile link to our author page. To call the Google profile link in our WordPress author.php page add;
<b>Google Profile: </b> <a rel="me" href="https://profiles.google.com/<?php echo the_author_meta('google_profile', $author->ID); ?>"><?php echo the_author_meta('google_profile', $author->ID); ?></a>
Note the underscores because we called the field in Register Plus Redux Google Profile. In addition to a standard call to the google.com root for profiles we have also added the rel=author” meta tag. Let’s not forget the aim of this tutorial is to make the most of Googles new support for this tag.
Currently Google needs you to link back to your Google profile for them to make use of the rel author tag by declaring this tag on the profile link you are connecting up posts that you make to your authorship. As a side note any photo that Google may decide to show against the search results will be a photo from your Google Profile and not one from your own web site so make sure you have a photo set to public on your Google account.
Adding an enhanced bio field to author.php.
We now want to add the enhanced bio section which is where people can add lots more information about themselves and we also want to add a photograph of the user.
To call a photo that has been uploaded by User Photo we use the template tag:
<div class="biophoto"><?php echo userphoto_the_author_photo() ?> </div>
Obviously you do your own styling for biophoto in your theme functions file. We call the enhanced bio section in much the same way as we call the other author meta information, Though obviously there’s no web address to call so;
<div class="enbio"><?php echo the_author_meta('enhanced_bio', $author->ID); ?> <br /></div>
Because we called the new field Enhanced bio in Register Plus Redux we have to use the underscore to call the information on the page. We don’t really want just a long passage of text in the enhanced bio section. We should give some option for a little bit of formatting like adding links, paragraphs and a few other basic formatting options.
We can do this with a little call in the theme functions file. Open the theme functions.php and add;
/** text format for enhanced bio */
if ( (strpos($_SERVER['SCRIPT_NAME'], 'wp-admin/user-edit.php')) || (strpos($_SERVER['SCRIPT_NAME'], 'wp-admin/profile.php'))) {
add_action('admin_head', 'add_tinymce');
}
remove_filter('pre_enhanced_bio', 'wp_filter_kses');
add_filter('pre_enhanced_bio', 'wpautop');
function add_tinymce() {
if (function_exists('wp_tiny_mce')) {
add_filter('teeny_mce_before_init', create_function('$a', ' $a["height"] = "200"; $a["width"] = "600"; $a["onpageload"] = ""; $a["mode"] = "exact"; $a["elements"] = "enhanced_bio"; $a["editor_selector"] = "mceEditor"; $a["plugins"] = "safari,inlinepopups,spellchecker"; $a["forced_root_block"] = false; $a["force_br_newlines"] = true; $a["force_p_newlines"] = false; $a["convert_newlines_to_brs"] = true; return $a;'));
wp_tiny_mce(true);
}
}
Because I started my author.php profile page with an opening if statement I need to close it all off at the end;
<?php endif; ?>
The final piece – confirming your authorship with Google.
Phew, we’re almost there. We’ve linked all our posts to our author page and we’ve put up quite a nice author profile on the author.php page. We’ve also linked our author profile page to our Google account so Google knows who is the author of the posts. There’s just one final piece of the jigsaw to fit and that is confirming to Google that you are indeed who you say you are.
You do this by adding your author profile page to your Google profile in the links section. Log into your Google account and go to your profile, press edit profile. Go to the links section and add new custom link, add your author profile page and tick the box that says the link is specifically about you.
You are now pretty much all set up to take advantage of the Google acceptance of rel=”author” tag. You can now start building your credibility as an author around the web. Whenever you make a comment or a guest post if possible link back to your own author page by using the rel=”me” tag. You should only use the rel=”author” tag for posts on your own domain.
If you keep a list of guest blogs that you have done on other sites on your own site then mark each of the links with rel=”me” and Google will know that you wrote those articles also – but only do that if the blogs or posts are on another domain.
I predict that we will see Google giving increasing importance to the authority and credibility of authors in the future. If you run a multi-author blog or site then you may want to look at the quality of the author – it may impact on your site if you have poor quality article authors.
http://www.youtube.com/watch?v=FgFb6Y-UJUI
works on wp 3.2.x
Ready made author.php file available for download at £5.00.








