The WordPress Theme Header Template

Now we get into the nitty-gritty: building up your header.php and validating your theme with an HTML Doctype. There’ll be a lot of PHP in this lesson but don’t despair. We’re also going to do two, essential, and kinda neat, search engine optimization tricks and start tricking out your theme with a functions.php file.

The Head Section

Right now your very blank WordPress Theme is technically invalid. That’s because it’s missing a Doctype telling the browser how to interpret the HTML it’s seeing. We’re going to use the XHTML Transitional Doctype. There are other options but right now, XHTML transitional is the best bet for a WordPress Theme.

Open up header.php and paste the following code there, before anything else.

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

We’re also going to add some attributes to your opening HTML tag that will make they type of page we’re creating more apparent to the browser. Replace the current <html> tag in header.php with the following line.

  1. <html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>

Now we’re going to get into the get into the <head> section of your WordPress Theme. The <head> section contains meta-information about a web page. Typically stuff like the document title seen at the top of your browser (and in search engine results), and links to style sheets and RSS feeds.

But first open up your functions.php file. We’re going to add a little helper function there, that’ll come in handy when we’re creating the document title. It’s going to give us a page number that we can add to the title.

Start off functions.php with

  1. <?php

and 2 lines down (I like to leave a couple of lines between functions) paste the following 2 PHP functions:

  1. // Make theme available for translation
  2. // Translations can be filed in the /languages/ directory
  3. load_theme_textdomain( 'your-theme', TEMPLATEPATH . '/languages' );
  4.  
  5. $locale = get_locale();
  6. $locale_file = TEMPLATEPATH . "/languages/$locale.php";
  7. if ( is_readable($locale_file) )
  8.  require_once($locale_file);
  9.  
  10. // Get the page number
  11. function get_page_number() {
  12.     if ( get_query_var('paged') ) {
  13.         print ' | ' . __( 'Page ' , 'your-theme') . get_query_var('paged');
  14.     }
  15. } // end get_page_number

The first function tells WordPress we want to make our theme available for translation and that translation files can be found in our theme folder in a folder called “languages”. If you’re going to create a WordPress Theme you should always try your best to make sure everything is translatable. You never know when you or someone else is going to need hard-coded content available in another language.

In our next function, get_the_page_number(), you’ll see some translatable text. It looks like this:

  1. __( 'Page ' , 'your-theme')

The text ready for translation is “Page “ followed by the directory name of our theme; in this case, “your-theme”. Pretty straightforward but there are couple other ways to write translatable text. We’ll get to them when we come to them.

Can you guess what get_page_number() is doing? If you take a look inside the function you can see that we’re checking with an IF statement to see if we’re on a paged page, you know, where you are when you click “older posts”. If you are, this function will print a bar separator and the current page number.

Also, If you’re new to PHP I want you to notice something else here. Anything after the double slash (//) is ignored and used as a comment. You’ll be seeing that a lot.

Alright, back to the <head> section of header.php.

Replace <head></head> with the following code:

  1. <head profile="http://gmpg.org/xfn/11">
  2.     <title><?php
  3.         if ( is_single() ) { single_post_title(); }      
  4.         elseif ( is_home() || is_front_page() ) { bloginfo('name'); print ' | '; bloginfo('description'); get_page_number(); }
  5.         elseif ( is_page() ) { single_post_title(''); }
  6.         elseif ( is_search() ) { bloginfo('name'); print ' | Search results for ' . wp_specialchars($s); get_page_number(); }
  7.         elseif ( is_404() ) { bloginfo('name'); print ' | Not Found'; }
  8.         else { bloginfo('name'); wp_title('|'); get_page_number(); }
  9.     ?></title>
  10.  
  11.  <meta http-equiv="content-type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
  12.  
  13.  <link rel="stylesheet" type="text/css" href="<?php bloginfo('stylesheet_url'); ?>" />
  14.  
  15.  <?php if ( is_singular() ) wp_enqueue_script( 'comment-reply' ); ?>
  16.  
  17.  <?php wp_head(); ?>
  18.  
  19.  <link rel="alternate" type="application/rss+xml" href="<?php bloginfo('rss2_url'); ?>" title="<?php printf( __( '%s latest posts', 'your-theme' ), wp_specialchars( get_bloginfo('name'), 1 ) ); ?>" />
  20.  <link rel="alternate" type="application/rss+xml" href="<?php bloginfo('comments_rss2_url') ?>" title="<?php printf( __( '%s latest comments', 'your-theme' ), wp_specialchars( get_bloginfo('name'), 1 ) ); ?>" />
  21.  <link rel="pingback" href="<?php bloginfo('pingback_url'); ?>" />
  22. </head>

If all this looks like gobbledygook to you that’s OK. I’ll explain the main sections.

A search engine optimized title tag that shows only the post title on single posts and pages. And, of course, adds page numbers with get_page_number() on “older post” pages.

    <?php
        if ( is_single() ) { single_post_title(); }
        elseif ( is_home() || is_front_page() ) { bloginfo('name'); print ' | '; bloginfo('description'); get_page_number(); }
        elseif ( is_page() ) { single_post_title(''); }
        elseif ( is_search() ) { bloginfo('name'); print ' | Search results for ' . wp_specialchars($s); get_page_number(); }
        elseif ( is_404() ) { bloginfo('name'); print ' | Not Found'; }
        else { bloginfo('name'); wp_title('|'); get_page_number(); }
    ?>

Some meta information about our page content.

	

A link to our stylesheet.


A script call so we can use threaded comments when we get to our comments section.

	

A hook for WordPress plugins and other cool stuff.

	

Links for our RSS Feeds and pingbacks.




The header section

Now we want to add in our blog title, which will act as a link to our home page, blog description, and menu.

In header.php move down to the #branding div. It’s here that we’ll add in the title and description. But we’re going to do something a little different from most themes.

You’ll find that a lot of WordPress Themes tell search engines that the most important thing on every page is your blog title. They do this by wrapping it in an h1 tag; the tag that says “this is what this particular page is all about”. I, and a small group of other theme developers, think this is a bad idea. For instance, the most important thing on this page, the text that defines this particular page, is not “ThemeShaper” but “The WordPress Theme Header Template”. That’s what this page is all about after all. And on our home page, really, the most important thing is the description of our blog. It literally provides an overarching description of all the content on that page.

Luckily, this is easy to take care of.

We’re going to use WordPress’ conditional tags and some plain old HTML to code our title and blog description to do just what best practices describe. Here’s what it looks like:

  1.    <div id="branding">
  2.     <div id="blog-title"><span><a href="<?php bloginfo( 'url' ) ?>/" title="<?php bloginfo( 'name' ) ?>" rel="home"><?php bloginfo( 'name' ) ?></a></span></div>
  3. <?php if ( is_home() || is_front_page() ) { ?>
  4.         <h1 id="blog-description"><?php bloginfo( 'description' ) ?></h1>
  5. <?php } else { ?>
  6.         <div id="blog-description"><?php bloginfo( 'description' ) ?></div>
  7. <?php } ?>
  8.    </div><!– #branding –>

So, the text of our anchored blog title is set perfunctorily in a casual div tag. Our blog description is set, using PHP IF statements and some WordPress conditional tags, either as a very important h1-wrapped description on the home page or front page or, like it’s relative the title, in a div everywhere else.

For beginners, this is a good place to step back and see what’s going on. In the code above we’re using a WordPress Template Tag called bloginfo(). You can see we’re using it to get the URL of our WordPress blog, the name of our blog, and the description. It can be used to get over 20 different pieces of information about your blog. It takes that information and prints it in your template. Understand this and you understand WordPress Themes. We take an HTML structure and we call WordPress Template Tags with PHP to fill it out. Simple stuff really. It’s just a matter of getting used to seeing the template tags in there, along with some IF statements and a few PHP loops (we’ll get to those too).

Move on down to the #access div. We’re going to add a skip link so folks using a screen reader don’t have to suffer through our menu when they just want to get to the content

  1.     <div class="skip-link"><a href="#content" title="<?php _e( 'Skip to content', 'your-theme' ) ?>"><?php _e( 'Skip to content', 'your-theme' ) ?></a></div>

and we’re going to add our page menu which, really couldn’t be any easier as it’s just one template tag, with only 1 argument:

  1.     <?php wp_page_menu( 'sort_column=menu_order' ); ?>

Easy, right? So your #access div should look like this:

  1.    <div id="access">
  2.     <div class="skip-link"><a href="#content" title="<?php _e( 'Skip to content', 'your-theme' ) ?>"><?php _e( 'Skip to content', 'your-theme' ) ?></a></div>
  3.     <?php wp_page_menu( 'sort_column=menu_order' ); ?>  
  4.    </div><!– #access –>

And that’s it! Your WordPress Theme Header Template is search engine optimized and coded up.

How To Create a WordPress Theme

This post is part of a WordPress Themes Tutorial that will show you how to create a powerful WordPress Theme from scratch. Read it from the beginning and code yourself up something awesome.

  1. WordPress Theme Tutorial Introduction
  2. Theme Development Tools
  3. Creating a Theme HTML Structure
  4. Template and Directory Structure
  5. The Header Template
  6. The Index Template
  7. The Single Post, Post Attachment, & 404 Templates
  8. The Comments Template
  9. The Search Template & The Page Template
  10. The Archive, Author, Category & Tags Template
  11. The Sidebar Template
  12. Reset-Rebuild Theme CSS & Define Your Layouts

Don't forget: You should follow me on twitter here.

Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

44 Comments

  1. Posted June 26, 2009 at 6:41 am | Permalink

    Is the transitional XHTML because of the plugin compatibility?

    great series, I’m following along and learning a lot, thanks

    • Posted June 26, 2009 at 6:46 am | Permalink

      Yep. And to keep it valid if a user writes something less than valid in the HTML editor.

  2. Posted June 26, 2009 at 6:46 am | Permalink

    shouldn’t the first line of the first function be :
    load_theme_textdomain( ‘your-theme’, TEMPLATEPATH . ‘/languages’ ) {
    instead of
    load_theme_textdomain( ‘your-theme’, TEMPLATEPATH . ‘/languages’ );

    • Posted June 26, 2009 at 8:06 am | Permalink

      ^^ no wtp because it’s not a conditional

      • Posted July 16, 2009 at 12:39 pm | Permalink

        The function ‘load_theme_textdomain’ is defined in a WordPress core file. So the question is really, “What is this function call doing in our theme’s function.php file?” Shouldn’t function.php only contain our theme’s custom defined functions?

        See File: ../wp-includes/i10n.php

        function load_theme_textdomain($domain, $path = false) {
        $locale = get_locale();
        $path = ( empty( $path ) ) ? get_template_directory() : $path;
        $mofile = “$path/$locale.mo”;
        return load_textdomain($domain, $mofile);
        }

  3. Posted June 26, 2009 at 8:54 am | Permalink

    Ian — Think about putting in a screenie of your main page so we can compare it to ours. That way we can be sure all code is correct?

    JIM

    • Posted June 26, 2009 at 8:58 am | Permalink

      Perhaps. I may make “Your-Theme” an open source project and just link to the raw files in each “chapter”. I’ll do something. :)

  4. Posted June 26, 2009 at 9:05 am | Permalink

    Thanks for this tutorial – I must admit I’ve been waiting eagerly for the next step to come up each day. While I agree about not using the blog title as h1 for any page other than the home – I don’t think that the blog description field really gets used in practice as a description, it seems to be used much more as a tagline, which makes it less appropriate to be used as a heading.

    But that’s fairly immaterial: thanks for doing this, I’m learning plenty and really enjoying your insights.

  5. Posted June 26, 2009 at 11:11 am | Permalink

    Excellent tutorial, thanks :)

    I’ve build WordPress themes before, but this is cleaning up some of the finer points!

    I’ll be following the next parts avidly.

  6. Posted June 26, 2009 at 2:53 pm | Permalink

    Thanks Ian — this is incredibly useful (and beautifully presented).

  7. Posted June 26, 2009 at 8:30 pm | Permalink

    I roared when I saw Geoff comment on eagerly awaiting the next step. I went to bed about 1:30 this morning, woke up about 4:00 for bathroom. Most people go right back to bed, not me! I went to see if Ian had put up next step!!!! Now tell me Ian is not doing a superb job.

  8. Posted June 26, 2009 at 10:27 pm | Permalink

    I’m glued to your site for this series. A series that is worth its weight in diamonds :)

    I also agree with your comment above, an open source version of the theme would be awesome to compare notes, ect.

  9. Todrick Moore
    Posted June 27, 2009 at 7:17 am | Permalink

    First let me say thank you for the series. I am enjoying it very much. I have two questions:
    1. Where and when will we see the function get_page_number in action?
    2. How can this project be turned into a framework like Thematic or any of the others?

    • Posted June 27, 2009 at 10:03 am | Permalink

      1. In this very tutorial you’ve been reading, in the title tag.
      2. With lots of patience and care! :) I may talk about this in a future post.

      • Posted July 9, 2009 at 3:34 am | Permalink

        Hopefully in the near future you’ll also consider doing a series on how to build a basic theme framework. I’ve been reading Justin’s bullet points on what features a theme framework should have and it can be good starting points. Cheers!

  10. Posted June 27, 2009 at 3:08 pm | Permalink

    Todrick and Ian,

    If anyone has doubts about the power of Thematic please do as I did and look at
    Cristi has made a child theme from Thematic and if you look at the code you will see what a great system Ian has developed. In agreement with Rodrick about tailoring this project towards a thematic framework.

  11. Posted June 27, 2009 at 8:11 pm | Permalink

    Keep up the amazing work Ian. Quick question: The “ unnecessary?

    • Posted June 27, 2009 at 8:17 pm | Permalink

      eeek! Cursed backticks! (Squawk at your friend Mr. Tadlock who got me used to sticking code between them) — What I meant to say, after telling you how fabulous this continues to be, was that the <?php opener in functions.php appears to have no closing tag. Is this something you intended, or is a closing tag unnecessary? Just trying to avoid fatal errors and stuff.

  12. Posted June 28, 2009 at 3:25 pm | Permalink

    Thanks for the tutorials. So far enjoying them greatly.

    I’m not sure if this has happened to anyone else. But this always happens to me. Having a blank functions.php file in the themes directory seriously kills wordpress. It’s not a big problem cause I can just delete the file or switch themes if that screen still lives. Or simply add a function into the file.

    Anyway, just thought I’d let people know in case they come across that.

    :)

  13. Posted July 2, 2009 at 7:32 am | Permalink

    I am just wondering why the text in the tag is not passed to _e() function

    Was it done on purpose?

    • Posted July 2, 2009 at 10:02 pm | Permalink

      Do you mean the title tag?

      • Posted July 3, 2009 at 12:02 am | Permalink

        Yes I meant the title tag.

        (I guess the HTML tags were stripped from my comment earlier)

    • Posted July 3, 2009 at 5:58 am | Permalink

      Ah. That would be a mistake, then. :) I’ll get that fixed up.

      • Daniel Balfour
        Posted July 24, 2009 at 8:30 am | Permalink

        Ian,

        I’m wondering if I may have found a bug?

        In this tutorial you stated:

        So, the text of our anchored blog title is set perfunctorily in a casual div tag. Our blog description is set, using PHP IF statements and some WordPress conditional tags, either as a very important h1-wrapped description on the home page or front page or, like it’s relative the title, in a div everywhere else.

        I just checked Thematic and my ‘Blog Description’ is wrapped in a plain old div tag (the blog title is as well, but that’s to be expected). I am of course referring to the home page and not any specific post/page pages.

        I could be making a mistake, but I’m pretty sure I went through the source code rather thoroughly.
        I’m developing a child theme for Thematic.

        Thoughts?

      • Daniel Balfour
        Posted July 24, 2009 at 8:32 am | Permalink

        Ian – my bad. I forgot that the child theme also takes php files from its own directory before going over to the parent theme’s directory.

        My bad – lessons learned.

  14. Posted July 7, 2009 at 11:00 pm | Permalink

    Hey! great tutorial so far!! I am wondering one thing, for all the files created is there a designated file for .html? I see the header file contains all of or a lot of the html, is that where it will be called from under the .php extension?

    thanks!
    Colin

  15. Posted July 9, 2009 at 10:54 pm | Permalink

    Dear Ian

    First of all, I would like to give you a very Big THANKS for this series.
    It’s by far the most updated and best documented version of how to create wp theme.

    For the header template, I have one question if you don’t mind.

    It’s about this part –>

    I was wondering if we still need this ?

    From my understanding, that line is like a patch for pre-2.7 theme
    (so that it’s compatible with threaded comment thing in 2.7 and higher)

    The other theme framework ( other than thematic) that I’m currently studying doesn’t have that line in the header template, but it uses ….if ( ( get_option(‘thread_comments’) )… in its custom comment callback function.

    I guess that will automatically call the comment-reply.js without that line in the header template.

    Please correct me if I’m wrong.

    and here again, Big Thanks for this series, really really GREAT posts.

  16. Posted July 9, 2009 at 10:57 pm | Permalink

    Oops ! here we go again.

    It’s about this part –> if ( is_singular() ) wp_enqueue_script( ‘comment-reply’ )

  17. Posted July 15, 2009 at 11:55 pm | Permalink

    With the skip-link div, can the skip-link class be added to the anchor tag and drop the extra div?

  18. Posted July 28, 2009 at 6:07 pm | Permalink

    Hi, great tutorial.

    Im planning to use your Shape-theme as my theme framework. Do you have the po-file so I can translate it to swedish?

  19. Posted September 25, 2009 at 1:40 pm | Permalink

    Hi Ian!

    Thanks a lot for your tutorial, I’m learning a lot! And having fun also, with your sense of humor.

    In the latest update to Thematic, languages is in library/languages directory. Then, shouldn’t

    load_theme_textdomain( ‘your-theme’, TEMPLATEPATH . ‘/languages’ );

    and

    $locale_file = TEMPLATEPATH . “/languages/$locale.php”;

    mention …”/library/languages/… ??

    Thanks.
    Gabriela

  20. Posted September 25, 2009 at 1:43 pm | Permalink

    Ah! Should a put a copy of library folder in my child Thematic theme?

  21. justkeepblogging
    Posted October 13, 2009 at 12:16 am | Permalink

    Ian,

    I’ve tried this a few times and every time I get to this part I get the following error:

    Fatal error: Call to undefined function get_page_number() in C:\xampp\htdocs\wordpress\wp-content\themes\thematic\header.php on line 7

    I’ve checked the code against the google code and it looks the same. What could I be doing wrong?

    Thanks for any help you can offer.

  22. mario
    Posted October 22, 2009 at 7:19 pm | Permalink

    Hi Ian, first of all thanks for Thematic theme.
    I love its essential look as ideal platform for loads of customizations.
    I’m not smart with codes so I use some wp plugins to build a little e-shop.
    I use wp-ecommerce by Instinct and I’d like to insert the shopping basket in the empty right side of header. (I deleted sidebar to have a wide square where to put all products images and descriptions)
    Instinct provides this shortcode to add the cart to the sidebar or header
    Please can you help me how to add this code to the header?
    Many thanks

  23. Lars
    Posted November 26, 2009 at 5:26 pm | Permalink

    This is one of the most comprehensive and thorough tutorials on WordPress template development I’ve come across. Some very useful tips on the header section, however I did miss one thing though. Why no meta description? Whilst it’s true that it offers no benefit with regards to actual search engine ranking it is vital for maintaining some control of what is actually displayed in the SERPs.

  24. vito
    Posted December 1, 2009 at 5:13 am | Permalink

    Hi

    Nice tutorial, but for some reason, fixed width?, some of the text disappear under the right column, making it very hard to understand.

    I’m on a 1280×800 laptop, nothing special, so I suppose others must have seen this as well.

    regards

    Vito

    • vito
      Posted December 1, 2009 at 5:32 am | Permalink

      By the way, tested this in both ie8, ff3 and chrome.

      Disabled css and kept reading this very fine tutorial….

      • Lars
        Posted December 1, 2009 at 6:33 am | Permalink

        I noticed that too when I came back to read the article again. It looks like the plugin that formats code is disabled or non-functional. It worked fine about a week ago.

  25. Posted December 20, 2009 at 12:49 am | Permalink

    Hey Ian, really great tutorial so far (I’m currently on step 5).

    Quick question so I’m not spinning my wheels, should this tutorial work fine with the latest WP 2.9 release? If not, do you know what steps need to be modified, or would you need to completely retool the tutorial?

    Thanks a mil, buddy :)

  26. Alex
    Posted December 29, 2009 at 6:47 pm | Permalink

    I have only recently taken up WordPress, and have been looking for something like this for the past week! So far I’m following along and understanding well, this is great.

  27. Alex
    Posted January 3, 2010 at 10:18 pm | Permalink

    Now that I’ve followed through your tutorials, how do I change my blog-title to an image? Been trying to figure this out for a little while but have had no sucess

5 Trackbacks

  1. [...] here: The WordPress Theme Header Template Share and [...]

  2. By WordPress 主题 Header 模板 | 精品博客 on June 30, 2009 at 9:06 pm

    [...] 原文:The WordPress Theme Header Template [...]

  3. By Top 10 WordPress hacks from June ‘09 on July 6, 2009 at 9:31 am
  4. [...] via themeshaper.com [...]

  5. By geedebook » 11 Trik WordPress Conditional Tags on January 27, 2010 at 3:22 am

    [...] Sumber: The WordPress Theme Header Template. [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

By submitting a comment here you grant this site a perpetual license to reproduce your words and name/web site in attribution. In addition, you may find yourself fitter, happier and more productive. Comment away.

Subscribe without commenting