PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents / 1.7.3
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents v1.7.3
4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.14 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.10 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.10 4.4.11 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1
embedpress / freemius / includes / managers / class-fs-admin-menu-manager.php
embedpress / freemius / includes / managers Last commit date
class-fs-admin-menu-manager.php 9 years ago class-fs-admin-notice-manager.php 9 years ago class-fs-cache-manager.php 9 years ago class-fs-key-value-storage.php 9 years ago class-fs-license-manager.php 9 years ago class-fs-option-manager.php 9 years ago class-fs-plan-manager.php 9 years ago class-fs-plugin-manager.php 9 years ago index.php 9 years ago
class-fs-admin-menu-manager.php
635 lines
1 <?php
2 /**
3 * @package Freemius
4 * @copyright Copyright (c) 2015, Freemius, Inc.
5 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
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 * @var string
19 */
20 protected $_plugin_slug;
21
22 /**
23 * @since 1.0.6
24 *
25 * @var string
26 */
27 private $_menu_slug;
28 /**
29 * @since 1.1.3
30 *
31 * @var string
32 */
33 private $_parent_slug;
34 /**
35 * @since 1.1.3
36 *
37 * @var string
38 */
39 private $_parent_type;
40 /**
41 * @since 1.1.3
42 *
43 * @var string
44 */
45 private $_type;
46 /**
47 * @since 1.1.3
48 *
49 * @var bool
50 */
51 private $_is_top_level;
52 /**
53 * @since 1.1.3
54 *
55 * @var bool
56 */
57 private $_is_override_exact;
58 /**
59 * @since 1.1.3
60 *
61 * @var array<string,bool>
62 */
63 private $_default_submenu_items;
64 /**
65 * @since 1.1.3
66 *
67 * @var string
68 */
69 private $_first_time_path;
70
71 #endregion Properties
72
73 /**
74 * @var FS_Logger
75 */
76 protected $_logger;
77
78 #region Singleton
79
80 /**
81 * @var FS_Admin_Menu_Manager[]
82 */
83 private static $_instances = array();
84
85 /**
86 * @param string $plugin_slug
87 *
88 * @return FS_Admin_Notice_Manager
89 */
90 static function instance( $plugin_slug ) {
91 if ( ! isset( self::$_instances[ $plugin_slug ] ) ) {
92 self::$_instances[ $plugin_slug ] = new FS_Admin_Menu_Manager( $plugin_slug );
93 }
94
95 return self::$_instances[ $plugin_slug ];
96 }
97
98 protected function __construct( $plugin_slug ) {
99 $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $plugin_slug . '_admin_menu', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
100
101 $this->_plugin_slug = $plugin_slug;
102 }
103
104 #endregion Singleton
105
106 #region Helpers
107
108 private function get_option( &$options, $key, $default = false ) {
109 return ! empty( $options[ $key ] ) ? $options[ $key ] : $default;
110 }
111
112 private function get_bool_option( &$options, $key, $default = false ) {
113 return isset( $options[ $key ] ) && is_bool( $options[ $key ] ) ? $options[ $key ] : $default;
114 }
115
116 #endregion Helpers
117
118 /**
119 * @param array $menu
120 * @param bool $is_addon
121 */
122 function init( $menu, $is_addon = false ) {
123 $this->_menu_slug = ! empty( $menu['slug'] ) ? $menu['slug'] : null;
124
125 $this->_default_submenu_items = array();
126 // @deprecated
127 $this->_type = 'page';
128 $this->_is_top_level = true;
129 $this->_is_override_exact = false;
130 $this->_parent_slug = false;
131 // @deprecated
132 $this->_parent_type = 'page';
133
134 if ( ! $is_addon && isset( $menu ) ) {
135 $this->_default_submenu_items = array(
136 'contact' => $this->get_bool_option( $menu, 'contact', true ),
137 'support' => $this->get_bool_option( $menu, 'support', true ),
138 'account' => $this->get_bool_option( $menu, 'account', true ),
139 'pricing' => $this->get_bool_option( $menu, 'pricing', true ),
140 'addons' => $this->get_bool_option( $menu, 'addons', true ),
141 );
142
143 // @deprecated
144 $this->_type = $this->get_option( $menu, 'type', 'page' );
145 $this->_is_override_exact = $this->get_bool_option( $menu, 'override_exact' );
146
147 if ( isset( $menu['parent'] ) ) {
148 $this->_parent_slug = $this->get_option( $menu['parent'], 'slug' );
149 // @deprecated
150 $this->_parent_type = $this->get_option( $menu['parent'], 'type', 'page' );
151
152 // If parent's slug is different, then it's NOT a top level menu item.
153 $this->_is_top_level = ( $this->_parent_slug === $this->_menu_slug );
154 } else {
155 /**
156 * If no parent then top level if:
157 * - Has custom admin menu ('page')
158 * - CPT menu type ('cpt')
159 */
160 // $this->_is_top_level = in_array( $this->_type, array(
161 // 'cpt',
162 // 'page'
163 // ) );
164 }
165
166 $this->_first_time_path = $this->get_option( $menu, 'first-path', false );
167 if ( ! empty( $this->_first_time_path ) && is_string( $this->_first_time_path ) ) {
168 $this->_first_time_path = admin_url( $this->_first_time_path, 'admin' );
169 }
170 }
171 }
172
173 /**
174 * Check if top level menu.
175 *
176 * @author Vova Feldman (@svovaf)
177 * @since 1.1.3
178 *
179 * @return bool False if submenu item.
180 */
181 function is_top_level() {
182 return $this->_is_top_level;
183 }
184
185 /**
186 * Check if the page should be override on exact URL match.
187 *
188 * @author Vova Feldman (@svovaf)
189 * @since 1.1.3
190 *
191 * @return bool False if submenu item.
192 */
193 function is_override_exact() {
194 return $this->_is_override_exact;
195 }
196
197
198 /**
199 * Get the path of the page the user should be forwarded to after first activation.
200 *
201 * @author Vova Feldman (@svovaf)
202 * @since 1.1.3
203 *
204 * @return string
205 */
206 function get_first_time_path() {
207 return $this->_first_time_path;
208 }
209
210 /**
211 * Check if plugin's menu item is part of a custom top level menu.
212 *
213 * @author Vova Feldman (@svovaf)
214 * @since 1.1.3
215 *
216 * @return bool
217 */
218 function has_custom_parent() {
219 return ! $this->_is_top_level && is_string( $this->_parent_slug );
220 }
221
222 /**
223 * @author Vova Feldman (@svovaf)
224 * @since 1.1.3
225 *
226 * @param string $id
227 * @param bool $default
228 *
229 * @return bool
230 */
231 function is_submenu_item_visible( $id, $default = true ) {
232 return fs_apply_filter(
233 $this->_plugin_slug,
234 'is_submenu_visible',
235 $this->get_bool_option( $this->_default_submenu_items, $id, $default ),
236 $id
237 );
238 }
239
240 /**
241 * Calculates admin settings menu slug.
242 * If plugin's menu slug is a file (e.g. CPT), uses plugin's slug as the menu slug.
243 *
244 * @author Vova Feldman (@svovaf)
245 * @since 1.1.3
246 *
247 * @param string $page
248 *
249 * @return string
250 */
251 function get_slug( $page = '' ) {
252 return ( ( false === strpos( $this->_menu_slug, '.php?' ) ) ?
253 $this->_menu_slug :
254 $this->_plugin_slug ) . ( empty( $page ) ? '' : ( '-' . $page ) );
255 }
256
257 /**
258 * Check if module has a menu slug set.
259 *
260 * @author Vova Feldman (@svovaf)
261 * @since 1.2.1.6
262 *
263 * @return bool
264 */
265 function has_menu_slug() {
266 return ! empty( $this->_menu_slug );
267 }
268
269 /**
270 * @author Vova Feldman (@svovaf)
271 * @since 1.1.3
272 *
273 * @return string
274 */
275 function get_parent_slug() {
276 return $this->_parent_slug;
277 }
278
279 /**
280 * @author Vova Feldman (@svovaf)
281 * @since 1.1.3
282 *
283 * @return string
284 */
285 function get_type() {
286 return $this->_type;
287 }
288
289 /**
290 * @author Vova Feldman (@svovaf)
291 * @since 1.1.3
292 *
293 * @return bool
294 */
295 function is_cpt() {
296 return ( 0 === strpos( $this->_menu_slug, 'edit.php?post_type=' ) ||
297 // Back compatibility.
298 'cpt' === $this->_type
299 );
300 }
301
302 /**
303 * @author Vova Feldman (@svovaf)
304 * @since 1.1.3
305 *
306 * @return string
307 */
308 function get_parent_type() {
309 return $this->_parent_type;
310 }
311
312 /**
313 * @author Vova Feldman (@svovaf)
314 * @since 1.1.3
315 *
316 * @return string
317 */
318 function get_raw_slug() {
319 return $this->_menu_slug;
320 }
321
322 /**
323 * Get plugin's original menu slug.
324 *
325 * @author Vova Feldman (@svovaf)
326 * @since 1.1.3
327 *
328 * @return string
329 */
330 function get_original_menu_slug() {
331 if ( 'cpt' === $this->_type ) {
332 return add_query_arg( array(
333 'post_type' => $this->_menu_slug
334 ), 'edit.php' );
335 }
336
337 if ( false === strpos( $this->_menu_slug, '.php?' ) ) {
338 return $this->_menu_slug;
339 } else {
340 return $this->_plugin_slug;
341 }
342 }
343
344 /**
345 * @author Vova Feldman (@svovaf)
346 * @since 1.1.3
347 *
348 * @return string
349 */
350 function get_top_level_menu_slug() {
351 return $this->has_custom_parent() ?
352 $this->get_parent_slug() :
353 $this->get_raw_slug();
354 }
355
356 /**
357 * Is user on plugin's admin activation page.
358 *
359 * @author Vova Feldman (@svovaf)
360 * @since 1.0.8
361 *
362 * @return bool
363 */
364 function is_activation_page() {
365 return isset( $_GET['page'] ) &&
366 ( ( strtolower( $this->_menu_slug ) === strtolower( $_GET['page'] ) ) ||
367 ( strtolower( $this->_plugin_slug ) === strtolower( $_GET['page'] ) ) );
368 }
369
370 #region Submenu Override
371
372 /**
373 * Override submenu's action.
374 *
375 * @author Vova Feldman (@svovaf)
376 * @since 1.1.0
377 *
378 * @param string $parent_slug
379 * @param string $menu_slug
380 * @param callable $function
381 *
382 * @return false|string If submenu exist, will return the hook name.
383 */
384 function override_submenu_action( $parent_slug, $menu_slug, $function ) {
385 global $submenu;
386
387 $menu_slug = plugin_basename( $menu_slug );
388 $parent_slug = plugin_basename( $parent_slug );
389
390 if ( ! isset( $submenu[ $parent_slug ] ) ) {
391 // Parent menu not exist.
392 return false;
393 }
394
395 $found_submenu_item = false;
396 foreach ( $submenu[ $parent_slug ] as $submenu_item ) {
397 if ( $menu_slug === $submenu_item[2] ) {
398 $found_submenu_item = $submenu_item;
399 break;
400 }
401 }
402
403 if ( false === $found_submenu_item ) {
404 // Submenu item not found.
405 return false;
406 }
407
408 // Remove current function.
409 $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug );
410 remove_all_actions( $hookname );
411
412 // Attach new action.
413 add_action( $hookname, $function );
414
415 return $hookname;
416 }
417
418 #endregion Submenu Override
419
420 #region Top level menu Override
421
422 /**
423 * Find plugin's admin dashboard main menu item.
424 *
425 * @author Vova Feldman (@svovaf)
426 * @since 1.0.2
427 *
428 * @return string[]|false
429 */
430 private function find_top_level_menu() {
431 global $menu;
432
433 $position = - 1;
434 $found_menu = false;
435
436 $menu_slug = $this->get_raw_slug();
437
438 $hook_name = get_plugin_page_hookname( $menu_slug, '' );
439 foreach ( $menu as $pos => $m ) {
440 if ( $menu_slug === $m[2] ) {
441 $position = $pos;
442 $found_menu = $m;
443 break;
444 }
445 }
446
447 if ( false === $found_menu ) {
448 return false;
449 }
450
451 return array(
452 'menu' => $found_menu,
453 'position' => $position,
454 'hook_name' => $hook_name
455 );
456 }
457
458 /**
459 * Find plugin's admin dashboard main submenu item.
460 *
461 * @author Vova Feldman (@svovaf)
462 * @since 1.2.1.6
463 *
464 * @return array|false
465 */
466 private function find_main_submenu() {
467 global $submenu;
468
469 $top_level_menu_slug = $this->get_top_level_menu_slug();
470
471 if ( ! isset( $submenu[ $top_level_menu_slug ] ) ) {
472 return false;
473 }
474
475 $submenu_slug = $this->get_raw_slug();
476
477 $position = - 1;
478 $found_submenu = false;
479
480 $hook_name = get_plugin_page_hookname( $submenu_slug, '' );
481
482 foreach ( $submenu[ $top_level_menu_slug ] as $pos => $sub ) {
483 if ( $submenu_slug === $sub[2] ) {
484 $position = $pos;
485 $found_submenu = $sub;
486 }
487 }
488
489 if ( false === $found_submenu ) {
490 return false;
491 }
492
493 return array(
494 'menu' => $found_submenu,
495 'parent_slug' => $top_level_menu_slug,
496 'position' => $position,
497 'hook_name' => $hook_name
498 );
499 }
500
501 /**
502 * Remove all sub-menu items.
503 *
504 * @author Vova Feldman (@svovaf)
505 * @since 1.0.7
506 *
507 * @return bool If submenu with plugin's menu slug was found.
508 */
509 private function remove_all_submenu_items() {
510 global $submenu;
511
512 $menu_slug = $this->get_raw_slug();
513
514 if ( ! isset( $submenu[ $menu_slug ] ) ) {
515 return false;
516 }
517
518 $submenu[ $menu_slug ] = array();
519
520 return true;
521 }
522
523 /**
524 *
525 * @author Vova Feldman (@svovaf)
526 * @since 1.0.9
527 *
528 * @return array[string]mixed
529 */
530 function remove_menu_item() {
531 $this->_logger->entrance();
532
533 // Find main menu item.
534 $menu = $this->find_top_level_menu();
535
536 if ( false === $menu ) {
537 return false;
538 }
539
540 // Remove it with its actions.
541 remove_all_actions( $menu['hook_name'] );
542
543 // Remove all submenu items.
544 $this->remove_all_submenu_items();
545
546 return $menu;
547 }
548
549 /**
550 * @author Vova Feldman (@svovaf)
551 * @since 1.1.4
552 *
553 * @param callable $function
554 *
555 * @return array[string]mixed
556 */
557 function override_menu_item( $function ) {
558 $found_menu = $this->remove_menu_item();
559
560 if ( false === $found_menu ) {
561 return false;
562 }
563
564 if ( ! $this->is_top_level() || ! $this->is_cpt() ) {
565 $menu_slug = plugin_basename( $this->get_slug() );
566
567 $hookname = get_plugin_page_hookname( $menu_slug, '' );
568
569 // Override menu action.
570 add_action( $hookname, $function );
571 } else {
572 global $menu;
573
574 // Remove original CPT menu.
575 unset( $menu[ $found_menu['position'] ] );
576
577 // Create new top-level menu action.
578 $hookname = add_menu_page(
579 $found_menu['menu'][3],
580 $found_menu['menu'][0],
581 'manage_options',
582 $this->get_slug(),
583 $function,
584 $found_menu['menu'][6],
585 $found_menu['position']
586 );
587 }
588
589 return $hookname;
590 }
591
592 /**
593 * Adds a counter to the module's top level menu item.
594 *
595 * @author Vova Feldman (@svovaf)
596 * @since 1.2.1.5
597 *
598 * @param int $counter
599 * @param string $class
600 */
601 function add_counter_to_menu_item( $counter = 1, $class = '' ) {
602 global $menu, $submenu;
603
604 $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>';
605
606 if ( $this->_is_top_level ) {
607 // Find main menu item.
608 $found_menu = $this->find_top_level_menu();
609
610 if ( false !== $found_menu ) {
611 // Override menu label.
612 $menu[ $found_menu['position'] ][0] = sprintf(
613 $mask,
614 $found_menu['menu'][0],
615 $class,
616 $counter
617 );
618 }
619 } else {
620 $found_submenu = $this->find_main_submenu();
621
622 if ( false !== $found_submenu ) {
623 // Override menu label.
624 $submenu[ $found_submenu['parent_slug'] ][ $found_submenu['position'] ][0] = sprintf(
625 $mask,
626 $found_submenu['menu'][0],
627 $class,
628 $counter
629 );
630 }
631 }
632 }
633
634 #endregion Top level menu Override
635 }