errors()->add( $field, 'missing_field' ); } } if ( ! $result->is_valid() ) { return $result; } $widgets_result = $this->parse_widgets( $variant['widgets'] ?? [] ); if ( ! $widgets_result->is_valid() ) { $result->errors()->merge( $widgets_result->errors(), 'widgets' ); return $result; } return $result->wrap( [ 'id' => sanitize_key( $variant['id'] ), 'label' => sanitize_text_field( $variant['label'] ), 'widgets' => $widgets_result->unwrap(), ] ); } private function parse_widgets( array $widgets ): Parse_Result { $result = Parse_Result::make(); $sanitized = []; foreach ( $widgets as $element_id => $entry ) { if ( ! is_string( $element_id ) || '' === $element_id ) { $result->errors()->add( (string) $element_id, 'invalid_element_id' ); continue; } if ( ! is_array( $entry ) ) { $result->errors()->add( $element_id, 'invalid_entry' ); continue; } $entry_result = $this->parse_widget_entry( $entry ); if ( ! $entry_result->is_valid() ) { $result->errors()->merge( $entry_result->errors(), $element_id ); continue; } $sanitized[ sanitize_key( $element_id ) ] = $entry_result->unwrap(); } if ( ! $result->is_valid() ) { return $result; } return $result->wrap( $sanitized ); } private function parse_widget_entry( array $entry ): Parse_Result { $result = Parse_Result::make(); $sanitized = []; if ( isset( $entry['settings'] ) ) { $settings_result = $this->parse_settings( $entry['settings'] ); if ( ! $settings_result->is_valid() ) { $result->errors()->merge( $settings_result->errors(), 'settings' ); return $result; } $sanitized_settings = $settings_result->unwrap(); if ( ! empty( $sanitized_settings ) ) { $sanitized['settings'] = $sanitized_settings; } } if ( isset( $entry[ self::NESTED_VARIANT_KEY ] ) ) { $nested = $entry[ self::NESTED_VARIANT_KEY ]; if ( ! is_string( $nested ) || '' === $nested ) { $result->errors()->add( self::NESTED_VARIANT_KEY, 'invalid_variant_id' ); return $result; } $sanitized[ self::NESTED_VARIANT_KEY ] = sanitize_key( $nested ); } return $result->wrap( $sanitized ); } private function parse_settings( array $settings ): Parse_Result { $result = Parse_Result::make(); if ( isset( $settings[ self::NESTED_VARIANT_KEY ] ) ) { $result->errors()->add( self::NESTED_VARIANT_KEY, 'nested_variant_forbidden' ); return $result; } $sanitized = []; if ( isset( $settings['classes'] ) ) { $classes_result = $this->parse_classes( $settings['classes'] ); if ( ! $classes_result->is_valid() ) { $result->errors()->merge( $classes_result->errors(), 'classes' ); return $result; } $sanitized_classes = $classes_result->unwrap(); if ( ! empty( $sanitized_classes ) ) { $sanitized['classes'] = $sanitized_classes; } } return $result->wrap( $sanitized ); } private function parse_classes( array $classes ): Parse_Result { $result = Parse_Result::make(); if ( ! isset( $classes[ self::ACTION_ADD ] ) ) { return $result->wrap( [] ); } $add_list = $classes[ self::ACTION_ADD ]; if ( ! is_array( $add_list ) ) { $result->errors()->add( self::ACTION_ADD, 'invalid_structure' ); return $result; } $transformable = [ '$$type' => Classes_Prop_Type::get_key(), 'value' => $add_list, ]; $classes_prop_type = Classes_Prop_Type::make(); if ( ! $classes_prop_type->validate( $transformable ) ) { $result->errors()->add( self::ACTION_ADD, 'invalid_class_id' ); return $result; } $sanitized = $classes_prop_type->sanitize( $transformable ); return $result->wrap( [ self::ACTION_ADD => array_values( $sanitized['value'] ), ] ); } }