You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
415 lines
15 KiB
PHTML
415 lines
15 KiB
PHTML
8 months ago
|
<?php
|
||
|
/**
|
||
|
* Class Assets
|
||
|
*
|
||
|
* @link https://github.com/googleforcreators/web-stories-wp
|
||
|
*
|
||
|
* @copyright 2020 Google LLC
|
||
|
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Copyright 2020 Google LLC
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
declare(strict_types = 1);
|
||
|
|
||
|
namespace Google\Web_Stories;
|
||
|
|
||
|
/**
|
||
|
* Class Assets
|
||
|
*
|
||
|
* @phpstan-type AssetMetadata array{
|
||
|
* version: string,
|
||
|
* dependencies: string[],
|
||
|
* js: string[],
|
||
|
* css: string[],
|
||
|
* chunks: string[],
|
||
|
* }
|
||
|
*/
|
||
|
class Assets {
|
||
|
/**
|
||
|
* An array of registered styles.
|
||
|
*
|
||
|
* @var array<string, bool>
|
||
|
*/
|
||
|
protected array $register_styles = [];
|
||
|
|
||
|
/**
|
||
|
* An array of registered scripts.
|
||
|
*
|
||
|
* @var array<string, bool>
|
||
|
*/
|
||
|
protected array $register_scripts = [];
|
||
|
|
||
|
/**
|
||
|
* Get path to file and directory.
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string $path Path.
|
||
|
*/
|
||
|
public function get_base_path( string $path ): string {
|
||
|
return WEBSTORIES_PLUGIN_DIR_PATH . $path;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get url of file and directory.
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string $path Path.
|
||
|
*/
|
||
|
public function get_base_url( string $path ): string {
|
||
|
return WEBSTORIES_PLUGIN_DIR_URL . $path;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get asset metadata.
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string $handle Script handle.
|
||
|
* @return array Array containing combined contents of "<$handle>.asset.php" and "<$handle>.chunks.php".
|
||
|
*
|
||
|
* @phpstan-return AssetMetadata
|
||
|
*/
|
||
|
public function get_asset_metadata( string $handle ): array {
|
||
|
$base_path = $this->get_base_path( 'assets/js/' );
|
||
|
|
||
|
// *.asset.php is generated by DependencyExtractionWebpackPlugin.
|
||
|
// *.chunks.php is generated by HtmlWebpackPlugin with a custom template.
|
||
|
$asset_file = $base_path . $handle . '.asset.php';
|
||
|
$chunks_file = $base_path . $handle . '.chunks.php';
|
||
|
|
||
|
// phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable
|
||
|
$asset = is_readable( $asset_file ) ? require $asset_file : [];
|
||
|
// phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable
|
||
|
$chunks = is_readable( $chunks_file ) ? require $chunks_file : [];
|
||
|
|
||
|
// A hash calculated based on the file content of the entry point bundle at <$handle>.js.
|
||
|
$asset['version'] ??= WEBSTORIES_VERSION;
|
||
|
|
||
|
$asset['dependencies'] ??= [];
|
||
|
$asset['js'] = $chunks['js'] ?? [];
|
||
|
$asset['css'] = $chunks['css'] ?? [];
|
||
|
$asset['chunks'] = $chunks['chunks'] ?? [];
|
||
|
|
||
|
return $asset;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register script using handle.
|
||
|
*
|
||
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string $script_handle Handle of script.
|
||
|
* @param string[] $script_dependencies Array of extra dependencies.
|
||
|
* @param bool $with_i18n Optional. Whether to setup i18n for this asset. Default true.
|
||
|
*/
|
||
|
public function register_script_asset( string $script_handle, array $script_dependencies = [], bool $with_i18n = true ): void {
|
||
|
if ( isset( $this->register_scripts[ $script_handle ] ) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$base_script_path = $this->get_base_url( 'assets/js/' );
|
||
|
$in_footer = true;
|
||
|
|
||
|
$asset = $this->get_asset_metadata( $script_handle );
|
||
|
$entry_version = $asset['version'];
|
||
|
// Register any chunks of $script_handle first.
|
||
|
// `$asset['js']` are preloaded chunks, `$asset['chunks']` dynamically imported ones.
|
||
|
foreach ( $asset['js'] as $chunk ) {
|
||
|
$this->register_script(
|
||
|
$chunk,
|
||
|
$base_script_path . $chunk . '.js',
|
||
|
[],
|
||
|
$entry_version,
|
||
|
$in_footer,
|
||
|
$with_i18n
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// Dynamically imported chunks MUST NOT be added as dependencies here.
|
||
|
$dependencies = [ ...$asset['dependencies'], ...$script_dependencies, ...$asset['js'] ];
|
||
|
|
||
|
$this->register_script(
|
||
|
$script_handle,
|
||
|
$base_script_path . $script_handle . '.js',
|
||
|
$dependencies,
|
||
|
$entry_version,
|
||
|
$in_footer,
|
||
|
$with_i18n
|
||
|
);
|
||
|
|
||
|
// "Save" all the script's chunks so we can later manually fetch them and their translations if needed.
|
||
|
wp_script_add_data( $script_handle, 'chunks', $asset['chunks'] );
|
||
|
|
||
|
// Register every dynamically imported chunk as a script, just so
|
||
|
// that we can print their translations whenever the main script is enqueued.
|
||
|
// The actual enqueueing of these chunks is done by the main script via dynamic imports.
|
||
|
foreach ( $asset['chunks'] as $dynamic_chunk ) {
|
||
|
$this->register_script(
|
||
|
$dynamic_chunk,
|
||
|
$base_script_path . $dynamic_chunk . '.js',
|
||
|
[],
|
||
|
$entry_version, // Not actually used / relevant, since enqueueing is done by webpack.
|
||
|
$in_footer, // Ditto.
|
||
|
$with_i18n
|
||
|
);
|
||
|
|
||
|
if ( $with_i18n ) {
|
||
|
wp_add_inline_script( $script_handle, (string) wp_scripts()->print_translations( $dynamic_chunk, false ) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enqueue script using handle.
|
||
|
*
|
||
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string $script_handle Handle of script.
|
||
|
* @param string[] $script_dependencies Array of extra dependencies.
|
||
|
* @param bool $with_i18n Optional. Whether to setup i18n for this asset. Default true.
|
||
|
*/
|
||
|
public function enqueue_script_asset( string $script_handle, array $script_dependencies = [], bool $with_i18n = true ): void {
|
||
|
$this->register_script_asset( $script_handle, $script_dependencies, $with_i18n );
|
||
|
$this->enqueue_script( $script_handle );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register style using handle.
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string $style_handle Handle of style.
|
||
|
* @param string[] $style_dependencies Array of extra dependencies.
|
||
|
*/
|
||
|
public function register_style_asset( string $style_handle, array $style_dependencies = [] ): void {
|
||
|
if ( isset( $this->register_styles[ $style_handle ] ) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$base_style_url = $this->get_base_url( 'assets/css/' );
|
||
|
$base_style_path = $this->get_base_path( 'assets/css/' );
|
||
|
$ext = is_rtl() ? '-rtl.css' : '.css';
|
||
|
|
||
|
// Register any chunks of $style_handle first.
|
||
|
$asset = $this->get_asset_metadata( $style_handle );
|
||
|
// Webpack appends "-[contenthash]" to filenames of chunks, so omit the `?ver=` query param.
|
||
|
$chunk_version = null;
|
||
|
foreach ( $asset['css'] as $style_chunk ) {
|
||
|
$this->register_style(
|
||
|
$style_chunk,
|
||
|
$base_style_url . $style_chunk . '.css',
|
||
|
[],
|
||
|
$chunk_version
|
||
|
);
|
||
|
|
||
|
wp_style_add_data( $style_chunk, 'path', $base_style_path . $style_chunk . $ext );
|
||
|
}
|
||
|
$style_dependencies = [ ...$style_dependencies, ...$asset['css'] ];
|
||
|
|
||
|
$entry_version = $asset['version'];
|
||
|
$this->register_style(
|
||
|
$style_handle,
|
||
|
$base_style_url . $style_handle . '.css',
|
||
|
$style_dependencies,
|
||
|
$entry_version
|
||
|
);
|
||
|
|
||
|
wp_style_add_data( $style_handle, 'rtl', 'replace' );
|
||
|
wp_style_add_data( $style_handle, 'path', $base_style_path . $style_handle . $ext );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enqueue style using handle.
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string $style_handle Handle of style.
|
||
|
* @param string[] $style_dependencies Array of extra dependencies.
|
||
|
*/
|
||
|
public function enqueue_style_asset( string $style_handle, array $style_dependencies = [] ): void {
|
||
|
$this->register_style_asset( $style_handle, $style_dependencies );
|
||
|
$this->enqueue_style( $style_handle );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register a CSS stylesheet.
|
||
|
*
|
||
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string $style_handle Name of the stylesheet. Should be unique.
|
||
|
* @param string|false $src Full URL of the stylesheet, or path of the stylesheet relative to the WordPress root directory.
|
||
|
* If source is set to false, stylesheet is an alias of other stylesheets it depends on.
|
||
|
* @param string[] $deps Optional. An array of registered stylesheet handles this stylesheet depends on. Default empty array.
|
||
|
* @param string|bool|null $ver Optional. String specifying stylesheet version number, if it has one, which is added to the URL
|
||
|
* as a query string for cache busting purposes. If version is set to false, a version
|
||
|
* number is automatically added equal to current installed WordPress version.
|
||
|
* If set to null, no version is added.
|
||
|
* @param string $media Optional. The media for which this stylesheet has been defined.
|
||
|
* Default 'all'. Accepts media types like 'all', 'print' and 'screen', or media queries like
|
||
|
* '(orientation: portrait)' and '(max-width: 640px)'.
|
||
|
* @return bool Whether the style has been registered. True on success, false on failure.
|
||
|
*/
|
||
|
public function register_style( string $style_handle, $src, array $deps = [], $ver = false, string $media = 'all' ): bool {
|
||
|
if ( ! isset( $this->register_styles[ $style_handle ] ) ) {
|
||
|
$this->register_styles[ $style_handle ] = wp_register_style( $style_handle, $src, $deps, $ver, $media );
|
||
|
}
|
||
|
|
||
|
return $this->register_styles[ $style_handle ];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register a new script.
|
||
|
*
|
||
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string $script_handle Name of the script. Should be unique.
|
||
|
* @param string|false $src Full URL of the script, or path of the script relative to the WordPress root directory.
|
||
|
* If source is set to false, script is an alias of other scripts it depends on.
|
||
|
* @param string[] $deps Optional. An array of registered script handles this script depends on. Default empty array.
|
||
|
* @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL
|
||
|
* as a query string for cache busting purposes. If version is set to false, a version
|
||
|
* number is automatically added equal to current installed WordPress version.
|
||
|
* If set to null, no version is added.
|
||
|
* @param bool $in_footer Optional. Whether to enqueue the script before </body> instead of in the <head>.
|
||
|
* Default 'false'.
|
||
|
* @param bool $with_i18n Optional. Whether to setup i18n for this asset. Default true.
|
||
|
* @return bool Whether the script has been registered. True on success, false on failure.
|
||
|
*/
|
||
|
public function register_script( string $script_handle, $src, array $deps = [], $ver = false, bool $in_footer = false, bool $with_i18n = true ): bool {
|
||
|
if ( ! isset( $this->register_scripts[ $script_handle ] ) ) {
|
||
|
$this->register_scripts[ $script_handle ] = wp_register_script( $script_handle, $src, $deps, $ver, $in_footer );
|
||
|
|
||
|
if ( $src && $with_i18n ) {
|
||
|
wp_set_script_translations( $script_handle, 'web-stories' );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $this->register_scripts[ $script_handle ];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enqueue a style.
|
||
|
*
|
||
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string $style_handle Name of the stylesheet. Should be unique.
|
||
|
* @param string $src Full URL of the stylesheet, or path of the stylesheet relative to the WordPress root directory.
|
||
|
* Default empty.
|
||
|
* @param string[] $deps Optional. An array of registered stylesheet handles this stylesheet depends on. Default empty array.
|
||
|
* @param string|bool|null $ver Optional. String specifying stylesheet version number, if it has one, which is added to the URL
|
||
|
* as a query string for cache busting purposes. If version is set to false, a version
|
||
|
* number is automatically added equal to current installed WordPress version.
|
||
|
* If set to null, no version is added.
|
||
|
* @param string $media Optional. The media for which this stylesheet has been defined.
|
||
|
* Default 'all'. Accepts media types like 'all', 'print' and 'screen', or media queries like
|
||
|
* '(orientation: portrait)' and '(max-width: 640px)'.
|
||
|
*/
|
||
|
public function enqueue_style( string $style_handle, string $src = '', array $deps = [], $ver = false, string $media = 'all' ): void {
|
||
|
$this->register_style( $style_handle, $src, $deps, $ver, $media );
|
||
|
wp_enqueue_style( $style_handle, $src, $deps, $ver, $media );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enqueue a script.
|
||
|
*
|
||
|
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string $script_handle Name of the script. Should be unique.
|
||
|
* @param string $src Full URL of the script, or path of the script relative to the WordPress root directory.
|
||
|
* Default empty.
|
||
|
* @param string[] $deps Optional. An array of registered script handles this script depends on. Default empty array.
|
||
|
* @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL
|
||
|
* as a query string for cache busting purposes. If version is set to false, a version
|
||
|
* number is automatically added equal to current installed WordPress version.
|
||
|
* If set to null, no version is added.
|
||
|
* @param bool $in_footer Optional. Whether to enqueue the script before </body> instead of in the <head>.
|
||
|
* Default 'false'.
|
||
|
* @param bool $with_i18n Optional. Whether to setup i18n for this asset. Default true.
|
||
|
*/
|
||
|
public function enqueue_script( string $script_handle, string $src = '', array $deps = [], $ver = false, bool $in_footer = false, bool $with_i18n = false ): void {
|
||
|
$this->register_script( $script_handle, $src, $deps, $ver, $in_footer, $with_i18n );
|
||
|
wp_enqueue_script( $script_handle, $src, $deps, $ver, $in_footer );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Remove admin styles.
|
||
|
*
|
||
|
* @since 1.8.0
|
||
|
*
|
||
|
* @param string[] $styles Array of styles to be removed.
|
||
|
*/
|
||
|
public function remove_admin_style( array $styles ): void {
|
||
|
wp_styles()->registered['wp-admin']->deps = array_diff( wp_styles()->registered['wp-admin']->deps, $styles );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the translations for a script and all of its chunks.
|
||
|
*
|
||
|
* @since 1.14.0
|
||
|
*
|
||
|
* @param string $script_handle Name of the script. Should be unique.
|
||
|
* @return array<int, mixed> Script translations.
|
||
|
*/
|
||
|
public function get_translations( string $script_handle ): array {
|
||
|
/**
|
||
|
* List of script chunks.
|
||
|
*
|
||
|
* @var false|string[]
|
||
|
*/
|
||
|
$chunks = wp_scripts()->get_data( $script_handle, 'chunks' );
|
||
|
|
||
|
if ( ! \is_array( $chunks ) ) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
$translations = [
|
||
|
(string) load_script_textdomain( $script_handle, 'web-stories' ),
|
||
|
];
|
||
|
|
||
|
/**
|
||
|
* Dynamic chunk name.
|
||
|
*
|
||
|
* @var string $dynamic_chunk
|
||
|
*/
|
||
|
foreach ( $chunks as $dynamic_chunk ) {
|
||
|
$translations[] = (string) load_script_textdomain( $dynamic_chunk, 'web-stories' );
|
||
|
}
|
||
|
|
||
|
return array_values(
|
||
|
array_map(
|
||
|
static fn( $translations ) => json_decode( $translations, true ),
|
||
|
array_filter( $translations )
|
||
|
)
|
||
|
);
|
||
|
}
|
||
|
}
|