Skip to content
Closed
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
46 changes: 44 additions & 2 deletions src/wp-includes/class-wp-dependencies.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,18 @@ class WP_Dependencies {
*/
private $queued_before_register = array();

/**
* List of handles for dependencies encountered which themselves have missing dependencies.
*
* A dependency handle is added to this list when it is discovered to have missing dependencies. At this time, a
* warning is emitted with {@see _doing_it_wrong()}. The handle is then added to this list, so that duplicate
* warnings don't occur.
*
* @since 7.0.0
* @var string[]
*/
private $dependencies_with_missing_dependencies = array();

/**
* Processes the items and dependencies.
*
Expand Down Expand Up @@ -199,10 +211,22 @@ public function all_deps( $handles, $recursion = false, $group = false ) {
continue;
}

$keep_going = true;
$keep_going = true;
$missing_dependencies = array();
if ( isset( $this->registered[ $handle ] ) && count( $this->registered[ $handle ]->deps ) > 0 ) {
$missing_dependencies = array_diff( $this->registered[ $handle ]->deps, array_keys( $this->registered ) );
}
if ( ! isset( $this->registered[ $handle ] ) ) {
$keep_going = false; // Item doesn't exist.
} elseif ( $this->registered[ $handle ]->deps && array_diff( $this->registered[ $handle ]->deps, array_keys( $this->registered ) ) ) {
} elseif ( count( $missing_dependencies ) > 0 ) {
if ( ! in_array( $handle, $this->dependencies_with_missing_dependencies, true ) ) {
_doing_it_wrong(
get_class( $this ) . '::add',
$this->get_dependency_warning_message( $handle, $missing_dependencies ),
'7.0.0'
);
$this->dependencies_with_missing_dependencies[] = $handle;
}
$keep_going = false; // Item requires dependencies that don't exist.
} elseif ( $this->registered[ $handle ]->deps && ! $this->all_deps( $this->registered[ $handle ]->deps, true, $new_group ) ) {
$keep_going = false; // Item requires dependencies that don't exist.
Expand Down Expand Up @@ -535,4 +559,22 @@ public function get_etag( $load ) {
*/
return 'W/"' . md5( $etag ) . '"';
}

/**
* Gets a dependency warning message for a handle.
*
* @since 7.0.0
*
* @param string $handle Handle with missing dependencies.
* @param string[] $missing_dependency_handles Missing dependency handles.
* @return string Formatted, localized warning message.
*/
protected function get_dependency_warning_message( $handle, $missing_dependency_handles ) {
return sprintf(
/* translators: 1: Handle, 2: Comma-separated list of missing dependency handles. */
__( 'The handle "%1$s" was enqueued with dependencies that are not registered: %2$s.' ),
$handle,
implode( ', ', $missing_dependency_handles )
);
}
}
28 changes: 27 additions & 1 deletion src/wp-includes/class-wp-script-modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ class WP_Script_Modules {
'high',
);

/**
* List of IDs for script modules encountered which have missing dependencies.
*
* An ID is added to this list when it is discovered to have missing dependencies. At this time, a warning is
* emitted with {@see _doing_it_wrong()}. The ID is then added to this list, so that duplicate warnings don't occur.
*
* @since 7.0.0
* @var string[]
*/
private $modules_with_missing_dependencies = array();

/**
* Registers the script module if no script module with that script module
* identifier has already been registered.
Expand Down Expand Up @@ -722,7 +733,22 @@ private function sort_item_dependencies( string $id, array $import_types, array
}

// If the item requires dependencies that do not exist, fail.
if ( count( array_diff( $dependency_ids, array_keys( $this->registered ) ) ) > 0 ) {
$missing_dependencies = array_diff( $dependency_ids, array_keys( $this->registered ) );
if ( count( $missing_dependencies ) > 0 ) {
if ( ! in_array( $id, $this->modules_with_missing_dependencies, true ) ) {
_doing_it_wrong(
get_class( $this ) . '::register',
sprintf(
/* translators: 1: Script module ID, 2: Comma-separated list of missing dependency IDs. */
__( 'The script module with the ID "%1$s" was enqueued with dependencies that are not registered: %2$s.' ),
$id,
implode( ', ', $missing_dependencies )
),
'7.0.0'
);
$this->modules_with_missing_dependencies[] = $id;
}

return false;
}

Expand Down
18 changes: 18 additions & 0 deletions src/wp-includes/class-wp-scripts.php
Original file line number Diff line number Diff line change
Expand Up @@ -1164,4 +1164,22 @@ public function reset() {
$this->ext_version = '';
$this->ext_handles = '';
}

/**
* Gets a script-specific dependency warning message.
*
* @since 7.0.0
*
* @param string $handle Script handle with missing dependencies.
* @param string[] $missing_dependency_handles Missing dependency handles.
* @return string Formatted, localized warning message.
*/
protected function get_dependency_warning_message( $handle, $missing_dependency_handles ) {
return sprintf(
/* translators: 1: Script handle, 2: Comma-separated list of missing dependency handles. */
__( 'The script with the handle "%1$s" was enqueued with dependencies that are not registered: %2$s.' ),
$handle,
implode( ', ', $missing_dependency_handles )
);
}
}
18 changes: 18 additions & 0 deletions src/wp-includes/class-wp-styles.php
Original file line number Diff line number Diff line change
Expand Up @@ -493,4 +493,22 @@ public function reset() {
$this->concat_version = '';
$this->print_html = '';
}

/**
* Gets a style-specific dependency warning message.
*
* @since 7.0.0
*
* @param string $handle Style handle with missing dependencies.
* @param string[] $missing_dependency_handles Missing dependency handles.
* @return string Formatted, localized warning message.
*/
protected function get_dependency_warning_message( $handle, $missing_dependency_handles ) {
return sprintf(
/* translators: 1: Style handle, 2: Comma-separated list of missing dependency handles. */
__( 'The style with the handle "%1$s" was enqueued with dependencies that are not registered: %2$s.' ),
$handle,
implode( ', ', $missing_dependency_handles )
);
}
}
29 changes: 29 additions & 0 deletions tests/phpunit/tests/dependencies/scripts.php
Original file line number Diff line number Diff line change
Expand Up @@ -4093,4 +4093,33 @@ public function test_print_translations_no_display_no_sourceurl() {
$translations_script_data = $wp_scripts->print_translations( 'test-example', false );
$this->assertStringNotContainsStringIgnoringCase( 'sourceURL=', $translations_script_data );
}

/**
* Tests that WP_Scripts emits a _doing_it_wrong() notice for missing dependencies.
*
* @ticket 64229
* @covers WP_Dependencies::all_deps
*/
public function test_wp_scripts_doing_it_wrong_for_missing_dependencies() {
$expected_incorrect_usage = 'WP_Scripts::add';
$this->setExpectedIncorrectUsage( $expected_incorrect_usage );

wp_register_script( 'registered-dep', '/registered-dep.js' );
wp_enqueue_script( 'main', '/main.js', array( 'registered-dep', 'missing-dep' ) );

$markup = get_echo( 'wp_print_scripts' );
$this->assertStringNotContainsString( 'main.js', $markup, 'Expected script to be absent.' );

$this->assertArrayHasKey(
$expected_incorrect_usage,
$this->caught_doing_it_wrong,
"Expected $expected_incorrect_usage to trigger a _doing_it_wrong() notice for missing dependency."
);

$this->assertStringContainsString(
'The script with the handle "main" was enqueued with dependencies that are not registered: missing-dep',
$this->caught_doing_it_wrong[ $expected_incorrect_usage ],
'Expected _doing_it_wrong() notice to indicate missing dependencies for enqueued script.'
);
}
}
32 changes: 32 additions & 0 deletions tests/phpunit/tests/dependencies/styles.php
Original file line number Diff line number Diff line change
Expand Up @@ -814,4 +814,36 @@ public function test_source_url_with_concat() {

$this->assertEqualHTML( $expected, $printed );
}

/**
* Tests that WP_Styles emits a _doing_it_wrong() notice for missing dependencies.
*
* @ticket 64229
* @covers WP_Dependencies::all_deps
*/
public function test_wp_style_doing_it_wrong_for_missing_dependencies() {
$expected_incorrect_usage = 'WP_Styles::add';
$this->setExpectedIncorrectUsage( $expected_incorrect_usage );

wp_enqueue_style(
'main-style',
'/main-style.css',
array( 'missing-style-dep' )
);

$markup = get_echo( 'wp_print_styles' );
$this->assertStringNotContainsString( 'main-style.css', $markup, 'Expected style to be absent.' );

$this->assertArrayHasKey(
$expected_incorrect_usage,
$this->caught_doing_it_wrong,
"Expected $expected_incorrect_usage to trigger a _doing_it_wrong() notice for missing dependency."
);

$this->assertStringContainsString(
'The style with the handle "main-style" was enqueued with dependencies that are not registered: missing-style-dep',
$this->caught_doing_it_wrong[ $expected_incorrect_usage ],
'Expected _doing_it_wrong() notice to indicate missing dependencies for enqueued styles.'
);
}
}
30 changes: 29 additions & 1 deletion tests/phpunit/tests/script-modules/wpScriptModules.php
Original file line number Diff line number Diff line change
Expand Up @@ -2059,7 +2059,7 @@ public function test_script_module_printing_and_dependency_ordering( bool $use_g
"Snapshot:\n" . var_export( $actual, true )
);

$deregister( array( 'b', 'c ' ) );
$deregister( array( 'b', 'c' ) );

// Test that registered dependency in footer doesn't place dependant in footer.
$register( 'd', '/d.js', array(), '1.0.0', array( 'in_footer' => true ) );
Expand Down Expand Up @@ -2312,4 +2312,32 @@ public function test_static_import_dependency_with_dynamic_imports_depending_on_
"Expected script modules to match snapshot:\n$script_modules"
);
}

/**
* Tests that a missing script module dependency triggers a _doing_it_wrong() notice.
*
* @ticket 64229
* @covers WP_Script_Modules::sort_item_dependencies
*/
public function test_missing_script_module_dependency_triggers_incorrect_usage() {
$expected_incorrect_usage = 'WP_Script_Modules::register';
$this->setExpectedIncorrectUsage( $expected_incorrect_usage );

$this->script_modules->enqueue( 'main-module', '/main-module.js', array( 'missing-mod-dep' ) );

$markup = get_echo( array( $this->script_modules, 'print_enqueued_script_modules' ) );
$this->assertStringNotContainsString( 'main-module.js', $markup, 'Expected script module to be absent.' );

$this->assertArrayHasKey(
$expected_incorrect_usage,
$this->caught_doing_it_wrong,
'Expected WP_Script_Modules::register to be reported via doing_it_wrong().'
);

// Assert the message mentions the missing dependency handle.
$this->assertStringContainsString(
'The script module with the ID "main-module" was enqueued with dependencies that are not registered: missing-mod-dep',
$this->caught_doing_it_wrong[ $expected_incorrect_usage ]
);
}
}
Loading