PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.3.8
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.3.8
2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.2 2.1.3 2.1.4 All 55 releases
easy-invoice / includes / Controllers / AddonsController.php

AddonsController.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.3.8, at includes/Controllers/AddonsController.php

188 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Addons admin page controller + AJAX toggle endpoint.
4 *
5 * @package EasyInvoice
6 */
7
8 namespace EasyInvoice\Controllers;
9
10 use EasyInvoice\Addons\AddonManager;
11 use EasyInvoice\Addons\AddonRegistry;
12 use EasyInvoice\Addons\LicensePlanResolver;
13
14 if (!defined('ABSPATH')) {
15 exit;
16 }
17
18 class AddonsController {
19
20 public const PAGE_SLUG = 'easy-invoice-addons';
21 public const NONCE = 'easy_invoice_addons_nonce';
22
23 public function init(): void {
24 add_action('wp_ajax_easy_invoice_toggle_addon', [$this, 'ajaxToggleAddon']);
25 add_action('admin_enqueue_scripts', [$this, 'enqueueAssets']);
26 }
27
28 /**
29 * Page renderer (called by EasyInvoiceAdmin::mainPageContent).
30 */
31 public function display(): void {
32 if (!current_user_can('manage_options')) {
33 wp_die(__('Sorry, you are not allowed to access this page.', 'easy-invoice'));
34 }
35
36 $addons = AddonRegistry::all();
37 $current_plan = LicensePlanResolver::getCurrentPlan();
38 $upgrade_urls = [
39 LicensePlanResolver::PLAN_PROFESSIONAL => 'https://matrixaddons.com/plugins/easy-invoice/#pricing',
40 LicensePlanResolver::PLAN_AGENCY => 'https://matrixaddons.com/plugins/easy-invoice/#pricing',
41 ];
42
43 // License banner state — surfaced below the page header instead of via
44 // wp-admin's global admin_notices (which would appear ABOVE the header).
45 $license_banner = $this->resolveLicenseBanner($current_plan);
46
47 include EASY_INVOICE_PLUGIN_DIR . 'templates/admin/addons-page.php';
48 }
49
50 /**
51 * Decide whether to show a contextual license banner inside the addons page.
52 *
53 * @return array{type:string,title:string,message:string,cta_label:string,cta_url:string}|null
54 */
55 private function resolveLicenseBanner(string $current_plan): ?array {
56 // No Pro plugin installed → encourage upgrade to unlock any addon.
57 if (!function_exists('easy_invoice_has_pro') || !easy_invoice_has_pro()) {
58 return [
59 'type' => 'info',
60 'title' => __('You\'re on the Free version.', 'easy-invoice'),
61 'message' => __('These addons require Easy Invoice Pro. Install Pro to unlock Personal-tier addons — recurring invoices, client portal, reports, item library, partial payments, and more — included at no extra cost. Activate a license key to enable Professional and Agency tiers.', 'easy-invoice'),
62 'cta_label' => __('Get Easy Invoice Pro', 'easy-invoice'),
63 'cta_url' => 'https://matrixaddons.com/plugins/easy-invoice/#pricing',
64 ];
65 }
66
67 // Pro plugin is installed. Personal is granted without a license
68 // (entry-level tier). A license unlocks Professional / Agency.
69 $has_valid = class_exists('\\EasyInvoicePro\\Updater\\License')
70 && \EasyInvoicePro\Updater\License::has_valid_license();
71
72 if (!$has_valid) {
73 // Pro installed but no license — Personal-tier addons are
74 // already usable. Surface an "Activate License" CTA so the
75 // merchant knows higher tiers exist.
76 return [
77 'type' => 'info',
78 'title' => __('You\'re on the Personal plan.', 'easy-invoice'),
79 'message' => __('All Personal-tier addons are unlocked. Activate your Easy Invoice Pro license to enable Professional and Agency addons.', 'easy-invoice'),
80 'cta_label' => __('Activate License', 'easy-invoice'),
81 'cta_url' => admin_url('admin.php?page=easy-invoice-license'),
82 ];
83 }
84
85 // License is valid but a lower tier than the addons that exist — soft suggestion.
86 if ($current_plan === LicensePlanResolver::PLAN_PROFESSIONAL) {
87 return [
88 'type' => 'info',
89 'title' => __('You\'re on the Professional plan.', 'easy-invoice'),
90 'message' => __('Upgrade to Agency to unlock Agency-tier addons like White-Label.', 'easy-invoice'),
91 'cta_label' => __('See Agency plan', 'easy-invoice'),
92 'cta_url' => 'https://matrixaddons.com/plugins/easy-invoice/#pricing',
93 ];
94 }
95
96 return null; // All good — no banner.
97 }
98
99 /**
100 * AJAX: toggle a single addon on/off.
101 *
102 * Expects POST: addon_id (string), enabled (0|1), _nonce.
103 */
104 public function ajaxToggleAddon(): void {
105 check_ajax_referer(self::NONCE, '_nonce');
106
107 if (!current_user_can('manage_options')) {
108 wp_send_json_error([
109 'code' => 'forbidden',
110 'message' => __('Permission denied.', 'easy-invoice'),
111 ], 403);
112 }
113
114 $addon_id = isset($_POST['addon_id']) ? sanitize_key($_POST['addon_id']) : '';
115 $enabled = !empty($_POST['enabled']);
116
117 if ($addon_id === '') {
118 wp_send_json_error([
119 'code' => 'missing_addon_id',
120 'message' => __('Addon ID is required.', 'easy-invoice'),
121 ], 400);
122 }
123
124 $result = $enabled
125 ? AddonManager::enable($addon_id)
126 : AddonManager::disable($addon_id);
127
128 if (!$result['success']) {
129 $payload = [
130 'code' => $result['code'],
131 'message' => $result['message'],
132 ];
133 if (!empty($result['required_plan'])) {
134 $payload['required_plan'] = $result['required_plan'];
135 $payload['required_plan_label'] = LicensePlanResolver::getPlanLabel($result['required_plan']);
136 $payload['upgrade_url'] = $this->upgradeUrlFor($result['required_plan']);
137 }
138 wp_send_json_error($payload, 200); // 200 — payload tells client what to do
139 }
140
141 wp_send_json_success([
142 'code' => $result['code'],
143 'message' => $result['message'],
144 'status' => AddonManager::statusFor($addon_id),
145 ]);
146 }
147
148 private function upgradeUrlFor(string $plan): string {
149 $base = 'https://matrixaddons.com/plugins/easy-invoice/#pricing';
150 return add_query_arg([
151 'plan' => $plan,
152 'discount' => 'EIEARLYBIRD',
153 'utm_source' => 'easy-invoice-plugin',
154 'utm_medium' => 'addons-page',
155 'utm_campaign' => 'addon-upgrade',
156 ], $base);
157 }
158
159 public function enqueueAssets(string $hook): void {
160 $current_page = isset($_GET['page']) ? sanitize_text_field($_GET['page']) : '';
161 if ($current_page !== self::PAGE_SLUG) {
162 return;
163 }
164
165 // Page chrome (sidebar, layout) comes from Easy Invoice's existing Tailwind UI;
166 // we only need the toggle/upgrade JS for this page.
167 wp_enqueue_script(
168 'easy-invoice-addons-page',
169 EASY_INVOICE_PLUGIN_URL . 'assets/js/addons-page.js',
170 ['jquery'],
171 EASY_INVOICE_VERSION,
172 true
173 );
174
175 wp_localize_script('easy-invoice-addons-page', 'EasyInvoiceAddons', [
176 'ajaxUrl' => admin_url('admin-ajax.php'),
177 'nonce' => wp_create_nonce(self::NONCE),
178 'strings' => [
179 'enabling' => __('Enabling…', 'easy-invoice'),
180 'disabling' => __('Disabling…', 'easy-invoice'),
181 'enableError' => __('Could not enable this addon.', 'easy-invoice'),
182 'disableError' => __('Could not disable this addon.', 'easy-invoice'),
183 'genericError' => __('Something went wrong. Please try again.', 'easy-invoice'),
184 ],
185 ]);
186 }
187 }
188