PluginProbe
Elementor Website Builder – more than just a page builder / 3.34.1
Elementor Website Builder – more than just a page builder v3.34.1
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 / editor-one / classes / menu-data-provider.php

menu-data-provider.php in Elementor Website Builder – more than just a page builder 3.34.1, at modules/editor-one/classes/menu-data-provider.php

373 lines 9.6 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\EditorOne\Classes;
4
5 use Elementor\Plugin;
6 use Elementor\Modules\EditorOne\Classes\Menu\Menu_Item_Interface;
7 use Elementor\Modules\EditorOne\Classes\Menu\Menu_Item_Third_Level_Interface;
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 class Menu_Data_Provider {
14
15 private static ?Menu_Data_Provider $instance = null;
16
17 private array $level3_items = [];
18 private array $level4_items = [];
19 private ?string $theme_builder_url = null;
20 private ?array $cached_editor_flyout_data = null;
21 private ?array $cached_level4_flyout_data = null;
22 private Slug_Normalizer $slug_normalizer;
23
24 public static function instance(): self {
25 if ( null === self::$instance ) {
26 self::$instance = new self();
27 }
28
29 return self::$instance;
30 }
31
32 private function __construct() {
33 $this->slug_normalizer = new Slug_Normalizer();
34 }
35
36 public function get_slug_normalizer(): Slug_Normalizer {
37 return $this->slug_normalizer;
38 }
39
40 public function register_menu( Menu_Item_Interface $item ): void {
41 if ( $item instanceof Menu_Item_Third_Level_Interface ) {
42 $this->register_level3_item( $item );
43 } else {
44 $this->register_level4_item( $item );
45 }
46 }
47
48 public function register_level3_item( Menu_Item_Third_Level_Interface $item ): void {
49 $group_id = $item->get_group_id();
50 $item_slug = $item->get_slug();
51
52 if ( ! isset( $this->level3_items[ $group_id ] ) ) {
53 $this->level3_items[ $group_id ] = [];
54 }
55
56 $this->level3_items[ $group_id ][ $item_slug ] = $item;
57
58 $this->invalidate_cache();
59 }
60
61 public function register_level4_item( Menu_Item_Interface $item ): void {
62 $group_id = $item->get_group_id();
63 $item_slug = $item->get_slug();
64
65 if ( ! isset( $this->level4_items[ $group_id ] ) ) {
66 $this->level4_items[ $group_id ] = [];
67 }
68
69 $this->level4_items[ $group_id ][ $item_slug ] = $item;
70 $this->invalidate_cache();
71 }
72
73 public function get_level3_items(): array {
74 return $this->level3_items;
75 }
76
77 public function get_level4_items(): array {
78 return $this->level4_items;
79 }
80
81 public function is_item_already_registered( string $item_slug ): bool {
82 $all_items = array_merge( $this->level3_items, $this->level4_items );
83
84 foreach ( $all_items as $group_items ) {
85 if ( isset( $group_items[ $item_slug ] ) ) {
86 return true;
87 }
88 }
89
90 return false;
91 }
92
93 public function get_editor_flyout_data(): array {
94 if ( null !== $this->cached_editor_flyout_data ) {
95 return $this->cached_editor_flyout_data;
96 }
97
98 $items = $this->build_level3_flyout_items();
99
100 $this->sort_items_by_priority( $items );
101
102 $this->cached_editor_flyout_data = [
103 'parent_slug' => Menu_Config::EDITOR_MENU_SLUG,
104 'items' => $items,
105 ];
106
107 return $this->cached_editor_flyout_data;
108 }
109
110 public function get_level4_flyout_data(): array {
111 if ( null !== $this->cached_level4_flyout_data ) {
112 return $this->cached_level4_flyout_data;
113 }
114
115 $groups = $this->build_level4_flyout_groups();
116
117 foreach ( $groups as $group_id => $group ) {
118 if ( ! empty( $group['items'] ) ) {
119 $this->sort_items_by_priority( $groups[ $group_id ]['items'] );
120 }
121 }
122
123 $this->cached_level4_flyout_data = $groups;
124
125 return $this->cached_level4_flyout_data;
126 }
127
128 public function get_theme_builder_url(): string {
129 if ( null === $this->theme_builder_url ) {
130 $pro_url = Plugin::$instance->app ? Plugin::$instance->app->get_settings( 'menu_url' ) : null;
131 $default_url = $pro_url ? $pro_url : admin_url( 'admin.php?page=elementor-app#site-editor/promotion' );
132
133 $this->theme_builder_url = apply_filters( 'elementor/editor-one/menu/theme_builder_url', $default_url );
134 }
135
136 return $this->theme_builder_url;
137 }
138
139 public function get_all_sidebar_page_slugs(): array {
140 $base_slugs = [
141 Menu_Config::ELEMENTOR_MENU_SLUG,
142 Menu_Config::EDITOR_MENU_SLUG,
143 ];
144
145 $slugs = array_merge(
146 $base_slugs,
147 $this->get_dynamic_page_slugs()
148 );
149
150 return array_values( array_unique( $slugs ) );
151 }
152
153 public function is_elementor_editor_page(): bool {
154 if ( ! get_current_screen() ) {
155 return false;
156 }
157
158 $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ?? '';
159
160 if ( in_array( $page, $this->get_all_sidebar_page_slugs(), true ) ) {
161 return true;
162 }
163
164 $post_type = filter_input( INPUT_GET, 'post_type', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ?? '';
165
166 return $this->is_elementor_post_type( $post_type );
167 }
168
169 private function is_elementor_post_type( string $post_type ): bool {
170 if ( empty( $post_type ) ) {
171 return false;
172 }
173
174 return isset( Menu_Config::get_elementor_post_types()[ $post_type ] );
175 }
176
177 public static function get_elementor_post_types(): array {
178 return Menu_Config::get_elementor_post_types();
179 }
180
181 private function get_dynamic_page_slugs(): array {
182 $slugs = [];
183
184 foreach ( $this->level3_items as $group_items ) {
185 $slugs = array_merge( $slugs, array_keys( $group_items ) );
186 }
187
188 foreach ( $this->level4_items as $group_items ) {
189 foreach ( $group_items as $item_slug => $item ) {
190 $slugs[] = $item_slug;
191 }
192 }
193
194 $allowed_prefixes = [ 'elementor', 'e-', 'popup_templates' ];
195
196 return array_values( array_filter( $slugs, function( string $slug ) use ( $allowed_prefixes ): bool {
197 foreach ( $allowed_prefixes as $prefix ) {
198 if ( 0 === strpos( $slug, $prefix ) ) {
199 return true;
200 }
201 }
202 return false;
203 } ) );
204 }
205
206 private function build_level3_flyout_items(): array {
207 $items = [];
208 $existing_slugs = [];
209 $excluded_slugs = Menu_Config::get_excluded_level3_slugs();
210
211 foreach ( $this->level3_items as $group_items ) {
212 foreach ( $group_items as $item_slug => $item ) {
213 if ( ! $this->should_include_flyout_item( $item, $item_slug, $existing_slugs, $excluded_slugs ) ) {
214 continue;
215 }
216
217 $items[] = $this->create_flyout_item_data( $item, $item_slug );
218 $existing_slugs[] = $item_slug;
219 }
220 }
221
222 return $items;
223 }
224
225 private function should_include_flyout_item( Menu_Item_Interface $item, string $item_slug, array $existing_slugs, array $excluded_slugs ): bool {
226 if ( ! $this->is_item_accessible( $item ) ) {
227 return false;
228 }
229
230 if ( in_array( $item_slug, $existing_slugs, true ) ) {
231 return false;
232 }
233
234 if ( in_array( $item_slug, $excluded_slugs, true ) ) {
235 return false;
236 }
237
238 if ( empty( trim( wp_strip_all_tags( $item->get_label() ) ) ) ) {
239 return false;
240 }
241
242 return true;
243 }
244
245 private function create_flyout_item_data( Menu_Item_Interface $item, string $item_slug ): array {
246 $has_children = $item->has_children();
247 $group_id = $has_children ? $item->get_group_id() : '';
248
249 return [
250 'slug' => $item_slug,
251 'label' => $item->get_label(),
252 'url' => $this->resolve_flyout_item_url( $item, $item_slug ),
253 'icon' => $item->get_icon(),
254 'group_id' => $group_id,
255 'priority' => $item->get_position() ?? 100,
256 ];
257 }
258
259 private function resolve_flyout_item_url( Menu_Item_Interface $item, string $item_slug ): string {
260 $url = $this->get_item_url( $item_slug, $item->get_parent_slug() );
261
262 if ( ! $item->has_children() ) {
263 return $url;
264 }
265
266 $children = $this->get_level4_items()[ $item->get_group_id() ] ?? [];
267
268 if ( empty( $children ) ) {
269 return $url;
270 }
271
272 $first_child_url = $this->get_first_accessible_child_url( $children );
273
274 return $first_child_url ?? $url;
275 }
276
277 private function get_first_accessible_child_url( array $children ): ?string {
278 $children_data = [];
279
280 foreach ( $children as $child_slug => $child_item ) {
281 if ( ! $this->is_item_accessible( $child_item ) ) {
282 continue;
283 }
284
285 $children_data[] = [
286 'url' => $this->get_item_url( $child_slug, $child_item->get_parent_slug() ),
287 'priority' => $child_item->get_position() ?? 100,
288 ];
289 }
290
291 if ( empty( $children_data ) ) {
292 return null;
293 }
294
295 $this->sort_items_by_priority( $children_data );
296
297 return $children_data[0]['url'];
298 }
299
300 private function build_level4_flyout_groups(): array {
301 $groups = [];
302 $excluded_slugs = Menu_Config::get_excluded_level4_slugs();
303
304 foreach ( $this->level4_items as $group_id => $items ) {
305 $groups[ $group_id ] = [ 'items' => [] ];
306 $existing_labels = [];
307
308 foreach ( $items as $item_slug => $item ) {
309 if ( ! $this->is_item_accessible( $item ) ) {
310 continue;
311 }
312
313 if ( $this->slug_normalizer->is_excluded( $item_slug, $excluded_slugs ) ) {
314 continue;
315 }
316
317 $label = $item->get_label();
318 $label_lower = strtolower( $label );
319
320 if ( in_array( $label_lower, $existing_labels, true ) ) {
321 continue;
322 }
323
324 $groups[ $group_id ]['items'][] = [
325 'slug' => $item_slug,
326 'label' => $label,
327 'url' => $this->get_item_url( $item_slug, $item->get_parent_slug() ),
328 'priority' => $item->get_position() ?? 100,
329 ];
330
331 $existing_labels[] = $label_lower;
332 }
333 }
334
335 return $groups;
336 }
337
338 private function is_item_accessible( Menu_Item_Interface $item ): bool {
339 return $item->is_visible() && current_user_can( $item->get_capability() );
340 }
341
342 private function get_item_url( string $item_slug, ?string $parent_slug = null ): string {
343 $admin_path_prefixes = [ 'edit.php', 'post-new.php', 'admin.php' ];
344
345 foreach ( $admin_path_prefixes as $prefix ) {
346 if ( 0 === strpos( $item_slug, $prefix ) ) {
347 return admin_url( $item_slug );
348 }
349 }
350
351 if ( 0 === strpos( $item_slug, 'http' ) ) {
352 return $item_slug;
353 }
354
355 if ( $parent_slug && 0 === strpos( $parent_slug, 'edit.php' ) ) {
356 return admin_url( $parent_slug . '&page=' . $item_slug );
357 }
358
359 return admin_url( 'admin.php?page=' . $item_slug );
360 }
361
362 private function sort_items_by_priority( array &$items ): void {
363 usort( $items, function ( array $a, array $b ): int {
364 return ( $a['priority'] ?? 100 ) <=> ( $b['priority'] ?? 100 );
365 } );
366 }
367
368 private function invalidate_cache(): void {
369 $this->cached_editor_flyout_data = null;
370 $this->cached_level4_flyout_data = null;
371 }
372 }
373