PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.3.2
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.3.2
2.4.0 2.4.1 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 All 57 releases
easy-invoice / includes / EasyInvoice.php

EasyInvoice.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.3.2, at includes/EasyInvoice.php

797 lines 30.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Main EasyInvoice Plugin Class
4 *
5 * @package EasyInvoice
6 * @author Your Name
7 * @copyright Copyright (c) 2023, Your Company
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.0.0
10 */
11
12 namespace EasyInvoice;
13
14 use EasyInvoice\PostTypes\InvoicePostType;
15 use EasyInvoice\PostTypes\PaymentPostType;
16
17 /**
18 * EasyInvoice main plugin class.
19 *
20 * @since 1.0.0
21 */
22 class EasyInvoice {
23 /**
24 * Plugin instance.
25 *
26 * @since 1.0.0
27 * @access private
28 * @var EasyInvoice
29 */
30 private static $instance = null;
31
32 /**
33 * Payment gateway manager instance.
34 *
35 * @since 1.0.0
36 * @access private
37 * @var PaymentGatewayManager
38 */
39 private $gateway_manager;
40
41 /**
42 * Get plugin instance.
43 *
44 * @since 1.0.0
45 * @return EasyInvoice
46 */
47 public static function getInstance(): EasyInvoice {
48 if ( null === self::$instance ) {
49 self::$instance = new self();
50 }
51 return self::$instance;
52 }
53
54 /**
55 * Initialize the plugin.
56 *
57 * @since 1.0.0
58 * @return void
59 */
60 public function init() {
61 // Define plugin constants.
62 $this->defineConstants();
63
64 // Initialize payment gateways first.
65 $this->initPaymentGateways();
66
67 // Note: Post types are now registered separately with proper timing
68
69 // Initialize template loader
70 $template_loader = new TemplateLoader();
71 $template_loader->init();
72
73 // Flush rewrite rules on first load to ensure public quote URLs work
74 if (get_option('easy_invoice_flush_rewrite_rules', false) === false) {
75 add_action('init', function() {
76 flush_rewrite_rules();
77 update_option('easy_invoice_flush_rewrite_rules', true);
78 }, 20);
79 }
80
81 // Also flush rewrite rules when post types are registered
82 add_action('init', function() {
83 if (get_option('easy_invoice_post_types_registered', false) === false) {
84 flush_rewrite_rules();
85 update_option('easy_invoice_post_types_registered', true);
86 }
87 }, 25);
88
89 // Initialize admin functionality if in admin area.
90 if ( is_admin() ) {
91 $this->initAdmin();
92 }
93
94
95
96 // Initialize background services
97 \EasyInvoice\Services\QuoteExpirationService::init();
98 }
99
100 /**
101 * Define plugin constants.
102 *
103 * @since 1.0.0
104 * @access private
105 * @return void
106 */
107 private function defineConstants(): void {
108 if ( ! defined( 'EASY_INVOICE_VERSION' ) ) {
109 $fallback = '2.1.18';
110 if ( defined( 'EASY_INVOICE_PLUGIN_FILE' ) && function_exists( 'get_file_data' ) ) {
111 $headers = get_file_data(
112 EASY_INVOICE_PLUGIN_FILE,
113 array( 'version' => 'Version' ),
114 'plugin'
115 );
116 $fallback = ! empty( $headers['version'] ) ? $headers['version'] : $fallback;
117 }
118 define( 'EASY_INVOICE_VERSION', $fallback );
119 }
120
121 if ( ! defined( 'EASY_INVOICE_FILE' ) ) {
122 define( 'EASY_INVOICE_FILE', dirname( dirname( __FILE__ ) ) . '/easy-invoice.php' );
123 }
124
125 if ( ! defined( 'EASY_INVOICE_PATH' ) ) {
126 define( 'EASY_INVOICE_PATH', plugin_dir_path( EASY_INVOICE_FILE ) );
127 }
128
129 if ( ! defined( 'EASY_INVOICE_URL' ) ) {
130 define( 'EASY_INVOICE_URL', plugin_dir_url( EASY_INVOICE_FILE ) );
131 }
132
133 if ( ! defined( 'EASY_INVOICE_ASSETS_URL' ) ) {
134 define( 'EASY_INVOICE_ASSETS_URL', EASY_INVOICE_URL . 'assets/' );
135 }
136 }
137
138 /**
139 * Initialize admin functionality.
140 *
141 * @since 1.0.0
142 * @access private
143 * @return void
144 */
145 private function initAdmin() {
146 // Load admin class if we're in the admin area.
147 $admin = new Admin\EasyInvoiceAdmin();
148 $admin->init();
149
150 // Initialize AJAX handlers.
151 $ajax = new Admin\EasyInvoiceAjax();
152 $ajax->init();
153
154 // Show draft invoices in the main list.
155 add_action( 'pre_get_posts', [ $this, 'modifyInvoiceAdminQuery' ] );
156
157 // Add custom columns to invoice list.
158 add_filter( 'manage_easy_invoice_posts_columns', [ $this, 'addInvoiceColumns' ] );
159 add_action( 'manage_easy_invoice_posts_custom_column', [ $this, 'populateInvoiceColumns' ], 10, 2 );
160
161 // Add custom columns to payment list.
162 add_filter( 'manage_easy_invoice_payment_posts_columns', [ $this, 'addPaymentColumns' ] );
163 add_action( 'manage_easy_invoice_payment_posts_custom_column', [ $this, 'populatePaymentColumns' ], 10, 2 );
164
165 // Add admin action to flush rewrite rules
166 add_action('admin_post_flush_easy_invoice_rewrite_rules', [$this, 'handleFlushRewriteRules']);
167
168 // Add admin action to fix quote slugs
169 add_action('admin_post_fix_easy_invoice_quote_slugs', [$this, 'handleFixQuoteSlugs']);
170
171 // Add admin action to manually register post types
172 add_action('admin_post_register_easy_invoice_post_types', [$this, 'handleRegisterPostTypes']);
173
174 // Disable admin notices on Easy Invoice pages for clean UI
175 add_action( 'admin_notices', [ $this, 'disableAdminNoticesOnEasyInvoicePages' ], 1 );
176 }
177
178 /**
179 * Modify the main query for easy_invoice post type in admin to include drafts.
180 *
181 * @since 1.0.0
182 * @param \WP_Query $query The WP_Query instance (passed by reference).
183 * @return void
184 */
185 public function modifyInvoiceAdminQuery( \WP_Query $query ) {
186 // Check if we are on the main query for the 'easy_invoice' post type admin page.
187 if ( ! is_admin() || ! $query->is_main_query() || $query->get( 'post_type' ) !== 'easy_invoice' ) {
188 return;
189 }
190
191 // Check if a specific post_status is already set in the query.
192 $current_status = $query->get( 'post_status' );
193 if ( empty( $current_status ) || $current_status === '' ||
194 ( is_array( $current_status ) && count( $current_status ) === 1 && $current_status[0] === 'any' ) ) {
195
196 // Also check for explicit views like 'all'.
197 if ( isset( $_GET['post_status'] ) && $_GET['post_status'] !== 'all' ) {
198 return;
199 }
200
201 // Include all needed statuses.
202 $query->set( 'post_status', [
203 'publish',
204 'private',
205 'draft',
206 'pending',
207 'future',
208 'pending-bank',
209 'pending-cheque'
210 ] );
211 }
212 }
213
214 /**
215 * Initialize payment gateways.
216 *
217 * @since 1.0.0
218 * @access private
219 * @return void
220 */
221 private function initPaymentGateways() {
222 if ( ! $this->gateway_manager ) {
223 $this->gateway_manager = new PaymentGatewayManager();
224
225 // Register payment gateways.
226 $gateways = [
227 new Gateways\PayPalGateway(),
228 new Gateways\ManualGateway(),
229 ];
230
231 foreach ( $gateways as $gateway ) {
232 $this->gateway_manager->registerGateway( $gateway );
233 }
234
235 // Initialize all gateways.
236 $this->gateway_manager->initGateways();
237
238 // Set default payment methods if not already set.
239 $this->setDefaultPaymentMethods();
240 }
241 }
242
243 /**
244 * Set default payment methods and their details.
245 *
246 * @since 1.0.0
247 * @access private
248 * @return void
249 */
250 private function setDefaultPaymentMethods() {
251 $payment_methods = get_option( 'easy_invoice_payment_methods', [] );
252
253 $defaults_updated = false;
254
255 // Bank Transfer, Cheque, and Cash payment defaults moved to Pro plugin
256
257 if ( $defaults_updated ) {
258 update_option( 'easy_invoice_payment_methods', array_unique( $payment_methods ) );
259 }
260 }
261
262 /**
263 * Get payment gateway manager.
264 *
265 * @since 1.0.0
266 * @return PaymentGatewayManager
267 */
268 public function getGatewayManager(): PaymentGatewayManager {
269 if ( ! $this->gateway_manager ) {
270 $this->initPaymentGateways();
271 }
272 return $this->gateway_manager;
273 }
274
275 /**
276 * Register custom post types.
277 *
278 * @since 1.0.0
279 * @return void
280 */
281 public function registerPostTypes() {
282 // Register Invoice post type.
283 register_post_type( \EasyInvoice\Constants\PostTypes::EASY_INVOICE_POST_TYPE, [
284 'labels' => [
285 'name' => _x( 'Invoices', 'post type general name', 'easy-invoice' ),
286 'singular_name' => _x( 'Invoice', 'post type singular name', 'easy-invoice' ),
287 'menu_name' => _x( 'Invoices', 'admin menu', 'easy-invoice' ),
288 'name_admin_bar' => _x( 'Invoice', 'add new on admin bar', 'easy-invoice' ),
289 'add_new' => _x( 'Add New', 'invoice', 'easy-invoice' ),
290 'add_new_item' => __( 'Add New Invoice', 'easy-invoice' ),
291 'new_item' => __( 'New Invoice', 'easy-invoice' ),
292 'edit_item' => __( 'Edit Invoice', 'easy-invoice' ),
293 'view_item' => __( 'View Invoice', 'easy-invoice' ),
294 'all_items' => __( 'All Invoices', 'easy-invoice' ),
295 'search_items' => __( 'Search Invoices', 'easy-invoice' ),
296 'parent_item_colon' => __( 'Parent Invoices:', 'easy-invoice' ),
297 'not_found' => __( 'No invoices found.', 'easy-invoice' ),
298 'not_found_in_trash' => __( 'No invoices found in Trash.', 'easy-invoice' )
299 ],
300 'description' => __( 'Invoices for Easy Invoice plugin.', 'easy-invoice' ),
301 'public' => true,
302 'publicly_queryable' => true,
303 'show_ui' => false,
304 'show_in_menu' => false,
305 'query_var' => true,
306 'rewrite' => [ 'slug' => 'invoice' ],
307 'capability_type' => 'post',
308 'has_archive' => false,
309 'hierarchical' => false,
310 'menu_position' => null,
311 'supports' => [ 'title', 'editor', 'custom-fields' ]
312 ]);
313
314 // Register Quote post type.
315 $quote_post_type = \EasyInvoice\Constants\PostTypes::EASY_INVOICE_QUOTE_POST_TYPE;
316
317 $result = register_post_type( $quote_post_type, [
318 'labels' => [
319 'name' => _x( 'Quotes', 'post type general name', 'easy-invoice' ),
320 'singular_name' => _x( 'Quote', 'post type singular name', 'easy-invoice' ),
321 'menu_name' => _x( 'Quotes', 'admin menu', 'easy-invoice' ),
322 'name_admin_bar' => _x( 'Quote', 'add new on admin bar', 'easy-invoice' ),
323 'add_new' => _x( 'Add New', 'quote', 'easy-invoice' ),
324 'add_new_item' => __( 'Add New Quote', 'easy-invoice' ),
325 'new_item' => __( 'New Quote', 'easy-invoice' ),
326 'edit_item' => __( 'Edit Quote', 'easy-invoice' ),
327 'view_item' => __( 'View Quote', 'easy-invoice' ),
328 'all_items' => __( 'All Quotes', 'easy-invoice' ),
329 'search_items' => __( 'Search Quotes', 'easy-invoice' ),
330 'parent_item_colon' => __( 'Parent Quotes:', 'easy-invoice' ),
331 'not_found' => __( 'No quotes found.', 'easy-invoice' ),
332 'not_found_in_trash' => __( 'No quotes found in Trash.', 'easy-invoice' )
333 ],
334 'description' => __( 'Quotes for Easy Invoice plugin.', 'easy-invoice' ),
335 'public' => true,
336 'publicly_queryable' => true,
337 'show_ui' => false,
338 'show_in_menu' => false,
339 'query_var' => true,
340 'rewrite' => [ 'slug' => 'easy-invoice-quote', 'with_front' => false ],
341 'capability_type' => 'post',
342 'has_archive' => false,
343 'hierarchical' => false,
344 'menu_position' => null,
345 'supports' => [ 'title', 'editor', 'custom-fields' ]
346 ]);
347
348
349
350 // Register Payment post type.
351 register_post_type( 'easy_invoice_payment', [
352 'labels' => [
353 'name' => _x( 'Payments', 'post type general name', 'easy-invoice' ),
354 'singular_name' => _x( 'Payment', 'post type singular name', 'easy-invoice' ),
355 'menu_name' => _x( 'Payments', 'admin menu', 'easy-invoice' ),
356 'name_admin_bar' => _x( 'Payment', 'add new on admin bar', 'easy-invoice' ),
357 'add_new' => _x( 'Add New', 'payment', 'easy-invoice' ),
358 'add_new_item' => __( 'Add New Payment', 'easy-invoice' ),
359 'new_item' => __( 'New Payment', 'easy-invoice' ),
360 'edit_item' => __( 'Edit Payment', 'easy-invoice' ),
361 'view_item' => __( 'View Payment', 'easy-invoice' ),
362 'all_items' => __( 'All Payments', 'easy-invoice' ),
363 'search_items' => __( 'Search Payments', 'easy-invoice' ),
364 'parent_item_colon' => __( 'Parent Payments:', 'easy-invoice' ),
365 'not_found' => __( 'No payments found.', 'easy-invoice' ),
366 'not_found_in_trash' => __( 'No payments found in Trash.', 'easy-invoice' )
367 ],
368 'description' => __( 'Payments for Easy Invoice plugin.', 'easy-invoice' ),
369 'public' => false,
370 'publicly_queryable' => false,
371 'show_ui' => true,
372 'show_in_menu' => 'edit.php?post_type=easy_invoice',
373 'query_var' => true,
374 'rewrite' => [ 'slug' => 'payment' ],
375 'capability_type' => 'post',
376 'has_archive' => false,
377 'hierarchical' => false,
378 'menu_position' => null,
379 'supports' => [ 'title', 'author', 'custom-fields' ],
380 'show_in_rest' => false,
381 ] );
382
383
384 // Force flush rewrite rules after post type registration
385 $this->flushRewriteRules();
386
387 // Force an immediate rewrite rules flush
388 flush_rewrite_rules(true);
389 }
390
391 /**
392 * Flush rewrite rules to ensure custom post type URLs work
393 */
394 private function flushRewriteRules() {
395 // Only flush if we haven't done it recently
396 $last_flush = get_option('easy_invoice_last_rewrite_flush', 0);
397 $current_time = time();
398
399 if ($current_time - $last_flush > 300) { // 5 minutes
400 flush_rewrite_rules();
401 update_option('easy_invoice_last_rewrite_flush', $current_time);
402 }
403 }
404
405 /**
406 * Manually flush rewrite rules (public method for admin use)
407 */
408 public function forceFlushRewriteRules() {
409 flush_rewrite_rules();
410 update_option('easy_invoice_last_rewrite_flush', time());
411 update_option('easy_invoice_flush_rewrite_rules', false);
412 update_option('easy_invoice_post_types_registered', false);
413 }
414
415 /**
416 * Add columns to invoice list table.
417 *
418 * @since 1.0.0
419 * @param array $columns List of columns.
420 * @return array Modified list of columns.
421 */
422 public function addInvoiceColumns( $columns ) {
423 $date_column = isset( $columns['date'] ) ? $columns['date'] : '';
424 unset( $columns['date'] );
425
426 $columns['invoice_number'] = __( 'Invoice #', 'easy-invoice' );
427 $columns['client'] = __( 'Client', 'easy-invoice' );
428 $columns['amount'] = __( 'Amount', 'easy-invoice' );
429 $columns['status'] = __( 'Status', 'easy-invoice' );
430 $columns['issue_date'] = __( 'Issue Date', 'easy-invoice' );
431 $columns['due_date'] = __( 'Due Date', 'easy-invoice' );
432
433 if ( $date_column ) {
434 $columns['date'] = $date_column;
435 }
436
437 return $columns;
438 }
439
440 /**
441 * Populate custom columns for invoice list table.
442 *
443 * @since 1.0.0
444 * @param string $column Column name.
445 * @param int $post_id Post ID.
446 * @return void
447 */
448 public function populateInvoiceColumns( $column, $post_id ) {
449 switch ( $column ) {
450 case 'invoice_number':
451 $invoice_number = get_post_meta( $post_id, '_invoice_number', true );
452 echo esc_html( ! empty( $invoice_number ) ? $invoice_number : "INV-{$post_id}" );
453 break;
454 case 'client':
455 $client_id = get_post_meta( $post_id, '_client_id', true );
456 if ( $client_id ) {
457 $client = get_post( $client_id );
458 if ( $client ) {
459 echo esc_html( $client->post_title );
460 } else {
461 echo esc_html__('', 'easy-invoice');
462 }
463 } else {
464 echo esc_html__('', 'easy-invoice');
465 }
466 break;
467 case 'amount':
468 $total = get_post_meta( $post_id, '_invoice_total', true );
469 if ( ! empty( $total ) ) {
470 echo esc_html( '$' . number_format( $total, 2 ) );
471 } else {
472 echo esc_html__('', 'easy-invoice');
473 }
474 break;
475 case 'status':
476 $status = get_post_meta( $post_id, '_payment_status', true );
477 if ( ! empty( $status ) ) {
478 echo '<span class="invoice-status status-' . esc_attr( $status ) . '">' . esc_html( ucfirst( $status ) ) . '</span>';
479 } else {
480 echo esc_html__('', 'easy-invoice');
481 }
482 break;
483 case 'issue_date':
484 $issue_date = get_post_meta( $post_id, '_issue_date', true );
485 if ( ! empty( $issue_date ) ) {
486 echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $issue_date ) ) );
487 } else {
488 echo esc_html__('', 'easy-invoice');
489 }
490 break;
491 case 'due_date':
492 $due_date = get_post_meta( $post_id, '_due_date', true );
493 if ( ! empty( $due_date ) ) {
494 echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $due_date ) ) );
495 } else {
496 echo '';
497 }
498 break;
499 }
500 }
501
502 /**
503 * Add columns to payment list table.
504 *
505 * @since 1.0.0
506 * @param array $columns List of columns.
507 * @return array Modified list of columns.
508 */
509 public function addPaymentColumns( $columns ) {
510 $date_column = isset( $columns['date'] ) ? $columns['date'] : '';
511 unset( $columns['date'] );
512
513 $columns['invoice'] = __( 'Invoice', 'easy-invoice' );
514 $columns['amount'] = __( 'Amount', 'easy-invoice' );
515 $columns['method'] = __( 'Method', 'easy-invoice' );
516 $columns['status'] = __( 'Status', 'easy-invoice' );
517 $columns['transaction_id'] = __( 'Transaction ID', 'easy-invoice' );
518
519 if ( $date_column ) {
520 $columns['date'] = $date_column;
521 }
522
523 return $columns;
524 }
525
526 /**
527 * Populate custom columns for payment list table.
528 *
529 * @since 1.0.0
530 * @param string $column Column name.
531 * @param int $post_id Post ID.
532 * @return void
533 */
534 public function populatePaymentColumns( $column, $post_id ) {
535 switch ( $column ) {
536 case 'invoice':
537 $invoice_id = get_post_meta( $post_id, '_invoice_id', true );
538 if ( $invoice_id ) {
539 $invoice = get_post( $invoice_id );
540 if ( $invoice ) {
541 $invoice_number = get_post_meta( $invoice_id, '_invoice_number', true );
542 if ( ! $invoice_number ) {
543 $invoice_number = "INV-{$invoice_id}";
544 }
545 echo '<a href="' . esc_url( admin_url( 'post.php?post=' . $invoice_id . '&action=edit' ) ) . '">' . esc_html( $invoice_number ) . '</a>';
546 } else {
547 echo '';
548 }
549 } else {
550 echo '';
551 }
552 break;
553 case 'amount':
554 $amount = get_post_meta( $post_id, '_amount', true );
555 $currency = get_post_meta( $post_id, '_currency_symbol', true ) ?: '$';
556 if ( ! empty( $amount ) ) {
557 echo esc_html( $currency . number_format( $amount, 2 ) );
558 } else {
559 echo '';
560 }
561 break;
562 case 'method':
563 $method = get_post_meta( $post_id, '_payment_method', true );
564 if ( ! empty( $method ) ) {
565 echo esc_html( ucfirst( $method ) );
566 } else {
567 echo '';
568 }
569 break;
570 case 'status':
571 $status = get_post_meta( $post_id, '_status', true );
572 if ( ! empty( $status ) ) {
573 echo '<span class="payment-status status-' . esc_attr( $status ) . '">' . esc_html( ucfirst( $status ) ) . '</span>';
574 } else {
575 echo '';
576 }
577 break;
578 case 'transaction_id':
579 $transaction_id = get_post_meta( $post_id, '_transaction_id', true );
580 if ( ! empty( $transaction_id ) ) {
581 echo esc_html( $transaction_id );
582 } else {
583 echo '';
584 }
585 break;
586 }
587 }
588
589 /**
590 * Register custom post statuses.
591 *
592 * @since 1.0.0
593 * @return void
594 */
595 public function registerCustomStatuses() {
596 // Register custom post statuses for invoices and payments.
597 $statuses = [
598 'pending-bank' => [
599 'label' => _x( 'Pending Bank Transfer', 'Invoice status', 'easy-invoice' ),
600 'public' => true,
601 'exclude_from_search' => false,
602 'show_in_admin_all_list' => true,
603 'show_in_admin_status_list' => true,
604 'label_count' => _n_noop(
605 'Pending Bank Transfer <span class="count">(%s)</span>',
606 'Pending Bank Transfer <span class="count">(%s)</span>',
607 'easy-invoice'
608 ),
609 ],
610 'pending-cheque' => [
611 'label' => _x( 'Pending Cheque', 'Invoice status', 'easy-invoice' ),
612 'public' => true,
613 'exclude_from_search' => false,
614 'show_in_admin_all_list' => true,
615 'show_in_admin_status_list' => true,
616 'label_count' => _n_noop(
617 'Pending Cheque <span class="count">(%s)</span>',
618 'Pending Cheque <span class="count">(%s)</span>',
619 'easy-invoice'
620 ),
621 ],
622 ];
623
624 foreach ( $statuses as $status => $args ) {
625 register_post_status( $status, $args );
626 }
627 }
628
629 /**
630 * Handle admin action to flush rewrite rules
631 */
632 public function handleFlushRewriteRules() {
633 if (!current_user_can('manage_options')) {
634 wp_die('Unauthorized');
635 }
636
637 check_admin_referer('flush_easy_invoice_rewrite_rules');
638
639 $this->forceFlushRewriteRules();
640
641 // Get the referer to determine which page to redirect back to
642 $referer = wp_get_referer();
643 $redirect_url = admin_url('admin.php?page=easy-quote-all&rewrite_flushed=1'); // Default fallback
644
645 if ($referer) {
646 // Check if user was on invoice page
647 if (strpos($referer, 'page=easy-invoice-all') !== false) {
648 $redirect_url = admin_url('admin.php?page=easy-invoice-all&rewrite_flushed=1');
649 } elseif (strpos($referer, 'page=easy-quote-all') !== false) {
650 $redirect_url = admin_url('admin.php?page=easy-quote-all&rewrite_flushed=1');
651 }
652 }
653
654 wp_redirect($redirect_url);
655 exit;
656 }
657
658 /**
659 * Handle admin action to manually register post types
660 */
661 public function handleRegisterPostTypes() {
662 if (!current_user_can('manage_options')) {
663 wp_die('Unauthorized');
664 }
665
666 check_admin_referer('register_easy_invoice_post_types');
667
668 $this->registerPostTypes();
669 $this->forceFlushRewriteRules();
670
671 // Get the referer to determine which page to redirect back to
672 $referer = wp_get_referer();
673 $redirect_url = admin_url('admin.php?page=easy-quote-all&post_types_registered=1'); // Default fallback
674
675 if ($referer) {
676 // Check if user was on invoice page
677 if (strpos($referer, 'page=easy-invoice-all') !== false) {
678 $redirect_url = admin_url('admin.php?page=easy-invoice-all&post_types_registered=1');
679 } elseif (strpos($referer, 'page=easy-quote-all') !== false) {
680 $redirect_url = admin_url('admin.php?page=easy-quote-all&post_types_registered=1');
681 }
682 }
683
684 wp_redirect($redirect_url);
685 exit;
686 }
687
688 /**
689 * Disable admin notices on Easy Invoice pages for clean UI.
690 *
691 * @since 1.0.0
692 * @return void
693 */
694 public function disableAdminNoticesOnEasyInvoicePages() {
695 // Get current page
696 $page = isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : '';
697
698 // Static list of core Easy Invoice page slugs. Addon-owned page
699 // slugs (Item Library, Template Builder, enterprise addon pages,
700 // export manager, etc.) are appended dynamically below from
701 // AddonRegistry so new addons automatically suppress WP notices
702 // on their pages without needing to edit this list.
703 $easy_invoice_pages = [
704 'easy-invoice', // Dashboard
705 'easy-invoice-all', // All invoices
706 'easy-invoice-builder', // Invoice builder
707 'easy-invoice-preview', // Invoice preview
708 'easy-quote-all', // All quotes
709 'easy-invoice-quote-builder', // Quote builder
710 'easy-quote-preview', // Quote preview
711 'easy-invoice-payments', // All payments
712 'easy-invoice-payment-new', // Add new payment
713 'easy-invoice-clients', // All clients
714 'easy-invoice-client-edit', // Edit client
715 'easy-invoice-client-view', // View client
716 'easy-invoice-reports', // Reports
717 'easy-invoice-settings', // Main settings
718 'easy-invoice-email-settings', // Email settings
719 'easy-invoice-email-settings-general',
720 'easy-invoice-email-settings-invoice',
721 'easy-invoice-email-settings-quote',
722 'easy-invoice-email-settings-payment',
723 'easy-invoice-pro-settings', // Pro settings
724 'easy-invoice-pro-translations',// Pro translations
725 'easy-invoice-pro-item-library',// Item Library (Pro)
726 'easy-invoice-templates', // Template Builder listing (Pro)
727 'easy-invoice-templates-new', // Template Builder "Create New" (Pro)
728 'easy-invoice-template-builder',// Template Builder canvas (Pro)
729 'easy-invoice-export', // Export Data (bulk_operations addon)
730 'easy-invoice-addons', // Addons grid
731 'easy-invoice-migration', // Migration page
732 'easy-invoice-license', // License page
733 'easy-invoice-free-vs-pro',
734 'easy-invoice-join-community',
735 ];
736
737 // Dynamically include every addon's `settings_url` page slug.
738 // This means enterprise addons (time-tracking, dunning, white-label,
739 // team-roles, webhooks) and any future addon automatically get
740 // notice-suppression without needing to update this array.
741 if ( class_exists( '\\EasyInvoice\\Addons\\AddonRegistry' ) ) {
742 foreach ( \EasyInvoice\Addons\AddonRegistry::all() as $ei_addon ) {
743 if ( empty( $ei_addon['settings_url'] ) ) {
744 continue;
745 }
746 $parts = wp_parse_url( $ei_addon['settings_url'] );
747 if ( empty( $parts['query'] ) ) {
748 continue;
749 }
750 parse_str( $parts['query'], $qs );
751 if ( ! empty( $qs['page'] ) ) {
752 $easy_invoice_pages[] = $qs['page'];
753 }
754 }
755 $easy_invoice_pages = array_values( array_unique( $easy_invoice_pages ) );
756 }
757
758 // Check if current page is an Easy Invoice page
759 if ( in_array( $page, $easy_invoice_pages ) ) {
760 // Don't remove our review notice - keep it for free users
761 // Store our notice callback temporarily
762 $review_notice_callback = false;
763 $review_notice_priority = false;
764
765 // Find our review notice hook
766 global $wp_filter;
767 if (isset($wp_filter['admin_notices']->callbacks)) {
768 foreach ($wp_filter['admin_notices']->callbacks as $priority => $callbacks) {
769 foreach ($callbacks as $callback) {
770 if (is_array($callback['function']) &&
771 is_object($callback['function'][0]) &&
772 $callback['function'][0] instanceof \EasyInvoice\Services\ReviewNoticeService &&
773 $callback['function'][1] === 'displayAdminNotice') {
774 $review_notice_callback = $callback['function'];
775 $review_notice_priority = $priority;
776 break 2;
777 }
778 }
779 }
780 }
781
782 // Remove all admin notices by removing the action
783 remove_all_actions( 'admin_notices' );
784
785 // Also remove network and user admin notices
786 remove_all_actions( 'network_admin_notices' );
787 remove_all_actions( 'user_admin_notices' );
788 remove_all_actions( 'all_admin_notices' );
789
790 // Re-add our review notice if it was found
791 if ($review_notice_callback !== false && $review_notice_priority !== false) {
792 add_action('admin_notices', $review_notice_callback, $review_notice_priority);
793 }
794 }
795 }
796 }
797