<?php
/**
* Assets
* Handles script and stylesheet loading.
*
* @package Sensei\Assets
* @since 3.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Sensei Assets
* Loading CSS and Javascript files.
*
* @package Core
* @author Automattic
* @since 3.1.0
*/
class Sensei_Assets {
/**
* The URL for the plugin.
*
* @var string
*/
protected $plugin_url;
/**
* Plugin location.
*
* @var string
*/
protected $plugin_path;
/**
* Plugin version.
*
* @var string
*/
protected $version;
/**
* Plugin text domain.
*
* @var string
*/
protected $text_domain;
/**
* Sensei_Assets constructor.
*
* @param string $plugin_url The URL for the plugin.
* @param string $plugin_path Plugin location.
* @param string $version Plugin version.
* @param string $text_domain Plugin text domain.
*/
public function __construct( $plugin_url, $plugin_path, $version, $text_domain = 'sensei-lms' ) {
$this->plugin_url = $plugin_url;
$this->plugin_path = $plugin_path;
$this->version = $version;
$this->text_domain = $text_domain;
}
/**
* Enqueue a script or stylesheet with wp_enqueue_script/wp_enqueue_style.
*
* @param string $handle Unique name of the asset.
* @param string $filename The filename.
* @param array $dependencies Dependencies.
* @param bool|string $args In footer flag (script) or media type (style).
*/
public function enqueue( $handle, $filename, $dependencies = [], $args = null ) {
$config = $this->asset_config( $filename, $dependencies, $args );
$this->call_wp( 'wp_enqueue', $handle, $config );
}
/**
* Register a script or stylesheet with wp_register_script/wp_register_style.
*
* @param string|null $handle Unique name of the asset.
* @param string $filename The filename.
* @param array $dependencies Dependencies.
* @param null $args Asset arguments.
*/
public function register( $handle, $filename, $dependencies = [], $args = null ) {
$config = $this->asset_config( $filename, $dependencies, $args );
$this->call_wp( 'wp_register', $handle, $config );
}
/**
* Enqueue a registered script.
*
* @param string $handle Unique name of the script.
*/
public function enqueue_script( $handle ) {
wp_enqueue_script( $handle );
}
/**
* Enqueue a registered stylesheet.
*
* @param string $handle Unique name of the stylesheet.
*/
public function enqueue_style( $handle ) {
wp_enqueue_style( $handle );
}
/**
* Call the wrapped WordPress core function with _type postfix
*
* @param string $action wp_enqueue or wp_register.
* @param string $handle Unique handle for the asset.
* @param array $config Asset information.
*/
private function call_wp( $action, $handle, $config ) {
call_user_func( $action . '_' . $config['type'], $handle, $config['url'], $config['dependencies'], $config['version'], $config['args'] );
if ( 'script' === $config['type'] && in_array( 'wp-i18n', $config['dependencies'], true ) ) {
wp_set_script_translations( $handle, $this->text_domain );
}
}
/**
* Builds asset metadata for a given file.
* Loads dependencies and version hash tracked by the build process from [filename].asset.php
*
* @param string $filename The filename.
* @param array $dependencies Dependencies.
* @param bool|string $args Argument passed to wp_enqueue_script or wp_enqueue_style.
*
* @return array Asset information.
*/
public function asset_config( $filename, $dependencies = [], $args = null ) {
$is_js = preg_match( '/\.js$/', $filename );
$basename = preg_replace( '/\.\w+$/', '', $filename );
$url = $this->asset_url( $filename );
$version = $this->version;
$asset_config_path = $this->dist_path( $basename . '.asset.php' );
if ( file_exists( $asset_config_path ) ) {
$asset_config = require $asset_config_path;
// Only add generated dependencies for scripts.
if ( $is_js ) {
$dependencies = array_unique( array_merge( $dependencies, $asset_config['dependencies'] ) );
}
$version = $asset_config['version'];
}
return [
'url' => $url,
'dependencies' => $dependencies,
'version' => $version,
'type' => $is_js ? 'script' : 'style',
'args' => null !== $args ? $args : ( $is_js ? false : 'all' ), // defaults for wp_enqueue_script or wp_enqueue_style.
];
}
/**
* Get path for file in plugin assets dist directory.
*
* @param string $file Asset file.
*
* @return string
*/
public function dist_path( $file ) {
return path_join( $this->plugin_path, 'assets/dist/' . $file );
}
/**
* Get path for file in plugin assets source directory.
*
* @param string $file Asset file.
*
* @return string
*/
public function src_path( $file ) {
return path_join( $this->plugin_path, 'assets/' . $file );
}
/**
* Construct public url for the file.
*
* @param string $filename The filename.
*
* @return string Public url for the file.
*/
public function asset_url( $filename ) {
return rtrim( $this->plugin_url, '/' ) . '/assets/dist/' . $filename;
}
/**
* Preload the given REST routes and pass data to Javascript.
*
* @param string[] $rest_routes REST routes to preload.
*/
public function preload_data( $rest_routes ) {
// Temporarily removes the user filter when loading from preload.
remove_action( 'pre_get_posts', array( Sensei()->teacher, 'filter_queries' ) );
$preload_data = array_reduce(
$rest_routes,
'rest_preload_api_request',
[]
);
add_action( 'pre_get_posts', array( Sensei()->teacher, 'filter_queries' ) );
wp_add_inline_script(
'wp-api-fetch',
sprintf( 'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );', wp_json_encode( $preload_data ) ),
'after'
);
}
/**
* Change implementation for an already registered script.
*
* @param string $handle Name of the script to override.
* @param string $src New filename.
* @param array $deps Specify to change script dependencies.
*
* @since 3.3.1
*
* @deprecated 3.10.0
*/
public function override_script( $handle, $src, $deps = null ) {
_deprecated_function( __METHOD__, '3.10.0' );
$scripts = wp_scripts();
$script = $scripts->query( $handle, 'registered' );
if ( $script ) {
$script->src = $this->asset_url( $src );
$script->ver = $this->version;
if ( null !== $deps ) {
$script->deps = $deps;
}
} else {
$this->register( $handle, $src, $deps );
}
}
/**
* Use bundled WordPress client libraries for older versions.
*
* @since 3.3.1
*
* @deprecated 3.10.0
*/
public function wp_compat() {
_deprecated_function( __METHOD__, '3.10.0' );
}
/**
* Disable loading frontend.css for the current page.
*/
public function disable_frontend_styles() {
add_filter( 'sensei_disable_styles', '__return_true' );
}
/**
* Gets the href to the file at assets/icons/<name>.svg
* inside a generated sprite.
*
* @since 3.15.0
*
* @param string $name The name of the icon file at "assets/icons/<name>.svg".
*
* @return string The icon href.
*/
private function get_icon_href( string $name ) : string {
$sprite_file = $this->plugin_url . 'assets/dist/icons/sensei-sprite.svg?v=' . $this->version;
/**
* Filters the icon href for the svg.
*
* @since 4.4.0
*
* @hook sensei_icon_href
*
* @param {string} $icon_href The icon href.
* @param {string} $sprite_file The sprite file URL.
* @param {string} $name The icon name.
* @return {string} The icon href.
*/
$icon_href = apply_filters( 'sensei_icon_href', "{$sprite_file}#sensei-sprite-{$name}", $sprite_file, $name );
return $icon_href;
}
/**
* Gets SVG HTML from a generated sprite.
*
* @since 3.15.0
*
* @param string $name The name of the icon file at "assets/images/<name>.svg".
* @param string $class_names Classnames to add to the SVG element.
*
* @return string The SVG HTML.
*/
public function get_icon( string $name, string $class_names = '' ) : string {
$href = $this->get_icon_href( $name );
return '<svg class="' . esc_attr( $class_names ) . '"><use href="' . esc_url( $href ) . '"></use></svg>';
}
/**
* Gets image from assets.
*
* @since 4.1.0
*
* @param string $name The name of the image file at "assets/images/<name>".
*
* @return string Image path.
*/
public function get_image( string $name ) : string {
return $this->plugin_url . 'assets/dist/images/' . $name;
}
}