Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support callables to provide the localization data #6

Merged
merged 1 commit into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ A library for managing asset registration and enqueuing in WordPress.
* [Conditional enqueuing](#conditional-enqueuing)
* [Firing a callback after enqueuing occurs](#firing-a-callback-after-enqueuing-occurs)
* [Output JS data](#output-js-data)
* [Using a callable to provide localization data](#using-a-callable-to-provide-localization-data)
* [Output content before/after a JS asset is output](#output-content-beforeafter-a-js-asset-is-output)
* [Style meta data](#style-meta-data)

Expand Down Expand Up @@ -500,6 +501,28 @@ 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.

#### Using a callable to provide localization data

If you need to provide localization data dynamically, you can use a callable to do so. The callable will be called
when the asset is enqueued and the return value will be used. The callable will be passed the asset as the first
argument and should return an array.

```php
Asset::add( 'my-script', 'js/some-asset.js' )
->add_localize_script(
'boomshakalaka.project.myScriptData',
function( Asset $asset ) {
return [
'animal' => 'cat',
'color' => 'orange',
];
}
)
->register();
```

Any valid callable can be used, including Closures, like in the example above.

### 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
Expand Down
6 changes: 4 additions & 2 deletions src/Assets/Asset.php
Original file line number Diff line number Diff line change
Expand Up @@ -414,11 +414,13 @@ public function call_after_enqueue( $callable ) {
* @since 1.0.0
*
* @param string $object_name JS object name.
* @param array $data Data assigned to the JS object.
* @param array|callable $data Data assigned to the JS object. If a callable is passed, it will be called
* when the asset is enqueued and the return value will be used. The callable
* will be passed the asset as the first argument and should return an array.
*
* @return static
*/
public function add_localize_script( string $object_name, array $data ) {
public function add_localize_script( string $object_name, $data ) {
if ( str_contains( $object_name, '.' ) ) {
$this->custom_localize_script_objects[] = [ $object_name, $data ];
} else {
Expand Down
7 changes: 6 additions & 1 deletion src/Assets/Assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ public function filter_add_localization_data( $tag, $handle ) {

// If we have a Callable as the Localize data we execute it.
if ( is_callable( $localize ) ) {
$localize = call_user_func( $localize, $asset );
$localize = $localize( $asset );
}

wp_localize_script( $asset->get_slug(), $key, $localize );
Expand All @@ -378,6 +378,11 @@ public function filter_add_localization_data( $tag, $handle ) {
* Print the dot.notation namespaced objects for the asset.
*/
foreach ( $custom_localize_scripts as [$object_name, $data] ) {
// If we have a Callable as the Localize data we execute it.
if ( is_callable( $data ) ) {
$data = $data( $asset );
}

$localized_key = "{$asset->get_slug()}::{$object_name}";

if ( in_array( $localized_key, $this->localized, true ) ) {
Expand Down
51 changes: 51 additions & 0 deletions tests/wpunit/AssetsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,55 @@ public function should_allow_localizing_data_in_normal_and_namespaced_form_for_s
$apply_filters
);
}

/**
* It should allow localizing data using a Closure
*
* @test
*/
public function should_allow_localizing_data_using_a_closure(): void {
$resolved_one = false;
$resolved_two = false;
$data_callback_one = function () use ( &$resolved_one ) {
$resolved_one = true;

return [
'animal' => 'cat',
'color' => 'orange',
];
};
$data_callback_two = function () use ( &$resolved_two ) {
$resolved_two = true;

return [
'animal' => 'dog',
'color' => 'green',
];
};

Asset::add( 'my-script-with-closure-data', 'test-script.js' )
->add_localize_script( 'scriptWithClosureData', $data_callback_one )
->add_localize_script( 'acme.project.closureData', $data_callback_two )
->register();

$this->assertFalse( $resolved_one, 'The first callback should not have been resolved yet.' );
$this->assertFalse( $resolved_two, 'The second callback should not have been resolved yet.' );

$apply_filters = apply_filters( 'script_loader_tag', '', 'my-script-with-closure-data' );
$this->assertEquals( <<< SCRIPT
<script id="my-script-with-closure-data-js-extra">
var scriptWithClosureData = {"animal":"cat","color":"orange"};
</script>
<script id="my-script-with-closure-data-ns-extra">
window.acme = window.acme || {};
window.acme.project = window.acme.project || {};
window.acme.project.closureData = Object.assign(window.acme.project.closureData || {}, {"animal":"dog","color":"green"});
</script>
SCRIPT,
$apply_filters
);

$this->assertTrue( $resolved_one );
$this->assertTrue( $resolved_two );
}
}
Loading