Index: /trunk/composer.json
===================================================================
--- /trunk/composer.json	(revision 56686)
+++ /trunk/composer.json	(revision 56687)
@@ -12,4 +12,7 @@
 	"require": {
 		"php": ">=7.0"
+	},
+	"suggest": {
+		"ext-dom": "*"
 	},
 	"require-dev": {
Index: /trunk/src/wp-includes/class-wp-customize-manager.php
===================================================================
--- /trunk/src/wp-includes/class-wp-customize-manager.php	(revision 56686)
+++ /trunk/src/wp-includes/class-wp-customize-manager.php	(revision 56687)
@@ -465,4 +465,6 @@
 				'error'         => $ajax_message,
 			);
+			$message .= ob_get_clean();
+			ob_start();
 			?>
 			<script>
@@ -473,5 +475,5 @@
 			</script>
 			<?php
-			$message .= ob_get_clean();
+			$message .= wp_get_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 		}
 
@@ -2084,4 +2086,5 @@
 			return;
 		}
+		ob_start();
 		?>
 		<script>
@@ -2107,4 +2110,5 @@
 		</script>
 		<?php
+		wp_print_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 	}
 
@@ -2202,6 +2206,7 @@
 		}
 
+		ob_start();
 		?>
-		<script type="text/javascript">
+		<script>
 			var _wpCustomizeSettings = <?php echo wp_json_encode( $settings ); ?>;
 			_wpCustomizeSettings.values = {};
@@ -2226,4 +2231,5 @@
 		</script>
 		<?php
+		wp_print_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 	}
 
@@ -4977,6 +4983,7 @@
 		}
 
+		ob_start();
 		?>
-		<script type="text/javascript">
+		<script>
 			var _wpCustomizeSettings = <?php echo wp_json_encode( $settings ); ?>;
 			_wpCustomizeSettings.initialClientTimestamp = _.now();
@@ -5013,4 +5020,5 @@
 		</script>
 		<?php
+		wp_print_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 	}
 
Index: /trunk/src/wp-includes/class-wp-customize-nav-menus.php
===================================================================
--- /trunk/src/wp-includes/class-wp-customize-nav-menus.php	(revision 56686)
+++ /trunk/src/wp-includes/class-wp-customize-nav-menus.php	(revision 56687)
@@ -1560,5 +1560,5 @@
 			'navMenuInstanceArgs' => $this->preview_nav_menu_instance_args,
 		);
-		printf( '<script>var _wpCustomizePreviewNavMenusExports = %s;</script>', wp_json_encode( $exports ) );
+		wp_print_inline_script_tag( sprintf( 'var _wpCustomizePreviewNavMenusExports = %s;', wp_json_encode( $exports ) ) );
 	}
 
Index: /trunk/src/wp-includes/class-wp-customize-widgets.php
===================================================================
--- /trunk/src/wp-includes/class-wp-customize-widgets.php	(revision 56686)
+++ /trunk/src/wp-includes/class-wp-customize-widgets.php	(revision 56687)
@@ -1311,10 +1311,7 @@
 			unset( $registered_widget['callback'] ); // May not be JSON-serializeable.
 		}
-
-		?>
-		<script type="text/javascript">
-			var _wpWidgetCustomizerPreviewSettings = <?php echo wp_json_encode( $settings ); ?>;
-		</script>
-		<?php
+		wp_print_inline_script_tag(
+			sprintf( 'var _wpWidgetCustomizerPreviewSettings = %s;', wp_json_encode( $settings ) )
+		);
 	}
 
Index: /trunk/src/wp-includes/class-wp-scripts.php
===================================================================
--- /trunk/src/wp-includes/class-wp-scripts.php	(revision 56686)
+++ /trunk/src/wp-includes/class-wp-scripts.php	(revision 56687)
@@ -124,15 +124,4 @@
 
 	/**
-	 * Holds a string which contains the type attribute for script tag.
-	 *
-	 * If the active theme does not declare HTML5 support for 'script',
-	 * then it initializes as `type='text/javascript'`.
-	 *
-	 * @since 5.3.0
-	 * @var string
-	 */
-	private $type_attr = '';
-
-	/**
 	 * Holds a mapping of dependents (as handles) for a given script handle.
 	 * Used to optimize recursive dependency tree checks.
@@ -168,12 +157,4 @@
 	 */
 	public function init() {
-		if (
-			function_exists( 'is_admin' ) && ! is_admin()
-		&&
-			function_exists( 'current_theme_supports' ) && ! current_theme_supports( 'html5', 'script' )
-		) {
-			$this->type_attr = " type='text/javascript'";
-		}
-
 		/**
 		 * Fires when the WP_Scripts instance is initialized.
@@ -246,18 +227,5 @@
 		}
 
-		printf( "<script%s id='%s-js-extra'>\n", $this->type_attr, esc_attr( $handle ) );
-
-		// CDATA is not needed for HTML 5.
-		if ( $this->type_attr ) {
-			echo "/* <![CDATA[ */\n";
-		}
-
-		echo "$output\n";
-
-		if ( $this->type_attr ) {
-			echo "/* ]]> */\n";
-		}
-
-		echo "</script>\n";
+		wp_print_inline_script_tag( $output, array( 'id' => "{$handle}-js-extra" ) );
 
 		return true;
@@ -336,5 +304,5 @@
 		$translations = $this->print_translations( $handle, false );
 		if ( $translations ) {
-			$translations = sprintf( "<script%s id='%s-js-translations'>\n%s\n</script>\n", $this->type_attr, esc_attr( $handle ), $translations );
+			$translations = wp_get_inline_script_tag( $translations, array( 'id' => "{$handle}-js-translations" ) );
 		}
 
@@ -404,5 +372,5 @@
 
 		/** This filter is documented in wp-includes/class-wp-scripts.php */
-		$src = esc_url( apply_filters( 'script_loader_src', $src, $handle ) );
+		$src = esc_url_raw( apply_filters( 'script_loader_src', $src, $handle ) );
 
 		if ( ! $src ) {
@@ -410,13 +378,16 @@
 		}
 
+		$attr = array(
+			'src' => $src,
+			'id'  => "{$handle}-js",
+		);
+		if ( $strategy ) {
+			$attr[ $strategy ] = true;
+		}
+		if ( $intended_strategy ) {
+			$attr['data-wp-strategy'] = $intended_strategy;
+		}
 		$tag  = $translations . $cond_before . $before_script;
-		$tag .= sprintf(
-			"<script%s src='%s' id='%s-js'%s%s></script>\n",
-			$this->type_attr,
-			$src, // Value is escaped above.
-			esc_attr( $handle ),
-			$strategy ? " {$strategy}" : '',
-			$intended_strategy ? " data-wp-strategy='{$intended_strategy}'" : ''
-		);
+		$tag .= wp_get_script_tag( $attr );
 		$tag .= $after_script . $cond_after;
 
@@ -721,5 +692,5 @@
 
 		if ( $display ) {
-			printf( "<script%s id='%s-js-translations'>\n%s\n</script>\n", $this->type_attr, esc_attr( $handle ), $output );
+			wp_print_inline_script_tag( $output, array( 'id' => "{$handle}-js-translations" ) );
 		}
 
Index: /trunk/src/wp-includes/comment-template.php
===================================================================
--- /trunk/src/wp-includes/comment-template.php	(revision 56686)
+++ /trunk/src/wp-includes/comment-template.php	(revision 56687)
@@ -1367,5 +1367,5 @@
 	if ( current_user_can( 'unfiltered_html' ) ) {
 		wp_nonce_field( 'unfiltered-html-comment_' . $post_id, '_wp_unfiltered_html_comment_disabled', false );
-		echo "<script>(function(){if(window===window.parent){document.getElementById('_wp_unfiltered_html_comment_disabled').name='_wp_unfiltered_html_comment';}})();</script>\n";
+		wp_print_inline_script_tag( "(function(){if(window===window.parent){document.getElementById('_wp_unfiltered_html_comment_disabled').name='_wp_unfiltered_html_comment';}})();" );
 	}
 }
Index: /trunk/src/wp-includes/customize/class-wp-customize-selective-refresh.php
===================================================================
--- /trunk/src/wp-includes/customize/class-wp-customize-selective-refresh.php	(revision 56686)
+++ /trunk/src/wp-includes/customize/class-wp-customize-selective-refresh.php	(revision 56687)
@@ -194,5 +194,5 @@
 
 		// Export data to JS.
-		printf( '<script>var _customizePartialRefreshExports = %s;</script>', wp_json_encode( $exports ) );
+		wp_print_inline_script_tag( sprintf( 'var _customizePartialRefreshExports = %s;', wp_json_encode( $exports ) ) );
 	}
 
Index: /trunk/src/wp-includes/functions.php
===================================================================
--- /trunk/src/wp-includes/functions.php	(revision 56686)
+++ /trunk/src/wp-includes/functions.php	(revision 56687)
@@ -7656,4 +7656,5 @@
 	$name = 'wp-preview-' . (int) $post->ID;
 
+	ob_start();
 	?>
 	<script>
@@ -7671,4 +7672,5 @@
 	</script>
 	<?php
+	wp_print_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 }
 
Index: /trunk/src/wp-includes/script-loader.php
===================================================================
--- /trunk/src/wp-includes/script-loader.php	(revision 56686)
+++ /trunk/src/wp-includes/script-loader.php	(revision 56687)
@@ -2788,5 +2788,9 @@
 function wp_get_script_tag( $attributes ) {
 	if ( ! isset( $attributes['type'] ) && ! is_admin() && ! current_theme_supports( 'html5', 'script' ) ) {
-		$attributes['type'] = 'text/javascript';
+		// Keep the type attribute as the first for legacy reasons (it has always been this way in core).
+		$attributes = array_merge(
+			array( 'type' => 'text/javascript' ),
+			$attributes
+		);
 	}
 	/**
@@ -2831,7 +2835,21 @@
  */
 function wp_get_inline_script_tag( $javascript, $attributes = array() ) {
-	if ( ! isset( $attributes['type'] ) && ! is_admin() && ! current_theme_supports( 'html5', 'script' ) ) {
-		$attributes['type'] = 'text/javascript';
-	}
+	$is_html5 = current_theme_supports( 'html5', 'script' ) || is_admin();
+	if ( ! isset( $attributes['type'] ) && ! $is_html5 ) {
+		// Keep the type attribute as the first for legacy reasons (it has always been this way in core).
+		$attributes = array_merge(
+			array( 'type' => 'text/javascript' ),
+			$attributes
+		);
+	}
+
+	// Ensure markup is XHTML compatible if not HTML5.
+	if ( ! $is_html5 ) {
+		$javascript = str_replace( ']]>', ']]]]><![CDATA[>', $javascript ); // Escape any existing CDATA section.
+		$javascript = sprintf( "/* <![CDATA[ */\n%s\n/* ]]> */", $javascript );
+	}
+
+	$javascript = "\n" . trim( $javascript, "\n\r " ) . "\n";
+
 	/**
 	 * Filters attributes to be added to a script tag.
@@ -2845,6 +2863,4 @@
 	 */
 	$attributes = apply_filters( 'wp_inline_script_attributes', $attributes, $javascript );
-
-	$javascript = "\n" . trim( $javascript, "\n\r " ) . "\n";
 
 	return sprintf( "<script%s>%s</script>\n", wp_sanitize_script_attributes( $attributes ), $javascript );
Index: /trunk/src/wp-includes/theme-templates.php
===================================================================
--- /trunk/src/wp-includes/theme-templates.php	(revision 56686)
+++ /trunk/src/wp-includes/theme-templates.php	(revision 56687)
@@ -161,6 +161,7 @@
 
 	/**
-	 * Print the skip-link script.
+	 * Enqueue the skip-link script.
 	 */
+	ob_start();
 	?>
 	<script>
@@ -205,4 +206,9 @@
 	</script>
 	<?php
+	$skip_link_script = str_replace( array( '<script>', '</script>' ), '', ob_get_clean() );
+	$script_handle    = 'wp-block-template-skip-link';
+	wp_register_script( $script_handle, false );
+	wp_add_inline_script( $script_handle, $skip_link_script );
+	wp_enqueue_script( $script_handle );
 }
 
Index: /trunk/src/wp-includes/theme.php
===================================================================
--- /trunk/src/wp-includes/theme.php	(revision 56686)
+++ /trunk/src/wp-includes/theme.php	(revision 56687)
@@ -3784,7 +3784,7 @@
 	$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"';
+	ob_start();
 	?>
-	<script<?php echo $type_attr; ?>>
+	<script>
 		(function() {
 			var request, b = document.body, c = 'className', cs = 'customize-support', rcs = new RegExp('(^|\\s+)(no-)?'+cs+'(\\s+|$)');
@@ -3802,4 +3802,5 @@
 	</script>
 	<?php
+	wp_print_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 }
 
Index: /trunk/src/wp-includes/widgets/class-wp-widget-archives.php
===================================================================
--- /trunk/src/wp-includes/widgets/class-wp-widget-archives.php	(revision 56686)
+++ /trunk/src/wp-includes/widgets/class-wp-widget-archives.php	(revision 56687)
@@ -101,6 +101,4 @@
 					break;
 			}
-
-			$type_attr = current_theme_supports( 'html5', 'script' ) ? '' : ' type="text/javascript"';
 			?>
 
@@ -110,6 +108,6 @@
 		</select>
 
-<script<?php echo $type_attr; ?>>
-/* <![CDATA[ */
+			<?php ob_start(); ?>
+<script>
 (function() {
 	var dropdown = document.getElementById( "<?php echo esc_js( $dropdown_id ); ?>" );
@@ -121,7 +119,7 @@
 	dropdown.onchange = onSelectChange;
 })();
-/* ]]> */
 </script>
 			<?php
+			wp_print_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 		} else {
 			$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
Index: /trunk/src/wp-includes/widgets/class-wp-widget-categories.php
===================================================================
--- /trunk/src/wp-includes/widgets/class-wp-widget-categories.php	(revision 56686)
+++ /trunk/src/wp-includes/widgets/class-wp-widget-categories.php	(revision 56687)
@@ -93,9 +93,8 @@
 			echo '</form>';
 
-			$type_attr = current_theme_supports( 'html5', 'script' ) ? '' : ' type="text/javascript"';
+			ob_start();
 			?>
 
-<script<?php echo $type_attr; ?>>
-/* <![CDATA[ */
+<script>
 (function() {
 	var dropdown = document.getElementById( "<?php echo esc_js( $dropdown_id ); ?>" );
@@ -107,8 +106,8 @@
 	dropdown.onchange = onCatChange;
 })();
-/* ]]> */
 </script>
 
 			<?php
+			wp_print_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 		} else {
 			$format = current_theme_supports( 'html5', 'navigation-widgets' ) ? 'html5' : 'xhtml';
Index: /trunk/src/wp-login.php
===================================================================
--- /trunk/src/wp-login.php	(revision 56686)
+++ /trunk/src/wp-login.php	(revision 56687)
@@ -102,7 +102,9 @@
 	 */
 	if ( 'loggedout' === $wp_error->get_error_code() ) {
+		ob_start();
 		?>
 		<script>if("sessionStorage" in window){try{for(var key in sessionStorage){if(key.indexOf("wp-autosave-")!=-1){sessionStorage.removeItem(key)}}}catch(e){}};</script>
 		<?php
+		wp_print_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 	}
 
@@ -194,7 +196,8 @@
 	</head>
 	<body class="login no-js <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
-	<script type="text/javascript">
-		document.body.className = document.body.className.replace('no-js','js');
-	</script>
+	<?php
+	wp_print_inline_script_tag( "document.body.className = document.body.className.replace('no-js','js');" );
+	?>
+
 	<?php
 	/**
@@ -415,10 +418,12 @@
 
 	if ( ! empty( $input_id ) ) {
+		ob_start();
 		?>
-		<script type="text/javascript">
+		<script>
 		try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e){}
 		if(typeof wpOnload==='function')wpOnload();
 		</script>
 		<?php
+		wp_print_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 	}
 
@@ -442,9 +447,5 @@
  */
 function wp_shake_js() {
-	?>
-	<script type="text/javascript">
-	document.querySelector('form').classList.add('shake');
-	</script>
-	<?php
+	wp_print_inline_script_tag( "document.querySelector('form').classList.add('shake');" );
 }
 
@@ -1358,7 +1359,9 @@
 
 				if ( $customize_login ) {
+					ob_start();
 					?>
-					<script type="text/javascript">setTimeout( function(){ new wp.customize.Messenger({ url: '<?php echo wp_customize_url(); ?>', channel: 'login' }).send('login') }, 1000 );</script>
+					<script>setTimeout( function(){ new wp.customize.Messenger({ url: '<?php echo wp_customize_url(); ?>', channel: 'login' }).send('login') }, 1000 );</script>
 					<?php
+					wp_print_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 				}
 
@@ -1606,13 +1609,10 @@
 		$login_script .= "if ( typeof wpOnload === 'function' ) { wpOnload() }";
 
-		?>
-		<script type="text/javascript">
-			<?php echo $login_script; ?>
-		</script>
-		<?php
+		wp_print_inline_script_tag( $login_script );
 
 		if ( $interim_login ) {
+			ob_start();
 			?>
-			<script type="text/javascript">
+			<script>
 			( function() {
 				try {
@@ -1628,4 +1628,5 @@
 			</script>
 			<?php
+			wp_print_inline_script_tag( str_replace( array( '<script>', '</script>' ), '', ob_get_clean() ) );
 		}
 
Index: /trunk/tests/phpunit/tests/customize/manager.php
===================================================================
--- /trunk/tests/phpunit/tests/customize/manager.php	(revision 56686)
+++ /trunk/tests/phpunit/tests/customize/manager.php	(revision 56687)
@@ -3137,5 +3137,5 @@
 		$manager->remove_frameless_preview_messenger_channel();
 		$output = ob_get_clean();
-		$this->assertStringContainsString( '<script>', $output );
+		$this->assertStringContainsString( '<script', $output );
 	}
 
Index: /trunk/tests/phpunit/tests/dependencies/scripts.php
===================================================================
--- /trunk/tests/phpunit/tests/dependencies/scripts.php	(revision 56686)
+++ /trunk/tests/phpunit/tests/dependencies/scripts.php	(revision 56687)
@@ -43,4 +43,5 @@
 		$this->wp_scripts_print_translations_output  = <<<JS
 <script type='text/javascript' id='__HANDLE__-js-translations'>
+/* <![CDATA[ */
 ( function( domain, translations ) {
 	var localeData = translations.locale_data[ domain ] || translations.locale_data.messages;
@@ -48,4 +49,5 @@
 	wp.i18n.setLocaleData( localeData, domain );
 } )( "__DOMAIN__", __JSON_TRANSLATIONS__ );
+/* ]]> */
 </script>
 JS;
@@ -78,5 +80,5 @@
 		$expected .= "<script type='text/javascript' src='http://example.com' id='empty-deps-null-version-js'></script>\n";
 
-		$this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 
 		// No scripts left to print.
@@ -119,10 +121,10 @@
 		$expected  = "<script type='text/javascript' src='http://example.org/ms-isa-1.js' id='ms-isa-1-js' data-wp-strategy='{$strategy}'></script>\n";
 		$expected .= wp_get_inline_script_tag(
-			"console.log(\"after one\");\n",
+			'console.log("after one");',
 			array(
 				'id' => 'ms-isa-1-js-after',
 			)
 		);
-		$this->assertSame( $expected, $output, 'Inline scripts in the "after" position, that are attached to a deferred main script, are failing to print/execute.' );
+		$this->assertEqualMarkup( $expected, $output, 'Inline scripts in the "after" position, that are attached to a deferred main script, are failing to print/execute.' );
 	}
 
@@ -147,5 +149,5 @@
 		$expected  = "<script type='text/javascript' src='http://example.org/ms-insa-3.js' id='ms-insa-3-js'></script>\n";
 		$expected .= wp_get_inline_script_tag(
-			"console.log(\"after one\");\n",
+			'console.log("after one");',
 			array(
 				'id' => 'ms-insa-3-js-after',
@@ -153,5 +155,5 @@
 		);
 
-		$this->assertSame( $expected, $output, 'Inline scripts in the "after" position, that are attached to a blocking main script, are failing to print/execute.' );
+		$this->assertEqualMarkup( $expected, $output, 'Inline scripts in the "after" position, that are attached to a blocking main script, are failing to print/execute.' );
 	}
 
@@ -181,5 +183,5 @@
 
 		$expected  = wp_get_inline_script_tag(
-			"console.log(\"before first\");\n",
+			'console.log("before first");',
 			array(
 				'id' => 'ds-i1-1-js-before',
@@ -190,5 +192,5 @@
 		$expected .= "<script type='text/javascript' src='http://example.org/ds-i1-3.js' id='ds-i1-3-js' $strategy data-wp-strategy='{$strategy}'></script>\n";
 		$expected .= wp_get_inline_script_tag(
-			"console.log(\"before last\");\n",
+			'console.log("before last");',
 			array(
 				'id'   => 'ms-i1-1-js-before',
@@ -198,5 +200,5 @@
 		$expected .= "<script type='text/javascript' src='http://example.org/ms-i1-1.js' id='ms-i1-1-js' {$strategy} data-wp-strategy='{$strategy}'></script>\n";
 
-		$this->assertSame( $expected, $output, 'Inline scripts in the "before" position, that are attached to a deferred main script, are failing to print/execute.' );
+		$this->assertEqualMarkup( $expected, $output, 'Inline scripts in the "before" position, that are attached to a deferred main script, are failing to print/execute.' );
 	}
 
@@ -216,5 +218,5 @@
 		$output   = get_echo( 'wp_print_scripts' );
 		$expected = "<script type='text/javascript' src='/main-script-a1.js' id='main-script-a1-js' async data-wp-strategy='async'></script>\n";
-		$this->assertSame( $expected, $output, 'Scripts enqueued with an async loading strategy are failing to have the async attribute applied to the script handle when being printed.' );
+		$this->assertEqualMarkup( $expected, $output, 'Scripts enqueued with an async loading strategy are failing to have the async attribute applied to the script handle when being printed.' );
 	}
 
@@ -236,7 +238,8 @@
 		wp_enqueue_script( 'dependency-script-a2', '/dependency-script-a2.js', array(), null );
 		wp_enqueue_script( 'main-script-a2', '/main-script-a2.js', array( 'dependency-script-a2' ), null, compact( 'strategy' ) );
-		$output   = get_echo( 'wp_print_scripts' );
-		$expected = "<script type='text/javascript' src='/main-script-a2.js' id='main-script-a2-js' {$strategy} data-wp-strategy='{$strategy}'></script>";
-		$this->assertStringContainsString( $expected, $output, 'Dependents of a blocking dependency are free to have any strategy.' );
+		$output    = get_echo( 'wp_print_scripts' );
+		$expected  = "<script id='dependency-script-a2-js' src='/dependency-script-a2.js'></script>\n";
+		$expected .= "<script type='text/javascript' src='/main-script-a2.js' id='main-script-a2-js' {$strategy} data-wp-strategy='{$strategy}'></script>";
+		$this->assertEqualMarkup( $expected, $output, 'Dependents of a blocking dependency are free to have any strategy.' );
 	}
 
@@ -258,5 +261,5 @@
 		wp_enqueue_script( 'dependent-script-a3', '/dependent-script-a3.js', array( 'main-script-a3' ), null );
 		$output   = get_echo( 'wp_print_scripts' );
-		$expected = "<script type='text/javascript' src='/main-script-a3.js' id='main-script-a3-js' data-wp-strategy='{$strategy}'></script>";
+		$expected = str_replace( "'", '"', "<script type='text/javascript' src='/main-script-a3.js' id='main-script-a3-js' data-wp-strategy='{$strategy}'></script>" );
 		$this->assertStringContainsString( $expected, $output, 'Blocking dependents must force delayed dependencies to become blocking.' );
 	}
@@ -276,9 +279,10 @@
 	 */
 	public function test_delayed_dependent_with_blocking_dependency_not_enqueued( $strategy ) {
+		$this->add_html5_script_theme_support();
 		wp_enqueue_script( 'main-script-a4', '/main-script-a4.js', array(), null, compact( 'strategy' ) );
 		// This dependent is registered but not enqueued, so it should not factor into the eligible loading strategy.
 		wp_register_script( 'dependent-script-a4', '/dependent-script-a4.js', array( 'main-script-a4' ), null );
 		$output   = get_echo( 'wp_print_scripts' );
-		$expected = "<script type='text/javascript' src='/main-script-a4.js' id='main-script-a4-js' {$strategy} data-wp-strategy='{$strategy}'></script>";
+		$expected = str_replace( "'", '"', "<script src='/main-script-a4.js' id='main-script-a4-js' {$strategy} data-wp-strategy='{$strategy}'></script>" );
 		$this->assertStringContainsString( $expected, $output, 'Only enqueued dependents should affect the eligible strategy.' );
 	}
@@ -965,7 +969,8 @@
 	 */
 	public function test_loading_strategy_with_defer_having_no_dependents_nor_dependencies() {
+		$this->add_html5_script_theme_support();
 		wp_enqueue_script( 'main-script-d1', 'http://example.com/main-script-d1.js', array(), null, array( 'strategy' => 'defer' ) );
 		$output   = get_echo( 'wp_print_scripts' );
-		$expected = "<script type='text/javascript' src='http://example.com/main-script-d1.js' id='main-script-d1-js' defer data-wp-strategy='defer'></script>\n";
+		$expected = str_replace( "'", '"', "<script src='http://example.com/main-script-d1.js' id='main-script-d1-js' defer data-wp-strategy='defer'></script>\n" );
 		$this->assertStringContainsString( $expected, $output, 'Expected defer, as there is no dependent or dependency' );
 	}
@@ -981,4 +986,5 @@
 	 */
 	public function test_loading_strategy_with_defer_dependent_and_varied_dependencies() {
+		$this->add_html5_script_theme_support();
 		wp_enqueue_script( 'dependency-script-d2-1', 'http://example.com/dependency-script-d2-1.js', array(), null, array( 'strategy' => 'defer' ) );
 		wp_enqueue_script( 'dependency-script-d2-2', 'http://example.com/dependency-script-d2-2.js', array(), null );
@@ -986,5 +992,5 @@
 		wp_enqueue_script( 'main-script-d2', 'http://example.com/main-script-d2.js', array( 'dependency-script-d2-1', 'dependency-script-d2-3' ), null, array( 'strategy' => 'defer' ) );
 		$output   = get_echo( 'wp_print_scripts' );
-		$expected = "<script type='text/javascript' src='http://example.com/main-script-d2.js' id='main-script-d2-js' defer data-wp-strategy='defer'></script>\n";
+		$expected = '<script src="http://example.com/main-script-d2.js" id="main-script-d2-js" defer data-wp-strategy="defer"></script>';
 		$this->assertStringContainsString( $expected, $output, 'Expected defer, as all dependencies are either deferred or blocking' );
 	}
@@ -1000,4 +1006,5 @@
 	 */
 	public function test_loading_strategy_with_all_defer_dependencies() {
+		$this->add_html5_script_theme_support();
 		wp_enqueue_script( 'main-script-d3', 'http://example.com/main-script-d3.js', array(), null, array( 'strategy' => 'defer' ) );
 		wp_enqueue_script( 'dependent-script-d3-1', 'http://example.com/dependent-script-d3-1.js', array( 'main-script-d3' ), null, array( 'strategy' => 'defer' ) );
@@ -1005,5 +1012,5 @@
 		wp_enqueue_script( 'dependent-script-d3-3', 'http://example.com/dependent-script-d3-3.js', array( 'dependent-script-d3-2' ), null, array( 'strategy' => 'defer' ) );
 		$output   = get_echo( 'wp_print_scripts' );
-		$expected = "<script type='text/javascript' src='http://example.com/main-script-d3.js' id='main-script-d3-js' defer data-wp-strategy='defer'></script>\n";
+		$expected = '<script src="http://example.com/main-script-d3.js" id="main-script-d3-js" defer data-wp-strategy="defer"></script>';
 		$this->assertStringContainsString( $expected, $output, 'Expected defer, as all dependents have defer loading strategy' );
 	}
@@ -1030,5 +1037,5 @@
 		$expected .= "<script type='text/javascript' src='/dependent-script-d4-3.js' id='dependent-script-d4-3-js' defer data-wp-strategy='defer'></script>\n";
 
-		$this->assertSame( $expected, $output, 'Scripts registered as defer but that have dependents that are async are expected to have said dependents deferred.' );
+		$this->assertEqualMarkup( $expected, $output, 'Scripts registered as defer but that have dependents that are async are expected to have said dependents deferred.' );
 	}
 
@@ -1050,5 +1057,5 @@
 		wp_enqueue_script( 'dependent-script-d4-3', '/dependent-script-d4-3.js', array( 'dependent-script-d4-2' ), null, array( 'strategy' => 'defer' ) );
 		$output   = get_echo( 'wp_print_scripts' );
-		$expected = "<script type='text/javascript' src='/main-script-d4.js' id='main-script-d4-js' data-wp-strategy='defer'></script>\n";
+		$expected = str_replace( "'", '"', "<script type='text/javascript' src='/main-script-d4.js' id='main-script-d4-js' data-wp-strategy='defer'></script>\n" );
 		$this->assertStringContainsString( $expected, $output, 'Scripts registered as defer but that have all dependents with no strategy, should become blocking (no strategy).' );
 	}
@@ -1068,4 +1075,5 @@
 		$output   = get_echo( 'wp_print_scripts' );
 		$expected = "<script type='text/javascript' src='/main-script-b1.js' id='main-script-b1-js'></script>\n";
+		$expected = str_replace( "'", '"', $expected );
 		$this->assertSame( $expected, $output, 'Scripts registered with a "blocking" strategy, and who have no dependencies, should have no loading strategy attributes printed.' );
 
@@ -1074,4 +1082,5 @@
 		$output   = get_echo( 'wp_print_scripts' );
 		$expected = "<script type='text/javascript' src='/main-script-b2.js' id='main-script-b2-js'></script>\n";
+		$expected = str_replace( "'", '"', $expected );
 		$this->assertSame( $expected, $output, 'Scripts registered with no strategy assigned, and who have no dependencies, should have no loading strategy attributes printed.' );
 	}
@@ -1100,5 +1109,5 @@
 		$expected_header .= "<script type='text/javascript' src='/enqueue-header-new.js' id='enqueue-header-new-js'></script>\n";
 
-		$this->assertSame( $expected_header, $actual_header, 'Scripts registered/enqueued using the older $in_footer parameter or the newer $args parameter should have the same outcome.' );
+		$this->assertEqualMarkup( $expected_header, $actual_header, 'Scripts registered/enqueued using the older $in_footer parameter or the newer $args parameter should have the same outcome.' );
 		$this->assertEmpty( $actual_footer, 'Expected footer to be empty since all scripts were for head.' );
 	}
@@ -1128,5 +1137,5 @@
 
 		$this->assertEmpty( $actual_header, 'Expected header to be empty since all scripts targeted footer.' );
-		$this->assertSame( $expected_footer, $actual_footer, 'Scripts registered/enqueued using the older $in_footer parameter or the newer $args parameter should have the same outcome.' );
+		$this->assertEqualMarkup( $expected_footer, $actual_footer, 'Scripts registered/enqueued using the older $in_footer parameter or the newer $args parameter should have the same outcome.' );
 	}
 
@@ -1247,5 +1256,5 @@
 		wp_enqueue_script( 'invalid-strategy' );
 
-		$this->assertSame(
+		$this->assertEqualMarkup(
 			"<script type='text/javascript' src='/defaults.js' id='invalid-strategy-js'></script>\n",
 			get_echo( 'wp_print_scripts' )
@@ -1272,5 +1281,5 @@
 		wp_enqueue_script( 'invalid-strategy' );
 
-		$this->assertSame(
+		$this->assertEqualMarkup(
 			"<script type='text/javascript' src='/defaults.js' id='invalid-strategy-js'></script>\n",
 			get_echo( 'wp_print_scripts' )
@@ -1293,5 +1302,5 @@
 		wp_enqueue_script( 'invalid-strategy', '/defaults.js', array(), null, array( 'strategy' => 'random-strategy' ) );
 
-		$this->assertSame(
+		$this->assertEqualMarkup(
 			"<script type='text/javascript' src='/defaults.js' id='invalid-strategy-js'></script>\n",
 			get_echo( 'wp_print_scripts' )
@@ -1331,5 +1340,5 @@
 		$expected .= "<script type='text/javascript' src='/main-script.js' id='main-defer-script-js' defer data-wp-strategy='defer'></script>\n";
 
-		$this->assertSame( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered with a "defer" loading strategy. Deferred scripts should not be part of the script concat loading query.' );
+		$this->assertEqualMarkup( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered with a "defer" loading strategy. Deferred scripts should not be part of the script concat loading query.' );
 	}
 
@@ -1366,5 +1375,5 @@
 		$expected .= "<script type='text/javascript' src='/main-script.js' id='main-async-script-1-js' async data-wp-strategy='async'></script>\n";
 
-		$this->assertSame( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered with an "async" loading strategy. Async scripts should not be part of the script concat loading query.' );
+		$this->assertEqualMarkup( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered with an "async" loading strategy. Async scripts should not be part of the script concat loading query.' );
 	}
 
@@ -1405,5 +1414,5 @@
 		$expected .= "<script type='text/javascript' src='/main-script.js' id='deferred-script-2-js' defer data-wp-strategy='defer'></script>\n";
 
-		$this->assertSame( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered as deferred after other blocking scripts are registered. Deferred scripts should not be part of the script concat loader query string. ' );
+		$this->assertEqualMarkup( $expected, $print_scripts, 'Scripts are being incorrectly concatenated when a main script is registered as deferred after other blocking scripts are registered. Deferred scripts should not be part of the script concat loader query string. ' );
 	}
 
@@ -1413,5 +1422,4 @@
 	public function test_wp_enqueue_script_with_html5_support_does_not_contain_type_attribute() {
 		global $wp_version;
-		add_theme_support( 'html5', array( 'script' ) );
 
 		$GLOBALS['wp_scripts']                  = new WP_Scripts();
@@ -1422,5 +1430,5 @@
 		$expected = "<script src='http://example.com?ver={$wp_version}' id='empty-deps-no-version-js'></script>\n";
 
-		$this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 	}
 
@@ -1461,5 +1469,5 @@
 
 		// Go!
-		$this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 
 		// No scripts left to print.
@@ -1504,5 +1512,5 @@
 
 		// Go!
-		$this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 
 		// No scripts left to print.
@@ -1522,5 +1530,5 @@
 
 		// Go!
-		$this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 
 		// No scripts left to print.
@@ -1540,7 +1548,8 @@
 		$expected  = "<!--[if lt IE 9]>\n<script type='text/javascript' id='test-conditional-with-data-js-extra'>\n/* <![CDATA[ */\ntesting\n/* ]]> */\n</script>\n<![endif]-->\n";
 		$expected .= "<!--[if lt IE 9]>\n<script type='text/javascript' src='http://example.com' id='test-conditional-with-data-js'></script>\n<![endif]-->\n";
+		$expected  = str_replace( "'", '"', $expected );
 
 		// Go!
-		$this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 
 		// No scripts left to print.
@@ -1560,8 +1569,8 @@
 
 		// Go!
-		$this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 
 		// No scripts left to print.
-		$this->assertSame( '', get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( '', get_echo( 'wp_print_scripts' ) );
 	}
 
@@ -1589,5 +1598,5 @@
 		wp_enqueue_script( 'handle-three' );
 
-		$this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 	}
 
@@ -1677,6 +1686,6 @@
 		$expected_footer  = "<script type='text/javascript' src='/parent.js' id='parent-js'></script>\n";
 
-		$this->assertSame( $expected_header, $header, 'Expected same header markup.' );
-		$this->assertSame( $expected_footer, $footer, 'Expected same footer markup.' );
+		$this->assertEqualMarkup( $expected_header, $header, 'Expected same header markup.' );
+		$this->assertEqualMarkup( $expected_footer, $footer, 'Expected same footer markup.' );
 	}
 
@@ -1698,6 +1707,6 @@
 		$expected_footer .= "<script type='text/javascript' src='/parent.js' id='parent-js'></script>\n";
 
-		$this->assertSame( $expected_header, $header, 'Expected same header markup.' );
-		$this->assertSame( $expected_footer, $footer, 'Expected same footer markup.' );
+		$this->assertEqualMarkup( $expected_header, $header, 'Expected same header markup.' );
+		$this->assertEqualMarkup( $expected_footer, $footer, 'Expected same footer markup.' );
 	}
 
@@ -1729,6 +1738,6 @@
 		$expected_footer .= "<script type='text/javascript' src='/parent-footer.js' id='parent-footer-js'></script>\n";
 
-		$this->assertSame( $expected_header, $header, 'Expected same header markup.' );
-		$this->assertSame( $expected_footer, $footer, 'Expected same footer markup.' );
+		$this->assertEqualMarkup( $expected_header, $header, 'Expected same header markup.' );
+		$this->assertEqualMarkup( $expected_footer, $footer, 'Expected same footer markup.' );
 	}
 
@@ -1953,4 +1962,5 @@
 		$expected_localized .= "<script type='text/javascript' id='test-example-js-extra'>\n/* <![CDATA[ */\nvar testExample = {\"foo\":\"bar\"};\n/* ]]> */\n</script>\n";
 		$expected_localized .= "<![endif]-->\n";
+		$expected_localized  = str_replace( "'", '"', $expected_localized );
 
 		$expected  = "<!--[if gte IE 9]>\n";
@@ -1959,4 +1969,5 @@
 		$expected .= "<script type='text/javascript' id='test-example-js-after'>\nconsole.log(\"after\");\n</script>\n";
 		$expected .= "<![endif]-->\n";
+		$expected  = str_replace( "'", '"', $expected );
 
 		wp_enqueue_script( 'test-example', 'example.com', array(), null );
@@ -2125,5 +2136,6 @@
 		$print_scripts = $this->getActualOutput();
 
-		$tail = substr( $print_scripts, strrpos( $print_scripts, "<script type='text/javascript' src='/customize-dependency.js' id='customize-dependency-js'>" ) );
+		$tail = substr( $print_scripts, strrpos( $print_scripts, '<script type="text/javascript" src="/customize-dependency.js" id="customize-dependency-js">' ) );
+
 		$this->assertEqualMarkup( $expected_tail, $tail );
 	}
@@ -2305,5 +2317,5 @@
 		$expected .= "<script type='text/javascript' src='/wp-includes/js/script.js' id='test-example-js'></script>\n";
 
-		$this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 	}
 
@@ -2332,5 +2344,5 @@
 		$expected .= "<script type='text/javascript' src='/wp-content/plugins/my-plugin/js/script.js' id='plugin-example-js'></script>\n";
 
-		$this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 	}
 
@@ -2359,5 +2371,5 @@
 		$expected .= "<script type='text/javascript' src='/wp-content/themes/my-theme/js/script.js' id='theme-example-js'></script>\n";
 
-		$this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 	}
 
@@ -2386,5 +2398,5 @@
 		$expected .= "<script type='text/javascript' src='/wp-admin/js/script.js' id='script-handle-js'></script>\n";
 
-		$this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 	}
 
@@ -2416,5 +2428,5 @@
 		$expected .= "<script type='text/javascript' src='/wp-admin/js/script.js' id='test-example-js'></script>\n";
 
-		$this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 	}
 
@@ -2445,5 +2457,5 @@
 		$expected .= "<script type='text/javascript' src='/wp-includes/js/script.js' id='test-example-js'></script>\n";
 
-		$this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 	}
 
@@ -2475,5 +2487,5 @@
 		$expected .= "<script type='text/javascript' src='/wp-includes/js/script2.js' id='test-example-js'></script>\n";
 
-		$this->assertSameIgnoreEOL( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 	}
 
@@ -2864,5 +2876,5 @@
 		$expected .= "<script type='text/javascript' src='http://example.com' id='test-example-js'></script>\n";
 
-		$this->assertSame( $expected, get_echo( 'wp_print_scripts' ) );
+		$this->assertEqualMarkup( $expected, get_echo( 'wp_print_scripts' ) );
 	}
 
@@ -2929,5 +2941,5 @@
 		$expected .= "<script type='text/javascript' src='/default/common.js' id='common-js'></script>\n";
 
-		$this->assertSame( $expected, $print_scripts );
+		$this->assertEqualMarkup( $expected, $print_scripts );
 	}
 
@@ -2968,5 +2980,5 @@
 	 *
 	 * @param string $markup Markup.
-	 * @return DOMElement Body element wrapping supplied markup fragment.
+	 * @return DOMDocument Document containing the normalized markup fragment.
 	 */
 	protected function parse_markup_fragment( $markup ) {
@@ -2986,9 +2998,9 @@
 		}
 
-		return $body;
-	}
-
-	/**
-	 * Assert markup is equal.
+		return $dom;
+	}
+
+	/**
+	 * Assert markup is equal after normalizing script tags.
 	 *
 	 * @param string $expected Expected markup.
@@ -2997,9 +3009,48 @@
 	 */
 	protected function assertEqualMarkup( $expected, $actual, $message = '' ) {
+		$expected_dom = $this->parse_markup_fragment( $expected );
+		$actual_dom   = $this->parse_markup_fragment( $actual );
+		foreach ( array( $expected_dom, $actual_dom ) as $dom ) {
+			$xpath = new DOMXPath( $dom );
+			/** @var DOMElement $script */
+
+			// Normalize type attribute. When missing, it defaults to text/javascript.
+			foreach ( $xpath->query( '//script[ not( @type ) ]' ) as $script ) {
+				$script->setAttribute( 'type', 'text/javascript' );
+			}
+
+			// Normalize script contents to remove CDATA wrapper.
+			foreach ( $xpath->query( '//script[ contains( text(), "<![CDATA[" ) ]' ) as $script ) {
+				$script->textContent = str_replace(
+					array(
+						"/* <![CDATA[ */\n",
+						"\n/* ]]> */",
+					),
+					'',
+					$script->textContent
+				);
+			}
+
+			// Normalize XHTML-compatible boolean attributes to HTML5 ones.
+			foreach ( array( 'async', 'defer' ) as $attribute ) {
+				foreach ( iterator_to_array( $xpath->query( "//script[ @{$attribute} = '{$attribute}' ]" ) ) as $script ) {
+					$script->removeAttribute( $attribute );
+					$script->setAttributeNode( $dom->createAttribute( $attribute ) );
+				}
+			}
+		}
+
 		$this->assertEquals(
-			$this->parse_markup_fragment( $expected ),
-			$this->parse_markup_fragment( $actual ),
+			$expected_dom->getElementsByTagName( 'body' )->item( 0 ),
+			$actual_dom->getElementsByTagName( 'body' )->item( 0 ),
 			$message
 		);
 	}
+
+	/**
+	 * Adds html5 script theme support.
+	 */
+	protected function add_html5_script_theme_support() {
+		add_theme_support( 'html5', array( 'script' ) );
+	}
 }
Index: /trunk/tests/phpunit/tests/dependencies/wpInlineScriptTag.php
===================================================================
--- /trunk/tests/phpunit/tests/dependencies/wpInlineScriptTag.php	(revision 56686)
+++ /trunk/tests/phpunit/tests/dependencies/wpInlineScriptTag.php	(revision 56687)
@@ -120,3 +120,17 @@
 		);
 	}
+
+	/**
+	 * Tests that CDATA wrapper duplication is handled.
+	 *
+	 * @ticket 58664
+	 */
+	public function test_get_inline_script_tag_with_duplicated_cdata_wrappers() {
+		remove_theme_support( 'html5' );
+
+		$this->assertSame(
+			"<script type=\"text/javascript\">\n/* <![CDATA[ */\n/* <![CDATA[ */ console.log( 'Hello World!' ); /* ]]]]><![CDATA[> */\n/* ]]> */\n</script>\n",
+			wp_get_inline_script_tag( "/* <![CDATA[ */ console.log( 'Hello World!' ); /* ]]> */" )
+		);
+	}
 }
