Converting the markup to HTML5

If you missed the first post, the goal of this blog is to document my experiments with the various new & exciting web technologies that tend to get banded together, rightly or wrongly, under the name HTML5.

I’m starting with Chris Coyier’s Blank WP theme as a base. The first step is to convert the blank template’s markup to HTML5 and decide what additional CSS and scripting would be useful. To make this article more readable, I’ve sprinkled a tiny bit of CSS on top; just basic heading styles and the like.

Additions

HTML5 reset

I’ll need an HTML5 reset stylesheet to provide base styles where the browser doesn’t have any and provide a level playing field in much the same way that Eric Meyer’s excellent reset stylesheet does.

Modernizr

I’m also going to make my only Javascript addition and include the Modernizr library. For those not familiar, Modernizr provides two useful functions: firstly, it implements the HTML5 Shiv which enables the use of the new HTML5 elements in browsers that don’t natively support them. It does this by creating one of each element using the elementCreate() javascript function which for some reason causes the browser to recognise the existence of the new elements thus allowing them to be styled. Bizarre but it works.

Of course this makes your styling completely reliant on Javascript being available. If you think there’s a chance your target audience may have Javascript switched off then you might want to rethink your strategy. Ie. use good old HTML4…

The other, and arguably main function it provides is feature detection. The library will test the browser for a range of features such as HTML5 Video / Audio support, various aspects of CSS3, Geolocation API etc. and will add classnames to the body tag of the document indicating what’s supported. This allows the developer to tailor his or her CSS depending to the features available.

Coding Style

I’m sticking with the XHTML style of markup. That means closing tags wherever possible, self closing tags where applicable, quoted attributes etc. I’m a sucker for convention and the potential freeform coding style that HTML5 allows makes me uncomfortable. One of the few good things to come from the W3Cs dabbling with XML is the rigorous coding style that it enforces. This leads to convention which in turn leads to standard coding styles and easier maintainability.

Potential Pitfalls

I guess the only pitfall I’m really anticipating is a potential issue with markup generated from the bowels of WordPress and the WP rich text editor. However, by sticking with the XHTML coding style that is already is used by WP, I hope to minimise the chance of any possible gotchas.

The Markup

I’m not going to delve too far into the semantics of the new elements. If you’re looking for more info on the elements themselves, check out Dive into HTML5 or the HTML5 working draft, which surprisingly, isn’t as dull as you might think.

I did consider documenting the process of converting the markup line by line but realised how utterly tedious that would be to both write and read. Instead, I’m only going highlight templates that I’ve made any significant changes to and even then I’ll be keeping it brief. I’ll upload it to Github so people to grab it and mangle to their heart’s content.

So with no further ado, let’s start at the top.

header.php

These are the changes I’ve made to the header.php:

  1. Replaced the DOCTYPE with the shorter (and considerably easier to remember) HTML5 version.
  2. Removed the xmlns attribute from <html>. We’re not in Kansas anymore, Toto. Kansas being a flimsy euphemism for XML.
  3. Removed unnecessary attributes from <head> section. Including profile attribute on <head> and http-equiv on meta tags.
  4. Replaced header <div> with <header>.
  5. Replaced description <div> with <h2> and wrapped both the <h1> and <h2> in an <hgroup> element.

That wasn’t too painful, was it? Here’s the file in full:

<!DOCTYPE html>

<html <?php language_attributes(); ?>>

<head>
  <meta charset="<?php bloginfo('charset'); ?>" />

  <?php if (is_search()) { ?>
  <meta name="robots" content="noindex, nofollow" />
  <?php } ?>

   <title>
   <?php
      if (function_exists('is_tag') && is_tag()) {
         single_tag_title("Tag Archive for &quot;"); echo '&quot; - '; }
      elseif (is_archive()) {
         wp_title(''); echo ' Archive - '; }
      elseif (is_search()) {
         echo 'Search for &quot;'.wp_specialchars($s).'&quot; - '; }
      elseif (!(is_404()) && (is_single()) || (is_page())) {
         wp_title(''); echo ' - '; }
      elseif (is_404()) {
         echo 'Not Found - '; }
      if (is_home()) {
         bloginfo('name'); echo ' - '; bloginfo('description'); }
      else {
          bloginfo('name'); }
      if ($paged>1) {
         echo ' - page '. $paged; }
   ?>
   </title>

  <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
  <link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>" />
  <link rel="pingback" href="<?php bloginfo('pingback_url'); ?>" />

  <script type="text/javascript" src="<?php echo get_bloginfo('template_url'); ?>/js/modernizr-1.5.min.js"></script>

  <?php if ( is_singular() ) wp_enqueue_script( 'comment-reply' ); ?>

  <?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>
  <div id="page-wrap">
    <header class="chrome">
      <hgroup>
        <h1><a href="<?php echo get_option('home'); ?>/"><?php bloginfo('name'); ?></a></h1>
	<h2 class="description"><?php bloginfo('description'); ?></h2>
      </hgroup>
    </header>

index.php

Next we’ll look at the main index.php file. Again, fairly simple stuff:

  1. Replaced the main post <div> with an <article> element
  2. Wrapped the whole lot in a <section> element
  3. Changed the post title from an <h2> to an <h1>. Headings have changed in HTML5 and we no longer have one linear document outline with a single <h1> and subsequent headings fanning out below it. In HTML5, logical “sections”, and this includes the new <article> element, each have their own “headings context”, for want of a better phrase. This means that the main heading in an article should be a <h1> with any other relevant headings following on from that. This is something I’ll be doing in a lot of whilst converting the template.
  4. Wrapped the post title in a <header> element.
  5. Moved the meta.php include directive inside the <header>.
  6. Replaced the post meta <div> with a <footer> element.
  7. Converted the second post meta <div> into a <footer> element.

I’ve also made very similar changes to the archive.php, search.php and single.php files so I won’t bother going into them in any greater detail.

<?php get_header(); ?>
  <section>
    <?php if (have_posts()) : while (have_posts()) : the_post(); ?>

      <article <?php post_class() ?> id="post-<?php the_ID(); ?>">

        <h1><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></h1>

        <?php include (TEMPLATEPATH . '/inc/meta.php' ); ?>

        <div class="entry">
          <?php the_content(); ?>
        </div>

        <div class="postmetadata">
          <?php the_tags('Tags: ', ', ', '<br />'); ?>
          Posted in <?php the_category(', ') ?> |
          <?php comments_popup_link('No Comments &#187;', '1 Comment &#187;', '% Comments &#187;'); ?>
        </div>

      </article>

    <?php endwhile; ?>

    <?php include (TEMPLATEPATH . '/inc/nav.php' ); ?>

    <?php else : ?>

      <h1>Not Found</h1>

    <?php endif; ?>
  </section>

<?php get_sidebar(); ?>

<?php get_footer(); ?>

inc/meta.php

All I’ve done here is wrapped the post date in the new <time> element. I included the “pubdate” flag on the <time> element to indicate a publishing date. The value of the “datetime” attribute must be a valid date in the format yyyy-mm-dd.

<div class="meta">
  <em>Posted on:</em> <time datetime="<?php the_time('Y-m-d') ?>" pubdate="pubdate"><?php the_time('F jS, Y') ?></time>
  <em>by</em> <?php the_author() ?>
  <?php comments_popup_link('No Comments', '1 Comment', '% Comments', 'comments-link', ''); ?>
</div>

inc/nav.php

Replaced <div class=”navigation”> with a <nav> element.

<nav class="paging">
  <div class="next-posts"><?php next_posts_link('&laquo; Older Entries') ?></div>
  <div class="prev-posts"><?php previous_posts_link('Newer Entries &raquo;') ?></div>
</nav>

footer.php

Replaced the footer <div> with a … <footer>. Also given it a class of “chrome” to distinguish it as the main footer.

    <footer class="chrome">
      &copy;<?php echo date("Y"); echo " "; bloginfo('name'); ?>
    </footer>

  </div>

  <?php wp_footer(); ?>

  <!-- Don't forget analytics -->

</body>
</html>

sidebar.php

The first change here was converting the sider <div> into an <aside> with a class of “chrome”. I then wrapped each list of links in a <nav> and changed all the <h2>s to <h1>s as the <nav> creates a new heading context just like the <article> element.

I’ve also added rel=”alternate” to the two RSS feed links.

<aside class="chrome">
  <?php if (function_exists('dynamic_sidebar') && dynamic_sidebar('Sidebar Widgets')) : else : ?>

    <!-- All this stuff in here only shows up if you DON'T have any widgets active in this zone -->

    <?php get_search_form(); ?>

    <nav>
      <h1>Pages</h1>
      <ul>
        <?php wp_list_pages('title_li='); ?>
      </ul>
    </nav>

    <nav>
      <h1>Archives</h1>
      <ul>
        <?php wp_get_archives('type=monthly'); ?>
      </ul>
    </nav>

    <nav>
      <h1>Categories</h1>
      <ul>
        <?php wp_list_categories('show_count=1&title_li='); ?>
      </ul>
    </nav>

    <nav>
      <?php wp_list_bookmarks(); ?>
    </nav>

    <nav>
      <h1>Meta</h1>
      <ul>
        <?php wp_register(); ?>
        <li><?php wp_loginout(); ?></li>
        <li><a href="http://wordpress.org/" rel="external" title="Powered by WordPress, state-of-the-art semantic personal publishing platform.">WordPress</a></li>
        <?php wp_meta(); ?>
      </ul>
    </nav>

    <nav>
      <h1>Subscribe</h1>
      <ul>
        <li><a href="<?php bloginfo('rss2_url'); ?>" rel="alternate">Entries (RSS)</a></li>
        <li><a href="<?php bloginfo('comments_rss2_url'); ?>" rel="alternate">Comments (RSS)</a></li>
      </ul>
    </nav>
  <?php endif; ?>
</aside>

searchform.php

I’ve changed the “type” attribute of the “s” field to “search”. If the browser doesn’t recognise any of the new “type” attributes, it *should* just treat them as text fields.

  <form action="<?php bloginfo('siteurl'); ?>" id="searchform" method="get">
    <div>
      <label for="s" class="screen-reader-text">Search for:</label>
      <input type="search" id="s" name="s" value="" />
      <input type="submit" value="Search" id="searchsubmit" />
    </div>
  </form>

comments.php

And last but not least, the comments. I’ve done a few things here, so let’s have ourselves another list, shall we?

  1. Wrapped the whole lot in a <section>.
  2. Changed the first <h2> to an <h1>.
  3. Changed the two navigation <div>s to <nav>s.
  4. Changed the “respond” <div> to a <section>.
  5. Updated the respond title to an <h1>.
  6. Changed the “type” attribute for the email form field to “email” and the type of the URL field to “url”.

The markup for the actual comments themselves is generated by the WordPress function, wp_list_comments(), so I’ll need to write a callback function customise that.

<section class="comments">
<?php

  if (!empty($_SERVER['SCRIPT_FILENAME']) && 'comments.php' == basename($_SERVER['SCRIPT_FILENAME']))
    die ('Please do not load this page directly. Thanks!');

  if ( post_password_required() ) { ?>
    This post is password protected. Enter the password to view comments.
  <?php
    return;
  }
?>

<?php if ( have_comments() ) : ?>

  <h1 id="comments"><?php comments_number('No Responses', 'One Response', '% Responses' );?></h1>

  <nav class="paging">
    <div class="next-posts"><?php previous_comments_link() ?></div>
    <div class="prev-posts"><?php next_comments_link() ?></div>
  </nav>

  <ol class="commentlist">
    <?php wp_list_comments(); ?>
  </ol>

  <nav class="paging">
    <div class="next-posts"><?php previous_comments_link() ?></div>
    <div class="prev-posts"><?php next_comments_link() ?></div>
  </nav>

 <?php else : // this is displayed if there are no comments so far ?>

  <?php if ( comments_open() ) : ?>
    <!-- If comments are open, but there are no comments. -->

   <?php else : // comments are closed ?>
    <p>Comments are closed.</p>

  <?php endif; ?>

<?php endif; ?>

<?php if ( comments_open() ) : ?>

<section id="respond">

  <h1><?php comment_form_title( 'Leave a Reply', 'Leave a Reply to %s' ); ?></h1>

  <div class="cancel-comment-reply">
    <?php cancel_comment_reply_link(); ?>
  </div>

  <?php if ( get_option('comment_registration') && !is_user_logged_in() ) : ?>
    <p>You must be <a href="<?php echo wp_login_url( get_permalink() ); ?>">logged in</a> to post a comment.</p>
  <?php else : ?>

  <form action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post" id="commentform">

    <?php if ( is_user_logged_in() ) : ?>

      <p>Logged in as <a href="<?php echo get_option('siteurl'); ?>/wp-admin/profile.php"><?php echo $user_identity; ?></a>. <a href="<?php echo wp_logout_url(get_permalink()); ?>" title="Log out of this account">Log out &raquo;</a></p>

    <?php else : ?>

      <div>
        <input type="text" name="author" id="author" value="<?php echo esc_attr($comment_author); ?>" size="22" tabindex="1" <?php if ($req) echo "aria-required='true'"; ?> />
        <label for="author">Name <?php if ($req) echo "(required)"; ?></label>
      </div>

      <div>
        <input type="email" name="email" id="email" value="<?php echo esc_attr($comment_author_email); ?>" size="22" tabindex="2" <?php if ($req) echo "aria-required='true'"; ?> />
        <label for="email">Mail (will not be published) <?php if ($req) echo "(required)"; ?></label>
      </div>

      <div>
        <input type="url" name="url" id="url" value="<?php echo esc_attr($comment_author_url); ?>" size="22" tabindex="3" />
        <label for="url">Website</label>
      </div>

    <?php endif; ?>

    <!--<p>You can use these tags: <code><?php echo allowed_tags(); ?></code></p>-->

    <div>
      <textarea name="comment" id="comment" cols="58" rows="10" tabindex="4"></textarea>
    </div>

    <div>
      <input name="submit" type="submit" id="submit" tabindex="5" value="Submit Comment" />
      <?php comment_id_fields(); ?>
    </div>

    <?php do_action('comment_form', $post->ID); ?>

  </form>

  <?php endif; // If registration required and not logged in ?>

</section>

<?php endif; ?>
</section>

functions.php

As mentioned above, I’ve had to add a function to customise the markup of the comments themselves. This has to be done as a callback function in the functions.php file that the wp_list_comments() function can call. All I’ve really done is wrapped each comment in a <article> element and wrapped the comment’s meta data in a <header>.

I’ve also commented out the lines that load jQuery by default. If you need jQuery, simply uncomment them.

<?php
  // Add RSS links to <head> section
  automatic_feed_links();

  // UNCOMMENT THE FOLLOWING IF YOU NEED JQUERY LOADED:
  /*
  if ( !is_admin() ) {
     wp_deregister_script('jquery');
     wp_register_script('jquery', ("http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"), false);
     wp_enqueue_script('jquery');
  }
  */

  // Clean up the <head>
  function removeHeadLinks() {
    remove_action('wp_head', 'rsd_link');
    remove_action('wp_head', 'wlwmanifest_link');
  }

  add_action('init', 'removeHeadLinks');
  remove_action('wp_head', 'wp_generator');

  if (function_exists('register_sidebar')) {
    register_sidebar(array(
      'name' => 'Sidebar Widgets',
      'id'   => 'sidebar-widgets',
      'description'   => 'These are widgets for the sidebar.',
      'before_widget' => '<div id="%1$s" class="widget %2$s">',
      'after_widget'  => '</div>',
      'before_title'  => '<h1>',
      'after_title'   => '</h1>'
    ));
  }

  function blankhtml5_comment($comment, $args, $depth) {
    $GLOBALS['comment'] = $comment; ?>
    <li <?php comment_class(); ?> id="li-comment-<?php comment_ID() ?>">
      <article id="comment-<?php comment_ID(); ?>">
        <header class="comment-author vcard">
          <?php echo get_avatar($comment,$size='48',$default='<path_to_url>' ); ?>

          <?php printf(__('<cite class="fn">%s</cite> <span class="says">says:</span>'), get_comment_author_link()) ?>
          <?php if ($comment->comment_approved == '0') : ?>
            <em><?php _e('Your comment is awaiting moderation.') ?></em><br />
          <?php endif; ?>

          <div class="comment-meta commentmetadata"><a href="<?php echo htmlspecialchars( get_comment_link( $comment->comment_ID ) ) ?>"><?php printf(__('%1$s at %2$s'), get_comment_date(),  get_comment_time()) ?></a><?php edit_comment_link(__('(Edit)'),'  ','') ?></div>
        </header>

        <?php comment_text() ?>

        <div class="reply">
          <?php comment_reply_link(array_merge( $args, array('depth' => $depth, 'max_depth' => $args['max_depth']))) ?>
        </div>
      </article>
  <?php
  }
?>

Questions and lessons

One area of ambiguity is the new approach to headings. As mentioned earlier, I’m so used to the current way of outlining content with headings that I found the new approach strange and perhaps a little confusing. Although I haven’t done so yet, running the markup through this outlining tool may give me a better idea as to how it all hangs together. Will report back when I do.

Another point of ambiguity is the <section> element. When is a section a section and not a div or an article? the working draft has this to say on the matter:

The section element represents a generic section of a document or application. A section, in this context, is a thematic grouping of content, typically with a heading.

Examples of sections would be chapters, the various tabbed pages in a tabbed dialog box, or the numbered sections of a thesis. A Web site’s home page could be split into sections for an introduction, news items, and contact information.

Authors are encouraged to use the article element instead of the section element when it would make sense to syndicate the contents of the element.

The section element is not a generic container element. When an element is needed for styling purposes or as a convenience for scripting, authors are encouraged to use the div element instead. A general rule is that the section element is appropriate only if the element’s contents would be listed explicitly in the document’s outline.

I think this could be a source of confusion for developers. Only time will tell.

On the whole, this has been a fairly simple exercise. That said, it’s hard to tell if the exercise has been a “success” as I don’t really have a benchmark for what constitutes a “success”. Does it validate? Yes but the real proof will be in the eating. Let’s see how I fare over the coming weeks as I try and style the markup.

Finally, I’ve taken a screen shot of this page as it is right now so it can be referred back if this site has changed drastically since this post was written.

Tags: , , , ,
2

2 Responses

  1. vale says:

    Nice article. I have a question. What if we use a widgetized sidebar? Each widget should be wrapped in the right html5 markup, not in a generic div or li element. For example a blogroll should be inside a nav tag, a generic text inside a section element, a tag cloud too should be inside a nav container as well, etc.
    Is it possible to change individually every widget container elements?

  2. vale says:

    Thanks a lot for sharing! This is exactly what I was looking for to understand how to change in WorpPress other markup to HTML5 (ie comments).

Leave a Reply