Script Loader: Introduce HTML5 support for scripts and styles.

When a theme declares HTML5 support for script and styles via `add_theme_support( 'html5', array( 'script', 'style' ) )`, the `type="text/javascript"` and `type="text/css"` attributes are omitted.

These attributes are unnecessary in HTML5 and cause warnings in the W3C Markup Validation Service.

Props sasiddiqui, swissspidy, knutsp, SergeyBiryukov.
See #42804.

git-svn-id: https://develop.svn.wordpress.org/trunk@46164 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Sergey Biryukov 2019-09-18 14:49:30 +00:00
parent 0dbd752500
commit 5fdf48c0ec
13 changed files with 173 additions and 47 deletions

View File

@ -1117,8 +1117,9 @@ function wp_admin_bar_add_secondary_groups( $wp_admin_bar ) {
* @since 3.1.0
*/
function wp_admin_bar_header() {
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
?>
<style type="text/css" media="print">#wpadminbar { display:none; }</style>
<style<?php echo $type_attr; ?> media="print">#wpadminbar { display:none; }</style>
<?php
}
@ -1128,9 +1129,9 @@ function wp_admin_bar_header() {
* @since 3.1.0
*/
function _admin_bar_bump_cb() {
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
?>
<style type="text/css" media="screen">
<style<?php echo $type_attr; ?> media="screen">
html { margin-top: 32px !important; }
* html body { margin-top: 32px !important; }
@media screen and ( max-width: 782px ) {

View File

@ -122,6 +122,17 @@ class WP_Scripts extends WP_Dependencies {
*/
public $default_dirs;
/**
* Holds a string which contains the type attribute for script tag.
*
* If the current theme does not declare HTML5 support for 'script',
* then it initializes as `type='text/javascript'`.
*
* @since 5.3.0
* @var string
*/
private $type_attr = '';
/**
* Constructor.
*
@ -130,6 +141,10 @@ class WP_Scripts extends WP_Dependencies {
public function __construct() {
$this->init();
add_action( 'init', array( $this, 'init' ), 0 );
if ( ! current_theme_supports( 'html5', 'script' ) ) {
$this->type_attr = " type='text/javascript'";
}
}
/**
@ -205,7 +220,7 @@ class WP_Scripts extends WP_Dependencies {
return $output;
}
echo "<script type='text/javascript'>\n"; // CDATA and type='text/javascript' is not needed for HTML 5.
echo "<script{$this->type_attr}>\n"; // CDATA and type="text/javascript" is not needed for HTML 5.
echo "/* <![CDATA[ */\n";
echo "$output\n";
echo "/* ]]> */\n";
@ -266,15 +281,15 @@ class WP_Scripts extends WP_Dependencies {
$after_handle = $this->print_inline_script( $handle, 'after', false );
if ( $before_handle ) {
$before_handle = sprintf( "<script type='text/javascript'>\n%s\n</script>\n", $before_handle );
$before_handle = sprintf( "<script%s>\n%s\n</script>\n", $this->type_attr, $before_handle );
}
if ( $after_handle ) {
$after_handle = sprintf( "<script type='text/javascript'>\n%s\n</script>\n", $after_handle );
$after_handle = sprintf( "<script%s>\n%s\n</script>\n", $this->type_attr, $after_handle );
}
if ( $before_handle || $after_handle ) {
$inline_script_tag = "{$cond_before}{$before_handle}{$after_handle}{$cond_after}";
$inline_script_tag = $cond_before . $before_handle . $after_handle . $cond_after;
} else {
$inline_script_tag = '';
}
@ -334,7 +349,7 @@ class WP_Scripts extends WP_Dependencies {
$translations = $this->print_translations( $handle, false );
if ( $translations ) {
$translations = sprintf( "<script type='text/javascript'>\n%s\n</script>\n", $translations );
$translations = sprintf( "<script%s>\n%s\n</script>\n", $this->type_attr, $translations );
}
if ( ! preg_match( '|^(https?:)?//|', $src ) && ! ( $this->content_url && 0 === strpos( $src, $this->content_url ) ) ) {
@ -352,7 +367,9 @@ class WP_Scripts extends WP_Dependencies {
return true;
}
$tag = "{$translations}{$cond_before}{$before_handle}<script type='text/javascript' src='$src'></script>\n{$after_handle}{$cond_after}";
$tag = $translations . $cond_before . $before_handle;
$tag .= sprintf( "<script%s src='%s'></script>\n", $this->type_attr, $src );
$tag .= $after_handle . $cond_after;
/**
* Filters the HTML script tag of an enqueued script.
@ -422,7 +439,7 @@ class WP_Scripts extends WP_Dependencies {
$output = trim( implode( "\n", $output ), "\n" );
if ( $echo ) {
printf( "<script type='text/javascript'>\n%s\n</script>\n", $output );
printf( "<script%s>\n%s\n</script>\n", $this->type_attr, $output );
}
return $output;
@ -557,7 +574,7 @@ class WP_Scripts extends WP_Dependencies {
JS;
if ( $echo ) {
printf( "<script type='text/javascript'>\n%s\n</script>\n", $output );
printf( "<script%s>\n%s\n</script>\n", $this->type_attr, $output );
}
return $output;

View File

@ -100,6 +100,17 @@ class WP_Styles extends WP_Dependencies {
*/
public $default_dirs;
/**
* Holds a string which contains the type attribute for style tag.
*
* If the current theme does not declare HTML5 support for 'style',
* then it initializes as `type='text/css'`.
*
* @since 5.3.0
* @var string
*/
private $type_attr = '';
/**
* Constructor.
*
@ -114,6 +125,10 @@ class WP_Styles extends WP_Dependencies {
* @param WP_Styles $this WP_Styles instance (passed by reference).
*/
do_action_ref_array( 'wp_default_styles', array( &$this ) );
if ( ! current_theme_supports( 'html5', 'style' ) ) {
$this->type_attr = " type='text/css'";
}
}
/**
@ -156,7 +171,12 @@ class WP_Styles extends WP_Dependencies {
$inline_style = $this->print_inline_style( $handle, false );
if ( $inline_style ) {
$inline_style_tag = sprintf( "<style id='%s-inline-css' type='text/css'>\n%s\n</style>\n", esc_attr( $handle ), $inline_style );
$inline_style_tag = sprintf(
"<style id='%s-inline-css'%s>\n%s\n</style>\n",
esc_attr( $handle ),
$this->type_attr,
$inline_style
);
} else {
$inline_style_tag = '';
}
@ -197,9 +217,17 @@ class WP_Styles extends WP_Dependencies {
}
$rel = isset( $obj->extra['alt'] ) && $obj->extra['alt'] ? 'alternate stylesheet' : 'stylesheet';
$title = isset( $obj->extra['title'] ) ? "title='" . esc_attr( $obj->extra['title'] ) . "'" : '';
$title = isset( $obj->extra['title'] ) ? sprintf( "title='%s'", esc_attr( $obj->extra['title'] ) ) : '';
$tag = "<link rel='$rel' id='$handle-css' $title href='$href' type='text/css' media='$media' />\n";
$tag = sprintf(
"<link rel='%s' id='%s-css' %s href='%s'%s media='%s' />\n",
$rel,
$handle,
$title,
$href,
$this->type_attr,
$media
);
/**
* Filters the HTML link tag of an enqueued style.
@ -223,7 +251,16 @@ class WP_Styles extends WP_Dependencies {
$rtl_href = $this->_css_href( $obj->extra['rtl'], $ver, "$handle-rtl" );
}
$rtl_tag = "<link rel='$rel' id='$handle-rtl-css' $title href='$rtl_href' type='text/css' media='$media' />\n";
$rtl_tag = sprintf(
"<link rel='%s' id='%s-rtl-css' %s href='%s'%s media='%s' />\n",
$rel,
$handle,
$title,
$rtl_href,
$this->type_attr,
$media
);
/** This filter is documented in wp-includes/class.wp-styles.php */
$rtl_tag = apply_filters( 'style_loader_tag', $rtl_tag, $handle, $rtl_href, $media );
@ -298,7 +335,12 @@ class WP_Styles extends WP_Dependencies {
return $output;
}
printf( "<style id='%s-inline-css' type='text/css'>\n%s\n</style>\n", esc_attr( $handle ), $output );
printf(
"<style id='%s-inline-css'%s>\n%s\n</style>\n",
esc_attr( $handle ),
$this->type_attr,
$output
);
return true;
}

View File

@ -1000,8 +1000,9 @@ function enqueue_embed_scripts() {
* @since 4.4.0
*/
function print_embed_styles() {
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
?>
<style type="text/css">
<style<?php echo $type_attr; ?>>
<?php
if ( SCRIPT_DEBUG ) {
readfile( ABSPATH . WPINC . '/css/wp-embed-template.css' );
@ -1031,8 +1032,9 @@ function print_embed_styles() {
* @since 4.4.0
*/
function print_embed_scripts() {
$type_attr = current_theme_supports( 'html5', 'script' ) ? '' : ' type="text/javascript"';
?>
<script type="text/javascript">
<script<?php echo $type_attr; ?>>
<?php
if ( SCRIPT_DEBUG ) {
readfile( ABSPATH . WPINC . '/js/wp-embed-template.js' );

View File

@ -5435,8 +5435,10 @@ function print_emoji_styles() {
}
$printed = true;
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
?>
<style type="text/css">
<style<?php echo $type_attr; ?>>
img.wp-smiley,
img.emoji {
display: inline !important;
@ -5517,7 +5519,8 @@ function _print_emoji_detection_script() {
'svgExt' => apply_filters( 'emoji_svg_ext', '.svg' ),
);
$version = 'ver=' . get_bloginfo( 'version' );
$version = 'ver=' . get_bloginfo( 'version' );
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/javascript"';
if ( SCRIPT_DEBUG ) {
$settings['source'] = array(
@ -5528,7 +5531,7 @@ function _print_emoji_detection_script() {
);
?>
<script type="text/javascript">
<script<?php echo $type_attr; ?>>
window._wpemojiSettings = <?php echo wp_json_encode( $settings ); ?>;
<?php readfile( ABSPATH . WPINC . '/js/wp-emoji-loader.js' ); ?>
</script>
@ -5550,7 +5553,7 @@ function _print_emoji_detection_script() {
* and edit wp-emoji-loader.js directly.
*/
?>
<script type="text/javascript">
<script<?php echo $type_attr; ?>>
window._wpemojiSettings = <?php echo wp_json_encode( $settings ); ?>;
include "js/wp-emoji-loader.min.js"
</script>

View File

@ -1944,8 +1944,10 @@ function gallery_shortcode( $attr ) {
* Otherwise, defaults to true.
*/
if ( apply_filters( 'use_default_gallery_style', ! $html5 ) ) {
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
$gallery_style = "
<style type='text/css'>
<style{$type_attr}>
#{$selector} {
margin: auto;
}

View File

@ -2465,11 +2465,12 @@ function _print_scripts() {
$zip = 'gzip';
}
$concat = trim( $wp_scripts->concat, ', ' );
$concat = trim( $wp_scripts->concat, ', ' );
$type_attr = current_theme_supports( 'html5', 'script' ) ? '' : " type='text/javascript'";
if ( $concat ) {
if ( ! empty( $wp_scripts->print_code ) ) {
echo "\n<script type='text/javascript'>\n";
echo "\n<script{$type_attr}>\n";
echo "/* <![CDATA[ */\n"; // not needed in HTML 5
echo $wp_scripts->print_code;
echo "/* ]]> */\n";
@ -2484,7 +2485,7 @@ function _print_scripts() {
}
$src = $wp_scripts->base_url . "/wp-admin/load-scripts.php?c={$zip}" . $concatenated . '&ver=' . $wp_scripts->default_version;
echo "<script type='text/javascript' src='" . esc_attr( $src ) . "'></script>\n";
echo "<script{$type_attr} src='" . esc_attr( $src ) . "'></script>\n";
}
if ( ! empty( $wp_scripts->print_html ) ) {
@ -2646,7 +2647,8 @@ function _print_styles() {
$zip = 'gzip';
}
$concat = trim( $wp_styles->concat, ', ' );
$concat = trim( $wp_styles->concat, ', ' );
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
if ( $concat ) {
$dir = $wp_styles->text_direction;
@ -2660,10 +2662,10 @@ function _print_styles() {
}
$href = $wp_styles->base_url . "/wp-admin/load-styles.php?c={$zip}&dir={$dir}" . $concatenated . '&ver=' . $ver;
echo "<link rel='stylesheet' href='" . esc_attr( $href ) . "' type='text/css' media='all' />\n";
echo "<link rel='stylesheet' href='" . esc_attr( $href ) . "'{$type_attr} media='all' />\n";
if ( ! empty( $wp_styles->print_code ) ) {
echo "<style type='text/css'>\n";
echo "<style{$type_attr}>\n";
echo $wp_styles->print_code;
echo "\n</style>\n";
}

View File

@ -702,7 +702,14 @@ function locale_stylesheet() {
if ( empty( $stylesheet ) ) {
return;
}
echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
printf(
'<link rel="stylesheet" href="%s"%s media="screen" />',
$stylesheet,
$type_attr
);
}
/**
@ -1641,7 +1648,8 @@ function _custom_background_cb() {
if ( ! $background && ! $color ) {
if ( is_customize_preview() ) {
echo '<style type="text/css" id="custom-background-css"></style>';
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
printf( '<style%s id="custom-background-css"></style>', $type_attr );
}
return;
}
@ -1693,9 +1701,11 @@ function _custom_background_cb() {
$attachment = " background-attachment: $attachment;";
$style .= $image . $position . $size . $repeat . $attachment;
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
}
?>
<style type="text/css" id="custom-background-css">
<style<?php echo $type_attr; ?> id="custom-background-css">
body.custom-background { <?php echo trim( $style ); ?> }
</style>
<?php
@ -1709,8 +1719,9 @@ body.custom-background { <?php echo trim( $style ); ?> }
function wp_custom_css_cb() {
$styles = wp_get_custom_css();
if ( $styles || is_customize_preview() ) :
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
?>
<style type="text/css" id="wp-custom-css">
<style<?php echo $type_attr; ?> id="wp-custom-css">
<?php echo strip_tags( $styles ); // Note that esc_html() cannot be used because `div &gt; span` is not interpreted properly. ?>
</style>
<?php
@ -2335,14 +2346,15 @@ function get_theme_starter_content() {
* ) );
*
* @since 2.9.0
* @since 3.6.0 The `html5` feature was added
* @since 3.9.0 The `html5` feature now also accepts 'gallery' and 'caption'
* @since 4.1.0 The `title-tag` feature was added
* @since 4.5.0 The `customize-selective-refresh-widgets` feature was added
* @since 4.7.0 The `starter-content` feature was added
* @since 3.6.0 The `html5` feature was added.
* @since 3.9.0 The `html5` feature now also accepts 'gallery' and 'caption'.
* @since 4.1.0 The `title-tag` feature was added.
* @since 4.5.0 The `customize-selective-refresh-widgets` feature was added.
* @since 4.7.0 The `starter-content` feature was added.
* @since 5.0.0 The `responsive-embeds`, `align-wide`, `dark-editor-style`, `disable-custom-colors`,
* `disable-custom-font-sizes`, `editor-color-palette`, `editor-font-sizes`,
* `editor-styles`, and `wp-block-styles` features were added.
* @since 5.3.0 The `html5` feature now also accepts 'script' and 'style'.
*
* @global array $_wp_theme_features
*
@ -2635,9 +2647,10 @@ function _custom_logo_header_styles() {
$classes = array_map( 'sanitize_html_class', $classes );
$classes = '.' . implode( ', .', $classes );
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
?>
<!-- Custom Logo: hide header text -->
<style id="custom-logo-css" type="text/css">
<style id="custom-logo-css"<?php echo $type_attr; ?>>
<?php echo $classes; ?> {
position: absolute;
clip: rect(1px, 1px, 1px, 1px);
@ -3196,15 +3209,15 @@ function wp_customize_support_script() {
$admin_origin = parse_url( admin_url() );
$home_origin = parse_url( home_url() );
$cross_domain = ( strtolower( $admin_origin['host'] ) != strtolower( $home_origin['host'] ) );
$type_attr = current_theme_supports( 'html5', 'script' ) ? '' : ' type="text/javascript"';
?>
<!--[if lte IE 8]>
<script type="text/javascript">
<script<?php echo $type_attr; ?>>
document.body.className = document.body.className.replace( /(^|\s)(no-)?customize-support(?=\s|$)/, '' ) + ' no-customize-support';
</script>
<![endif]-->
<!--[if gte IE 9]><!-->
<script type="text/javascript">
<script<?php echo $type_attr; ?>>
(function() {
var request, b = document.body, c = 'className', cs = 'customize-support', rcs = new RegExp('(^|\\s+)(no-)?'+cs+'(\\s+|$)');

View File

@ -98,6 +98,8 @@ class WP_Widget_Archives extends WP_Widget {
$label = __( 'Select Post' );
break;
}
$type_attr = current_theme_supports( 'html5', 'script' ) ? '' : ' type="text/javascript"';
?>
<option value=""><?php echo esc_attr( $label ); ?></option>
@ -105,7 +107,7 @@ class WP_Widget_Archives extends WP_Widget {
</select>
<script type='text/javascript'>
<script<?php echo $type_attr; ?>>
/* <![CDATA[ */
(function() {
var dropdown = document.getElementById( "<?php echo esc_js( $dropdown_id ); ?>" );

View File

@ -89,9 +89,11 @@ class WP_Widget_Categories extends WP_Widget {
wp_dropdown_categories( apply_filters( 'widget_categories_dropdown_args', $cat_args, $instance ) );
echo '</form>';
$type_attr = current_theme_supports( 'html5', 'script' ) ? '' : ' type="text/javascript"';
?>
<script type='text/javascript'>
<script<?php echo $type_attr; ?>>
/* <![CDATA[ */
(function() {
var dropdown = document.getElementById( "<?php echo esc_js( $dropdown_id ); ?>" );

View File

@ -53,9 +53,13 @@ class WP_Widget_Recent_Comments extends WP_Widget {
|| ! apply_filters( 'show_recent_comments_widget_style', true, $this->id_base ) ) {
return;
}
?>
<style type="text/css">.recentcomments a{display:inline !important;padding:0 !important;margin:0 !important;}</style>
<?php
$type_attr = current_theme_supports( 'html5', 'style' ) ? '' : ' type="text/css"';
printf(
'<style%s>.recentcomments a{display:inline !important;padding:0 !important;margin:0 !important;}</style>',
$type_attr
);
}
/**

View File

@ -44,6 +44,7 @@ JS;
wp_enqueue_script( 'empty-deps-no-version', 'example.com' );
wp_enqueue_script( 'empty-deps-version', 'example.com', array(), 1.2 );
wp_enqueue_script( 'empty-deps-null-version', 'example.com', array(), null );
$ver = get_bloginfo( 'version' );
$expected = "<script type='text/javascript' src='http://example.com?ver=$ver'></script>\n";
$expected .= "<script type='text/javascript' src='http://example.com?ver=$ver'></script>\n";
@ -56,6 +57,23 @@ JS;
$this->assertEquals( '', get_echo( 'wp_print_scripts' ) );
}
/**
* @ticket 42804
*/
function test_wp_enqueue_script_with_html5_support_does_not_contain_type_attribute() {
add_theme_support( 'html5', array( 'script' ) );
$GLOBALS['wp_scripts'] = new WP_Scripts();
$GLOBALS['wp_scripts']->default_version = get_bloginfo( 'version' );
wp_enqueue_script( 'empty-deps-no-version', 'example.com' );
$ver = get_bloginfo( 'version' );
$expected = "<script src='http://example.com?ver=$ver'></script>\n";
$this->assertEquals( $expected, get_echo( 'wp_print_scripts' ) );
}
/**
* Test the different protocol references in wp_enqueue_script
*

View File

@ -56,6 +56,7 @@ class Tests_Dependencies_Styles extends WP_UnitTestCase {
wp_enqueue_style( 'no-deps-version', 'example.com', array(), 1.2 );
wp_enqueue_style( 'no-deps-null-version', 'example.com', array(), null );
wp_enqueue_style( 'no-deps-null-version-print-media', 'example.com', array(), null, 'print' );
$ver = get_bloginfo( 'version' );
$expected = "<link rel='stylesheet' id='no-deps-no-version-css' href='http://example.com?ver=$ver' type='text/css' media='all' />\n";
$expected .= "<link rel='stylesheet' id='no-deps-version-css' href='http://example.com?ver=1.2' type='text/css' media='all' />\n";
@ -68,6 +69,23 @@ class Tests_Dependencies_Styles extends WP_UnitTestCase {
$this->assertEquals( '', get_echo( 'wp_print_styles' ) );
}
/**
* @ticket 42804
*/
function test_wp_enqueue_style_with_html5_support_does_not_contain_type_attribute() {
add_theme_support( 'html5', array( 'style' ) );
$GLOBALS['wp_styles'] = new WP_Styles();
$GLOBALS['wp_styles']->default_version = get_bloginfo( 'version' );
wp_enqueue_style( 'no-deps-no-version', 'example.com' );
$ver = get_bloginfo( 'version' );
$expected = "<link rel='stylesheet' id='no-deps-no-version-css' href='http://example.com?ver=$ver' media='all' />\n";
$this->assertEquals( $expected, get_echo( 'wp_print_styles' ) );
}
/**
* Test the different protocol references in wp_enqueue_style
*