Make WordPress Core

Changeset 61323 for trunk


Ignore:
Timestamp:
11/30/2025 12:54:26 AM (4 months ago)
Author:
westonruter
Message:

Script Loader: Emit notices when enqueueing a script, style, or script module with missing dependencies.

Developed in https://github.com/WordPress/wordpress-develop/pull/10545

Follow-up to [60999].

Props deepakprajapati, westonruter.
See #63486.
Fixes #64229.

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-dependencies.php

    r61299 r61323  
    104104     */
    105105    private $queued_before_register = array();
     106
     107    /**
     108     * List of handles for dependencies encountered which themselves have missing dependencies.
     109     *
     110     * A dependency handle is added to this list when it is discovered to have missing dependencies. At this time, a
     111     * warning is emitted with {@see _doing_it_wrong()}. The handle is then added to this list, so that duplicate
     112     * warnings don't occur.
     113     *
     114     * @since 7.0.0
     115     * @var string[]
     116     */
     117    private $dependencies_with_missing_dependencies = array();
    106118
    107119    /**
     
    200212            }
    201213
    202             $keep_going = true;
     214            $keep_going           = true;
     215            $missing_dependencies = array();
     216            if ( isset( $this->registered[ $handle ] ) && count( $this->registered[ $handle ]->deps ) > 0 ) {
     217                $missing_dependencies = array_diff( $this->registered[ $handle ]->deps, array_keys( $this->registered ) );
     218            }
    203219            if ( ! isset( $this->registered[ $handle ] ) ) {
    204220                $keep_going = false; // Item doesn't exist.
    205             } elseif ( $this->registered[ $handle ]->deps && array_diff( $this->registered[ $handle ]->deps, array_keys( $this->registered ) ) ) {
     221            } elseif ( count( $missing_dependencies ) > 0 ) {
     222                if ( ! in_array( $handle, $this->dependencies_with_missing_dependencies, true ) ) {
     223                    _doing_it_wrong(
     224                        get_class( $this ) . '::add',
     225                        $this->get_dependency_warning_message( $handle, $missing_dependencies ),
     226                        '7.0.0'
     227                    );
     228                    $this->dependencies_with_missing_dependencies[] = $handle;
     229                }
    206230                $keep_going = false; // Item requires dependencies that don't exist.
    207231            } elseif ( $this->registered[ $handle ]->deps && ! $this->all_deps( $this->registered[ $handle ]->deps, true, $new_group ) ) {
     
    536560        return 'W/"' . md5( $etag ) . '"';
    537561    }
     562
     563    /**
     564     * Gets a dependency warning message for a handle.
     565     *
     566     * @since 7.0.0
     567     *
     568     * @param string   $handle                     Handle with missing dependencies.
     569     * @param string[] $missing_dependency_handles Missing dependency handles.
     570     * @return string Formatted, localized warning message.
     571     */
     572    protected function get_dependency_warning_message( $handle, $missing_dependency_handles ) {
     573        return sprintf(
     574            /* translators: 1: Handle, 2: Comma-separated list of missing dependency handles. */
     575            __( 'The handle "%1$s" was enqueued with dependencies that are not registered: %2$s.' ),
     576            $handle,
     577            implode( ', ', $missing_dependency_handles )
     578        );
     579    }
    538580}
  • trunk/src/wp-includes/class-wp-script-modules.php

    r61073 r61323  
    7070        'high',
    7171    );
     72
     73    /**
     74     * List of IDs for script modules encountered which have missing dependencies.
     75     *
     76     * An ID is added to this list when it is discovered to have missing dependencies. At this time, a warning is
     77     * emitted with {@see _doing_it_wrong()}. The ID is then added to this list, so that duplicate warnings don't occur.
     78     *
     79     * @since 7.0.0
     80     * @var string[]
     81     */
     82    private $modules_with_missing_dependencies = array();
    7283
    7384    /**
     
    723734
    724735        // If the item requires dependencies that do not exist, fail.
    725         if ( count( array_diff( $dependency_ids, array_keys( $this->registered ) ) ) > 0 ) {
     736        $missing_dependencies = array_diff( $dependency_ids, array_keys( $this->registered ) );
     737        if ( count( $missing_dependencies ) > 0 ) {
     738            if ( ! in_array( $id, $this->modules_with_missing_dependencies, true ) ) {
     739                _doing_it_wrong(
     740                    get_class( $this ) . '::register',
     741                    sprintf(
     742                        /* translators: 1: Script module ID, 2: Comma-separated list of missing dependency IDs. */
     743                        __( 'The script module with the ID "%1$s" was enqueued with dependencies that are not registered: %2$s.' ),
     744                        $id,
     745                        implode( ', ', $missing_dependencies )
     746                    ),
     747                    '7.0.0'
     748                );
     749                $this->modules_with_missing_dependencies[] = $id;
     750            }
     751
    726752            return false;
    727753        }
  • trunk/src/wp-includes/class-wp-scripts.php

    r61223 r61323  
    11651165        $this->ext_handles    = '';
    11661166    }
     1167
     1168    /**
     1169     * Gets a script-specific dependency warning message.
     1170     *
     1171     * @since 7.0.0
     1172     *
     1173     * @param string   $handle                     Script handle with missing dependencies.
     1174     * @param string[] $missing_dependency_handles Missing dependency handles.
     1175     * @return string Formatted, localized warning message.
     1176     */
     1177    protected function get_dependency_warning_message( $handle, $missing_dependency_handles ) {
     1178        return sprintf(
     1179            /* translators: 1: Script handle, 2: Comma-separated list of missing dependency handles. */
     1180            __( 'The script with the handle "%1$s" was enqueued with dependencies that are not registered: %2$s.' ),
     1181            $handle,
     1182            implode( ', ', $missing_dependency_handles )
     1183        );
     1184    }
    11671185}
  • trunk/src/wp-includes/class-wp-styles.php

    r61084 r61323  
    494494        $this->print_html     = '';
    495495    }
     496
     497    /**
     498     * Gets a style-specific dependency warning message.
     499     *
     500     * @since 7.0.0
     501     *
     502     * @param string   $handle                     Style handle with missing dependencies.
     503     * @param string[] $missing_dependency_handles Missing dependency handles.
     504     * @return string Formatted, localized warning message.
     505     */
     506    protected function get_dependency_warning_message( $handle, $missing_dependency_handles ) {
     507        return sprintf(
     508            /* translators: 1: Style handle, 2: Comma-separated list of missing dependency handles. */
     509            __( 'The style with the handle "%1$s" was enqueued with dependencies that are not registered: %2$s.' ),
     510            $handle,
     511            implode( ', ', $missing_dependency_handles )
     512        );
     513    }
    496514}
  • trunk/tests/phpunit/tests/dependencies/scripts.php

    r61223 r61323  
    40944094        $this->assertStringNotContainsStringIgnoringCase( 'sourceURL=', $translations_script_data );
    40954095    }
     4096
     4097    /**
     4098     * Tests that WP_Scripts emits a _doing_it_wrong() notice for missing dependencies.
     4099     *
     4100     * @ticket 64229
     4101     * @covers WP_Dependencies::all_deps
     4102     */
     4103    public function test_wp_scripts_doing_it_wrong_for_missing_dependencies() {
     4104        $expected_incorrect_usage = 'WP_Scripts::add';
     4105        $this->setExpectedIncorrectUsage( $expected_incorrect_usage );
     4106
     4107        wp_register_script( 'registered-dep', '/registered-dep.js' );
     4108        wp_enqueue_script( 'main', '/main.js', array( 'registered-dep', 'missing-dep' ) );
     4109
     4110        $markup = get_echo( 'wp_print_scripts' );
     4111        $this->assertStringNotContainsString( 'main.js', $markup, 'Expected script to be absent.' );
     4112
     4113        $this->assertArrayHasKey(
     4114            $expected_incorrect_usage,
     4115            $this->caught_doing_it_wrong,
     4116            "Expected $expected_incorrect_usage to trigger a _doing_it_wrong() notice for missing dependency."
     4117        );
     4118
     4119        $this->assertStringContainsString(
     4120            'The script with the handle "main" was enqueued with dependencies that are not registered: missing-dep',
     4121            $this->caught_doing_it_wrong[ $expected_incorrect_usage ],
     4122            'Expected _doing_it_wrong() notice to indicate missing dependencies for enqueued script.'
     4123        );
     4124    }
    40964125}
  • trunk/tests/phpunit/tests/dependencies/styles.php

    r61084 r61323  
    815815        $this->assertEqualHTML( $expected, $printed );
    816816    }
     817
     818    /**
     819     * Tests that WP_Styles emits a _doing_it_wrong() notice for missing dependencies.
     820     *
     821     * @ticket 64229
     822     * @covers WP_Dependencies::all_deps
     823     */
     824    public function test_wp_style_doing_it_wrong_for_missing_dependencies() {
     825        $expected_incorrect_usage = 'WP_Styles::add';
     826        $this->setExpectedIncorrectUsage( $expected_incorrect_usage );
     827
     828        wp_enqueue_style(
     829            'main-style',
     830            '/main-style.css',
     831            array( 'missing-style-dep' )
     832        );
     833
     834        $markup = get_echo( 'wp_print_styles' );
     835        $this->assertStringNotContainsString( 'main-style.css', $markup, 'Expected style to be absent.' );
     836
     837        $this->assertArrayHasKey(
     838            $expected_incorrect_usage,
     839            $this->caught_doing_it_wrong,
     840            "Expected $expected_incorrect_usage to trigger a _doing_it_wrong() notice for missing dependency."
     841        );
     842
     843        $this->assertStringContainsString(
     844            'The style with the handle "main-style" was enqueued with dependencies that are not registered: missing-style-dep',
     845            $this->caught_doing_it_wrong[ $expected_incorrect_usage ],
     846            'Expected _doing_it_wrong() notice to indicate missing dependencies for enqueued styles.'
     847        );
     848    }
    817849}
  • trunk/tests/phpunit/tests/script-modules/wpScriptModules.php

    r61073 r61323  
    20602060        );
    20612061
    2062         $deregister( array( 'b', 'c ' ) );
     2062        $deregister( array( 'b', 'c' ) );
    20632063
    20642064        // Test that registered dependency in footer doesn't place dependant in footer.
     
    23132313        );
    23142314    }
     2315
     2316    /**
     2317     * Tests that a missing script module dependency triggers a _doing_it_wrong() notice.
     2318     *
     2319     * @ticket 64229
     2320     * @covers WP_Script_Modules::sort_item_dependencies
     2321     */
     2322    public function test_missing_script_module_dependency_triggers_incorrect_usage() {
     2323        $expected_incorrect_usage = 'WP_Script_Modules::register';
     2324        $this->setExpectedIncorrectUsage( $expected_incorrect_usage );
     2325
     2326        $this->script_modules->enqueue( 'main-module', '/main-module.js', array( 'missing-mod-dep' ) );
     2327
     2328        $markup = get_echo( array( $this->script_modules, 'print_enqueued_script_modules' ) );
     2329        $this->assertStringNotContainsString( 'main-module.js', $markup, 'Expected script module to be absent.' );
     2330
     2331        $this->assertArrayHasKey(
     2332            $expected_incorrect_usage,
     2333            $this->caught_doing_it_wrong,
     2334            'Expected WP_Script_Modules::register to be reported via doing_it_wrong().'
     2335        );
     2336
     2337        // Assert the message mentions the missing dependency handle.
     2338        $this->assertStringContainsString(
     2339            'The script module with the ID "main-module" was enqueued with dependencies that are not registered: missing-mod-dep',
     2340            $this->caught_doing_it_wrong[ $expected_incorrect_usage ]
     2341        );
     2342    }
    23152343}
Note: See TracChangeset for help on using the changeset viewer.