functions.php runs automatically on every request, the same way a plugin does — except it's scoped to whichever theme is active. This is where a theme declares what it supports, sets up menus and image sizes, and defines any custom logic the templates will lean on.
WordPress ships with a long list of features a theme can opt into, one call at a time:
<?php
function mytheme_setup() {
add_theme_support( 'title-tag' );
add_theme_support( 'post-thumbnails' );
add_theme_support( 'custom-logo' );
add_theme_support( 'html5', [ 'search-form', 'comment-form', 'comment-list', 'gallery', 'caption' ] );
}
add_action( 'after_setup_theme', 'mytheme_setup' );| Feature | What it enables |
|---|---|
| title-tag | Lets WordPress manage the <title> tag itself, instead of the theme writing it by hand |
| post-thumbnails | Featured images — without this, has_post_thumbnail() never returns true |
| custom-logo | A logo upload/crop screen in the Customizer, read back with the_custom_logo() |
| html5 | Modern HTML5 markup for the listed elements instead of WordPress's older default markup |
Theme setup code never runs directly at the top level of functions.php — it's wrapped in a function and attached to the after_setup_theme action hook, which WordPress fires once it has finished loading the active theme. Some features (like add_theme_support()) genuinely require this — calling them too early fails silently.
Prefix everything
Every function you define in functions.php shares one global namespace with WordPress core, every active plugin, and (if it's ever changed) any other theme. Two functions with the same name crash the site with a fatal error. Always prefix your own function names with something specific to the theme — mytheme_setup(), not setup().
Beyond initial setup, functions.php is also where a theme registers navigation menus (a later lesson), enqueues its stylesheets and scripts (also a later lesson), and defines any custom helper functions the template files call. As a theme grows, it's common to split these into separate included files rather than letting one functions.php sprawl — but everything still ultimately loads through it.
The next lesson puts some of this to use directly — building header.php and footer.php, the two files every other template shares.