Commit 3938d15885 for wordpress.org

commit 3938d158859c4a9efe119b182e0a6e3843b76498
Author: ramonopoly <ramonopoly@git.wordpress.org>
Date:   Sun Oct 18 22:53:49 2026 +0000

    Editor: Remove theme.json preset items of unexpected types to prevent fatals in PHP

    This commit prevents `WP_Theme_JSON` from throwing fatal TypeErrors when preset items in theme.json or global styles data contain values of the wrong type. Those values could be user- or AI-generated.

    It does this by removing theme.json preset items that aren't objects, or whose `slug` isn't a scalar, in `WP_Theme_JSON::sanitize()`.

    Previouly, for example, a preset list of strings, such as `"fontFamilies": [ "Inter" ]`, failed with `Cannot access offset of type string on string` when the stylesheet is generated.

    Developed in: https://github.com/WordPress/wordpress-develop/pull/14262

    Props ramonopoly, aaronrobertshaw, isabel_brison.

    Fixes #66304.


    Built from https://develop.svn.wordpress.org/trunk@64491


    git-svn-id: http://core.svn.wordpress.org/trunk@63641 1a063a9b-81f0-0310-95a4-ce76da25c4cd

diff --git a/wp-includes/class-wp-theme-json.php b/wp-includes/class-wp-theme-json.php
index f5cdc1b43c..116a8ad951 100644
--- a/wp-includes/class-wp-theme-json.php
+++ b/wp-includes/class-wp-theme-json.php
@@ -1536,6 +1536,32 @@ class WP_Theme_JSON {
 				$result['viewport'] = self::sanitize_viewport_settings( $input[ $subtree ]['viewport'] );
 			}

+			if ( 'settings' === $subtree ) {
+				// Preset leaves are untyped in VALID_SETTINGS, but consumers read `$preset['slug']` as a string.
+				$is_valid_preset = static function ( $preset ) {
+					return is_array( $preset ) && ( ! isset( $preset['slug'] ) || is_scalar( $preset['slug'] ) );
+				};
+				foreach ( static::get_setting_nodes( array( 'settings' => $result ) ) as $node ) {
+					foreach ( static::PRESETS_METADATA as $preset_metadata ) {
+						$path    = array_merge( array_slice( $node['path'], 1 ), $preset_metadata['path'] );
+						$presets = _wp_array_get( $result, $path, null );
+						if ( ! is_array( $presets ) ) {
+							continue;
+						}
+						if ( isset( $presets[0] ) ) {
+							$presets = array_values( array_filter( $presets, $is_valid_preset ) );
+						} else {
+							foreach ( static::VALID_ORIGINS as $origin ) {
+								if ( isset( $presets[ $origin ] ) && is_array( $presets[ $origin ] ) ) {
+									$presets[ $origin ] = array_values( array_filter( $presets[ $origin ], $is_valid_preset ) );
+								}
+							}
+						}
+						_wp_array_set( $result, $path, $presets );
+					}
+				}
+			}
+
 			if ( empty( $result ) ) {
 				unset( $output[ $subtree ] );
 			} else {
diff --git a/wp-includes/version.php b/wp-includes/version.php
index b9e895e42b..99c1adcdfb 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '7.2-alpha-64490';
+$wp_version = '7.2-alpha-64491';

 /**
  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.