diff --git a/src/wp-includes/class-wp-scripts.php b/src/wp-includes/class-wp-scripts.php index 2b857b0f7c9d6..10b81ceb6f23e 100644 --- a/src/wp-includes/class-wp-scripts.php +++ b/src/wp-includes/class-wp-scripts.php @@ -321,9 +321,16 @@ public function do_item( $handle, $group = false ) { if ( $after_non_standalone_handle ) { $initial_type_attr = $this->type_attr; $this->type_attr = " type='text/template'"; - $after_handle .= sprintf( "\n%s\n\n", $this->type_attr, esc_attr( $handle ), $after_non_standalone_handle ); + $after_handle .= sprintf( + '%4$s%3$s%4$s%4$s', + $this->type_attr, + esc_attr( $handle ), + $after_non_standalone_handle, + PHP_EOL + ); $this->type_attr = $initial_type_attr; + $this->has_load_later_inline = true; } } @@ -414,6 +421,9 @@ public function do_item( $handle, $group = false ) { if ( '' !== $strategy ) { $strategy = ' ' . $strategy; + if ( ! empty( $after_non_standalone_handle ) ) { + $strategy .= sprintf( " onload='wpLoadAfterScripts(\"%s\")'", esc_attr( $handle ) ); + } } $tag = $translations . $cond_before . $before_handle; $tag .= sprintf( @@ -505,7 +515,14 @@ public function print_inline_script( $handle, $position = 'after', $display = tr if ( 'after-non-standalone' === $position ) { $initial_type_attr = $this->type_attr; $this->type_attr = " type='text/template'"; - printf( "\n%s\n\n", $this->type_attr, esc_attr( $handle ), $output ); + printf( + '%5$s%4$s%5$s%5$s', + $this->type_attr, + esc_attr( $handle ), + esc_attr( $position ), + $output, + PHP_EOL + ); $this->type_attr = $initial_type_attr; } else { printf( "\n%s\n\n", $this->type_attr, esc_attr( $handle ), esc_attr( $position ), $output ); @@ -778,6 +795,23 @@ public function add_data( $handle, $key, $value ) { return parent::add_data( $handle, $key, $value ); } + /** + * Checks all handles for any delayed inline scripts. + * + * @return bool True if the inline script present, otherwise false. + */ + public function has_delayed_inline_script() { + foreach ( $this->registered as $handle => $script ) { + // non standalone after scripts of async or defer are usually delayed. + if ( in_array( $this->get_intended_strategy( $handle ), array( 'defer', 'async' ), true ) && + $this->has_non_standalone_inline_script( $handle, 'after' ) + ) { + return true; + } + } + return false; + } + /** * Normalize the data inside the $args parameter and support backward compatibility. * diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index f10dc6f280b2b..0ad5131e2af97 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -568,6 +568,7 @@ add_action( 'enqueue_block_editor_assets', 'wp_enqueue_editor_format_library_assets' ); add_action( 'enqueue_block_editor_assets', 'wp_enqueue_global_styles_css_custom_properties' ); add_filter( 'wp_print_scripts', 'wp_just_in_time_script_localization' ); +add_action( 'wp_print_scripts', 'wp_print_template_loader_script' ); add_filter( 'print_scripts_array', 'wp_prototype_before_jquery' ); add_filter( 'customize_controls_print_styles', 'wp_resource_hints', 1 ); add_action( 'admin_head', 'wp_check_widget_editor_deps' ); diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index f584df22de73c..a3979e7bc1e6e 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -1843,6 +1843,30 @@ function wp_just_in_time_script_localization() { ); } + +/** + * Prints a loader script if there is text/template registered script. + * + * When injected in DOM, this script converts any text/template script + * associated with a handle to type/javascript and execute them. + */ +function wp_print_template_loader_script() { + $wp_scripts = wp_scripts(); + if ( $wp_scripts->has_delayed_inline_script() ) { + $output = << { + script.setAttribute("type","text/javascript"); + eval(script.innerHTML); + }) +} +JS; + $type_attr = current_theme_supports( 'html5', 'script' ) ? '' : " type='text/javascript'"; + printf( "\n%s\n\n", $type_attr, $output ); + } +} + /** * Localizes the jQuery UI datepicker. * diff --git a/tests/phpunit/includes/utils.php b/tests/phpunit/includes/utils.php index 30af6aa348490..371b7c3d09fcc 100644 --- a/tests/phpunit/includes/utils.php +++ b/tests/phpunit/includes/utils.php @@ -645,3 +645,47 @@ function test_rest_expand_compact_links( $links ) { } return $links; } + +/** + * Removes all handles from $wp_script. + */ +function unregister_all_script_handles() { + global $wp_scripts; + + /** + * Do not deregister following library through this function. + */ + $libraries = array( + 'jquery', + 'jquery-core', + 'jquery-migrate', + 'jquery-ui-core', + 'jquery-ui-accordion', + 'jquery-ui-autocomplete', + 'jquery-ui-button', + 'jquery-ui-datepicker', + 'jquery-ui-dialog', + 'jquery-ui-draggable', + 'jquery-ui-droppable', + 'jquery-ui-menu', + 'jquery-ui-mouse', + 'jquery-ui-position', + 'jquery-ui-progressbar', + 'jquery-ui-resizable', + 'jquery-ui-selectable', + 'jquery-ui-slider', + 'jquery-ui-sortable', + 'jquery-ui-spinner', + 'jquery-ui-tabs', + 'jquery-ui-tooltip', + 'jquery-ui-widget', + 'backbone', + 'underscore', + ); + + foreach ( $wp_scripts->registered as $handle_name => $handle ) { + if ( ! in_array( $handle_name, $libraries, true ) ) { + wp_deregister_script( $handle_name ); + } + } +} diff --git a/tests/phpunit/tests/dependencies/scripts.php b/tests/phpunit/tests/dependencies/scripts.php index 218d2ace456f9..090684c105e8b 100644 --- a/tests/phpunit/tests/dependencies/scripts.php +++ b/tests/phpunit/tests/dependencies/scripts.php @@ -70,34 +70,43 @@ public function test_wp_enqueue_script() { */ public function test_non_standalone_and_standalone_after_script_combined() { // If a main script containing a `defer` strategy has an `after` inline script, the expected script type is type='javascript', otherwise type='text/template'. + unregister_all_script_handles(); wp_enqueue_script( 'ms-isinsa-1', 'http://example.org/ms-isinsa-1.js', array(), null, array( 'strategy' => 'defer' ) ); wp_add_inline_script( 'ms-isinsa-1', 'console.log("after one");', 'after', true ); wp_add_inline_script( 'ms-isinsa-1', 'console.log("after two");', 'after' ); - $output = get_echo( 'wp_print_scripts' ); - $expected = "\n"; - $expected .= "\n"; - $expected .= "\n"; + $output = get_echo( 'wp_print_scripts' ); + $expected = << +function wpLoadAfterScripts( handle ) { + let scripts = document.querySelectorAll(`[type="text/template"][data-wp-executes-after="\${handle}"]`); + scripts.forEach( (script) => { + script.setAttribute("type","text/javascript"); + eval(script.innerHTML); + }) +} + + + + + +EXP; $this->assertSame( $expected, $output ); } /** - * Test `standalone` inline scripts in the `after` position. + * Test `standalone` inline scripts in the `after` position with deferred main script. + * + * If the main script with a `defer` loading strategy has an `after` inline script, + * the inline script should not be affected. * * @ticket 12009 - * @dataProvider data_standalone_after_inline_script */ - public function test_standalone_after_inline_script( $expected, $output, $message ) { - $this->assertSame( $expected, $output, $message ); - } - - public function data_standalone_after_inline_script() { - $data = array(); - - // If the main script with a `defer` loading strategy has an `after` inline script, the inline script should not be affected. + public function test_standalone_after_inline_script_with_defer_main_script() { + unregister_all_script_handles(); wp_enqueue_script( 'ms-isa-1', 'http://example.org/ms-isa-1.js', array(), null, array( 'strategy' => 'defer' ) ); wp_add_inline_script( 'ms-isa-1', 'console.log("after one");', 'after', true ); $output = get_echo( 'wp_print_scripts' ); @@ -105,9 +114,19 @@ public function data_standalone_after_inline_script() { $expected .= "\n"; - array_push( $data, array( $expected, $output, 'Expected no type attribute for inline script.' ) ); + $this->assertSame( $expected, $output ); + } - // If a main script with an `async` strategy has an `after` inline script, the inline script should not be affected. + /** + * Test `standalone` inline scripts in the `after` position with async main script. + * + * If the main script with async strategy has a `after` inline script, + * the inline script should not be affected. + * + * @ticket 12009 + */ + public function test_standalone_after_inline_script_with_async_main_script() { + unregister_all_script_handles(); wp_enqueue_script( 'ms-isa-2', 'http://example.org/ms-isa-2.js', array(), null, array( 'strategy' => 'defer' ) ); wp_add_inline_script( 'ms-isa-2', 'console.log("after one");', 'after', true ); $output = get_echo( 'wp_print_scripts' ); @@ -115,87 +134,135 @@ public function data_standalone_after_inline_script() { $expected .= "\n"; - array_push( $data, array( $expected, $output, 'Expected no type attribute for inline script.' ) ); - - return $data; + $this->assertSame( $expected, $output ); } /** - * Test non standalone inline scripts in the `after` position. + * Test non standalone inline scripts in the `after` position with deferred main script. + * + * If a main script with a `defer` loading strategy has an `after` inline script, + * the inline script should be rendered as type='text/template'. + * The common loader script should also be injected in this case. * * @ticket 12009 - * @dataProvider data_non_standalone_after_inline_script */ - public function test_non_standalone_after_inline_script( $expected, $output, $message ) { - $this->assertSame( $expected, $output, $message ); - } - - public function data_non_standalone_after_inline_script() { - $data = array(); - - // If a main script with a `defer` loading strategy has an `after` inline script, the inline script should be rendered as type='module'. + public function test_non_standalone_after_inline_script_with_defer_main_script() { + unregister_all_script_handles(); wp_enqueue_script( 'ms-insa-1', 'http://example.org/ms-insa-1.js', array(), null, array( 'strategy' => 'defer' ) ); wp_add_inline_script( 'ms-insa-1', 'console.log("after one");', 'after' ); - $output = get_echo( 'wp_print_scripts' ); - $expected = "\n"; - $expected .= "\n"; - array_push( $data, array( $expected, $output, 'Expected type="text/template" for inline script.' ) ); + $output = get_echo( 'wp_print_scripts' ); + $expected = << +function wpLoadAfterScripts( handle ) { + let scripts = document.querySelectorAll(`[type="text/template"][data-wp-executes-after="\${handle}"]`); + scripts.forEach( (script) => { + script.setAttribute("type","text/javascript"); + eval(script.innerHTML); + }) +} + + + - // If a main script with an `async` loading strategy has an `after` inline script, the inline script should be rendered as type='module'. - wp_enqueue_script( 'ms-insa-2', 'http://example.org/ms-insa-2.js', array(), null, array( 'strategy' => 'defer' ) ); +EXP; + $this->assertSame( $expected, $output ); + } + + /** + * Test non standalone inline scripts in the `after` position with async main script. + * + * If a main script with an `async` loading strategy has an `after` inline script, + * the inline script should be rendered as type='text/template'. + * The common loader script should also be injected in this case. + * + * @ticket 12009 + */ + public function test_non_standalone_after_inline_script_with_async_main_script() { + unregister_all_script_handles(); + wp_enqueue_script( 'ms-insa-2', 'http://example.org/ms-insa-2.js', array(), null, array( 'strategy' => 'async' ) ); wp_add_inline_script( 'ms-insa-2', 'console.log("after one");', 'after' ); - $output = get_echo( 'wp_print_scripts' ); - $expected = "\n"; - $expected .= "\n"; - array_push( $data, array( $expected, $output, 'Expected type="text/template" for inline script.' ) ); + $output = get_echo( 'wp_print_scripts' ); + $expected = << +function wpLoadAfterScripts( handle ) { + let scripts = document.querySelectorAll(`[type="text/template"][data-wp-executes-after="\${handle}"]`); + scripts.forEach( (script) => { + script.setAttribute("type","text/javascript"); + eval(script.innerHTML); + }) +} + + + - // If a main script with a `blocking` strategy has an `after` inline script, the inline script should be rendered as type='javascript'. +EXP; + $this->assertSame( $expected, $output ); + } + + /** + * Test non standalone inline scripts in the `after` position with blocking main script. + * + * If a main script with a `blocking` strategy has an `after` inline script, + * the inline script should be rendered as type='text/javascript'. + * + * @ticket 12009 + */ + public function test_non_standalone_after_inline_script_with_blocking_main_script() { + unregister_all_script_handles(); wp_enqueue_script( 'ms-insa-3', 'http://example.org/ms-insa-3.js', array(), null, array( 'strategy' => 'blocking' ) ); wp_add_inline_script( 'ms-insa-3', 'console.log("after one");', 'after' ); - $output = get_echo( 'wp_print_scripts' ); + $output = get_echo( 'wp_print_scripts' ); + $expected = "\n"; $expected .= "\n"; - array_push( $data, array( $expected, $output, 'Expected no type attribute for inline script.' ) ); - // If a main script with no loading strategy has an `after` inline script, the inline script should be rendered as type='javascript'. + $this->assertSame( $expected, $output ); + } + + /** + * Test non standalone inline scripts in the `after` position with deferred main script. + * + * If a main script with no loading strategy has an `after` inline script, + * the inline script should be rendered as type='text/javascript'. + * + * @ticket 12009 + */ + public function test_non_standalone_after_inline_script_with_main_script_with_no_strategy() { + unregister_all_script_handles(); wp_enqueue_script( 'ms-insa-4', 'http://example.org/ms-insa-4.js', array(), null ); wp_add_inline_script( 'ms-insa-4', 'console.log("after one");', 'after' ); - $output = get_echo( 'wp_print_scripts' ); + $output = get_echo( 'wp_print_scripts' ); + $expected = "\n"; $expected .= "\n"; - array_push( $data, array( $expected, $output, 'Expected no type attribute for inline script.' ) ); - return $data; + $this->assertSame( $expected, $output ); } /** * Test non standalone `before` inline scripts attached to deferred main scripts. * + * If the main script has a `before` inline script, all dependencies will be blocking. + * * @ticket 12009 - * @dataProvider data_non_standalone_before_inline_script_with_defer */ - public function test_non_standalone_before_inline_script_with_defer( $expected, $output, $message ) { - $this->assertSame( $expected, $output, $message ); - } - - public function data_non_standalone_before_inline_script_with_defer() { - $data = array(); - - // If the main script has a `before` inline script, all dependencies will be blocking. + public function test_non_standalone_before_inline_script_with_defer_main_script() { + unregister_all_script_handles(); wp_enqueue_script( 'ds-i1-1', 'http://example.org/ds-i1-1.js', array(), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ds-i1-2', 'http://example.org/ds-i1-2.js', array(), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ds-i1-3', 'http://example.org/ds-i1-3.js', array(), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ms-i1-1', 'http://example.org/ms-i1-1.js', array( 'ds-i1-1', 'ds-i1-2', 'ds-i1-3' ), null, array( 'strategy' => 'defer' ) ); wp_add_inline_script( 'ms-i1-1', 'console.log("before one");', 'before' ); - $output = get_echo( 'wp_print_scripts' ); + $output = get_echo( 'wp_print_scripts' ); + $expected = "\n"; $expected .= "\n"; $expected .= "\n"; @@ -203,15 +270,26 @@ public function data_non_standalone_before_inline_script_with_defer() { $expected .= "console.log(\"before one\");\n"; $expected .= "\n"; $expected .= "\n"; - array_push( $data, array( $expected, $output, 'All dependency in the chain should be blocking' ) ); - // If any of the dependencies in the chain have a `before` inline script, all scripts above it should be blocking. + $this->assertSame( $expected, $output ); + } + + /** + * Test non standalone `before` inline scripts attached to a dependency scripts in a all scripts `defer` chain. + * + * If any of the dependencies in the chain have a `before` inline script, all scripts above it should be blocking. + * + * @ticket 12009 + */ + public function test_non_standalone_before_inline_script_on_dependency_script() { + unregister_all_script_handles(); wp_enqueue_script( 'ds-i2-1', 'http://example.org/ds-i2-1.js', array(), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ds-i2-2', 'http://example.org/ds-i2-2.js', array( 'ds-i2-1' ), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ds-i2-3', 'http://example.org/ds-i2-3.js', array( 'ds-i2-2' ), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ms-i2-1', 'http://example.org/ms-i2-1.js', array( 'ds-i2-3' ), null, array( 'strategy' => 'defer' ) ); wp_add_inline_script( 'ds-i2-2', 'console.log("before one");', 'before' ); - $output = get_echo( 'wp_print_scripts' ); + $output = get_echo( 'wp_print_scripts' ); + $expected = "\n"; $expected .= "\n"; $expected .= "\n"; $expected .= "\n"; - array_push( $data, array( $expected, $output, 'Scripts in the chain before the script having before must be blocking.' ) ); - // If the top most dependency in the chain has a `before` inline script, none of the scripts bellow it will be blocking. + $this->assertSame( $expected, $output ); + } + + /** + * Test non standalone `before` inline scripts attached to top most dependency in a all scripts `defer` chain. + * + * If the top most dependency in the chain has a `before` inline script, + * none of the scripts bellow it will be blocking. + * + * @ticket 12009 + */ + public function test_non_standalone_before_inline_script_on_top_most_dependency_script() { + unregister_all_script_handles(); wp_enqueue_script( 'ds-i3-1', 'http://example.org/ds-i3-1.js', array(), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ds-i3-2', 'http://example.org/ds-i3-2.js', array( 'ds-i3-1' ), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ms-i3-1', 'http://example.org/ms-i3-1.js', array( 'ds-i3-2' ), null, array( 'strategy' => 'defer' ) ); wp_add_inline_script( 'ds-i3-1', 'console.log("before one");', 'before' ); - $output = get_echo( 'wp_print_scripts' ); + $output = get_echo( 'wp_print_scripts' ); + $expected = "\n"; $expected .= "\n"; $expected .= "\n"; $expected .= "\n"; - array_push( $data, array( $expected, $output, 'Top most has before inline script. All the script in the chain defer.' ) ); - // If there are two dependency chains, rules are applied to the scripts in the chain that contain a `before` inline script. + $this->assertSame( $expected, $output ); + } + + /** + * Test non standalone `before` inline scripts attached to one the chain, of the two all scripts `defer` chains. + * + * If there are two dependency chains, rules are applied to the scripts in the chain that contain a `before` inline script. + * + * @ticket 12009 + */ + public function test_non_standalone_before_inline_script_on_multiple_defer_script_chain() { + unregister_all_script_handles(); wp_enqueue_script( 'ch1-ds-i4-1', 'http://example.org/ch1-ds-i4-1.js', array(), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ch1-ds-i4-2', 'http://example.org/ch1-ds-i4-2.js', array( 'ch1-ds-i4-1' ), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ch2-ds-i4-1', 'http://example.org/ch2-ds-i4-1.js', array(), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ch2-ds-i4-2', 'http://example.org/ch2-ds-i4-2.js', array( 'ch2-ds-i4-1' ), null, array( 'strategy' => 'defer' ) ); wp_add_inline_script( 'ch2-ds-i4-2', 'console.log("before one");', 'before' ); wp_enqueue_script( 'ms-i4-1', 'http://example.org/ms-i4-1.js', array( 'ch2-ds-i4-1', 'ch2-ds-i4-2' ), null, array( 'strategy' => 'defer' ) ); - $output = get_echo( 'wp_print_scripts' ); + $output = get_echo( 'wp_print_scripts' ); + $expected = "\n"; $expected .= "\n"; $expected .= "\n"; @@ -251,31 +352,27 @@ public function data_non_standalone_before_inline_script_with_defer() { $expected .= "\n"; $expected .= "\n"; $expected .= "\n"; - array_push( $data, array( $expected, $output, 'Only top dependency script in chain two should be blocking.' ) ); - return $data; + $this->assertSame( $expected, $output ); } /** - * Test standalone tests. + * Test `standalone` inline scripts in the `before` position with deferred main script. + * + * If the main script has a `before` inline script, `standalone` doesn't apply to + * any inline script associated with the main script. * * @ticket 12009 - * @dataProvider data_standalone_inline_script */ - public function test_standalone_inline_script( $expected, $output, $message ) { - $this->assertSame( $expected, $output, $message ); - } - - public function data_standalone_inline_script() { - $data = array(); - - // If the main script has a `before` inline script, `standalone` doesn't apply to any inline script associated with the main script. + public function test_standalone_before_inline_script_with_defer_main_script() { + unregister_all_script_handles(); wp_enqueue_script( 'ds-is1-1', 'http://example.org/ds-is1-1.js', array(), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ds-is1-2', 'http://example.org/ds-is1-2.js', array(), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ds-is1-3', 'http://example.org/ds-is1-3.js', array(), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ms-is1-1', 'http://example.org/ms-is1-1.js', array( 'ds-is1-1', 'ds-is1-2', 'ds-is1-3' ), null, array( 'strategy' => 'defer' ) ); wp_add_inline_script( 'ms-is1-1', 'console.log("before one");', 'before', true ); - $output = get_echo( 'wp_print_scripts' ); + $output = get_echo( 'wp_print_scripts' ); + $expected = "\n"; $expected .= "\n"; $expected .= "\n"; @@ -283,15 +380,27 @@ public function data_standalone_inline_script() { $expected .= "console.log(\"before one\");\n"; $expected .= "\n"; $expected .= "\n"; - array_push( $data, array( $expected, $output, 'All dependency in the chain should be blocking' ) ); - // If one of the dependencies in the chain has a `before` inline script associated with it, `standalone` doesn't apply to any inline script(s) associated with the main script. + $this->assertSame( $expected, $output ); + } + + /** + * Test `standalone` inline scripts in the `before` position with defer main script. + * + * If one of the deferred dependencies in the chain has a `before` inline `standalone` script associated with it, + * strategy of the dependencies above it remains unchanged. + * + * @ticket 12009 + */ + public function test_standalone_before_inline_script_with_defer_dependency_script() { + unregister_all_script_handles(); wp_enqueue_script( 'ds-is2-1', 'http://example.org/ds-is2-1.js', array(), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ds-is2-2', 'http://example.org/ds-is2-2.js', array( 'ds-is2-1' ), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ds-is2-3', 'http://example.org/ds-is2-3.js', array( 'ds-is2-2' ), null, array( 'strategy' => 'defer' ) ); wp_enqueue_script( 'ms-is2-1', 'http://example.org/ms-is2-1.js', array( 'ds-is2-3' ), null, array( 'strategy' => 'defer' ) ); wp_add_inline_script( 'ds-is2-2', 'console.log("before one");', 'before', true ); - $output = get_echo( 'wp_print_scripts' ); + $output = get_echo( 'wp_print_scripts' ); + $expected = "\n"; $expected .= "\n"; $expected .= "\n"; $expected .= "\n"; - array_push( $data, array( $expected, $output, 'Scripts in the chain before the script having before must be blocking.' ) ); - return $data; + $this->assertSame( $expected, $output ); } /** @@ -348,6 +456,11 @@ public function test_loading_strategy_with_valid_defer_registration( $expected, $this->assertStringContainsString( $expected, $output, $message ); } + /** + * Data provider. + * + * @return array + */ public function data_loading_strategy_with_valid_defer_registration() { $data = array();