Как работают хуки в wordpress (фильтры и события)

Гибридные или сложные

Но бокс – это не только одиночные удары. Существуют ещё и комбинированные. К этой группе относятся оверхенд и даункот. Первый совмещает в себе умелую комбинацию из хука и кросса. Двигаться во время оверхенда нужно по дуге, а его направление сверху вниз. Наносить можно на любой дистанции, поскольку он совмещает в себе разные виды ударов, которые эффективны как при ближнем бое, так и при боксировании на большом расстоянии.


Минус исполнения — атакующий боксёр остаётся открытым, т. е. незащищённым. Тем самым возрастает риск нарваться на «ответочку».

Даункот используется достаточно редко. Причина – сложное исполнение комбинации. Наносить его нужно кулаком, согнув бьющую руку в локте. Траектория удара — сверху сбоку. Минус в том, что спортсмен, наносящий удар даункот, может получить предупреждение от рефери «за нанесение удара открытой перчаткой» если кулак будет выставлен неправильно. Дабы избежать такой ситуации, кулак должен располагаться ладонью вниз.

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

RTFM

Что такое хук (hook — крючок, англ.)? Это механизм, позволяющий отследить некое событие в операционной системе. Было оно разработано дяденьками из Microsoft с самыми благими намерениями — позволить программисту более эффективно решать свои задачи путем установки контроля над событиями клавиатуры, мыши и многого другого. Реализовался он при помощи всем известных функций: SetWindowsHook(Ex), UnhookWindowsHook(Ex) и CallNextHook(Ex).

Хук служит для перехвата неких событий до того, как они дойдут до приложения. Эта функция может реагировать на события и, в некоторых случаях, изменять или отменять их. Функции, получающие уведомления о событиях, называются «фильтрующими функ циями» и различаются по типам перехватываемых ими событий. Пример — фильтру ющая функция для перехвата всех событий мыши или клавиатуры. Чтобы Windows смогла вызывать функцию-фильтр, эта функция должна быть установлена, то есть, прикреплена к хуку (например, к клавиатурному). Прикрепление одной или нескольких фильтрующих функций к какомунибудь хуку называется установкой хука. Если к одному хуку прикреплено несколько фильтрующих функций, Windows реализует очередь функций, причем функция, прикрепленная последней, оказывается в начале очереди, а самая первая функция — в ее конце.

Со временем благородное понятие хука извратилось, причиной чего стали действия вирусописателей и малварщиков. Первые вирусы были, как бы это сказать… наивными, наверное. Они представляли собой отдельный exe-файл, напрямую вызывающий нужные функции системы. Шло время и антивирусы, которые появились чуть позже и вдруг стали коммерческими, довольно быстро научились ловить вирусы по сигнатурам путем простого сканирования оперативной памяти или дискового пространства.

И вот тут-то, в пылу извечной борьбы между писателями вирусов и их «ловцами» встал один-единственный вопрос, который стоит на повестке дня до сих пор и будет стоять в ближайшем необозримом будущем — это вопрос выживания в операционной системе. Причем он также актуален и для антивирусов, ведь для хорошего системного программиста, пишущего вирусы/ руткиты, вынести процесс антивируса из системы — не слишком сложная задача.

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

«А как же SetWindowsHook?» — спросишь ты меня. «Прошлый век», — отвечу я. Использовать их давно уже не кошерно.

Назначение Хуков WordPress

Основное назначение хуков – автоматический запуск функции. Кроме того, этот метод также даёт возможность изменять, расширять или ограничивать функциональность темы или плагина.

Пример хука в WordPress:

function mytheme_enqueue_script() 
{wp_enqueue_script( 'my-custom-js', 'custom.js', false );}
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_script' );

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

Хуки часто используются при создании компонентов плагина приложения. Они применяются не только в системах управления контентом (CMS), таких как WordPress, но и на сайтах электронной коммерции (англ) и на корпоративных интранет-сайтах.

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

3.12.3.4 Объявление переменной состояния

В классе мы инициализируем состояние счетчика значением , устанавливая равным в конструкторе:

Код

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

Код

Что делает вызов ? Он объявляет «переменную состояния». Это способ «сохранять» некоторые значения между вызовами функций. Наша переменная называется , но мы можем назвать ее как угодно, например, . — это новый способ использовать точно такие же возможности, которые предоставляет в классе. Обычно переменные теряются при выходе из функции, но переменные состояния сохраняются React-ом.

Что мы передаем в качестве аргумента? Единственный аргумент для хука — это начальное состояние. В отличие от классов, состояние не обязательно должно быть объектом. Мы можем сохранять число или строку, если это все, что нам нужно. В нашем примере мы хотим хранить просто число, показывающее сколько раз пользователь кликал, поэтому передаем в качестве начального состояния для нашей переменной. (Если бы мы хотели сохранить два разных значения в состоянии, мы бы вызвали дважды.)

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

Теперь, когда мы знаем, что делает хук , наш пример должен иметь больше смысла:

Код

Мы объявляем переменную состояния с именем и устанавливаем ее равной . React запоминает ее текущее значение между повторными отрисовками и предоставляет самое последнее значение для нашей функции. Если мы хотим обновить текущее значение счетчика, мы можем вызвать .

Как правильно бить прямой удар в боксе

Как правильно бить прямой удар в боксе? Многое зависит от того, какой его вид реализуется. Выше уже были описаны некоторые техники.

Боксёры отрабатывают и реализуют разные приёмы. А как называются прямые удары в боксе – джебы и кроссы.

Первые распространены довольно широко. Соперник поражается передней рукой. В момент атаки она полностью выпрямлена. Позиция кулака по отношению к поверхности параллельна. Во время штурма боец вышагивает вперёд. Так серьёзно развивается мощь его нападения. Не атакующий кулак в этот момент защищает лицо бойца. А его локоть обороняет солнечное сплетение. В этих условиях оппонент постоянно напряжён, расходует много энергии. Однако джеб не отличается огромной мощью. Его цель – выматывать соперника и держать его на необходимой дистанции.


Вторые тоже используются часто. Они характеризуются высокой точностью и серьёзной силой. Инструмент реализации кросса – дальняя прямая рука. Эти атаки можно осуществлять в большом количестве за небольшой промежуток времени. Этот удар в боксе считается коротким прямым. Причины:

  1. Во время исполнения локоть разгибается весь.
  2. Дистанция дальней руки от цели короткая. И цель (голова или корпус) поражается стремительно.

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

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

Этот пример показывает, как подключить файл js скрипта, если активирован виджет «Календарь». По аналогии можно подключить скрипты для любого активного виджета.

## Подключение скрипта, если есть активный виджет
## ID базовый виджетов WP смотрите в описании http://wp-kama.ru/function/the_widget
add_action('wp_enqueue_scripts', 'add_calendar_widget_scripts');
function add_my_widget_scripts(){
	if( ! is_active_widget( false, false, 'calendar' ) ) return; // выходим если виджет не активен

	$theme_url = get_stylesheet_directory_uri();

	wp_enqueue_script('my_widget_script', $theme_url .'/calendar_widget_script.js' );
}

Подробнее читайте описание функции is_active_widget().

Данные на каждый виджет WordPress, смотрите в описании функции the_widget()

Подключение скрипта при активном виджете в коде самого виджета

Этот код пригодится для разработчиков, которые создают виджет. Если у виджета есть свой отдельный код скрипта или стили. То разумнее подключить их только если виджет активирован.

// Класс виджета
class My_Widget extends WP_Widget {

	function __construct() {
		// Запускаем родительский класс
		parent::__construct(
			'идентификатор_виджета', // ID виджета, если не указать (оставить ''), то ID будет равен названию класса в нижнем регистре: my_widget
			'Название виджета',
			array('description' => 'Описание виджета'),
		);

		// скрипты/стили виджета, только если он активен
		if ( is_active_widget( false, false, $this->id_base ) || is_customize_preview() ) {
			add_action('wp_enqueue_scripts', array( $this, 'add_my_widget_scripts' ));
			add_action('wp_head', array( $this, 'add_my_widget_style' ) );
		}
	}

	// Вывод виджета
	function widget( $args, $instance ){
		$title = apply_filters( 'widget_title', $instance );

		echo $args;

		if( $title )
			echo $args . $title . $args;

		echo 'Привет!';

		echo $args;
	}

	// Сохранение настроек виджета (очистка)
	function update( $new_instance, $old_instance ) {
	}

	// html форма настроек виджета в Админ-панели
	function form( $instance ) {
	}

	// скрипт виджета
	function add_my_widget_scripts() {
		// фильтр чтобы можно было отключить скрипты
		if( ! apply_filters( 'show_my_widget_script', true, $this->id_base ) )
			return;

		$theme_url = get_stylesheet_directory_uri();

		wp_enqueue_script('my_widget_script', $theme_url .'/my_widget_script.js' );
	}

	// стили виджета
	function add_my_widget_style() {
		// фильтр чтобы можно было отключить стили
		if( ! apply_filters( 'show_my_widget_style', true, $this->id_base ) )
			return;
		?>
		<style type="text/css">
			.my_widget a{ display:inline; }
		</style>
		<?php
	}
}

3.12.3.7 Резюме

Теперь давайте резюмируем то, что мы узнали, построчно и проверим наше понимание.

Код

  • Строка 1: мы импортируем хук из React. Это позволяет нам сохранять локальное состояние в компоненте-функции.

  • Строка 4: внутри компонента мы объявляем новую переменную состояния, вызывая хук . Он возвращает пару значений, которым мы даем имена. Мы называем нашу переменную , потому что она содержит количество нажатий кнопки. Мы инициализируем её нулем, передавая как единственный аргумент . Второй возвращаемый элемент сам по себе является функцией и позволяет нам обновлять счетчик , поэтому мы назовем его .

  • Строка 9: когда пользователь кликает, мы вызываем с новым значением. Затем React повторно выполнит отрисовку компонента , передав ему новое значение .

Поначалу это может показаться слишком сложным. Но не торопитесь! Если вы запутались в нашем объяснении, снова посмотрите на приведенный выше код и попробуйте прочитать его сверху вниз. Мы обещаем, что как только вы попытаетесь «забыть», как работает состояние в классах, и посмотрите на этот код свежим взглядом, его смысл станет полностью понятен.

3.12.3.7.1 Подсказка: что означают квадратные скобки?

Вы могли заметить квадратные скобки, когда мы объявляем переменную состояния:

Код

Имена слева не являются частью React API. Вы можете назначить свои собственные имена переменным состояния:

Код

Данный синтаксис JavaScript называется «деструктуризация массива». Он означает, что мы создаем две новые переменные и , где во устанавливается первое значение, возвращаемое , а в второе. Это эквивалентно следующему коду:

Код

Когда мы объявляем переменную состояния с помощью , он возвращает пару — массив с двумя элементами. Первый элемент — это текущее значение, а второй — функция, которая позволяет нам его обновлять. Использование и для доступа к ним немного сбивает с толку, поскольку они имеют конкретное смысловое значение. Вот почему вместо этого мы используем деструктуризацию массива.

Внимание!

Вам может быть любопытно, как React узнает, какому компоненту соответствует , ведь мы не передаем React никакой информации вроде . Мы ответим на этот и многие другие вопросы в разделе FAQ по хукам.

3.12.3.7.1 Подсказка: использование множества переменных состояния

Объявление переменных состояния как пары также удобно потому, что позволяет нам давать им разные имена, если мы хотим использовать несколько переменных:

Код

В приведенном компоненте у нас есть , и в качестве локальных переменных, и мы можем обновлять их индивидуально:

Код

Вам не обязательно использовать много переменных состояния. Переменные состояния могут отлично хранить объекты и массивы, так что вы можете группировать связанные данные вместе. Однако, в отличие от в классе, обновление переменной состояния всегда заменяет ее, а не объединяет(мержит).

Мы даем больше рекомендаций по разбиению независимых переменных состояния в FAQ.

Свинг

Наносится прямой рукой с предварительным замахом. Исполняется всем корпусом. Во время нанесения нужно делать толчок ногой, и развернуть корпус. Чтобы его реализовать, нужно сделать отвлекающий манёвр, который заставит оппонента раскрыться. Свинг наносится с правой стороны. Выполнить его – быть в одном шаге от победы, поскольку свинг обладает огромной силой.

Существует 2 вида свинга: английский и американский. Отличаются они манерой держать кулак. Первый подразумевает горизонтальное расположение кулака, второй вертикальное. По направлению и исполнению свинг бывает трёх типов:

  • левой рукой в голову и корпус;
  • левой рукой в корпус с отклонением;
  • правой рукой в голову и корпус.

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

📌 Хук состояния

Рассмотрим пример, в котором рендерится счётчик. Если вы нажмёте на кнопку, значение счётчика будет инкрементировано.

В этом примере,  — это хук (определение хука дано ниже). Мы вызываем его, чтобы наделить наш функциональный компонент внутренним состоянием. React будет хранить это состояние между рендерами. Вызов возвращает две вещи: текущее значение состояния и функцию для его обновления. Эту функцию можно использовать где угодно, например, в обработчике событий. Она схожа с  в классах, но не сливает новое и старое состояние вместе. Сравнение хука и  приводится на странице Использование хука состояния.

Единственный аргумент  — это начальное состояние. В примере выше — это , так как наш счётчик начинается с нуля. Заметьте, что в отличие от , в нашем случае состояние может, но не обязано, быть объектом. Исходное значение аргумента используется только при первом рендере.

Объявление нескольких переменных состояния

Хук состояния можно использовать в компоненте более одного раза.

Синтаксис позволяет нам по-разному называть переменные состояния, которые мы объявляем при вызове . Так как имён этих переменных нет в API , React предполагает, что если вы вызываете много раз, вы делаете это в одинаковой последовательности при каждом рендере. Мы расскажем, почему это работает и когда это целесообразно, немного позже.

Что же такое хук?

Хуки — это функции, с помощью которых вы можете «подцепиться» к состоянию и методам жизненного цикла React из функциональных компонентов. Хуки не работают внутри классов — они дают вам возможность использовать React без классов. (Мы  сразу же переписывать существующие компоненты, но при желании, вы можете начать использовать хуки в своих новых компонентах.)

React содержит несколько встроенных хуков, таких как . Вы также можете создавать собственные хуки, чтобы повторно использовать их в других своих компонентах. Давайте для начала рассмотрим встроенные хуки.

Что имеем?

Проще всего установить хук в системе путем создания так называемой прокси-функции. Иначе говоря, тебе надо определиться, какую функцию ты перехватываешь, и найти адрес ее вызова. Для этого обычно используется функция GetProcAddress примерно вот так: GetProcAddress(GetModuleHandle(«ntdll.dll»), «CsrNewThread»).

Однако просвещенные знают, что она практически всегда перехватывается аверами, и для нахождения адреса функции используют парсинг таблицы импорта той или иной библиотеки, обычно ntdll.dll, kernel32.dll (kernelbase.dll в Windows7) или advapi32.dll.

Далее тебе нужно создать свою прокси-функцию, точь-в-точь повторяющую вызываемую примерно вот таким образом:

После этого следует перезаписать адрес вызова OriginalFunction на свой — то есть, на MyNewFunction.


Теперь, если кто-либо захочет вызвать для исполнения OriginalFunction, сначала будет вызвана твоя прокси-функция MyNewFunction, которая уже потом передаст управление на оригинальный адрес. Вот таким вот нехитрым образом действуют, наверное, 8 хуков из 10. Этот способ удобен лишь своей простотой, но при этом представляет собой ужасное палево для аверов. Как? Поразмысли сам — все, что аверу нужно, это сравнить прежний, «законный», адрес функции с тем, что есть на самом деле. Если они отличаются — бьем тревогу. Кстати, встает и следующий вопрос: откуда взять этот самый адрес оригинальной функции? Тут особо гадать не надо — его считывают с нужного файла на диске. Этот подход основывается на том предположении, что вирус не будет патчить таблицу экспорта файла, лежащего на диске, ограничившись патчем виртуальной памяти.

Итак, едем дальше. Как я уже говорил, использование хука в виде прокси-функции хоть и удобная вещь, но, во-первых, палевная, а во-вторых, подходит лишь для начинающих. То есть не для тебя :). Самый распространенный вид хука — это сплайсинг. Уверен, ты не раз слышал это слово. В нашем случае это запись на начало функции пятибайтовой последовательности, которая представляет собой команду jmp по адресу обработчика перехвата. Здесь первый байт — опкод jmp, оставшиеся четыре байта — адрес твоей функции.

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

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

#3. Программируем обработчик

Обработчик события (или в терминах Cotonti — хук) это PHP файл в папке расширения, имя которого согласуется с именем хука. Это не жесткое требование, но рекомендуемое к выполнению правило, как пример файл myext.page.edit.update.done.php в котором содержится код обработчика хука page.edit.update.done.

Примерный шаблон файла-обработчика представлен ниже:

<?php
/* ====================

Hooks=page.tags
Tags=page.tpl:{PAGE_MYEXT_TAG1},{PAGE_MYEXT_TAG2}
Order=10

==================== */

defined('COT_CODE') or die('Wrong URL');

// Hook handler code goes here  

Для начала рассмотрим заголовок файла (это блок которй заключен внутри специальных маркеров BEGIN_COT_EXT и END_COT_EXT). Главным и единственным обязательным параметром является ключ Hooks, который задает список хуков обрабатываемых данным файлом. Один файл может быть назначен обработчиком нескольких хуков. В таком случае в ключе задается список хуков, разделенных запятыми. Остальные настройки (ключи) опциональны и могут быть опущены.

Ключ Tags используется для описания дополнительных тегов, назначаемых в процессе обработки. Этот ключ используется в качестве информационного — для отображения в админ-панеле списка дополнительных тегов и имен шаблонов в которых они используются.

На один хук различными расширениями может быть назначено несколько обработчиков. В таких случаях, иногда, полезно иметь возможность задать порядок вызова обработчиков. Для этой цели используется ключ Order, определяющий порядок вызова обработчика. Число определяющее порядок обычно находится в диапазоне 1-99. В первую оччередь выполняются обработчики чей порядковый номер меньше, т.е. в порядке возрастания номеров. Если параметр Order не задан, обработчику будет присвоен порядковый номер по умолчанию — 10.

Что же мы можем сделать используя обработчики? Да почти все что угодно! Вот несколько простеньких примеров:

  • Делать запросы в БД для извлечения и изменения данных;
  • Изменять текущие значения и объекты;
  • Назначать теги для шаблонов и обрабатывать определенные блоки в шаблонах.

Важная вещь, о которой стоит упомянуть это область видимости. Исторически Cotonti использует процедурный стиль выполнения скрипта, и большая часть хуков определена в глобальной области видимости. Поэтому в большинстве случаев вам не надо предпринимать дополнительных усилий. Однако есть и такие хуки, которые вызываются внутри функций, в таких случаях вам надо позаботится о доступе к глобальным переменным внутри этой функции, используя ключевое слово . Наиболее часто используемые переменные это: $cfg, $usr, $db, $id, $strucutre, $t. Сейчас не будем рассматривать их назначение, т.к. это тема отдельной статьи.

Обратите внимание, что с версии 0.9.15 все наиболее востребованные глобальные переменные ($cfg, $usr, $db, $id, $strucutre и пр.) доступны через специальный «фасад»-класс . Таким образом нет необходимости использовать явное указание переменных в списке , а можно обратиться к ним напрямую через свойство объекта:  (например)

Полный список переменных доступных через «фасад» следующий: $cache, $cfg, $cot_extrafields, $db, $db_x, $env, $L, $out, $R, $structure, $sys, $usr.

Основной совет начинающим разработчикам расширений для Cotonti —начните с изучения кода. Если вы хотите знать как писать плагины — посмотрите на код некоторых из них (среди них есть очень простые и понятные даже для начинающих). Если вы хотите знать как изменить поведение той или иной части — найдите код, который за нее отвечает, посмотрите где определены ближайшие точки вызова хуков и проанализируйте что происходит в этом куске кода. Cotonti написан в простой и понятной форме и код исполняется достаточно линейно, поэтому можно быстро в нем разобраться. Как только вы разберете основной алгоритм выполнения, вы с легкостью сможете менять его. Для написания более сложных плагинов вам потребуется иметь дело с несколькими хуками и обработчиками, но это уже будет не намного сложней чем начать..

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

Какие бывают хуки

Ловушки (hook) могут быть режима пользователя (usermode) и режима ядра (kernelmode). Установка хуков режима пользователя сводится к методу сплайсинга и методу правки таблиц IAT. Ограничения этих методов очевидны: перехватить можно только userspace API, а вот до функций с префиксом Zw*, Ki* и прочих «ядерных» из режима пользователя дотянуться нельзя.

Установка хуков режима ядра позволяет менять любую информацию, которой оперирует Windows на самом низком уровне. Для перехватов подобного типа необходимо модифицировать таблицы SSDT/IDT либо менять само тело функции (kernel patch). Надо сказать, что в Windows на архитектуре x64 ядро контролирует свою целостность при помощи механизма KPP (Kernel Patch Protection), который является частью PatchGuard и просто так подобные манипуляции с системными таблицами сделать не позволит.

Как правильно подключать внешние CSS и JS файлы в тему WordPress

1. Регистрируем наши css и js файлы

Для этого в файле functions.php. Например, мне нужно подключить файл bootstrap_grid.css.

Для этого в function.php я использую функцию Php wp_register_style, которая может получать 5 параметров:

wp_register_style( $handle, $src, $deps, $ver, $media )

Два обязательных параметра

$handle(строка)


Это название подключаемого файла (например, style, bootstrap, responsive). Оно должно быть уникальным

Это важно

$src(строка) Адрес к подключаемому файлу стилей. Например, http://site.ru/css/style.css.

Советую указывать относительный адрес. То есть, в случае с темой —

get_template_directory_uri() . '/css/bootstrap_grid.css'

Необязательные параметры

$deps(массив)

Массив идентификаторов других стилей, от которых зависит подключаемый файл стилей. Указанные тут стили, будут подключены до текущего.По умолчанию: array()

$ver(строка/логический)

Указания версии файла. Версия будет добавлена в конец ссылки на файл: ?ver=3.5.1.

По умолчанию: false

$media(строка)

Устанавливается значение атрибута media. media указывает тип устройства для которого будет работать текущий стиль. Может быть:

all screen handheld print

В моем случае я использую только пару обязательных параметров

  1. Имя (bootstrap_grid)
  2. Адрес (get_template_directory_uri() . ‘/css/bootstrap_grid.css’)

Итого получается так

wp_register_style( 'bootstrap_grid', get_template_directory_uri() . '/css/bootstrap_grid.css' );

2. Ставим в очередь на загрузку

Функция wp_enqueue_style необходима как раз для того, чтобы поставить наши стили в очередь на загрузку, она принимает такие же параметры как и функция wp_register_style

<?php wp_enqueue_style( $handle, $src, $deps, $ver, $media ) ?>

В нашем случае выйдет так

wp_register_style( 'bootstrap_grid', get_template_directory_uri() . '/css/bootstrap_grid.css' );
wp_enqueue_style( 'bootstrap_grid' );

3. Запускаем наш файл стилей

Для этого наш нужно использовать функцию add_action.

Я не буду расписывать все ее возможные параметры. Нам достаточно передать дав параметра

add_action( 'wp_enqueue_scripts', 'bootstrap_grid' );

Мы используем wp_enqueue_scripts как для подключения скриптов, так и для подключения стилей!

P.S. Мой совет

Я рекомендую под подключение css и js создавать отдельные функции и вызывать их по мере необходимости.

Например, я создал функцию all_css, где зарегистрировал и поставил в очередь все свои css-файлы. И, затем, ее вызвал.

function all_css() {
	
	wp_register_style( 'bootstrap_grid', get_template_directory_uri() . '/css/bootstrap_grid.css' );
	wp_enqueue_style( 'bootstrap_grid' );

	wp_register_style( 'blog', get_template_directory_uri() . '/css/blog.css' );
	wp_enqueue_style( 'blog' );

	wp_register_style( 'style', get_template_directory_uri() . '/css/style.css' );
	wp_enqueue_style( 'style' );

}
add_action( 'wp_enqueue_scripts', 'all_css' );

С этим читают