Almost every page a theme renders shares the same opening and closing markup — the <head>, the site header and navigation at the top, the footer at the bottom. Rather than repeating that in every template file, it lives in exactly two places: header.php and footer.php.
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<?php wp_head(); ?>
</head>
<body <?php body_class(); ?>>
<header id="site-header">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php bloginfo( 'name' ); ?></a>
</header>Three functions here matter more than the rest of the markup:
| Function | What it does |
|---|---|
wp_head() | Fires a hook that WordPress core, every plugin, and SEO tools all attach to — stylesheets, meta tags, tracking scripts, and more all get injected here |
body_class() | Outputs a set of CSS classes describing the current page (home, single-post, page-id-12, and more) — useful for page-specific styling without extra PHP logic |
language_attributes() | Outputs the correct lang and text-direction attributes for the site's configured language |
<footer id="site-footer">
<p>© <?php echo esc_html( date( 'Y' ) ); ?> <?php bloginfo( 'name' ); ?></p>
</footer>
<?php wp_footer(); ?>
</body>
</html>wp_footer() is wp_head()'s counterpart — plugins that need to output JavaScript near the closing </body> tag (most of them, for performance reasons) hook in here instead of the head.
These two hooks are not optional
Never leave out wp_head() or wp_footer(). Plugins genuinely depend on both firing on every page — leaving one out doesn't just look wrong, it silently breaks plugin functionality with no obvious error message pointing at the cause.
Every other template file starts with get_header() and ends with get_footer() — WordPress functions that simply include the matching file:
<?php get_header(); ?>
<p>Page-specific content goes here.</p>
<?php get_footer(); ?>With the shared shell in place, the next lesson looks at what actually goes between get_header() and get_footer() — the Loop, the piece of code that outputs a post or page's actual content.