Я разрабатываю тему WordPress с использованием шаблонизатора. Я хочу, чтобы мой код был максимально совместим с основными функциями WP.
Сначала какой-то контекст
Моя первая проблема состояла в том, чтобы найти способ разрешить шаблон, начиная с запроса WP. Я решил эту проблему, используя мою библиотеку Brain \ Hierarchy .
Что касается get_template_part()
и других функций , которые загружают обертонам нравятся get_header()
, get_footer()
и похоже, что это было довольно легко писать обертку для частичной функциональности шаблона двигателя.
Проблема
Моя проблема сейчас, как загрузить шаблон комментариев.
Функция WordPress comments_template()
- это функция ~ 200 строк, которая делает много вещей, которые я хочу сделать также для максимальной совместимости ядра.
Однако, как только я позвоню comments_template()
, файл require
d, это первый из:
- файл в константе
COMMENTS_TEMPLATE
, если он определен comments.php
в папке темы, если найден/theme-compat/comments.php
в WP включена папка как последнее средство откат
Короче говоря, нет способа помешать функции загружать файл PHP, что мне нежелательно, потому что мне нужно рендерить свои шаблоны, а не просто использовать require
.
Текущее решение
В данный момент я отправляю пустой comments.php
файл и использую 'comments_template'
фильтр-ловушку, чтобы узнать, какой шаблон WordPress хочет загрузить, и использую функцию из моего механизма шаблонов для загрузки шаблона.
Что-то вроде этого:
function engineCommentsTemplate($myEngine) {
$toLoad = null; // this will hold the template path
$tmplGetter = function($tmpl) use(&$toLoad) {
$toLoad = $tmpl;
return $tmpl;
};
// late priority to allow filters attached here to do their job
add_filter('comments_template', $tmplGetter, PHP_INT_MAX);
// this will load an empty comments.php file I ship in my theme
comments_template();
remove_filter('comments_template', $tmplGetter, PHP_INT_MAX);
if (is_file($toLoad) && is_readable($toLoad)) {
return $myEngine->render($toLoad);
}
return '';
}
Вопрос
Это работает, совместимо ли ядро, но ... есть ли способ заставить его работать, не отправляя пустой comments.php
?
Потому что мне это не нравится.
comments_template
фильтр илиCOMMENTS_TEMPLATE
константу для настройки шаблона. Что не является ключевым, но, как я уже сказал, я хотел быть максимально совместимым с ядром.Решение: используйте временный файл - с уникальным именем файла
После многих прыжков и проникновения в самые грязные уголки PHP, я перефразировал вопрос:
так как код в ядре как раз есть
Тогда вопрос был решен быстрее:
и это все. Возможно, было бы лучше использовать
wp_upload_dir()
вместо:Другой вариант может заключаться в том,
get_temp_dir()
какие обертки использоватьWP_TEMP_DIR
. Подсказка: как ни странно,/tmp/
файлы не сохранятся между перезагрузками, что/var/tmp/
могло бы произойти . Можно выполнить простое сравнение строк в конце и проверить возвращаемое значение, а затем исправить это в случае необходимости, чего в этом случае нет:Теперь, чтобы быстро проверить, есть ли ошибки для временного файла без содержимого:
И: нет ошибок → работает.
РЕДАКТИРОВАТЬ: Как @toscho указал в комментариях, есть еще лучший способ сделать это:
Примечание. Согласно примечанию пользователя на php.net docs ,
sys_get_temp_dir()
поведение в разных системах различается. Поэтому в результате удаляется завершающий слеш, а затем добавляется снова. Поскольку основная ошибка № 22267 исправлена, теперь это должно работать и на серверах Win / IIS.Ваша рефакторированная функция (не проверена):
Бонус №1:
tmpfile()
вернетсяNULL
. Да, действительно.Бонус №2:
file_exists( __DIR__ )
вернетсяTRUE
. Да, действительно ... если ты забыл.^ Это приводит к реальной ошибке в ядре WP.
Чтобы помочь другим перейти в режим проводника и найти их (плохо для недокументированных фрагментов), я быстро подведу итог тому, что я пробовал:
Попытка 1: временный файл в памяти
Первой попыткой было создать поток во временный файл, используя
php://temp
. Из документов PHP:Код:
Находка: Нет, не работает.
Попытка 2: использовать временный файл
Там
tmpfile()
, так почему бы не использовать это ?!Да, так много об этом ярлыке.
Попытка 3: использовать пользовательскую потоковую оболочку
Затем я подумал, что мог бы создать собственную обертку потока и зарегистрировать ее, используя
stream_wrapper_register()
. Тогда я мог бы использовать виртуальный шаблон из этого потока, чтобы обмануть ядро, поверив, что у нас есть файл. Пример кода ниже (я уже удалил весь класс, а истории не хватает шагов…)Опять же , это возвращается
NULL
наfile_exists()
.Протестировано с PHP 5.6.20
источник
stream_stat()
? Я думаю, что это то, чтоfile_exists()
вызовет, чтобы проверить ... php.net/manual/en/streamwrapper.stream-stat.phptempnam()
. Использование задания cron будет работать, но это дополнительные издержки ...tempnam( sys_get_temp_dir(), 'comments.php' )
записывается один раз , вы можете повторно использовать имя файла, и файл пуст , поэтому он не использует много ресурсов. Плюс это легко понять в вашем коде. Безусловно лучшее решение, имхо.Поскольку @AlainSchlesser предложил следовать по маршруту (и поскольку нерабочие вещи всегда вызывают у меня проблемы ), я попытался создать потоковую оболочку для виртуальных файлов. Я не мог решить это (читай: чтение возвращаемых значений в документации) самостоятельно, но решил это с помощью @HPierce на SO .
Вам просто нужно зарегистрировать новый класс как новый протокол:
Затем это позволяет создать виртуальный (не существующий) файл:
Ваша функция может затем быть реорганизована в:
как
file_exists()
проверка в ядре возвращаетсяTRUE
иrequire $file
выбрасывает без ошибок.Я должен отметить, что я очень рад, как это получилось, поскольку это может быть очень полезно при юнит-тестах.
источник