[ 'build' => 'front', 'style' => 'css/remaily.css', 'deps' => [] ] * 'remaily-editor' => [ 'build' => 'editor', 'style_deps' => [ 'wp-components' ], 'translations' => 'remaily' ] * * 'data' => [ 'remailyData', callable ] is built on first enqueue only. Paths are relative to assets/; 'url' loads a * script from elsewhere (a captcha provider's). * More handles through remaily_assets. */ class Assets { /** * Handles registered * * @var array|null */ private static $assets = null; /** * Handles whose data is printed * * @var array [ handle => true ] */ private static $data = []; /** * Init */ public static function init() { add_action( 'wp_enqueue_scripts', [ __CLASS__, 'register' ], 5 ); add_action( 'admin_enqueue_scripts', [ __CLASS__, 'register' ], 5 ); add_action( 'enqueue_block_assets', [ __CLASS__, 'register' ], 5 ); } /** * The plugin's handles * * @return array [ handle => asset ] */ public static function all() { $all = [ // Front end // The front script, built from assets/src/front into one file 'remaily' => [ 'build' => 'front', 'style' => 'css/remaily.css', 'data' => [ 'remailyData', [ Renderer::class, 'script_data' ] ] ], 'remaily-preview' => [ 'script' => 'js/preview.js', 'style' => 'css/preview.css' ], 'remaily-admin-bar' => [ 'script' => 'js/admin-bar.js', 'style' => 'css/admin-bar.css', 'deps' => [ 'admin-bar' ] ], // Admin 'remaily-admin-menu' => [ 'style' => 'css/admin-menu.css' ], 'remaily-admin-settings' => [ 'script' => 'js/admin-settings.js', 'style' => 'css/admin-settings.css' ], 'remaily-admin-list' => [ 'style' => 'css/admin-list.css' ], 'remaily-admin-dashboard' => [ 'style' => 'css/admin-dashboard.css' ], 'remaily-admin-welcome' => [ 'style' => 'css/admin-welcome.css', 'deps' => [ 'remaily-admin-settings' ] ], 'remaily-editor' => [ 'build' => 'editor', 'translations' => 'remaily' ], 'remaily-admin-addons' => [ 'script' => 'js/admin-addons.js', 'style' => 'css/admin-addons.css', 'deps' => [ 'remaily-admin-settings' ], 'data' => [ 'remailyAddons', [ AddonsPage::class, 'script_data' ] ] ], 'remaily-blocks' => [ 'build' => 'blocks', 'translations' => 'remaily', 'data' => [ 'remailyBlocks', [ Block::class, 'script_data' ] ] ], ]; return (array) apply_filters( 'remaily_assets', $all ); } /** * Register every handle; again if WordPress's lists were made anew since (the block widgets screen does that * after an early call, which would leave the handles out) */ public static function register() { if ( null === self::$assets ) { self::$assets = []; foreach ( self::all() as $handle => $asset ) { $asset = self::resolve( $asset ); if ( $asset ) { self::$assets[ $handle ] = $asset; } } } foreach ( self::$assets as $handle => $asset ) { if ( $asset['script'] && !wp_script_is( $handle, 'registered' ) ) { wp_register_script( $handle, $asset['script'], $asset['deps'], $asset['version'], [ 'in_footer' => true, 'strategy' => 'defer' ] ); if ( $asset['translations'] ) { wp_set_script_translations( $handle, $asset['translations'] ); } // Its data goes with the new registration unset( self::$data[ $handle ] ); } if ( $asset['style'] && !wp_style_is( $handle, 'registered' ) ) { wp_register_style( $handle, $asset['style'], $asset['style_deps'] ?? $asset['deps'], $asset['version'] ); if ( $asset['rtl'] ) { wp_style_add_data( $handle, 'rtl', 'replace' ); } elseif ( $asset['path'] ) { // WordPress prints it inline when it's small enough (wp_maybe_inline_styles): one request less wp_style_add_data( $handle, 'path', $asset['path'] ); } } } } /** * Enqueue the script and style of handles * * @param string ...$handles Handles */ public static function enqueue( ...$handles ) { self::register(); foreach ( $handles as $handle ) { if ( !empty( self::$assets[ $handle ]['script'] ) ) { wp_enqueue_script( $handle ); if ( !empty( self::$assets[ $handle ]['data'] ) && !isset( self::$data[ $handle ] ) ) { self::$data[ $handle ] = true; [ $name, $callback ] = self::$assets[ $handle ]['data']; self::data( $handle, $name, (array) call_user_func( $callback ) ); } } if ( !empty( self::$assets[ $handle ]['style'] ) ) { wp_enqueue_style( $handle ); } } } /** * Enqueue only the style of a handle (enqueue_block_assets: it also reaches the editor canvas) * * @param string $handle Handle */ public static function enqueue_style( $handle ) { self::register(); if ( !empty( self::$assets[ $handle ]['style'] ) ) { wp_enqueue_style( $handle ); } } /** * Data for a script, as window.{name} before it * * @param string $handle Handle * @param string $name Global name * @param array $data Data */ public static function data( $handle, $name, array $data ) { self::register(); wp_add_inline_script( $handle, sprintf( 'window.%s = %s;', $name, wp_json_encode( $data ) ), 'before' ); } /** * A script's URL with its version, for a script loaded only when needed (the payment script) * * @param string $handle Handle * * @return string */ public static function src( $handle ) { self::register(); return empty( self::$assets[ $handle ]['script'] ) ? '' : add_query_arg( 'ver', self::$assets[ $handle ]['version'], self::$assets[ $handle ]['script'] ); } /** * URL of a file in assets/ * * @param string $path Path relative to assets/ * * @return string */ public static function url( $path ) { return REMAILY_URL . 'assets/' . ltrim( $path, '/' ); } /** * Files, dependencies and version of a handle; null when its files are missing * * @param array $asset Asset * * @return array|null */ private static function resolve( array $asset ) { if ( !empty( $asset['url'] ) ) { return [ 'script' => esc_url_raw( $asset['url'] ), 'style' => '', 'path' => '', 'deps' => [], 'data' => null, 'style_deps' => null, 'version' => null, 'translations' => '', 'rtl' => false ]; } $asset += [ 'script' => '', 'style' => '', 'deps' => [], 'data' => null, 'style_deps' => null, 'version' => null, 'translations' => '', 'rtl' => false, ]; if ( !empty( $asset['build'] ) ) { $manifest = REMAILY_PATH . 'assets/build/' . $asset['build'] . '.asset.php'; if ( !is_file( $manifest ) ) { return null; } $built = require $manifest; // A manifest still being uploaded if ( !is_array( $built ) ) { return null; } $css = is_file( REMAILY_PATH . 'assets/build/' . $asset['build'] . '.css' ); $asset['script'] = 'build/' . $asset['build'] . '.js'; // The bundle's own CSS, else the style named with it (the front script's css/remaily.css) $asset['style'] = $css ? 'build/' . $asset['build'] . '.css' : $asset['style']; $asset['deps'] = array_merge( $built['dependencies'], $asset['deps'] ); $asset['version'] = $built['version']; $asset['rtl'] = $css; // The bundle's dependencies are scripts $asset['style_deps'] = $asset['style_deps'] ?? []; } // A release's minified copy (npm run release), the readable one with SCRIPT_DEBUG if ( 0 === strpos( $asset['script'], 'js/' ) && !( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ) { $min = substr( $asset['script'], 0, -3 ) . '.min.js'; if ( is_file( REMAILY_PATH . 'assets/' . $min ) ) { $asset['script'] = $min; } } $file = $asset['script'] ?: $asset['style']; if ( !is_file( REMAILY_PATH . 'assets/' . $file ) ) { return null; } $asset['version'] = $asset['version'] ?? REMAILY_VERSION . '.' . filemtime( REMAILY_PATH . 'assets/' . $file ); $asset['path'] = $asset['style'] ? REMAILY_PATH . 'assets/' . $asset['style'] : ''; $asset['script'] = $asset['script'] ? self::url( $asset['script'] ) : ''; $asset['style'] = $asset['style'] ? self::url( $asset['style'] ) : ''; return $asset; } }