MJC SEO & Web Development Blog > Drupal 7 SEO: Controlling Page Titles and Meta Elements at the Theme Layer

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

Drupal 7 Development: How to Set Field Based Page Titles and Meta Descriptions in template.php

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:


if ( arg(0) == 'node' && is_numeric(arg(1)) ) {
  $node = node_load(arg(1));
  if ( $node->type == 'page' && !empty($node->field_title[0]) ) {
    // Output CCK Title
print content_format('field_title', $node->field_title[0]);
else {
print $head_title;


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:

 * 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".
 * 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 <head> (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.


  1. Eli
    Posted September 10, 2011 at 4:19 pm | Permalink

    I’ve been trying to go in a similar direction with my page titles, and page_title module did not really do the job. This post has been very helpful. Thanks Miles.

  2. Posted September 15, 2011 at 12:17 pm | Permalink

    Thanks for sharing, worked perfectly for me :-)

  3. Erik Jonsson
    Posted August 15, 2012 at 11:38 am | Permalink

    Thank you so much! Worked great for me. Now I just have to figure out how to do with the views template. Any ideas?

  4. Miles Carter
    Posted August 17, 2012 at 2:36 am | Permalink

    Hi Erik, glad this has been of use. Not sure that this will be possible to modify the script to work with views templates, as they would not meet the conditions for being a node. The same is true of panel templates, but they can somehow express a particular node virtually which allows it to work. Also, please try the new version of the script, see the link at the top of the page.

  5. simon
    Posted August 22, 2012 at 7:51 am | Permalink

    how cam this be done for taxonomy pages?

  6. Posted January 16, 2013 at 6:32 am | Permalink

    thanks for sharing, useful for me

  7. Posted January 27, 2013 at 7:07 am | Permalink

    It is working fine for me. Thanks.

  8. drupix
    Posted March 6, 2013 at 12:23 pm | Permalink

    Useful post, just replace $var_name['und']['0']['value'] with $var_name[LANGUAGE_NONE]['0']['value'].

    Community Documentation : http://drupal.org/update/modules/6/7#drupal_language_none


  9. Miles Carter
    Posted March 8, 2013 at 7:13 am | Permalink

    @drupix – Thanks for letting me know, I am a bit lapse on coding standards! I will test for myself to make sure it still works and update accordingly. Also note there is a newer multilingual version of this script (that still works with single/undefined language sites) for only a few more LOC

  10. Jason Martino
    Posted August 22, 2013 at 10:23 pm | Permalink

    Thanks for the tip. I needed it to set the title and metatags on a view.

One Trackback

  1. [...] Descriptions from template.php This is an update of a previous post on this blog from July 2011 Drupal 7 SEO: Controlling Page Titles and Meta Elements at the Theme Layer. The script allows the setting of custom page titles and Meta descriptions from defined fields in [...]

Post a Comment

Your email is never shared. Required fields are marked *