diff --git a/src/wp-includes/class-wp.php b/src/wp-includes/class-wp.php
index ce88c102cf..9003cef029 100644
--- a/src/wp-includes/class-wp.php
+++ b/src/wp-includes/class-wp.php
@@ -547,6 +547,11 @@ class WP {
 			}
 		}
 
+		$x_robots_tag_value = wp_x_robots_tag_header_string();
+		if ( is_string( $x_robots_tag_value ) ) {
+			$headers['X-Robots-Tag'] = $x_robots_tag_value;
+		}
+
 		/**
 		 * Filters the HTTP headers before they're sent to the browser.
 		 *
diff --git a/src/wp-includes/robots-template.php b/src/wp-includes/robots-template.php
index e719e745d6..ec7c2e59dc 100644
--- a/src/wp-includes/robots-template.php
+++ b/src/wp-includes/robots-template.php
@@ -49,6 +49,39 @@ function wp_robots() {
 	echo "<meta name='robots' content='" . esc_attr( implode( ', ', $robots_strings ) ) . "' />\n";
 }
 
+/**
+ * Returns the necessary X-Robots-Tag value.
+ *
+ * Gathers robots directives to include for the current context, using the
+ * {@see 'wp_robots'} filter. The directives are then sanitized, and the
+ * X-Robots-Tag header is output if there is at least one relevant directive.
+ *
+ * @since x.x.x
+ *
+ * @return string|null The X-Robots-Tag header value, or null if no relevant directives.
+ */
+function wp_x_robots_tag_header_string() {
+	/** This filter is documented in wp-includes/robots-template.php */
+	$robots = apply_filters( 'wp_robots', array() );
+
+	$robots_strings = array();
+	foreach ( $robots as $directive => $value ) {
+		if ( is_string( $value ) ) {
+			// If a string value, include it as value for the directive.
+			$robots_strings[] = "{$directive}={$value}";
+		} elseif ( $value ) {
+			// Otherwise, include the directive if it is truthy.
+			$robots_strings[] = $directive;
+		}
+	}
+
+	if ( empty( $robots_strings ) ) {
+		return null;
+	}
+
+	return implode( ', ', $robots_strings );
+}
+
 /**
  * Adds `noindex` to the robots meta tag if required by the site configuration.
  *
