diff --git a/src/Assets/Asset.php b/src/Assets/Asset.php index 874256c..f998fa3 100644 --- a/src/Assets/Asset.php +++ b/src/Assets/Asset.php @@ -4,6 +4,9 @@ use InvalidArgumentException; +/** + * Class Asset. + */ class Asset { /** * @var array The asset action. @@ -1696,15 +1699,176 @@ public function set_as_registered() { return $this; } + /** + * Prints the asset using wp_print_scripts or wp_print_styles. + * + * @since 1.4.4 + * + * @return static + */ + public function print_asset() { + $method = 'wp_print_' . $this->get_script_or_style() . 's'; + $method( $this->get_slug() ); + return $this; + } + + /** + * Enqueues the asset using wp_enqueue_script or wp_enqueue_style. + * + * @since 1.4.4 + * + * @return static + */ + public function enqueue_asset() { + $method = 'wp_enqueue_' . $this->get_script_or_style(); + $method( $this->get_slug() ); + return $this; + } + + /** + * Registers the asset using wp_register_script or wp_register_style. + * + * @since 1.4.4 + * + * @param string $url The URL to the asset. + * @param array $dependencies The dependencies for the asset. + * @param string $version The version of the asset. + * @param bool|string $in_footer_or_media Whether to enqueue in the footer or the media type for the asset. + * + * @return static + */ + public function register_asset( string $url = '', array $dependencies = [], string $version = null, $in_footer_or_media = 'all' ) { + $url = $url ? $url : $this->get_url(); + $dependencies = $dependencies ? $dependencies : $this->get_dependencies(); + $version = $version ?? $this->get_version(); + $in_footer_or_media = $in_footer_or_media ? $in_footer_or_media : ( $this->is_js() ? $this->is_in_footer() : $this->get_media() ); + + $method = 'wp_register_' . $this->get_script_or_style(); + $method( $this->get_slug(), $url, $dependencies, $version, $in_footer_or_media ); + return $this; + } + + /** + * Dequeues the asset using wp_dequeue_script or wp_dequeue_style. + * + * @since 1.4.4 + * + * @return static + */ + public function dequeue_asset() { + $method = 'wp_dequeue_' . $this->get_script_or_style(); + $method( $this->get_slug() ); + return $this; + } + + /** + * Deregisters the asset using wp_deregister_script or wp_deregister_style. + * + * @since 1.4.4 + * + * @return static + */ + public function deregister_asset() { + $method = 'wp_deregister_' . $this->get_script_or_style(); + $method( $this->get_slug() ); + return $this; + } + + /** + * Check if the asset is something. + * + * In the background uses wp_script_is or wp_style_is. + * + * @since 1.4.4 + * + * @param string $what The what to check against. + * + * @return bool + */ + public function asset_is( string $what ): bool { + return ( 'wp_' . $this->get_script_or_style() . '_is' )( $this->get_slug(), $what ); + } + + /** + * Get the script or style based on the asset type. + * + * @since 1.4.4 + * + * @return string + */ + protected function get_script_or_style(): string { + return 'js' === $this->get_type() ? 'script' : 'style'; + } + + /** + * Prints the asset + * + * @since 1.4.4 + * + * @return static + */ + public function do_print() { + if ( $this->should_print() && ! $this->is_printed() ) { + $this->set_as_printed(); + $this->print_asset(); + } + + // We print first, and tell the system it was enqueued, WP is smart not to do it twice. + $this->enqueue_asset(); + + if ( ! $this->is_css() ) { + return $this; + } + + foreach ( $this->get_style_data() as $key => $value ) { + wp_style_add_data( $this->get_slug(), $key, $value ); + } + + return $this; + } + + /** + * Performs the asset registration in WP. + * + * @since 1.4.4 + * + * @return static + */ + public function do_register() { + $this->register_asset( $this->get_url(), $this->get_dependencies(), $this->get_version(), $this->is_js() ? $this->is_in_footer() : $this->get_media() ); + $this->set_as_registered(); + + if ( $this->is_js() ) { + if ( empty( $this->get_translation_path() ) || empty( $this->get_textdomain() ) ) { + return $this; + } + + wp_set_script_translations( $this->get_slug(), $this->get_textdomain(), $this->get_translation_path() ); + return $this; + } + + + $style_data = $this->get_style_data(); + if ( $style_data ) { + foreach ( $style_data as $datum_key => $datum_value ) { + wp_style_add_data( $this->get_slug(), $datum_key, $datum_value ); + } + } + + return $this; + } + /** * Set the asset enqueue status to false. * * @since 1.0.0 + * @since 1.4.4 - Actually dequeues the asset. * * @return static */ public function set_as_unenqueued() { $this->is_enqueued = false; + $this->dequeue_asset(); return $this; } @@ -1712,11 +1876,13 @@ public function set_as_unenqueued() { * Set the asset registration status to false. * * @since 1.0.0 + * @since 1.4.4 - Actually deregisters the asset. * * @return static */ public function set_as_unregistered() { $this->is_registered = false; + $this->deregister_asset(); return $this; } diff --git a/src/Assets/Assets.php b/src/Assets/Assets.php index e9f719a..46c81e3 100755 --- a/src/Assets/Assets.php +++ b/src/Assets/Assets.php @@ -643,27 +643,7 @@ protected function do_enqueue( Asset $asset, bool $force_enqueue = false ): void return; } - if ( 'js' === $asset->get_type() ) { - if ( $asset->should_print() && ! $asset->is_printed() ) { - $asset->set_as_printed(); - wp_print_scripts( [ $slug ] ); - } - // We print first, and tell the system it was enqueued, WP is smart not to do it twice. - wp_enqueue_script( $slug ); - } else { - if ( $asset->should_print() && ! $asset->is_printed() ) { - $asset->set_as_printed(); - wp_print_styles( [ $slug ] ); - } - - // We print first, and tell the system it was enqueued, WP is smart not to do it twice. - wp_enqueue_style( $slug ); - - $style_data = $asset->get_style_data(); - foreach ( $style_data as $key => $value ) { - wp_style_add_data( $slug, $key, $value ); - } - } + $asset->do_print(); if ( ! empty( $asset->get_after_enqueue() ) && is_callable( $asset->get_after_enqueue() ) ) { call_user_func_array( $asset->get_after_enqueue(), [ $asset ] ); @@ -713,49 +693,7 @@ public function register_in_wp( $assets = null ) { continue; } - $asset_slug = $asset->get_slug(); - - if ( 'js' === $asset->get_type() ) { - // Script is already registered. - if ( wp_script_is( $asset_slug, 'registered' ) ) { - continue; - } - - wp_register_script( $asset_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 - if ( wp_script_is( $asset_slug, 'registered' ) ) { - $asset->set_as_registered(); - } - - if ( - ! empty( $asset->get_translation_path() ) - && ! empty( $asset->get_textdomain() ) - ) { - wp_set_script_translations( $asset_slug, $asset->get_textdomain(), $asset->get_translation_path() ); - } - } else { - // Style is already registered. - if ( wp_style_is( $asset_slug, 'registered' ) ) { - continue; - } - - wp_register_style( $asset_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_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_slug, $datum_key, $datum_value ); - } - } - } + $asset->do_register(); // If we don't have an action we don't even register the action to enqueue. if ( empty( $asset->get_action() ) ) { @@ -788,16 +726,14 @@ public function remove( $slug ) { return false; } - $type = $this->get( $slug )->get_type(); + $asset = $this->get( $slug ); - if ( $type === 'css' ) { - wp_dequeue_style( $slug ); - wp_deregister_style( $slug ); - } else { - wp_dequeue_script( $slug ); - wp_deregister_script( $slug ); + if ( ! $asset instanceof Asset ) { + return true; } + $asset->dequeue_asset()->deregister_asset(); + unset( $this->assets[ $slug ] ); return true; @@ -836,9 +772,8 @@ public function print_group( $group, $echo = true ) { if ( $asset->is_registered() ) { continue; } - 'js' === $asset->get_type() - ? wp_register_script( $slug, $asset->get_file(), $asset->get_dependencies(), $asset->get_version() ) - : wp_register_style( $slug, $asset->get_file(), $asset->get_dependencies(), $asset->get_version() ); + + $asset->register_asset( $asset->get_file(), $asset->get_dependencies(), $asset->get_version() ); } ob_start(); diff --git a/tests/wpunit/AssetTest.php b/tests/wpunit/AssetTest.php index 032ce72..47614df 100644 --- a/tests/wpunit/AssetTest.php +++ b/tests/wpunit/AssetTest.php @@ -29,4 +29,155 @@ public function test_add_to_group_path_changes_resolution_path_to_group(): void $this->assertEquals( WP_PLUGIN_DIR . '/assets/tests/_data/', $asset->get_root_path() ); } + + public function test_it_can_enqueue_multiple_times_overwritting_previous(): void { + Config::reset(); + Config::set_hook_prefix( 'bork' ); + Config::set_version( '1.1.0' ); + Config::set_path( constant( 'WP_PLUGIN_DIR' ) . '/assets' ); + Config::set_relative_asset_path( 'tests/_data/' ); + + $checker = static fn( string $handle ): array => wp_scripts()->registered[ $handle ]->deps; + + $asset = Asset::add( 'test-script-unique-654321', 'fake.js', '1.0.0', codecept_data_dir() ); + $asset->enqueue_on( 'a_random_action_1234' ); + $asset->set_dependencies( 'jquery', 'jquery-ui-core' ); + + do_action( 'a_random_action_1234' ); + + $asset->enqueue(); + + $this->assertTrue( wp_script_is( $asset->get_slug(), 'enqueued' ) ); + $this->assertTrue( $asset->asset_is( 'enqueued' ) ); + $this->assertEquals( [ 'jquery', 'jquery-ui-core' ], $checker( $asset->get_slug() ) ); + $this->assertEquals( [ 'jquery', 'jquery-ui-core' ], $asset->get_dependencies() ); + + $asset->set_dependencies( 'jquery' ); + // It's not going to register again! We need to set it as unregistered first. + $asset->enqueue(); + + $this->assertTrue( wp_script_is( $asset->get_slug(), 'enqueued' ) ); + $this->assertTrue( $asset->asset_is( 'enqueued' ) ); + $this->assertEquals( [ 'jquery', 'jquery-ui-core' ], $checker( $asset->get_slug() ) ); + $this->assertEquals( [ 'jquery' ], $asset->get_dependencies() ); + + $asset->set_as_unregistered(); + $asset->enqueue(); + + $this->assertTrue( wp_script_is( $asset->get_slug(), 'enqueued' ) ); + $this->assertTrue( $asset->asset_is( 'enqueued' ) ); + $this->assertEquals( [ 'jquery' ], $checker( $asset->get_slug() ) ); + $this->assertEquals( [ 'jquery' ], $asset->get_dependencies() ); + } + + public function test_it_can_register_multiple_times_overwritting_previous(): void { + Config::reset(); + Config::set_hook_prefix( 'bork' ); + Config::set_version( '1.1.0' ); + Config::set_path( constant( 'WP_PLUGIN_DIR' ) . '/assets' ); + Config::set_relative_asset_path( 'tests/_data/' ); + + $checker = static fn( string $handle ): array => wp_scripts()->registered[ $handle ]->deps; + + $asset = new Asset( 'test-script-unique-123456', 'fake.js', '1.0.0', codecept_data_dir() ); + + $asset->set_dependencies( 'jquery', 'jquery-ui-core' ); + $asset->register(); + + $this->assertTrue( wp_script_is( $asset->get_slug(), 'registered' ) ); + $this->assertTrue( $asset->asset_is( 'registered' ) ); + $this->assertEquals( [ 'jquery', 'jquery-ui-core' ], $checker( $asset->get_slug() ) ); + $this->assertEquals( [ 'jquery', 'jquery-ui-core' ], $asset->get_dependencies() ); + + $asset->set_dependencies( 'jquery' ); + // It's not going to register again! We need to set it as unregistered first. + $asset->register(); + + $this->assertTrue( wp_script_is( $asset->get_slug(), 'registered' ) ); + $this->assertTrue( $asset->asset_is( 'registered' ) ); + $this->assertEquals( [ 'jquery', 'jquery-ui-core' ], $checker( $asset->get_slug() ) ); + $this->assertEquals( [ 'jquery' ], $asset->get_dependencies() ); + + $asset->set_as_unregistered(); + $asset->register(); + + $this->assertTrue( wp_script_is( $asset->get_slug(), 'registered' ) ); + $this->assertTrue( $asset->asset_is( 'registered' ) ); + $this->assertEquals( [ 'jquery' ], $checker( $asset->get_slug() ) ); + $this->assertEquals( [ 'jquery' ], $asset->get_dependencies() ); + } + + public function test_it_print_asset() { + Config::reset(); + Config::set_hook_prefix( 'bork' ); + Config::set_version( '1.1.0' ); + Config::set_path( constant( 'WP_PLUGIN_DIR' ) . '/assets' ); + Config::set_relative_asset_path( 'tests/_data/' ); + + $asset_js = new Asset( 'test-script', 'fake.js', '1.0.0' ); + $asset_css = new Asset( 'test-style', 'fake.css', '1.0.0' ); + + ob_start(); + $asset_js->register_asset(); + $asset_css->register_asset(); + $asset_js->print_asset(); + $asset_css->print_asset(); + $this->assertEquals( + ' + +', + ob_get_clean() + ); + } + + public function test_it_enqueues_asset() { + Config::reset(); + Config::set_hook_prefix( 'bork' ); + Config::set_version( '1.1.0' ); + Config::set_path( constant( 'WP_PLUGIN_DIR' ) . '/assets' ); + Config::set_relative_asset_path( 'tests/_data/' ); + + $asset_js = new Asset( 'test-script', 'fake.js', '1.0.0' ); + $asset_css = new Asset( 'test-style', 'fake.css', '1.0.0' ); + + $asset_js->register_asset(); + $asset_css->register_asset(); + + $this->assertTrue( wp_script_is( 'test-script', 'registered' ) ); + $this->assertSame( $asset_js->asset_is( 'registered' ), wp_script_is( 'test-script', 'registered' ) ); + $this->assertTrue( wp_style_is( 'test-style', 'registered' ) ); + $this->assertSame( $asset_css->asset_is( 'registered' ), wp_style_is( 'test-style', 'registered' ) ); + + $asset_js->enqueue_asset(); + $asset_css->enqueue_asset(); + + $this->assertTrue( wp_script_is( 'test-script', 'enqueued' ) ); + $this->assertSame( $asset_js->asset_is( 'enqueued' ), wp_script_is( 'test-script', 'enqueued' ) ); + $this->assertTrue( wp_style_is( 'test-style', 'enqueued' ) ); + $this->assertSame( $asset_css->asset_is( 'enqueued' ), wp_style_is( 'test-style', 'enqueued' ) ); + + $asset_js->dequeue_asset(); + $asset_css->dequeue_asset(); + + $this->assertFalse( wp_script_is( 'test-script', 'enqueued' ) ); + $this->assertSame( $asset_js->asset_is( 'enqueued' ), wp_script_is( 'test-script', 'enqueued' ) ); + $this->assertFalse( wp_style_is( 'test-style', 'enqueued' ) ); + $this->assertSame( $asset_css->asset_is( 'enqueued' ), wp_style_is( 'test-style', 'enqueued' ) ); + $this->assertTrue( wp_script_is( 'test-script', 'registered' ) ); + $this->assertSame( $asset_js->asset_is( 'registered' ), wp_script_is( 'test-script', 'registered' ) ); + $this->assertTrue( wp_style_is( 'test-style', 'registered' ) ); + $this->assertSame( $asset_css->asset_is( 'registered' ), wp_style_is( 'test-style', 'registered' ) ); + + $asset_js->deregister_asset(); + $asset_css->deregister_asset(); + + $this->assertFalse( wp_script_is( 'test-script', 'enqueued' ) ); + $this->assertSame( $asset_js->asset_is( 'enqueued' ), wp_script_is( 'test-script', 'enqueued' ) ); + $this->assertFalse( wp_style_is( 'test-style', 'enqueued' ) ); + $this->assertSame( $asset_css->asset_is( 'enqueued' ), wp_style_is( 'test-style', 'enqueued' ) ); + $this->assertFalse( wp_script_is( 'test-script', 'registered' ) ); + $this->assertSame( $asset_js->asset_is( 'registered' ), wp_script_is( 'test-script', 'registered' ) ); + $this->assertFalse( wp_style_is( 'test-style', 'registered' ) ); + $this->assertSame( $asset_css->asset_is( 'registered' ), wp_style_is( 'test-style', 'registered' ) ); + } }