Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough

Drupal 7 SEO: Controlling Page Titles and Meta Elements at the Theme Layer

Parent Feed: 

This script has been updated to work with multilingual sites too! See http://www.milesjcarter.co.uk/blog/web-design-development/drupal-7-seo-page-titles-meta-elements-theme-layer-multilingual/. All further development will be with the new version

Drupal 6 was great for manual control of page titles, either with the page_title module, or with control at the theme layer.

In Drupal 6, I used a small snippet of code like this in the page.tpl.php to set a custom page title, simply because it was simple and sufficient for most sites:

<span class="c3"><?php</span><p><span class="c4">if</span> <span class="c5">(</span> arg<span class="c5">(</span><span class="c6">0</span><span class="c5">)</span> <span class="c7">==</span> <span class="c8">'node'</span> <span class="c7">&&</span> <a href="http://www.php.net/is_numeric"><span class="c9">is_numeric</span></a><span class="c5">(</span>arg<span class="c5">(</span><span class="c6">1</span><span class="c5">)</span><span class="c5">)</span> <span class="c5">)</span> <span class="c5">{</span><br />  <span class="c10">$node</span> <span class="c7">=</span> node_load<span class="c5">(</span>arg<span class="c5">(</span><span class="c6">1</span><span class="c5">)</span><span class="c5">)</span><span class="c7">;</span><br />  <span class="c4">if</span> <span class="c5">(</span> <span class="c10">$node</span><span class="c7">-></span><span class="c11">type</span> <span class="c7">==</span> <span class="c8">'page'</span> <span class="c7">&&</span> <span class="c7">!</span><a href="http://www.php.net/empty"><span class="c9">empty</span></a><span class="c5">(</span><span class="c10">$node</span><span class="c7">-></span><span class="c11">field_title</span><span class="c5">[</span><span class="c6">0</span><span class="c5">]</span><span class="c5">)</span> <span class="c5">)</span> <span class="c5">{</span><br />    <span class="c12">// Output CCK Title</span><br /><span class="c4">print</span> content_format<span class="c5">(</span><span class="c8">'field_title'</span><span class="c7">,</span> <span class="c10">$node</span><span class="c7">-></span><span class="c11">field_title</span><span class="c5">[</span><span class="c6">0</span><span class="c5">]</span><span class="c5">)</span><span class="c7">;</span><br />  <span class="c5">}</span><br /><span class="c5">}</span><br /><span class="c4">else</span> <span class="c5">{</span><br /><span class="c4">print</span> <span class="c10">$head_title</span><span class="c7">;</span><br /><span class="c5">}</span></p><p><span class="c3">?></span></p>

field_title being a field called “title” I added with CCK to the ‘page’ content type or any other content type that should have hand-written page titles. A similar snippet also did the trick for the Meta description.

However, Drupal 7 makes this a lot trickier – whereas the title and other head elements are declared individually in page.tpl.php in Drupal 6, the replacement for Drupal 7 is:

<?php print render($page['header']); ?>;

In Drupal 7, anything to be inserted into the head at the theme layer (by my understanding) has to be done through preprocess functions in template.php.

As an aside, notice in the previous the use of the render() function to output the header – this is a common source of confusion amongst those new to Drupal 7 theme development, where just print is needed to output regions in Drupal 6.

This is made doubly tricky by node variables not being directly available in template.php as they are in page.tpl.php.

I tried out the page_title module for Drupal 7, and this does work to an extent, but it breaks completely with panel pages. You could, according to a post on drupal.org use panels as a template to display nodes, but for a single page usage (as in a homepage only use) this seems like something not straighforward. It’s also another module to keep maintained, and with field tokens currently broken and not much progress being made the page_title module is a lot less useful than it was in Drupal 6.

A Drupal 7 Solution:

I was inspired by this post by Sivaji Ganesh, containing this line:

$vars['head_title'] = implode(' | ', array(drupal_get_title(), variable_get('site_name', ''), variable_get('site_slogan', '')));

For setting a title at the theme layer as “title (as in the h1 title) | site_name | site_slogan”

This gave me a base to work from. The code I finally came up with (after about 8hr of perserverance) was this:

/* --- DRUPAL SEO: FIELD BASED PAGE TITLES & META DESCRIPTIONS ---
 * Ver: 0.9c
 * By Miles J Carter
 * http://www.milesjcarter.co.uk/blog
 * Tested with Drupal versions 7.3, 7.4, 7.7
 * licensed under the GPL license:
 * http://www.gnu.org/licenses/gpl.html
 *
 * Works for content types that have text fields created
 * named "title" and "meta_desc".
 * INSERT INTO YOUR
 * function THEME_preprocess_html(&$vars) {
 * in template.php
 */

// Find Node ID
$node = $vars['page']['content']['system_main'];

if (isset($node['nodes'])) {
 
        $node = $node['nodes'];
 
        // Extract key value for node ID
  if (list($key, $val) = each($node))  {
   
    // Create node object variable
    $node = ($node[$key]['#node']);    
               
               
                // Creat page title field content variable, if set             
                if (isset($node->field_title)) {
      $node_title = $node->field_title;
                         
                if (isset($node_title['und']['0']['value'])) {
        $seo_title = $node_title['und']['0']['value'];
      }
                }
        }
       
  // If manual field title for SEO has been set, set the title to [seo-title] | [site-name]
  if (isset($seo_title)){
       
                 $vars['head_title'] = implode(' | ', array($seo_title, variable_get('site_name', ''),  ));
  }
}

/* If SEO title field not set, or content type not page,
use an automatic [current-page-title] | [site-name] scheme */

else { 
  $vars['head_title'] = implode(' | ', array(drupal_get_title(), variable_get('site_name', ''), ));  
}

// ----- Custom Meta Description -----

// Create meta_desc field content variable, if set
if (isset($node->field_meta_desc)) {
  $node_desc = $node->field_meta_desc;
                         
        if (isset($node_desc['und']['0']['value'])) {
   
                $seo_desc = $node_desc['und']['0']['value'];

    // Create meta description element array for insertion into head
    $element = array(
      '#tag' => 'meta',
      '#attributes' => array(
        'name' => 'description',
        'content' => "$seo_desc",
      ),
    );
   
    // Insert element into (if field has a value)
    drupal_add_html_head($element, 'meta_description');

  }
}

// ------- END SEO CODE ---------

This allows a field created called “title” to manually set the page title. If this field is not set, or the page is a view or  any other non-node page, the title will be “get_title() | site_name”, with get_title() the h1 title. Other fields could easily be incorporated into the script by minor modification.

Once the title was figured out, it was pretty easy to set up a field based meta description too.

As this issue had been holding me up from developing with Drupal 7, I hope the above code is useful to other SEOs and developers.

Author: 
Original Post: 

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web