WordPress Canonical URLs Done Right

Updated April 7, 2014 for search results and to automatically hook into wp_head().

WordPress still has some issues with canonical links. Namely, it only outputs them on singular pages, such as individual blog posts, Pages, etc. Archives, paged pages, category and search pages all get nothing.

There are plenty of plugins out there that handle this, but as I’ve mentioned before, they’re prone to error, especially when working with advanced taxonomies and post types.

Therefore, I bring to you a little bit of functions.php love you can use to sort out canonicals as best as I’ve been able to figure out. Give it a whirl:

// canonicals done right
remove_action('wp_head', 'rel_canonical');
function click_canonical() {
global $post;
if (is_singular() && !is_attachment()) { $plycanonical = get_permalink( $id ); }
elseif ( is_front_page() ) { $plycanonical = site_url(); }
elseif ( is_home() && "page" == get_option('show_on_front') ) { $plycanonical = get_permalink( get_option( 'page_for_posts' ) ); }
elseif (is_attachment()) { $plycanonical = get_permalink($post->post_parent); }
elseif (is_home()) { $plycanonical = 'http://'.$_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]; }
elseif (is_post_type_archive( 'cn_webdesign' )) { $plycanonical = site_url().'/web-design/'; }
elseif (is_category()) { $category_id = get_query_var('cat'); $plycanonical = get_category_link( $category_id ); }
elseif (is_archive() || is_search()) { $plycanonical = site_url(); }
elseif (is_paged()) { $plycanonical = site_url(); }
else {$plycanonical = 'http://'.$_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];}
echo '<link rel="canonical" href="'.$plycanonical.'"/>
';
}
add_action('wp_head', 'click_canonical');

Any thoughts on how it could be done differently / better? Let me know in the comments!

Up Next: WordPress Body Class CSS for a Variety of Devices