Skip to content

Commit

Permalink
Merge pull request #19 from stellarwp/feature/wp-scripts-asset-file
Browse files Browse the repository at this point in the history
Add support for *.asset.php files
  • Loading branch information
borkweb authored Sep 27, 2024
2 parents 1cd83c9 + fff9e8c commit 5127693
Show file tree
Hide file tree
Showing 10 changed files with 401 additions and 32 deletions.
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ A library for managing asset registration and enqueuing in WordPress.
* [`remove()`](#remove)
* [Advanced topics](#advanced-topics)
* [Minified files](#minified-files)
* [Support for wp-scripts](#support-for-wp-scripts)
* [Default example](#default-example)
* [Overriding the default asset file location](#overriding-the-default-asset-file-location)
* [Conditional enqueuing](#conditional-enqueuing)
* [Firing a callback after enqueuing occurs](#firing-a-callback-after-enqueuing-occurs)
* [Output JS data](#output-js-data)
Expand Down Expand Up @@ -225,6 +228,7 @@ Asset::add( 'my-asset', 'js/some-asset.js', $an_optional_version, $an_optional_p
->set_as_async( true )
->set_as_deferred( true )
->set_as_module( true )
->set_asset_file( 'other-asset-directory/some-asset' ) // This allows you to manually set the path to a *.asset.php file.
->set_condition( // This can be any callable that returns a boolean.
static function() {
return is_front_page() || is_single();
Expand Down Expand Up @@ -357,6 +361,50 @@ Asset::add( 'my-asset', 'js/some-asset.js' )
->register();
```

### Support for wp-scripts

This library supports `*.asset.php` files generated by `wp-scripts` out of the box. It will attempt to find the `*.asset.php` file in the same directory as the asset file you're registering, however, you can manually set the path to the asset file via `::set_asset_file()` if you need to.

#### Default example

Assume you have a `something.asset.php` file in the same directory as your `something.js` file. Within that asset file is the standard asset array that contains `dependencies` and `version` keys.

```php
Asset::add( 'my-thing', 'js/something.js' )
->register();
```

This will automatically use the `something.asset.php` file's `dependencies` and `version` values for the asset.

Shown below is an example of the directory structure:

```
my-plugin/
├── src/
│ ├── assets/
│ │ ├── js/
│ │ │ ├── something.js
│ │ │ └── something.asset.php
```

Within the `something.asset.php` file, you have the following:

```php
<?php return array('dependencies' => array('some-dependency'), 'version' => '5.0.0');
```

#### Overriding the default asset file location

You may need to override the default location of the asset file. You can do this by using the `::set_asset_file()` method.

```php
Asset::add( 'my-thing', 'js/something.js' )
->set_asset_file( 'other-asset-directory/something' )
->register();
```

Note: You can provide the JS file extension (`other-asset-directory/something.js`), the asset file extension (`other-asset-directory/something.asset.php`), or leave it off entirely (`other-asset-directory/something`).

### Conditional enqueuing

It is rare that you will want to enqueue an asset on every page load. Luckily, you can specify a condition for when an
Expand Down
198 changes: 176 additions & 22 deletions src/Assets/Asset.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,34 @@ class Asset {
*/
protected $after_enqueue;

/**
* The asset asset file contents.
*
* @var array
*/
protected array $asset_file_contents = [];

/**
* The asset file path.
*
* @var string
*/
protected string $asset_file_path = '';

/**
* The asset conditional callable.
*
* @var mixed
*/
protected $condition;

/**
* An array of objects to localized using dot-notation and namespaces.
*
* @var array<array{0: string, 1:mixed}>
*/
protected array $custom_localize_script_objects = [];

/**
* The asset dependencies.
*
Expand Down Expand Up @@ -217,13 +238,6 @@ class Asset {
*/
protected ?string $version = null;

/**
* An array of objects to localized using dot-notation and namespaces.
*
* @var array<array{0: string, 1:mixed}>
*/
protected array $custom_localize_script_objects = [];

/**
* Constructor.
*
Expand Down Expand Up @@ -312,13 +326,11 @@ public function add_to_group( string $group ) {
}

/**
* Builds the base asset URL.
* Builds the path information for the asset.
*
* @since 1.0.0
*
* @return string
* @return array<string,string>
*/
protected function build_asset_url(): string {
protected function build_resource_path_data(): array {
$resource = $this->get_file();
$root_path = $this->get_root_path();
$relative_path_to_assets = $this->is_vendor() ? '' : null;
Expand All @@ -327,11 +339,11 @@ protected function build_asset_url(): string {
$root_path = Config::get_path();
}

$plugin_base_url = Config::get_url( $root_path );
$hook_prefix = Config::get_hook_prefix();
$extension = pathinfo( $resource, PATHINFO_EXTENSION );
$resource_path = $relative_path_to_assets;
$type = $this->get_type();
$hook_prefix = Config::get_hook_prefix();
$extension = pathinfo( $resource, PATHINFO_EXTENSION );
$resource_path = $relative_path_to_assets;
$type = $this->get_type();
$prefix_dir = '';

if ( ! $extension && $type ) {
$extension = $type;
Expand All @@ -344,8 +356,6 @@ protected function build_asset_url(): string {
$resource_path = $resources_path;

if ( $should_prefix ) {
$prefix_dir = '';

switch ( $extension ) {
case 'css':
$prefix_dir = 'css';
Expand Down Expand Up @@ -378,6 +388,38 @@ protected function build_asset_url(): string {
}
}

$data = [
'resource_path' => $resource_path,
'resource' => $resource,
'prefix_dir' => $prefix_dir,
];

/**
* Filters the asset URL
*
* @param array<string,string> $data Resource path data.
* @param string $slug Asset slug.
* @param Asset $asset The Asset object.
*/
return (array) apply_filters( "stellarwp/assets/{$hook_prefix}/resource_path_data", $data, $this->get_slug(), $this );
}

/**
* Builds the base asset URL.
*
* @since 1.0.0
*
* @return string
*/
protected function build_asset_url(): string {
$resource_path_data = $this->build_resource_path_data();
$resource = $resource_path_data['resource'];
$resource_path = $resource_path_data['resource_path'];

$root_path = $this->get_root_path();
$plugin_base_url = Config::get_url( $root_path );
$hook_prefix = Config::get_hook_prefix();

$url = $plugin_base_url . $resource_path . $resource;

/**
Expand Down Expand Up @@ -583,6 +625,57 @@ public function get_after_enqueue() {
return $this->after_enqueue;
}

/**
* Get the asset asset file contents.
*
* @return array
*/
public function get_asset_file_contents(): array {
if ( ! empty( $this->asset_file_contents ) ) {
return $this->asset_file_contents;
}

$default = [
'dependencies' => [],
'version' => null,
];

if ( ! $this->has_asset_file() ) {
$this->asset_file_contents = $default;

return $this->asset_file_contents;
}

$asset_file_contents = include $this->get_asset_file_path();

if ( ! is_array( $asset_file_contents ) ) {
$this->asset_file_contents = $default;

return $this->asset_file_contents;
}

$asset_file_contents = wp_parse_args( $asset_file_contents, $default );
$asset_file_contents['dependencies'] = array_unique( $asset_file_contents['dependencies'] );

$this->asset_file_contents = $asset_file_contents;

return $this->asset_file_contents;
}

/**
* Get the asset asset file path.
*
* @return string
*/
public function get_asset_file_path(): string {
if ( $this->asset_file_path === '' ) {
$resource_path_data = $this->build_resource_path_data();
$this->asset_file_path = $this->get_root_path() . $resource_path_data['resource_path'] . str_replace( [ '.css', '.js' ], '', $this->get_file() ) . '.asset.php';
}

return $this->asset_file_path;
}

/**
* Get the asset condition callable.
*
Expand All @@ -595,10 +688,27 @@ public function get_condition() {
/**
* Get the asset dependencies.
*
* @return array<string>|callable
* @return array<string>
*/
public function get_dependencies() {
return $this->dependencies;
public function get_dependencies(): array {
$dependencies = $this->dependencies;

if ( is_callable( $dependencies ) ) {
$dependencies = $dependencies( $this );
}

$asset_file_contents = $this->get_asset_file_contents();

if ( ! empty( $asset_file_contents['dependencies'] ) ) {
$dependencies = array_unique(
array_merge(
$asset_file_contents['dependencies'],
$dependencies
)
);
}

return $dependencies;
}

/**
Expand Down Expand Up @@ -800,9 +910,30 @@ public function get_url( bool $use_min_if_available = true ): string {
* @return string
*/
public function get_version(): string {
$asset_file_contents = $this->get_asset_file_contents();

if ( ! empty( $asset_file_contents['version'] ) ) {
return (string) $asset_file_contents['version'];
}

return $this->version;
}

/**
* Determines if the asset has an asset.php file.
*
* @return boolean
*/
public function has_asset_file(): bool {
$asset_file_path = $this->get_asset_file_path();

if ( empty( $asset_file_path ) ) {
return false;
}

return file_exists( $asset_file_path );
}

/**
* Sets the asset to be loaded in the footer.
*
Expand Down Expand Up @@ -1115,6 +1246,29 @@ public function set_action( string $action ) {
return $this;
}

/**
* Set the asset file path for the asset.
*
* @since TBD
*
* @param string $path The partial path to the asset.
*
* @return static
*/
public function set_asset_file( string $path ) {
if ( strpos( $path, '.asset.php' ) === false ) {
$path = preg_replace( '/\.(js|css)$/', '', $path );
$path .= '.asset.php';
}

$this->asset_file_path = $this->get_root_path() . $this->get_path() . $path;

// Since we are setting a new asset file path, reset the asset file contents.
$this->asset_file_contents = [];

return $this;
}

/**
* Set the asset as async.
*
Expand Down
10 changes: 1 addition & 9 deletions src/Assets/Assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -719,15 +719,7 @@ public function register_in_wp( $assets = null ) {
continue;
}

$dependencies = $asset->get_dependencies();

// If the asset is a callable, we call the function,
// passing it the asset and expecting back an array of dependencies.
if ( is_callable( $dependencies ) ) {
$dependencies = $dependencies( $asset );
}

wp_register_script( $asset->get_slug(), $asset->get_url(), $dependencies, $asset->get_version(), $asset->is_in_footer() );
wp_register_script( $asset->get_slug(), $asset->get_url(), $asset->get_dependencies(), $asset->get_version(), $asset->is_in_footer() );

// Register that this asset is actually registered on the WP methods.
// @phpstan-ignore-next-line
Expand Down
1 change: 1 addition & 0 deletions tests/_data/css/fake4.asset.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return array('dependencies' => array('some-dependency'), 'version' => '12345');
Empty file added tests/_data/css/fake4.css
Empty file.
1 change: 1 addition & 0 deletions tests/_data/js/fake4.asset.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return array('dependencies' => array('jquery'), 'version' => '12345');
Empty file added tests/_data/js/fake4.js
Empty file.
1 change: 1 addition & 0 deletions tests/_data/other-asset-root/fake4.asset.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return array('dependencies' => array('some-dependency'), 'version' => '67890');
19 changes: 18 additions & 1 deletion tests/acceptance/EnqueueJSCest.php
Original file line number Diff line number Diff line change
Expand Up @@ -267,4 +267,21 @@ public function it_should_localize( AcceptanceTester $I ) {
Assert::assertContains( 'var animal', $contents );
Assert::assertContains( 'var color', $contents );
}
}

public function it_should_enqueue_and_use_asset_file( AcceptanceTester $I ) {
$code = file_get_contents( codecept_data_dir( 'enqueue-template.php' ) );
$code .= <<<PHP
add_action( 'wp_enqueue_scripts', function() {
Asset::add( 'fake4-js', 'fake4.js' )
->enqueue_on( 'wp_enqueue_scripts' )
->register();
}, 100 );
PHP;

$I->haveMuPlugin( 'enqueue.php', $code );


$I->amOnPage( '/' );
$I->seeElement( 'script', [ 'src' => 'http://wordpress.test/wp-content/plugins/assets/tests/_data/js/fake4.js?ver=12345' ] );
}
}
Loading

0 comments on commit 5127693

Please sign in to comment.