GetPaid_Admin::get_notices()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Contains the admin class.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * The main admin class.
11
 *
12
 * @since       1.0.19
13
 */
14
class GetPaid_Admin {
15
16
    /**
17
	 * Local path to this plugins admin directory
18
	 *
19
	 * @var         string
20
	 */
21
	public $admin_path;
22
23
	/**
24
	 * Web path to this plugins admin directory
25
	 *
26
	 * @var         string
27
	 */
28
	public $admin_url;
29
30
	/**
31
	 * Reports components.
32
	 *
33
	 * @var GetPaid_Reports
34
	 */
35
    public $reports;
36
37
    /**
38
	 * Class constructor.
39
	 */
40
	public function __construct() {
41
42
        $this->admin_path  = plugin_dir_path( __FILE__ );
43
		$this->admin_url   = plugins_url( '/', __FILE__ );
44
		$this->reports     = new GetPaid_Reports();
45
46
        if ( is_admin() ) {
47
			$this->init_admin_hooks();
48
        }
49
50
    }
51
52
    /**
53
	 * Init action and filter hooks
54
	 *
55
	 */
56
	private function init_admin_hooks() {
57
        add_action( 'admin_enqueue_scripts', array( $this, 'enqeue_scripts' ), 9 );
58
        add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
59
        add_action( 'admin_init', array( $this, 'init_ayecode_connect_helper' ) );
60
        add_action( 'admin_init', array( $this, 'activation_redirect' ) );
61
        add_action( 'admin_init', array( $this, 'maybe_do_admin_action' ) );
62
		add_action( 'admin_notices', array( $this, 'show_notices' ) );
63
		add_action( 'getpaid_authenticated_admin_action_rate_plugin', array( $this, 'redirect_to_wordpress_rating_page' ) );
64
		add_action( 'getpaid_authenticated_admin_action_duplicate_form', array( $this, 'duplicate_payment_form' ) );
65
		add_action( 'getpaid_authenticated_admin_action_reset_form_stats', array( $this, 'reset_form_stats' ) );
66
		add_action( 'getpaid_authenticated_admin_action_duplicate_invoice', array( $this, 'duplicate_invoice' ) );
67
		add_action( 'getpaid_authenticated_admin_action_refund_invoice', array( $this, 'refund_invoice' ) );
68
		add_action( 'getpaid_authenticated_admin_action_send_invoice', array( $this, 'send_customer_invoice' ) );
69
		add_action( 'getpaid_authenticated_admin_action_send_invoice_reminder', array( $this, 'send_customer_payment_reminder' ) );
70
        add_action( 'getpaid_authenticated_admin_action_reset_tax_rates', array( $this, 'admin_reset_tax_rates' ) );
71
		add_action( 'getpaid_authenticated_admin_action_create_missing_pages', array( $this, 'admin_create_missing_pages' ) );
72
		add_action( 'getpaid_authenticated_admin_action_refresh_permalinks', array( $this, 'admin_refresh_permalinks' ) );
73
		add_action( 'getpaid_authenticated_admin_action_create_missing_tables', array( $this, 'admin_create_missing_tables' ) );
74
		add_action( 'getpaid_authenticated_admin_action_migrate_old_invoices', array( $this, 'admin_migrate_old_invoices' ) );
75
		add_action( 'getpaid_authenticated_admin_action_download_customers', array( $this, 'admin_download_customers' ) );
76
		add_action( 'getpaid_authenticated_admin_action_recalculate_discounts', array( $this, 'admin_recalculate_discounts' ) );
77
		add_action( 'getpaid_authenticated_admin_action_translate_db_texts', array( $this, 'tool_translate_db_texts' ) );
78
		add_action( 'getpaid_authenticated_admin_action_install_plugin', array( $this, 'admin_install_plugin' ) );
79
		add_action( 'getpaid_authenticated_admin_action_connect_gateway', array( $this, 'admin_connect_gateway' ) );
80
		add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ) );
81
		do_action( 'getpaid_init_admin_hooks', $this );
82
83
		// Setup/welcome
84
		if ( ! empty( $_GET['page'] ) ) {
85
			switch ( sanitize_text_field( $_GET['page'] ) ) {
86
				case 'gp-setup':
87
					include_once dirname( __FILE__ ) . '/class-getpaid-admin-setup-wizard.php';
88
					break;
89
			}
90
		}
91
92
    }
93
94
    /**
95
	 * Register admin scripts
96
	 *
97
	 */
98
	public function enqeue_scripts() {
99
        global $current_screen, $pagenow;
100
101
		$page    = isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : '';
102
		$editing = $pagenow == 'post.php' || $pagenow == 'post-new.php';
103
104
        if ( ! empty( $current_screen->post_type ) ) {
105
			$page = $current_screen->post_type;
106
        }
107
108
        // General styles.
109
        if ( false !== stripos( $page, 'wpi' ) || false !== stripos( $page, 'getpaid' ) || 'gp-setup' == $page || false !== stripos( $page, 'geodir-tickets' ) ) {
110
111
            // Styles.
112
            $version = filemtime( WPINV_PLUGIN_DIR . 'assets/css/admin.css' );
113
            wp_enqueue_style( 'wpinv_admin_style', WPINV_PLUGIN_URL . 'assets/css/admin.css', array( 'wp-color-picker' ), $version );
114
            wp_enqueue_style( 'select2', WPINV_PLUGIN_URL . 'assets/css/select2/select2.min.css', array(), '4.0.13', 'all' );
115
116
            // Scripts.
117
            wp_enqueue_script( 'select2', WPINV_PLUGIN_URL . 'assets/js/select2/select2.full.min.js', array( 'jquery' ), WPINV_VERSION );
118
119
            $version = filemtime( WPINV_PLUGIN_DIR . 'assets/js/admin.js' );
120
            wp_enqueue_script( 'wpinv-admin-script', WPINV_PLUGIN_URL . 'assets/js/admin.js', array( 'jquery', 'wp-color-picker', 'jquery-ui-tooltip' ), $version );
121
            wp_localize_script( 'wpinv-admin-script', 'WPInv_Admin', apply_filters( 'wpinv_admin_js_localize', $this->get_admin_i18() ) );
122
123
        }
124
125
        // Payment form scripts.
126
		if ( 'wpi_payment_form' == $page && $editing ) {
127
            $this->load_payment_form_scripts();
128
        }
129
130
		if ( $page == 'wpinv-subscriptions' ) {
131
			wp_enqueue_script( 'postbox' );
132
		}
133
134
    }
135
136
    /**
137
	 * Returns admin js translations.
138
	 *
139
	 */
140
	protected function get_admin_i18() {
141
        global $post;
142
143
		$date_range = array(
144
			'period' => isset( $_GET['date_range'] ) ? sanitize_text_field( $_GET['date_range'] ) : '7_days',
145
		);
146
147
		if ( $date_range['period'] == 'custom' ) {
148
149
			if ( isset( $_GET['from'] ) ) {
150
				$date_range['after'] = date( 'Y-m-d', strtotime( sanitize_text_field( $_GET['from'] ), current_time( 'timestamp' ) ) - DAY_IN_SECONDS );
151
			}
152
153
			if ( isset( $_GET['to'] ) ) {
154
				$date_range['before'] = date( 'Y-m-d', strtotime( sanitize_text_field( $_GET['to'] ), current_time( 'timestamp' ) ) + DAY_IN_SECONDS );
155
			}
156
}
157
158
        $i18n = array(
159
            'ajax_url'                  => admin_url( 'admin-ajax.php' ),
160
            'post_ID'                   => isset( $post->ID ) ? $post->ID : '',
161
			'wpinv_nonce'               => wp_create_nonce( 'wpinv-nonce' ),
162
			'rest_nonce'                => wp_create_nonce( 'wp_rest' ),
163
			'rest_root'                 => esc_url_raw( rest_url() ),
164
			'date_range'                => $date_range,
165
            'add_invoice_note_nonce'    => wp_create_nonce( 'add-invoice-note' ),
166
            'delete_invoice_note_nonce' => wp_create_nonce( 'delete-invoice-note' ),
167
            'invoice_item_nonce'        => wp_create_nonce( 'invoice-item' ),
168
            'billing_details_nonce'     => wp_create_nonce( 'get-billing-details' ),
169
            'tax'                       => wpinv_tax_amount(),
170
            'discount'                  => 0,
171
			'currency_symbol'           => wpinv_currency_symbol(),
172
			'currency'                  => wpinv_get_currency(),
173
            'currency_pos'              => wpinv_currency_position(),
174
            'thousand_sep'              => wpinv_thousands_separator(),
175
            'decimal_sep'               => wpinv_decimal_separator(),
176
            'decimals'                  => wpinv_decimals(),
177
            'save_invoice'              => __( 'Save Invoice', 'invoicing' ),
178
            'status_publish'            => wpinv_status_nicename( 'publish' ),
179
            'status_pending'            => wpinv_status_nicename( 'wpi-pending' ),
180
            'delete_tax_rate'           => __( 'Are you sure you wish to delete this tax rate?', 'invoicing' ),
181
            'status_pending'            => wpinv_status_nicename( 'wpi-pending' ),
182
            'FillBillingDetails'        => __( 'Fill the user\'s billing information? This will remove any currently entered billing information', 'invoicing' ),
183
            'confirmCalcTotals'         => __( 'Recalculate totals? This will recalculate totals based on the user billing country. If no billing country is set it will use the base country.', 'invoicing' ),
184
            'AreYouSure'                => __( 'Are you sure?', 'invoicing' ),
185
            'errDeleteItem'             => __( 'This item is in use! Before delete this item, you need to delete all the invoice(s) using this item.', 'invoicing' ),
186
            'delete_subscription'       => __( 'Are you sure you want to delete this subscription?', 'invoicing' ),
187
            'action_edit'               => __( 'Edit', 'invoicing' ),
188
            'action_cancel'             => __( 'Cancel', 'invoicing' ),
189
            'item_description'          => __( 'Item Description', 'invoicing' ),
190
            'invoice_description'       => __( 'Invoice Description', 'invoicing' ),
191
            'discount_description'      => __( 'Discount Description', 'invoicing' ),
192
			'searching'                 => __( 'Searching', 'invoicing' ),
193
			'loading'                   => __( 'Loading...', 'invoicing' ),
194
			'search_customers'          => __( 'Enter customer name or email', 'invoicing' ),
195
			'search_items'              => __( 'Enter item name', 'invoicing' ),
196
			'graphs'                    => array_merge( array( 'refunded_fees', 'refunded_items', 'refunded_subtotal', 'refunded_tax' ), array_keys( wpinv_get_report_graphs() ) ),
197
        );
198
199
		if ( ! empty( $post ) && getpaid_is_invoice_post_type( $post->post_type ) ) {
200
201
			$invoice              = new WPInv_Invoice( $post );
202
			$i18n['save_invoice'] = sprintf(
203
				__( 'Save %s', 'invoicing' ),
204
				ucfirst( $invoice->get_invoice_quote_type() )
205
			);
206
207
			$i18n['invoice_description'] = sprintf(
208
				__( '%s Description', 'invoicing' ),
209
				ucfirst( $invoice->get_invoice_quote_type() )
210
			);
211
212
		}
213
		return $i18n;
214
	}
215
216
	/**
217
	 * Change the admin footer text on GetPaid admin pages.
218
	 *
219
	 * @since  2.0.0
220
	 * @param  string $footer_text
221
	 * @return string
222
	 */
223
	public function admin_footer_text( $footer_text ) {
224
		global $current_screen;
225
226
		$page    = isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : '';
227
228
        if ( ! empty( $current_screen->post_type ) ) {
229
			$page = $current_screen->post_type;
230
        }
231
232
        // General styles.
233
        if ( apply_filters( 'getpaid_display_admin_footer_text', wpinv_current_user_can_manage_invoicing() ) && false !== stripos( $page, 'wpi' ) ) {
234
235
			// Change the footer text
236
			if ( ! get_user_meta( get_current_user_id(), 'getpaid_admin_footer_text_rated', true ) ) {
237
238
				$rating_url  = esc_url(
239
					wp_nonce_url(
240
						admin_url( 'admin.php?page=wpinv-reports&getpaid-admin-action=rate_plugin' ),
241
						'getpaid-nonce',
242
						'getpaid-nonce'
243
                    )
244
				);
245
246
				$footer_text = sprintf(
247
					/* translators: %s: five stars */
248
					__( 'If you like <strong>GetPaid</strong>, please leave us a %s rating. A huge thanks in advance!', 'invoicing' ),
249
					"<a href='$rating_url'>&#9733;&#9733;&#9733;&#9733;&#9733;</a>"
250
				);
251
252
			} else {
253
254
				$footer_text = sprintf(
255
					/* translators: %s: GetPaid */
256
					__( 'Thank you for using %s!', 'invoicing' ),
257
					"<a href='https://wpgetpaid.com/' target='_blank'><strong>GetPaid</strong></a>"
258
				);
259
260
			}
261
}
262
263
		return $footer_text;
264
	}
265
266
	/**
267
	 * Redirects to wp.org to rate the plugin.
268
	 *
269
	 * @since  2.0.0
270
	 */
271
	public function redirect_to_wordpress_rating_page() {
272
		update_user_meta( get_current_user_id(), 'getpaid_admin_footer_text_rated', 1 );
273
		wp_redirect( 'https://wordpress.org/support/plugin/invoicing/reviews?rate=5#new-post' );
274
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
275
	}
276
277
    /**
278
	 * Loads payment form js.
279
	 *
280
	 */
281
	protected function load_payment_form_scripts() {
282
        global $post;
283
284
        wp_enqueue_script( 'vue', WPINV_PLUGIN_URL . 'assets/js/vue/vue.min.js', array(), WPINV_VERSION );
285
		wp_enqueue_script( 'sortable', WPINV_PLUGIN_URL . 'assets/js/sortable.min.js', array(), WPINV_VERSION );
286
		wp_enqueue_script( 'vue_draggable', WPINV_PLUGIN_URL . 'assets/js/vue/vuedraggable.min.js', array( 'sortable', 'vue' ), WPINV_VERSION );
287
288
		wp_register_script( 'wpinv-admin-payment-form-script', WPINV_PLUGIN_URL . 'assets/js/admin-payment-forms.min.js', array( 'wpinv-admin-script', 'vue_draggable', 'wp-hooks' ), WPINV_VERSION );
289
290
		wp_localize_script(
291
            'wpinv-admin-payment-form-script',
292
            'wpinvPaymentFormAdmin',
293
            array(
294
				'elements'      => wpinv_get_data( 'payment-form-elements' ),
295
				'form_elements' => getpaid_get_payment_form_elements( $post->ID ),
296
				'currency'      => wpinv_currency_symbol(),
297
				'position'      => wpinv_currency_position(),
298
				'decimals'      => (int) wpinv_decimals(),
299
				'thousands_sep' => wpinv_thousands_separator(),
300
				'decimals_sep'  => wpinv_decimal_separator(),
301
				'form_items'    => gepaid_get_form_items( $post->ID ),
302
				'is_default'    => $post->ID == wpinv_get_default_payment_form(),
303
            )
304
        );
305
306
        wp_enqueue_script( 'wpinv-admin-payment-form-script' );
307
308
    }
309
310
    /**
311
	 * Add our classes to admin pages.
312
     *
313
     * @param string $classes
314
     * @return string
315
	 *
316
	 */
317
    public function admin_body_class( $classes ) {
318
		global $pagenow, $post, $current_screen;
319
320
        $page = isset( $_GET['page'] ) ? sanitize_text_field( $_GET['page'] ) : '';
321
322
        if ( ! empty( $current_screen->post_type ) ) {
323
			$page = $current_screen->post_type;
324
        }
325
326
        if ( false !== stripos( $page, 'wpi' ) ) {
327
            $classes .= ' wpi-' . sanitize_key( $page );
328
        }
329
330
        if ( in_array( $page, wpinv_parse_list( 'wpi_invoice wpi_payment_form wpi_quote' ) ) ) {
331
            $classes .= ' wpinv-cpt wpinv';
332
		}
333
334
		if ( getpaid_is_invoice_post_type( $page ) ) {
335
            $classes .= ' getpaid-is-invoice-cpt';
336
        }
337
338
		return $classes;
339
    }
340
341
    /**
342
	 * Maybe show the AyeCode Connect Notice.
343
	 */
344
	public function init_ayecode_connect_helper() {
345
346
		// Register with the deactivation survey class.
347
		AyeCode_Deactivation_Survey::instance(
348
            array(
349
				'slug'              => 'invoicing',
350
				'version'           => WPINV_VERSION,
351
				'support_url'       => 'https://wpgetpaid.com/support/',
352
				'documentation_url' => 'https://docs.wpgetpaid.com/',
353
				'activated'         => (int) get_option( 'gepaid_installed_on' ),
354
            )
355
        );
356
357
        new AyeCode_Connect_Helper(
358
            array(
359
				'connect_title'     => __( 'WP Invoicing - an AyeCode product!', 'invoicing' ),
360
				'connect_external'  => __( 'Please confirm you wish to connect your site?', 'invoicing' ),
361
				'connect'           => sprintf( __( '<strong>Have a license?</strong> Forget about entering license keys or downloading zip files, connect your site for instant access. %1$slearn more%2$s', 'invoicing' ), "<a href='https://ayecode.io/introducing-ayecode-connect/' target='_blank'>", '</a>' ),
362
				'connect_button'    => __( 'Connect Site', 'invoicing' ),
363
				'connecting_button' => __( 'Connecting...', 'invoicing' ),
364
				'error_localhost'   => __( 'This service will only work with a live domain, not a localhost.', 'invoicing' ),
365
				'error'             => __( 'Something went wrong, please refresh and try again.', 'invoicing' ),
366
            ),
367
            array( 'wpi-addons' )
368
        );
369
370
    }
371
372
	/**
373
	 * Redirect users to settings on activation.
374
	 *
375
	 * @return void
376
	 */
377
	public function activation_redirect() {
378
379
		$redirected = get_option( 'wpinv_redirected_to_settings' );
380
381
		if ( ! empty( $redirected ) || wp_doing_ajax() || ! current_user_can( 'manage_options' ) ) {
382
			return;
383
		}
384
385
		// Bail if activating from network, or bulk
386
		if ( is_network_admin() || isset( $_GET['activate-multi'] ) ) {
387
			return;
388
		}
389
390
	    update_option( 'wpinv_redirected_to_settings', 1 );
391
392
        wp_safe_redirect( admin_url( 'index.php?page=gp-setup' ) );
393
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
394
395
	}
396
397
    /**
398
     * Fires an admin action after verifying that a user can fire them.
399
     */
400
    public function maybe_do_admin_action() {
401
        if ( isset( $_REQUEST['getpaid-admin-action'] ) && isset( $_REQUEST['getpaid-nonce'] ) && wp_verify_nonce( $_REQUEST['getpaid-nonce'], 'getpaid-nonce' ) && wpinv_current_user_can( sanitize_text_field( $_REQUEST['getpaid-admin-action'] ), $_REQUEST ) ) {
402
            $key = sanitize_key( $_REQUEST['getpaid-admin-action'] );
403
404
            do_action( "getpaid_authenticated_admin_action_$key", $_REQUEST );
405
        }
406
    }
407
408
	/**
409
     * Duplicate invoice.
410
	 *
411
	 * @param array $args
412
     */
413
    public function duplicate_invoice( $args ) {
414
415
		if ( empty( $args['invoice_id'] ) ) {
416
			return;
417
		}
418
419
		$invoice = new WPInv_Invoice( (int) $args['invoice_id'] );
420
421
		if ( ! $invoice->exists() ) {
422
			return;
423
		}
424
425
		$new_invoice = getpaid_duplicate_invoice( $invoice );
426
		$new_invoice->save();
427
428
		if ( $new_invoice->exists() ) {
429
430
			getpaid_admin()->show_success( __( 'Invoice duplicated successfully.', 'invoicing' ) );
431
432
			wp_safe_redirect(
433
				add_query_arg(
434
					array(
435
						'action' => 'edit',
436
						'post'   => $new_invoice->get_id(),
437
					),
438
					admin_url( 'post.php' )
439
				)
440
			);
441
			exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
442
443
		}
444
445
		getpaid_admin()->show_error( __( 'There was an error duplicating this invoice. Please try again.', 'invoicing' ) );
446
447
	}
448
449
	/**
450
     * Refund an invoice.
451
	 *
452
	 * @param array $args
453
     */
454
    public function refund_invoice( $args ) {
455
456
		if ( empty( $args['invoice_id'] ) ) {
457
			return;
458
		}
459
460
		$invoice = new WPInv_Invoice( (int) $args['invoice_id'] );
461
462
		if ( ! $invoice->exists() || $invoice->is_refunded() ) {
463
			return;
464
		}
465
466
		$invoice->refund();
467
468
		// Refund remotely.
469
		if ( getpaid_payment_gateway_supports( $invoice->get_gateway(), 'refunds' ) && ! empty( $args['getpaid_refund_remote'] ) ) {
470
			do_action( 'getpaid_refund_invoice_remotely', $invoice );
471
		}
472
473
		// Cancel subscriptions.
474
		if ( ! empty( $args['getpaid_cancel_subscription'] ) ) {
475
			$subscriptions = getpaid_get_invoice_subscriptions( $invoice );
476
477
			if ( ! empty( $subscriptions ) ) {
478
				if ( ! is_array( $subscriptions ) ) {
0 ignored issues
show
introduced by
The condition is_array($subscriptions) is always false.
Loading history...
479
					$subscriptions = array( $subscriptions );
480
				}
481
482
				foreach ( $subscriptions as $subscription ) {
483
					$subscription->cancel();
484
					$invoice->add_system_note(
485
						sprintf(
486
							// translators: %s: subscription ID.
487
							__( 'Subscription #%s cancelled', 'invoicing' ),
488
							$subscription->get_id()
489
						)
490
					);
491
				}
492
			}
493
		}
494
495
		// Add notice.
496
		$this->show_success( __( 'Invoice refunded successfully.', 'invoicing' ) );
497
498
		// Redirect.
499
		wp_safe_redirect(
500
			remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce', 'invoice_id', 'getpaid_cancel_subscription', 'getpaid_refund_remote' ) )
501
		);
502
	}
503
504
	/**
505
     * Sends a payment reminder to a customer.
506
	 *
507
	 * @param array $args
508
     */
509
    public function duplicate_payment_form( $args ) {
510
511
		if ( empty( $args['form_id'] ) ) {
512
			return;
513
		}
514
515
		$form = new GetPaid_Payment_Form( (int) $args['form_id'] );
516
517
		if ( ! $form->exists() ) {
518
			return;
519
		}
520
521
		$new_form = new GetPaid_Payment_Form();
522
		$new_form->set_author( $form->get_author( 'edit' ) );
523
		$new_form->set_name( $form->get_name( 'edit' ) . __( '(copy)', 'invoicing' ) );
524
		$new_form->set_elements( $form->get_elements( 'edit' ) );
525
		$new_form->set_items( $form->get_items( 'edit' ) );
526
		$new_form->save();
527
528
		if ( $new_form->exists() ) {
529
			$this->show_success( __( 'Form duplicated successfully', 'invoicing' ) );
530
			$url = get_edit_post_link( $new_form->get_id(), 'edit' );
531
		} else {
532
			$this->show_error( __( 'Unable to duplicate form', 'invoicing' ) );
533
			$url = remove_query_arg( array( 'getpaid-admin-action', 'form_id', 'getpaid-nonce' ) );
534
		}
535
536
		wp_redirect( $url );
537
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
538
	}
539
540
	/**
541
     * Resets form stats.
542
	 *
543
	 * @param array $args
544
     */
545
    public function reset_form_stats( $args ) {
546
547
		if ( empty( $args['form_id'] ) ) {
548
			return;
549
		}
550
551
		$form = new GetPaid_Payment_Form( (int) $args['form_id'] );
552
553
		if ( ! $form->exists() ) {
554
			return;
555
		}
556
557
		$form->set_earned( 0 );
558
		$form->set_refunded( 0 );
559
		$form->set_cancelled( 0 );
560
		$form->set_failed( 0 );
561
		$form->save();
562
563
		$this->show_success( __( 'Form stats reset successfully', 'invoicing' ) );
564
565
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'form_id', 'getpaid-nonce' ) ) );
566
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
567
	}
568
569
	/**
570
     * Sends a payment reminder to a customer.
571
	 *
572
	 * @param array $args
573
     */
574
    public function send_customer_invoice( $args ) {
575
		getpaid()->get( 'invoice_emails' )->user_invoice( new WPInv_Invoice( $args['invoice_id'] ), true );
576
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce', 'invoice_id' ) ) );
577
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
578
	}
579
580
	/**
581
     * Sends a payment reminder to a customer.
582
	 *
583
	 * @param array $args
584
     */
585
    public function send_customer_payment_reminder( $args ) {
586
		$sent = getpaid()->get( 'invoice_emails' )->force_send_overdue_notice( new WPInv_Invoice( $args['invoice_id'] ) );
587
588
		if ( $sent ) {
589
			$this->show_success( __( 'Payment reminder was successfully sent to the customer', 'invoicing' ) );
590
		} else {
591
			$this->show_error( __( 'Could not sent payment reminder to the customer', 'invoicing' ) );
592
		}
593
594
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce', 'invoice_id' ) ) );
595
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
596
	}
597
598
	/**
599
     * Resets tax rates.
600
	 *
601
     */
602
    public function admin_reset_tax_rates() {
603
604
		update_option( 'wpinv_tax_rates', wpinv_get_data( 'tax-rates' ) );
605
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
606
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
607
608
	}
609
610
	/**
611
     * Resets admin pages.
612
	 *
613
     */
614
    public function admin_create_missing_pages() {
615
		$installer = new GetPaid_Installer();
616
		$installer->create_pages();
617
		$this->show_success( __( 'GetPaid pages updated.', 'invoicing' ) );
618
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
619
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
620
	}
621
622
	/**
623
	 * Refreshes the permalinks.
624
	 */
625
	public function admin_refresh_permalinks() {
626
		flush_rewrite_rules();
627
		$this->show_success( __( 'Permalinks refreshed.', 'invoicing' ) );
628
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
629
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
630
	}
631
632
	/**
633
     * Creates missing admin tables.
634
	 *
635
     */
636
    public function admin_create_missing_tables() {
637
		global $wpdb;
638
639
		GetPaid_Installer::create_db_tables();
640
		GetPaid_Installer::migrate_old_customers();
641
642
		if ( '' !== $wpdb->last_error ) {
643
			$this->show_error( __( 'Your GetPaid tables have been updated:', 'invoicing' ) . ' ' . $wpdb->last_error );
644
		} else {
645
			$this->show_success( __( 'Your GetPaid tables have been updated.', 'invoicing' ) );
646
		}
647
648
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
649
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
650
	}
651
652
	/**
653
     * Migrates old invoices to the new database tables.
654
	 *
655
     */
656
    public function admin_migrate_old_invoices() {
657
658
		// Migrate the invoices.
659
		$installer = new GetPaid_Installer();
660
		$installer->migrate_old_invoices();
661
662
		// Show an admin message.
663
		$this->show_success( __( 'Your invoices have been migrated.', 'invoicing' ) );
664
665
		// Redirect the admin.
666
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
667
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
668
669
	}
670
671
	/**
672
     * Download customers.
673
	 *
674
     */
675
    public function admin_download_customers() {
676
677
		$output = fopen( 'php://output', 'w' );
678
679
		if ( false === $output ) {
680
			wp_die( esc_html__( 'Unsupported server', 'invoicing' ), 500 );
681
		}
682
683
		header( 'Content-Type:text/csv' );
684
		header( 'Content-Disposition:attachment;filename=customers.csv' );
685
686
		/** @var GetPaid_Customer[] $customers */
687
		$customers = getpaid_get_customers( array( 'number' => -1 ) );
688
		$columns   = array_keys( GetPaid_Customer_Data_Store::get_database_fields() );
689
690
		// Output the csv column headers.
691
		fputcsv( $output, $columns );
692
693
		// Loop through
694
		foreach ( $customers as $customer ) {
695
696
			$row  = array();
697
698
			foreach ( $columns as $column ) {
699
				$row[]  = (string) maybe_serialize( $customer->get( $column, 'edit' ) );
700
			}
701
702
			fputcsv( $output, $row );
703
		}
704
705
		fclose( $output );
706
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
707
708
	}
709
710
	/**
711
     * Installs a plugin.
712
	 *
713
	 * @param array $data
714
     */
715
    public function admin_install_plugin( $data ) {
716
717
		if ( ! empty( $data['plugins'] ) ) {
718
			include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
719
			wp_cache_flush();
720
721
			foreach ( $data['plugins'] as $slug => $file ) {
722
				$plugin_zip = esc_url( 'https://downloads.wordpress.org/plugin/' . $slug . '.latest-stable.zip' );
723
				$upgrader   = new Plugin_Upgrader( new Automatic_Upgrader_Skin() );
724
				$installed  = $upgrader->install( $plugin_zip );
725
726
				if ( ! is_wp_error( $installed ) && $installed ) {
727
					activate_plugin( $file, '', false, true );
728
				} else {
729
					wpinv_error_log( $upgrader->skin->get_upgrade_messages(), false );
0 ignored issues
show
Bug introduced by
The method get_upgrade_messages() does not exist on WP_Upgrader_Skin. It seems like you code against a sub-type of WP_Upgrader_Skin such as Automatic_Upgrader_Skin. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

729
					wpinv_error_log( $upgrader->skin->/** @scrutinizer ignore-call */ get_upgrade_messages(), false );
Loading history...
Bug introduced by
$upgrader->skin->get_upgrade_messages() of type string[] is incompatible with the type string expected by parameter $log of wpinv_error_log(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

729
					wpinv_error_log( /** @scrutinizer ignore-type */ $upgrader->skin->get_upgrade_messages(), false );
Loading history...
730
				}
731
}
732
}
733
734
		$redirect = isset( $data['redirect'] ) ? esc_url_raw( $data['redirect'] ) : admin_url( 'plugins.php' );
735
		wp_safe_redirect( $redirect );
736
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
737
738
	}
739
740
	/**
741
     * Connects a gateway.
742
	 *
743
	 * @param array $data
744
     */
745
    public function admin_connect_gateway( $data ) {
746
747
		if ( ! empty( $data['plugin'] ) ) {
748
749
			$gateway     = sanitize_key( $data['plugin'] );
750
			$connect_url = apply_filters( "getpaid_get_{$gateway}_connect_url", false, $data );
751
752
			if ( ! empty( $connect_url ) ) {
753
				wp_redirect( $connect_url );
754
				exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
755
			}
756
757
			if ( 'stripe' == $data['plugin'] ) {
758
				require_once ABSPATH . 'wp-admin/includes/plugin.php';
759
				include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
760
				wp_cache_flush();
761
762
				if ( ! array_key_exists( 'getpaid-stripe-payments/getpaid-stripe-payments.php', get_plugins() ) ) {
763
					$plugin_zip = esc_url( 'https://downloads.wordpress.org/plugin/getpaid-stripe-payments.latest-stable.zip' );
764
					$upgrader   = new Plugin_Upgrader( new Automatic_Upgrader_Skin() );
765
					$upgrader->install( $plugin_zip );
766
				}
767
768
				activate_plugin( 'getpaid-stripe-payments/getpaid-stripe-payments.php', '', false, true );
769
			}
770
771
			$connect_url = apply_filters( "getpaid_get_{$gateway}_connect_url", false, $data );
772
			if ( ! empty( $connect_url ) ) {
773
				wp_redirect( $connect_url );
774
				exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
775
			}
776
}
777
778
		$redirect = isset( $data['redirect'] ) ? esc_url_raw( urldecode( $data['redirect'] ) ) : admin_url( 'admin.php?page=wpinv-settings&tab=gateways' );
779
		wp_safe_redirect( $redirect );
780
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
781
782
	}
783
784
	/**
785
     * Recalculates discounts.
786
	 *
787
     */
788
    public function admin_recalculate_discounts() {
789
		global $wpdb;
790
791
		// Fetch all invoices that have discount codes.
792
		$table    = $wpdb->prefix . 'getpaid_invoices';
793
		$invoices = $wpdb->get_col( "SELECT `post_id` FROM `$table` WHERE `discount` = 0 && `discount_code` <> ''" );
794
795
		foreach ( $invoices as $invoice ) {
796
797
			$invoice = new WPInv_Invoice( $invoice );
798
799
			if ( ! $invoice->exists() ) {
800
				continue;
801
			}
802
803
			// Abort if the discount does not exist or does not apply here.
804
			$discount = new WPInv_Discount( $invoice->get_discount_code() );
805
			if ( ! $discount->exists() ) {
806
				continue;
807
			}
808
809
			$invoice->add_discount( getpaid_calculate_invoice_discount( $invoice, $discount ) );
810
			$invoice->recalculate_total();
811
812
			if ( $invoice->get_total_discount() > 0 ) {
813
				$invoice->save();
814
			}
815
}
816
817
		// Show an admin message.
818
		$this->show_success( __( 'Discounts have been recalculated.', 'invoicing' ) );
819
820
		// Redirect the admin.
821
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
822
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
823
824
	}
825
826
	/**
827
	 * Load dynamic strings in to file to translate via po editor
828
	 *
829
	 * @since   2.8.32
830
	 *
831
	 * @global null|object $wp_filesystem WP_Filesystem object.
832
	 *
833
	 * @return bool True if file created otherwise false
834
	 */
835
    public function tool_translate_db_texts() {
836
		$language_file = wp_normalize_path( WPINV_PLUGIN_DIR . 'db-language.php' );
837
838
		if ( getpaid_sync_db_text_translation() ) {
839
			// Success
840
			$this->show_success( wp_sprintf( __( 'Strings are added in the file <b>%s</b> for translation.', 'invoicing' ), $language_file ) );
841
		} else {
842
			// Failure
843
			$this->show_error( wp_sprintf( __( 'There was a problem creating the file <b>%s</b>. Please check file permissions.', 'invoicing' ), $language_file ) );
844
		}
845
846
		// Redirect the admin.
847
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
848
849
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
850
	}
851
852
    /**
853
	 * Returns an array of admin notices.
854
	 *
855
	 * @since       1.0.19
856
     * @return array
857
	 */
858
	public function get_notices() {
859
		$notices = get_option( 'wpinv_admin_notices' );
860
        return is_array( $notices ) ? $notices : array();
861
	}
862
863
	/**
864
	 * Checks if we have any admin notices.
865
	 *
866
	 * @since       2.0.4
867
     * @return array
868
	 */
869
	public function has_notices() {
870
		return count( $this->get_notices() ) > 0;
0 ignored issues
show
Bug Best Practice introduced by
The expression return count($this->get_notices()) > 0 returns the type boolean which is incompatible with the documented return type array.
Loading history...
871
	}
872
873
	/**
874
	 * Clears all admin notices
875
	 *
876
	 * @access      public
877
	 * @since       1.0.19
878
	 */
879
	public function clear_notices() {
880
		delete_option( 'wpinv_admin_notices' );
881
	}
882
883
	/**
884
	 * Saves a new admin notice
885
	 *
886
	 * @access      public
887
	 * @since       1.0.19
888
	 */
889
	public function save_notice( $type, $message ) {
890
		$notices = $this->get_notices();
891
892
		if ( empty( $notices[ $type ] ) || ! is_array( $notices[ $type ] ) ) {
893
			$notices[ $type ] = array();
894
		}
895
896
		$notices[ $type ][] = $message;
897
898
		update_option( 'wpinv_admin_notices', $notices );
899
	}
900
901
	/**
902
	 * Displays a success notice
903
	 *
904
	 * @param       string $msg The message to qeue.
905
	 * @access      public
906
	 * @since       1.0.19
907
	 */
908
	public function show_success( $msg ) {
909
		$this->save_notice( 'success', $msg );
910
	}
911
912
	/**
913
	 * Displays a error notice
914
	 *
915
	 * @access      public
916
	 * @param       string $msg The message to qeue.
917
	 * @since       1.0.19
918
	 */
919
	public function show_error( $msg ) {
920
		$this->save_notice( 'error', $msg );
921
	}
922
923
	/**
924
	 * Displays a warning notice
925
	 *
926
	 * @access      public
927
	 * @param       string $msg The message to qeue.
928
	 * @since       1.0.19
929
	 */
930
	public function show_warning( $msg ) {
931
		$this->save_notice( 'warning', $msg );
932
	}
933
934
	/**
935
	 * Displays a info notice
936
	 *
937
	 * @access      public
938
	 * @param       string $msg The message to qeue.
939
	 * @since       1.0.19
940
	 */
941
	public function show_info( $msg ) {
942
		$this->save_notice( 'info', $msg );
943
	}
944
945
	/**
946
	 * Show notices
947
	 *
948
	 * @access      public
949
	 * @since       1.0.19
950
	 */
951
	public function show_notices() {
952
953
        $notices = $this->get_notices();
954
        $this->clear_notices();
955
956
		foreach ( $notices as $type => $messages ) {
957
958
			if ( ! is_array( $messages ) ) {
959
				continue;
960
			}
961
962
            $type  = esc_attr( $type );
963
			foreach ( $messages as $message ) {
964
				echo wp_kses_post( "<div class='notice notice-$type is-dismissible'><p>$message</p></div>" );
965
            }
966
}
967
968
		foreach ( array( 'checkout_page', 'invoice_history_page', 'success_page', 'failure_page', 'invoice_subscription_page' ) as $page ) {
969
970
			if ( ! is_numeric( wpinv_get_option( $page, false ) ) ) {
971
				$url     = wp_nonce_url(
972
					add_query_arg( 'getpaid-admin-action', 'create_missing_pages' ),
973
					'getpaid-nonce',
974
					'getpaid-nonce'
975
				);
976
				$message  = __( 'Some GetPaid pages are missing. To use GetPaid without any issues, click the button below to generate the missing pages.', 'invoicing' );
977
				$message2 = __( 'Generate Pages', 'invoicing' );
978
				echo wp_kses_post( "<div class='notice notice-warning is-dismissible'><p>$message<br><br><a href='$url' class='button button-primary'>$message2</a></p></div>" );
979
				break;
980
			}
981
}
982
983
	}
984
985
}
986