@@ -641,6 +641,34 @@ private static function append_to_selector( $selector, $to_append ) {
641641 return implode ( ', ' , $ new_selectors );
642642 }
643643
644+ /**
645+ * Function that given an array of presets keyed by origin
646+ * and the value key of the preset returns an array where each key is
647+ * the a preset slug and each value is the preset value.
648+ *
649+ * @param array $preset_per_origin Array of presets keyed by origin.
650+ * @param string $value_key The property of the preset that contains its value.
651+ *
652+ * @return array Array of presets where each key is a slug and each value is the preset value.
653+ */
654+ private static function get_merged_preset_by_slug ( $ preset_per_origin , $ value_key ) {
655+ $ origins = array ( 'core ' , 'theme ' , 'user ' );
656+ $ result = array ();
657+ foreach ( $ origins as $ origin ) {
658+ if ( ! isset ( $ preset_per_origin [ $ origin ] ) ) {
659+ continue ;
660+ }
661+ foreach ( $ preset_per_origin [ $ origin ] as $ preset ) {
662+ // We don't want to use kebabCase here,
663+ // see https://github.com/WordPress/gutenberg/issues/32347
664+ // However, we need to make sure the generated class or css variable
665+ // doesn't contain spaces.
666+ $ result [ preg_replace ( '/\s+/ ' , '- ' , $ preset ['slug ' ] ) ] = $ preset [ $ value_key ];
667+ }
668+ }
669+ return $ result ;
670+ }
671+
644672 /**
645673 * Given a settings array, it returns the generated rulesets
646674 * for the preset classes.
@@ -659,19 +687,16 @@ private static function compute_preset_classes( $settings, $selector ) {
659687
660688 $ stylesheet = '' ;
661689 foreach ( self ::PRESETS_METADATA as $ preset ) {
662- $ values = _wp_array_get ( $ settings , $ preset ['path ' ], array () );
663- foreach ( $ values as $ value ) {
664- foreach ( $ preset ['classes ' ] as $ class ) {
690+ $ preset_per_origin = _wp_array_get ( $ settings , $ preset ['path ' ], array () );
691+ $ preset_by_slug = self ::get_merged_preset_by_slug ( $ preset_per_origin , $ preset ['value_key ' ] );
692+ foreach ( $ preset ['classes ' ] as $ class ) {
693+ foreach ( $ preset_by_slug as $ slug => $ value ) {
665694 $ stylesheet .= self ::to_ruleset (
666- // We don't want to use kebabCase here,
667- // see https://github.com/WordPress/gutenberg/issues/32347
668- // However, we need to make sure the generated class
669- // doesn't contain spaces.
670- self ::append_to_selector ( $ selector , '.has- ' . preg_replace ( '/\s+/ ' , '- ' , $ value ['slug ' ] ) . '- ' . $ class ['class_suffix ' ] ),
695+ self ::append_to_selector ( $ selector , '.has- ' . $ slug . '- ' . $ class ['class_suffix ' ] ),
671696 array (
672697 array (
673698 'name ' => $ class ['property_name ' ],
674- 'value ' => $ value[ $ preset [ ' value_key ' ] ] . ' !important ' ,
699+ 'value ' => $ value . ' !important ' ,
675700 ),
676701 )
677702 );
@@ -701,11 +726,12 @@ private static function compute_preset_classes( $settings, $selector ) {
701726 private static function compute_preset_vars ( $ settings ) {
702727 $ declarations = array ();
703728 foreach ( self ::PRESETS_METADATA as $ preset ) {
704- $ values = _wp_array_get ( $ settings , $ preset ['path ' ], array () );
705- foreach ( $ values as $ value ) {
729+ $ preset_per_origin = _wp_array_get ( $ settings , $ preset ['path ' ], array () );
730+ $ preset_by_slug = self ::get_merged_preset_by_slug ( $ preset_per_origin , $ preset ['value_key ' ] );
731+ foreach ( $ preset_by_slug as $ slug => $ value ) {
706732 $ declarations [] = array (
707- 'name ' => '--wp--preset-- ' . $ preset ['css_var_infix ' ] . '-- ' . $ value [ ' slug ' ] ,
708- 'value ' => $ value[ $ preset [ ' value_key ' ] ] ,
733+ 'name ' => '--wp--preset-- ' . $ preset ['css_var_infix ' ] . '-- ' . $ slug ,
734+ 'value ' => $ value ,
709735 );
710736 }
711737 }
@@ -1101,85 +1127,59 @@ public function get_stylesheet( $type = 'all' ) {
11011127 /**
11021128 * Merge new incoming data.
11031129 *
1104- * @param WP_Theme_JSON_Gutenberg $incoming Data to merge.
1105- * @param string $update_or_remove Whether update or remove existing colors
1106- * for which the incoming data has a duplicated slug.
1130+ * @param WP_Theme_JSON $incoming Data to merge.
1131+ * @param string $origin origin of the incoming data (e.g: core, theme, or user).
11071132 */
1108- public function merge ( $ incoming , $ update_or_remove = 'remove ' ) {
1109- $ incoming_data = $ incoming ->get_raw_data ();
1110- $ existing_data = $ this ->theme_json ;
1133+ public function merge ( $ incoming , $ origin ) {
1134+
1135+ $ incoming_data = $ incoming ->get_raw_data ();
1136+ $ this ->theme_json = array_replace_recursive ( $ this ->theme_json , $ incoming_data );
11111137
11121138 // The array_replace_recursive algorithm merges at the leaf level.
11131139 // For leaf values that are arrays it will use the numeric indexes for replacement.
1114- $ this ->theme_json = array_replace_recursive ( $ this ->theme_json , $ incoming_data );
1140+ // In those cases, what we want is to use the incoming value, if it exists.
1141+ //
1142+ // These are the cases that have array values at the leaf levels.
1143+ $ properties = array ();
1144+ $ properties [] = array ( 'custom ' );
1145+ $ properties [] = array ( 'spacing ' , 'units ' );
1146+ $ properties [] = array ( 'color ' , 'duotone ' );
11151147
1116- // There are a few cases in which we want to merge things differently
1117- // from what array_replace_recursive does.
1118-
1119- // Some incoming properties should replace the existing.
1120- $ to_replace = array ();
1121- $ to_replace [] = array ( 'custom ' );
1122- $ to_replace [] = array ( 'spacing ' , 'units ' );
1123- $ to_replace [] = array ( 'typography ' , 'fontSizes ' );
1124- $ to_replace [] = array ( 'typography ' , 'fontFamilies ' );
1125-
1126- // Some others should be appended to the existing.
1127- // If the slug is the same than an existing element,
1128- // the $update_or_remove param is used to decide
1129- // what to do with the existing element:
1130- // either remove it and append the incoming,
1131- // or update it with the incoming.
11321148 $ to_append = array ();
1133- $ to_append [] = array ( 'color ' , 'duotone ' );
1134- $ to_append [] = array ( 'color ' , 'gradients ' );
11351149 $ to_append [] = array ( 'color ' , 'palette ' );
1150+ $ to_append [] = array ( 'color ' , 'gradients ' );
1151+ $ to_append [] = array ( 'typography ' , 'fontSizes ' );
1152+ $ to_append [] = array ( 'typography ' , 'fontFamilies ' );
11361153
11371154 $ nodes = self ::get_setting_nodes ( $ this ->theme_json );
11381155 foreach ( $ nodes as $ metadata ) {
1139- foreach ( $ to_replace as $ path_to_replace ) {
1140- $ path = array_merge ( $ metadata ['path ' ], $ path_to_replace );
1156+ foreach ( $ properties as $ property_path ) {
1157+ $ path = array_merge ( $ metadata ['path ' ], $ property_path );
11411158 $ node = _wp_array_get ( $ incoming_data , $ path , array () );
11421159 if ( ! empty ( $ node ) ) {
11431160 gutenberg_experimental_set ( $ this ->theme_json , $ path , $ node );
11441161 }
11451162 }
1146- foreach ( $ to_append as $ path_to_append ) {
1147- $ path = array_merge ( $ metadata ['path ' ], $ path_to_append );
1148- $ incoming_node = _wp_array_get ( $ incoming_data , $ path , array () );
1149- $ existing_node = _wp_array_get ( $ existing_data , $ path , array () );
1150-
1151- if ( empty ( $ incoming_node ) && empty ( $ existing_node ) ) {
1152- continue ;
1153- }
11541163
1155- $ index_table = array ();
1156- $ existing_slugs = array ();
1157- $ merged = array ();
1158- foreach ( $ existing_node as $ key => $ value ) {
1159- $ index_table [ $ value ['slug ' ] ] = $ key ;
1160- $ existing_slugs [] = $ value ['slug ' ];
1161- $ merged [ $ key ] = $ value ;
1162- }
1163-
1164- $ to_remove = array ();
1165- foreach ( $ incoming_node as $ value ) {
1166- if ( ! in_array ( $ value ['slug ' ], $ existing_slugs , true ) ) {
1167- $ merged [] = $ value ;
1168- } elseif ( 'update ' === $ update_or_remove ) {
1169- $ merged [ $ index_table [ $ value ['slug ' ] ] ] = $ value ;
1164+ foreach ( $ to_append as $ property_path ) {
1165+ $ path = array_merge ( $ metadata ['path ' ], $ property_path );
1166+ $ node = _wp_array_get ( $ incoming_data , $ path , null );
1167+ if ( null !== $ node ) {
1168+ $ existing_node = _wp_array_get ( $ this ->theme_json , $ path , null );
1169+ $ new_node = array_filter (
1170+ $ existing_node ,
1171+ function ( $ key ) {
1172+ return in_array ( $ key , array ( 'core ' , 'theme ' , 'user ' ), true );
1173+ },
1174+ ARRAY_FILTER_USE_KEY
1175+ );
1176+ if ( isset ( $ node [ $ origin ] ) ) {
1177+ $ new_node [ $ origin ] = $ node [ $ origin ];
11701178 } else {
1171- $ merged [] = $ value ;
1172- $ to_remove [] = $ index_table [ $ value ['slug ' ] ];
1179+ $ new_node [ $ origin ] = $ node ;
11731180 }
1181+ gutenberg_experimental_set ( $ this ->theme_json , $ path , $ new_node );
11741182 }
1175-
1176- // Remove the duplicated values and pack the sparsed array.
1177- foreach ( $ to_remove as $ index ) {
1178- unset( $ merged [ $ index ] );
1179- }
1180- $ merged = array_values ( $ merged );
1181-
1182- gutenberg_experimental_set ( $ this ->theme_json , $ path , $ merged );
11831183 }
11841184 }
11851185
0 commit comments