Agregar tiempo de última modificación como versión a CSS y JS
Pude agregar el tiempo de última modificación del archivo como versión a los archivos CSS y JS. Como pueden ver, tengo que repetir filemtime(get_theme_file_path('...'))
cada vez que se agrega un nuevo enlace.
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');
¿Hay alguna manera de usar un filtro personalizado o algo similar en lugar de agregar manualmente esa línea cada vez?
Similar a la función siguiente (para eliminar números de versión), pero me gustaría agregar números de versión.
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);

Podrías usar add_query_arg() pero entonces tendrías que analizar la URI cada vez, prefiero crear una función envoltorio para 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);
}
Añade esto en tu archivo functions y luego en lugar de por ejemplo:
wp_enqueue_script('_base', get_theme_file_uri('/assets/js/base.js'), array(), filemtime(get_theme_file_path('/assets/js/base.js')));
llama:
my_enqueuer('_base', '/assets/js/base.js');
y en lugar de por ejemplo:
wp_enqueue_style('_base', get_theme_file_uri('/assets/css/base.css'), array(), filemtime(get_theme_file_path('/assets/css/base.css')));
llama:
my_enqueuer('_base', '/assets/css/base.css', 'style');
Puedes pasar el array de dependencias como último argumento cuando sea necesario. Para scripts, si pasas el array de dependencias, tendrás que pasar también el tercer parámetro 'script', aunque lo he establecido como valor por defecto.

Solía usar YYYYMMDD como número de versión para los archivos en cola (enqueued), lo cual era razonablemente bueno, pero causaba problemas cuando cambiaba más de una vez en el día y aún así requería recordar actualizar el número de versión cuando se hacían cambios al archivo. Un ejemplo de un enqueue podría verse así:
<?php wp_enqueue_style( 'child-theme', get_stylesheet_directory_uri() . '/css/styles.css', array(), '20150731' ); ?>
Mi enfoque revisado comienza creando una variable para la ruta del archivo CSS/JS y luego usando filemtime en el número de versión en lugar de YYYYMMDD:
<?php
$themecsspath = get_stylesheet_directory() . '/css/styles.css';
wp_enqueue_style(
'child-theme',
get_stylesheet_directory_uri() . '/css/styles.css',
array(),
filemtime( $themecsspath )
);
?>
Ahora, en lugar de que mis archivos en cola contengan el número de versión de WordPress, así:
<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' />
Se ven así:
<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' />

Esta respuesta fue adaptada de la solución de @CGodo
.
Estaba obteniendo Errores Fatales con el código original. He probado este código y hace lo que creo que la respuesta original pretendía hacer.
/**
* Reemplaza la versión de la consulta en scripts o estilos registrados con el tiempo de modificación del archivo
*
* @param $src
*
* @return string
*/
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 );

Si por alguna razón alguien lo necesita, estos hooks añadirán versiones basadas en el tiempo de modificación a todos los scripts y estilos de WordPress, excepto para aquellos cargados desde PHP.
La razón por la que utiliza las instancias singleton WP_Scripts y WP_Styles es porque esas instancias ya tienen calculada la base_url.
/**
* Reemplaza la versión query en scripts o estilos registrados con el tiempo de modificación del archivo
* @param string $src URL de origen
* @param string $baseUrl URL base del sitio
* @return string
*/
function put_modified_time_version($src, $baseUrl)
{
// Solo trabajar con objetos de baseUrl
if ($src && strpos($src, $baseUrl) === 0) {
// Eliminar cualquier versión existente
$newSrc = remove_query_arg('ver', $src);
// Obtener ruta después de base_url
$path = substr($newSrc, strlen($baseUrl));
$path = wp_parse_url($path, PHP_URL_PATH);
// Aplicar versión de tiempo de modificación si existe
if ($mtime = @filemtime(untrailingslashit(ABSPATH) . $path)) {
$src = add_query_arg('ver', $mtime, $newSrc);
}
}
return $src;
}
/**
* Filtra las fuentes de estilos para poner el tiempo de modificación como query string
* @param $src
* @return string
*/
function modified_time_version_style($src) {
// base_url de WP_Versions ya está en memoria
return ($src) ? put_modified_time_version($src, wp_styles()->base_url) : $src;
}
/**
* Filtra las fuentes de scripts para poner el tiempo de modificación como query string
* @param $src
* @return string
*/
function modified_time_version_script($src) {
// base_url de WP_Styles ya está en memoria
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);

Busqué todo el día una forma de versionar mis hojas de estilos. Tuve un problema al usar esto para todos los scripts, pero simplemente comenté el filtro para los scripts ya que no lo necesitaba para ese caso.
Nota: Tuve que cambiar la prioridad de 15 a 9999 para que funcionara para mí. Estoy seguro de que los plugins que estaba abordando establecieron una prioridad más alta de lo que deberían.

Acabo de escribir dos métodos para mi clase de plugin, que hacen muy fácil registrar y encolar scripts y estilos. Y por supuesto, como se desea, siempre se añade la última fecha de modificación como parámetro de versión. Quizás esto le pueda ser útil a alguien.
Cómo usarlos:
/**
* Para estos ejemplos asumimos que los assets de tu plugin están ubicados en
* wp-content/plugins/mi-plugin/ruta/hacia/assets/
*/
// añade tu estilo
$this->registrarAsset('ruta/hacia/assets/tu-estilo.css');
// añade tu script funciona exactamente igual
$this->registrarAsset('ruta/hacia/assets/tu-script.js');
// añade script con dependencia
$this->registrarAsset('ruta/hacia/assets/script-con-dependencias.js', [
'jquery'
]);
// añade script con dependencia interna
$this->registrarAsset('ruta/hacia/assets/script-con-dependencias.js', [
'jquery',
$this->getAssetHandle('ruta/hacia/assets/tu-script.js')
]);
// para dependencias internas también puedes pasar la ruta de la dependencia directamente
$this->registrarAsset('ruta/hacia/assets/script-con-dependencias.js', [
'jquery',
'ruta/hacia/assets/tu-script.js'
]);
Hay algunas opciones más, pero puedes consultar la documentación sobre los métodos en el código fuente que necesitas:
class miPlugin
{
public function __construct()
{
}
/**
* Registra y encola un script o estilo
*
* @param STRING $ruta La ruta del archivo que quieres registrar o encolar (relativa a la carpeta de tu plugin).
* @param ARRAY $dependencias Las dependencias como las conoces de wp_enqueue_script, pero también permite rutas de otros assets registrados con este método.
* @param BOOLEAN $encolar Si es FALSE solo se registrará, de lo contrario también se encolará.
* @param STRING|NULL $tipo Tipo del asset. Tipos permitidos son 'script' y 'style'. Si es NULL, el tipo se detecta automáticamente por la extensión del archivo.
* @param STRING $media Para definir 'media' al añadir CSS (Se ignora para assets JS - Los assets JS siempre reciben TRUE para el parámetro in_footer ya que esta es la forma recomendada usualmente)
*
* @return BOOLEAN|NULL Cuando $encolar es TRUE, el valor de retorno es siempre NULL. De lo contrario TRUE en éxito, FALSE en fallo.
*/
public function registrarAsset($ruta, $dependencias = [], $encolar = true, $tipo = null, $media = 'all')
{
$ruta = '/' . ltrim($ruta, '/');
$nombreDirPlugin = explode(DIRECTORY_SEPARATOR, ltrim(str_replace(realpath(WP_PLUGIN_DIR), '', realpath(__FILE__)), DIRECTORY_SEPARATOR), 2)[0];
$dirPlugin = realpath(WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $nombreDirPlugin);
if ($tipo === null) {
$extensiones = ['js' => 'script', 'css' => 'style'];
$extension = pathinfo($ruta, PATHINFO_EXTENSION);
$tipo = isset($extensiones[$extension]) ? $extensiones[$extension] : null;
}
if (!in_array($tipo, ['script', 'style']) || !file_exists($dirPlugin . $ruta)) {
return;
}
foreach ($dependencias as $indice => $dependencia) {
if (preg_match('/\.(js|css)$/', $dependencia) && file_exists($dirPlugin . DIRECTORY_SEPARATOR . ltrim($dependencia, '\\/'))) {
$dependencias[$indice] = $this->getAssetHandle($dependencia);
}
}
$func = 'wp_' . ($encolar ? 'enqueue' : 'register') . '_' . $tipo;
return $func($this->getAssetHandle($ruta), plugins_url($nombreDirPlugin . $ruta), $dependencias, filemtime($dirPlugin . $ruta), $tipo === 'script' ? true : $media);
}
/**
* Obtiene el handle de un asset que registrarAsset() usa automáticamente
*
* @param STRING $ruta La ruta que usaste con registrarAsset()
*
* @return STRING El nombre del handle del asset
*/
public function getAssetHandle($ruta)
{
$nombreDirPlugin = explode(DIRECTORY_SEPARATOR, ltrim(str_replace(realpath(WP_PLUGIN_DIR), '', realpath(__FILE__)), DIRECTORY_SEPARATOR), 2)[0];
return preg_replace('/[^a-zA-Z0-9]+/', '-', $nombreDirPlugin . '-' . $ruta);
}
}
