В процессе разработки по WordPress есть куча неоднозначных и не очевидных моментов. Возможно API WordPress скрывает намного больше таких «странностей» назовем это так и некоторые из них еще боле плохи чем то о чем я расскажу здесь, но по моему мнению рассказать нужно именно о том что я опишу ниже.
Для начала весь список :
- register_setting
- wp-db update
- get_post_statuses
- register_post_type ( public, show_ui , show_in_menu)
- get_post_meta/update_post_meta
Если в вашем коде встречается одна или несколько функций из этого списка значит есть повод не на долго но все же задуматься.
register_setting
Казалось бы все очевидно функция которая предназначена API настроек которое всего то служит для создания страницы опций , сугубо утилитарная вещь , но все не так просто как может показаться на первый взгляд.
register_setting( $option_group, $option_name, $sanitize_callback );
$option_group — строка, обязательный аргумент содержит название группы, к которой будет принадлежать опция. то самое название которое должно совпадать с названием группы в функции settings_fields(). Как раз этот первый аргумент запутывает нас больше всего, далее я расскажу почему
$option_name — строка, обязательный аргумент содержит название опции, которая будет сохраняться в БД. Здесь все очевидно.
$sanitize_callback (строка/массив) Название колбека который должен обрабатывать значение опции перед сохранением. И дьявол кроется именно в нем.
Суть проблемы.
В процессе создания страницы опций я как разработчик внимательно прочитавший Codex WordPress интуитивно понимаю что API опций как и все прочие созданы интуитивно понятными, названия функций осмысленные и выбраны не случайно (хотя по видимости не везде, как выяснилось) и register_setting так называется потому что работает исключительно на странице опций с полями зарегистрированными с помощь settings_fields() что кажется логичным так как аргументы в этих функциях должны совпадать о чем сказано в документации.
Но если разобраться глубже и посмотреть в код register_setting() можно увидеть что это не совсем так sanitize_option() , внутри этой функции можно найти фильтр:
add_filter( "sanitize_option_{$option_name}", $sanitize_callback );
это кусочек кода который применяет наш колбек из второго аргумента register_setting() для результата перед сохранением опции и все бы ничего если бы функции add_option() и updtae_option() точно так же не применяли этот фильтр для своего результата своей работы.
Складывается ситуация когда разработчик создал некий функционал успешно и бесперебойно работающий с опциями после решил сделать некоторый интерфейс для редактирования опций в процессе использовал скажем функции settings_fields(), do_settings_sections(), do_settings_fields(), add_settings_error(), get_settings_errors() и для безопасности или удобства добавил в register_setting() колбек проверяющий пользовательский код после чего написанные до этого момента и работающие безупречно куски кода содержащие update_option(); стали вести себя странно, особенно легко представить случай когда update_option() два раза применит колбек функцию так как разработчик может не знать об особенностях работы с register_setting() и применять свой колбек отдельно при вызове update_option().
Я не хочу сказать что register_setting работает как то совсем плохо, но есть вопросы к её именованию почему бы не назвать её скажем register_option и не вынести за пределы Settings API или не описать явно в документации то что её колбек напрямую влияет на результат update_option() и add_option() это могло бы здорово сэкономить нервов разработчикам.
<h2>Глобальный объект wpdb</h2> Сразу поясню что неясность возникает из-за кэширование объектов, которое является очень полезной и вопросов к нему нет. Но есть не очевидные сайд эффекты, например если вам пришло в голову обновить заголовок поста и после получить его из базы во время выполнения того же запроса, вы это сделать не сможете: [php]global $wpdb; $post_id = 1; //id поста $update['post_title'] = 'NEW'; //новый заголовок $wpdb->update($wpdb->posts, $update, array('ID' =>$post_id), '%s'); $result = get_post($post_id); // пытаемся получить заголовок равный //NEW d($result); // смотрим результат и видим что заголовок не изменился на NEW
что делает функция d() я описывал в одном из прошлых постов про Kint debugger
Так вот пример выше никогда не установит переменной $result содержимое «NEW» при первой итерации/запуске потому как каждый раз заголовок поста будет выводиться из кеша объектов.
Эта самый очевидный пункт списка но многим он может быть не очевиден.
register_post_type
Эта функция регистрирует новый тип поста. Здесь неочевидность заключается в аргументах:
public — аргумент определяет нужно ли показать пользовательский интерфейс, возможные значения true/false;
show_ui — Определяет нужно ли выводить тип записи в администраторском меню. Если true — показывается, если false то не показывать , по умолчанию значение берется из аргумента public.
show_in_menu — false — не показывать в администраторском меню , true — показывать как меню первого уровня, так же можно задать в качестве аргумента slug, что бы меню отображалось как элемент меню первого уровня.
Тут как напрашивается вывод что у любого элемента значение false скроет пункт из админ меню причем аргументы перекрывают друг друга, значения по умолчанию так же перекрываются в зависимости от прочих соседних аргументах, так же очевидно что можно сделать при помощи show_in_menu, ну кроме как скрыть админ меню и при каких значениях соседних элементов.
Если вы уже запутались то, могу лишь посоветовать экспериментировать дабы понять такую скрытую «логику «. Объяснить понятно, я это не могу даже понимая как эти аргументы работают.
get_post_meta/update_post_meta
что может быть проще произвольных мета полей WordPress, но поверьте даже здесь могут подстерегать неожиданности .
Аргументы функции get_post_meta:
$post_id — ID поста, произвольные поля (или поле) которого нужно получить.
$key — Строка, имя произвольного поля значение или значения которого или которых нужно получить
$single Аргумент определяет нужно ли получит единственное значение произвольного поля либо же получить все значения произвольных полей имеющих имя равное $key. Что бы получит единственное значения аргумент нужно задать равным true, а что бы получить массив всех значений необходимо установить false. по умолчанию false.
И да в WordPress Codex написано что если произвольное поле начинается с «_» то есть с нижнего подчеркивания то поле не будет отображаться в админке в мета боксе произвольных полей , сделано это что бы иметь возможность срыть поля с системными метаданными.
Как видно на скриншоте полей с нижним подчеркиванием не отображается, но поверьте они есть в посте с которого был этот срин снят, просто поверьте.
update_post_meta — обновляет существующие поле или создает новое если к моменту обновления поле еще не существует.
$post_id ID поста произвольные поля которого нужно обновить или создать.
$meta_key Имя произвольного поля которое нужно обновить или создать.
$meta_value Новое, значение произвольного поля, которое нужно обновить/создать. Может быть строкой либо массивом .
$prev_value Значение произвольного поля, которое мы хотим обновить или добавить. Тип данных строка. Ну то есть если условно сравнить с массивом в php $meta_key это ключ массива, а $meta_value это его значение. Если мы хотим обновить не все элементы ( как бы массива ) $meta_key, то нужно указать элемент с каким значением мы хотим обновить.
P.S. Да я знаю что в моем примере ключи $meta_key могут быть не уникальными, но пусть будет так, хоть это и не очень похоже на массивы — сделаем такое допущение.
Функция get_post_meta может вернуть как единственное значение так и массив значение это понятная часть, повествования, но даже здесь многие могут запутаться.
Есть еще один непонятный момент как говорилось выше в админке не выводятся поля начинающиеся с «_», но это только часть правды при добавлении полей из админки нет никаких подводных камней, но если мы добавляем поле при помощи функции update_post_meta то его значением как я уже говорил может быть и массив. Соответственно массив показать в интерфейсе админки затруднительно, поэтому такое поле так же не будет отображаться в мета боксе, даже если оно не начинается с нижнего подчеркивания. Так же обратное утверждение не всегда верно если get_post_meta вернул массив не всегда значит то что мета поля не видны в админке возможно просто у get_post_meta последний аргумент равен false и в админке отображается больше одного поля.
Так же если мы обновляем функцией update_post_meta мета поле значением которого является массив и таких полей больше одного то не получится использовать $prev_value в этой функции так как аргумент должен иметь тип string как уже говорилось выше.
Благодарю но…у тебя хронический дефицит знаков препинания? =)
Бывает не отрицаю