diff --git a/README.md b/README.md
index 70045c8..093703c 100644
--- a/README.md
+++ b/README.md
@@ -427,6 +427,79 @@ Asset::add( 'my-asset', 'css/some-asset.css' )
->register();
```
+If you specify an object name using dot notation, then the object will be printed on the page "merging" it with other, pre-existing objects.
+In the following example, the `boomshakalaka.project` object will be created and then the `firstScriptData` and `secondScriptData` objects will be added to it:
+
+```php
+use Boomshakalaka\StellarWP\Assets\Asset;
+
+Asset::add( 'my-first-script', 'js/first-script.js' )
+ ->add_localize_script(
+ 'boomshakalaka.project.firstScriptData',
+ [
+ 'animal' => 'cat',
+ 'color' => 'orange',
+ ]
+ )
+ ->register();
+
+Asset::add( 'my-second-script', 'js/second-script.js' )
+ ->add_localize_script(
+ 'boomshakalaka.project.secondScriptData',
+ [
+ 'animal' => 'dog',
+ 'color' => 'green',
+ ]
+ )
+ ->register();
+
+Asset::add( 'my-second-script-mod', 'js/second-script-mod.js' )
+ ->add_localize_script(
+ 'boomshakalaka.project.secondScriptData',
+ [
+ 'animal' => 'horse'
+ ]
+ )
+ ->register();
+```
+
+The resulting output will be:
+
+```html
+
+
+
+
+
+
+```
+
+Note the `my-second-script-mod` handle is overriding a specific nested
+key, `boomshakalaka.project.secondScriptData.animal`, in the `boomshakalaka.project.secondScriptData` object while
+preserving the other keys.
+
### Output content before/after a JS asset is output
There may be times when you wish to output markup or text immediately before or immediately after outputting the JS
diff --git a/src/Assets/Asset.php b/src/Assets/Asset.php
index ab82dcb..d93b479 100644
--- a/src/Assets/Asset.php
+++ b/src/Assets/Asset.php
@@ -115,7 +115,7 @@ class Asset {
/**
* The asset wp_localize_script objects for this asset.
*
- * @var array
+ * @var array
*/
protected array $wp_localize_script_objects = [];
@@ -217,6 +217,13 @@ class Asset {
*/
protected ?string $version = null;
+ /**
+ * An array of objects to localized using dot-notation and namespaces.
+ *
+ * @var array
+ */
+ protected array $custom_localize_script_objects = [];
+
/**
* Constructor.
*
@@ -412,7 +419,12 @@ public function call_after_enqueue( $callable ) {
* @return static
*/
public function add_localize_script( string $object_name, array $data ) {
- $this->wp_localize_script_objects[ $object_name ] = $data;
+ if ( str_contains( $object_name, '.' ) ) {
+ $this->custom_localize_script_objects[] = [ $object_name, $data ];
+ } else {
+ $this->wp_localize_script_objects[ $object_name ] = $data;
+ }
+
return $this;
}
@@ -520,6 +532,15 @@ public function get_localize_scripts(): array {
return $this->wp_localize_script_objects;
}
+ /**
+ * Get the asset wp_localize_script_objects.
+ *
+ * @return array A set of data to localized using dot-notation.
+ */
+ public function get_custom_localize_scripts(): array {
+ return $this->custom_localize_script_objects;
+ }
+
/**
* Get the asset media setting.
*
diff --git a/src/Assets/Assets.php b/src/Assets/Assets.php
index fb0da65..afdf42e 100755
--- a/src/Assets/Assets.php
+++ b/src/Assets/Assets.php
@@ -48,11 +48,39 @@ class Assets {
protected $localized = [];
/**
- * Singleton instance.
+ * Constructor.
+ *
+ * @param string|null $base_path Base path to the directory.
+ * @param string|null $assets_url Directory to the assets.
+ *
+ * @since 1.0.0
+ *
+ */
+ public function __construct( ?string $base_path = null, ?string $assets_url = null ) {
+ $this->base_path = $base_path ?: Config::get_path();
+ $this->assets_url = $assets_url ?: trailingslashit( get_site_url() . $this->base_path );
+ $this->version = Config::get_version();
+ $this->controller = new Controller( $this );
+ $this->controller->register();
+ }
+
+ /**
+ * Helper method to get the instance object. Alias of ::init().
*
+ * @return Assets
* @since 1.0.0
*
+ */
+ public static function instance(): Assets {
+ return static::init();
+ }
+
+ /**
+ * Singleton instance.
+ *
* @return Assets
+ * @since 1.0.0
+ *
*/
public static function init(): Assets {
if ( ! isset( static::$instance ) ) {
@@ -63,42 +91,66 @@ public static function init(): Assets {
}
/**
- * Helper method to get the instance object. Alias of ::init().
+ * Create an asset.
+ *
+ * @param string $slug The asset slug.
+ * @param string $file The asset file path.
+ * @param string|null $version The asset version.
+ * @param string|null $plugin_path The path to the root of the plugin.
+ */
+ public static function asset( string $slug, string $file, string $version = null, string $plugin_path = null ) {
+ return static::init()->add( new Asset( $slug, $file, $version, $plugin_path ) );
+ }
+
+ /**
+ * Register an Asset and attach a callback to the required action to display it correctly.
*
+ * @param Asset $asset Register an asset.
+ *
+ * @return Asset|false The registered object or false on error.
* @since 1.0.0
*
- * @return Assets
*/
- public static function instance(): Assets {
- return static::init();
+ public function add( Asset $asset ) {
+ // Prevent weird stuff here.
+ $slug = $asset->get_slug();
+
+ if ( $this->exists( $slug ) ) {
+ return $this->get( $slug );
+ }
+
+ // Set the Asset on the array of notices.
+ $this->assets[ $slug ] = $asset;
+
+ // Return the Slug because it might be modified.
+ return $asset;
}
/**
- * Constructor.
+ * Checks if an Asset exists.
+ *
+ * @param string|array $slug Slug of the Asset.
*
+ * @return bool
* @since 1.0.0
*
- * @param string|null $base_path Base path to the directory.
- * @param string|null $assets_url Directory to the assets.
*/
- public function __construct( ?string $base_path = null, ?string $assets_url = null ) {
- $this->base_path = $base_path ?: Config::get_path();
- $this->assets_url = $assets_url ?: trailingslashit( get_site_url() . $this->base_path );
- $this->version = Config::get_version();
- $this->controller = new Controller( $this );
- $this->controller->register();
+ public function exists( $slug ) {
+ $slug = sanitize_key( $slug );
+
+ return isset( $this->assets[ $slug ] );
}
/**
* Depending on how certain scripts are loaded and how much cross-compatibility is required we need to be able to
* create noConflict backups and restore other scripts, which normally need to be printed directly on the scripts.
*
- * @since 1.0.0
- *
- * @param string $tag Tag we are filtering.
+ * @param string $tag Tag we are filtering.
* @param string $handle Which is the ID/Handle of the tag we are about to print.
*
* @return string Script tag with the before and after strings attached to it.
+ * @since 1.0.0
+ *
*/
public function filter_print_before_after_script( $tag, $handle ): string {
// Only filter for our own filters.
@@ -134,15 +186,137 @@ public function filter_print_before_after_script( $tag, $handle ): string {
}
/**
- * Handles adding localization data, when attached to `script_loader_tag` which allows dependencies to load in their
- * localization data as well.
+ * Get the Asset Object configuration.
+ *
+ * @param string|array $slug Slug of the Asset.
+ * @param boolean $sort If we should do any sorting before returning.
+ *
+ * @return array|Asset Array of asset objects, single asset object, or null if looking for a single asset but
+ * it was not in the array of objects.
+ * @since 1.0.0
+ *
+ */
+ public function get( $slug = null, $sort = true ) {
+ $obj = $this;
+
+ if ( is_null( $slug ) ) {
+ if ( $sort ) {
+ $cache_key_count = __METHOD__ . ':count';
+ // Sorts by priority.
+ $cache_count = $this->get_var( $cache_key_count, 0 );
+ $count = count( $this->assets );
+
+ if ( $count !== $cache_count ) {
+ uasort( $this->assets, static function ( $a, $b ) use ( $obj ) {
+ return $obj->sort_by_priority( $a, $b, 'get_priority' );
+ } );
+ $this->set_var( $cache_key_count, $count );
+ }
+ }
+
+ return $this->assets;
+ }
+
+ // If slug is an array we return all of those.
+ if ( is_array( $slug ) ) {
+ $assets = [];
+ foreach ( $slug as $asset_slug ) {
+ $asset_slug = sanitize_key( $asset_slug );
+ // Skip empty assets.
+ if ( empty( $this->assets[ $asset_slug ] ) ) {
+ continue;
+ }
+
+ $assets[ $asset_slug ] = $this->assets[ $asset_slug ];
+ }
+
+ if ( empty( $assets ) ) {
+ return [];
+ }
+
+ if ( $sort ) {
+ // Sorts by priority.
+ uasort( $assets, static function ( $a, $b ) use ( $obj ) {
+ return $obj->sort_by_priority( $a, $b, 'get_priority' );
+ } );
+ }
+
+ return $assets;
+ }
+
+ // Prevent weird stuff here.
+ $slug = sanitize_key( $slug );
+
+ if ( ! empty( $this->assets[ $slug ] ) ) {
+ return $this->assets[ $slug ];
+ }
+
+ return [];
+ }
+
+ /**
+ * Gets a memoized value.
+ *
+ * @param string $var Var name.
+ * @param mixed|null $default Default value.
+ *
+ * @return mixed|null
+ */
+ public function get_var( string $var, $default = null ) {
+ return $this->memoized[ $var ] ?? $default;
+ }
+
+ /**
+ * Sorting function based on Priority
+ *
+ * @param object|array $b Second subject to compare.
+ * @param object|array $a First Subject to compare.
+ * @param string $method Method to use for sorting.
*
+ * @return int
* @since 1.0.0
*
- * @param string $tag Tag we are filtering.
+ */
+ public function sort_by_priority( $a, $b, $method = null ) {
+ if ( is_array( $a ) ) {
+ $a_priority = $a['priority'];
+ } else {
+ $a_priority = $method ? $a->$method() : $a->priority;
+ }
+
+ if ( is_array( $b ) ) {
+ $b_priority = $b['priority'];
+ } else {
+ $b_priority = $method ? $b->$method() : $b->priority;
+ }
+
+ if ( (int) $a_priority === (int) $b_priority ) {
+ return 0;
+ }
+
+ return (int) $a_priority > (int) $b_priority ? 1 : - 1;
+ }
+
+ /**
+ * Sets a memoized value.
+ *
+ * @param string $var Var name.
+ * @param mixed|null $value The value.
+ */
+ public function set_var( string $var, $value = null ) {
+ $this->memoized[ $var ] = $value;
+ }
+
+ /**
+ * Handles adding localization data, when attached to `script_loader_tag` which allows dependencies to load in their
+ * localization data as well.
+ *
+ * @param string $tag Tag we are filtering.
* @param string $handle Which is the ID/Handle of the tag we are about to print.
*
* @return string Script tag with the localization variable HTML attached to it.
+ * @since 1.0.0
+ *
*/
public function filter_add_localization_data( $tag, $handle ) {
// Only filter for own filters.
@@ -155,56 +329,95 @@ public function filter_add_localization_data( $tag, $handle ) {
return $tag;
}
+ $localize_scripts = $asset->get_localize_scripts();
+ $custom_localize_scripts = $asset->get_custom_localize_scripts();
+
// Only localize on JS and if we have data.
- if ( empty( $asset->get_localize_scripts() ) ) {
+ if ( empty( $localize_scripts ) && empty( $custom_localize_scripts ) ) {
return $tag;
}
- global $wp_scripts;
+ $localization_html = '';
- $localization = $asset->get_localize_scripts();
+ if ( count( $localize_scripts ) ) {
+ global $wp_scripts;
- /**
- * Check to ensure we haven't already localized it before.
- *
- * @since 1.0.0
+ $localization = $localize_scripts;
+
+ /**
+ * Check to ensure we haven't already localized it before.
+ *
+ * @since 1.0.0
+ */
+ foreach ( $localization as $key => $localize ) {
+
+ if ( in_array( $key, $this->localized ) ) {
+ continue;
+ }
+
+ // If we have a Callable as the Localize data we execute it.
+ if ( is_callable( $localize ) ) {
+ $localize = call_user_func( $localize, $asset );
+ }
+
+ wp_localize_script( $asset->get_slug(), $key, $localize );
+
+ $this->localized[] = $key;
+ }
+
+ // Fetch the HTML for all the localized data.
+ ob_start();
+ $wp_scripts->print_extra_script( $asset->get_slug(), true );
+ $localization_html = ob_get_clean();
+
+ // After printing it remove data;|
+ $wp_scripts->add_data( $asset->get_slug(), 'data', '' );
+ }
+
+ /*
+ * Print the dot.notation namespaced objects for the asset.
*/
- foreach ( $localization as $key => $localize ) {
+ foreach ( $custom_localize_scripts as [$object_name, $data] ) {
+ $localized_key = "{$asset->get_slug()}::{$object_name}";
- if ( in_array( $key, $this->localized ) ) {
+ if ( in_array( $localized_key, $this->localized, true ) ) {
continue;
}
- // If we have a Callable as the Localize data we execute it.
- if ( is_callable( $localize ) ) {
- $localize = call_user_func( $localize, $asset );
+ $frags = explode( '.', $object_name );
+ $js_data = '';
+ $var_name = '';
+ foreach ( $frags as $i => $frag ) {
+ $var_name = ltrim( $var_name . '.' . $frag, '.' );
+ if ( isset( $frags[ $i + 1 ] ) ) {
+ $js_data .= PHP_EOL . sprintf( 'window.%1$s = window.%1$s || {};', $var_name );
+ } else {
+ $json_data = wp_json_encode( $data );
+ $js_data .= PHP_EOL . sprintf( 'window.%1$s = Object.assign(window.%1$s || {}, %2$s);', $var_name, $json_data );
+ }
}
- wp_localize_script( $asset->get_slug(), $key, $localize );
+ $localization_html .= sprintf(
+ '',
+ $asset->get_slug(),
+ $js_data
+ );
- $this->localized[] = $key;
+ $this->localized[] = $localized_key;
}
- // Fetch the HTML for all the localized data.
- ob_start();
- $wp_scripts->print_extra_script( $asset->get_slug(), true );
- $localization_html = ob_get_clean();
-
- // After printing it remove data;|
- $wp_scripts->add_data( $asset->get_slug(), 'data', '' );
-
return $localization_html . $tag;
}
/**
* Filters the Script tags to attach Async and/or Defer based on the rules we set in our Asset class.
*
- * @since 1.0.0
- *
- * @param string $tag Tag we are filtering.
+ * @param string $tag Tag we are filtering.
* @param string $handle Which is the ID/Handle of the tag we are about to print.
*
* @return string Script tag with the defer and/or async attached.
+ * @since 1.0.0
+ *
*/
public function filter_tag_async_defer( $tag, $handle ) {
// Only filter for our own filters.
@@ -241,12 +454,12 @@ public function filter_tag_async_defer( $tag, $handle ) {
/**
* Filters the Script tags to attach type=module based on the rules we set in our Asset class.
*
- * @since 1.0.0
- *
- * @param string $tag Tag we are filtering.
+ * @param string $tag Tag we are filtering.
* @param string $handle Which is the ID/Handle of the tag we are about to print.
*
* @return string Script tag with the type=module
+ * @since 1.0.0
+ *
*/
public function filter_modify_to_module( $tag, $handle ) {
// Only filter for own own filters.
@@ -277,118 +490,87 @@ public function filter_modify_to_module( $tag, $handle ) {
}
/**
- * Register the Assets on the correct hooks.
+ * Enqueues registered assets based on their groups.
+ *
+ * @param string|array $groups Which groups will be enqueued.
+ * @param bool $should_enqueue_no_matter_what Whether to ignore conditional requirements when enqueuing.
*
* @since 1.0.0
*
- * @param array|Asset|null $assets Array of asset objects, single asset object, or null.
+ * @uses Assets::enqueue()
*
- * @return void
*/
- public function register_in_wp( $assets = null ) {
- if ( is_null( $assets ) ) {
- $assets = $this->get();
- }
-
- if ( ! is_array( $assets ) ) {
- $assets = [ $assets ];
- }
+ public function enqueue_group( $groups, bool $should_enqueue_no_matter_what = false ) {
+ $assets = $this->get( null, false );
+ $enqueue = [];
foreach ( $assets as $asset ) {
- // Asset is already registered.
- if ( $asset->is_registered() ) {
+ if ( empty( $asset->get_groups() ) ) {
continue;
}
- if ( 'js' === $asset->get_type() ) {
- // Script is already registered.
- if ( wp_script_is( $asset->get_slug(), 'registered' ) ) {
- continue;
- }
-
- $dependencies = $asset->get_dependencies();
+ $intersect = array_intersect( (array) $groups, $asset->get_groups() );
- // If the asset is a callable, we call the function,
- // passing it the asset and expecting back an array of dependencies.
- if ( is_callable( $asset->get_dependencies() ) ) {
- $dependencies = call_user_func( $asset->get_dependencies(), [ $asset ] );
- }
-
- wp_register_script( $asset->get_slug(), $asset->get_url(), $dependencies, $asset->get_version(), $asset->is_in_footer() );
-
- // Register that this asset is actually registered on the WP methods.
- // @phpstan-ignore-next-line
- if ( wp_script_is( $asset->get_slug(), 'registered' ) ) {
- $asset->set_as_registered();
- }
- } else {
- // Style is already registered.
- if ( wp_style_is( $asset->get_slug(), 'registered' ) ) {
- continue;
- }
-
- wp_register_style( $asset->get_slug(), $asset->get_url(), $asset->get_dependencies(), $asset->get_version(), $asset->get_media() );
-
- // Register that this asset is actually registered on the WP methods.
- // @phpstan-ignore-next-line
- if ( wp_style_is( $asset->get_slug(), 'registered' ) ) {
- $asset->set_as_registered();
- }
-
- $style_data = $asset->get_style_data();
- if ( $style_data ) {
- foreach ( $style_data as $datum_key => $datum_value ) {
- wp_style_add_data( $asset->get_slug(), $datum_key, $datum_value );
- }
- }
- }
-
- // If we don't have an action we don't even register the action to enqueue.
- if ( empty( $asset->get_action() ) ) {
+ if ( empty( $intersect ) ) {
continue;
}
-
- // Now add an action to enqueue the registered assets.
- foreach ( (array) $asset->get_action() as $action ) {
- // Enqueue the registered assets at the appropriate time.
- if ( did_action( $action ) > 0 ) {
- $this->enqueue();
- } else {
- add_action( $action, [ $this, 'enqueue' ], $asset->get_priority(), 0 );
- }
- }
+ $enqueue[] = $asset->get_slug();
}
+
+ $this->enqueue( $enqueue, $should_enqueue_no_matter_what );
}
/**
- * Enqueues registered assets based on their groups.
+ * Enqueues registered assets.
*
- * @since 1.0.0
+ * This method is called on whichever action (if any) was declared during registration.
+ *
+ * It can also be called directly with a list of asset slugs to forcibly enqueue, which may be
+ * useful where an asset is required in a situation not anticipated when it was originally
+ * registered.
*
- * @param string|array $groups Which groups will be enqueued.
- * @param bool $should_enqueue_no_matter_what Whether to ignore conditional requirements when enqueuing.
+ * @param string|array $assets_to_enqueue Which assets will be enqueued.
+ * @param bool $should_enqueue_no_matter_what Whether to ignore conditional requirements when enqueuing.
*
- * @uses Assets::enqueue()
+ * @since 1.0.0
*
*/
- public function enqueue_group( $groups, bool $should_enqueue_no_matter_what = false ) {
- $assets = $this->get( null, false );
- $enqueue = [];
+ public function enqueue( $assets_to_enqueue = null, bool $should_enqueue_no_matter_what = false ) {
+ $assets_to_enqueue = array_filter( (array) $assets_to_enqueue );
+ if ( ! empty( $assets_to_enqueue ) ) {
+ $assets = (array) $this->get( $assets_to_enqueue );
+ } else {
+ $assets = $this->get();
+ }
foreach ( $assets as $asset ) {
- if ( empty( $asset->get_groups() ) ) {
- continue;
+ $slug = $asset->get_slug();
+
+ // Should this asset be enqueued regardless of the current filter/any conditional requirements?
+ $must_enqueue = in_array( $slug, $assets_to_enqueue );
+ $actions = $asset->get_action();
+
+ if ( empty( $actions ) && $must_enqueue ) {
+ $this->do_enqueue( $asset, $must_enqueue );
}
- $intersect = array_intersect( (array) $groups, $asset->get_groups() );
+ foreach ( $asset->get_action() as $action ) {
+ $in_filter = current_filter() === $action;
+ $did_action = did_action( $action ) > 0;
- if ( empty( $intersect ) ) {
- continue;
+ // Skip if we are not on the correct filter (unless we are forcibly enqueuing).
+ if ( ! $in_filter && ! $must_enqueue && ! $did_action ) {
+ continue;
+ }
+
+ // If any single conditional returns true, then we need to enqueue the asset.
+ if ( empty( $action ) && ! $must_enqueue ) {
+ continue;
+ }
+
+ $this->do_enqueue( $asset, $should_enqueue_no_matter_what );
}
- $enqueue[] = $asset->get_slug();
}
-
- $this->enqueue( $enqueue, $should_enqueue_no_matter_what );
}
/**
@@ -400,10 +582,11 @@ public function enqueue_group( $groups, bool $should_enqueue_no_matter_what = fa
* useful where an asset is required in a situation not anticipated when it was originally
* registered.
*
+ * @param Asset $asset Asset to enqueue.
+ * @param bool $force_enqueue Whether to ignore conditional requirements when enqueuing.
+ *
* @since 1.0.0
*
- * @param Asset $asset Asset to enqueue.
- * @param bool $force_enqueue Whether to ignore conditional requirements when enqueuing.
*/
protected function do_enqueue( Asset $asset, bool $force_enqueue = false ): void {
$hook_prefix = Config::get_hook_prefix();
@@ -431,20 +614,22 @@ protected function do_enqueue( Asset $asset, bool $force_enqueue = false ): void
/**
* Allows developers to hook-in and prevent an asset from being loaded.
*
+ * @param bool $enqueue If we should enqueue or not a given asset.
+ * @param object $asset Which asset we are dealing with.
+ *
* @since 1.0.0
*
- * @param bool $enqueue If we should enqueue or not a given asset.
- * @param object $asset Which asset we are dealing with.
*/
$enqueue = (bool) apply_filters( "stellarwp/assets/{$hook_prefix}/enqueue", $enqueue, $asset );
/**
* Allows developers to hook-in and prevent an asset from being loaded.
*
+ * @param bool $enqueue If we should enqueue or not a given asset.
+ * @param object $asset Which asset we are dealing with.
+ *
* @since 1.0.0
*
- * @param bool $enqueue If we should enqueue or not a given asset.
- * @param object $asset Which asset we are dealing with.
*/
$enqueue = (bool) apply_filters( "stellarwp/assets/{$hook_prefix}/enqueue_{$slug}", $enqueue, $asset );
@@ -482,101 +667,97 @@ protected function do_enqueue( Asset $asset, bool $force_enqueue = false ): void
}
/**
- * Enqueues registered assets.
- *
- * This method is called on whichever action (if any) was declared during registration.
+ * Register the Assets on the correct hooks.
*
- * It can also be called directly with a list of asset slugs to forcibly enqueue, which may be
- * useful where an asset is required in a situation not anticipated when it was originally
- * registered.
+ * @param array|Asset|null $assets Array of asset objects, single asset object, or null.
*
+ * @return void
* @since 1.0.0
*
- * @param string|array $assets_to_enqueue Which assets will be enqueued.
- * @param bool $should_enqueue_no_matter_what Whether to ignore conditional requirements when enqueuing.
*/
- public function enqueue( $assets_to_enqueue = null, bool $should_enqueue_no_matter_what = false ) {
- $assets_to_enqueue = array_filter( (array) $assets_to_enqueue );
- if ( ! empty( $assets_to_enqueue ) ) {
- $assets = (array) $this->get( $assets_to_enqueue );
- } else {
+ public function register_in_wp( $assets = null ) {
+ if ( is_null( $assets ) ) {
$assets = $this->get();
}
+ if ( ! is_array( $assets ) ) {
+ $assets = [ $assets ];
+ }
+
foreach ( $assets as $asset ) {
- $slug = $asset->get_slug();
+ // Asset is already registered.
+ if ( $asset->is_registered() ) {
+ continue;
+ }
- // Should this asset be enqueued regardless of the current filter/any conditional requirements?
- $must_enqueue = in_array( $slug, $assets_to_enqueue );
- $actions = $asset->get_action();
+ if ( 'js' === $asset->get_type() ) {
+ // Script is already registered.
+ if ( wp_script_is( $asset->get_slug(), 'registered' ) ) {
+ continue;
+ }
- if ( empty( $actions ) && $must_enqueue ) {
- $this->do_enqueue( $asset, $must_enqueue );
- }
+ $dependencies = $asset->get_dependencies();
- foreach ( $asset->get_action() as $action ) {
- $in_filter = current_filter() === $action;
- $did_action = did_action( $action ) > 0;
+ // If the asset is a callable, we call the function,
+ // passing it the asset and expecting back an array of dependencies.
+ if ( is_callable( $asset->get_dependencies() ) ) {
+ $dependencies = call_user_func( $asset->get_dependencies(), [ $asset ] );
+ }
- // Skip if we are not on the correct filter (unless we are forcibly enqueuing).
- if ( ! $in_filter && ! $must_enqueue && ! $did_action ) {
+ wp_register_script( $asset->get_slug(), $asset->get_url(), $dependencies, $asset->get_version(), $asset->is_in_footer() );
+
+ // Register that this asset is actually registered on the WP methods.
+ // @phpstan-ignore-next-line
+ if ( wp_script_is( $asset->get_slug(), 'registered' ) ) {
+ $asset->set_as_registered();
+ }
+ } else {
+ // Style is already registered.
+ if ( wp_style_is( $asset->get_slug(), 'registered' ) ) {
continue;
}
- // If any single conditional returns true, then we need to enqueue the asset.
- if ( empty( $action ) && ! $must_enqueue ) {
- continue;
+ wp_register_style( $asset->get_slug(), $asset->get_url(), $asset->get_dependencies(), $asset->get_version(), $asset->get_media() );
+
+ // Register that this asset is actually registered on the WP methods.
+ // @phpstan-ignore-next-line
+ if ( wp_style_is( $asset->get_slug(), 'registered' ) ) {
+ $asset->set_as_registered();
}
- $this->do_enqueue( $asset, $should_enqueue_no_matter_what );
+ $style_data = $asset->get_style_data();
+ if ( $style_data ) {
+ foreach ( $style_data as $datum_key => $datum_value ) {
+ wp_style_add_data( $asset->get_slug(), $datum_key, $datum_value );
+ }
+ }
}
- }
- }
- /**
- * Register an Asset and attach a callback to the required action to display it correctly.
- *
- * @since 1.0.0
- *
- * @param Asset $asset Register an asset.
- *
- * @return Asset|false The registered object or false on error.
- */
- public function add( Asset $asset ) {
- // Prevent weird stuff here.
- $slug = $asset->get_slug();
+ // If we don't have an action we don't even register the action to enqueue.
+ if ( empty( $asset->get_action() ) ) {
+ continue;
+ }
- if ( $this->exists( $slug ) ) {
- return $this->get( $slug );
+ // Now add an action to enqueue the registered assets.
+ foreach ( (array) $asset->get_action() as $action ) {
+ // Enqueue the registered assets at the appropriate time.
+ if ( did_action( $action ) > 0 ) {
+ $this->enqueue();
+ } else {
+ add_action( $action, [ $this, 'enqueue' ], $asset->get_priority(), 0 );
+ }
+ }
}
-
- // Set the Asset on the array of notices.
- $this->assets[ $slug ] = $asset;
-
- // Return the Slug because it might be modified.
- return $asset;
- }
-
- /**
- * Create an asset.
- *
- * @param string $slug The asset slug.
- * @param string $file The asset file path.
- * @param string|null $version The asset version.
- * @param string|null $plugin_path The path to the root of the plugin.
- */
- public static function asset( string $slug, string $file, string $version = null, string $plugin_path = null ) {
- return static::init()->add( new Asset( $slug, $file, $version, $plugin_path ) );
}
/**
* Removes an Asset from been registered and enqueue.
*
- * @since 1.0.0
- *
* @param string $slug Slug of the Asset.
*
* @return bool
+ * @since 1.0.0
+ *
*/
public function remove( $slug ) {
if ( ! $this->exists( $slug ) ) {
@@ -594,101 +775,8 @@ public function remove( $slug ) {
}
unset( $this->assets[ $slug ] );
- return true;
- }
-
- /**
- * Get the Asset Object configuration.
- *
- * @since 1.0.0
- *
- * @param string|array $slug Slug of the Asset.
- * @param boolean $sort If we should do any sorting before returning.
- *
- * @return array|Asset Array of asset objects, single asset object, or null if looking for a single asset but
- * it was not in the array of objects.
- */
- public function get( $slug = null, $sort = true ) {
- $obj = $this;
-
- if ( is_null( $slug ) ) {
- if ( $sort ) {
- $cache_key_count = __METHOD__ . ':count';
- // Sorts by priority.
- $cache_count = $this->get_var( $cache_key_count, 0 );
- $count = count( $this->assets );
-
- if ( $count !== $cache_count ) {
- uasort( $this->assets, static function( $a, $b ) use ( $obj ) {
- return $obj->sort_by_priority( $a, $b, 'get_priority' );
- } );
- $this->set_var( $cache_key_count, $count );
- }
- }
- return $this->assets;
- }
-
- // If slug is an array we return all of those.
- if ( is_array( $slug ) ) {
- $assets = [];
- foreach ( $slug as $asset_slug ) {
- $asset_slug = sanitize_key( $asset_slug );
- // Skip empty assets.
- if ( empty( $this->assets[ $asset_slug ] ) ) {
- continue;
- }
- $assets[ $asset_slug ] = $this->assets[ $asset_slug ];
- }
-
- if ( empty( $assets ) ) {
- return [];
- }
-
- if ( $sort ) {
- // Sorts by priority.
- uasort( $assets, static function( $a, $b ) use ( $obj ) {
- return $obj->sort_by_priority( $a, $b, 'get_priority' );
- } );
- }
-
- return $assets;
- }
-
- // Prevent weird stuff here.
- $slug = sanitize_key( $slug );
-
- if ( ! empty( $this->assets[ $slug ] ) ) {
- return $this->assets[ $slug ];
- }
-
- return [];
- }
-
- /**
- * Gets a memoized value.
- *
- * @param string $var Var name.
- * @param mixed|null $default Default value.
- *
- * @return mixed|null
- */
- public function get_var( string $var, $default = null ) {
- return $this->memoized[ $var ] ?? $default;
- }
-
- /**
- * Checks if an Asset exists.
- *
- * @since 1.0.0
- *
- * @param string|array $slug Slug of the Asset.
- *
- * @return bool
- */
- public function exists( $slug ) {
- $slug = sanitize_key( $slug );
- return isset( $this->assets[ $slug ] );
+ return true;
}
/**
@@ -696,23 +784,23 @@ public function exists( $slug ) {
*
* The method will force the scripts and styles to print overriding their registration and conditional.
*
- * @since 1.0.0
- *
* @param string|array $group Which group(s) should be enqueued.
- * @param bool $echo Whether to print the group(s) tag(s) to the page or not; default to `true` to
+ * @param bool $echo Whether to print the group(s) tag(s) to the page or not; default to `true` to
* print the HTML `script` (JS) and `link` (CSS) tags to the page.
*
* @return string The `script` and `link` HTML tags produced for the group(s).
+ * @since 1.0.0
+ *
*/
public function print_group( $group, $echo = true ) {
$all_assets = $this->get();
$groups = (array) $group;
- $to_print = array_filter( $all_assets, static function( Asset $asset ) use ( $groups ) {
+ $to_print = array_filter( $all_assets, static function ( Asset $asset ) use ( $groups ) {
$asset_groups = $asset->get_groups();
return ! empty( $asset_groups ) && array_intersect( $asset_groups, $groups );
} );
- $by_type = array_reduce( $to_print, static function( array $acc, Asset $asset ) {
+ $by_type = array_reduce( $to_print, static function ( array $acc, Asset $asset ) {
$acc[ $asset->get_type() ][] = $asset->get_slug();
return $acc;
@@ -741,45 +829,4 @@ public function print_group( $group, $echo = true ) {
return $tags;
}
- /**
- * Sets a memoized value.
- *
- * @param string $var Var name.
- * @param mixed|null $value The value.
- */
- public function set_var( string $var, $value = null ) {
- $this->memoized[ $var ] = $value;
- }
-
- /**
- * Sorting function based on Priority
- *
- * @since 1.0.0
- *
- * @param object|array $b Second subject to compare.
- * @param object|array $a First Subject to compare.
- * @param string $method Method to use for sorting.
- *
- * @return int
- */
- public function sort_by_priority( $a, $b, $method = null ) {
- if ( is_array( $a ) ) {
- $a_priority = $a['priority'];
- } else {
- $a_priority = $method ? $a->$method() : $a->priority;
- }
-
- if ( is_array( $b ) ) {
- $b_priority = $b['priority'];
- } else {
- $b_priority = $method ? $b->$method() : $b->priority;
- }
-
- if ( (int) $a_priority === (int) $b_priority ) {
- return 0;
- }
-
- return (int) $a_priority > (int) $b_priority ? 1 : -1;
- }
-
}
diff --git a/tests/wpunit/AssetsTest.php b/tests/wpunit/AssetsTest.php
index b82b83a..3345662 100644
--- a/tests/wpunit/AssetsTest.php
+++ b/tests/wpunit/AssetsTest.php
@@ -1,4 +1,5 @@
assertFalse( Assets::init()->exists( 'my-script' ) );
$this->assertFalse( wp_script_is( 'my-script', 'enqueued' ) );
}
+
+ /**
+ * It should localize data correctly
+ *
+ * @test
+ */
+ public function should_localize_data_correctly(): void {
+ Asset::add( 'my-first-script', 'first-script.js' )
+ ->add_localize_script( 'boomshakalakaProjectFirstScriptData', [
+ 'animal' => 'cat',
+ 'color' => 'orange',
+ ] )
+ ->register();
+ Asset::add( 'my-second-script', 'second-script.js' )
+ ->add_localize_script( 'boomshakalakaProjectSecondScriptData', [
+ 'animal' => 'dog',
+ 'color' => 'green',
+ ] )
+ ->register();
+ Asset::add( 'my-second-script-mod', 'second-script-mod.js' )
+ ->add_localize_script( 'boomshakalakaProjectSecondScriptModData', [
+ 'animal' => 'horse'
+ ] )
+ ->register();
+
+ $this->assertEquals( <<< SCRIPT
+
+
+SCRIPT,
+ apply_filters( 'script_loader_tag', '', 'my-first-script' )
+ );
+ $this->assertEquals( <<< SCRIPT
+
+
+SCRIPT,
+ apply_filters( 'script_loader_tag', '', 'my-second-script' )
+ );
+
+ $this->assertEquals( <<< SCRIPT
+
+
+SCRIPT,
+ apply_filters( 'script_loader_tag', '', 'my-second-script-mod' )
+ );
+ }
+
+ /**
+ * It should localize dot notation data correctly
+ *
+ * @test
+ */
+ public function should_localize_dot_notation_data_correctly(): void {
+ Asset::add( 'my-first-ns-script', 'first-script.js' )
+ ->add_localize_script( 'boomshakalaka.project.firstScriptData', [
+ 'animal' => 'cat',
+ 'color' => 'orange',
+ ] )
+ ->register();
+ Asset::add( 'my-second-ns-script', 'second-script.js' )
+ ->add_localize_script( 'boomshakalaka.project.secondScriptData', [
+ 'animal' => 'dog',
+ 'color' => 'green',
+ ] )
+ ->register();
+ Asset::add( 'my-second-ns-script-mod', 'second-script-mod.js' )
+ ->add_localize_script( 'boomshakalaka.project.secondScriptData', [
+ 'animal' => 'horse'
+ ] )
+ ->register();
+
+ $this->assertEquals( <<< SCRIPT
+
+SCRIPT,
+ apply_filters( 'script_loader_tag', '', 'my-first-ns-script' )
+ );
+ $this->assertEquals( <<< SCRIPT
+
+SCRIPT,
+ apply_filters( 'script_loader_tag', '', 'my-second-ns-script' )
+ );
+
+ $this->assertEquals( <<< SCRIPT
+
+SCRIPT,
+ apply_filters( 'script_loader_tag', '', 'my-second-ns-script-mod' )
+ );
+ }
+
+ /**
+ * It should allow localizing data in normal and namespaced form for same script
+ *
+ * @test
+ */
+ public function should_allow_localizing_data_in_normal_and_namespaced_form_for_same_script(): void {
+ Asset::add( 'my-test-script', 'test-script.js' )
+ ->add_localize_script( 'boomshakalakaProjectTestScriptData', [
+ 'animal' => 'cat',
+ 'color' => 'orange',
+ ] )
+ ->add_localize_script( 'boomshakalaka.project.testScriptData', [
+ 'animal' => 'dog',
+ 'color' => 'green',
+ ] )
+ ->register();
+
+ $apply_filters = apply_filters( 'script_loader_tag', '', 'my-test-script' );
+ $this->assertEquals( <<< SCRIPT
+
+
+SCRIPT,
+ $apply_filters
+ );
+ }
}