PluginProbe
Adminify – White Label, Admin Menu Editor, Login Customizer / 4.1.17
Adminify – White Label, Admin Menu Editor, Login Customizer v4.1.17
4.3.1 4.3.0 4.2.26 4.2.25 4.2.24 4.2.23 4.2.22 4.2.21 4.2.20 4.2.19 4.2.18 4.2.17 4.2.16 4.2.15 4.2.14 4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 4.1.17 All 164 releases
adminify / Inc / Modules / MenuEditor / MenuEditor.php

MenuEditor.php in Adminify – White Label, Admin Menu Editor, Login Customizer 4.1.17, at Inc/Modules/MenuEditor/MenuEditor.php

1,926 lines 85.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPAdminify\Inc\Modules\MenuEditor;
4
5 use WPAdminify\Inc\Utils;
6 use WPAdminify\Inc\Admin\AdminSettings;
7 use WPAdminify\Inc\Modules\MenuEditor\MenuEditorAssets;
8 use WPAdminify\Inc\Admin\AdminSettingsModel;
9 use enshrined\svgSanitize\Sanitizer;
10 // no direct access allowed
11 if ( !defined( 'ABSPATH' ) ) {
12 exit;
13 }
14 /**
15 * WP Adminify
16 *
17 * @package WP Adminify: Menu Editor
18 *
19 * @author WP Adminify <support@wpadminify.com>
20 */
21 if ( !class_exists( 'MenuEditor' ) ) {
22 class MenuEditor extends MenuEditorModel {
23 public $url;
24
25 public $menu;
26
27 public $users;
28
29 public $roles;
30
31 public $submenu;
32
33 public $options = [];
34
35 public $menu_settings = [];
36
37 public static $instance;
38
39 public static function get_instance() {
40 if ( self::$instance === null ) {
41 self::$instance = new self();
42 }
43 return self::$instance;
44 }
45
46 public function __construct() {
47 $this->menu_settings = ( new MenuEditorOptions() )->get();
48 $this->options = (array) AdminSettings::get_instance()->get();
49 add_filter( 'upload_mimes', [$this, 'custom_icon_mime_types'] );
50 add_filter( 'wp_handle_upload_prefilter', [$this, 'sanitize_svg_file'] );
51 add_filter( 'admin_body_class', [$this, 'jltwp_adminify_menu_editor_body_class'] );
52 // add_filter('parent_file', [$this, 'set_menu'], 800);
53 // add_filter('parent_file', [$this, 'apply_menu'], 900);
54 // add_action('jltwp_adminify_modules_menu_editor_render', [$this, 'jltwp_adminify_modules_menu_editor_render']);
55 if ( apply_filters( 'enable_jltwp_adminify_menu_editor_render', true ) ) {
56 add_filter( 'parent_file', [$this, 'set_menu'], 800 );
57 add_filter( 'parent_file', [$this, 'apply_menu'], 900 );
58 }
59 add_action( 'wp_ajax_adminify_save_menu_settings', [$this, 'adminify_save_menu_settings'] );
60 add_action( 'wp_ajax_adminify_reset_menu_settings', [$this, 'adminify_reset_menu_settings'] );
61 add_action( 'wp_ajax_adminify_export_menu_settings', [$this, 'adminify_export_menu_settings'] );
62 add_action( 'wp_ajax_adminify_import_menu_settings', [$this, 'adminify_import_menu_settings'] );
63 add_action( 'wp_ajax_adminify_file_upload', [$this, 'adminify_file_upload_callback'] );
64 add_action( 'wp_ajax_adminify_load_custom_icons', [$this, 'adminify_load_custom_icons_callback'] );
65 add_action( 'wp_ajax_adminify_search_users', [$this, 'adminify_search_users_callback'] );
66 new MenuEditorAssets();
67 }
68
69 public function custom_icon_mime_types( $mimes ) {
70 if ( current_user_can( 'administrator' ) ) {
71 $mimes['svg'] = 'image/svg+xml';
72 }
73 return $mimes;
74 }
75
76 public function sanitize_svg_file( $file ) {
77 // Step 1: Validate File Type
78 $file_type = wp_check_filetype( $file['name'] );
79 // Ensure the file is an SVG
80 if ( $file_type['ext'] === 'svg' ) {
81 // Read the contents of the SVG file
82 $file_contents = file_get_contents( $file['tmp_name'] );
83 // Validate if it's an actual SVG by checking if it contains the <svg> tag
84 if ( strpos( $file_contents, '<svg' ) === false ) {
85 $file['error'] = 'Invalid SVG file';
86 return $file;
87 // Stop further processing if it's not a valid SVG
88 }
89 // Step 2: Sanitize the SVG File
90 $sanitizer = new Sanitizer();
91 $clean_svg = $sanitizer->sanitize( $file_contents );
92 if ( $clean_svg ) {
93 // Save the sanitized SVG back to the file
94 file_put_contents( $file['tmp_name'], $clean_svg );
95 } else {
96 $file['error'] = 'Failed to sanitize the SVG file';
97 }
98 }
99 return $file;
100 }
101
102 public function filter_attachment( $value ) {
103 // return $value->post_title == 'adminify-custom-icon';
104 return strpos( $value->guid, 'adminify-custom-icon' ) !== false;
105 }
106
107 public function adminify_load_custom_icons_callback() {
108 // Security check - verify nonce and capability
109 check_ajax_referer( 'adminify-menu-editor-security-nonce', 'security' );
110 if ( !current_user_can( 'manage_options' ) ) {
111 wp_send_json_error( array(
112 'message' => __( 'You do not have permission to perform this action.', 'adminify' ),
113 ) );
114 }
115 $result['images'] = null;
116 $query = get_posts( [
117 'post_type' => 'attachment',
118 'numberposts' => -1,
119 ] );
120 $filtered = array_filter( $query, [$this, 'filter_attachment'] );
121 foreach ( $filtered as $key => $value ) {
122 $result['images'][$value->ID] = $value->guid;
123 }
124 echo wp_json_encode( $result );
125 die;
126 }
127
128 public function adminify_file_upload_callback() {
129 $result['status'] = false;
130 check_ajax_referer( 'adminify-menu-editor-security-nonce', 'security' );
131 if ( !current_user_can( 'manage_options' ) ) {
132 wp_send_json_error( array(
133 'message' => __( 'You do not have permission to perform this action.', 'adminify' ),
134 ) );
135 }
136 $upload_dir = wp_upload_dir();
137 $targeted_dir = $upload_dir['basedir'] . '/adminify-custom-icons';
138 if ( !is_dir( $targeted_dir ) ) {
139 wp_mkdir_p( $targeted_dir );
140 }
141 add_filter( 'upload_dir', [$this, 'adminify_icon_custom_upload_dir'] );
142 $files = wp_kses_post_deep( wp_unslash( $_FILES['my_file_upload'] ) );
143 foreach ( $files['name'] as $key => $value ) {
144 if ( $files['name'][$key] ) {
145 $file = [
146 'name' => $files['name'][$key],
147 'type' => $files['type'][$key],
148 'tmp_name' => $files['tmp_name'][$key],
149 'error' => $files['error'][$key],
150 'size' => $files['size'][$key],
151 ];
152 $_FILES = [
153 'upload_file' => $file,
154 ];
155 $attachment_id = media_handle_upload( 'upload_file', 0 );
156 if ( is_wp_error( $attachment_id ) ) {
157 // There was an error uploading the image.
158 $result['status'] = false;
159 $result['message'] = __( 'Error uploading file.', 'adminify' );
160 } else {
161 // The image was uploaded successfully!
162 $result['status'] = true;
163 $result['message'] = __( 'File Uploaded successfully.', 'adminify' );
164 $result['images'][$attachment_id] = wp_get_attachment_url( $attachment_id );
165 }
166 }
167 }
168 remove_filter( 'upload_dir', [$this, 'adminify_icon_custom_upload_dir'] );
169 echo wp_json_encode( $result );
170 wp_die();
171 }
172
173 public function adminify_icon_custom_upload_dir( $dir_data ) {
174 // $dir_data already you might want to use
175 $custom_dir = 'adminify-custom-icons';
176 return [
177 'path' => $dir_data['basedir'] . '/' . $custom_dir,
178 'url' => $dir_data['baseurl'] . '/' . $custom_dir,
179 'subdir' => '/' . $custom_dir,
180 'basedir' => $dir_data['basedir'],
181 'baseurl' => $dir_data['baseurl'],
182 'error' => $dir_data['error'],
183 ];
184 }
185
186 /**
187 * AJAX callback to search users for Select2
188 * Uses 'fields' parameter for optimized database query performance
189 */
190 public function adminify_search_users_callback() {
191 check_ajax_referer( 'adminify-menu-editor-security-nonce', 'security' );
192 if ( !current_user_can( 'manage_options' ) ) {
193 wp_send_json_error( array(
194 'message' => __( 'You do not have permission to perform this action.', 'adminify' ),
195 ) );
196 }
197 $search = ( isset( $_GET['search'] ) ? sanitize_text_field( wp_unslash( $_GET['search'] ) ) : '' );
198 // If no search term or less than 3 chars, return first 3 users
199 if ( strlen( $search ) < 3 ) {
200 $args = array(
201 'number' => 3,
202 'orderby' => 'ID',
203 'order' => 'DESC',
204 'fields' => array('ID', 'user_login', 'display_name'),
205 );
206 $users = get_users( $args );
207 $results = array();
208 foreach ( $users as $user ) {
209 $results[] = array(
210 'id' => $user->user_login,
211 'text' => $user->user_login . ' (' . $user->display_name . ')',
212 );
213 }
214 // Get total user count efficiently
215 $user_count = count_users();
216 $total_users = $user_count['total_users'];
217 wp_send_json( array(
218 'results' => $results,
219 'pagination' => array(
220 'more' => $total_users > 3,
221 ),
222 'total_users' => $total_users,
223 ) );
224 return;
225 }
226 // Search users when 3+ characters typed
227 $args = array(
228 'search' => '*' . $search . '*',
229 'search_columns' => array('user_login', 'user_email', 'display_name'),
230 'number' => 20,
231 'orderby' => 'display_name',
232 'order' => 'ASC',
233 'fields' => array('ID', 'user_login', 'display_name'),
234 );
235 $users = get_users( $args );
236 $results = array();
237 foreach ( $users as $user ) {
238 $results[] = array(
239 'id' => $user->user_login,
240 'text' => $user->user_login . ' (' . $user->display_name . ')',
241 );
242 }
243 wp_send_json( array(
244 'results' => $results,
245 'pagination' => array(
246 'more' => false,
247 ),
248 ) );
249 }
250
251 // Menu Editor Body Class
252 public function jltwp_adminify_menu_editor_body_class( $classes ) {
253 $classes .= ' adminify_menu_editor ';
254 return $classes;
255 }
256
257 /**
258 * Sanitises and strips tags of input from ajax
259 *
260 * @since 1.0.0
261 * @variables $values = item to clean (array or string)
262 */
263 public function clean_ajax_input( $values ) {
264 if ( is_array( $values ) ) {
265 foreach ( $values as $index => $in ) {
266 if ( is_array( $in ) ) {
267 $values[$index] = $this->clean_ajax_input( $in );
268 } else {
269 $values[$index] = wp_strip_all_tags( $in );
270 }
271 }
272 } else {
273 $values = wp_strip_all_tags( $values );
274 }
275 return $values;
276 }
277
278 /**
279 * Returns ajax error
280 *
281 * @since 1.4
282 * @variables $message = error message to send back to user (string)
283 */
284 public function ajax_error_message( $message ) {
285 $returndata = [];
286 $returndata['error'] = true;
287 $returndata['error_message'] = $message;
288 return json_encode( $returndata );
289 }
290
291 public function adminify_save_menu_settings() {
292 if ( defined( 'DOING_AJAX' ) && DOING_AJAX && check_ajax_referer( 'adminify-menu-editor-security-nonce', 'security' ) > 0 ) {
293 if ( !current_user_can( 'manage_options' ) ) {
294 wp_send_json_error( array(
295 'message' => __( 'You do not have permission to perform this action.', 'adminify' ),
296 ) );
297 }
298 $options = wp_kses_post_deep( wp_unslash( $_POST['options'] ) );
299 $options = $this->clean_ajax_input( $options );
300 if ( $options == '' || !is_array( $options ) ) {
301 $message = __( 'No options supplied to save', 'adminify' );
302 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_kses_custom() is a wp_kses() wrapper; output already escaped.
303 echo Utils::wp_kses_custom( $this->ajax_error_message( $message ) );
304 die;
305 }
306 if ( is_array( $options ) ) {
307 update_option( $this->prefix, $options );
308 $returndata = [];
309 $returndata['success'] = true;
310 $returndata['message'] = __( 'Settings saved', 'adminify' );
311 echo json_encode( $returndata );
312 die;
313 } else {
314 $message = __( 'Something went wrong', 'adminify' );
315 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_kses_custom() is a wp_kses() wrapper; output already escaped.
316 echo Utils::wp_kses_custom( $this->ajax_error_message( $message ) );
317 die;
318 }
319 }
320 die;
321 }
322
323 /**
324 * Menu Editor Settings Reset
325 *
326 * @return void
327 */
328 public function adminify_reset_menu_settings() {
329 if ( defined( 'DOING_AJAX' ) && DOING_AJAX && check_ajax_referer( 'adminify-menu-editor-security-nonce', 'security' ) > 0 ) {
330 if ( !current_user_can( 'manage_options' ) ) {
331 wp_send_json_error( array(
332 'message' => __( 'You do not have permission to perform this action.', 'adminify' ),
333 ) );
334 }
335 update_option( $this->prefix, [] );
336 $menu_editor_options = get_option( $this->prefix );
337 if ( !$menu_editor_options ) {
338 $returndata = [];
339 $returndata['success'] = true;
340 $returndata['message'] = __( 'Settings reset', 'adminify' );
341 echo json_encode( $returndata );
342 die;
343 } else {
344 $message = __( 'Something went wrong', 'adminify' );
345 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_kses_custom() is a wp_kses() wrapper; output already escaped.
346 echo Utils::wp_kses_custom( $this->ajax_error_message( $message ) );
347 die;
348 }
349 }
350 die;
351 }
352
353 /**
354 * Export Menu Editor Settings
355 *
356 * @return void
357 */
358 public function adminify_export_menu_settings() {
359 if ( defined( 'DOING_AJAX' ) && DOING_AJAX && check_ajax_referer( 'adminify-menu-editor-security-nonce', 'security' ) > 0 ) {
360 if ( !current_user_can( 'manage_options' ) ) {
361 wp_send_json_error( array(
362 'message' => __( 'You do not have permission to perform this action.', 'adminify' ),
363 ) );
364 }
365 $menu_editor_options = get_option( $this->prefix );
366 echo json_encode( $menu_editor_options );
367 }
368 die;
369 }
370
371 /**
372 * Import Menu Editor Settings
373 *
374 * @since 1.0.0
375 */
376 public function adminify_import_menu_settings() {
377 if ( defined( 'DOING_AJAX' ) && DOING_AJAX && check_ajax_referer( 'adminify-menu-editor-security-nonce', 'security' ) > 0 ) {
378 if ( !current_user_can( 'manage_options' ) ) {
379 wp_send_json_error( array(
380 'message' => __( 'You do not have permission to perform this action.', 'adminify' ),
381 ) );
382 }
383 $new_options = wp_kses_post_deep( $_POST['settings'] );
384 if ( $new_options == '' || !is_array( $new_options ) ) {
385 $message = __( 'No options supplied to save', 'adminify' );
386 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_kses_custom() is a wp_kses() wrapper; output already escaped.
387 echo Utils::wp_kses_custom( $this->ajax_error_message( $message ) );
388 die;
389 }
390 if ( is_array( $new_options ) ) {
391 update_option( $this->prefix, $new_options );
392 $returndata = [];
393 $returndata['success'] = true;
394 $returndata['message'] = __( 'Menu Imported', 'adminify' );
395 echo json_encode( $returndata );
396 die;
397 } else {
398 $message = __( 'Something went wrong', 'adminify' );
399 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_kses_custom() is a wp_kses() wrapper; output already escaped.
400 echo Utils::wp_kses_custom( $this->ajax_error_message( $message ) );
401 die;
402 }
403 }
404 die;
405 }
406
407 /**
408 * Find menu settings for a given slug.
409 * Some plugins (e.g. Yoast SEO) register different top-level menu slugs
410 * depending on user capabilities. The admin sees slug 'wpseo_dashboard'
411 * but the editor sees 'wpseo_tools'. This method handles that mismatch
412 * by falling back to checking if the slug appears as a submenu key.
413 *
414 * @param string $slug The menu slug to look up.
415 * @return array|null The matching settings array, or null if not found.
416 */
417 public function find_menu_settings_by_slug( $slug ) {
418 // Direct match
419 if ( isset( $this->menu_settings[$slug] ) ) {
420 return $this->menu_settings[$slug];
421 }
422 // Fallback: check if this slug is a submenu of any saved parent menu
423 if ( is_array( $this->menu_settings ) ) {
424 foreach ( $this->menu_settings as $parent_slug => $parent_settings ) {
425 if ( !is_array( $parent_settings ) || !isset( $parent_settings['submenu'] ) || !is_array( $parent_settings['submenu'] ) ) {
426 continue;
427 }
428 if ( isset( $parent_settings['submenu'][$slug] ) ) {
429 return $parent_settings;
430 }
431 }
432 }
433 return null;
434 }
435
436 /**
437 * Get menu items
438 *
439 * @param [type] $parent_file
440 *
441 * @return void
442 */
443 public function set_menu( $parent_file ) {
444 global $menu, $submenu;
445 $this->menu = $this->sort_menu_settings( $menu );
446 $this->submenu = $this->sort_sub_menu_settings( $this->menu, $submenu );
447 return $parent_file;
448 }
449
450 /**
451 * Sorts Menu's for Option settings
452 */
453 public function sort_menu_settings( $thismenu ) {
454 $menu_settings = $this->menu_settings;
455 $tempmenu = [];
456 foreach ( $thismenu as $key => $current_menu_item ) {
457 if ( $current_menu_item[4] === "wp-menu-separator" ) {
458 unset($thismenu[$key]);
459 continue;
460 }
461 if ( !current_user_can( 'administrator' ) && $current_menu_item[2] === 'vc-welcome' ) {
462 unset($thismenu[$key]);
463 continue;
464 }
465 $next_menu_item = next( $thismenu );
466 $optiongroup = [];
467 $order = $key;
468 $separator = 0;
469 $external_link = 0;
470 $icon = null;
471 $hidden_for = [];
472 if ( !empty( $next_menu_item ) && strpos( $next_menu_item[2], 'separator' ) !== false ) {
473 $separator = 1;
474 }
475 if ( is_array( $menu_settings ) ) {
476 // Direct slug match first, then fallback for dynamic-slug plugins (e.g. Yoast SEO)
477 if ( isset( $menu_settings[$current_menu_item[2]] ) ) {
478 $optiongroup = $menu_settings[$current_menu_item[2]];
479 } else {
480 $fallback = $this->find_menu_settings_by_slug( $current_menu_item[2] );
481 if ( $fallback !== null ) {
482 $optiongroup = $fallback;
483 }
484 }
485 if ( !empty( $optiongroup ) ) {
486 if ( isset( $optiongroup['order'] ) ) {
487 $order = $optiongroup['order'];
488 }
489 if ( isset( $optiongroup['separator'] ) ) {
490 $separator = $optiongroup['separator'];
491 }
492 if ( isset( $optiongroup['external_link'] ) ) {
493 $external_link = $optiongroup['external_link'];
494 }
495 if ( !empty( $optiongroup['icon'] ) ) {
496 $icon = $optiongroup['icon'];
497 }
498 if ( !empty( $optiongroup['hidden_for'] ) ) {
499 $hidden_for = $optiongroup['hidden_for'];
500 }
501 }
502 }
503 $current_menu_item['order'] = $order;
504 $current_menu_item['hidden_for'] = $hidden_for;
505 $current_menu_item['separator'] = $separator;
506 $current_menu_item['external_link'] = $external_link;
507 // if (empty($this->options['admin_ui'])) {
508 if ( $icon !== null ) {
509 if ( strpos( $icon, 'dashicons ' ) !== false ) {
510 $menu_icon = str_replace( 'dashicons ', '', $icon );
511 $current_menu_item[6] = $menu_icon;
512 } else {
513 if ( strpos( $icon, ',' ) !== false ) {
514 $menu_icon = explode( ',', $icon )[1];
515 } else {
516 $menu_icon = 'dashicons-adminify- ' . $icon;
517 }
518 $current_menu_item[6] = $menu_icon;
519 }
520 }
521 if ( $separator == 1 ) {
522 $current_menu_item[4] = $current_menu_item[4] . ' adminify-menu-separator';
523 }
524 // }
525 array_push( $tempmenu, $current_menu_item );
526 if ( isset( $menu_settings[$current_menu_item[2]] ) ) {
527 unset($menu_settings[$current_menu_item[2]]);
528 }
529 }
530 if ( is_array( $menu_settings ) && !array_key_exists( 0, $menu_settings ) ) {
531 foreach ( $menu_settings as $key => $menu_s ) {
532 // Skip if $menu_s is not an array
533 if ( !is_array( $menu_s ) ) {
534 continue;
535 }
536 // Ensure required keys exist with defaults
537 $menu_s = wp_parse_args( $menu_s, [
538 'name' => '',
539 'link' => '',
540 'icon' => '',
541 'order' => 0,
542 'separator' => 0,
543 'external_link' => 0,
544 'hidden_for' => [],
545 ] );
546 $new_array = [
547 $menu_s['name'],
548 'read',
549 ( !empty( $menu_s['link'] ) ? $menu_s['link'] : '' ),
550 '',
551 'menu-top menu-icon-custom',
552 $key,
553 ( !empty( $menu_s['icon'] ) ? $menu_s['icon'] : '' ),
554 'order' => $menu_s['order'],
555 'separator' => ( !empty( $menu_s['separator'] ) ? $menu_s['separator'] : 0 ),
556 'external_link' => ( !empty( $menu_s['external_link'] ) ? $menu_s['external_link'] : 0 ),
557 'hidden_for' => ( !empty( $menu_s['hidden_for'] ) ? $menu_s['hidden_for'] : [] )
558 ];
559 // if (empty($this->options['admin_ui'])) {
560 if ( strpos( $menu_s['icon'], 'dashicons ' ) !== false ) {
561 $menu_icon = str_replace( 'dashicons ', '', $menu_s['icon'] );
562 } else {
563 if ( empty( $menu_s['icon'] ) || strpos( $menu_s['icon'], ',' ) !== false ) {
564 if ( empty( $menu_s['icon'] ) ) {
565 $menu_icon = WP_ADMINIFY_ASSETS_IMAGE . 'logos/menu-icon.svg';
566 } else {
567 $menu_icon = explode( ',', $menu_s['icon'] )[1];
568 }
569 } else {
570 $menu_icon = 'dashicons-adminify- ' . $menu_s['icon'];
571 }
572 }
573 if ( !empty( $menu_s['separator'] ) && $menu_s['separator'] == 1 ) {
574 $new_array[4] = $new_array[4] . ' adminify-menu-separator';
575 }
576 // if (!empty($menu_s['external_link']) && $menu_s['external_link'] == 1) {
577 // $new_array[4] = $new_array[4] . ' adminify-menu-external_link';
578 // }
579 $new_array[6] = $menu_icon;
580 // }
581 array_push( $tempmenu, $new_array );
582 }
583 }
584 return $this->sort_array( $tempmenu );
585 }
586
587 /**
588 * usort function for menu arrays
589 */
590 public function sort_array_helper( $a, $b ) {
591 $result = 0;
592 if ( !isset( $a['order'] ) ) {
593 return $result;
594 }
595 if ( $a['order'] > $b['order'] ) {
596 $result = 1;
597 } elseif ( $a['order'] < $b['order'] ) {
598 $result = -1;
599 }
600 return $result;
601 }
602
603 /**
604 * Sorts arrays by key 'order'
605 */
606 public function sort_array( $tosort ) {
607 usort( $tosort, [$this, 'sort_array_helper'] );
608 return $tosort;
609 }
610
611 /**
612 * Sorts Sub Menu for settings
613 *
614 * @since 1.4
615 */
616 public function sort_sub_menu_settings( $themenu, $thesubmenu ) {
617 $menu_settings = $this->menu_settings;
618 $tempsubmenu = [];
619 foreach ( $themenu as $current_menu_item ) {
620 $optiongroup = [];
621 $submenu_items = [];
622 if ( isset( $thesubmenu[$current_menu_item[2]] ) ) {
623 $submenuitems = $thesubmenu[$current_menu_item[2]];
624 foreach ( $submenuitems as $key => $subitem ) {
625 $subitem['order'] = $key;
626 if ( is_array( $menu_settings ) && isset( $menu_settings[$current_menu_item[2]] ) && isset( $menu_settings[$current_menu_item[2]]['submenu'] ) ) {
627 $submenugroup = $menu_settings[$current_menu_item[2]]['submenu'];
628 if ( isset( $submenugroup[$subitem[2]] ) ) {
629 $itemoptions = $submenugroup[$subitem[2]];
630 if ( isset( $itemoptions['order'] ) ) {
631 $subitem['order'] = $itemoptions['order'];
632 }
633 }
634 }
635 array_push( $submenu_items, $subitem );
636 }
637 $submenu_items = $this->sort_array( $submenu_items );
638 $tempsubmenu[$current_menu_item[2]] = $submenu_items;
639 }
640 }
641 if ( is_array( $menu_settings ) ) {
642 $tmp_menu = [];
643 foreach ( $menu_settings as $key => $menu_s ) {
644 if ( isset( $menu_s['submenu'] ) && is_array( $menu_s['submenu'] ) ) {
645 $tmp_sub_menu = [];
646 $i = 0;
647 foreach ( $menu_s['submenu'] as $k => $sub_menu ) {
648 if ( strpos( $k, 'adminify-custom-submenu' ) === false ) {
649 continue;
650 }
651 $order = ( $sub_menu['order'] ? $sub_menu['order'] : $i );
652 $new_array = [
653 ( $sub_menu['name'] ? $sub_menu['name'] : '' ),
654 'read',
655 ( $sub_menu['link'] ? $sub_menu['link'] : '' ),
656 'order' => $order,
657 'key' => $k,
658 'hidden_for' => ( isset( $sub_menu['hidden_for'] ) ? $sub_menu['hidden_for'] : [] )
659 ];
660 // processing submenu array
661 $tmp_sub_menu[$order] = $new_array;
662 $i++;
663 }
664 if ( !empty( $tmp_sub_menu ) ) {
665 // adding submenu into temp variable
666 $tmp_menu[$key] = $tmp_sub_menu;
667 }
668 }
669 }
670 if ( !empty( $tmp_menu ) ) {
671 $tempsubmenu = array_merge_recursive( $tempsubmenu, $tmp_menu );
672 }
673 foreach ( $tempsubmenu as $m_k => $m_menu ) {
674 $tempsubmenu[$m_k] = $this->sort_array( $tempsubmenu[$m_k] );
675 }
676 }
677 return $tempsubmenu;
678 }
679
680 /**
681 * Applies menu settings
682 */
683 public function apply_menu( $parent_file ) {
684 // Not applicable for Network Admin
685 if ( is_multisite() && is_network_admin() ) {
686 return;
687 }
688 global $menu, $submenu;
689 $tempmenu = [];
690 $tempsub = [];
691 $submenu = $this->sort_sub_menu_settings( $menu, $submenu );
692 if ( $this->menu && is_array( $this->menu ) ) {
693 foreach ( $this->menu as $key => $menu_item ) {
694 if ( empty( $menu_item[2] ) ) {
695 continue;
696 }
697 if ( strpos( $menu_item[2], 'separator' ) !== false && !$menu_item[0] ) {
698 // Build Separator
699 $newitem = $this->apply_separator_settings( $menu_item, $key );
700 if ( $newitem ) {
701 array_push( $tempmenu, $newitem );
702 }
703 } else {
704 // Build Top Level
705 $newitem = $this->apply_top_level_settings( $menu_item, $key );
706 if ( $newitem ) {
707 array_push( $tempmenu, $newitem );
708 // Menu Editor Custom Separator
709 if ( !empty( $newitem['separator'] ) ) {
710 $separator_order = $this->menu[$key]['order'];
711 $empty_separator = array(
712 0 => '',
713 1 => 'read',
714 2 => 'separator_' . wp_rand( 200, 1000 ) * 1000,
715 3 => '',
716 4 => 'wp-menu-separator',
717 'order' => $separator_order + 0.5,
718 );
719 array_push( $tempmenu, $empty_separator );
720 }
721 $parent_key = $newitem[2];
722 if ( strpos( $newitem[5], 'adminify-custom-menu-' ) !== false ) {
723 $parent_key = $newitem[5];
724 }
725 if ( isset( $this->submenu[$parent_key] ) ) {
726 $subitem = $this->apply_sub_level_settings( $this->submenu[$parent_key], $parent_key );
727 if ( $subitem ) {
728 $tempsub[$newitem[2]] = $this->apply_sub_level_settings( $this->submenu[$parent_key], $parent_key );
729 }
730 }
731 }
732 }
733 }
734 }
735 $submenu = $tempsub;
736 $menu = $this->sort_array( $tempmenu );
737 return $parent_file;
738 }
739
740 /**
741 * Applies sub level menu item settings
742 *
743 * @return $tempsub | false
744 *
745 * @since 1.4
746 */
747 public function apply_sub_level_settings( $subitems, $parentname ) {
748 if ( !is_array( $this->menu_settings ) ) {
749 return $subitems;
750 }
751 if ( !isset( $this->menu_settings[$parentname]['submenu'] ) ) {
752 return $subitems;
753 }
754 $submenu_settings = $this->menu_settings[$parentname]['submenu'];
755 $tempsub = [];
756 foreach ( $subitems as $current_menu_item ) {
757 $sub_level = apply_filters( 'adminify/menu_editor', [
758 'sub_level' => false,
759 ] );
760 if ( !empty( $sub_level['sub_level'] ) ) {
761 if ( empty( $current_menu_item[0] ) || $current_menu_item[2] === 'wp-adminify-settings-pricing' ) {
762 continue;
763 }
764 }
765 $name = '';
766 $link = '';
767 $disabled_for = [];
768 $optiongroup = [];
769 // NO SETTINGS
770 if ( isset( $submenu_settings[$current_menu_item[2]] ) ) {
771 $optiongroup = $submenu_settings[$current_menu_item[2]];
772 if ( isset( $optiongroup['name'] ) ) {
773 $name = $optiongroup['name'];
774 if ( $name != '' ) {
775 $current_menu_item[0] = $name;
776 }
777 }
778 if ( isset( $optiongroup['link'] ) ) {
779 $link = $optiongroup['link'];
780 if ( $link != '' ) {
781 $current_menu_item[2] = $link;
782 $current_menu_item['link'] = $link;
783 }
784 }
785 if ( isset( $optiongroup['external_link'] ) ) {
786 $external_link = $optiongroup['external_link'];
787 }
788 if ( isset( $optiongroup['hidden_for'] ) ) {
789 $disabled_for = $optiongroup['hidden_for'];
790 if ( $this->is_hidden( $disabled_for ) ) {
791 $current_menu_item['hidden_for'] = true;
792 continue;
793 }
794 }
795 }
796 $custom_menu = ( isset( $current_menu_item['key'] ) ? $current_menu_item['key'] : '' );
797 if ( strpos( $custom_menu, 'adminify-custom-submenu-' ) !== false ) {
798 if ( isset( $submenu_settings[$current_menu_item['key']]['hidden_for'] ) ) {
799 $disabled_for = $submenu_settings[$current_menu_item['key']]['hidden_for'];
800 }
801 if ( isset( $submenu_settings[$current_menu_item['key']]['external_link'] ) ) {
802 $external_link = $submenu_settings[$current_menu_item['key']]['external_link'];
803 }
804 if ( $this->is_hidden( $disabled_for ) ) {
805 $current_menu_item['hidden_for'] = true;
806 continue;
807 }
808 }
809 array_push( $tempsub, $current_menu_item );
810 }
811 if ( count( $tempsub ) < 1 ) {
812 return false;
813 } else {
814 return $tempsub;
815 }
816 }
817
818 /**
819 * Applies top level menu item settings
820 *
821 * @since 1.4
822 */
823 public function apply_top_level_settings( $current_menu_item, $key ) {
824 $name = '';
825 $link = '';
826 $icon = '';
827 $disabled_for = [];
828 $optiongroup = [];
829 $order = $key;
830 if ( is_array( $this->menu_settings ) ) {
831 // Direct slug match first, then fallback for dynamic-slug plugins (e.g. Yoast SEO)
832 if ( isset( $this->menu_settings[$current_menu_item[2]] ) ) {
833 $optiongroup = $this->menu_settings[$current_menu_item[2]];
834 } else {
835 $fallback = $this->find_menu_settings_by_slug( $current_menu_item[2] );
836 if ( $fallback !== null ) {
837 $optiongroup = $fallback;
838 }
839 }
840 if ( !empty( $optiongroup ) ) {
841 if ( isset( $optiongroup['name'] ) ) {
842 $name = $optiongroup['name'];
843 if ( $name != '' ) {
844 $current_menu_item[0] = $name;
845 }
846 }
847 if ( isset( $optiongroup['link'] ) ) {
848 $link = $optiongroup['link'];
849 if ( $link != '' ) {
850 $current_menu_item[2] = $link;
851 $current_menu_item['link'] = $link;
852 }
853 }
854 if ( isset( $optiongroup['external_link'] ) ) {
855 $external_link = ( $optiongroup['external_link'] ? $optiongroup['external_link'] : '' );
856 }
857 if ( isset( $optiongroup['icon'] ) ) {
858 $icon = $optiongroup['icon'];
859 if ( $icon != '' ) {
860 $current_menu_item['icon'] = $icon;
861 }
862 }
863 if ( isset( $optiongroup['order'] ) ) {
864 $order = $optiongroup['order'];
865 }
866 if ( isset( $optiongroup['hidden_for'] ) ) {
867 $disabled_for = $optiongroup['hidden_for'];
868 if ( $this->is_hidden( $disabled_for ) ) {
869 $current_menu_item['hidden_for'] = true;
870 } else {
871 $current_menu_item['hidden_for'] = false;
872 }
873 }
874 }
875 $custom_menu = ( isset( $current_menu_item[5] ) ? $current_menu_item[5] : '' );
876 if ( strpos( $custom_menu, 'adminify-custom-menu-' ) !== false ) {
877 if ( isset( $this->menu_settings[$current_menu_item[5]]['hidden_for'] ) && !empty( $this->menu_settings[$current_menu_item[5]]['hidden_for'] ) ) {
878 $disabled_for = $this->menu_settings[$current_menu_item[5]]['hidden_for'];
879 if ( $this->is_hidden( $disabled_for ) ) {
880 $current_menu_item['hidden_for'] = true;
881 }
882 }
883 if ( isset( $this->menu_settings[$current_menu_item[5]]['external_link'] ) ) {
884 $external_link = $this->menu_settings[$current_menu_item[5]]['external_link'];
885 }
886 }
887 }
888 $current_menu_item['order'] = $order;
889 // Check hidden_for: boolean true means hide, array means check via is_hidden
890 if ( isset( $current_menu_item['hidden_for'] ) ) {
891 if ( $current_menu_item['hidden_for'] === true ) {
892 return false;
893 } elseif ( is_array( $current_menu_item['hidden_for'] ) && !empty( $current_menu_item['hidden_for'] ) ) {
894 // Fallback: hidden_for is still an array (settings lookup may have missed it)
895 if ( $this->is_hidden( $current_menu_item['hidden_for'] ) ) {
896 return false;
897 }
898 }
899 return $current_menu_item;
900 } else {
901 return $current_menu_item;
902 }
903 }
904
905 /**
906 * Hidden for method
907 *
908 * @param [type] $disabled_for
909 *
910 * @return boolean
911 */
912 public function is_hidden( $disabled_for ) {
913 if ( !is_array( $disabled_for ) ) {
914 return false;
915 }
916 $current_user = wp_get_current_user();
917 $current_roles = $current_user->roles;
918 $all_roles = wp_roles()->get_names();
919 foreach ( $current_roles as $current_role ) {
920 if ( isset( $all_roles[$current_role] ) && in_array( $all_roles[$current_role], $disabled_for ) ) {
921 return true;
922 }
923 }
924 // Normalize disabled_for array
925 $disabled_for_arr = [];
926 foreach ( $disabled_for as $v ) {
927 $disabled_for_arr[] = jlt_adminify_sluggify_with_underscores( $v );
928 }
929 $slugify_user_login = jlt_adminify_sluggify_with_underscores( $current_user->user_login );
930 // Check Username
931 if ( in_array( $current_user->user_login, $disabled_for_arr ) || in_array( $slugify_user_login, $disabled_for_arr ) ) {
932 return true;
933 }
934 // Check User Roles and Capabilities
935 foreach ( $current_roles as $role ) {
936 $role_obj = get_role( $role );
937 if ( !$role_obj ) {
938 continue;
939 }
940 // Check if role slug is in disabled array
941 if ( in_array( $role, $disabled_for_arr ) ) {
942 return true;
943 }
944 // Check if role display name is in disabled array
945 if ( isset( $disabled_for_arr[$role] ) && (in_array( $all_roles[$role], $disabled_for ) || in_array( strtolower( $all_roles[$role] ), array_map( 'strtolower', $disabled_for ) )) ) {
946 return true;
947 }
948 // Check for custom roles
949 foreach ( $disabled_for as $disabled_item ) {
950 // Convert role names to match WordPress format
951 $disabled_role = str_replace( ' ', '_', strtolower( $disabled_item ) );
952 if ( $role === $disabled_role ) {
953 return true;
954 }
955 }
956 }
957 // Handle Super Admin specially
958 if ( is_super_admin( $current_user->ID ) ) {
959 if ( in_array( 'Super Admin', $disabled_for_arr ) || in_array( 'super_admin', $disabled_for_arr ) || in_array( 'administrator', $disabled_for_arr ) ) {
960 return true;
961 }
962 // Super admin sees everything by default unless explicitly disabled
963 return false;
964 }
965 // Special check for user ID 1 (default admin)
966 if ( $current_user->ID === 1 ) {
967 if ( in_array( 'Super Admin', $disabled_for_arr ) || in_array( 'super_admin', $disabled_for_arr ) || in_array( 'administrator', $disabled_for_arr ) ) {
968 return true;
969 }
970 return false;
971 }
972 return false;
973 }
974
975 /**
976 * Applies separator menu item settings
977 *
978 * @since 1.0.0
979 */
980 public function apply_separator_settings( $current_menu_item, $key ) {
981 $name = '';
982 $disabled_for = [];
983 $optiongroup = [];
984 $order = $key;
985 if ( is_array( $this->menu_settings ) ) {
986 if ( isset( $this->menu_settings[$current_menu_item[2]] ) ) {
987 $optiongroup = $this->menu_settings[$current_menu_item[2]];
988 if ( isset( $optiongroup['name'] ) ) {
989 $name = $optiongroup['name'];
990 if ( $name != '' ) {
991 $current_menu_item['name'] = $name;
992 }
993 }
994 if ( isset( $optiongroup['order'] ) ) {
995 $order = $optiongroup['order'];
996 }
997 if ( isset( $optiongroup['hidden_for'] ) ) {
998 $disabled_for = $optiongroup['hidden_for'];
999 if ( $this->is_hidden( $disabled_for ) ) {
1000 $current_menu_item['hidden_for'] = true;
1001 }
1002 }
1003 }
1004 }
1005 $current_menu_item['order'] = $order;
1006 if ( isset( $current_menu_item['hidden_for'] ) ) {
1007 if ( $current_menu_item['hidden_for'] == true ) {
1008 return false;
1009 } else {
1010 return $current_menu_item;
1011 }
1012 } else {
1013 return $current_menu_item;
1014 }
1015 }
1016
1017 public function get_saved_sub_menu() {
1018 $menu_settings = $this->menu_settings;
1019 $menu = $this->menu;
1020 $submenu = $this->submenu;
1021 if ( is_array( $menu_settings ) && !array_key_exists( 0, $menu_settings ) ) {
1022 foreach ( $menu as $menu_item ) {
1023 if ( isset( $menu_settings[$menu_item[2]] ) ) {
1024 unset($menu_settings[$menu_item[2]]);
1025 }
1026 }
1027 $tmp_menu = [];
1028 foreach ( $menu_settings as $key => $menu_s ) {
1029 if ( isset( $menu_s['submenu'] ) && is_array( $menu_s['submenu'] ) ) {
1030 $tmp_sub_menu = [];
1031 $i = 0;
1032 foreach ( $menu_s['submenu'] as $k => $sub_menu ) {
1033 $new_array = [
1034 $sub_menu['name'],
1035 'read',
1036 $sub_menu['link'],
1037 'order' => $i
1038 ];
1039 $tmp_sub_menu[$i] = $new_array;
1040 $i++;
1041 }
1042 if ( !empty( $tmp_sub_menu ) ) {
1043 $tmp_menu[$key] = $tmp_sub_menu;
1044 }
1045 }
1046 }
1047 if ( !empty( $tmp_menu ) ) {
1048 $submenu = $submenu + $tmp_menu;
1049 }
1050 }
1051 return $submenu;
1052 }
1053
1054 /**
1055 * Render Menu Editor
1056 */
1057 public function render_menu_editor() {
1058 global $wp_roles;
1059 $this->roles = $wp_roles->roles;
1060 if ( $this->menu && is_array( $this->menu ) ) {
1061 foreach ( $this->menu as $menu_item ) {
1062 $next_menu_item = next( $this->menu );
1063 if ( strpos( $menu_item[2], 'separator' ) !== false && !$menu_item[0] ) {
1064 // Render Separator
1065 // $this->render_menu_separator($menu_item);
1066 } else {
1067 // Render Top Level menu
1068 $this->render_top_level_menu_item(
1069 $this->menu,
1070 $menu_item,
1071 $this->submenu,
1072 $next_menu_item
1073 );
1074 }
1075 }
1076 $this->render_add_new_menu_item();
1077 }
1078 }
1079
1080 public function get_icon( $value, $default ) {
1081 if ( empty( $value ) ) {
1082 return $default;
1083 }
1084 return $value;
1085 }
1086
1087 /**
1088 * Generate User Rules Select box
1089 */
1090 public function generate_user_rules_select_field( $menu_id, $disabled_for, $menu_type = 'menu' ) {
1091 ob_start();
1092 ?>
1093 <select class="adminify-menu-settings adminify-user-role-select <?php
1094 echo esc_attr( $menu_type );
1095 ?>_setting" name="hidden_for" id="<?php
1096 echo esc_attr( $menu_id );
1097 ?>-user-role-types" multiple>
1098 <optgroup label="<?php
1099 esc_attr_e( 'Roles', 'adminify' );
1100 ?>">
1101 <?php
1102 foreach ( $this->roles as $role ) {
1103 $rolename = $role['name'];
1104 if ( 'administrator' == strtolower( $rolename ) ) {
1105 continue;
1106 }
1107 $sel = '';
1108 if ( in_array( $rolename, $disabled_for ) ) {
1109 $sel = 'selected';
1110 }
1111 ?>
1112 <option value="<?php
1113 echo esc_attr( $rolename );
1114 ?>" <?php
1115 echo esc_attr( $sel );
1116 ?>><?php
1117 echo esc_html( $rolename );
1118 ?></option>
1119 <?php
1120 }
1121 ?>
1122 </optgroup>
1123
1124 <optgroup label="<?php
1125 esc_attr_e( 'Users', 'adminify' );
1126 ?>" class="adminify-users-optgroup">
1127 <?php
1128 // Only include pre-selected users in HTML (AJAX will populate dropdown)
1129 foreach ( $disabled_for as $item ) {
1130 // Check if this is a user (not a role)
1131 $is_role = false;
1132 foreach ( $this->roles as $role ) {
1133 if ( $role['name'] === $item ) {
1134 $is_role = true;
1135 break;
1136 }
1137 }
1138 if ( !$is_role ) {
1139 $user = get_user_by( 'login', $item );
1140 if ( $user ) {
1141 ?>
1142 <option value="<?php
1143 echo esc_attr( $user->user_login );
1144 ?>" selected><?php
1145 echo esc_html( $user->user_login . ' (' . $user->display_name . ')' );
1146 ?></option>
1147 <?php
1148 }
1149 }
1150 }
1151 ?>
1152 </optgroup>
1153 </select>
1154 <?php
1155 return ob_get_clean();
1156 }
1157
1158 /**
1159 * Render Top Level menu Item
1160 *
1161 * @return void
1162 */
1163 public function render_top_level_menu_item(
1164 $master_menu,
1165 $current_menu_item,
1166 $master_sub_menu,
1167 $next_menu_item
1168 ) {
1169 if ( empty( $current_menu_item[2] ) ) {
1170 return;
1171 }
1172 // $disabled_for = '';
1173 $menu_id = preg_replace( '/[^A-Za-z0-9 ]/', '', $current_menu_item[5] );
1174 $name = '';
1175 $link = '';
1176 $external_link = '';
1177 $icon = '';
1178 $separator = '';
1179 $disabled_for = [];
1180 $optiongroup = [];
1181 $menu_options = $this->menu_settings;
1182 if ( !empty( $next_menu_item ) && strpos( $next_menu_item[2], 'separator' ) !== false ) {
1183 $separator = 1;
1184 }
1185 if ( is_array( $menu_options ) ) {
1186 if ( isset( $menu_options[$current_menu_item[2]] ) ) {
1187 $optiongroup = $menu_options[$current_menu_item[2]];
1188 if ( isset( $optiongroup['name'] ) ) {
1189 $name = $optiongroup['name'];
1190 }
1191 if ( isset( $optiongroup['link'] ) ) {
1192 $link = $optiongroup['link'];
1193 }
1194 if ( isset( $optiongroup['icon'] ) ) {
1195 $icon = $optiongroup['icon'];
1196 }
1197 if ( isset( $optiongroup['hidden_for'] ) ) {
1198 $disabled_for = $optiongroup['hidden_for'];
1199 }
1200 if ( isset( $optiongroup['separator'] ) ) {
1201 $separator = $optiongroup['separator'];
1202 }
1203 if ( isset( $optiongroup['external_link'] ) ) {
1204 $external_link = $optiongroup['external_link'];
1205 }
1206 }
1207 }
1208 $name_attr = $current_menu_item[2];
1209 if ( strpos( $current_menu_item[5], 'adminify-custom-menu-' ) !== false ) {
1210 $name_attr = $current_menu_item[5];
1211 $name = $current_menu_item[0];
1212 $link = $current_menu_item[2];
1213 if ( isset( $menu_options[$current_menu_item[5]]['hidden_for'] ) ) {
1214 $disabled_for = $menu_options[$current_menu_item[5]]['hidden_for'];
1215 }
1216 if ( isset( $menu_options[$current_menu_item[5]] ) ) {
1217 $optiongroup = $menu_options[$current_menu_item[5]];
1218 }
1219 if ( isset( $menu_options[$current_menu_item[5]]['icon'] ) ) {
1220 $icon = $menu_options[$current_menu_item[5]]['icon'];
1221 }
1222 if ( isset( $current_menu_item['separator'] ) ) {
1223 $separator = $current_menu_item['separator'];
1224 }
1225 if ( isset( $current_menu_item['external_link'] ) ) {
1226 $external_link = $current_menu_item['external_link'];
1227 }
1228 }
1229 if ( !is_array( $disabled_for ) ) {
1230 $disabled_for = [];
1231 }
1232 // LIST OF AVAILABLE MENU ICONS
1233 $icons = [
1234 'dashicons-admin-multisite' => 'dashicons dashicons-admin-multisite',
1235 'dashicons-dashboard' => 'dashicons dashicons-dashboard',
1236 'dashicons-admin-post' => 'dashicons dashicons-admin-post',
1237 'dashicons-database' => 'dashicons dashicons-database',
1238 'dashicons-admin-media' => 'dashicons dashicons-admin-media',
1239 'dashicons-admin-page' => 'dashicons dashicons-admin-page',
1240 'dashicons-admin-comments' => 'dashicons dashicons-admin-comments',
1241 'dashicons-admin-appearance' => 'dashicons dashicons-admin-appearance',
1242 'dashicons-admin-plugins' => 'dashicons dashicons-admin-plugins',
1243 'dashicons-admin-users' => 'dashicons dashicons-admin-users',
1244 'dashicons-admin-tools' => 'dashicons dashicons-admin-tools',
1245 'dashicons-chart-bar' => 'dashicons dashicons-chart-bar',
1246 'dashicons-admin-settings' => 'dashicons dashicons-admin-settings',
1247 ];
1248 $default_icons = ( isset( $current_menu_item ) ? $current_menu_item[6] : 'dashicons dashicons-external' );
1249 ?>
1250 <div class="accordion adminify_menu_item" name="<?php
1251 echo esc_attr( $name_attr );
1252 ?>" id="wp-adminify-top-menu-<?php
1253 echo esc_attr( $menu_id );
1254 ?>">
1255 <input type="number" class="top_level_order" value="" style="display:none;">
1256 <a class="menu-editor-title accordion-button adminify-flex adminify-flex-center adminify-gap-2" href="#">
1257 <svg class="drag-icon is-pulled-left mr-2" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1258 <path d="M12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14Z" fill="#4E4B66" fill-opacity="0.72" />
1259 <path d="M12 7C13.1046 7 14 6.10457 14 5C14 3.89543 13.1046 3 12 3C10.8954 3 10 3.89543 10 5C10 6.10457 10.8954 7 12 7Z" fill="#4E4B66" fill-opacity="0.72" />
1260 <path d="M12 21C13.1046 21 14 20.1046 14 19C14 17.8954 13.1046 17 12 17C10.8954 17 10 17.8954 10 19C10 20.1046 10.8954 21 12 21Z" fill="#4E4B66" fill-opacity="0.72" />
1261 <path d="M5 14C6.10457 14 7 13.1046 7 12C7 10.8954 6.10457 10 5 10C3.89543 10 3 10.8954 3 12C3 13.1046 3.89543 14 5 14Z" fill="#4E4B66" fill-opacity="0.72" />
1262 <path d="M5 7C6.10457 7 7 6.10457 7 5C7 3.89543 6.10457 3 5 3C3.89543 3 3 3.89543 3 5C3 6.10457 3.89543 7 5 7Z" fill="#4E4B66" fill-opacity="0.72" />
1263 <path d="M5 21C6.10457 21 7 20.1046 7 19C7 17.8954 6.10457 17 5 17C3.89543 17 3 17.8954 3 19C3 20.1046 3.89543 21 5 21Z" fill="#4E4B66" fill-opacity="0.72" />
1264 <path d="M19 14C20.1046 14 21 13.1046 21 12C21 10.8954 20.1046 10 19 10C17.8954 10 17 10.8954 17 12C17 13.1046 17.8954 14 19 14Z" fill="#4E4B66" fill-opacity="0.72" />
1265 <path d="M19 7C20.1046 7 21 6.10457 21 5C21 3.89543 20.1046 3 19 3C17.8954 3 17 3.89543 17 5C17 6.10457 17.8954 7 19 7Z" fill="#4E4B66" fill-opacity="0.72" />
1266 <path d="M19 21C20.1046 21 21 20.1046 21 19C21 17.8954 20.1046 17 19 17C17.8954 17 17 17.8954 17 19C17 20.1046 17.8954 21 19 21Z" fill="#4E4B66" fill-opacity="0.72" />
1267 </svg>
1268 <?php
1269 echo wp_kses_post( preg_replace( '/\\<span.*?>.*?\\<\\/span><\\/span>/s', '', $current_menu_item[0] ) );
1270 ?>
1271 </a>
1272
1273 <div class="accordion-body adminify_top_level_settings">
1274 <div class="tabs tabbable">
1275 <ul class="adminify-flex adminify-flex-center adminify-m-0 nav nav-tabs">
1276 <li class="nav-item active">
1277 <a class="nav-link is-clickable active" href="#tab-<?php
1278 echo esc_attr( $menu_id );
1279 ?>-1">
1280 <?php
1281 esc_html_e( 'Settings', 'adminify' );
1282 ?>
1283 </a>
1284 </li>
1285 <li class="nav-item" role="presentation">
1286 <a class="nav-link is-clickable" href="#tab-<?php
1287 echo esc_attr( $menu_id );
1288 ?>-2">
1289 <?php
1290 esc_html_e( 'Submenu', 'adminify' );
1291 ?>
1292 </a>
1293 </li>
1294 </ul>
1295 </div>
1296
1297 <div class="tab-content tab-panel panel adminify-p-4">
1298 <div id="tab-<?php
1299 echo esc_attr( $menu_id );
1300 ?>-1" class="tab-pane">
1301 <div class="menu-editor-form">
1302 <div class="columns">
1303 <div class="column">
1304 <label for="<?php
1305 echo esc_attr( $current_menu_item[2] );
1306 ?>">
1307 <?php
1308 esc_html_e( 'Rename as', 'adminify' );
1309 ?>
1310 </label>
1311 <input class="menu_setting" type="text" name="name" data-top-menu-id="<?php
1312 echo esc_attr( $menu_id );
1313 ?>" placeholder="<?php
1314 echo esc_attr( $current_menu_item[0] );
1315 ?>" value='<?php
1316 echo esc_attr( $name );
1317 ?>' />
1318 </div>
1319 <div class="column">
1320 <label for="<?php
1321 echo esc_attr( $current_menu_item[2] );
1322 ?>">
1323 <?php
1324 esc_html_e( 'Hidden For Roles or Users', 'adminify' );
1325 ?>
1326 </label>
1327
1328 <div class="select is-small">
1329
1330 <?php
1331 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- generate_user_rules_select_field() returns a trusted <select> template with form inputs that wp_kses_post() would strip; values inside are escaped.
1332 echo $this->generate_user_rules_select_field( $menu_id, $disabled_for );
1333 ?>
1334
1335 </div>
1336 </div>
1337 </div>
1338
1339 <div class="columns">
1340 <!-- <div class="column">
1341 <label for="">
1342 <?php
1343 esc_html_e( 'Change Link', 'adminify' );
1344 ?>
1345 </label>
1346 <input class="menu_setting" name="link" type="url" placeholder="<?php
1347 esc_html_e( 'New link', 'adminify' );
1348 ?>" value="<?php
1349 echo esc_attr( ( $name_attr != ltrim( $link, '#' ) ? $link : '' ) );
1350 ?>" onchange="checkForLinkTarget(this)" >
1351
1352 <label for="external_link-<?php
1353 echo esc_attr( $name_attr );
1354 ?>">
1355 <?php
1356 esc_html_e( 'New Window?', 'adminify' );
1357 ?>
1358 <input class="menu_setting" id="external_link-<?php
1359 echo esc_attr( $name_attr );
1360 ?>" name="external_link" type="checkbox" value="0" <?php
1361 checked( (int) $external_link, 1 );
1362 ?> disabled>
1363
1364 </label>
1365 <script>
1366 function checkForLinkTarget(inputField) {
1367 var checkbox = inputField.closest('.column').querySelector('input[type="checkbox"]');
1368
1369 if (inputField.value.trim() !== "") {
1370 checkbox.disabled = false; // Enable checkbox if input is not empty
1371 } else {
1372 checkbox.disabled = true; // Disable checkbox if input is empty
1373 }
1374 }
1375 </script>
1376 </div> -->
1377
1378 <div class="column">
1379 <label for="">
1380 <?php
1381 esc_html_e( 'Change Link', 'adminify' );
1382 ?>
1383 </label>
1384 <input class="menu_setting" name="link" type="url"
1385 placeholder="<?php
1386 esc_html_e( 'New link', 'adminify' );
1387 ?>"
1388 value="<?php
1389 echo esc_attr( ( $name_attr != ltrim( $link, '#' ) ? $link : '' ) );
1390 ?>"
1391 oninput="checkForLinkTarget(this)">
1392 <div class="new-tab-settings" style="padding-top: 10px;">
1393 <label for="external_link-<?php
1394 echo esc_attr( $name_attr );
1395 ?>" style="display: flex; align-items: center; gap: 8px;">
1396
1397 <input class="menu_setting" id="external_link-<?php
1398 echo esc_attr( $name_attr );
1399 ?>"
1400 name="external_link" type="checkbox" value="1"
1401 <?php
1402 checked( (int) $external_link, 1 );
1403 ?> disabled style="margin-top: 0;" >
1404 <span><?php
1405 esc_html_e( 'New Window?', 'adminify' );
1406 ?></span>
1407 </label>
1408 </div>
1409
1410 <script>
1411 // Function to validate URL
1412 function isValidURL(url) {
1413 // Allow absolute URLs (with http:// or https://)
1414 var absolutePattern = /^(https?:\/\/)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}.*$/;
1415
1416 // Allow relative URLs (starting with "/")
1417 var relativePattern = /^\/[a-zA-Z0-9-_\/]+$/;
1418
1419 return absolutePattern.test(url) || relativePattern.test(url);
1420 }
1421
1422
1423 function checkForLinkTarget(inputField) {
1424 var checkbox = inputField.closest('.column').querySelector('input[type="checkbox"]');
1425
1426 if (isValidURL(inputField.value.trim())) {
1427 checkbox.disabled = false; // Enable if URL is valid
1428 } else {
1429 checkbox.disabled = true; // Disable if invalid
1430 checkbox.checked = false; // Also uncheck if disabled
1431 }
1432 }
1433
1434 // Run on page load
1435 document.addEventListener("DOMContentLoaded", function() {
1436 document.querySelectorAll('.column input[name="link"]').forEach(function(inputField) {
1437 checkForLinkTarget(inputField);
1438 });
1439 });
1440 </script>
1441 </div>
1442
1443 <div class="column">
1444 <label for="">
1445 <?php
1446 esc_html_e( 'Set Custom Icon', 'adminify' );
1447 ?>
1448 </label>
1449 <div class="icon-picker-wrap wp-adminify-menu-icon-picker adminify-icon-picker-input icon-select-button is-clickable is-pulled-left">
1450 <ul class="icon-picker">
1451 <li class="icon-none" title="None"><i class="dashicons dashicons-dismiss"></i></li>
1452 <li class="select-icon <?php
1453 echo ( !empty( $icon ) && preg_match( '/http(s?)\\:\\/\\//i', $icon ) || empty( $icon ) && empty( $icons[$default_icons] ) ? 'custom-icon' : '' );
1454 ?>" title="Icon Library">
1455 <?php
1456 if ( !empty( $icon ) ) {
1457 if ( preg_match( '/http(s?)\\:\\/\\//i', $icon ) ) {
1458 $image = explode( ',', $icon );
1459 echo '<i class=""><img width="24" height="24" src=' . esc_url( $image[1] ) . ' ></i>';
1460 } else {
1461 ?>
1462 <i class="<?php
1463 echo esc_attr( $this->get_icon( esc_attr( $icon ), '' ) );
1464 ?>"></i>
1465 <?php
1466 }
1467 } else {
1468 $adminify_icon = WP_ADMINIFY_ASSETS_IMAGE . 'logos/menu-icon.svg';
1469 if ( empty( $icons[$default_icons] ) ) {
1470 echo '<i class=""><img width="24" height="24" src=' . esc_url( $adminify_icon ) . ' ></i>';
1471 } else {
1472 ?>
1473 <i class="<?php
1474 echo wp_kses_post( $this->get_icon( esc_attr( $icon ), $icons[$default_icons] ) );
1475 ?>"></i>
1476 <?php
1477 }
1478 }
1479 ?>
1480
1481 </li>
1482 <input type="hidden" class="menu_setting" name="icon" value="<?php
1483 echo esc_attr( $icon );
1484 ?>">
1485 </ul>
1486 </div>
1487 </div>
1488 </div>
1489 <div class='columns'>
1490 <?php
1491 $upgrade_pro = '';
1492 $separator_name_attr = '';
1493 $upgrade_pro = 'upgrade-pro';
1494 $separator_name_attr = Utils::adminify_upgrade_pro( 'Add Separator' );
1495 ?>
1496
1497 <div class='column <?php
1498 echo esc_attr( $upgrade_pro );
1499 ?>'>
1500 <label for="seperator-<?php
1501 echo esc_attr( $name_attr );
1502 ?>">
1503 <?php
1504 $separator_content = apply_filters( 'adminify/menu_editor/add_separator', $separator_name_attr, $separator );
1505 // Apply the filter
1506 echo wp_kses_post( $separator_content || "" );
1507 ?>
1508 </label>
1509 </div>
1510 </div>
1511 </div>
1512 <?php
1513 if ( strpos( $current_menu_item[5], 'adminify-custom-menu-' ) !== false ) {
1514 ?>
1515 <div class="remove-add-new-menu"><span data-id="<?php
1516 echo esc_attr( $current_menu_item[5] );
1517 ?>"><i class="icon-close"></i> Delete</span></div>
1518 <?php
1519 }
1520 ?>
1521 </div>
1522 <div id="tab-<?php
1523 echo esc_attr( $menu_id );
1524 ?>-2" class="tab-pane tab-pane--submenu">
1525 <?php
1526 // Sub Menu Items Check
1527 $link = $current_menu_item[2];
1528 if ( isset( $master_sub_menu[$name_attr] ) && is_array( $master_sub_menu[$name_attr] ) ) {
1529 foreach ( $master_sub_menu[$name_attr] as $sub_menu_item ) {
1530 $this->build_sub_menu_item( $sub_menu_item, $optiongroup, $name_attr );
1531 }
1532 } else {
1533 ?>
1534 <span><?php
1535 esc_html_e( 'No sub menu items', 'adminify' );
1536 ?></span>
1537 <?php
1538 }
1539 $this->render_add_new_menu_item( true );
1540 // true for submenu item
1541 ?>
1542
1543 </div>
1544 </div>
1545
1546 </div>
1547 </div>
1548
1549 <?php
1550 }
1551
1552 public function render_menu_separator( $current_menu_item ) {
1553 $disabled_for = [];
1554 $name = '';
1555 $menu_id = preg_replace( '/[^A-Za-z0-9 ]/', '', $current_menu_item[2] );
1556 $menu_options = $this->menu_settings;
1557 if ( is_array( $menu_options ) ) {
1558 if ( isset( $menu_options[$current_menu_item[2]] ) ) {
1559 $optiongroup = $menu_options[$current_menu_item[2]];
1560 if ( isset( $optiongroup['name'] ) ) {
1561 $name = $optiongroup['name'];
1562 }
1563 if ( isset( $optiongroup['hidden_for'] ) ) {
1564 $disabled_for = $optiongroup['hidden_for'];
1565 }
1566 }
1567 }
1568 if ( !is_array( $disabled_for ) ) {
1569 $disabled_for = [];
1570 }
1571 ?>
1572 <div class="accordion adminify_menu_item" name="<?php
1573 echo esc_attr( $current_menu_item[2] );
1574 ?>" id="<?php
1575 echo esc_attr( $menu_id );
1576 ?>">
1577 <input type="number" class="top_level_order" value="" style="display:none;">
1578 <a class="menu-editor-title accordion-button p-4" href="#">
1579 <svg class="drag-icon is-pulled-left mr-2" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1580 <path d="M12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14Z" fill="#4E4B66" fill-opacity="0.72" />
1581 <path d="M12 7C13.1046 7 14 6.10457 14 5C14 3.89543 13.1046 3 12 3C10.8954 3 10 3.89543 10 5C10 6.10457 10.8954 7 12 7Z" fill="#4E4B66" fill-opacity="0.72" />
1582 <path d="M12 21C13.1046 21 14 20.1046 14 19C14 17.8954 13.1046 17 12 17C10.8954 17 10 17.8954 10 19C10 20.1046 10.8954 21 12 21Z" fill="#4E4B66" fill-opacity="0.72" />
1583 <path d="M5 14C6.10457 14 7 13.1046 7 12C7 10.8954 6.10457 10 5 10C3.89543 10 3 10.8954 3 12C3 13.1046 3.89543 14 5 14Z" fill="#4E4B66" fill-opacity="0.72" />
1584 <path d="M5 7C6.10457 7 7 6.10457 7 5C7 3.89543 6.10457 3 5 3C3.89543 3 3 3.89543 3 5C3 6.10457 3.89543 7 5 7Z" fill="#4E4B66" fill-opacity="0.72" />
1585 <path d="M5 21C6.10457 21 7 20.1046 7 19C7 17.8954 6.10457 17 5 17C3.89543 17 3 17.8954 3 19C3 20.1046 3.89543 21 5 21Z" fill="#4E4B66" fill-opacity="0.72" />
1586 <path d="M19 14C20.1046 14 21 13.1046 21 12C21 10.8954 20.1046 10 19 10C17.8954 10 17 10.8954 17 12C17 13.1046 17.8954 14 19 14Z" fill="#4E4B66" fill-opacity="0.72" />
1587 <path d="M19 7C20.1046 7 21 6.10457 21 5C21 3.89543 20.1046 3 19 3C17.8954 3 17 3.89543 17 5C17 6.10457 17.8954 7 19 7Z" fill="#4E4B66" fill-opacity="0.72" />
1588 <path d="M19 21C20.1046 21 21 20.1046 21 19C21 17.8954 20.1046 17 19 17C17.8954 17 17 17.8954 17 19C17 20.1046 17.8954 21 19 21Z" fill="#4E4B66" fill-opacity="0.72" />
1589 </svg>
1590 <?php
1591 esc_html_e( 'Separator', 'adminify' );
1592 ?>
1593 </a>
1594
1595 <div class="accordion-body adminify_top_level_settings">
1596 <div class="tab-content tab-panel panel p-4">
1597 <div class="menu-editor-form">
1598 <div class="columns">
1599 <div class="column">
1600 <label for=""><?php
1601 esc_html_e( 'Rename as', 'adminify' );
1602 ?></label>
1603 <input class="menu_setting" type="text" name="name" placeholder="<?php
1604 esc_html_e( 'New Name', 'adminify' );
1605 ?>" value="<?php
1606 echo esc_attr( $name );
1607 ?>">
1608 </div>
1609 <div class="column">
1610 <label for=""><?php
1611 esc_html_e( 'Hidden For Roles or Users', 'adminify' );
1612 ?></label>
1613
1614 <div class="select is-small">
1615 <?php
1616 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- generate_user_rules_select_field() returns a trusted <select> template with form inputs that wp_kses_post() would strip; values inside are escaped.
1617 echo $this->generate_user_rules_select_field( $menu_id, $disabled_for );
1618 ?>
1619 </div>
1620 </div>
1621 </div>
1622 </div>
1623
1624 </div>
1625 </div>
1626 </div>
1627
1628 <?php
1629 }
1630
1631 public function build_sub_menu_item( $current_menu_item, $optiongroup, $name_attr ) {
1632 $name = '';
1633 $link = '';
1634 $icon = '';
1635 $external_link = '';
1636 $disabled_for = [];
1637 $suboptiongroup = [];
1638 $menu_options = $this->menu_settings;
1639 if ( isset( $optiongroup['submenu'] ) ) {
1640 if ( isset( $optiongroup['submenu'][$current_menu_item[2]] ) ) {
1641 $suboptiongroup = $optiongroup['submenu'][$current_menu_item[2]];
1642 if ( isset( $suboptiongroup['name'] ) ) {
1643 $name = $suboptiongroup['name'];
1644 }
1645 if ( isset( $suboptiongroup['link'] ) ) {
1646 $link = $suboptiongroup['link'];
1647 }
1648 if ( isset( $suboptiongroup['external_link'] ) ) {
1649 $external_link = $suboptiongroup['external_link'];
1650 }
1651 if ( isset( $suboptiongroup['icon'] ) ) {
1652 $icon = $suboptiongroup['icon'];
1653 }
1654 if ( isset( $suboptiongroup['hidden_for'] ) ) {
1655 $disabled_for = $suboptiongroup['hidden_for'];
1656 }
1657 }
1658 }
1659 $sub_menu_name_attr = $current_menu_item[2];
1660 if ( isset( $current_menu_item['key'] ) ) {
1661 $sub_menu_name_attr = $current_menu_item['key'];
1662 }
1663 if ( strpos( $sub_menu_name_attr, 'adminify-custom-submenu-' ) !== false ) {
1664 $name = $current_menu_item[0];
1665 $link = $current_menu_item[2];
1666 if ( isset( $optiongroup['submenu'][$sub_menu_name_attr]['hidden_for'] ) ) {
1667 $disabled_for = $optiongroup['submenu'][$sub_menu_name_attr]['hidden_for'];
1668 }
1669 if ( isset( $optiongroup['submenu'][$sub_menu_name_attr]['icon'] ) ) {
1670 $icon = $optiongroup['submenu'][$sub_menu_name_attr]['icon'];
1671 }
1672 if ( isset( $optiongroup['submenu'][$sub_menu_name_attr]['external_link'] ) ) {
1673 $external_link = $optiongroup['submenu'][$sub_menu_name_attr]['external_link'];
1674 }
1675 }
1676 if ( !is_array( $disabled_for ) ) {
1677 $disabled_for = [];
1678 }
1679 $menu_id = preg_replace( '/[^A-Za-z0-9 ]/', '', $sub_menu_name_attr );
1680 ?>
1681 <div class="accordion adminify_sub_menu_item" name="<?php
1682 echo esc_attr( $sub_menu_name_attr );
1683 ?>" id="wp-adminify-sub-menu-<?php
1684 echo esc_attr( $menu_id );
1685 ?>">
1686 <input type="number" class="top_level_order" value="" style="display:none;">
1687 <a class="menu-editor-title accordion-button adminify-flex adminify-flex-center adminify-gap-2" href="#">
1688 <svg class="drag-icon is-pulled-left mr-2" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1689 <path d="M12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14Z" fill="#4E4B66" fill-opacity="0.72" />
1690 <path d="M12 7C13.1046 7 14 6.10457 14 5C14 3.89543 13.1046 3 12 3C10.8954 3 10 3.89543 10 5C10 6.10457 10.8954 7 12 7Z" fill="#4E4B66" fill-opacity="0.72" />
1691 <path d="M12 21C13.1046 21 14 20.1046 14 19C14 17.8954 13.1046 17 12 17C10.8954 17 10 17.8954 10 19C10 20.1046 10.8954 21 12 21Z" fill="#4E4B66" fill-opacity="0.72" />
1692 <path d="M5 14C6.10457 14 7 13.1046 7 12C7 10.8954 6.10457 10 5 10C3.89543 10 3 10.8954 3 12C3 13.1046 3.89543 14 5 14Z" fill="#4E4B66" fill-opacity="0.72" />
1693 <path d="M5 7C6.10457 7 7 6.10457 7 5C7 3.89543 6.10457 3 5 3C3.89543 3 3 3.89543 3 5C3 6.10457 3.89543 7 5 7Z" fill="#4E4B66" fill-opacity="0.72" />
1694 <path d="M5 21C6.10457 21 7 20.1046 7 19C7 17.8954 6.10457 17 5 17C3.89543 17 3 17.8954 3 19C3 20.1046 3.89543 21 5 21Z" fill="#4E4B66" fill-opacity="0.72" />
1695 <path d="M19 14C20.1046 14 21 13.1046 21 12C21 10.8954 20.1046 10 19 10C17.8954 10 17 10.8954 17 12C17 13.1046 17.8954 14 19 14Z" fill="#4E4B66" fill-opacity="0.72" />
1696 <path d="M19 7C20.1046 7 21 6.10457 21 5C21 3.89543 20.1046 3 19 3C17.8954 3 17 3.89543 17 5C17 6.10457 17.8954 7 19 7Z" fill="#4E4B66" fill-opacity="0.72" />
1697 <path d="M19 21C20.1046 21 21 20.1046 21 19C21 17.8954 20.1046 17 19 17C17.8954 17 17 17.8954 17 19C17 20.1046 17.8954 21 19 21Z" fill="#4E4B66" fill-opacity="0.72" />
1698 </svg>
1699 <?php
1700 if ( !empty( $current_menu_item[0] ) ) {
1701 echo wp_kses_post( preg_replace( '/\\<span.*?>.*?\\<\\/span><\\/span>/s', '', $current_menu_item[0] ) );
1702 }
1703 ?>
1704 </a>
1705
1706 <div class="accordion-body">
1707 <div class="tab-content tab-panel panel p-4">
1708 <div class="tab-pane">
1709 <div class="menu-editor-form">
1710 <div class="columns">
1711 <div class="column">
1712 <label for=""><?php
1713 esc_html_e( 'Rename as', 'adminify' );
1714 ?></label>
1715 <input class="sub_menu_setting" type="text" data-sub-menu-id="<?php
1716 echo esc_attr( $menu_id );
1717 ?>" name="name" placeholder="<?php
1718 esc_html_e( 'New Menu name...', 'adminify' );
1719 ?>" value="<?php
1720 echo esc_attr( $name );
1721 ?>">
1722 </div>
1723 <div class="column">
1724 <label for=""><?php
1725 esc_html_e( 'Hidden For Roles or Users', 'adminify' );
1726 ?></label>
1727
1728 <div class="select is-small">
1729 <?php
1730 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- generate_user_rules_select_field() returns a trusted <select> template with form inputs that wp_kses_post() would strip; values inside are escaped.
1731 echo $this->generate_user_rules_select_field( $menu_id, $disabled_for, 'sub_menu' );
1732 ?>
1733 </div>
1734 </div>
1735 </div>
1736 <div class="columns">
1737 <div class="column">
1738 <label for=""><?php
1739 esc_html_e( 'Change Link', 'adminify' );
1740 ?></label>
1741 <input class="sub_menu_setting" name="link" type="url" placeholder="New link" value="<?php
1742 echo esc_attr( ( $sub_menu_name_attr != ltrim( $link, '#' ) ? $link : '' ) );
1743 ?>" onchange="checkForLinkTarget(this)" >
1744
1745 <label for="external_link-<?php
1746 echo esc_attr( $sub_menu_name_attr );
1747 ?>">
1748 <?php
1749 esc_html_e( 'New Window?', 'adminify' );
1750 ?>
1751 <input class="sub_menu_setting" id="external_link-<?php
1752 echo esc_attr( $sub_menu_name_attr );
1753 ?>" name="external_link" type="checkbox" value="0" <?php
1754 checked( (int) $external_link, 1 );
1755 ?>disabled />
1756
1757 </label>
1758 </div>
1759 <div class="column">
1760 <label for="" style="margin-top:25px">
1761 <?php
1762 esc_html_e( 'Custom Icon is not allowed for Submenu', 'adminify' );
1763 ?>
1764 </label>
1765 </div>
1766 </div>
1767 </div>
1768 <?php
1769 if ( strpos( $sub_menu_name_attr, 'adminify-custom-submenu-' ) !== false ) {
1770 ?>
1771 <div class="remove-add-new-menu"><span data-id="<?php
1772 echo esc_attr( $sub_menu_name_attr );
1773 ?>"><i class="icon-close"></i> Delete</span></div>
1774 <?php
1775 }
1776 ?>
1777 </div>
1778 </div>
1779 </div>
1780 </div>
1781
1782 <?php
1783 }
1784
1785 /**
1786 * Add New Menu Item.
1787 */
1788 public function render_add_new_menu_item( $submenu = false ) {
1789 $add_item = apply_filters( 'adminify/menu_editor', [
1790 'upgrade_pro' => Utils::adminify_upgrade_pro( ' ' ),
1791 'upgrade_class' => 'upgrade-pro',
1792 ] );
1793 ?>
1794 <div class="adminify-accordion adminify-add-new-menu-editor-item upgrade-pro adminify-field adminify-field-switcher adminify-depend-visible adminify-depend-on adminify-pro-notice <?php
1795 echo esc_attr( ( $submenu ? 'submenu' : '' ) );
1796 ?> <?php
1797 echo Utils::wp_kses_custom( $add_item['upgrade_class'] );
1798 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_kses_custom() is a wp_kses() wrapper; output already escaped.
1799 ?>">
1800 <div class="inner-text">
1801 <i class="dashicons dashicons-plus-alt"></i>
1802 <span class="title"><?php
1803 esc_html_e( 'Add Item', 'adminify' );
1804 ?></span>
1805 </div>
1806 <?php
1807 echo Utils::wp_kses_custom( $add_item['upgrade_pro'] );
1808 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_kses_custom() is a wp_kses() wrapper; output already escaped.
1809 ?>
1810 </div>
1811 <?php
1812 }
1813
1814 /**
1815 * Menu Editor Header
1816 *
1817 * @return void
1818 */
1819 public static function render_menu_editor_header() {
1820 ?>
1821
1822 <div class="adminify-flex adminify-flex-center adminify-justify-between">
1823 <div class="adminify-menu-editor-help-urls adminify-flex adminify-flex-center adminify-gap-2">
1824 <?php
1825 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- adminfiy_help_urls() returns a trusted template containing inline SVG icons that wp_kses_post() would strip; URLs inside are passed through esc_url().
1826 echo Utils::adminfiy_help_urls(
1827 __( 'Menu Editor', 'adminify' ),
1828 'https://wpadminify.com/kb/wordpress-dashboard-menu-editor/',
1829 'https://www.youtube.com/playlist?list=PLqpMw0NsHXV-EKj9Xm1DMGa6FGniHHly8',
1830 'https://www.facebook.com/groups/jeweltheme',
1831 esc_url( \WPAdminify\Inc\Admin\AdminSettings::support_url() )
1832 );
1833 ?>
1834 </div>
1835
1836
1837 <div class="wp-adminify--page--title--actions adminify-flex adminify-flex-center adminify-gap-2">
1838
1839 <button class="adminify-btn adminify-btn-outline-primary adminify_menu_save_settings">
1840 <?php
1841 esc_html_e( 'Save', 'adminify' );
1842 ?>
1843 </button>
1844
1845 <div class="adminify-dropdown">
1846 <div class="adminify-dropdown-trigger">
1847 <button class="adminify-btn adminify-btn-outline-primary" aria-haspopup="true" aria-controls="dropdown-menu">
1848 <svg class="icon" width="16" height="12" viewBox="0 0 16 12" fill="none" xmlns="http://www.w3.org/2000/svg">
1849 <path d="M5 12C3.63144 12.0007 2.43589 11.0751 2.09375 9.75H0.5V8.25H2.0945C2.48423 6.74059 3.96509 5.78119 5.50196 6.04243C7.03883 6.30366 8.11953 7.69847 7.98865 9.25188C7.85776 10.8053 6.55892 11.9996 5 12ZM5 7.5C4.18055 7.50083 3.51342 8.15914 3.50167 8.97851C3.48993 9.79788 4.13792 10.475 4.95702 10.4993C5.77611 10.5237 6.46312 9.88613 6.5 9.0675V9.3675V9C6.5 8.17158 5.82843 7.5 5 7.5ZM15.5 9.75H8.75V8.25H15.5V9.75ZM8.75 6C7.38172 6.00035 6.18657 5.07483 5.8445 3.75H0.5V2.25H5.8445C6.23423 0.740588 7.71509 -0.218809 9.25196 0.0424253C10.7888 0.30366 11.8695 1.69847 11.7386 3.25188C11.6078 4.80529 10.3089 5.99961 8.75 6ZM8.75 1.5C7.93055 1.50083 7.26342 2.15914 7.25167 2.97851C7.23993 3.79788 7.88792 4.47503 8.70702 4.49934C9.52611 4.52365 10.2131 3.88613 10.25 3.0675V3.3675V3C10.25 2.17158 9.57843 1.5 8.75 1.5ZM15.5 3.75H12.5V2.25H15.5V3.75Z" fill="#0347FF" />
1850 </svg>
1851 </button>
1852 </div>
1853 <div class="adminify-dropdown-menu" id="dropdown-menu" role="menu">
1854 <div class="adminify-dropdown-content adminify-flex adminify-flex-col adminify-gap-2">
1855 <a href="#" class="adminify-dropdown-item adminify_export_menu_settings">
1856 <?php
1857 esc_html_e( 'Export menu', 'adminify' );
1858 ?>
1859 </a>
1860 <input accept=".json" type="file" single="" id="adminify_import_menu" class="hidden">
1861 <a href="#" class="adminify-dropdown-item adminify_import_menu_settings">
1862 <?php
1863 esc_html_e( 'Import menu', 'adminify' );
1864 ?>
1865 </a>
1866 <a href="#" class="adminify-dropdown-item adminify_reset_menu_settings">
1867 <?php
1868 esc_html_e( 'Reset menu', 'adminify' );
1869 ?>
1870 </a>
1871 </div>
1872 </div>
1873 </div>
1874 </div>
1875 </div>
1876
1877 <div class="adminify-text-wrap">
1878 <p><?php
1879 esc_html_e( 'Edit each menu item\'s name, link, icon and visibility. Drag and drop to rearange the menu. Changes will take effect after page refresh.', 'adminify' );
1880 ?></p>
1881 <p class="adminify-flex adminify-flex-center adminify-gap-1">
1882 <svg class="" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
1883 <path d="M7.33398 7.32002C7.33398 7.14321 7.40422 6.97364 7.52925 6.84861C7.65427 6.72359 7.82384 6.65335 8.00065 6.65335C8.17746 6.65335 8.34703 6.72359 8.47206 6.84861C8.59708 6.97364 8.66732 7.14321 8.66732 7.32002V11.32C8.66732 11.4968 8.59708 11.6664 8.47206 11.7914C8.34703 11.9164 8.17746 11.9867 8.00065 11.9867C7.82384 11.9867 7.65427 11.9164 7.52925 11.7914C7.40422 11.6664 7.33398 11.4968 7.33398 11.32V7.32002Z" fill="#4E4B66" />
1884 <path d="M8.00065 4.034C7.82384 4.034 7.65427 4.10423 7.52925 4.22926C7.40422 4.35428 7.33398 4.52385 7.33398 4.70066C7.33398 4.87747 7.40422 5.04704 7.52925 5.17207C7.65427 5.29709 7.82384 5.36733 8.00065 5.36733C8.17746 5.36733 8.34703 5.29709 8.47206 5.17207C8.59708 5.04704 8.66732 4.87747 8.66732 4.70066C8.66732 4.52385 8.59708 4.35428 8.47206 4.22926C8.34703 4.10423 8.17746 4.034 8.00065 4.034Z" fill="#4E4B66" />
1885 <path fill-rule="evenodd" clip-rule="evenodd" d="M8.00065 1.33334C4.31865 1.33334 1.33398 4.31801 1.33398 8.00001C1.33398 11.682 4.31865 14.6667 8.00065 14.6667C11.6827 14.6667 14.6673 11.682 14.6673 8.00001C14.6673 4.31801 11.6827 1.33334 8.00065 1.33334ZM2.66732 8.00001C2.66732 9.4145 3.22922 10.7711 4.22942 11.7712C5.22961 12.7714 6.58616 13.3333 8.00065 13.3333C9.41514 13.3333 10.7717 12.7714 11.7719 11.7712C12.7721 10.7711 13.334 9.4145 13.334 8.00001C13.334 6.58552 12.7721 5.22897 11.7719 4.22877C10.7717 3.22858 9.41514 2.66668 8.00065 2.66668C6.58616 2.66668 5.22961 3.22858 4.22942 4.22877C3.22922 5.22897 2.66732 6.58552 2.66732 8.00001V8.00001Z" fill="#4E4B66" />
1886 </svg>
1887
1888 <?php
1889 esc_html_e( 'If you have Adminify Menu Module disabled, icons and label dividers won\'t change.', 'adminify' );
1890 ?>
1891
1892 </p>
1893 </div>
1894
1895
1896 <?php
1897 }
1898
1899 public function jltwp_adminify_menu_editor_contents() {
1900 ?>
1901
1902 <div class="wrap">
1903 <div class="wp-adminify--menu--editor--container">
1904
1905 <!-- <div id="adminify-data-saved-message"></div> -->
1906
1907 <?php
1908 //self::render_menu_editor_header();
1909 ?>
1910
1911 <div class="wp-adminify--menu--editor--settings adminify-flex adminify-flex-col adminify-gap-4">
1912 <div class="wp-adminify-menu-editor-loader"></div>
1913 <?php
1914 $this->render_menu_editor();
1915 ?>
1916 </div>
1917
1918 </div>
1919 </div>
1920 <a href="#" id="adminify_download_settings" style="display: none;" ?></a>
1921 <?php
1922 }
1923
1924 }
1925
1926 }