Drupal 7 – Canonical Link Removal & Replacement

Drupal 7 canonical handling can be a confusing mess.  You can throw this into an existing metatag module or create a custom module and this function will make life easier.

This relies on a custom field called field_canonical_url.  Make sure you create the field if you want to be able to customize this at the node level.  Otherwise you can remove the logic if you want something a little simpler.  Simply remove lines 40-51.

function %modulename%_metatag_html_head_alter(&$head_elements) {
  // Specific canonical url handling.
  // Strips out any existing canonical links, replaces with absolute links,
  // which can be overwritten by URL's stored in the content specific
  // field_canonical_url.  This must be setup correcly on each site, otherwise
  // This will not work.

  // Get all the nodes.
  $node = menu_get_object();
  // Get all of the existing node types available.
  $available_node_types = node_type_get_types();
  // Transform to make a usable array.
  $currentNodeTypes = array();
  foreach ($available_node_types as $available_node_type) {
    $currentNodeTypes[] = $available_node_type->type;
  // Pull in the base url and relative path.
  $baseURL = ($GLOBALS['base_url']);
  $relativeURL = ($GLOBALS['_SERVER']['REQUEST_URI']);
  // Unset all existing canonical references.
  foreach ($head_elements as $key => $element) {
    if (isset($element['#attributes']['rel']) && $element['#attributes']['rel'] == 'canonical') {
  // No need to set canonical links on adminstrative pages.
  if(!path_is_admin(current_path())) {
    // Concats and sets the Canonical URL.
    $canonical_url = $baseURL . $relativeURL;
    // Check to validate that the canonical url field exists.
    if(isset($node->field_canonical_url)) {
      // Check if not empty.
      if(!empty($node->field_canonical_url[LANGUAGE_NONE][0]['url'])) {
        // Check if an existing node type.
        if(in_array($node->type, $currentNodeTypes)) {
          // Sets the custom canonical url, and cleans up said dirty url.
          $cust_canonical = $node->field_canonical_url[LANGUAGE_NONE][0]['url'];
          $canonical_url = drupal_strip_dangerous_protocols($cust_canonical);
  // Sets the appropriate canonical url.
  $head_elements['canonical_url'] = array(
    '#tag' => 'link',
    '#type' => 'html_tag',
    '#attributes' => array(
      'rel' => 'canonical',
      'href' => $canonical_url,