cool tech graphics

How to Change the Content-Type Meta Tag in Drupal

Filed under:

I'm working on an HTML5 theme for Drupal 7 right now, and I needed to change the meta content-type tag. By default it looks like this: <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />, and I needed the updated HTML5 version: <meta charset="utf-8" />. Normally, you can replace these things in one of the theme template files, but in this case, the meta tag was hard-coded in the Drupal source code somewhere, so I needed a programmatic solution. Here's what I found for both Drupal 6 and 7.

Drupal 6

The meta tag is stored in the $vars['head'] array, so we can simply use the php str_replace() function to change it. Just drop this code into the template.php file for your theme.

// replace the meta content-type tag for Drupal 6
function YOURTHEME_preprocess_page(&$vars, $hook) {
  $vars['head'] = str_replace(
    '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',
    '<meta charset="utf-8" />',

Drupal 7

This is slightly more complicated in Drupal 7, because instead of storing the meta tag directly in a variable, the attributes for the tag are stored in an array, which is later converted into markup. Now, we could still edit that markup, but it's more elegant to update the attributes in the array before it's turned into markup, rather than rely on a string replace. Here's how to do it. Again, just drop this code into your theme's template.php file.

// replace the meta content-type tag for Drupal 7
function YOURTHEME_html_head_alter(&$head_elements) {
  $head_elements['system_meta_content_type']['#attributes'] = array(
    'charset' => 'utf-8'

You can use this technique to update any setting stored in that array. To see what your options are, add print_r($head_elements); inside that function. It'll display the contents of the array on your page (though you may need to view source to make any sense of it). To edit a different tag, just replace system_meta_content_type with the item you want to alter. You can even remove an item from the array entirely like this:

// remove a tag from the head for Drupal 7
function YOURTHEME_html_head_alter(&$head_elements) {

This is a perfect example of one of my frustrations with Drupal. For the most part, the theme system is well thought out, but if you stray from the beaten path by trying to do something they didn't think you would need to do, you have to do it programmatically. It's hard for me to fathom why certain parts of the markup, like this meta tag, are locked away, instead of making everything available in the theme layer. Still, this code should give you the tools you need to gain access to them.

Want more awesome content like this? Check out our top 20 Drupal tips of all time!

Date posted: May 28, 2010


A more elegant and Drupal-y way to write this, as one of our programmers just pointed out to me, would have been like this:

function YOURTHEME_html_head_alter(&$head_elements) {
  foreach($head_elements as $key => $element) {
    switch ($key) {
      case 'system_meta_content_type':
        $head_elements[$key]['#attributes'] = array(
          'charset' => 'utf-8'
      case 'system_meta_generator':

I don't see how that's more elegant or more Drupal-y. You're unnecessarily iterating through an array to adjust keys you already know are going to be there. Better to just set (or unset) them directly.

Oh, yeshh :)

For one line of execution there's no need to do a switch. That's what he meant!


Drupal 7 builds this stuff up programatically, for several reasons. One of which is because now with RDFa, these tags are manipulated by the RDFa module, giving your markup richer meaning. Another reason being flexibility. It's much easier to alter the $head array than doing a str_replace(). Especially when you get into things like hook_page_alter().

And you may want to check out the dpm() function that Devel module provides rather than using print_r() - it's much easier to read and traverse.

Nice article, thanks.

Specially, drupal-y way looks great.

Isn't is allowed to just add <meta charset="utf-8" />

@Garrett - Thanks, turns out there's some disagreement among our in-house programmers. Code style philosophy aside, they were both able to agree that the simpler versions were faster and more efficient.

@Scott - I know you don't *need* to change it, but this new theme I'm working on is all about pushing the boundaries, and I figured I'm probably not the only front-end guy who was struggling to change the code in the $head.

@ao2 - I saw that thread, the intent is a little different than what I'm trying to do, but the end result would be good. I'll post to the thread.

@dalin - thanks for the background, I ddn't know about the RDFa stuff. I agree that the D7 way seems cleaner, albeit somewhat harder for newbies and front-end guys like myself to figure out.

@Jorrit - sure, you can add any code you want to your TPL files, but the issue I was facing was that Drupal is already spitting out a meta content-type tag, and I didn't want two of them, so I was trying to find a way to edit the default one.

I know I'm coming to this late but have you found that your Drupal 6 version fix is still working? I think I'm obviously missing something because I can't get your code to work at all. The preprocess code is the first thing in my template.php file but it doesn't affect the output. One thing I'm probably missing is how you call the function from the page.tpl.php page--I've followed standard methods of function calls it simply will not work whether I put the functional call before the or directly after it. I really don't want to modify the core file as the discussions suggest in and to be honest I'm really surprised nobody seems to have fixed this by now--basically 8 months past your original post date.

This may no longer be possible in D6. Starting with Drupal 6.11, there's some additional header manipulation performed to try to protect IE6 and IE7 users.

More details are at .

I think you're confusing the doctype with the http-equiv content-type meta element. The latter is not in html.tpl.php, so there's nothing to change. Since this element is set in _drupal_default_html_head(), it must be overridden with hook_html_head_alter().

Great write up.

I am using D6, and this works, but I am still having the existing D6 issue of a duplicate charset output. See this issue.

So, that means I get one output HTML5 charset output and one old method. Ugh. Even has two charsets being outputted.

They fixed the problem for D7, but not for D6. Any suggestions?

my failed the w3c validator

I get a little uneasy when someone suggests an override in the template.php file... I haven't tested it, but wouldn't the preferred approach be to use the metatag module? Although I think the meta content-type is probably pretty static and consistent site-wide, I'd still be hesitant to effectively hard-code this aspect of the site.

Awesome post. Thank you, saved my day :)

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <cpp>, <java>, <php>. The supported tag styles are: <foo>, [foo].
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.

Metal Toad is an Advanced AWS Consulting Partner. Learn more about our AWS Managed Services

Have questions?