PluginProbe
BlockSpare – Gutenberg Blocks for News, Magazine, Blog & Business Websites / trunk
BlockSpare – Gutenberg Blocks for News, Magazine, Blog & Business Websites vtrunk
4.1.0 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 2.1.2 2.5.0 2.5.3 2.6.1 All 38 releases
blockspare / freemius / includes / managers / class-fs-admin-menu-manager.php

class-fs-admin-menu-manager.php in BlockSpare – Gutenberg Blocks for News, Magazine, Blog & Business Websites trunk, at freemius/includes/managers/class-fs-admin-menu-manager.php

1,026 lines 26.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Freemius
4 * @copyright Copyright (c) 2015, Freemius, Inc.
5 * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6 * @since 1.1.3
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 class FS_Admin_Menu_Manager {
14
15 #region Properties
16
17 /**
18 * @since 1.2.2
19 *
20 * @var string
21 */
22 protected $_module_unique_affix;
23
24 /**
25 * @since 1.2.2
26 *
27 * @var number
28 */
29 protected $_module_id;
30
31 /**
32 * @since 1.2.2
33 *
34 * @var string
35 */
36 protected $_module_type;
37
38 /**
39 * @since 1.0.6
40 *
41 * @var string
42 */
43 private $_menu_slug;
44 /**
45 * @since 1.1.3
46 *
47 * @var string
48 */
49 private $_parent_slug;
50 /**
51 * @since 1.1.3
52 *
53 * @var string
54 */
55 private $_parent_type;
56 /**
57 * @since 1.1.3
58 *
59 * @var string
60 */
61 private $_type;
62 /**
63 * @since 1.1.3
64 *
65 * @var bool
66 */
67 private $_is_top_level;
68 /**
69 * @since 1.1.3
70 *
71 * @var bool
72 */
73 private $_is_override_exact;
74 /**
75 * @since 1.1.3
76 *
77 * @var array<string,bool>
78 */
79 private $_default_submenu_items;
80 /**
81 * @since 1.1.3
82 *
83 * @var string
84 */
85 private $_first_time_path;
86 /**
87 * @since 1.2.2
88 *
89 * @var bool
90 */
91 private $_menu_exists;
92 /**
93 * @since 2.0.0
94 *
95 * @var bool
96 */
97 private $_network_menu_exists;
98
99 #endregion Properties
100
101 /**
102 * @var FS_Logger
103 */
104 protected $_logger;
105
106 #region Singleton
107
108 /**
109 * @var FS_Admin_Menu_Manager[]
110 */
111 private static $_instances = array();
112
113 /**
114 * @param number $module_id
115 * @param string $module_type
116 * @param string $module_unique_affix
117 *
118 * @return FS_Admin_Menu_Manager
119 */
120 static function instance( $module_id, $module_type, $module_unique_affix ) {
121 $key = 'm_' . $module_id;
122
123 if ( ! isset( self::$_instances[ $key ] ) ) {
124 self::$_instances[ $key ] = new FS_Admin_Menu_Manager( $module_id, $module_type, $module_unique_affix );
125 }
126
127 return self::$_instances[ $key ];
128 }
129
130 protected function __construct( $module_id, $module_type, $module_unique_affix ) {
131 $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $module_id . '_admin_menu', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
132
133 $this->_module_id = $module_id;
134 $this->_module_type = $module_type;
135 $this->_module_unique_affix = $module_unique_affix;
136 }
137
138 #endregion Singleton
139
140 #region Helpers
141
142 private function get_option( &$options, $key, $default = false ) {
143 return ! empty( $options[ $key ] ) ? $options[ $key ] : $default;
144 }
145
146 private function get_bool_option( &$options, $key, $default = false ) {
147 return isset( $options[ $key ] ) && is_bool( $options[ $key ] ) ? $options[ $key ] : $default;
148 }
149
150 #endregion Helpers
151
152 /**
153 * @param array $menu
154 * @param bool $is_addon
155 */
156 function init( $menu, $is_addon = false ) {
157 $this->_menu_exists = ( isset( $menu['slug'] ) && ! empty( $menu['slug'] ) );
158 $this->_network_menu_exists = ( ! empty( $menu['network'] ) && true === $menu['network'] );
159
160 $this->_menu_slug = ( $this->_menu_exists ? $menu['slug'] : $this->_module_unique_affix );
161
162 $this->_default_submenu_items = array();
163 // @deprecated
164 $this->_type = 'page';
165 $this->_is_top_level = true;
166 $this->_is_override_exact = false;
167 $this->_parent_slug = false;
168 // @deprecated
169 $this->_parent_type = 'page';
170
171 if ( isset( $menu ) ) {
172 if ( ! $is_addon ) {
173 $this->_default_submenu_items = array(
174 'contact' => $this->get_bool_option( $menu, 'contact', true ),
175 'support' => $this->get_bool_option( $menu, 'support', true ),
176 'affiliation' => $this->get_bool_option( $menu, 'affiliation', true ),
177 'account' => $this->get_bool_option( $menu, 'account', true ),
178 'pricing' => $this->get_bool_option( $menu, 'pricing', true ),
179 'addons' => $this->get_bool_option( $menu, 'addons', true ),
180 );
181
182 // @deprecated
183 $this->_type = $this->get_option( $menu, 'type', 'page' );
184 }
185
186 $this->_is_override_exact = $this->get_bool_option( $menu, 'override_exact' );
187
188 if ( isset( $menu['parent'] ) ) {
189 $this->_parent_slug = $this->get_option( $menu['parent'], 'slug' );
190 // @deprecated
191 $this->_parent_type = $this->get_option( $menu['parent'], 'type', 'page' );
192
193 // If parent's slug is different, then it's NOT a top level menu item.
194 $this->_is_top_level = ( $this->_parent_slug === $this->_menu_slug );
195 } else {
196 /**
197 * If no parent then top level if:
198 * - Has custom admin menu ('page')
199 * - CPT menu type ('cpt')
200 */
201 // $this->_is_top_level = in_array( $this->_type, array(
202 // 'cpt',
203 // 'page'
204 // ) );
205 }
206
207 $first_path = $this->get_option( $menu, 'first-path', false );
208
209 if ( ! empty( $first_path ) && is_string( $first_path ) ) {
210 $this->_first_time_path = $first_path;
211 }
212 }
213 }
214
215 /**
216 * Check if top level menu.
217 *
218 * @author Vova Feldman (@svovaf)
219 * @since 1.1.3
220 *
221 * @return bool False if submenu item.
222 */
223 function is_top_level() {
224 return $this->_is_top_level;
225 }
226
227 /**
228 * Check if the page should be override on exact URL match.
229 *
230 * @author Vova Feldman (@svovaf)
231 * @since 1.1.3
232 *
233 * @return bool False if submenu item.
234 */
235 function is_override_exact() {
236 return $this->_is_override_exact;
237 }
238
239
240 /**
241 * Get the path of the page the user should be forwarded to after first activation.
242 *
243 * @author Vova Feldman (@svovaf)
244 * @since 1.1.3
245 *
246 * @param bool $is_network Since 2.4.5
247 *
248 * @return string
249 */
250 function get_first_time_path( $is_network = false ) {
251 if ( empty ( $this->_first_time_path ) ) {
252 return $this->_first_time_path;
253 }
254
255 if ( $is_network ) {
256 return network_admin_url( $this->_first_time_path );
257 } else {
258 return admin_url( $this->_first_time_path );
259 }
260 }
261
262 /**
263 * Check if plugin's menu item is part of a custom top level menu.
264 *
265 * @author Vova Feldman (@svovaf)
266 * @since 1.1.3
267 *
268 * @return bool
269 */
270 function has_custom_parent() {
271 return ! $this->_is_top_level && is_string( $this->_parent_slug );
272 }
273
274 /**
275 * @author Leo Fajardo (@leorw)
276 * @since 1.2.2
277 *
278 * @return bool
279 */
280 function has_menu() {
281 return $this->_menu_exists;
282 }
283
284 /**
285 * @author Vova Feldman (@svovaf)
286 * @since 2.0.0
287 *
288 * @return bool
289 */
290 function has_network_menu() {
291 return $this->_network_menu_exists;
292 }
293
294 /**
295 * @author Leo Fajardo (@leorw)
296 *
297 * @param string $menu_slug
298 *
299 * @since 2.1.3
300 */
301 function set_slug_and_network_menu_exists_flag($menu_slug ) {
302 $this->_menu_slug = $menu_slug;
303 $this->_network_menu_exists = false;
304 }
305
306 /**
307 * @author Vova Feldman (@svovaf)
308 * @since 1.1.3
309 *
310 * @param string $id
311 * @param bool $default
312 * @param bool $ignore_menu_existence Since 1.2.2.7 If true, check if the submenu item visible even if there's no parent menu.
313 *
314 * @return bool
315 */
316 function is_submenu_item_visible( $id, $default = true, $ignore_menu_existence = false ) {
317 if ( ! $ignore_menu_existence && ! $this->has_menu() ) {
318 return false;
319 }
320
321 return fs_apply_filter(
322 $this->_module_unique_affix,
323 'is_submenu_visible',
324 $this->get_bool_option( $this->_default_submenu_items, $id, $default ),
325 $id
326 );
327 }
328
329 /**
330 * Calculates admin settings menu slug.
331 * If plugin's menu slug is a file (e.g. CPT), uses plugin's slug as the menu slug.
332 *
333 * @author Vova Feldman (@svovaf)
334 * @since 1.1.3
335 *
336 * @param string $page
337 *
338 * @return string
339 */
340 function get_slug( $page = '' ) {
341 return ( ( false === strpos( $this->_menu_slug, '.php?' ) ) ?
342 $this->_menu_slug :
343 $this->_module_unique_affix ) . ( empty( $page ) ? '' : ( '-' . $page ) );
344 }
345
346 /**
347 * @author Vova Feldman (@svovaf)
348 * @since 1.1.3
349 *
350 * @return string
351 */
352 function get_parent_slug() {
353 return $this->_parent_slug;
354 }
355
356 /**
357 * @author Vova Feldman (@svovaf)
358 * @since 1.1.3
359 *
360 * @return string
361 */
362 function get_type() {
363 return $this->_type;
364 }
365
366 /**
367 * @author Vova Feldman (@svovaf)
368 * @since 1.1.3
369 *
370 * @return bool
371 */
372 function is_cpt() {
373 return ( 0 === strpos( $this->_menu_slug, 'edit.php?post_type=' ) ||
374 // Back compatibility.
375 'cpt' === $this->_type
376 );
377 }
378
379 /**
380 * @author Vova Feldman (@svovaf)
381 * @since 1.1.3
382 *
383 * @return string
384 */
385 function get_parent_type() {
386 return $this->_parent_type;
387 }
388
389 /**
390 * @author Vova Feldman (@svovaf)
391 * @since 1.1.3
392 *
393 * @return string
394 */
395 function get_raw_slug() {
396 return $this->_menu_slug;
397 }
398
399 /**
400 * Get plugin's original menu slug.
401 *
402 * @author Vova Feldman (@svovaf)
403 * @since 1.1.3
404 *
405 * @return string
406 */
407 function get_original_menu_slug() {
408 if ( 'cpt' === $this->_type ) {
409 return add_query_arg( array(
410 'post_type' => $this->_menu_slug
411 ), 'edit.php' );
412 }
413
414 if ( false === strpos( $this->_menu_slug, '.php?' ) ) {
415 return $this->_menu_slug;
416 } else {
417 return $this->_module_unique_affix;
418 }
419 }
420
421 /**
422 * @author Vova Feldman (@svovaf)
423 * @since 1.1.3
424 *
425 * @return string
426 */
427 function get_top_level_menu_slug() {
428 return $this->has_custom_parent() ?
429 $this->get_parent_slug() :
430 $this->get_raw_slug();
431 }
432
433 /**
434 * Is user on plugin's admin activation page.
435 *
436 * @author Vova Feldman (@svovaf)
437 * @since 1.0.8
438 *
439 * @param bool $show_opt_in_on_themes_page Since 2.3.1
440 *
441 * @return bool
442 *
443 * @deprecated Please use is_activation_page() instead.
444 */
445 function is_main_settings_page( $show_opt_in_on_themes_page = false ) {
446 return $this->is_activation_page( $show_opt_in_on_themes_page );
447 }
448
449 /**
450 * Is user on product's admin activation page.
451 *
452 * @author Vova Feldman (@svovaf)
453 * @since 2.3.1
454 *
455 * @param bool $show_opt_in_on_themes_page Since 2.3.1
456 *
457 * @return bool
458 */
459 function is_activation_page( $show_opt_in_on_themes_page = false ) {
460 if ( $show_opt_in_on_themes_page ) {
461 /**
462 * In activation only when show_optin query string param is given.
463 *
464 * @since 1.2.2
465 */
466 return (
467 ( WP_FS__MODULE_TYPE_THEME === $this->_module_type ) &&
468 Freemius::is_themes_page() &&
469 fs_request_get_bool( $this->_module_unique_affix . '_show_optin' )
470 );
471 }
472
473 if ( $this->_menu_exists &&
474 ( fs_is_plugin_page( $this->_menu_slug ) || fs_is_plugin_page( $this->_module_unique_affix ) )
475 ) {
476 /**
477 * Module has a settings menu and the context page is the main settings page, so assume it's in
478 * activation (doesn't really check if already opted-in/skipped or not).
479 *
480 * @since 1.2.2
481 */
482 return true;
483 }
484
485 return false;
486 }
487
488 #region Submenu Override
489
490 /**
491 * Override submenu's action.
492 *
493 * @author Vova Feldman (@svovaf)
494 * @since 1.1.0
495 *
496 * @param string $parent_slug
497 * @param string $menu_slug
498 * @param callable $function
499 *
500 * @return false|string If submenu exist, will return the hook name.
501 */
502 function override_submenu_action( $parent_slug, $menu_slug, $function ) {
503 global $submenu;
504
505 $menu_slug = plugin_basename( $menu_slug );
506 $parent_slug = plugin_basename( $parent_slug );
507
508 if ( ! isset( $submenu[ $parent_slug ] ) ) {
509 // Parent menu not exist.
510 return false;
511 }
512
513 $found_submenu_item = false;
514 foreach ( $submenu[ $parent_slug ] as $submenu_item ) {
515 if ( $menu_slug === $submenu_item[2] ) {
516 $found_submenu_item = $submenu_item;
517 break;
518 }
519 }
520
521 if ( false === $found_submenu_item ) {
522 // Submenu item not found.
523 return false;
524 }
525
526 // Remove current function.
527 $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug );
528 remove_all_actions( $hookname );
529
530 // Attach new action.
531 add_action( $hookname, $function );
532
533 return $hookname;
534 }
535
536 #endregion Submenu Override
537
538 #region Top level menu Override
539
540 /**
541 * Find plugin's admin dashboard main menu item.
542 *
543 * @author Vova Feldman (@svovaf)
544 * @since 1.0.2
545 *
546 * @return string[]|false
547 */
548 private function find_top_level_menu() {
549 global $menu;
550
551 $position = - 1;
552 $found_menu = false;
553
554 $menu_slug = $this->get_raw_slug();
555
556 $hook_name = get_plugin_page_hookname( $menu_slug, '' );
557 foreach ( $menu as $pos => $m ) {
558 if ( $menu_slug === $m[2] ) {
559 $position = $pos;
560 $found_menu = $m;
561 break;
562 }
563 }
564
565 if ( false === $found_menu ) {
566 return false;
567 }
568
569 return array(
570 'menu' => $found_menu,
571 'position' => $position,
572 'hook_name' => $hook_name
573 );
574 }
575
576 /**
577 * Find plugin's admin dashboard main submenu item.
578 *
579 * @author Vova Feldman (@svovaf)
580 * @since 1.2.1.6
581 *
582 * @return array|false
583 */
584 private function find_main_submenu() {
585 global $submenu;
586
587 $top_level_menu_slug = $this->get_top_level_menu_slug();
588
589 if ( ! isset( $submenu[ $top_level_menu_slug ] ) ) {
590 return false;
591 }
592
593 $submenu_slug = $this->get_raw_slug();
594
595 $position = - 1;
596 $found_submenu = false;
597
598 $hook_name = get_plugin_page_hookname( $submenu_slug, '' );
599
600 foreach ( $submenu[ $top_level_menu_slug ] as $pos => $sub ) {
601 if ( $submenu_slug === $sub[2] ) {
602 $position = $pos;
603 $found_submenu = $sub;
604 }
605 }
606
607 if ( false === $found_submenu ) {
608 return false;
609 }
610
611 return array(
612 'menu' => $found_submenu,
613 'parent_slug' => $top_level_menu_slug,
614 'position' => $position,
615 'hook_name' => $hook_name
616 );
617 }
618
619 /**
620 * Remove all sub-menu items.
621 *
622 * @author Vova Feldman (@svovaf)
623 * @since 1.0.7
624 *
625 * @return bool If submenu with plugin's menu slug was found.
626 */
627 private function remove_all_submenu_items() {
628 global $submenu;
629
630 $menu_slug = $this->get_raw_slug();
631
632 if ( ! isset( $submenu[ $menu_slug ] ) ) {
633 return false;
634 }
635
636 /**
637 * This method is NOT executed for WordPress.org themes.
638 * Since we maintain only one version of the SDK we added this small
639 * hack to avoid the error from Theme Check since it's a false-positive.
640 *
641 * @author Vova Feldman (@svovaf)
642 * @since 1.2.2.7
643 */
644 $submenu_ref = &$submenu;
645 $submenu_ref[ $menu_slug ] = array();
646
647 return true;
648 }
649
650 /**
651 *
652 * @author Vova Feldman (@svovaf)
653 * @since 1.0.9
654 *
655 * @param bool $remove_top_level_menu
656 *
657 * @return false|array[string]mixed
658 */
659 function remove_menu_item( $remove_top_level_menu = false ) {
660 $this->_logger->entrance();
661
662 // Find main menu item.
663 $top_level_menu = $this->find_top_level_menu();
664
665 if ( false === $top_level_menu ) {
666 return false;
667 }
668
669 // Remove it with its actions.
670 remove_all_actions( $top_level_menu['hook_name'] );
671
672 // Remove all submenu items.
673 $this->remove_all_submenu_items();
674
675 if ( $remove_top_level_menu ) {
676 global $menu;
677 unset( $menu[ $top_level_menu['position'] ] );
678 }
679
680 return $top_level_menu;
681 }
682
683 /**
684 * Get module's main admin setting page URL.
685 *
686 * @todo This method was only tested for wp.org compliant themes with a submenu item. Need to test for plugins with top level, submenu, and CPT top level, menu items.
687 *
688 * @author Vova Feldman (@svovaf)
689 * @since 1.2.2.7
690 *
691 * @return string
692 */
693 function main_menu_url() {
694 $this->_logger->entrance();
695
696 if ( $this->_is_top_level ) {
697 $menu = $this->find_top_level_menu();
698 } else {
699 $menu = $this->find_main_submenu();
700 }
701
702 $menu_slug = $menu['menu'][2];
703 $parent_slug = isset( $menu['parent_slug'] ) ?
704 $menu['parent_slug'] :
705 'admin.php';
706
707 if ( fs_apply_filter( $this->_module_unique_affix, 'enable_cpt_advanced_menu_logic', false ) ) {
708 $parent_slug = 'admin.php';
709
710 /**
711 * This line and the `if` block below it are based on the `menu_page_url()` function of WordPress.
712 *
713 * @author Leo Fajardo (@leorw)
714 * @since 2.10.2
715 */
716 global $_parent_pages;
717
718 if ( ! empty( $_parent_pages[ $menu_slug ] ) ) {
719 $_parent_slug = $_parent_pages[ $menu_slug ];
720 $parent_slug = isset( $_parent_pages[ $_parent_slug ] ) ?
721 $parent_slug :
722 $menu['parent_slug'];
723 }
724 }
725
726 return admin_url(
727 $parent_slug .
728 ( false === strpos( $parent_slug, '?' ) ? '?' : '&' ) .
729 'page=' .
730 $menu_slug
731 );
732 }
733
734 /**
735 * @author Vova Feldman (@svovaf)
736 * @since 1.1.4
737 *
738 * @param callable $function
739 *
740 * @return false|array[string]mixed
741 */
742 function override_menu_item( $function ) {
743 $found_menu = $this->remove_menu_item();
744
745 if ( false === $found_menu ) {
746 return false;
747 }
748
749 if ( ! $this->is_top_level() || ! $this->is_cpt() ) {
750 $menu_slug = plugin_basename( $this->get_slug() );
751
752 $hookname = get_plugin_page_hookname( $menu_slug, '' );
753
754 // Override menu action.
755 add_action( $hookname, $function );
756 } else {
757 global $menu;
758
759 // Remove original CPT menu.
760 unset( $menu[ $found_menu['position'] ] );
761
762 // Create new top-level menu action.
763 $hookname = self::add_page(
764 $found_menu['menu'][3],
765 $found_menu['menu'][0],
766 'manage_options',
767 $this->get_slug(),
768 $function,
769 $found_menu['menu'][6],
770 $found_menu['position']
771 );
772 }
773
774 return $hookname;
775 }
776
777 /**
778 * Adds a counter to the module's top level menu item.
779 *
780 * @author Vova Feldman (@svovaf)
781 * @since 1.2.1.5
782 *
783 * @param int $counter
784 * @param string $class
785 */
786 function add_counter_to_menu_item( $counter = 1, $class = '' ) {
787 global $menu, $submenu;
788
789 $mask = '%s <span class="update-plugins %s count-%3$s" aria-hidden="true"><span>%3$s<span class="screen-reader-text">%3$s notifications</span></span></span>';
790
791 /**
792 * This method is NOT executed for WordPress.org themes.
793 * Since we maintain only one version of the SDK we added this small
794 * hack to avoid the error from Theme Check since it's a false-positive.
795 *
796 * @author Vova Feldman (@svovaf)
797 * @since 1.2.2.7
798 */
799 $menu_ref = &$menu;
800 $submenu_ref = &$submenu;
801
802 if ( $this->_is_top_level ) {
803 // Find main menu item.
804 $found_menu = $this->find_top_level_menu();
805
806 if ( false !== $found_menu ) {
807 // Override menu label.
808 $menu_ref[ $found_menu['position'] ][0] = sprintf(
809 $mask,
810 $found_menu['menu'][0],
811 $class,
812 $counter
813 );
814 }
815 } else {
816 $found_submenu = $this->find_main_submenu();
817
818 if ( false !== $found_submenu ) {
819 // Override menu label.
820 $submenu_ref[ $found_submenu['parent_slug'] ][ $found_submenu['position'] ][0] = sprintf(
821 $mask,
822 $found_submenu['menu'][0],
823 $class,
824 $counter
825 );
826 }
827 }
828 }
829
830 #endregion Top level menu Override
831
832 /**
833 * Add a top-level menu page.
834 *
835 * Note for WordPress.org Theme/Plugin reviewer:
836 *
837 * This is a replication of `add_menu_page()` to avoid Theme Check warning.
838 *
839 * Why?
840 * ====
841 * Freemius is an SDK for plugin and theme developers. Since the core
842 * of the SDK is relevant both for plugins and themes, for obvious reasons,
843 * we only develop and maintain one code base.
844 *
845 * This method will not run for wp.org themes (only plugins) since theme
846 * admin settings/options are now only allowed in the customizer.
847 *
848 * If you have any questions or need clarifications, please don't hesitate
849 * pinging me on slack, my username is @svovaf.
850 *
851 * @author Vova Feldman (@svovaf)
852 * @since 1.2.2
853 *
854 * @param string $page_title The text to be displayed in the title tags of the page when the menu is
855 * selected.
856 * @param string $menu_title The text to be used for the menu.
857 * @param string $capability The capability required for this menu to be displayed to the user.
858 * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu).
859 * @param callable|string $function The function to be called to output the content for this page.
860 * @param string $icon_url The URL to the icon to be used for this menu.
861 * * Pass a base64-encoded SVG using a data URI, which will be colored to
862 * match the color scheme. This should begin with
863 * 'data:image/svg+xml;base64,'.
864 * * Pass the name of a Dashicons helper class to use a font icon,
865 * e.g. 'dashicons-chart-pie'.
866 * * Pass 'none' to leave div.wp-menu-image empty so an icon can be added
867 * via CSS.
868 * @param int $position The position in the menu order this one should appear.
869 *
870 * @return string The resulting page's hook_suffix.
871 */
872 static function add_page(
873 $page_title,
874 $menu_title,
875 $capability,
876 $menu_slug,
877 $function = '',
878 $icon_url = '',
879 $position = null
880 ) {
881 $fn = 'add_menu' . '_page';
882
883 return $fn(
884 $page_title,
885 $menu_title,
886 $capability,
887 $menu_slug,
888 $function,
889 $icon_url,
890 $position
891 );
892 }
893
894 /**
895 * Add page and update menu instance settings.
896 *
897 * @author Vova Feldman (@svovaf)
898 * @since 2.0.0
899 *
900 * @param string $page_title
901 * @param string $menu_title
902 * @param string $capability
903 * @param string $menu_slug
904 * @param callable|string $function
905 * @param string $icon_url
906 * @param int|null $position
907 *
908 * @return string
909 */
910 function add_page_and_update(
911 $page_title,
912 $menu_title,
913 $capability,
914 $menu_slug,
915 $function = '',
916 $icon_url = '',
917 $position = null
918 ) {
919 $this->_menu_slug = $menu_slug;
920 $this->_is_top_level = true;
921 $this->_menu_exists = true;
922 $this->_network_menu_exists = true;
923
924 return self::add_page(
925 $page_title,
926 $menu_title,
927 $capability,
928 $menu_slug,
929 $function,
930 $icon_url,
931 $position
932 );
933 }
934
935 /**
936 * Add a submenu page.
937 *
938 * Note for WordPress.org Theme/Plugin reviewer:
939 *
940 * This is a replication of `add_submenu_page()` to avoid Theme Check warning.
941 *
942 * Why?
943 * ====
944 * Freemius is an SDK for plugin and theme developers. Since the core
945 * of the SDK is relevant both for plugins and themes, for obvious reasons,
946 * we only develop and maintain one code base.
947 *
948 * This method will not run for wp.org themes (only plugins) since theme
949 * admin settings/options are now only allowed in the customizer.
950 *
951 * If you have any questions or need clarifications, please don't hesitate
952 * pinging me on slack, my username is @svovaf.
953 *
954 * @author Vova Feldman (@svovaf)
955 * @since 1.2.2
956 *
957 * @param string $parent_slug The slug name for the parent menu (or the file name of a standard
958 * WordPress admin page).
959 * @param string $page_title The text to be displayed in the title tags of the page when the menu is
960 * selected.
961 * @param string $menu_title The text to be used for the menu.
962 * @param string $capability The capability required for this menu to be displayed to the user.
963 * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu).
964 * @param callable|string $function The function to be called to output the content for this page.
965 *
966 * @return false|string The resulting page's hook_suffix, or false if the user does not have the capability
967 * required.
968 */
969 static function add_subpage(
970 $parent_slug,
971 $page_title,
972 $menu_title,
973 $capability,
974 $menu_slug,
975 $function = ''
976 ) {
977 $fn = 'add_submenu' . '_page';
978
979 return $fn( $parent_slug,
980 $page_title,
981 $menu_title,
982 $capability,
983 $menu_slug,
984 $function
985 );
986 }
987
988 /**
989 * Add sub page and update menu instance settings.
990 *
991 * @author Vova Feldman (@svovaf)
992 * @since 2.0.0
993 *
994 * @param string $parent_slug
995 * @param string $page_title
996 * @param string $menu_title
997 * @param string $capability
998 * @param string $menu_slug
999 * @param callable|string $function
1000 *
1001 * @return string
1002 */
1003 function add_subpage_and_update(
1004 $parent_slug,
1005 $page_title,
1006 $menu_title,
1007 $capability,
1008 $menu_slug,
1009 $function = ''
1010 ) {
1011 $this->_menu_slug = $menu_slug;
1012 $this->_parent_slug = $parent_slug;
1013 $this->_is_top_level = false;
1014 $this->_menu_exists = true;
1015 $this->_network_menu_exists = true;
1016
1017 return self::add_subpage(
1018 $parent_slug,
1019 $page_title,
1020 $menu_title,
1021 $capability,
1022 $menu_slug,
1023 $function
1024 );
1025 }
1026 }