Как эффективно использовать functions.php в разработке тем

Раздел: WordPress -> Файлы темы WordPress

Файл functions.php является центральным элементом любой темы WordPress. Он позволяет добавлять пользовательские функции, подключать стили и скрипты, регистрировать произвольные типы записей, таксономии и многое другое. В этой статье рассматриваются основные приёмы работы с этим файлом, приводятся примеры кода и поясняются типичные ошибки.

Основное использование и эффективное решение

Самый распространённый сценарий - подключение стилей и скриптов через хуки. Для этого используется функция wp_enqueue_style и wp_enqueue_script, обёрнутые в функцию, которая прикрепляется к действию wp_enqueue_scripts.


// Подключение стилей и скриптов темы
function my_theme_assets() {
    wp_enqueue_style( 'my-theme-style', get_stylesheet_uri() );
    wp_enqueue_script( 'my-theme-script', get_template_directory_uri() . '/js/script.js', array(), '1.0', true );
}
add_action( 'wp_enqueue_scripts', 'my_theme_assets' );

Пояснение: первый параметр - уникальное имя, второй - путь к файлу. Для стилей можно использовать get_stylesheet_uri(), для скриптов - get_template_directory_uri() или get_stylesheet_directory_uri() в дочерней теме. Параметр true в wp_enqueue_script означает, что скрипт будет загружен в подвале.

Типичная ошибка: вызов wp_enqueue_style вне хука wp_enqueue_scripts. Это может привести к неправильному порядку загрузки или полному отсутствию стилей. Решение: всегда оборачивать подключение в функцию и вешать её на соответствующий хук.

Как добавить произвольный тип записи (например, «Отзывы»)?


function create_testimonial_post_type() {
    register_post_type( 'testimonial',
        array(
            'labels' => array(
                'name' => __( 'Отзывы' ),
                'singular_name' => __( 'Отзыв' )
            ),
            'public' => true,
            'has_archive' => true,
            'supports' => array( 'title', 'editor', 'thumbnail' )
        )
    );
}
add_action( 'init', 'create_testimonial_post_type' );

Проблема: после добавления кода тип записи не появляется. Частая причина - неиспользование функции flush_rewrite_rules() после регистрации. Решение: на время разработки можно добавить вызов flush_rewrite_rules() внутри функции, но потом его лучше убрать и выполнить сброс правил перезаписи через админку (Настройки → Постоянные ссылки → Сохранить).

Как изменить длину отрывка (excerpt) записей?


function custom_excerpt_length( $length ) {
    return 20; // количество слов
}
add_filter( 'excerpt_length', 'custom_excerpt_length' );

Ошибка: фильтр не срабатывает, если отрывок задан вручную через поле «Отрывок» в админке - тогда фильтр игнорируется. Решение: использовать get_the_excerpt только для автоматически сгенерированных отрывков.

Как добавить поддержку вложенных меню и произвольные поля?


// Включение поддержки меню в теме
function theme_setup() {
    register_nav_menus( array(
        'primary' => __( 'Основное меню' )
    ) );
}
add_action( 'after_setup_theme', 'theme_setup' );

Как добавить поддержку произвольных полей (meta boxes) для страниц?


function add_custom_meta_box() {
    add_meta_box(
        'custom_meta',
        'Дополнительные настройки',
        'render_custom_meta_box',
        'page',
        'normal',
        'default'
    );
}
add_action( 'add_meta_boxes', 'add_custom_meta_box' );

function render_custom_meta_box( $post ) {
    $value = get_post_meta( $post->ID, '_custom_field', true );
    echo '<input type="text" name="custom_field" value="' . esc_attr( $value ) . '">';
}

Проблема: при сохранении данные не сохраняются. Забыта функция сохранения через хук save_post. Пример:


function save_custom_meta_box( $post_id ) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
    if ( ! current_user_can( 'edit_page', $post_id ) ) return;
    if ( isset( $_POST['custom_field'] ) ) {
        update_post_meta( $post_id, '_custom_field', sanitize_text_field( $_POST['custom_field'] ) );
    }
}
add_action( 'save_post', 'save_custom_meta_box' );

Как изменить текст «Читать далее» в отрывках?


function custom_read_more( $more ) {
    return '... <a class="read-more" href="' . get_permalink() . '">Подробнее</a>';
}
add_filter( 'excerpt_more', 'custom_read_more' );

Расширенные примеры и нестандартные сценарии

Ниже приведены более сложные примеры использования functions.php, включающие работу с REST API, кешированием и объектно-ориентированным подходом.

Создание шорткода с атрибутами и кешированием

Пример

// Шорткод [latest_posts count="5" category="news"]
function latest_posts_shortcode( $atts ) {
    $atts = shortcode_atts( array(
        'count' => 3,
        'category' => ''
    ), $atts );
    
    $cache_key = 'latest_posts_' . md5( serialize( $atts ) );
    $output = get_transient( $cache_key );
    if ( false === $output ) {
        $args = array(
            'posts_per_page' => intval( $atts['count'] ),
            'category_name' => sanitize_title( $atts['category'] )
        );
        $query = new WP_Query( $args );
        $output = '<ul>';
        while ( $query->have_posts() ) {
            $query->the_post();
            $output .= '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
        }
        $output .= '</ul>';
        wp_reset_postdata();
        set_transient( $cache_key, $output, HOUR_IN_SECONDS );
    }
    return $output;
}
add_shortcode( 'latest_posts', 'latest_posts_shortcode' );
Результат: выводит список последних записей из указанной категории (или всех) в виде ненумерованного списка. При повторном вызове в течение часа данные берутся из Transients API, что снижает нагрузку на базу данных.

Добавление кастомной конечной точки REST API

Пример

function custom_rest_endpoint() {
    register_rest_route( 'myplugin/v1', '/data/', array(
        'methods' => 'GET',
        'callback' => 'handle_custom_data',
        'permission_callback' => function() { return current_user_can( 'manage_options' ); }
    ) );
}
add_action( 'rest_api_init', 'custom_rest_endpoint' );

function handle_custom_data( $request ) {
    $param = $request->get_param( 'id' );
    // логика получения данных
    return array( 'status' => 'ok', 'id' => $param );
}
Результат: по URL /wp-json/myplugin/v1/data?id=5 авторизованный пользователь получает JSON-ответ с переданным id.

Использование классов для организации кода

Пример

class ThemeCustomizer {
    public function __construct() {
        add_action( 'customize_register', array( $this, 'register_settings' ) );
        add_action( 'wp_head', array( $this, 'output_custom_css' ) );
    }
    
    public function register_settings( $wp_customize ) {
        $wp_customize->add_section( 'theme_colors', array(
            'title' => 'Цветовые настройки'
        ) );
        $wp_customize->add_setting( 'primary_color', array(
            'default' => '#0073aa',
            'sanitize_callback' => 'sanitize_hex_color'
        ) );
        $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'primary_color', array(
            'label' => 'Основной цвет',
            'section' => 'theme_colors'
        ) ) );
    }
    
    public function output_custom_css() {
        $color = get_theme_mod( 'primary_color', '#0073aa' );
        echo '<style>.primary-btn { background-color: ' . esc_attr( $color ) . '; }</style>';
    }
}
new ThemeCustomizer();
Результат: в разделе «Настройки темы» появляется секция для выбора основного цвета, а во фронтенде кнопки с классом primary-btn получают заданный цвет фона.

Условное подключение скриптов только на определённых страницах

Пример

function conditional_scripts() {
    if ( is_page( 'contact' ) ) {
        wp_enqueue_script( 'contact-form-js', get_template_directory_uri() . '/js/contact.js', array(), '1.0', true );
    }
    if ( is_single() && has_category( 'video' ) ) {
        wp_enqueue_style( 'video-style', get_template_directory_uri() . '/css/video.css' );
    }
}
add_action( 'wp_enqueue_scripts', 'conditional_scripts' );
Результат: скрипт contact.js загружается только на странице «Контакты», а стили video.css - только на страницах отдельных записей из категории «video».

Файл functions.php - comments

En
Wp functions php (php)