Дочерние темы WordPress: создание, кастомизация и подводные камни

Когда нужно изменить внешний вид сайта на WordPress — добавить свои стили, переопределить шаблон или подключить скрипт — многие редактируют файлы родительской темы напрямую. После обновления темы все правки исчезают. Дочерняя тема решает эту проблему: она наследует весь функционал родительской и позволяет безопасно вносить любые изменения.

Структура дочерней темы

Минимальная дочерняя тема состоит из двух файлов: style.css с обязательным заголовком и functions.php для подключения стилей родительской темы. Создайте каталог в wp-content/themes/:

wp-content/themes/
├── flavor/               ← родительская тема
│   ├── style.css
│   ├── functions.php
│   ├── header.php
│   ├── single.php
│   └── ...
└── flavor-child/         ← дочерняя тема
    ├── style.css         ← обязательно
    ├── functions.php     ← обязательно
    ├── screenshot.png    ← необязательно, но желательно
    └── ...

Файл style.css дочерней темы содержит метаданные в комментарии. Ключевое поле — Template, оно должно точно совпадать с именем каталога родительской темы:

/*
Theme Name:   Flavor Child
Theme URI:    https://example.com/flavor-child
Description:  Дочерняя тема для Flavor с кастомными стилями и шаблонами
Author:       Developer Name
Author URI:   https://example.com
Template:     flavor
Version:      1.0.0
License:      GNU General Public License v2 or later
License URI:  https://www.gnu.org/licenses/gpl-2.0.html
Text Domain:  flavor-child
*/

/* Свои стили ниже */
.site-header {
    background-color: #1a1a2e;
}

.entry-title a {
    color: #e94560;
    text-decoration: none;
}

.entry-title a:hover {
    color: #0f3460;
}

Поле Template регистрозависимо и должно содержать точное имя каталога родительской темы (не название из заголовка, а имя папки). Если родительская тема лежит в wp-content/themes/flavor, пишите Template: flavor.

Правильное подключение стилей

Стили родительской темы не наследуются автоматически — их нужно подключить явно через wp_enqueue_style() в functions.php дочерней темы. Это правильный способ, который гарантирует корректный порядок загрузки.

<?php
// functions.php дочерней темы
add_action( 'wp_enqueue_scripts', function() {
    // Подключаем стили родительской темы
    wp_enqueue_style(
        'flavor-parent-style',
        get_template_directory_uri() . '/style.css',
        [],
        wp_get_theme( 'flavor' )->get( 'Version' )
    );

    // Подключаем стили дочерней темы (зависят от родительских)
    wp_enqueue_style(
        'flavor-child-style',
        get_stylesheet_directory_uri() . '/style.css',
        [ 'flavor-parent-style' ],
        wp_get_theme()->get( 'Version' )
    );

    // Дополнительный CSS-файл дочерней темы
    wp_enqueue_style(
        'flavor-child-custom',
        get_stylesheet_directory_uri() . '/assets/css/custom.css',
        [ 'flavor-child-style' ],
        '1.0.0'
    );

    // Скрипт дочерней темы
    wp_enqueue_script(
        'flavor-child-script',
        get_stylesheet_directory_uri() . '/assets/js/custom.js',
        [ 'jquery' ],
        '1.0.0',
        true
    );
});

// Отключение ненужного скрипта родительской темы
add_action( 'wp_enqueue_scripts', function() {
    wp_dequeue_script( 'flavor-slider' );
    wp_deregister_script( 'flavor-slider' );
}, 20 ); // приоритет выше, чтобы выполнилось после подключения

Обратите внимание на разницу между двумя функциями:

  • get_template_directory_uri() — возвращает URL каталога родительской темы
  • get_stylesheet_directory_uri() — возвращает URL каталога дочерней (текущей активной) темы

То же самое для путей к файлам: get_template_directory() и get_stylesheet_directory(). Это самый частый источник ошибок при разработке дочерних тем.

Переопределение шаблонов

WordPress использует иерархию шаблонов: для каждого типа страницы он ищет файл сначала в дочерней теме, затем в родительской. Чтобы изменить шаблон, скопируйте его из родительской темы в дочернюю и отредактируйте.

# Копируем single.php из родительской темы в дочернюю
cp wp-content/themes/flavor/single.php wp-content/themes/flavor-child/single.php

# Копируем шаблон-часть (если есть)
mkdir -p wp-content/themes/flavor-child/template-parts
cp wp-content/themes/flavor/template-parts/content-single.php \
   wp-content/themes/flavor-child/template-parts/content-single.php

Теперь можно редактировать скопированные файлы — WordPress подхватит версию из дочерней темы. Пример добавления блока «Похожие записи» в single.php:

<?php
// single.php дочерней темы — добавляем блок после статьи
get_header();
?>

<main id="primary" class="site-main">
    <?php
    while ( have_posts() ) :
        the_post();
        get_template_part( 'template-parts/content', 'single' );

        // Навигация между записями
        the_post_navigation([
            'prev_text' => '&larr; %title',
            'next_text' => '%title &rarr;',
        ]);

        // Блок похожих записей по текущей категории
        $categories = get_the_category();
        if ( $categories ) {
            $related = new WP_Query([
                'category__in'   => [ $categories[0]->term_id ],
                'post__not_in'   => [ get_the_ID() ],
                'posts_per_page' => 3,
                'orderby'        => 'rand',
            ]);

            if ( $related->have_posts() ) :
            ?>
            <div class="related-posts">
                <h2>Похожие записи</h2>
                <div class="related-grid">
                    <?php while ( $related->have_posts() ) : $related->the_post(); ?>
                    <article class="related-item">
                        <?php if ( has_post_thumbnail() ) : ?>
                            <a href="<?php the_permalink(); ?>">
                                <?php the_post_thumbnail( 'medium' ); ?>
                            </a>
                        <?php endif; ?>
                        <h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
                    </article>
                    <?php endwhile; ?>
                </div>
            </div>
            <?php
            endif;
            wp_reset_postdata();
        }

        // Комментарии
        if ( comments_open() || get_comments_number() ) :
            comments_template();
        endif;
    endwhile;
    ?>
</main>

<?php
get_sidebar();
get_footer();

Хуки в дочерней теме

Многие родительские темы предоставляют собственные хуки (action/filter) для кастомизации без переопределения шаблонов. Это предпочтительный способ — он не ломается при обновлении шаблонов родительской темы.

<?php
// functions.php дочерней темы

// Добавляем код в <head> через стандартный хук WordPress
add_action( 'wp_head', function() {
    ?>
    <meta name="yandex-verification" content="abc123" />
    <?php
}, 1 );

// Меняем длину анонса
add_filter( 'excerpt_length', function() {
    return 25; // слов вместо стандартных 55
});

// Меняем текст «Читать далее»
add_filter( 'excerpt_more', function() {
    return '&hellip; <a href="' . get_permalink() . '" class="read-more">Читать далее</a>';
});

// Добавляем поддержку дополнительных форматов изображений
add_action( 'after_setup_theme', function() {
    add_image_size( 'card-thumbnail', 400, 250, true );
    add_image_size( 'hero-banner', 1200, 400, true );
});

// Регистрируем дополнительное меню
add_action( 'after_setup_theme', function() {
    register_nav_menus([
        'footer-menu'  => 'Меню в подвале',
        'social-links' => 'Социальные сети',
    ]);
});

// Переопределяем функцию родительской темы (если она объявлена через if !function_exists)
function flavor_posted_on() {
    $time = '<time datetime="' . esc_attr( get_the_date( 'c' ) ) . '">' . get_the_date() . '</time>';
    echo '<span class="posted-on">Опубликовано: ' . $time . '</span>';
}

Многие темы оборачивают свои функции в if ( ! function_exists( 'theme_function' ) ). Это позволяет дочерней теме определить функцию с тем же именем — она загрузится первой и «перебьёт» родительскую без конфликтов.

Распространённые ошибки и подводные камни

Дочерние темы — простой механизм, но несколько ошибок встречаются регулярно:

  • Неправильное значение Template — должно совпадать с именем каталога родительской темы, не с Theme Name. Тема просто не активируется
  • @import вместо wp_enqueue_style — устаревший способ подключения стилей. Он не позволяет контролировать порядок загрузки и не работает с HTTP/2 push
  • Путаница get_template vs get_stylesheetget_template_directory() указывает на родительскую тему, get_stylesheet_directory() — на дочернюю. Если подключаете файл из дочерней темы, используйте get_stylesheet_directory()
  • Копирование всех шаблонов — копируйте только те файлы, которые реально меняете. Чем меньше файлов переопределено, тем меньше проблем при обновлении родительской темы
  • Забыли подключить стили родителя — без wp_enqueue_style для родительского style.css сайт останется без основного оформления
  • Дублирование add_action в functions.phpfunctions.php дочерней темы не заменяет родительский, а дополняет его. Оба файла загружаются: сначала дочерний, потом родительский. Если нужно убрать хук родителя, используйте remove_action()

Когда дочерняя тема не нужна

Дочерняя тема — не единственный способ кастомизации. Рассмотрите альтернативы:

  • Кастомайзер (Внешний вид → Настроить) — для изменения цветов, шрифтов, логотипа. Изменения хранятся в БД и не теряются при обновлении
  • Дополнительный CSS (в кастомайзере) — для небольших стилевых правок
  • Плагин функциональности — если код не зависит от темы (шорткоды, CPT, виджеты), лучше вынести его в плагин. При смене темы функциональность сохранится
  • Своя тема с нуля — если вы переписываете больше 70% шаблонов, дочерняя тема теряет смысл. Проще создать свою тему

Дочерняя тема — обязательный инструмент при работе с готовыми темами из каталога WordPress.org или коммерческих маркетплейсов. Она гарантирует, что ваши изменения переживут обновления родительской темы, и позволяет откатиться к оригиналу в один клик — достаточно деактивировать дочернюю тему.