PluginProbe
Adminify – White Label, Admin Menu Editor, Login Customizer / 4.0
Adminify – White Label, Admin Menu Editor, Login Customizer v4.0
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
← All changes | Inc/Modules/MenuEditor/MenuEditor.php +219 -534 4.1.174.0 View file →
@@ -5,9 +5,8 @@
5 5 use WPAdminify\Inc\Utils;
6 6 use WPAdminify\Inc\Admin\AdminSettings;
7 7 use WPAdminify\Inc\Modules\MenuEditor\MenuEditorAssets;
8 8 use WPAdminify\Inc\Admin\AdminSettingsModel;
9 -use enshrined\svgSanitize\Sanitizer;
10 9 // no direct access allowed
11 10 if ( !defined( 'ABSPATH' ) ) {
12 11 exit;
13 12 }
@@ -46,17 +45,12 @@
46 45 public function __construct() {
47 46 $this->menu_settings = ( new MenuEditorOptions() )->get();
48 47 $this->options = (array) AdminSettings::get_instance()->get();
49 48 add_filter( 'upload_mimes', [$this, 'custom_icon_mime_types'] );
50 - add_filter( 'wp_handle_upload_prefilter', [$this, 'sanitize_svg_file'] );
49 + // add_action('admin_menu', [$this, 'jltwp_adminify_menu_editor_submenu'], 51);
51 50 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 - }
51 + add_filter( 'parent_file', [$this, 'set_menu'], 800 );
52 + add_filter( 'parent_file', [$this, 'apply_menu'], 900 );
59 53 add_action( 'wp_ajax_adminify_save_menu_settings', [$this, 'adminify_save_menu_settings'] );
60 54 add_action( 'wp_ajax_adminify_reset_menu_settings', [$this, 'adminify_reset_menu_settings'] );
61 55 add_action( 'wp_ajax_adminify_export_menu_settings', [$this, 'adminify_export_menu_settings'] );
62 56 add_action( 'wp_ajax_adminify_import_menu_settings', [$this, 'adminify_import_menu_settings'] );
@@ -61,45 +55,16 @@
61 55 add_action( 'wp_ajax_adminify_export_menu_settings', [$this, 'adminify_export_menu_settings'] );
62 56 add_action( 'wp_ajax_adminify_import_menu_settings', [$this, 'adminify_import_menu_settings'] );
63 57 add_action( 'wp_ajax_adminify_file_upload', [$this, 'adminify_file_upload_callback'] );
64 58 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 59 new MenuEditorAssets();
67 60 }
68 61
69 62 public function custom_icon_mime_types( $mimes ) {
70 - if ( current_user_can( 'administrator' ) ) {
71 - $mimes['svg'] = 'image/svg+xml';
72 - }
63 + $mimes['svg'] = 'image/svg+xml';
73 64 return $mimes;
74 65 }
75 66
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 67 public function filter_attachment( $value ) {
103 68 // return $value->post_title == 'adminify-custom-icon';
104 69 return strpos( $value->guid, 'adminify-custom-icon' ) !== false;
105 70 }
@@ -104,15 +69,8 @@
104 69 return strpos( $value->guid, 'adminify-custom-icon' ) !== false;
105 70 }
106 71
107 72 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 73 $result['images'] = null;
116 74 $query = get_posts( [
117 75 'post_type' => 'attachment',
118 76 'numberposts' => -1,
@@ -127,13 +85,8 @@
127 85
128 86 public function adminify_file_upload_callback() {
129 87 $result['status'] = false;
130 88 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 89 $upload_dir = wp_upload_dir();
137 90 $targeted_dir = $upload_dir['basedir'] . '/adminify-custom-icons';
138 91 if ( !is_dir( $targeted_dir ) ) {
139 92 wp_mkdir_p( $targeted_dir );
@@ -182,73 +135,8 @@
182 135 'error' => $dir_data['error'],
183 136 ];
184 137 }
185 138
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 139 // Menu Editor Body Class
252 140 public function jltwp_adminify_menu_editor_body_class( $classes ) {
253 141 $classes .= ' adminify_menu_editor ';
254 142 return $classes;
@@ -265,13 +153,13 @@
265 153 foreach ( $values as $index => $in ) {
266 154 if ( is_array( $in ) ) {
267 155 $values[$index] = $this->clean_ajax_input( $in );
268 156 } else {
269 - $values[$index] = wp_strip_all_tags( $in );
157 + $values[$index] = strip_tags( $in );
270 158 }
271 159 }
272 160 } else {
273 - $values = wp_strip_all_tags( $values );
161 + $values = strip_tags( $values );
274 162 }
275 163 return $values;
276 164 }
277 165
@@ -289,18 +177,12 @@
289 177 }
290 178
291 179 public function adminify_save_menu_settings() {
292 180 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 181 $options = wp_kses_post_deep( wp_unslash( $_POST['options'] ) );
299 182 $options = $this->clean_ajax_input( $options );
300 183 if ( $options == '' || !is_array( $options ) ) {
301 184 $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 185 echo Utils::wp_kses_custom( $this->ajax_error_message( $message ) );
304 186 die;
305 187 }
306 188 if ( is_array( $options ) ) {
@@ -311,9 +193,8 @@
311 193 echo json_encode( $returndata );
312 194 die;
313 195 } else {
314 196 $message = __( 'Something went wrong', 'adminify' );
315 - // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_kses_custom() is a wp_kses() wrapper; output already escaped.
316 197 echo Utils::wp_kses_custom( $this->ajax_error_message( $message ) );
317 198 die;
318 199 }
319 200 }
@@ -326,13 +207,8 @@
326 207 * @return void
327 208 */
328 209 public function adminify_reset_menu_settings() {
329 210 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 211 update_option( $this->prefix, [] );
336 212 $menu_editor_options = get_option( $this->prefix );
337 213 if ( !$menu_editor_options ) {
338 214 $returndata = [];
@@ -341,9 +217,8 @@
341 217 echo json_encode( $returndata );
342 218 die;
343 219 } else {
344 220 $message = __( 'Something went wrong', 'adminify' );
345 - // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_kses_custom() is a wp_kses() wrapper; output already escaped.
346 221 echo Utils::wp_kses_custom( $this->ajax_error_message( $message ) );
347 222 die;
348 223 }
349 224 }
@@ -356,13 +231,8 @@
356 231 * @return void
357 232 */
358 233 public function adminify_export_menu_settings() {
359 234 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 235 $menu_editor_options = get_option( $this->prefix );
366 236 echo json_encode( $menu_editor_options );
367 237 }
368 238 die;
@@ -374,17 +244,11 @@
374 244 * @since 1.0.0
375 245 */
376 246 public function adminify_import_menu_settings() {
377 247 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 248 $new_options = wp_kses_post_deep( $_POST['settings'] );
384 249 if ( $new_options == '' || !is_array( $new_options ) ) {
385 250 $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 251 echo Utils::wp_kses_custom( $this->ajax_error_message( $message ) );
388 252 die;
389 253 }
390 254 if ( is_array( $new_options ) ) {
@@ -395,9 +259,8 @@
395 259 echo json_encode( $returndata );
396 260 die;
397 261 } else {
398 262 $message = __( 'Something went wrong', 'adminify' );
399 - // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_kses_custom() is a wp_kses() wrapper; output already escaped.
400 263 echo Utils::wp_kses_custom( $this->ajax_error_message( $message ) );
401 264 die;
402 265 }
403 266 }
@@ -404,37 +267,8 @@
404 267 die;
405 268 }
406 269
407 270 /**
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 271 * Get menu items
438 272 *
439 273 * @param [type] $parent_file
440 274 *
@@ -453,21 +287,12 @@
453 287 public function sort_menu_settings( $thismenu ) {
454 288 $menu_settings = $this->menu_settings;
455 289 $tempmenu = [];
456 290 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 291 $next_menu_item = next( $thismenu );
466 292 $optiongroup = [];
467 293 $order = $key;
468 294 $separator = 0;
469 - $external_link = 0;
470 295 $icon = null;
471 296 $hidden_for = [];
472 297 if ( !empty( $next_menu_item ) && strpos( $next_menu_item[2], 'separator' ) !== false ) {
473 298 $separator = 1;
@@ -472,18 +297,10 @@
472 297 if ( !empty( $next_menu_item ) && strpos( $next_menu_item[2], 'separator' ) !== false ) {
473 298 $separator = 1;
474 299 }
475 300 if ( is_array( $menu_settings ) ) {
476 - // Direct slug match first, then fallback for dynamic-slug plugins (e.g. Yoast SEO)
477 301 if ( isset( $menu_settings[$current_menu_item[2]] ) ) {
478 302 $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 303 if ( isset( $optiongroup['order'] ) ) {
487 304 $order = $optiongroup['order'];
488 305 }
489 306 if ( isset( $optiongroup['separator'] ) ) {
@@ -488,11 +305,8 @@
488 305 }
489 306 if ( isset( $optiongroup['separator'] ) ) {
490 307 $separator = $optiongroup['separator'];
491 308 }
492 - if ( isset( $optiongroup['external_link'] ) ) {
493 - $external_link = $optiongroup['external_link'];
494 - }
495 309 if ( !empty( $optiongroup['icon'] ) ) {
496 310 $icon = $optiongroup['icon'];
497 311 }
498 312 if ( !empty( $optiongroup['hidden_for'] ) ) {
@@ -500,29 +314,27 @@
500 314 }
501 315 }
502 316 }
503 317 $current_menu_item['order'] = $order;
504 - $current_menu_item['hidden_for'] = $hidden_for;
505 318 $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];
319 + if ( empty( $this->options['admin_ui'] ) ) {
320 + if ( $icon !== null ) {
321 + if ( strpos( $icon, 'dashicons ' ) !== false ) {
322 + $menu_icon = str_replace( 'dashicons ', '', $icon );
323 + $current_menu_item[6] = $menu_icon;
515 324 } else {
516 - $menu_icon = 'dashicons-adminify- ' . $icon;
325 + if ( strpos( $icon, ',' ) !== false ) {
326 + $menu_icon = explode( ',', $icon )[1];
327 + } else {
328 + $menu_icon = 'dashicons-adminify- ' . $icon;
329 + }
330 + $current_menu_item[6] = $menu_icon;
517 331 }
518 - $current_menu_item[6] = $menu_icon;
519 332 }
333 + if ( $separator == 1 ) {
334 + $current_menu_item[4] = $current_menu_item[4] . ' adminify-menu-separator';
335 + }
520 336 }
521 - if ( $separator == 1 ) {
522 - $current_menu_item[4] = $current_menu_item[4] . ' adminify-menu-separator';
523 - }
524 - // }
525 337 array_push( $tempmenu, $current_menu_item );
526 338 if ( isset( $menu_settings[$current_menu_item[2]] ) ) {
527 339 unset($menu_settings[$current_menu_item[2]]);
528 340 }
@@ -528,22 +340,8 @@
528 340 }
529 341 }
530 342 if ( is_array( $menu_settings ) && !array_key_exists( 0, $menu_settings ) ) {
531 343 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 344 $new_array = [
547 345 $menu_s['name'],
548 346 'read',
549 347 ( !empty( $menu_s['link'] ) ? $menu_s['link'] : '' ),
@@ -552,33 +350,29 @@
552 350 $key,
553 351 ( !empty( $menu_s['icon'] ) ? $menu_s['icon'] : '' ),
554 352 'order' => $menu_s['order'],
555 353 'separator' => ( !empty( $menu_s['separator'] ) ? $menu_s['separator'] : 0 ),
556 - 'external_link' => ( !empty( $menu_s['external_link'] ) ? $menu_s['external_link'] : 0 ),
557 354 'hidden_for' => ( !empty( $menu_s['hidden_for'] ) ? $menu_s['hidden_for'] : [] )
558 355 ];
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';
356 + if ( empty( $this->options['admin_ui'] ) ) {
357 + if ( strpos( $menu_s['icon'], 'dashicons ' ) !== false ) {
358 + $menu_icon = str_replace( 'dashicons ', '', $menu_s['icon'] );
359 + } else {
360 + if ( empty( $menu_s['icon'] ) || strpos( $menu_s['icon'], ',' ) !== false ) {
361 + if ( empty( $menu_s['icon'] ) ) {
362 + $menu_icon = WP_ADMINIFY_ASSETS_IMAGE . 'logos/menu-icon.svg';
363 + } else {
364 + $menu_icon = explode( ',', $menu_s['icon'] )[1];
365 + }
566 366 } else {
567 - $menu_icon = explode( ',', $menu_s['icon'] )[1];
367 + $menu_icon = 'dashicons-adminify- ' . $menu_s['icon'];
568 368 }
569 - } else {
570 - $menu_icon = 'dashicons-adminify- ' . $menu_s['icon'];
571 369 }
370 + if ( $menu_s['separator'] == 1 ) {
371 + $new_array[4] = $new_array[4] . ' adminify-menu-separator';
372 + }
373 + $new_array[6] = $menu_icon;
572 374 }
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 375 array_push( $tempmenu, $new_array );
582 376 }
583 377 }
584 378 return $this->sort_array( $tempmenu );
@@ -690,11 +484,12 @@
690 484 $tempsub = [];
691 485 $submenu = $this->sort_sub_menu_settings( $menu, $submenu );
692 486 if ( $this->menu && is_array( $this->menu ) ) {
693 487 foreach ( $this->menu as $key => $menu_item ) {
694 - if ( empty( $menu_item[2] ) ) {
695 - continue;
696 - }
488 + // if (empty($menu_item[0])) {
489 + // continue;
490 + // }
491 + // if (strpos($menu_item[2], 'separator') !== false && !$menu_item[0]) {
697 492 if ( strpos( $menu_item[2], 'separator' ) !== false && !$menu_item[0] ) {
698 493 // Build Separator
699 494 $newitem = $this->apply_separator_settings( $menu_item, $key );
700 495 if ( $newitem ) {
@@ -704,21 +499,8 @@
704 499 // Build Top Level
705 500 $newitem = $this->apply_top_level_settings( $menu_item, $key );
706 501 if ( $newitem ) {
707 502 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 503 $parent_key = $newitem[2];
722 504 if ( strpos( $newitem[5], 'adminify-custom-menu-' ) !== false ) {
723 505 $parent_key = $newitem[5];
724 506 }
@@ -781,15 +563,12 @@
781 563 $current_menu_item[2] = $link;
782 564 $current_menu_item['link'] = $link;
783 565 }
784 566 }
785 - if ( isset( $optiongroup['external_link'] ) ) {
786 - $external_link = $optiongroup['external_link'];
787 - }
788 567 if ( isset( $optiongroup['hidden_for'] ) ) {
789 568 $disabled_for = $optiongroup['hidden_for'];
790 569 if ( $this->is_hidden( $disabled_for ) ) {
791 - $current_menu_item['hidden_for'] = true;
570 + $current_menu_item['hidden'] = true;
792 571 continue;
793 572 }
794 573 }
795 574 }
@@ -797,13 +576,10 @@
797 576 if ( strpos( $custom_menu, 'adminify-custom-submenu-' ) !== false ) {
798 577 if ( isset( $submenu_settings[$current_menu_item['key']]['hidden_for'] ) ) {
799 578 $disabled_for = $submenu_settings[$current_menu_item['key']]['hidden_for'];
800 579 }
801 - if ( isset( $submenu_settings[$current_menu_item['key']]['external_link'] ) ) {
802 - $external_link = $submenu_settings[$current_menu_item['key']]['external_link'];
803 - }
804 580 if ( $this->is_hidden( $disabled_for ) ) {
805 - $current_menu_item['hidden_for'] = true;
581 + $current_menu_item['hidden'] = true;
806 582 continue;
807 583 }
808 584 }
809 585 array_push( $tempsub, $current_menu_item );
@@ -827,18 +603,10 @@
827 603 $disabled_for = [];
828 604 $optiongroup = [];
829 605 $order = $key;
830 606 if ( is_array( $this->menu_settings ) ) {
831 - // Direct slug match first, then fallback for dynamic-slug plugins (e.g. Yoast SEO)
832 607 if ( isset( $this->menu_settings[$current_menu_item[2]] ) ) {
833 608 $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 609 if ( isset( $optiongroup['name'] ) ) {
842 610 $name = $optiongroup['name'];
843 611 if ( $name != '' ) {
844 612 $current_menu_item[0] = $name;
@@ -850,11 +618,8 @@
850 618 $current_menu_item[2] = $link;
851 619 $current_menu_item['link'] = $link;
852 620 }
853 621 }
854 - if ( isset( $optiongroup['external_link'] ) ) {
855 - $external_link = ( $optiongroup['external_link'] ? $optiongroup['external_link'] : '' );
856 - }
857 622 if ( isset( $optiongroup['icon'] ) ) {
858 623 $icon = $optiongroup['icon'];
859 624 if ( $icon != '' ) {
860 625 $current_menu_item['icon'] = $icon;
@@ -865,39 +630,29 @@
865 630 }
866 631 if ( isset( $optiongroup['hidden_for'] ) ) {
867 632 $disabled_for = $optiongroup['hidden_for'];
868 633 if ( $this->is_hidden( $disabled_for ) ) {
869 - $current_menu_item['hidden_for'] = true;
870 - } else {
871 - $current_menu_item['hidden_for'] = false;
634 + $current_menu_item['hidden'] = true;
872 635 }
873 636 }
874 637 }
875 638 $custom_menu = ( isset( $current_menu_item[5] ) ? $current_menu_item[5] : '' );
876 639 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'] ) ) {
640 + if ( isset( $this->menu_settings[$current_menu_item[5]]['hidden_for'] ) ) {
878 641 $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 642 }
883 - if ( isset( $this->menu_settings[$current_menu_item[5]]['external_link'] ) ) {
884 - $external_link = $this->menu_settings[$current_menu_item[5]]['external_link'];
643 + if ( $this->is_hidden( $disabled_for ) ) {
644 + $current_menu_item['hidden'] = true;
885 645 }
886 646 }
887 647 }
888 648 $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 ) {
649 + if ( isset( $current_menu_item['hidden'] ) ) {
650 + if ( $current_menu_item['hidden'] == true ) {
892 651 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 - }
652 + } else {
653 + return $current_menu_item;
898 654 }
899 - return $current_menu_item;
900 655 } else {
901 656 return $current_menu_item;
902 657 }
903 658 }
@@ -913,64 +668,36 @@
913 668 if ( !is_array( $disabled_for ) ) {
914 669 return false;
915 670 }
916 671 $current_user = wp_get_current_user();
672 + $current_name = $current_user->display_name;
917 673 $current_roles = $current_user->roles;
918 674 $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 ) ) {
675 + if ( in_array( $current_name, $disabled_for ) ) {
932 676 return true;
933 677 }
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 ) ) {
678 + // MULTISITE SUPER ADMIN
679 + if ( is_super_admin() && is_multisite() ) {
680 + if ( in_array( 'Super Admin', $disabled_for ) ) {
942 681 return true;
682 + } else {
683 + return false;
943 684 }
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 685 }
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 ) ) {
686 + // NORMAL SUPER ADMIN
687 + if ( $current_user->ID === 1 ) {
688 + if ( in_array( 'Super Admin', $disabled_for ) ) {
960 689 return true;
690 + } else {
691 + return false;
961 692 }
962 - // Super admin sees everything by default unless explicitly disabled
963 - return false;
964 693 }
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 ) ) {
694 + foreach ( $current_roles as $role ) {
695 + $role_name = $all_roles[$role];
696 + if ( in_array( $role_name, $disabled_for ) ) {
968 697 return true;
969 698 }
970 - return false;
971 699 }
972 - return false;
973 700 }
974 701
975 702 /**
976 703 * Applies separator menu item settings
@@ -996,16 +723,16 @@
996 723 }
997 724 if ( isset( $optiongroup['hidden_for'] ) ) {
998 725 $disabled_for = $optiongroup['hidden_for'];
999 726 if ( $this->is_hidden( $disabled_for ) ) {
1000 - $current_menu_item['hidden_for'] = true;
727 + $current_menu_item['hidden'] = true;
1001 728 }
1002 729 }
1003 730 }
1004 731 }
1005 732 $current_menu_item['order'] = $order;
1006 - if ( isset( $current_menu_item['hidden_for'] ) ) {
1007 - if ( $current_menu_item['hidden_for'] == true ) {
733 + if ( isset( $current_menu_item['hidden'] ) ) {
734 + if ( $current_menu_item['hidden'] == true ) {
1008 735 return false;
1009 736 } else {
1010 737 return $current_menu_item;
1011 738 }
@@ -1013,8 +740,23 @@
1013 740 return $current_menu_item;
1014 741 }
1015 742 }
1016 743
744 + /**
745 + * Menu Editor Menu
746 + */
747 + public function jltwp_adminify_menu_editor_submenu() {
748 + add_submenu_page(
749 + 'wp-adminify-settings',
750 + esc_html__( 'Menu Editor by WP Adminify', 'adminify' ),
751 + esc_html__( 'Menu Editor', 'adminify' ),
752 + apply_filters( 'jltwp_adminify_capability', 'manage_options' ),
753 + 'adminify-menu-editor',
754 + // Page slug, will be displayed in URL
755 + [$this, 'jltwp_adminify_menu_editor_contents']
756 + );
757 + }
758 +
1017 759 public function get_saved_sub_menu() {
1018 760 $menu_settings = $this->menu_settings;
1019 761 $menu = $this->menu;
1020 762 $submenu = $this->submenu;
@@ -1055,8 +797,10 @@
1055 797 * Render Menu Editor
1056 798 */
1057 799 public function render_menu_editor() {
1058 800 global $wp_roles;
801 + $users = get_users();
802 + $this->users = $users;
1059 803 $this->roles = $wp_roles->roles;
1060 804 if ( $this->menu && is_array( $this->menu ) ) {
1061 805 foreach ( $this->menu as $menu_item ) {
1062 806 $next_menu_item = next( $this->menu );
@@ -1073,8 +817,25 @@
1073 817 );
1074 818 }
1075 819 }
1076 820 $this->render_add_new_menu_item();
821 + ?>
822 + <script>
823 + jQuery(function($) {
824 +
825 + $('.adminify-menu-settings').tokenize2({
826 + placeholder: '<?php
827 + esc_html_e( 'Select roles or users', 'adminify' );
828 + ?>'
829 + });
830 +
831 + $('.adminify-menu-settings').on('tokenize:select', function() {
832 + $(this).tokenize2().trigger('tokenize:search', [$(this).tokenize2().input.val()]);
833 + });
834 +
835 + });
836 + </script>
837 + <?php
1077 838 }
1078 839 }
1079 840
1080 841 public function get_icon( $value, $default ) {
@@ -1089,17 +850,27 @@
1089 850 */
1090 851 public function generate_user_rules_select_field( $menu_id, $disabled_for, $menu_type = 'menu' ) {
1091 852 ob_start();
1092 853 ?>
1093 - <select class="adminify-menu-settings adminify-user-role-select <?php
1094 - echo esc_attr( $menu_type );
854 + <select class="adminify-menu-settings <?php
855 + echo $menu_type;
1095 856 ?>_setting" name="hidden_for" id="<?php
1096 857 echo esc_attr( $menu_id );
1097 858 ?>-user-role-types" multiple>
1098 - <optgroup label="<?php
1099 - esc_attr_e( 'Roles', 'adminify' );
1100 - ?>">
1101 859 <?php
860 + $sel = '';
861 + // if (in_array('Super Admin', $disabled_for)) {
862 + // $sel = 'selected';
863 + // }
864 + ?>
865 +
866 + <!-- <option value="Super Admin" <?php
867 + // echo esc_attr($sel);
868 + ?>><?php
869 + // esc_html_e('Super Admin', 'adminify');
870 + ?></option> -->
871 +
872 + <?php
1102 873 foreach ( $this->roles as $role ) {
1103 874 $rolename = $role['name'];
1104 875 if ( 'administrator' == strtolower( $rolename ) ) {
1105 876 continue;
@@ -1117,40 +888,25 @@
1117 888 echo esc_html( $rolename );
1118 889 ?></option>
1119 890 <?php
1120 891 }
1121 - ?>
1122 - </optgroup>
1123 -
1124 - <optgroup label="<?php
1125 - esc_attr_e( 'Users', 'adminify' );
1126 - ?>" class="adminify-users-optgroup">
892 + foreach ( $this->users as $user ) {
893 + $username = $user->display_name;
894 + $sel = '';
895 + if ( in_array( $username, $disabled_for ) ) {
896 + $sel = 'selected';
897 + }
898 + ?>
899 + <option value="<?php
900 + echo esc_attr( $username );
901 + ?>" <?php
902 + echo esc_attr( $sel );
903 + ?>><?php
904 + echo esc_html( $username );
905 + ?></option>
1127 906 <?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 907 }
1151 908 ?>
1152 - </optgroup>
1153 909 </select>
1154 910 <?php
1155 911 return ob_get_clean();
1156 912 }
@@ -1165,16 +921,12 @@
1165 921 $current_menu_item,
1166 922 $master_sub_menu,
1167 923 $next_menu_item
1168 924 ) {
1169 - if ( empty( $current_menu_item[2] ) ) {
1170 - return;
1171 - }
1172 - // $disabled_for = '';
925 + $disabled_for = '';
1173 926 $menu_id = preg_replace( '/[^A-Za-z0-9 ]/', '', $current_menu_item[5] );
1174 927 $name = '';
1175 928 $link = '';
1176 - $external_link = '';
1177 929 $icon = '';
1178 930 $separator = '';
1179 931 $disabled_for = [];
1180 932 $optiongroup = [];
@@ -1199,11 +951,8 @@
1199 951 }
1200 952 if ( isset( $optiongroup['separator'] ) ) {
1201 953 $separator = $optiongroup['separator'];
1202 954 }
1203 - if ( isset( $optiongroup['external_link'] ) ) {
1204 - $external_link = $optiongroup['external_link'];
1205 - }
1206 955 }
1207 956 }
1208 957 $name_attr = $current_menu_item[2];
1209 958 if ( strpos( $current_menu_item[5], 'adminify-custom-menu-' ) !== false ) {
@@ -1221,11 +970,8 @@
1221 970 }
1222 971 if ( isset( $current_menu_item['separator'] ) ) {
1223 972 $separator = $current_menu_item['separator'];
1224 973 }
1225 - if ( isset( $current_menu_item['external_link'] ) ) {
1226 - $external_link = $current_menu_item['external_link'];
1227 - }
1228 974 }
1229 975 if ( !is_array( $disabled_for ) ) {
1230 976 $disabled_for = [];
1231 977 }
@@ -1320,9 +1066,9 @@
1320 1066 <label for="<?php
1321 1067 echo esc_attr( $current_menu_item[2] );
1322 1068 ?>">
1323 1069 <?php
1324 - esc_html_e( 'Hidden For Roles or Users', 'adminify' );
1070 + esc_html_e( 'Hidden For Rules', 'adminify' );
1325 1071 ?>
1326 1072 </label>
1327 1073
1328 1074 <div class="select is-small">
@@ -1327,9 +1073,8 @@
1327 1073
1328 1074 <div class="select is-small">
1329 1075
1330 1076 <?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 1077 echo $this->generate_user_rules_select_field( $menu_id, $disabled_for );
1333 1078 ?>
1334 1079
1335 1080 </div>
@@ -1334,11 +1079,10 @@
1334 1079
1335 1080 </div>
1336 1081 </div>
1337 1082 </div>
1338 -
1339 1083 <div class="columns">
1340 - <!-- <div class="column">
1084 + <div class="column">
1341 1085 <label for="">
1342 1086 <?php
1343 1087 esc_html_e( 'Change Link', 'adminify' );
1344 1088 ?>
@@ -1346,103 +1090,12 @@
1346 1090 <input class="menu_setting" name="link" type="url" placeholder="<?php
1347 1091 esc_html_e( 'New link', 'adminify' );
1348 1092 ?>" value="<?php
1349 1093 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 1094 ?>">
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 -
1095 + </div>
1378 1096 <div class="column">
1379 1097 <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 1098 <?php
1446 1099 esc_html_e( 'Set Custom Icon', 'adminify' );
1447 1100 ?>
1448 1101 </label>
@@ -1455,9 +1108,9 @@
1455 1108 <?php
1456 1109 if ( !empty( $icon ) ) {
1457 1110 if ( preg_match( '/http(s?)\\:\\/\\//i', $icon ) ) {
1458 1111 $image = explode( ',', $icon );
1459 - echo '<i class=""><img width="24" height="24" src=' . esc_url( $image[1] ) . ' ></i>';
1112 + echo '<i class=""><img src=' . esc_url( $image[1] ) . ' ></i>';
1460 1113 } else {
1461 1114 ?>
1462 1115 <i class="<?php
1463 1116 echo esc_attr( $this->get_icon( esc_attr( $icon ), '' ) );
@@ -1466,9 +1119,9 @@
1466 1119 }
1467 1120 } else {
1468 1121 $adminify_icon = WP_ADMINIFY_ASSETS_IMAGE . 'logos/menu-icon.svg';
1469 1122 if ( empty( $icons[$default_icons] ) ) {
1470 - echo '<i class=""><img width="24" height="24" src=' . esc_url( $adminify_icon ) . ' ></i>';
1123 + echo '<i class=""><img src=' . esc_url( $adminify_icon ) . ' ></i>';
1471 1124 } else {
1472 1125 ?>
1473 1126 <i class="<?php
1474 1127 echo wp_kses_post( $this->get_icon( esc_attr( $icon ), $icons[$default_icons] ) );
@@ -1486,27 +1139,16 @@
1486 1139 </div>
1487 1140 </div>
1488 1141 </div>
1489 1142 <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 1143 <div class='column <?php
1498 - echo esc_attr( $upgrade_pro );
1144 + echo ( !jltwp_adminify()->can_use_premium_code__premium_only() ? 'upgrade-pro' : '' );
1499 1145 ?>'>
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 || "" );
1146 + <?php
1507 1147 ?>
1508 - </label>
1148 + <?php
1149 + echo Utils::adminify_upgrade_pro( 'Add Separator' );
1150 + ?>
1509 1151 </div>
1510 1152 </div>
1511 1153 </div>
1512 1154 <?php
@@ -1607,16 +1249,36 @@
1607 1249 ?>">
1608 1250 </div>
1609 1251 <div class="column">
1610 1252 <label for=""><?php
1611 - esc_html_e( 'Hidden For Roles or Users', 'adminify' );
1253 + esc_html_e( 'Hidden For Rules', 'adminify' );
1612 1254 ?></label>
1613 1255
1614 1256 <div class="select is-small">
1615 1257 <?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 1258 echo $this->generate_user_rules_select_field( $menu_id, $disabled_for );
1618 1259 ?>
1260 +
1261 + <script>
1262 + jQuery('#<?php
1263 + echo esc_attr( $menu_id );
1264 + ?> #<?php
1265 + echo esc_attr( $menu_id );
1266 + ?>-user-role-types').tokenize2({
1267 + placeholder: '<?php
1268 + esc_html_e( 'Select roles or users', 'adminify' );
1269 + ?>'
1270 + });
1271 + jQuery(document).ready(function($) {
1272 + $('#<?php
1273 + echo esc_attr( $menu_id );
1274 + ?> #<?php
1275 + echo esc_attr( $menu_id );
1276 + ?>-user-role-types').on('tokenize:select', function(container) {
1277 + $(this).tokenize2().trigger('tokenize:search', [$(this).tokenize2().input.val()]);
1278 + });
1279 + })
1280 + </script>
1619 1281 </div>
1620 1282 </div>
1621 1283 </div>
1622 1284 </div>
@@ -1631,9 +1293,8 @@
1631 1293 public function build_sub_menu_item( $current_menu_item, $optiongroup, $name_attr ) {
1632 1294 $name = '';
1633 1295 $link = '';
1634 1296 $icon = '';
1635 - $external_link = '';
1636 1297 $disabled_for = [];
1637 1298 $suboptiongroup = [];
1638 1299 $menu_options = $this->menu_settings;
1639 1300 if ( isset( $optiongroup['submenu'] ) ) {
@@ -1644,11 +1305,8 @@
1644 1305 }
1645 1306 if ( isset( $suboptiongroup['link'] ) ) {
1646 1307 $link = $suboptiongroup['link'];
1647 1308 }
1648 - if ( isset( $suboptiongroup['external_link'] ) ) {
1649 - $external_link = $suboptiongroup['external_link'];
1650 - }
1651 1309 if ( isset( $suboptiongroup['icon'] ) ) {
1652 1310 $icon = $suboptiongroup['icon'];
1653 1311 }
1654 1312 if ( isset( $suboptiongroup['hidden_for'] ) ) {
@@ -1668,11 +1326,8 @@
1668 1326 }
1669 1327 if ( isset( $optiongroup['submenu'][$sub_menu_name_attr]['icon'] ) ) {
1670 1328 $icon = $optiongroup['submenu'][$sub_menu_name_attr]['icon'];
1671 1329 }
1672 - if ( isset( $optiongroup['submenu'][$sub_menu_name_attr]['external_link'] ) ) {
1673 - $external_link = $optiongroup['submenu'][$sub_menu_name_attr]['external_link'];
1674 - }
1675 1330 }
1676 1331 if ( !is_array( $disabled_for ) ) {
1677 1332 $disabled_for = [];
1678 1333 }
@@ -1721,16 +1376,38 @@
1721 1376 ?>">
1722 1377 </div>
1723 1378 <div class="column">
1724 1379 <label for=""><?php
1725 - esc_html_e( 'Hidden For Roles or Users', 'adminify' );
1380 + esc_html_e( 'Hidden For Rules', 'adminify' );
1726 1381 ?></label>
1727 1382
1728 1383 <div class="select is-small">
1384 +
1729 1385 <?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 1386 echo $this->generate_user_rules_select_field( $menu_id, $disabled_for, 'sub_menu' );
1732 1387 ?>
1388 +
1389 + <script>
1390 + jQuery('#wp-adminify-sub-menu-<?php
1391 + echo esc_attr( $menu_id );
1392 + ?> #<?php
1393 + echo esc_attr( $menu_id );
1394 + ?>-user-role-types').tokenize2({
1395 + placeholder: '<?php
1396 + esc_html_e( 'Select roles or users', 'adminify' );
1397 + ?>'
1398 + });
1399 + jQuery(document).ready(function($) {
1400 + $('#wp-adminify-sub-menu-<?php
1401 + echo esc_attr( $menu_id );
1402 + ?> #<?php
1403 + echo esc_attr( $menu_id );
1404 + ?>-user-role-types').on('tokenize:select', function(container) {
1405 + $(this).tokenize2().trigger('tokenize:search', [$(this).tokenize2().input.val()]);
1406 + });
1407 + })
1408 + </script>
1409 +
1733 1410 </div>
1734 1411 </div>
1735 1412 </div>
1736 1413 <div class="columns">
@@ -1739,30 +1416,41 @@
1739 1416 esc_html_e( 'Change Link', 'adminify' );
1740 1417 ?></label>
1741 1418 <input class="sub_menu_setting" name="link" type="url" placeholder="New link" value="<?php
1742 1419 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 1420 ?>">
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 1421 </div>
1759 1422 <div class="column">
1760 - <label for="" style="margin-top:25px">
1761 - <?php
1762 - esc_html_e( 'Custom Icon is not allowed for Submenu', 'adminify' );
1423 + <label for=""><?php
1424 + esc_html_e( 'Set Custom Icon', 'adminify' );
1425 + ?> <i>(<?php
1426 + esc_html_e( 'Not available for Submenu.', 'adminify' );
1427 + ?>)</i></label>
1428 +
1429 + <div class="icon-picker-wrap wp-adminify-menu-icon-picker adminify-icon-picker-input icon-select-button is-clickable-no is-pulled-left">
1430 + <ul class="icon-picker">
1431 + <li class="icon-none" title="None"><i class="dashicons dashicons-dismiss"></i></li>
1432 + <?php
1433 + $custom_class = '';
1434 + $icon = '<i class="' . $this->get_icon( esc_attr( $icon ), 'dashicons dashicons-external' ) . '"></i>';
1435 + if ( strpos( $sub_menu_name_attr, 'adminify-custom-submenu-' ) !== false ) {
1436 + $custom_class = 'custom-icon';
1437 + $icon = '<img src="' . esc_url( WP_ADMINIFY_ASSETS_IMAGE ) . 'logos/menu-icon.svg" />';
1438 + }
1763 1439 ?>
1764 - </label>
1440 + <li class="select-icon <?php
1441 + echo esc_attr( $custom_class );
1442 + ?>" title="Icon Library">
1443 + <?php
1444 + echo wp_kses_post( $icon );
1445 + ?>
1446 + </li>
1447 + <input type="hidden" class="sub_menu_setting" name="icon" value="<?php
1448 + echo esc_attr( $icon );
1449 + ?>">
1450 + </ul>
1451 + </div>
1452 +
1765 1453 </div>
1766 1454 </div>
1767 1455 </div>
1768 1456 <?php
@@ -1794,9 +1482,8 @@
1794 1482 <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 1483 echo esc_attr( ( $submenu ? 'submenu' : '' ) );
1796 1484 ?> <?php
1797 1485 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 1486 ?>">
1800 1487 <div class="inner-text">
1801 1488 <i class="dashicons dashicons-plus-alt"></i>
1802 1489 <span class="title"><?php
@@ -1804,9 +1491,8 @@
1804 1491 ?></span>
1805 1492 </div>
1806 1493 <?php
1807 1494 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 1495 ?>
1810 1496 </div>
1811 1497 <?php
1812 1498 }
@@ -1821,15 +1507,14 @@
1821 1507
1822 1508 <div class="adminify-flex adminify-flex-center adminify-justify-between">
1823 1509 <div class="adminify-menu-editor-help-urls adminify-flex adminify-flex-center adminify-gap-2">
1824 1510 <?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 1511 echo Utils::adminfiy_help_urls(
1827 1512 __( 'Menu Editor', 'adminify' ),
1828 1513 'https://wpadminify.com/kb/wordpress-dashboard-menu-editor/',
1829 1514 'https://www.youtube.com/playlist?list=PLqpMw0NsHXV-EKj9Xm1DMGa6FGniHHly8',
1830 1515 'https://www.facebook.com/groups/jeweltheme',
1831 - esc_url( \WPAdminify\Inc\Admin\AdminSettings::support_url() )
1516 + 'https://wpadminify.com/support/'
1832 1517 );
1833 1518 ?>
1834 1519 </div>
1835 1520
@@ -1885,9 +1570,9 @@
1885 1570 <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 1571 </svg>
1887 1572
1888 1573 <?php
1889 - esc_html_e( 'If you have Adminify Menu Module disabled, icons and label dividers won\'t change.', 'adminify' );
1574 + esc_html_e( 'If you have WP Adminify Menu Module disabled, icons and label dividers won\'t change.', 'adminify' );
1890 1575 ?>
1891 1576
1892 1577 </p>
1893 1578 </div>
@@ -1901,9 +1586,9 @@
1901 1586
1902 1587 <div class="wrap">
1903 1588 <div class="wp-adminify--menu--editor--container">
1904 1589
1905 - <!-- <div id="adminify-data-saved-message"></div> -->
1590 + <!-- <div id="adminify-data-saved-message"></div> -->
1906 1591
1907 1592 <?php
1908 1593 //self::render_menu_editor_header();
1909 1594 ?>