Skip to content

Commit

Permalink
Merge pull request #49 from 10up/enhancement/add_text_template
Browse files Browse the repository at this point in the history
Add text template
  • Loading branch information
10upsimon authored Apr 3, 2023
2 parents 28ba27c + 4cc2502 commit 0007785
Show file tree
Hide file tree
Showing 5 changed files with 397 additions and 41 deletions.
73 changes: 67 additions & 6 deletions src/wp-includes/class-wp-scripts.php
Original file line number Diff line number Diff line change
Expand Up @@ -294,15 +294,44 @@ public function do_item( $handle, $group = false ) {
$cond_after = "<![endif]-->\n";
}

$strategy = $this->get_eligible_loading_strategy( $handle );

$before_handle = $this->print_inline_script( $handle, 'before', false );
$after_handle = $this->print_inline_script( $handle, 'after', false );

if ( $before_handle ) {
$before_handle = sprintf( "<script%s id='%s-js-before'>\n%s\n</script>\n", $this->type_attr, esc_attr( $handle ), $before_handle );
}

if ( $after_handle ) {
$after_handle = sprintf( "<script%s id='%s-js-after'>\n%s\n</script>\n", $this->type_attr, esc_attr( $handle ), $after_handle );
$after_handle = '';
if ( '' === $strategy ) {
$after_handle = $this->print_inline_script( $handle, 'after', false );

if ( $after_handle ) {
$after_handle = sprintf( "<script%s id='%s-js-after'>\n%s\n</script>\n", $this->type_attr, esc_attr( $handle ), $after_handle );
}
} else {
$after_standalone_handle = $this->print_inline_script( $handle, 'after-standalone', false );

if ( $after_standalone_handle ) {
$after_handle .= sprintf( "<script%s id='%s-js-after'>\n%s\n</script>\n", $this->type_attr, esc_attr( $handle ), $after_standalone_handle );
}

$after_non_standalone_handle = $this->print_inline_script( $handle, 'after-non-standalone', false );

if ( $after_non_standalone_handle ) {
$initial_type_attr = $this->type_attr;
$this->type_attr = " type='text/template'";
$after_handle .= sprintf(
'<script%1$s id=\'%2$s-js-after\' data-wp-executes-after=\'%2$s\'>%4$s%3$s%4$s</script>%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;
}
}

if ( $before_handle || $after_handle ) {
Expand Down Expand Up @@ -390,9 +419,11 @@ public function do_item( $handle, $group = false ) {
return true;
}

$strategy = $this->get_eligible_loading_strategy( $handle );
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(
Expand All @@ -402,7 +433,6 @@ public function do_item( $handle, $group = false ) {
esc_attr( $handle ),
$strategy
);
// TODO: Handle onload logic for defer/async here.
$tag .= $after_handle . $cond_after;

/**
Expand Down Expand Up @@ -482,7 +512,21 @@ public function print_inline_script( $handle, $position = 'after', $display = tr
$output = trim( implode( "\n", $output ), "\n" );

if ( $display ) {
printf( "<script%s id='%s-js-%s'>\n%s\n</script>\n", $this->type_attr, esc_attr( $handle ), esc_attr( $position ), $output );
if ( 'after-non-standalone' === $position ) {
$initial_type_attr = $this->type_attr;
$this->type_attr = " type='text/template'";
printf(
'<script%1$s id=\'%2$s-js-after\' type=\'text/template\' data-wp-executes-after=\'%2$s\'>%5$s%4$s%5$s</script>%5$s',
$this->type_attr,
esc_attr( $handle ),
esc_attr( $position ),
$output,
PHP_EOL
);
$this->type_attr = $initial_type_attr;
} else {
printf( "<script%s id='%s-js-%s'>\n%s\n</script>\n", $this->type_attr, esc_attr( $handle ), esc_attr( $position ), $output );
}
}

return $output;
Expand Down Expand Up @@ -751,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.
*
Expand Down
1 change: 1 addition & 0 deletions src/wp-includes/default-filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' );
Expand Down
24 changes: 24 additions & 0 deletions src/wp-includes/script-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <<<JS
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);
})
}
JS;
$type_attr = current_theme_supports( 'html5', 'script' ) ? '' : " type='text/javascript'";
printf( "<script%s id='wp-executes-after-js'>\n%s\n</script>\n", $type_attr, $output );
}
}

/**
* Localizes the jQuery UI datepicker.
*
Expand Down
44 changes: 44 additions & 0 deletions tests/phpunit/includes/utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
}
}
}
Loading

0 comments on commit 0007785

Please sign in to comment.