WordPress’s add_theme_support() function is the theme’s declaration to the core that it opts into specific features. Without these declarations, core features that require theme cooperation are simply inactive — there will be no <title> tag in the document head, no featured image support, no wide-aligned block support, and no custom logo picker in the Customizer. The function must be called inside the after_setup_theme hook (not init), because theme setup runs before init and some features — particularly html5 and title-tag — affect output that is generated before init fires. Correctly declaring theme support is the first step in building any production WordPress theme and has implications for accessibility, SEO, and the block editor.
Problem: A custom theme has no <title> tag in its source, featured images do not appear in the block editor sidebar, the Customizer has no Custom Logo option, and wide/full-width blocks are constrained to the content width.
Solution: Add all required add_theme_support() calls inside after_setup_theme. Each feature needs its own call with the correct argument structure.
<?php
// functions.php — must be in after_setup_theme, NOT init
add_action( 'after_setup_theme', 'my_theme_setup' );
function my_theme_setup(): void {
// ── 1. Dynamic tag — replaces hardcoded in header.php ─
add_theme_support( 'title-tag' );
// ── 2. Featured images (post thumbnails) ──────────────────────────
add_theme_support( 'post-thumbnails' );
// Enable for specific post types only:
// add_theme_support( 'post-thumbnails', [ 'post', 'product' ] );
// ── 3. HTML5 semantic markup for core elements ────────────────────
add_theme_support( 'html5', [
'search-form',
'comment-form',
'comment-list',
'gallery',
'caption',
'style', // outputs