diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php
index 366f8f93667e7..cd8caac1d045c 100644
--- a/src/wp-includes/script-loader.php
+++ b/src/wp-includes/script-loader.php
@@ -2880,7 +2880,31 @@ function wp_get_script_tag( $attributes ) {
*/
$attributes = apply_filters( 'wp_script_attributes', $attributes );
- return sprintf( "\n", wp_sanitize_script_attributes( $attributes ) );
+ $processor = new WP_HTML_Tag_Processor( '' );
+ $processor->next_tag();
+ foreach ( $attributes as $name => $value ) {
+ /*
+ * Lexical variations of an attribute name may represent the
+ * same attribute in HTML, therefore it’s possible that the
+ * input array might contain duplicate attributes even though
+ * it’s keyed on their name. Calling code should rewrite an
+ * attribute’s value rather than sending a duplicate attribute.
+ *
+ * Example:
+ *
+ * array( 'id' => 'main', 'ID' => 'nav' )
+ *
+ * In this example, there are two keys both describing the `id`
+ * attribute. PHP array iteration is in key-insertion order so
+ * the 'id' value will be set in the SCRIPT tag.
+ */
+ if ( null !== $processor->get_attribute( $name ) ) {
+ continue;
+ }
+
+ $processor->set_attribute( $name, $value ?? true );
+ }
+ return "{$processor->get_updated_html()}\n";
}
/**
@@ -2901,13 +2925,27 @@ function wp_print_script_tag( $attributes ) {
* Constructs an inline script tag.
*
* It is possible to inject attributes in the `" );' );
+ *
+ * // This data is unsafe and `text/plain` cannot be escaped.
+ * // The following will return `""` to indicate failure:
+ * wp_get_inline_script_tag( '', array( 'type' => 'text/plain' ) );
*
* @since 5.7.0
+ * @since 7.0.0 Returns an empty string if the data cannot be safely embedded in a script tag.
*
* @param string $data Data for script tag: JavaScript, importmap, speculationrules, etc.
* @param array $attributes Optional. Key-value pairs representing `\n", wp_sanitize_script_attributes( $attributes ), $data );
+ $processor = new WP_HTML_Tag_Processor( '' );
+ $processor->next_tag();
+ foreach ( $attributes as $name => $value ) {
+ /*
+ * Lexical variations of an attribute name may represent the
+ * same attribute in HTML, therefore it’s possible that the
+ * input array might contain duplicate attributes even though
+ * it’s keyed on their name. Calling code should rewrite an
+ * attribute’s value rather than sending a duplicate attribute.
+ *
+ * Example:
+ *
+ * array( 'id' => 'main', 'ID' => 'nav' )
+ *
+ * In this example, there are two keys both describing the `id`
+ * attribute. PHP array iteration is in key-insertion order so
+ * the 'id' value will be set in the SCRIPT tag.
+ */
+ if ( null !== $processor->get_attribute( $name ) ) {
+ continue;
+ }
+
+ $processor->set_attribute( $name, $value ?? true );
+ }
+
+ if ( ! $processor->set_modifiable_text( $data ) ) {
+ _doing_it_wrong(
+ __FUNCTION__,
+ __( 'Unable to set inline script data.' ),
+ '7.0.0'
+ );
+ return '';
+ }
+
+ return "{$processor->get_updated_html()}\n";
}
/**
diff --git a/tests/phpunit/tests/dependencies/wpInlineScriptTag.php b/tests/phpunit/tests/dependencies/wpInlineScriptTag.php
index 9958a2468706b..e8fabd7226e84 100644
--- a/tests/phpunit/tests/dependencies/wpInlineScriptTag.php
+++ b/tests/phpunit/tests/dependencies/wpInlineScriptTag.php
@@ -164,4 +164,23 @@ public function test_script_tag_repeat_attributes() {
),
);
}
+
+ /**
+ * Test failure conditions setting inline script tag contents.
+ *
+ * @ticket 64500
+ */
+ public function test_script_tag_dangerous_unescapeable_contents() {
+ $this->setExpectedIncorrectUsage( 'wp_get_inline_script_tag' );
+ /*
+ * cannot be printed inside a script tag
+ * the `example/example` type is an unknown type with no known escaping rules.
+ * The only choice is to abort.
+ */
+ $result = wp_get_inline_script_tag(
+ '',
+ array( 'type' => 'example/example' )
+ );
+ $this->assertSame( '', $result );
+ }
}