PluginProbe
YayMail – WooCommerce Email Customizer / 4.4.5
YayMail – WooCommerce Email Customizer v4.4.5
4.4.6 4.4.5 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 All 57 releases
← All changes | vendor-prefixed/src/Menu/PluginSubmenu.php +22 -9 4.4.2 → 4.4.5 View file →
@@ -4,8 +4,9 @@
4 4
5 5 use YayMailScoped\YayCommerce\AdminShell\Contracts\PluginMenuAdapter;
6 6 use YayMailScoped\YayCommerce\AdminShell\License\Contracts\LicenseConfigAdapter;
7 7 use YayMailScoped\YayCommerce\AdminShell\License\License;
8 +use YayMailScoped\YayCommerce\AdminShell\Pages\WooCommerceRequiredPage;
8 9 use YayMailScoped\YayCommerce\AdminShell\Support\AdminContext;
9 10 /**
10 11 * Registers a plugin-named submenu under YayCommerce.
11 12 * Works with any PluginMenuAdapter (lite or pro).
@@ -11,9 +12,8 @@
11 12 * Works with any PluginMenuAdapter (lite or pro).
12 13 *
13 14 * For pro plugins: automatically redirects to Licenses page when license
14 15 * is not active — no developer action needed.
15 - * @internal
16 16 */
17 17 class PluginSubmenu
18 18 {
19 19 private PluginMenuAdapter $adapter;
@@ -20,15 +20,15 @@
20 20 public function __construct(PluginMenuAdapter $adapter)
21 21 {
22 22 $this->adapter = $adapter;
23 23 }
24 - public function init() : void
24 + public function init(): void
25 25 {
26 26 // Bound to both hooks; the context gate in register() decides whether the
27 27 // plugin actually registers in the current (site vs network) context.
28 28 AdminContext::bind_menu([$this, 'register'], 10);
29 29 }
30 - public function register() : void
30 + public function register(): void
31 31 {
32 32 // Context gate: register only where the plugin opted in. Network Admin
33 33 // requires wants_network_menu(); site dashboard requires wants_site_menu().
34 34 // Defaults (legacy adapters): site=true, network=false.
@@ -49,9 +49,9 @@
49 49 if (isset($submenu['yaycommerce'])) {
50 50 $yaycommerce_menu = $submenu['yaycommerce'];
51 51 foreach ($yaycommerce_menu as $key => $value) {
52 52 if ($value[2] === $menu_slug) {
53 - if (\method_exists($this->adapter, 'is_licensed') && $this->adapter->is_licensed() || !\method_exists($this->adapter, 'is_licensed')) {
53 + if (method_exists($this->adapter, 'is_licensed') && $this->adapter->is_licensed() || !method_exists($this->adapter, 'is_licensed')) {
54 54 remove_submenu_page('yaycommerce', $menu_slug);
55 55 $is_override = \true;
56 56 } else {
57 57 $has_menu = \true;
@@ -64,9 +64,9 @@
64 64 return;
65 65 }
66 66 $callback = $this->adapter->get_settings_page_callback();
67 67 // Guard: ensure callback is actually callable
68 - if (null !== $callback && !\is_callable($callback)) {
68 + if (null !== $callback && !is_callable($callback)) {
69 69 $callback = null;
70 70 }
71 71 // Pro plugins without active license → override callback to redirect
72 72 $needs_redirect = \false;
@@ -71,13 +71,26 @@
71 71 // Pro plugins without active license → override callback to redirect
72 72 $needs_redirect = \false;
73 73 if ($this->adapter instanceof LicenseConfigAdapter) {
74 74 $license = new License($this->adapter);
75 - if (!$license->is_active() || $license->is_expired()) {
75 + if (!$license->is_active()) {
76 76 $needs_redirect = \true;
77 77 $callback = null;
78 78 }
79 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 + }
80 93 $page_id = add_submenu_page(
81 94 'yaycommerce',
82 95 $this->adapter->get_page_title(),
83 96 $this->adapter->get_menu_title(),
@@ -91,20 +104,20 @@
91 104 // the assembled $submenu['yaycommerce'] from the shared position map.
92 105 null
93 106 );
94 107 if ($is_override) {
95 - \remove_all_actions('load-' . $page_id);
108 + remove_all_actions('load-' . $page_id);
96 109 }
97 110 if ($needs_redirect) {
98 111 add_action('load-' . $page_id, [__CLASS__, 'redirect_to_licenses']);
99 112 }
100 113 }
101 - public static function redirect_to_licenses() : void
114 + public static function redirect_to_licenses(): void
102 115 {
103 116 // The load hook fires in the current context — target the matching dashboard
104 117 // so a network-flagged pro plugin redirects within Network Admin, not the site.
105 118 $path = 'admin.php?page=yaycommerce-licenses';
106 - $url = AdminContext::is_network() ? network_admin_url($path) : \admin_url($path);
119 + $url = AdminContext::is_network() ? network_admin_url($path) : admin_url($path);
107 120 wp_safe_redirect($url);
108 121 exit;
109 122 }
110 123 }