WordPress. Theme Customize API. Часть 9

17.04.2019

Теги: APICMSWeb-разработкаWordPressНастройка

Разработчики WordPress рекомендуют не доверять пользовательским данным и для каждой настройки задавать функции обратного вызова, чтобы проверить и «дезинфицировать» полученные данные. Эти функции указываются в параметрах validate_callback и sanitize_callback метода add_setting().

Давайте создадим настройку «Дата начала публикаций», которая позволяет задать год начала публикаций в блоге, чтобы правильно выводить copyright:

<footer>
    <div class="container">
        <div id="copyright">
            &copy; 2015 — 2019 Все права защищены
        </div>
    </div>
</footer>

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

<?php
add_action(
    'customize_register',
    function($customizer) { // $customizer — объект класса WP_Customize_Manager

        // Добавляем настройку «Дата начала публикаций»
        $customizer->add_setting(
            'setting_copyright_start', // идентифкатор настройки
            [
                // значение по умолчанию
                'default'           => date('Y'),
                // настройка только для темы
                'type'              => 'theme_mod',
                // как обновлять окно предпросмотра (refresh или postMessage)
                'transport'         => 'refresh',
                // функция очистки данных
                'sanitize_callback' => 'absint',
                // функция проверки данных
                'validate_callback' => function($validity, $value) {
                    $value = intval($value);
                    if (empty($value) || !is_numeric($value)) {
                        $validity->add('required', 'Поле обязательно для заполнения');
                    } elseif ($value < 1900) {
                        $validity->add('year_too_small', 'Значение слишком маленькое' );
                    } elseif ($value > date('Y')) {
                        $validity->add('year_too_big', 'Значение слишком большое');
                    }
                    return $validity;
                }
            ]
        );
        $customizer->add_control(
            'control_copyright_start', // идентификатор элемента управления
            [
                'label'       => 'Дата начала публикаций', // label элемента формы
                'section'     => 'static_front_page', // идентификатор секции
                'settings'    => 'setting_copyright_start', // идентификатор настройки
                'priority'    => 100, // порядок сортировки
            ]
        );
);
<footer>
    <div class="container">
        <div id="copyright">
            &copy;
            <?php
            $start = get_theme_mod('setting_copyright_start', date('Y'));
            ?>
            <?php if ($start != date('Y')): ?>
                <?= $start; ?><?php endif; ?>
            <?= date('Y'); ?>
            Все права защищены
        </div>
    </div>
</footer>

<?php wp_footer(); ?>
</body>
</html>

И вот что получилось в итоге:

Хорошо, теперь изменим параметр transport на postMessage. В этом случае возможны два варианта. Если мы задаем выборочное обновление (selective refresh) для нашей настройки — сообщения об ошибках будут переданы на сторону клиента и показаны пользователю без нашего участия. В противном случае, мы должны сами написать js-код, который будет выводить в окне просмотра значение настройки. И сами написать js-код, который будет показывать сообщения об ошибках.

Итак, первый вариант — используем selective refresh:

add_action(
    'customize_register',
    function($customizer) { // $customizer — объект класса WP_Customize_Manager

        // Добавляем настройку «Дата начала публикаций»
        $customizer->add_setting(
            'setting_copyright_start', // идентифкатор настройки
            [
                // значение по умолчанию
                'default'           => date('Y'),
                // значение по умолчанию
                'type'              => 'theme_mod', // настройка только для темы
                // как обновлять окно предпросмотра (refresh или postMessage)
                'transport'         => 'postMessage',
                // функция очистки данных
                'sanitize_callback' => 'absint',
                // функция проверки данных
                'validate_callback' => function($validity, $value) {
                    $value = intval($value);
                    if (empty($value) || !is_numeric($value)) {
                        $validity->add('required', 'Поле обязательно для заполнения');
                    } elseif ($value < 1900) {
                        $validity->add('year_too_small', 'Значение слишком маленькое' );
                    } elseif ($value > date('Y')) {
                        $validity->add('year_too_big', 'Значение слишком большое');
                    }
                    return $validity;
                }
            ]
        );
        $customizer->add_control(
            'control_copyright_start', // идентификатор элемента управления
            [
                'label'       => 'Дата начала публикаций', // label элемента формы
                'section'     => 'static_front_page', // идентификатор секции
                'settings'    => 'setting_copyright_start', // идентификатор настройки
                'priority'    => 100, // порядок сортировки
            ]
        );
        // используем selective refresh для обновления окна просмотра
        $customizer->selective_refresh->add_partial(
            'setting_copyright_start', // идентификатор настройки
            [
                // CSS-селектор контейнера, который будет обновляться
                'selector' => '#copyright > span',
                // функция генерирует контент для контейнера #copyright > span
                'render_callback' => function() {
                    $start = get_theme_mod('setting_copyright_start', date('Y'));
                    if ($start != date('Y')) {
                        echo $start, ' —';
                    }
                }
            ]
        );
    }
);
<footer>
    <div class="container">
        <div id="copyright">
            &copy;
            <?php
            $start = get_theme_mod('setting_copyright_start', date('Y'));
            ?>
            <?php if ($start != date('Y')): ?>
                <span><?= $start; ?></span>
            <?php endif; ?>
            <?= date('Y'); ?>
            Все права защищены
        </div>
    </div>
</footer>

<?php wp_footer(); ?>
</body>
</html>

Второй вариант — не используем selective refresh. Нам нужно подключить js-файл, который будет обеспечивать обновление окна просмотра. И еще один js-файл — для проверки данных и вывода сообщений об ошибках. Первый файл мы уже создали ранее, это customize.js в директории customize. А вот второй надо создать и подключить.

Здесь надо понимать, что первый файл выполняется в контексте окна просмотра, а второй — контексте панели настройщика. Соответственно, подключение первого вешаем на событие customize_preview_init, а второй — на событие customize_controls_enqueue_scripts.

add_action(
    'customize_register',
    function($customizer) { // $customizer — объект класса WP_Customize_Manager

        // Добавляем настройку «Дата начала публикаций»
        $customizer->add_setting(
            'setting_copyright_start', // идентифкатор настройки
            [
                // значение по умолчанию
                'default'           => date('Y'),
                // значение по умолчанию
                'type'              => 'theme_mod', // настройка только для темы
                // как обновлять окно предпросмотра (refresh или postMessage)
                'transport'         => 'postMessage',
                // функция очистки данных
                'sanitize_callback' => 'absint',
                // функция проверки данных
                'validate_callback' => function($validity, $value) {
                    $value = intval($value);
                    if (empty($value) || !is_numeric($value)) {
                        $validity->add('required', 'Поле обязательно для заполнения');
                    } elseif ($value < 1900) {
                        $validity->add('year_too_small', 'Значение слишком маленькое');
                    } elseif ($value > date('Y')) {
                        $validity->add('year_too_big', 'Значение слишком большое');
                    }
                    return $validity;
                }
            ]
        );
        $customizer->add_control(
            'control_copyright_start', // идентификатор элемента управления
            [
                'label'       => 'Дата начала публикаций', // label элемента формы
                'section'     => 'static_front_page', // идентификатор секции
                'settings'    => 'setting_copyright_start', // идентификатор настройки
                'priority'    => 100, // порядок сортировки
            ]
        );
    }
);

/*
 * Подключаем JS-файл скрипта, который обеспечивает предварительный
 * просмотр изменений настроек темы без перезагрузки окна просмотра
 */
add_action(
    'customize_preview_init',
    function() {
        wp_enqueue_script(
            'theme-settings-preview', // будет зарегистрирован под этим именем
            get_template_directory_uri() . '/customize/customize.js',
            array('jquery', 'customize-preview'), // должен быть подключен после этих скриптов
            null, // версии нет, поэтому null
            true // подключаем перед закрывающим тегом body
        );
    }
);

/*
 * Подключаем JS-файл скрипта, который обеспечивает проверку введенных
 * пользователем данных и показывает сообщения об ошибках
 */
add_action(
    'customize_controls_enqueue_scripts',
    function() {
        wp_enqueue_script(
            'theme-settings-validate', // будет зарегистрирован под этим именем
            get_template_directory_uri() . '/customizer/validator.js',
            array('customize-controls'), // должен быть подключен после этих скриптов
            null, // версии нет, поэтому null
            true // подключаем перед закрывающим тегом body
        );
    }
);

Теперь создаем файл validator.js в директории customize и добавляем в него js-код проверки данных:

wp.customize('setting_copyright_start', function (setting) {
    setting.validate = function (value) {
        var code, notification;
        var year = parseInt(value, 10);

        code = 'required';
        if (isNaN(year)) {
            notification = new wp.customize.Notification(
                code,
                {message: 'Поле обязательно для заполнения'}
            );
            setting.notifications.add(code, notification);
        } else {
            setting.notifications.remove(code);
        }

        // если это не число, дальше проверять нет смысла
        if (isNaN(year)) {
            return value;
        }

        code = 'year_too_small';
        if (year < 1900) {
            notification = new wp.customize.Notification(
                code,
                {message: 'Значение слишком маленькое'}
            );
            setting.notifications.add(code, notification);
        } else {
            setting.notifications.remove(code);
        }

        code = 'year_too_big';
        if (year > new Date().getFullYear()) {
            notification = new wp.customize.Notification(
                code,
                {message: 'Значение слишком большое'}
            );
            setting.notifications.add(code, notification);
        } else {
            setting.notifications.remove(code);
        }

        return value;
    };
});

Добавляем в файл customize.js js-код обновления окна просмотра:

(function(api, $) {
    api('setting_copyright_start', function(setting) {
        // обновляем окно просмотра
        setting.bind(function(value) {
            if (new Date().getFullYear() != value) {
                $('#copyright > span').text(value + ' —');
            } else {
                $('#copyright > span').text('');
            }
        });
    });
})(wp.customize, jQuery);

Шаблон footer.php, где выводится наша настройка:

<footer>
    <div class="container">
        <div id="copyright">
            &copy;
            <?php
            $start = get_theme_mod('setting_copyright_start', date('Y'));
            ?>
            <?php if ($start != date('Y')): ?>
                <span><?= $start; ?></span>
            <?php endif; ?>
            <?= date('Y'); ?>
            Все права защищены
        </div>
    </div>
</footer>

<?php wp_footer(); ?>
</body>
</html>

Дополнительно

Поиск: API • CMS • Web-разработка • WordPress • Настройка • Элемент управления • Секция • Control • Section • Setting • Theme Customize • Sanitize • Validate

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.