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

Add support for *.asset.php files #19

Merged
merged 8 commits into from
Sep 27, 2024
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
Loading