PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.1
Elementor Website Builder – more than just a page builder v4.3.1
4.3.1 4.3.0 4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 All 454 releases
elementor / modules / mcp / abilities / appliers / class-applier.php

class-applier.php in Elementor Website Builder – more than just a page builder 4.3.1, at modules/mcp/abilities/appliers/class-applier.php

171 lines 4.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Elementor\Modules\Mcp\Abilities\Appliers;
4
5 use Elementor\Modules\GlobalClasses\Global_Classes_Repository;
6
7 if ( ! defined( 'ABSPATH' ) ) {
8 exit;
9 }
10
11 class Class_Applier {
12
13 private Global_Classes_Repository $repository;
14
15 public function __construct( Global_Classes_Repository $repository ) {
16 $this->repository = $repository;
17 }
18
19 /**
20 * @param array<string, array&> $config_id_index Index of subtree refs.
21 * @param array<string, mixed> $classes_input Per-config-id global class labels.
22 */
23 public function apply( array $config_id_index, array $classes_input ): ?\WP_Error {
24 if ( empty( $classes_input ) ) {
25 return null;
26 }
27
28 $id_by_label = $this->build_label_to_id_map( $this->repository->all_labels() );
29 $errors = [];
30
31 foreach ( $classes_input as $config_id => $labels ) {
32 if ( ! isset( $config_id_index[ $config_id ] ) ) {
33 continue;
34 }
35
36 if ( ! is_array( $labels ) ) {
37 $errors[] = sprintf(
38 '[%s] classes must be an array of global class labels, got %s.',
39 $config_id,
40 gettype( $labels )
41 );
42 continue;
43 }
44
45 $node = &$config_id_index[ $config_id ];
46 $resolved_labels = $this->resolve_labels( $labels, $id_by_label, $config_id, $errors );
47
48 if ( V3_Node_Bridge::is_v3_node( $node ) ) {
49 if ( empty( $labels ) ) {
50 V3_Node_Bridge::clear_classes( $node );
51 } elseif ( ! empty( $resolved_labels ) ) {
52 V3_Node_Bridge::apply_classes( $node, $resolved_labels );
53 }
54
55 unset( $node );
56 continue;
57 }
58
59 if ( empty( $labels ) ) {
60 $node['settings'] = $this->clear_global_classes( $node['settings'] ?? [] );
61 unset( $node );
62 continue;
63 }
64
65 if ( empty( $resolved_labels ) ) {
66 unset( $node );
67 continue;
68 }
69
70 $resolved_ids = array_map(
71 static fn( string $label ) => $id_by_label[ $label ],
72 $resolved_labels
73 );
74
75 $node['settings'] = $this->prepend_global_classes( $node['settings'] ?? [], $resolved_ids );
76 unset( $node );
77 }
78
79 if ( empty( $errors ) ) {
80 return null;
81 }
82
83 return new \WP_Error(
84 'elementor_unknown_global_class',
85 implode( ' ', $errors ),
86 [ 'status' => \WP_Http::BAD_REQUEST ]
87 );
88 }
89
90 /**
91 * @param string[] $labels Global class labels input for this node.
92 * @param array<string,string> $id_by_label Map of label => class id (for validation).
93 * @param string $config_id Identifier used in error messages.
94 * @param string[] $errors Collected error messages (by reference).
95 * @return string[] Validated labels.
96 */
97 private function resolve_labels( array $labels, array $id_by_label, string $config_id, array &$errors ): array {
98 $resolved_labels = [];
99
100 foreach ( $labels as $label ) {
101 if ( ! is_string( $label ) || '' === $label ) {
102 $errors[] = sprintf( '[%s] Each global class label must be a non-empty string.', $config_id );
103 continue;
104 }
105
106 if ( ! isset( $id_by_label[ $label ] ) ) {
107 $errors[] = sprintf(
108 '[%s] Unknown global class label "%s". Available labels: %s',
109 $config_id,
110 $label,
111 ! empty( $id_by_label ) ? implode( ', ', array_keys( $id_by_label ) ) : '(none)'
112 );
113 continue;
114 }
115
116 $resolved_labels[] = $label;
117 }
118
119 return $resolved_labels;
120 }
121
122 private function build_label_to_id_map( array $label_by_id ): array {
123 $id_by_label = [];
124
125 foreach ( $label_by_id as $id => $label ) {
126 if ( is_string( $label ) && '' !== $label ) {
127 $id_by_label[ $label ] = $id;
128 }
129 }
130
131 return $id_by_label;
132 }
133
134 private function clear_global_classes( array $settings ): array {
135 $existing = $settings['classes']['value'] ?? [];
136
137 if ( ! is_array( $existing ) ) {
138 $existing = [];
139 }
140
141 $local_only = array_values( array_filter(
142 $existing,
143 static fn( $id ) => is_string( $id ) && str_starts_with( $id, Style_Applier::LOCAL_STYLE_ID_PREFIX )
144 ) );
145
146 $settings['classes'] = [
147 '$$type' => 'classes',
148 'value' => $local_only,
149 ];
150
151 return $settings;
152 }
153
154 private function prepend_global_classes( array $settings, array $class_ids ): array {
155 $existing = $settings['classes']['value'] ?? [];
156
157 if ( ! is_array( $existing ) ) {
158 $existing = [];
159 }
160
161 $merged = array_values( array_unique( array_merge( $class_ids, $existing ) ) );
162
163 $settings['classes'] = [
164 '$$type' => 'classes',
165 'value' => $merged,
166 ];
167
168 return $settings;
169 }
170 }
171