PluginProbe
Elementor Website Builder – more than just a page builder / 4.0.3
Elementor Website Builder – more than just a page builder v4.0.3
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 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / modules / atomic-widgets / usage / atomic-element-usage-calculator.php

atomic-element-usage-calculator.php in Elementor Website Builder – more than just a page builder 4.0.3, at modules/atomic-widgets/usage/atomic-element-usage-calculator.php

260 lines 7.1 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\AtomicWidgets\Usage;
4
5 use Elementor\Modules\AtomicWidgets\Controls\Base\Atomic_Control_Base;
6 use Elementor\Modules\AtomicWidgets\Controls\Section;
7 use Elementor\Modules\AtomicWidgets\Styles\Style_Schema;
8 use Elementor\Modules\AtomicWidgets\Utils\Utils as Atomic_Utils;
9 use Elementor\Modules\Usage\Contracts\Element_Usage_Calculator;
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit; // Exit if accessed directly.
13 }
14
15 class Atomic_Element_Usage_Calculator implements Element_Usage_Calculator {
16
17 const TAB_GENERAL = 'General';
18 const TAB_STYLE = 'Style';
19 const DEFAULT_SECTION = 'Styles';
20
21 private array $style_props_schema;
22
23 public function __construct() {
24 $this->style_props_schema = Style_Schema::get_style_schema() ?? [];
25 }
26
27 public function can_calculate( array $element, $element_instance ): bool {
28 if ( null === $element_instance ) {
29 return false;
30 }
31
32 return Atomic_Utils::is_atomic( $element_instance );
33 }
34
35 public function calculate( array $element, $element_instance, array $usage ): array {
36 $type = $this->get_element_type( $element );
37 $usage = $this->ensure_usage_entry( $usage, $type );
38 $usage[ $type ]['count']++;
39
40 if ( ! $element_instance ) {
41 return $usage;
42 }
43
44 $settings = $element['settings'] ?? [];
45 $styles = $element['styles'] ?? [];
46
47 $control_sections = $this->build_control_section_map( $element_instance->get_atomic_controls() );
48 $changed_props = $this->count_props_usage( $settings, $control_sections, $usage, $type );
49 $changed_styles = $this->count_styles_usage( $styles, $usage, $type );
50
51 $usage[ $type ]['control_percent'] = $this->calculate_control_percent(
52 $changed_props + $changed_styles,
53 $element_instance
54 );
55
56 return $usage;
57 }
58
59 private function get_element_type( array $element ): string {
60 return $element['widgetType'] ?? $element['elType'];
61 }
62
63 private function ensure_usage_entry( array $usage, string $type ): array {
64 if ( ! isset( $usage[ $type ] ) ) {
65 $usage[ $type ] = [
66 'count' => 0,
67 'control_percent' => 0,
68 'controls' => [],
69 ];
70 }
71
72 return $usage;
73 }
74
75 private function build_control_section_map( array $atomic_controls ): array {
76 $map = [];
77
78 foreach ( $atomic_controls as $item ) {
79 if ( ! ( $item instanceof Section ) ) {
80 continue;
81 }
82
83 foreach ( $item->get_items() as $control ) {
84 if ( $control instanceof Atomic_Control_Base ) {
85 $map[ $control->get_bind() ] = $item->get_label();
86 }
87 }
88 }
89
90 return $map;
91 }
92
93 private function count_props_usage( array $settings, array $control_sections, array &$usage, string $type ): int {
94 $count = 0;
95
96 foreach ( $settings as $prop_name => $value ) {
97 if ( '_cssid' === $prop_name ) {
98 continue;
99 }
100
101 if ( 'classes' === $prop_name ) {
102 $this->increment_control( $usage, $type, self::TAB_STYLE, $prop_name );
103 $count++;
104 continue;
105 }
106
107 $section = $control_sections[ $prop_name ] ?? 'unknown';
108 $this->increment_control( $usage, $type, self::TAB_GENERAL, $prop_name, $section );
109 $count++;
110 }
111
112 return $count;
113 }
114
115 private function count_styles_usage( array $styles, array &$usage, string $type ): int {
116 $count = 0;
117 $style_props = $this->collect_style_props( $styles );
118 $has_custom_css = $this->has_custom_css( $styles );
119
120 if ( $has_custom_css ) {
121 $this->increment_control( $usage, $type, self::TAB_STYLE, 'custom_css' );
122 $count++;
123 }
124
125 foreach ( $style_props as $prop_name => $value ) {
126 $prop_type = $this->style_props_schema[ $prop_name ] ?? null;
127 $count++;
128
129 if ( $prop_type ) {
130 $decomposed = $this->decompose_style_props( $prop_name, $value, $prop_type );
131 foreach ( $decomposed as $control_name ) {
132 $this->increment_control( $usage, $type, self::TAB_STYLE, $control_name );
133 }
134 } else {
135 $this->increment_control( $usage, $type, self::TAB_STYLE, $prop_name );
136 }
137 }
138
139 return $count;
140 }
141
142 private function collect_style_props( array $styles ): array {
143 $props = [];
144
145 foreach ( $styles as $style_data ) {
146 if ( empty( $style_data['variants'] ) ) {
147 continue;
148 }
149
150 foreach ( $style_data['variants'] as $variant ) {
151 if ( ! empty( $variant['props'] ) ) {
152 $props = array_merge( $props, $variant['props'] );
153 }
154 }
155 }
156
157 return $props;
158 }
159
160 private function has_custom_css( array $styles ): bool {
161 foreach ( $styles as $style_data ) {
162 if ( empty( $style_data['variants'] ) ) {
163 continue;
164 }
165
166 foreach ( $style_data['variants'] as $variant ) {
167 if ( ! empty( $variant['custom_css'] ) ) {
168 return true;
169 }
170 }
171 }
172
173 return false;
174 }
175
176 private function calculate_control_percent( int $changed_count, $instance ): int {
177 $props_schema = $instance::get_props_schema();
178 $style_props = Style_Schema::get();
179
180 $total = count( $props_schema ) + count( $style_props );
181
182 if ( 0 === $total ) {
183 return 0;
184 }
185
186 return (int) round( ( $changed_count / $total ) * 100 );
187 }
188
189 private function increment_control( array &$usage, string $type, string $tab, string $control, string $section = self::DEFAULT_SECTION ): void {
190 if ( ! isset( $usage[ $type ]['controls'][ $tab ] ) ) {
191 $usage[ $type ]['controls'][ $tab ] = [];
192 }
193
194 if ( ! isset( $usage[ $type ]['controls'][ $tab ][ $section ] ) ) {
195 $usage[ $type ]['controls'][ $tab ][ $section ] = [];
196 }
197
198 if ( ! isset( $usage[ $type ]['controls'][ $tab ][ $section ][ $control ] ) ) {
199 $usage[ $type ]['controls'][ $tab ][ $section ][ $control ] = 0;
200 }
201
202 $usage[ $type ]['controls'][ $tab ][ $section ][ $control ]++;
203 }
204
205 private function decompose_style_props( string $prop_name, $value, $prop_type, string $prefix = '' ): array {
206 $control_names = [];
207 $control_name = $prefix ? "{$prefix}-{$prop_name}" : $prop_name;
208 // phpcs:ignore
209 $kind = $prop_type::$KIND;
210
211 if ( ! $value ) {
212 return $control_names;
213 }
214
215 switch ( $kind ) {
216 case 'object':
217 $prop_shape = $prop_type->get_shape();
218 if ( isset( $value['value'] ) && is_array( $value['value'] ) ) {
219 foreach ( $value['value'] as $key => $nested_value ) {
220 if ( isset( $prop_shape[ $key ] ) ) {
221 $nested = $this->decompose_style_props( $key, $nested_value, $prop_shape[ $key ], $control_name );
222 $control_names = array_merge( $control_names, $nested );
223 }
224 }
225 }
226 break;
227
228 case 'array':
229 $item_type = $prop_type->get_item_type();
230 if ( isset( $value['value'] ) && is_array( $value['value'] ) ) {
231 foreach ( $value['value'] as $item ) {
232 $item_name = $item['$$type'] ?? 'item';
233 // phpcs:ignore
234 $item_prop_type = 'union' === $item_type::$KIND ? $item_type->get_prop_type( $item_name ) : $item_type;
235
236 if ( $item_prop_type ) {
237 $nested = $this->decompose_style_props( $item_name, $item, $item_prop_type, $control_name );
238 $control_names = array_merge( $control_names, $nested );
239 }
240 }
241 }
242 break;
243
244 case 'union':
245 $union_prop_type = $prop_type->get_prop_type_from_value( $value );
246 if ( $union_prop_type ) {
247 $nested = $this->decompose_style_props( $prop_name, $value, $union_prop_type, $prefix );
248 $control_names = array_merge( $control_names, $nested );
249 }
250 break;
251
252 default:
253 $control_names[] = $control_name;
254 break;
255 }
256
257 return $control_names;
258 }
259 }
260