| 1 |
<?php |
| 2 |
/** |
| 3 |
* Catalogue of available Easy Invoice addons. |
| 4 |
* |
| 5 |
* The Free plugin owns the metadata so the Addons page renders even when Pro |
| 6 |
* is inactive. The Pro plugin owns the executable code at the `pro_file` path. |
| 7 |
* |
| 8 |
* @package EasyInvoice |
| 9 |
*/ |
| 10 |
|
| 11 |
namespace EasyInvoice\Addons; |
| 12 |
|
| 13 |
if (!defined('ABSPATH')) { |
| 14 |
exit; |
| 15 |
} |
| 16 |
|
| 17 |
class AddonRegistry { |
| 18 |
|
| 19 |
/** |
| 20 |
* @return array<int,array<string,mixed>> |
| 21 |
*/ |
| 22 |
public static function all(): array { |
| 23 |
return apply_filters('easy_invoice_addons_registry', [ |
| 24 |
|
| 25 |
// ─── PROFESSIONAL ───────────────────────────────────────────── |
| 26 |
[ |
| 27 |
'id' => 'time_tracking', |
| 28 |
'name' => __('Time Tracking & Project Billing', 'easy-invoice'), |
| 29 |
'short_name' => __('Time Tracking', 'easy-invoice'), |
| 30 |
'tagline' => __('Track billable hours and convert them to invoice lines in one click.', 'easy-invoice'), |
| 31 |
'description' => __('Built-in start/stop timer with per-project and per-client entries. Convert any block of tracked time into invoice line items in one click — replaces your standalone time-tracking tool.', 'easy-invoice'), |
| 32 |
'plan' => LicensePlanResolver::PLAN_PROFESSIONAL, |
| 33 |
'icon' => 'dashicons-clock', |
| 34 |
'category' => 'productivity', |
| 35 |
'badge' => 'popular', |
| 36 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/time-tracking/', |
| 37 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-time-tracking'), |
| 38 |
'pro_class' => 'EasyInvoicePro\\Addons\\TimeTracking\\TimeTracking', |
| 39 |
], |
| 40 |
|
| 41 |
[ |
| 42 |
'id' => 'expense_tracking', |
| 43 |
'name' => __('Expense Tracking & Reimbursable Items', 'easy-invoice'), |
| 44 |
'short_name' => __('Expenses', 'easy-invoice'), |
| 45 |
'tagline' => __('Log billable expenses, mark them up, and convert to invoice lines in one click.', 'easy-invoice'), |
| 46 |
'description' => __('Track project expenses (software, mileage, materials, contractor costs) with receipt uploads. Apply markup and roll selected expenses into invoice line items — the same pattern as Time Tracking, for everything that isn\'t billable hours.', 'easy-invoice'), |
| 47 |
'plan' => LicensePlanResolver::PLAN_PROFESSIONAL, |
| 48 |
'icon' => 'dashicons-money', |
| 49 |
'category' => 'billing', |
| 50 |
'badge' => 'new', |
| 51 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/expense-tracking/', |
| 52 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-expense-tracking'), |
| 53 |
'pro_class' => 'EasyInvoicePro\\Addons\\ExpenseTracking\\ExpenseTracking', |
| 54 |
], |
| 55 |
|
| 56 |
[ |
| 57 |
'id' => 'dunning', |
| 58 |
'name' => __('Smart Reminders & Late Fees', 'easy-invoice'), |
| 59 |
'short_name' => __('Smart Reminders', 'easy-invoice'), |
| 60 |
'tagline' => __('Recover overdue invoices automatically — without the awkward chase emails.', 'easy-invoice'), |
| 61 |
'description' => __('Configure a multi-step reminder cadence with per-step templates that escalate in tone. Auto-apply late fees and offer early-payment discounts — typically recovers 30%+ of overdue invoices.', 'easy-invoice'), |
| 62 |
'plan' => LicensePlanResolver::PLAN_PROFESSIONAL, |
| 63 |
'icon' => 'dashicons-email-alt', |
| 64 |
'category' => 'billing', |
| 65 |
'badge' => null, |
| 66 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/smart-reminders/', |
| 67 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-dunning'), |
| 68 |
'pro_class' => 'EasyInvoicePro\\Addons\\SmartReminders\\SmartReminders', |
| 69 |
], |
| 70 |
|
| 71 |
// ─── AGENCY ─────────────────────────────────────────────────── |
| 72 |
[ |
| 73 |
'id' => 'white_label', |
| 74 |
'name' => __('White-Label & Brand Override', 'easy-invoice'), |
| 75 |
'short_name' => __('White-Label', 'easy-invoice'), |
| 76 |
'tagline' => __('Rebrand Easy Invoice as your own product — every label, footer, and PDF.', 'easy-invoice'), |
| 77 |
'description' => __('Replace the plugin name, admin menu, dashboard icon, PDF footer, and email signature with your own brand. Hide every upgrade prompt — essential for agencies reselling Easy Invoice as a managed service.', 'easy-invoice'), |
| 78 |
'plan' => LicensePlanResolver::PLAN_AGENCY, |
| 79 |
'icon' => 'dashicons-businesswoman', |
| 80 |
'category' => 'branding', |
| 81 |
'badge' => 'new', |
| 82 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/white-label/', |
| 83 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-white-label'), |
| 84 |
'pro_class' => 'EasyInvoicePro\\Addons\\WhiteLabel\\WhiteLabel', |
| 85 |
], |
| 86 |
|
| 87 |
[ |
| 88 |
'id' => 'team_roles', |
| 89 |
'name' => __('Team Members & Audit Log', 'easy-invoice'), |
| 90 |
'short_name' => __('Team & Audit', 'easy-invoice'), |
| 91 |
'tagline' => __('Invite staff with scoped roles. See who did what, when, and why.', 'easy-invoice'), |
| 92 |
'description' => __('Scoped roles (Manager / Accountant / Sales / Viewer) so staff can work without touching refunds or settings. Every action lands in a searchable audit log — required for compliance and accountant hand-offs.', 'easy-invoice'), |
| 93 |
'plan' => LicensePlanResolver::PLAN_AGENCY, |
| 94 |
'icon' => 'dashicons-groups', |
| 95 |
'category' => 'team', |
| 96 |
'badge' => 'new', |
| 97 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/team-roles/', |
| 98 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-team-roles'), |
| 99 |
'pro_class' => 'EasyInvoicePro\\Addons\\TeamRoles\\TeamRoles', |
| 100 |
], |
| 101 |
|
| 102 |
[ |
| 103 |
'id' => 'accounting_sync', |
| 104 |
'name' => __('Accounting Sync (QuickBooks / Xero / FreshBooks)', 'easy-invoice'), |
| 105 |
'short_name' => __('Accounting Sync', 'easy-invoice'), |
| 106 |
'tagline' => __('Two-way sync with QuickBooks Online, Xero, and FreshBooks — invoices out, payments back.', 'easy-invoice'), |
| 107 |
'description' => __('Push invoices to your accounting tool when created; pull payment status back when reconciled there. Chart-of-accounts mapping, customer mirroring, and bank-rec friendly. Pluggable provider layer for QBO, Xero, FreshBooks (and adding more).', 'easy-invoice'), |
| 108 |
'plan' => LicensePlanResolver::PLAN_AGENCY, |
| 109 |
'icon' => 'dashicons-update-alt', |
| 110 |
'category' => 'integrations', |
| 111 |
'badge' => 'new', |
| 112 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/accounting-sync/', |
| 113 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-accounting-sync'), |
| 114 |
'pro_class' => 'EasyInvoicePro\\Addons\\AccountingSync\\AccountingSync', |
| 115 |
], |
| 116 |
|
| 117 |
[ |
| 118 |
'id' => 'webhooks', |
| 119 |
'name' => __('Webhooks & Zapier Bridge', 'easy-invoice'), |
| 120 |
'short_name' => __('Webhooks', 'easy-invoice'), |
| 121 |
'tagline' => __('Push invoice events into Zapier, your CRM, Slack — anywhere with a URL.', 'easy-invoice'), |
| 122 |
'description' => __('Subscribe any URL to invoice events (paid, accepted, failed, recurring run). HMAC-SHA256 signed payloads, automatic retries. Drops into Zapier, Make, n8n, your CRM — connect to 5,000+ tools.', 'easy-invoice'), |
| 123 |
'plan' => LicensePlanResolver::PLAN_AGENCY, |
| 124 |
'icon' => 'dashicons-rest-api', |
| 125 |
'category' => 'integrations', |
| 126 |
'badge' => 'new', |
| 127 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/webhooks/', |
| 128 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-webhooks'), |
| 129 |
'pro_class' => 'EasyInvoicePro\\Addons\\Webhooks\\Webhooks', |
| 130 |
], |
| 131 |
|
| 132 |
// ─── PRO-FEATURE ADDONS (migrated from monolithic Pro plugin) ──── |
| 133 |
// |
| 134 |
// These ten addons wrap features that previously loaded |
| 135 |
// unconditionally inside easy-invoice-pro.php. They're enabled |
| 136 |
// by default on EXISTING installs via the migration in |
| 137 |
// ProAddonMigration::migrate(), and disabled by default on |
| 138 |
// FRESH installs so new users can opt in only to what they need. |
| 139 |
// |
| 140 |
// None of these have settings pages of their own (they reuse |
| 141 |
// existing Pro settings pages); the Addons grid only exposes |
| 142 |
// the enable/disable toggle. The settings_url field points at |
| 143 |
// the closest relevant settings tab. |
| 144 |
|
| 145 |
[ |
| 146 |
'id' => 'recurring_invoices', |
| 147 |
'name' => __('Recurring Invoices & Subscriptions', 'easy-invoice'), |
| 148 |
'short_name' => __('Recurring', 'easy-invoice'), |
| 149 |
'tagline' => __('Auto-bill clients on autopilot — weekly, monthly, or any custom schedule.', 'easy-invoice'), |
| 150 |
'description' => __('Set the frequency, end date, and payment method once; Easy Invoice generates and sends each invoice on schedule. Optional auto-charge through your gateway closes the loop — predictable revenue, zero admin.', 'easy-invoice'), |
| 151 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 152 |
'icon' => 'dashicons-update', |
| 153 |
'category' => 'billing', |
| 154 |
'badge' => null, |
| 155 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/recurring-invoices/', |
| 156 |
// No dedicated settings page. Recurring data lives as |
| 157 |
// post-meta on regular easy_invoice posts (META_ENABLED, |
| 158 |
// META_FREQUENCY, etc. in RecurringInvoices.php) — the |
| 159 |
// merchant toggles "Make this recurring" on the invoice |
| 160 |
// editor. The legacy easy_invoice_recurring CPT was |
| 161 |
// registered with show_in_menu=false + create_posts= |
| 162 |
// do_not_allow, so linking to its list page from the |
| 163 |
// addon card just dumped users on a WP-styled, read-only, |
| 164 |
// dead-end screen. Empty settings_url hides that link. |
| 165 |
'settings_url' => admin_url('admin.php?page=easy-invoice-settings§ion=invoice'), |
| 166 |
'pro_class' => 'EasyInvoicePro\\Addons\\RecurringInvoices\\RecurringInvoices', |
| 167 |
], |
| 168 |
[ |
| 169 |
'id' => 'partial_payments', |
| 170 |
'name' => __('Partial Payments & Deposits', 'easy-invoice'), |
| 171 |
'short_name' => __('Partial Payments', 'easy-invoice'), |
| 172 |
'tagline' => __('Get paid sooner with deposits and flexible installment plans.', 'easy-invoice'), |
| 173 |
'description' => __('Require a deposit (% or flat) before work begins, then let clients pay the balance in installments. Tracks every part-payment and shows the running balance — no spreadsheets, no manual reconciliation.', 'easy-invoice'), |
| 174 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 175 |
'icon' => 'dashicons-money-alt', |
| 176 |
'category' => 'billing', |
| 177 |
'badge' => null, |
| 178 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/partial-payments/', |
| 179 |
// PartialPaymentsSettingsController appends its fields to the |
| 180 |
// main Settings page via the easy_invoice_settings_fields_config |
| 181 |
// filter — no dedicated page slug. Leave settings_url empty |
| 182 |
// so the addon card doesn't render a misleading "Settings →" |
| 183 |
// link that just dumps the user on the main Settings page. |
| 184 |
'settings_url' => admin_url('admin.php?page=easy-invoice-settings§ion=invoice'), |
| 185 |
'pro_class' => 'EasyInvoicePro\\Addons\\PartialPayments\\PartialPayments', |
| 186 |
], |
| 187 |
[ |
| 188 |
'id' => 'client_portal', |
| 189 |
'name' => __('Client Portal', 'easy-invoice'), |
| 190 |
'short_name' => __('Client Portal', 'easy-invoice'), |
| 191 |
'tagline' => __('Give clients a branded self-service area for invoices, quotes, and receipts.', 'easy-invoice'), |
| 192 |
'description' => __('Clients log in to a branded portal to view invoices, download PDFs, see payment history, and accept or decline quotes — on their own time. Stops the back-and-forth email asking for old documents.', 'easy-invoice'), |
| 193 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 194 |
'icon' => 'dashicons-admin-users', |
| 195 |
'category' => 'clients', |
| 196 |
'badge' => null, |
| 197 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/client-portal/', |
| 198 |
'settings_url' => admin_url('admin.php?page=easy-invoice-settings§ion=client_portal'), |
| 199 |
'pro_class' => 'EasyInvoicePro\\Addons\\ClientPortal\\ClientPortal', |
| 200 |
], |
| 201 |
[ |
| 202 |
'id' => 'pdf_toolkit', |
| 203 |
'name' => __('PDF Toolkit', 'easy-invoice'), |
| 204 |
'short_name' => __('PDF Toolkit', 'easy-invoice'), |
| 205 |
'tagline' => __('Stamp your invoices and quotes with a custom watermark.', 'easy-invoice'), |
| 206 |
// Describes what the addon actually offers. It previously advertised |
| 207 |
// "custom headers and footers" and "color and font controls": those are |
| 208 |
// not implemented and not exposed anywhere in its settings. The handlers |
| 209 |
// for them hang off six `easy_invoice_pdf_*` filters that nothing in |
| 210 |
// either plugin ever fires, because PDFs are rendered in the browser |
| 211 |
// from the document view rather than by a server-side pipeline there |
| 212 |
// would be something to hook. Headers, footers and font control need |
| 213 |
// that server-side renderer first. The watermark is real: it is drawn |
| 214 |
// into the document view, which is what the PDF is rasterised from. |
| 215 |
'description' => __('Watermark your invoices and quotes — text or image, with control over the wording, colour, size and opacity. Use it to stamp PAID, DRAFT, OVERDUE or VOID across a document, or to drop your logo behind the content.', 'easy-invoice'), |
| 216 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 217 |
'icon' => 'dashicons-pdf', |
| 218 |
'category' => 'branding', |
| 219 |
'badge' => null, |
| 220 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/pdf-toolkit/', |
| 221 |
// PdfCustomizationSettingsController appends fields to the |
| 222 |
// main Settings page via filter; no dedicated slug. Empty |
| 223 |
// settings_url hides the misleading "Settings →" link. |
| 224 |
'settings_url' => admin_url('admin.php?page=easy-invoice-settings§ion=invoice'), |
| 225 |
'pro_class' => 'EasyInvoicePro\\Addons\\PdfToolkit\\PdfToolkit', |
| 226 |
], |
| 227 |
[ |
| 228 |
'id' => 'bulk_operations', |
| 229 |
'name' => __('Bulk Email & Export', 'easy-invoice'), |
| 230 |
'short_name' => __('Bulk Ops', 'easy-invoice'), |
| 231 |
'tagline' => __('Send and export hundreds of invoices in a single click.', 'easy-invoice'), |
| 232 |
'description' => __('Bulk actions on every list screen — email batches of invoices in one click, or export selected rows to CSV, Excel, or PDF. \"Export All\" downloads your entire history, perfect for year-end accounting.', 'easy-invoice'), |
| 233 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 234 |
'icon' => 'dashicons-download', |
| 235 |
'category' => 'productivity', |
| 236 |
'badge' => null, |
| 237 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/bulk-operations/', |
| 238 |
// The addon does own a screen — Export Data. Leaving this empty meant |
| 239 |
// the Addons card offered no way into it, and, more importantly, the |
| 240 |
// admin dispatcher uses this list to recognise addon-owned slugs: with |
| 241 |
// no entry it fell through and painted the Dashboard, then the export |
| 242 |
// form rendered underneath it (the "two pages stacked" case the |
| 243 |
// dispatcher's default branch warns about). |
| 244 |
'settings_url' => admin_url('admin.php?page=easy-invoice-export'), |
| 245 |
'pro_class' => 'EasyInvoicePro\\Addons\\BulkOperations\\BulkOperations', |
| 246 |
], |
| 247 |
[ |
| 248 |
'id' => 'item_library', |
| 249 |
'name' => __('Item Library', 'easy-invoice'), |
| 250 |
'short_name' => __('Item Library', 'easy-invoice'), |
| 251 |
'tagline' => __('Build a reusable catalog of services and products.', 'easy-invoice'), |
| 252 |
'description' => __('Save your common services and products with name, description, price, and SKU. Insert into any invoice or quote in one click — stop retyping and keep pricing consistent across every document.', 'easy-invoice'), |
| 253 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 254 |
'icon' => 'dashicons-products', |
| 255 |
'category' => 'productivity', |
| 256 |
'badge' => null, |
| 257 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/item-library/', |
| 258 |
// Verified slug: ItemLibraryController::addAdminMenu() |
| 259 |
// registers 'easy-invoice-pro-item-library'. |
| 260 |
'settings_url' => admin_url('admin.php?page=easy-invoice-pro-item-library'), |
| 261 |
'pro_class' => 'EasyInvoicePro\\Addons\\ItemLibrary\\ItemLibrary', |
| 262 |
], |
| 263 |
[ |
| 264 |
'id' => 'custom_templates', |
| 265 |
'name' => __('Custom Invoice & Quote Templates', 'easy-invoice'), |
| 266 |
'short_name' => __('Templates', 'easy-invoice'), |
| 267 |
'tagline' => __('Design pixel-perfect invoice and quote layouts with a drag-and-drop builder.', 'easy-invoice'), |
| 268 |
'description' => __('Build your own invoice and quote layouts with the visual editor — drag in logos, company info, item tables, totals, signatures, and footers. Save multiple templates and assign different layouts per client.', 'easy-invoice'), |
| 269 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 270 |
'icon' => 'dashicons-layout', |
| 271 |
'category' => 'branding', |
| 272 |
'badge' => null, |
| 273 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/custom-templates/', |
| 274 |
// Verified slug: TemplateBuilderController registers |
| 275 |
// 'easy-invoice-templates' (the listing) — that's the |
| 276 |
// canonical entry point. settings_url here is used by |
| 277 |
// the per-addon sidebar loop in main-template.php to |
| 278 |
// render a sidebar entry BELOW the Addons menu. The |
| 279 |
// addons-page.php card does NOT render a "Settings →" |
| 280 |
// link anymore (the sidebar is the navigation). |
| 281 |
'settings_url' => admin_url('admin.php?page=easy-invoice-templates'), |
| 282 |
'pro_class' => 'EasyInvoicePro\\Addons\\CustomTemplates\\CustomTemplates', |
| 283 |
], |
| 284 |
[ |
| 285 |
'id' => 'additional_tax', |
| 286 |
'name' => __('Additional Tax Lines', 'easy-invoice'), |
| 287 |
'short_name' => __('Additional Tax', 'easy-invoice'), |
| 288 |
'tagline' => __('Multiple tax lines per invoice — VAT + duty, GST + PST, federal + state.', 'easy-invoice'), |
| 289 |
'description' => __('Add unlimited named tax lines per invoice — VAT + duty, GST + PST, federal + state — each with its own rate. Renders every tax as a separate line on the PDF so clients see exactly what they\'re paying.', 'easy-invoice'), |
| 290 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 291 |
'icon' => 'dashicons-chart-bar', |
| 292 |
'category' => 'billing', |
| 293 |
'badge' => null, |
| 294 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/additional-tax/', |
| 295 |
// AdditionalTax extension appends "Enable Additional Tax" |
| 296 |
// + per-tax-rate fields via the main Settings page; no |
| 297 |
// dedicated slug → empty settings_url hides the |
| 298 |
// misleading "Settings →" link. |
| 299 |
'settings_url' => admin_url('admin.php?page=easy-invoice-settings§ion=tax'), |
| 300 |
'pro_class' => 'EasyInvoicePro\\Addons\\AdditionalTax\\AdditionalTax', |
| 301 |
], |
| 302 |
[ |
| 303 |
'id' => 'email_enhancements', |
| 304 |
'name' => __('Email Enhancements', 'easy-invoice'), |
| 305 |
'short_name' => __('Email Tools', 'easy-invoice'), |
| 306 |
'tagline' => __('Your own email layout, and a Reply-To per kind of email.', 'easy-invoice'), |
| 307 |
'description' => __('Wrap every email Easy Invoice sends in your own HTML layout, and route replies by kind — invoice questions to accounts, quote replies to sales, receipts and reminders wherever they belong.', 'easy-invoice'), |
| 308 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 309 |
'icon' => 'dashicons-email', |
| 310 |
'category' => 'productivity', |
| 311 |
'badge' => null, |
| 312 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/email-enhancements/', |
| 313 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-email-enhancements'), |
| 314 |
'pro_class' => 'EasyInvoicePro\\Addons\\EmailEnhancements\\EmailEnhancements', |
| 315 |
], |
| 316 |
[ |
| 317 |
'id' => 'secure_links', |
| 318 |
'name' => __('Secure Links for Invoices & Quotes', 'easy-invoice'), |
| 319 |
'short_name' => __('Secure Links', 'easy-invoice'), |
| 320 |
'tagline' => __('Share invoices and quotes with unguessable, signed URLs instead of plain post slugs.', 'easy-invoice'), |
| 321 |
'description' => __('Replace predictable invoice/quote permalinks with cryptographically signed, expiring URLs. Stops competitors and customers from incrementing IDs to view documents that aren\'t theirs. Already wired into emails, the [easy_invoice_links] shortcode, and recurring child invoices.', 'easy-invoice'), |
| 322 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 323 |
'icon' => 'dashicons-lock', |
| 324 |
'category' => 'compliance', |
| 325 |
'badge' => null, |
| 326 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/secure-links/', |
| 327 |
// Settings live inside Settings → Advanced, injected |
| 328 |
// by SecureLinks::registerAdvancedFields() (the same |
| 329 |
// pattern Payment Reminder uses for the Email tab). |
| 330 |
// The toggle there stays in lock-step with the |
| 331 |
// addon-enabled state via the addon's |
| 332 |
// update_option_* hooks. |
| 333 |
'settings_url' => admin_url('admin.php?page=easy-invoice-settings§ion=advanced'), |
| 334 |
'pro_class' => 'EasyInvoicePro\\Addons\\SecureLinks\\SecureLinks', |
| 335 |
], |
| 336 |
[ |
| 337 |
'id' => 'privacy_tools', |
| 338 |
'name' => __('Privacy & GDPR', 'easy-invoice'), |
| 339 |
'short_name' => __('Privacy', 'easy-invoice'), |
| 340 |
'tagline' => __('Comply with GDPR, CCPA, and other data-protection laws in one click.', 'easy-invoice'), |
| 341 |
'description' => __('Wires Easy Invoice into WordPress\'s Personal Data Export and Erase tools. Client invoice, quote, and payment history is included automatically in data-subject requests — required for EU and California compliance.', 'easy-invoice'), |
| 342 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 343 |
'icon' => 'dashicons-shield', |
| 344 |
'category' => 'compliance', |
| 345 |
'badge' => null, |
| 346 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/privacy-tools/', |
| 347 |
// The privacy_tools addon hooks WordPress's built-in |
| 348 |
// personal-data exporter / eraser registries — those |
| 349 |
// registries are managed by WP core under |
| 350 |
// Tools → Export/Erase Personal Data (a WP-native page, |
| 351 |
// not our UI). There is no addon-specific settings page |
| 352 |
// to surface from the addons grid, so leave settings_url |
| 353 |
// empty — the addon card just shows Active/Inactive. |
| 354 |
'settings_url' => '', |
| 355 |
'pro_class' => 'EasyInvoicePro\\Addons\\PrivacyTools\\PrivacyTools', |
| 356 |
], |
| 357 |
[ |
| 358 |
'id' => 'einvoicing', |
| 359 |
'name' => __('E-Invoicing (Factur-X / ZUGFeRD / Peppol UBL)', 'easy-invoice'), |
| 360 |
'short_name' => __('E-Invoicing', 'easy-invoice'), |
| 361 |
'tagline' => __('Issue and read the structured invoices now required across the EU.', 'easy-invoice'), |
| 362 |
'description' => __('Turn any invoice into Factur-X — a PDF your client can read with the EN 16931 machine-readable document carried inside it — or into Peppol BIS 3.0 UBL, which is what Belgium, the Netherlands and the Peppol network run on. Your customer\'s country decides which. Also opens incoming Factur-X, ZUGFeRD, CII and UBL invoices from your suppliers, which is the obligation that lands first: France requires every VAT-registered business to receive structured invoices from September 2026, Germany has since 2025. Produces the compliant file; sending stays with your own Peppol, KSeF or PDP provider.', 'easy-invoice'), |
| 363 |
'plan' => LicensePlanResolver::PLAN_PROFESSIONAL, |
| 364 |
'icon' => 'dashicons-media-code', |
| 365 |
'category' => 'compliance', |
| 366 |
'badge' => 'new', |
| 367 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/e-invoicing/', |
| 368 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-einvoicing'), |
| 369 |
'pro_class' => 'EasyInvoicePro\\Addons\\EInvoicing\\EInvoicing', |
| 370 |
], |
| 371 |
[ |
| 372 |
'id' => 'client_language', |
| 373 |
'name' => __('Client Language', 'easy-invoice'), |
| 374 |
// Sidebar label: the page it opens is the Translations screen. |
| 375 |
'short_name' => __('Translations', 'easy-invoice'), |
| 376 |
'tagline' => __('Each client gets invoices, PDFs and emails in their own language.', 'easy-invoice'), |
| 377 |
'description' => __('Set a language on the client record and every document for that client — the public page, the PDF, the emails — is produced in it, using the WordPress language pack and the per-language wording from the Translations screen. Invoice French, German and Italian clients from one site without three sites.', 'easy-invoice'), |
| 378 |
'plan' => LicensePlanResolver::PLAN_PROFESSIONAL, |
| 379 |
'icon' => 'dashicons-translation', |
| 380 |
'category' => 'clients', |
| 381 |
'badge' => 'new', |
| 382 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/client-language/', |
| 383 |
// The language is chosen on each client's record; the wording |
| 384 |
// per language lives on the Translations screen — that is the |
| 385 |
// one place this addon has settings of its own. |
| 386 |
'settings_url' => admin_url('admin.php?page=easy-invoice-pro-translations'), |
| 387 |
'settings_label' => __('Translations', 'easy-invoice'), |
| 388 |
'pro_class' => 'EasyInvoicePro\\Addons\\ClientLanguage\\ClientLanguage', |
| 389 |
], |
| 390 |
[ |
| 391 |
'id' => 'retainers', |
| 392 |
'name' => __('Retainers & Prepaid Credit', 'easy-invoice'), |
| 393 |
'short_name' => __('Retainers', 'easy-invoice'), |
| 394 |
'tagline' => __('Record a prepayment once; let invoices draw it down.', 'easy-invoice'), |
| 395 |
'description' => __('A monthly block of hours, a deposit that covers several small jobs, a negotiated prepayment: record it against the client and apply it to invoices as they come, by hand from the client record or automatically the moment an invoice is issued. Applied credit is an ordinary payment, so statements, reports and accounting sync all see money received, and the balance is always on the client record.', 'easy-invoice'), |
| 396 |
'plan' => LicensePlanResolver::PLAN_PROFESSIONAL, |
| 397 |
'icon' => 'dashicons-vault', |
| 398 |
'category' => 'billing', |
| 399 |
'badge' => 'new', |
| 400 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/retainers/', |
| 401 |
'settings_url' => admin_url('admin.php?page=easy-invoice-settings&tab=invoice'), |
| 402 |
'pro_class' => 'EasyInvoicePro\\Addons\\Retainers\\Retainers', |
| 403 |
], |
| 404 |
[ |
| 405 |
'id' => 'payment_links', |
| 406 |
'name' => __('Payment Links & QR Codes', 'easy-invoice'), |
| 407 |
'short_name' => __('Payment Links', 'easy-invoice'), |
| 408 |
'tagline' => __('Get paid from a link or a QR code — no invoice needed first.', 'easy-invoice'), |
| 409 |
'description' => __('Create a link for a fixed amount, or one where the payer enters the amount, and share it anywhere: an email signature, a social post, a printed QR code at the counter. The payer types their name and email, an invoice is created for them on the spot, and they pay it with any of your gateways — so receipts, the client record, reports and accounting sync all just work. Every link shows what it has collected.', 'easy-invoice'), |
| 410 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 411 |
'icon' => 'dashicons-admin-links', |
| 412 |
'category' => 'billing', |
| 413 |
'badge' => 'new', |
| 414 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/payment-links/', |
| 415 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-payment-links'), |
| 416 |
'pro_class' => 'EasyInvoicePro\\Addons\\PaymentLinks\\PaymentLinks', |
| 417 |
], |
| 418 |
[ |
| 419 |
'id' => 'quote_signatures', |
| 420 |
'name' => __('Quote E-Signatures', 'easy-invoice'), |
| 421 |
'short_name' => __('E-Signatures', 'easy-invoice'), |
| 422 |
'tagline' => __('Accepted means signed: a drawn signature, name, time and address on every approval.', 'easy-invoice'), |
| 423 |
'description' => __('When a client accepts a quote they sign it — drawn with a mouse or finger, with their typed name, the time and their connection details recorded. The signature block is printed on the quote, its PDF and any invoice made from it, so an approval is something you can show rather than a click in a log. Required or optional, your choice.', 'easy-invoice'), |
| 424 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 425 |
'icon' => 'dashicons-edit', |
| 426 |
'category' => 'documents', |
| 427 |
'badge' => 'new', |
| 428 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/quote-signatures/', |
| 429 |
'settings_url' => admin_url('admin.php?page=easy-invoice-settings&tab=quote'), |
| 430 |
'pro_class' => 'EasyInvoicePro\\Addons\\QuoteSignatures\\QuoteSignatures', |
| 431 |
], |
| 432 |
[ |
| 433 |
'id' => 'quote_forms', |
| 434 |
'name' => __('Quote Request Forms', 'easy-invoice'), |
| 435 |
'short_name' => __('Quote Forms', 'easy-invoice'), |
| 436 |
'tagline' => __('A form submission becomes a draft quote, client included.', 'easy-invoice'), |
| 437 |
'description' => __('Connect WPForms, Gravity Forms, Contact Form 7 or Fluent Forms: when someone submits your quote-request form, the client is found or created from their email and a draft quote opens with what they wrote — and a first line item if the form asks for a service or amount. You price it and send it; nothing is retyped. Any other form can feed it through one action hook.', 'easy-invoice'), |
| 438 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 439 |
'icon' => 'dashicons-feedback', |
| 440 |
'category' => 'integrations', |
| 441 |
'badge' => 'new', |
| 442 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/quote-forms/', |
| 443 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-quote-forms'), |
| 444 |
'pro_class' => 'EasyInvoicePro\\Addons\\QuoteForms\\QuoteForms', |
| 445 |
], |
| 446 |
[ |
| 447 |
'id' => 'woocommerce', |
| 448 |
'name' => __('WooCommerce Invoicing', 'easy-invoice'), |
| 449 |
'short_name' => __('WooCommerce', 'easy-invoice'), |
| 450 |
'tagline' => __('A real invoice for every shop order — and a credit note for every refund.', 'easy-invoice'), |
| 451 |
'description' => __('Issue an Easy Invoice invoice automatically when a WooCommerce order is paid, mirroring its lines and totals exactly. Refunds become credit notes against the invoice. Customers get an Invoice link in My Account, the order screen shows the invoice with its PDF, and with the E-Invoicing addon every order can be sent as Factur-X or Peppol UBL — which no WooCommerce PDF plugin offers without a further paid extension. Works with High-Performance Order Storage.', 'easy-invoice'), |
| 452 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 453 |
'icon' => 'dashicons-cart', |
| 454 |
'category' => 'integrations', |
| 455 |
'badge' => 'new', |
| 456 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/woocommerce/', |
| 457 |
'settings_url' => admin_url('admin.php?page=easy-invoice-addon-woocommerce'), |
| 458 |
'pro_class' => 'EasyInvoicePro\\Addons\\WooCommerce\\WooCommerce', |
| 459 |
], |
| 460 |
[ |
| 461 |
'id' => 'reports', |
| 462 |
'name' => __('Reports & Analytics', 'easy-invoice'), |
| 463 |
'short_name' => __('Reports', 'easy-invoice'), |
| 464 |
'tagline' => __('See your revenue, outstanding balances, and best clients at a glance.', 'easy-invoice'), |
| 465 |
'description' => __('Visual dashboard for invoice revenue, outstanding balances, payment status, and per-client performance, plus a month-by-month profit & loss statement — money received against costs from Expense Tracking, with net and margin. Filter by any date range, export for your accountant, and decide on data instead of guessing.', 'easy-invoice'), |
| 466 |
'plan' => LicensePlanResolver::PLAN_PERSONAL, |
| 467 |
'icon' => 'dashicons-chart-line', |
| 468 |
'category' => 'analytics', |
| 469 |
'badge' => null, |
| 470 |
'docs_url' => 'https://easy-invoice.matrixaddons.com/docs/addons/reports/', |
| 471 |
// ReportController lives in the Free plugin (the class |
| 472 |
// existed before addonization) but the page is a Pro |
| 473 |
// feature shown to Free users only as an upsell badge. |
| 474 |
// Gating its sidebar link + page dispatch on this addon |
| 475 |
// makes "Reports" opt-in for Pro users too. The slug |
| 476 |
// 'easy-invoice-reports' is registered as an EI admin |
| 477 |
// submenu by EasyInvoiceAdmin::registerMenuPages(). |
| 478 |
'settings_url' => admin_url('admin.php?page=easy-invoice-reports'), |
| 479 |
'pro_class' => 'EasyInvoicePro\\Addons\\Reports\\Reports', |
| 480 |
], |
| 481 |
|
| 482 |
]); |
| 483 |
} |
| 484 |
|
| 485 |
/** |
| 486 |
* IDs of every addon that wraps a previously-monolithic Pro feature. |
| 487 |
* Used by ProAddonMigration to know which flags to set for existing |
| 488 |
* Pro installs (so their currently-active features keep working) and |
| 489 |
* to leave disabled for fresh installs. |
| 490 |
* |
| 491 |
* @return array<int,string> |
| 492 |
*/ |
| 493 |
public static function migratedProAddonIds(): array { |
| 494 |
return [ |
| 495 |
'recurring_invoices', |
| 496 |
'partial_payments', |
| 497 |
'client_portal', |
| 498 |
'pdf_toolkit', |
| 499 |
'bulk_operations', |
| 500 |
'item_library', |
| 501 |
'custom_templates', |
| 502 |
'additional_tax', |
| 503 |
'email_enhancements', |
| 504 |
'privacy_tools', |
| 505 |
// Reports was previously gated only by easy_invoice_has_pro(); |
| 506 |
// any Pro install was using it. The migration falls through |
| 507 |
// to isExistingProInstall() for this id, so existing Pro |
| 508 |
// sites keep Reports active after the addon-ization migration. |
| 509 |
'reports', |
| 510 |
// Secure Links was always-loaded Pro infrastructure |
| 511 |
// gated only by easy_invoice_pro_enable_secure_links. |
| 512 |
// Migration auto-enables the addon when that legacy |
| 513 |
// option was 'yes' so signed URLs already in the wild |
| 514 |
// (emails, shortcodes) keep resolving. |
| 515 |
'secure_links', |
| 516 |
]; |
| 517 |
} |
| 518 |
|
| 519 |
/** |
| 520 |
* Find a single addon definition by id. |
| 521 |
* |
| 522 |
* @return array<string,mixed>|null |
| 523 |
*/ |
| 524 |
public static function find(string $id): ?array { |
| 525 |
foreach (self::all() as $addon) { |
| 526 |
if ($addon['id'] === $id) { |
| 527 |
return $addon; |
| 528 |
} |
| 529 |
} |
| 530 |
return null; |
| 531 |
} |
| 532 |
|
| 533 |
/** |
| 534 |
* Distinct categories present in the registry — drives the filter chips in the UI. |
| 535 |
* |
| 536 |
* @return array<int,string> |
| 537 |
*/ |
| 538 |
public static function categories(): array { |
| 539 |
$cats = []; |
| 540 |
foreach (self::all() as $addon) { |
| 541 |
$cats[$addon['category']] = true; |
| 542 |
} |
| 543 |
return array_keys($cats); |
| 544 |
} |
| 545 |
} |
| 546 |
|