Добавление времени последнего изменения в качестве версии для CSS и JS
Мне удалось добавить время последнего изменения файла в качестве версии для CSS и JS файлов. Как видите, мне приходится повторно добавлять filemtime(get_theme_file_path('...'))
каждый раз при добавлении новой ссылки.
function _enqueue_scripts() {
wp_enqueue_style('_base', get_theme_file_uri('/assets/css/base.css'), array(), filemtime(get_theme_file_path('/assets/css/base.css')));
wp_enqueue_script('_base', get_theme_file_uri('/assets/js/base.js'), array(), filemtime(get_theme_file_path('/assets/js/base.js')));
}
add_action('wp_enqueue_scripts', '_enqueue_scripts');
Есть ли способ использовать пользовательский фильтр или что-то подобное для этого, вместо того чтобы вручную добавлять эту строку каждый раз?
Похоже на функцию ниже (для удаления номеров версий), но я хотел бы добавлять номера версий.
function _remove_script_version($src) {
return $src ? esc_url(remove_query_arg('ver', $src)) : false;
}
add_filter('style_loader_src', '_remove_script_version', 15, 1);
add_filter('script_loader_src', '_remove_script_version', 15, 1);

Вы можете использовать add_query_arg(), но тогда вам придется парсить URI каждый раз. Я бы предпочел создать обертку для функций wp_enqueue_script/style:
function my_enqueuer($my_handle, $relpath, $type='script', $my_deps=array()) {
$uri = get_theme_file_uri($relpath);
$vsn = filemtime(get_theme_file_path($relpath));
if($type == 'script') wp_enqueue_script($my_handle, $uri, $my_deps, $vsn);
else if($type == 'style') wp_enqueue_style($my_handle, $uri, $my_deps, $vsn);
}
Добавьте это в ваш файл функций, а затем вместо, например:
wp_enqueue_script('_base', get_theme_file_uri('/assets/js/base.js'), array(), filemtime(get_theme_file_path('/assets/js/base.js')));
используйте:
my_enqueuer('_base', '/assets/js/base.js');
и вместо:
wp_enqueue_style('_base', get_theme_file_uri('/assets/css/base.css'), array(), filemtime(get_theme_file_path('/assets/css/base.css')));
используйте:
my_enqueuer('_base', '/assets/css/base.css', 'style');
Вы можете передать массив зависимостей в качестве последнего аргумента, когда это необходимо. Для скриптов, если вы передаете массив зависимостей, вам также придется передать третий параметр 'script', несмотря на то, что я установил его значение по умолчанию.

Раньше я использовал формат YYYYMMDD в качестве номера версии для подключаемых файлов, что было достаточно удобно, но вызывало проблемы, если файл менялся более одного раза в день. Кроме того, приходилось помнить о необходимости обновлять номер версии при внесении изменений в файл. Пример такого подключения мог выглядеть так:
<?php wp_enqueue_style( 'child-theme', get_stylesheet_directory_uri() . '/css/styles.css', array(), '20150731' ); ?>
Мой пересмотренный подход начинается с создания переменной для пути к CSS/JS файлу, а затем использования функции filemtime вместо YYYYMMDD в качестве номера версии:
<?php
$themecsspath = get_stylesheet_directory() . '/css/styles.css';
wp_enqueue_style(
'child-theme',
get_stylesheet_directory_uri() . '/css/styles.css',
array(),
filemtime( $themecsspath )
);
?>
Теперь вместо номера версии WordPress в подключаемых файлах, как здесь:
<link rel='stylesheet' id='child-theme-css' href='http://example.com/wp-content/themes/child/css/styles.css?ver=4.3.1' type='text/css' media='all' />
Файлы выглядят так:
<link rel='stylesheet' id='child-theme-css' href='http://example.com/wp-content/themes/child/css/styles.css?ver=1447781986' type='text/css' media='all' />

Этот ответ адаптирован из решения @CGodo
.
Я получал фатальные ошибки с оригинальным кодом. Я протестировал этот код, и он делает то, что, как я считаю, предполагалось в исходном ответе.
/**
* Заменяет версию запроса в зарегистрированных скриптах или стилях на время последнего изменения файла
*
* @param string $src Исходный URL
*
* @return string URL с добавленной версией
*/
function add_modified_time( $src ) {
$clean_src = remove_query_arg( 'ver', $src );
$path = wp_parse_url( $src, PHP_URL_PATH );
// Пытаемся получить время модификации файла
if ( $modified_time = @filemtime( untrailingslashit( ABSPATH ) . $path ) ) {
$src = add_query_arg( 'ver', $modified_time, $clean_src );
} else {
// Если не удалось - используем текущее время
$src = add_query_arg( 'ver', time(), $clean_src );
}
return $src;
}
// Подключаем фильтры для скриптов и стилей
add_filter( 'style_loader_src', 'add_modified_time', 99999999, 1 );
add_filter( 'script_loader_src', 'add_modified_time', 99999999, 1 );

Если кому-то понадобится, эти хуки добавят версии на основе времени модификации ко всем скриптам и стилям WordPress, кроме загружаемых напрямую из PHP.
Причина использования синглтонов WP_Scripts и WP_Styles в том, что эти экземпляры уже содержат вычисленный base_url.
/**
* Заменяет версию в запросе для зарегистрированных скриптов или стилей на время модификации файла
* @param string $src Исходный URL
* @param string $baseUrl Базовый URL сайта
* @return string
*/
function put_modified_time_version($src, $baseUrl)
{
// Работаем только с объектами из baseUrl
if ($src && strpos($src, $baseUrl) === 0) {
// Удаляем любую существующую версию
$newSrc = remove_query_arg('ver', $src);
// Получаем путь после base_url
$path = substr($newSrc, strlen($baseUrl));
$path = wp_parse_url($path, PHP_URL_PATH);
// Добавляем версию на основе времени модификации, если файл существует
if ($mtime = @filemtime(untrailingslashit(ABSPATH) . $path)) {
$src = add_query_arg('ver', $mtime, $newSrc);
}
}
return $src;
}
/**
* Фильтрует источники стилей, добавляя время модификации файла как строку запроса
* @param $src
* @return string
*/
function modified_time_version_style($src) {
// base_url из WP_Versions уже в памяти
return ($src) ? put_modified_time_version($src, wp_styles()->base_url) : $src;
}
/**
* Фильтрует источники скриптов, добавляя время модификации файла как строку запроса
* @param $src
* @return string
*/
function modified_time_version_script($src) {
// base_url из WP_Styles уже в памяти
return ($src) ? put_modified_time_version($src, wp_scripts()->base_url) : $src;
}
add_filter('style_loader_src', 'modified_time_version_style', 15, 1);
add_filter('script_loader_src', 'modified_time_version_script', 15, 1);

Я целый день искал способ версионировать свои таблицы стилей. У меня возникла проблема с использованием этого для всех скриптов, но я просто закомментировал фильтр для скриптов, так как он мне не был нужен для этого случая.
Примечание: мне пришлось изменить приоритет с 15 на 9999, чтобы это заработало. Уверен, что плагины, с которыми я работал, устанавливали приоритет выше, чем следовало.

Я только что написал два метода для класса своего плагина, которые значительно упрощают регистрацию и подключение скриптов и стилей. И, конечно же, как и требовалось, в параметр версии всегда добавляется время последнего изменения. Возможно, это кому-то пригодится.
Как их использовать:
/**
* Для этих примеров предположим, что ресурсы вашего плагина находятся в
* wp-content/plugins/my-plugin/path/to/assets/
*/
// добавить ваш стиль
$this->registerAsset('path/to/assets/your-style.css');
// добавить ваш скрипт работает точно так же
$this->registerAsset('path/to/assets/your-script.js');
// добавить скрипт с зависимостью
$this->registerAsset('path/to/assets/script-with-dependencies.js', [
'jquery'
]);
// добавить скрипт с внутренней зависимостью
$this->registerAsset('path/to/assets/script-with-dependencies.js', [
'jquery',
$this->getAssetHandle('path/to/assets/your-script.js')
]);
// для внутренних зависимостей вы также можете передать путь к зависимости напрямую
$this->registerAsset('path/to/assets/script-with-dependencies.js', [
'jquery',
'path/to/assets/your-script.js'
]);
Есть еще несколько опций, но просто ознакомьтесь с документацией по методам в исходном коде, который вам нужен:
class myPlugin
{
public function __construct()
{
}
/**
* Регистрирует и подключает скрипт или стиль
*
* @param STRING $path Путь к файлу, который вы хотите зарегистрировать или подключить (относительно папки вашего плагина).
* @param ARRAY $dependencies Зависимости, как вы знаете из wp_enqueue_script, но также допускаются пути к другим ресурсам, зарегистрированным этим методом.
* @param BOOLEAN $enqueue Если FALSE, ресурс будет только зарегистрирован, в противном случае он также будет подключен.
* @param STRING|NULL $type Тип ресурса. Допустимые типы: 'script' и 'style'. Если NULL, тип автоматически определяется по расширению файла.
* @param STRING $media Определение 'media' при добавлении CSS (игнорируется для JS ресурсов - JS ресурсы всегда получают TRUE для параметра in_footer, так как это обычно рекомендуемый способ)
*
* @return BOOLEAN|NULL Когда $enqueue равен TRUE, возвращаемое значение всегда NULL. В противном случае TRUE при успехе, FALSE при неудаче.
*/
public function registerAsset($path, $dependencies = [], $enqueue = true, $type = null, $media = 'all')
{
$path = '/' . ltrim($path, '/');
$pluginDirName = explode(DIRECTORY_SEPARATOR, ltrim(str_replace(realpath(WP_PLUGIN_DIR), '', realpath(__FILE__)), DIRECTORY_SEPARATOR), 2)[0];
$pluginDir = realpath(WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $pluginDirName);
if ($type === null) {
$extensions = ['js' => 'script', 'css' => 'style'];
$extension = pathinfo($path, PATHINFO_EXTENSION);
$type = isset($extensions[$extension]) ? $extensions[$extension] : null;
}
if (!in_array($type, ['script', 'style']) || !file_exists($pluginDir . $path)) {
return;
}
foreach ($dependencies as $index => $dependency) {
if (preg_match('/\.(js|css)$/', $dependency) && file_exists($pluginDir . DIRECTORY_SEPARATOR . ltrim($dependency, '\\/'))) {
$dependencies[$index] = $this->getAssetHandle($dependency);
}
}
$func = 'wp_' . ($enqueue ? 'enqueue' : 'register') . '_' . $type;
return $func($this->getAssetHandle($path), plugins_url($pluginDirName . $path), $dependencies, filemtime($pluginDir . $path), $type === 'script' ? true : $media);
}
/**
* Получает handle ресурса, который автоматически использует registerAsset()
*
* @param STRING $path Путь, который вы использовали с registerAsset()
*
* @return STRING Имя handle ресурса
*/
public function getAssetHandle($path)
{
$pluginDirName = explode(DIRECTORY_SEPARATOR, ltrim(str_replace(realpath(WP_PLUGIN_DIR), '', realpath(__FILE__)), DIRECTORY_SEPARATOR), 2)[0];
return preg_replace('/[^a-zA-Z0-9]+/', '-', $pluginDirName . '-' . $path);
}
}
