PluginProbe
YayMail – WooCommerce Email Customizer / trunk
YayMail – WooCommerce Email Customizer vtrunk
4.4.4 4.4.3 4.4.2 4.4.1 trunk 1.9.6 2.1.4 2.1.5 3.2.2 3.2.6 3.2.7.1 3.2.8.1 3.2.9 3.3 3.3.1 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4 3.4.1 3.4.2 3.4.3 All 55 releases
yaymail / vendor-prefixed / src / Menu / PluginSubmenu.php

PluginSubmenu.php in YayMail – WooCommerce Email Customizer trunk, at vendor-prefixed/src/Menu/PluginSubmenu.php

124 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace YayMailScoped\YayCommerce\AdminShell\Menu;
4
5 use YayMailScoped\YayCommerce\AdminShell\Contracts\PluginMenuAdapter;
6 use YayMailScoped\YayCommerce\AdminShell\License\Contracts\LicenseConfigAdapter;
7 use YayMailScoped\YayCommerce\AdminShell\License\License;
8 use YayMailScoped\YayCommerce\AdminShell\Pages\WooCommerceRequiredPage;
9 use YayMailScoped\YayCommerce\AdminShell\Support\AdminContext;
10 /**
11 * Registers a plugin-named submenu under YayCommerce.
12 * Works with any PluginMenuAdapter (lite or pro).
13 *
14 * For pro plugins: automatically redirects to Licenses page when license
15 * is not active — no developer action needed.
16 */
17 class PluginSubmenu
18 {
19 private PluginMenuAdapter $adapter;
20 public function __construct(PluginMenuAdapter $adapter)
21 {
22 $this->adapter = $adapter;
23 }
24 public function init(): void
25 {
26 // Bound to both hooks; the context gate in register() decides whether the
27 // plugin actually registers in the current (site vs network) context.
28 AdminContext::bind_menu([$this, 'register'], 10);
29 }
30 public function register(): void
31 {
32 // Context gate: register only where the plugin opted in. Network Admin
33 // requires wants_network_menu(); site dashboard requires wants_site_menu().
34 // Defaults (legacy adapters): site=true, network=false.
35 if (AdminContext::is_network()) {
36 if (!AdminContext::wants_network($this->adapter)) {
37 return;
38 }
39 } elseif (!AdminContext::wants_site($this->adapter)) {
40 return;
41 }
42 $menu_slug = $this->adapter->get_menu_slug();
43 if (empty($menu_slug)) {
44 return;
45 }
46 global $submenu;
47 $has_menu = \false;
48 $is_override = \false;
49 if (isset($submenu['yaycommerce'])) {
50 $yaycommerce_menu = $submenu['yaycommerce'];
51 foreach ($yaycommerce_menu as $key => $value) {
52 if ($value[2] === $menu_slug) {
53 if (method_exists($this->adapter, 'is_licensed') && $this->adapter->is_licensed() || !method_exists($this->adapter, 'is_licensed')) {
54 remove_submenu_page('yaycommerce', $menu_slug);
55 $is_override = \true;
56 } else {
57 $has_menu = \true;
58 }
59 break;
60 }
61 }
62 }
63 if ($has_menu) {
64 return;
65 }
66 $callback = $this->adapter->get_settings_page_callback();
67 // Guard: ensure callback is actually callable
68 if (null !== $callback && !is_callable($callback)) {
69 $callback = null;
70 }
71 // Pro plugins without active license → override callback to redirect
72 $needs_redirect = \false;
73 if ($this->adapter instanceof LicenseConfigAdapter) {
74 $license = new License($this->adapter);
75 if (!$license->is_active()) {
76 $needs_redirect = \true;
77 $callback = null;
78 }
79 }
80 // WooCommerce dependency gate: when the plugin depends on WooCommerce and it
81 // is inactive, render the shared "install WooCommerce" screen in place of the
82 // settings page. Applied only on the real render path — the license redirect
83 // above takes precedence, so unlicensed pro plugins still land on Licenses.
84 // Opt-in via the optional needs_woocommerce_screen() adapter method; the
85 // adapter owns the runtime WooCommerce check so it runs un-prefixed under
86 // PHP-Scoper (the adapter class is excluded from scoping in each plugin).
87 if (!$needs_redirect && method_exists($this->adapter, 'needs_woocommerce_screen') && $this->adapter->needs_woocommerce_screen()) {
88 $screen_copy = method_exists($this->adapter, 'get_woocommerce_screen_copy') ? (array) $this->adapter->get_woocommerce_screen_copy() : [];
89 $callback = static function () use ($screen_copy) {
90 WooCommerceRequiredPage::render($screen_copy);
91 };
92 }
93 $page_id = add_submenu_page(
94 'yaycommerce',
95 $this->adapter->get_page_title(),
96 $this->adapter->get_menu_title(),
97 // In Network Admin, elevate to manage_network (super-admin only).
98 AdminContext::capability($this->adapter->get_capability()),
99 $menu_slug,
100 $callback ?? '__return_false',
101 // Position intentionally null here. WP treats add_submenu_page()'s
102 // $position as a fragile array insertion index, not an ordering rank.
103 // Final ordering is applied later by SubmenuPositioner, which reorders
104 // the assembled $submenu['yaycommerce'] from the shared position map.
105 null
106 );
107 if ($is_override) {
108 remove_all_actions('load-' . $page_id);
109 }
110 if ($needs_redirect) {
111 add_action('load-' . $page_id, [__CLASS__, 'redirect_to_licenses']);
112 }
113 }
114 public static function redirect_to_licenses(): void
115 {
116 // The load hook fires in the current context — target the matching dashboard
117 // so a network-flagged pro plugin redirects within Network Admin, not the site.
118 $path = 'admin.php?page=yaycommerce-licenses';
119 $url = AdminContext::is_network() ? network_admin_url($path) : admin_url($path);
120 wp_safe_redirect($url);
121 exit;
122 }
123 }
124