Статьи

Создание мини-CSS препроцессора для параметров цвета темы

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

В этом уроке я покажу вам, как упростить получение параметров цвета, которые установлены в настройщике, в CSS во внешнем интерфейсе. Эта простая система может быть адаптирована для использования с другими свойствами CSS, а также. Это означает, что вы можете использовать эти методы для работы с параметрами, установленными с помощью других методов, кроме Theme Customizer.

Слишком часто для получения цветов и других параметров, установленных в Theme Customizer, требуется смешанный код, смешивающий PHP и CSS.

Например:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
add_action( ‘wp_head’, ‘slug_theme_customizer_css’ );
 
function slug_theme_customizer_css() {
    ?>
    <style type=»text/css»>
        h1.site-title a {
            color: <?php echo get_theme_mod( ‘site_title_color’, ‘#ff0000’ );
        }
 
        h3.site-description {
            color: <?php echo get_theme_mod( ‘site_description_color’, ‘#000’ );
        }
    </style>
    <?php
}

Проблема с этим кодом не является чисто эстетической или трудно читаемой. Слишком легко ошибиться. Например, закрытие тегов PHP с последующим закрытием объявления CSS приводит к следующему: ?>; , который выглядит неправильно, но технически правильно.

Хотя вы можете запустить эту функцию, передав все необходимые значения цвета в переменные, вам все равно нужно открыть теги PHP, чтобы отобразить их значения в CSS. Тем не менее, это хорошее начало. Разумеется, возможность помещать значения цвета CSS в переменные является одной из многих замечательных особенностей использования препроцессора CSS.

Хотя добавление полноценного процессора Sass или LESS в вашу тему возможно, и для этого есть плагины, это слишком сложно для простой задачи преобразования нескольких переменных в шестнадцатеричные значения. Вместо этого я покажу вам, как создать простой препроцессор в вашей теме с помощью всего лишь нескольких строк кода.

Первое, что вам нужно сделать, это создать файл в вашей теме с именем customizer.css . Этот файл действительно может иметь любое расширение, но его расширение css означает, что ваш редактор кода или IDE будет обрабатывать его как файл CSS, облегчая работу с ним.

В customizer.css вы можете переформатировать этот уродливый код из предыдущего примера в следующее:

1
2
3
4
5
6
7
h1.site-title a {
    color: [site_title_color];
}
 
h3.site-description {
    color: [site_description_color];
}

Как видите, теперь вы можете писать CSS так, как если бы это был CSS. Вы просто заменяете значения, которые будут установлены в настройщике, на имя theme_mod в скобках. Эти строки будут заменены нашим препроцессором с их значением из базы данных. Самое главное, что вы используете название модов вашей темы в качестве значения замещения в необработанном CSS.

Сам препроцессор на самом деле невероятно прост, поскольку он берет содержимое вашего customizer.css и использует str_replace() PHP str_replace() для замены значений в скобках на значения из настройщика.

Вся система включает в себя один простой класс с тремя методами и одной функцией вне класса, подключенный к wp_head для вывода обработанного и оптимизированного CSS. Имейте в виду, что этот код предполагает, что все данные, которые нам нужны, хранятся в модах темы, которые используются по умолчанию для настройщика темы. Возможно, вам придется заменить get_theme_mod() на get_option() в вашем коде, в зависимости от ваших конкретных потребностей.

Этот класс использует цикл foreach в каждом методе. Если вы не знакомы с циклом foreach , я рекомендую взглянуть на мою статью о работе с циклами и массивами . Кроме того, если вы не знакомы с PHP-классами или объектно-ориентированным PHP (ООП) в целом, вам следует ознакомиться с вводным циклом Тома Макфарлина по ООП .

Для начала, в вашем functions.php или в файле, включенном в него, создайте пустой класс с именем slug_theme_customizer_output заменив «slug» уникальным slug_theme_customizer_output вашей темы. Это должно выглядеть так:

1
2
3
class Slug_Theme_Customizer_Output {
 
}

Первый метод в классе будет тем, где вы будете устанавливать моды темы, которые будете использовать, а также значения по умолчанию для каждого мода темы. Вы устанавливаете каждый из них в массиве в форме theme_mod => default . Придерживаясь тех же двух настроек, что и раньше, было бы так:

1
2
3
4
5
6
function theme_mods() {
    return array(
        ‘site_title_color’ => ‘#ff0000’,
        ‘site_description_color’ => ‘#000’
    );
}

Следующим шагом будет получение текущего значения каждого theme_mod и помещение его в массив, который мы можем использовать в нашем реальном препроцессоре. Этот метод просто получает каждое значение из theme_mods() и передает ключ в качестве первого аргумента, который является именем get_theme_mods() для get_theme_mods() при этом передавая значение по умолчанию в качестве второго аргумента, который будет возвращен, если ничего не установлено в этот мод мод. Это будет выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
12
13
function prepare_values() {
    $colors = array();
 
    // Get our theme mods and default values.
    $theme_mods = $this->theme_mods();
 
    // For each theme mod, output the value of the theme mod or the default value.
    foreach( $theme_mods as $theme_mod => $default ) {
        $colors[ $theme_mod ] = get_theme_mod( $theme_mod, $default );
    }
 
    return $colors;
}

Теперь у нас есть массив в виде 'theme_mod_name' => 'value to replace' и мы готовы обработать CSS в третьем и последнем методе этого класса.

В цикле foreach в этом методе мы используем возможность, которую PHP дает нам для обработки ключа и значения массива как отдельных переменных. Это действительно мощная функция PHP-циклов foreach которая требует небольшого планирования структуры каждого массива и делает жизнь намного проще.

Первым шагом будет использование file_get_contents() для преобразования файла customizer.css в строку и сохранения его в переменной. Так как эта функция вызовет фатальную ошибку, если не сможет найти файл, нам нужно обернуть весь код этого метода в тест, если файл вообще существует.

Обратите внимание, что в этом коде предполагается, что файл customizer.css находится в том же каталоге, что и класс, вам может потребоваться настроить структуру файла вашей темы. Вот как мы начинаем этот метод:

01
02
03
04
05
06
07
08
09
10
11
12
function process() {
    $css = »;
 
    // Modify this filename and / or location to meet your needs.
    $theme_customizer_file = trailingslashit( dirname( __FILE__ ) ) .
 
    // Make sure the file exists.
    if ( file_exists( $theme_customizer_file ) ) {
        // Get contents of the file.
        $css = file_get_contents( $theme_customizer_file );
    }
}

Как я уже говорил, весь этот метод упакован в проверку, существует ли файл. Это означает, что он вернет false если файл не загружается. Имейте это в виду, поскольку нам потребуется учесть эту возможность позже.

Теперь, когда у нас есть CSS в виде строки, нам нужно получить наши массивы значений подстановки из prepare_values() . Опять же, мы будем использовать ключ массива и переменную как отдельные переменные в цикле foreach . Для каждого theme_mod мы должны добавить скобки вокруг него, затем мы можем использовать его для замены строки подстановки в CSS на str_replace() , например так:

1
2
3
4
5
6
7
8
// Get our colors.
$colors = $this->prepare_values();
 
// Replace each color.
foreach ( $colors as $theme_mod => $color ) {
    $search = ‘[‘ .
    $css = str_replace( $search, $color, $css );
}

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

1
2
3
4
// Add style tags.
$css = ‘<style type=»text/css»>’ .
 
return $css;

Вот и весь препроцессор. Единственный оставленный шаг — вывести сам CSS. Для этого мы можем использовать функцию вне класса, которая инициализирует класс и выводит его в заголовке темы.

Эта функция выглядит так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
add_action( ‘wp_head’, ‘slug_theme_customizer_output’ );
 
function slug_theme_customizer_output() {
    // Make sure our class exists.
    if ( class_exists( ‘Slug_Theme_Customizer_Output’) ) {
        // Initialize the class and get processed css.
        $class= new Slug_Theme_Customizer_Output();
        $css = $class->process();
 
        // To be safe, make sure `process` method didn’t return false or anything other than a string.
        if ( $css && is_string( $css ) ) {
            echo $css;
        }
    }
}

Если вы помните, метод process() может вернуть false, если файл CSS не может быть загружен. Чтобы учесть эту возможность, перед повторением значения метода process() важно убедиться, что он не возвращает false и не возвращает ничего, кроме строки.

Хотя мы могли бы на этом остановиться, я бы хотел сделать вещи немного более эффективными. Эта система прекрасно работает, но она также выполняет многократную обработку, которая может включать несколько запросов к базе данных при каждой загрузке страницы. Лично я бы предпочел пропустить запуск всего класса и вместо этого просто получить одну строку из базы данных.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
add_action( ‘wp_head’, ‘slug_theme_customizer_output’ );
 
function slug_theme_customizer_output() {
    // Either set css to the transient or rebuild.
    if ( false === ( $css = get_transient( ‘slug_theme_customizer_css’ ) ) ) {
        // Make sure our class exists.
        if ( class_exists( ‘Slug_Theme_Customizer_Output’) ) {
            // Initialize the class and get processed css.
            $class= new Slug_Theme_Customizer_Output();
            $css = $class->process();
 
            // Cache css for next time.
            set_transient( ‘slug_theme_customizer_css’, $css );
        }
    }
 
    // To be safe, make sure `process` method didn’t return false or anything other than a string.
    if ( $css && is_string( $css ) ) {
        echo $css;
    }
}

Теперь, если есть значение, установленное в переходном slug_theme_customizer_css оно может быть slug_theme_customizer_css напрямую, после прохождения тех же тестов, чтобы убедиться, что оно не является false или не является строкой. Класс препроцессора не загружен, и к базе данных делается только один запрос. Если переходный процесс возвращает false , процесс запускается и значение кэшируется в следующий раз.

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

Мы можем использовать это действие, так как моды темы хранят опцию, названную для темы, с которой она связана. Например, моды темы TwentyFourteen хранятся в опции theme_mods_twentyfourteen . Вот как мы используем это действие, чтобы очистить наш переходный процесс:

01
02
03
04
05
06
07
08
09
10
11
12
/**
 * Reset the slug_theme_customizer_css transient when theme mods are updated.
 */
 
// Get current theme’s name.
$theme = get_stylesheet();
 
add_action( «update_option_theme_mods_{$theme}», ‘slug_reset_theme_customizer_css_transient’ );
 
function slug_reset_theme_customizer_css_transient() {
    delete_transient( ‘slug_theme_customizer_css’ );
}

Теперь, когда вы можете написать свой CSS, который будет обновляться, из настройщика темы с переменными, вы можете рассмотреть одну вещь — использовать один мод темы во многих местах.

Например, как насчет того, чтобы вместо установки theme_mod для каждого цвета в теме и вызывать перегрузку опций, как насчет опций для основного цвета, вторичного цвета и цвета акцента?

Система, которую я показал вам, как создавать здесь, работает только с параметрами цвета, что делает ее действительно полезной только для таких свойств CSS, как color , background-color , border-color и т. Д. Вы можете расширить ее, чтобы она была полезна для других типов свойства.

Просто помните, чтобы не изобретать Sass или LESS, суть всего этого состояла в том, чтобы избежать вздутия вашей темы полной реализацией PHP Sass или LESS, которые уже доступны в виде плагинов.