Исправляем: PHP Fatal error: Call to undefined function wp_get_current_user() на мультисайте
Интересный баг обнаружил при работе дополнения на мультисайте WordPress. Здесь расскажу о нем, его не очевидном выявлении и это поможет вам избежать подобных промашек.
Предыстория:
Вначале один пользователь сообщил мне что активировав мое дополнение для WordPress плагина WP-Recall он не может перейти в консоль управления мультисайтом (Управление сетью->Консоль)
Вот сюда:
Ок,
"Какую ошибку выдает на момент перехода? Что в Error.log сервера?"
- ответ был такой:
PHP Fatal error: Uncaught Error: Call to undefined function wp_get_current_user() in our-site.ru/wp-includes/capabilities.php:598
Самая засада в том, что мое дополнение не использует функцию wp_get_current_user. Больше никаких подробностей не сообщалось.
Я свои дополнения не тестировал в работе режима мультисайта и не заявляю о его поддержке (потому что малый процент использование его только лишь добавит мне проблем и траты времени на его тестирование и отладку). Поэтому не придал проблеме должного внимания. Но интересное пошло потом - еще один пользователь сообщил мне о проблеме с 2-мя моими дополнениями. Это было накануне новогодних праздников. Так вот после них я и решил глянуть - в чем проблема. Один репорт - случайность, два - закономерность, а три - это уже проблема. Проблемы должны решаться. Что я и сделал вчера.
Поиск виновного:
Установил на поддомене чистый вордпресс, активировал на нем режим мультисайта, взяв дефолтные настройки сети (каждый новый сайт в подкаталоге).
Активировал проблемный доп и перешел по скрину выше в управление мультисайтом. Белый экран.
Полез в логи и вот что увидел:
PHP Fatal error: Uncaught Error: Call to undefined function wp_get_current_user() in .otshelnik-fm.ru/wp-includes/capabilities.php:598
Stack trace:
# 0 .otshelnik-fm.ru/wp-admin/network/settings.php(16): current_user_can('manage_network_...')
# 1 .otshelnik-fm.ru/wp-content/wp-recall/add-on/hello-private-message/index.php(3): require_once('...')
# 2 .otshelnik-fm.ru/wp-content/plugins/wp-recall/functions/addons.php(96): include_once('...')
# 3 .otshelnik-fm.ru/wp-content/plugins/wp-recall/wp-recall.php(400): rcl_include_addon('...', 'hello-private-m...')
# 4 .otshelnik-fm.ru/wp-content/plugins/wp-recall/wp-recall.php(354): WP_Recall->include_addon('hello-private-m...'
# 5 .otshelnik-fm.ru/wp-content/plugins/wp-recall/wp-recall.php(181): WP_Recall->include_addons()
# 6 .otshelnik-fm.ru/wp-includes/capabilities.php on line 598
wp_get_current_user - эту функцию мой доп не использует, но по стеку видно что add-on/hello-private-message/index.php(3)
- в 3-й строке доп подключает файл. Но php скрипт не обрывается, а выполняется дальше. Стек трейс мой доп упомянул - значит косвенно он участвует в падении.
Смотрим, что в 3-й строке:
require_once('settings.php');
- и всё!
WTF? Почему подключая файл settings.php, который лежит в корне дополнения, я получаю белый экран? Я закомментировал эту строчку и смог войти в панель управления мультисайтом.
Вернул как было.
Я еще был далек от понимания. В файле settings.php - настройки для админки, но там нет вызова этой функции. Стер весь файл settings.php - он пустой. И снова получаю белый экран с этой же ошибкой.
Тут я понимаю что стек трейс я читаю неверно. Что после подключения settings.php файла я оказываюсь выше по стеку:
/wp-admin/network/settings.php(16): current_user_can('manage_network_...')
а урл, который в админке с белым экраном, такой:
.otshelnik-fm.ru/wp-admin/network/
- и тут пришло озарение: что путь подключения, функция require_once, берет не от корня моего дополнения, а от урл моего нахождения /wp-admin/network/settings.php(16)
- вот он settings.php и подключается. Только с другого пути. Перечитал описание функций require_once и require и include и башка вскипела.
Константы __DIR__ и __FILE__ выдают мне пути до моего дополнения.
Я переименовал файл в корне моего дополнения на sssettings.php и исправил в 3й строке подключение к нему на новое имя. Белый экран пропал. Я попал в консоль управления мультисайтом.
Решение проблемы:
Решений несколько:
1. Как вариант - не иметь в корне дополнения (или вашего плагина) файла settings.php и вообще таких имен:
2. Или перенести в подпапку inc свой файл settings.php (подозреваю что имя подпапки не должно совпадать с именем подпапки по вышеуказанному пути - не дай боже второй раз совпадение будет)
3. Подключать файл указав полный путь до дополнения:
require_once rcl_addon_path(__FILE__).'settings.php';
- функция wp-recall - содержит полный путь до вашего дополнения на сервере. Можете и ВП аналогичные функции использовать
4. Вводить проверку:
if( is_admin() && !is_network_admin() ){
require_once 'settings.php';
}
- мы проверяем что мы в админке, но не на странице управления мультисайтом.
Выводы:
Не все очевидно с багами которые нам встречаются. Мультисайтовая сборка доставляет нам еще один опыт. Виновен ли php - или сам мультисайт? У меня прозрение не наступило - сказать не могу. Но мы получили такой опыт.
Гугл не давал мне результатов кроме одного. Теперь стоит запомнить эту ошибку и внимательнее смотреть к репортам пользователей. Возможно одного пользователя я потерял. Но второй меня заставил все таки пошевелиться и отнестись внимательнее к проблеме. Входных данных конечно было мало и это возможно остановило меня при первом репорте.
Дополнения я свои исправлю. Но не буду утверждать что я поддерживаю работу в режиме мультисайта - тестировать еще одну сущность, да крайне редкую не буду. Только по факту обращения с проблемами.
upd: подобную проблему обнаружил подключая файл из корня: require_once 'setup.php';
- решение такое же, как в заметке выше.
Ты наверное единственный кто решил потратить свое время и описать эту проблему, я времени на это так и не нашел, хотя тоже ее выявлял. По своему опыту могу добавить, что также крайне не рекомендуется иметь в своем дополнении/плагине файл options.php - будут проблемы.
Я эти баги связываю с ядром WP, видимо где у него прописаны эти файлы в каких то исключениях и они подключаются не так как все остальные.
В гугле этого почти не было - теперь будет))
Баг интересный получился - решил покопать. 100% сил конечно решить и выяснить не получилось - но мир чуток светлей стал
Досада теперь - тратить время и подправлять допы. Я наверно буду исправлять по 4-му методу - воткну проверку
Я на wp-kama находил в комментах насчет options.php, но там без пояснений было. Просто не надо использовать и все. Теперь все понятно, точнее понятна причина.
Гугл меня забанил наверно - поэтому я нашел только один комментарий про эту "особенность" (там не один час я поиск и так и эдак на буржуйском юзал. В рунете минут 10 прошелся только - но внятного в индексе не увидел), в тикет системе вордпресса не нашел упоминания. На гитхабе в одном проекте увидел лишь проверку с каментом - что мол если ты в управлении сетью - нефиг подключать тебе settings.php
Завел себе этот сайт - бывало гуглишь какую-то мелкую неприятность, а найти ее не можешь. Здесь вот и буду свои находки расписывать. Пусть индексируется и пробел заполняется.
Вывод не вполне корректный, то же самое будет и с любым другим файлом из wp-admin, только сообщения об ошибке будут разные.
В момент активации плагина каталог wp-admin или wp-admin/network оказывается текущим, поэтому PHP в первую очередь пытается найти файл там, если указано только имя, а не полный путь.
Нет в ядре WP никаких исключений, и вполне можно иметь в плагине и options.php и settings.php, и т.д.
Просто нужно в require и include всегда прописывать полный путь, чтобы случайно не подключить файл с тем же именем из совсем другого каталога.
Это большое дело и подспорье однозначно. Полезность огромная именно тонких вещей. Я в читателях постоянных)
Вопрос лишь во времени - писать надо регулярно что-то. Желательно годное, а не очередное - "как добавить кнопки соцсетей на вордпресс сайт". Для этого надо жестко планировать свой распорядок наверно на неделю. Чтобы понимать - седня я пишу на эту тему, завтра я программирую, в среду надо поработать над функционалом да еще учитывать что могут всплывать неожиданные баги и нужно поддерживать обратную связь - все это потребует выделения времени.
Потом в выходные садиться и планировать вновь.
На этом сайте зависли три больших дела - если реализую - появится больше контента, репосты в соцсети и таймлайн моей работы будет виден всем (сайт то портфолио - это пока правда не видно и не очевидно - надо исправить). Но пока в приоритете книга по WP-Recall.
Для сайта хорошее дело составить контент план по 14 дней. Тогда можно уже остальные дела не упускать. Без плана трудно вести сайт, метания начинаются.