Passed
Push — master ( 3f789e...c58b71 )
by Brian
04:52
created

GetPaid_Admin   F

Complexity

Total Complexity 101

Size/Duplication

Total Lines 786
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 331
dl 0
loc 786
rs 2
c 5
b 0
f 0
wmc 101

29 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 2
A show_error() 0 2 1
A maybe_do_admin_action() 0 5 5
A admin_create_missing_pages() 0 6 1
A save_notice() 0 10 3
A activation_redirect() 0 17 6
A admin_migrate_old_invoices() 0 12 1
A show_warning() 0 2 1
B admin_create_missing_tables() 0 34 8
A show_info() 0 2 1
A admin_recalculate_discounts() 0 36 5
A load_payment_form_scripts() 0 27 1
B get_admin_i18() 0 74 8
A clear_notices() 0 2 1
A send_customer_payment_reminder() 0 11 2
A admin_footer_text() 0 42 6
B enqeue_scripts() 0 34 9
A has_notices() 0 2 1
A admin_install_plugin() 0 24 6
B admin_download_customers() 0 75 10
A show_notices() 0 31 6
A init_ayecode_connect_helper() 0 13 1
A init_admin_hooks() 0 26 3
A show_success() 0 2 1
A admin_body_class() 0 23 6
A admin_reset_tax_rates() 0 5 1
A send_customer_invoice() 0 11 2
A get_notices() 0 3 2
A redirect_to_wordpress_rating_page() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like GetPaid_Admin often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use GetPaid_Admin, and based on these observations, apply Extract Interface, too.

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' ) );
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_send_invoice', array( $this, 'send_customer_invoice' ) );
65
		add_action( 'getpaid_authenticated_admin_action_send_invoice_reminder', array( $this, 'send_customer_payment_reminder' ) );
66
        add_action( 'getpaid_authenticated_admin_action_reset_tax_rates', array( $this, 'admin_reset_tax_rates' ) );
67
		add_action( 'getpaid_authenticated_admin_action_create_missing_pages', array( $this, 'admin_create_missing_pages' ) );
68
		add_action( 'getpaid_authenticated_admin_action_create_missing_tables', array( $this, 'admin_create_missing_tables' ) );
69
		add_action( 'getpaid_authenticated_admin_action_migrate_old_invoices', array( $this, 'admin_migrate_old_invoices' ) );
70
		add_action( 'getpaid_authenticated_admin_action_download_customers', array( $this, 'admin_download_customers' ) );
71
		add_action( 'getpaid_authenticated_admin_action_recalculate_discounts', array( $this, 'admin_recalculate_discounts' ) );
72
		add_action( 'getpaid_authenticated_admin_action_install_plugin', array( $this, 'admin_install_plugin' ) );
73
		add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ) );
74
		do_action( 'getpaid_init_admin_hooks', $this );
75
76
		// Setup/welcome
77
		if ( ! empty( $_GET['page'] ) ) {
78
			switch ( $_GET['page'] ) {
79
				case 'gp-setup' :
80
					include_once( dirname( __FILE__ ) . '/class-getpaid-admin-setup-wizard.php' );
81
					break;
82
			}
83
		}
84
85
    }
86
87
    /**
88
	 * Register admin scripts
89
	 *
90
	 */
91
	public function enqeue_scripts() {
92
        global $current_screen, $pagenow;
93
94
		$page    = isset( $_GET['page'] ) ? $_GET['page'] : '';
95
		$editing = $pagenow == 'post.php' || $pagenow == 'post-new.php';
96
97
        if ( ! empty( $current_screen->post_type ) ) {
98
			$page = $current_screen->post_type;
99
        }
100
101
        // General styles.
102
        if ( false !== stripos( $page, 'wpi' ) || 'gp-setup' == $page ) {
103
104
            // Styles.
105
            $version = filemtime( WPINV_PLUGIN_DIR . 'assets/css/admin.css' );
106
            wp_enqueue_style( 'wpinv_admin_style', WPINV_PLUGIN_URL . 'assets/css/admin.css', array( 'wp-color-picker' ), $version );
107
            wp_enqueue_style( 'select2', WPINV_PLUGIN_URL . 'assets/css/select2/select2.min.css', array(), '4.0.13', 'all' );
108
109
            // Scripts.
110
            wp_enqueue_script('select2', WPINV_PLUGIN_URL . 'assets/js/select2/select2.full.min.js', array( 'jquery' ), WPINV_VERSION );
111
112
            $version = filemtime( WPINV_PLUGIN_DIR . 'assets/js/admin.js' );
113
            wp_enqueue_script( 'wpinv-admin-script', WPINV_PLUGIN_URL . 'assets/js/admin.js', array( 'jquery', 'wp-color-picker', 'jquery-ui-tooltip' ),  $version );
114
            wp_localize_script( 'wpinv-admin-script', 'WPInv_Admin', apply_filters( 'wpinv_admin_js_localize', $this->get_admin_i18() ) );
115
116
        }
117
118
        // Payment form scripts.
119
		if ( 'wpi_payment_form' == $page && $editing ) {
120
            $this->load_payment_form_scripts();
121
        }
122
123
		if ( $page == 'wpinv-subscriptions' ) {
124
			wp_enqueue_script( 'postbox' );
125
		}
126
127
    }
128
129
    /**
130
	 * Returns admin js translations.
131
	 *
132
	 */
133
	protected function get_admin_i18() {
134
        global $post;
135
136
		$date_range = array(
137
			'period' => isset( $_GET['date_range'] ) ? sanitize_text_field( $_GET['date_range'] ) : '7_days'
138
		);
139
140
		if ( $date_range['period'] == 'custom' ) {
141
			
142
			if ( isset( $_GET['from'] ) ) {
143
				$date_range[ 'after' ] = date( 'Y-m-d', strtotime( sanitize_text_field( $_GET['from'] ), current_time( 'timestamp' ) ) - DAY_IN_SECONDS );
144
			}
145
146
			if ( isset( $_GET['to'] ) ) {
147
				$date_range[ 'before' ] = date( 'Y-m-d', strtotime( sanitize_text_field( $_GET['to'] ), current_time( 'timestamp' ) ) + DAY_IN_SECONDS );
148
			}
149
150
		}
151
152
        $i18n = array(
153
            'ajax_url'                  => admin_url( 'admin-ajax.php' ),
154
            'post_ID'                   => isset( $post->ID ) ? $post->ID : '',
155
			'wpinv_nonce'               => wp_create_nonce( 'wpinv-nonce' ),
156
			'rest_nonce'                => wp_create_nonce( 'wp_rest' ),
157
			'rest_root'                 => esc_url_raw( rest_url() ),
158
			'date_range'                => $date_range,
159
            'add_invoice_note_nonce'    => wp_create_nonce( 'add-invoice-note' ),
160
            'delete_invoice_note_nonce' => wp_create_nonce( 'delete-invoice-note' ),
161
            'invoice_item_nonce'        => wp_create_nonce( 'invoice-item' ),
162
            'billing_details_nonce'     => wp_create_nonce( 'get-billing-details' ),
163
            'tax'                       => wpinv_tax_amount(),
164
            'discount'                  => 0,
165
			'currency_symbol'           => wpinv_currency_symbol(),
166
			'currency'                  => wpinv_get_currency(),
167
            'currency_pos'              => wpinv_currency_position(),
168
            'thousand_sep'              => wpinv_thousands_separator(),
169
            'decimal_sep'               => wpinv_decimal_separator(),
170
            'decimals'                  => wpinv_decimals(),
171
            'save_invoice'              => __( 'Save Invoice', 'invoicing' ),
172
            'status_publish'            => wpinv_status_nicename( 'publish' ),
173
            'status_pending'            => wpinv_status_nicename( 'wpi-pending' ),
174
            'delete_tax_rate'           => __( 'Are you sure you wish to delete this tax rate?', 'invoicing' ),
175
            'status_pending'            => wpinv_status_nicename( 'wpi-pending' ),
176
            'FillBillingDetails'        => __( 'Fill the user\'s billing information? This will remove any currently entered billing information', 'invoicing' ),
177
            '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' ),
178
            'AreYouSure'                => __( 'Are you sure?', 'invoicing' ),
179
            'errDeleteItem'             => __( 'This item is in use! Before delete this item, you need to delete all the invoice(s) using this item.', 'invoicing' ),
180
            'delete_subscription'       => __( 'Are you sure you want to delete this subscription?', 'invoicing' ),
181
            'action_edit'               => __( 'Edit', 'invoicing' ),
182
            'action_cancel'             => __( 'Cancel', 'invoicing' ),
183
            'item_description'          => __( 'Item Description', 'invoicing' ),
184
            'invoice_description'       => __( 'Invoice Description', 'invoicing' ),
185
            'discount_description'      => __( 'Discount Description', 'invoicing' ),
186
			'searching'                 => __( 'Searching', 'invoicing' ),
187
			'loading'                   => __( 'Loading...', 'invoicing' ),
188
			'search_customers'          => __( 'Enter customer name or email', 'invoicing' ),
189
			'search_items'              => __( 'Enter item name', 'invoicing' ),
190
        );
191
192
		if ( ! empty( $post ) && getpaid_is_invoice_post_type( $post->post_type ) ) {
193
194
			$invoice              = new WPInv_Invoice( $post );
195
			$i18n['save_invoice'] = sprintf(
196
				__( 'Save %s', 'invoicing' ),
197
				ucfirst( $invoice->get_invoice_quote_type() )
198
			);
199
200
			$i18n['invoice_description'] = sprintf(
201
				__( '%s Description', 'invoicing' ),
202
				ucfirst( $invoice->get_invoice_quote_type() )
203
			);
204
205
		}
206
		return $i18n;
207
	}
208
209
	/**
210
	 * Change the admin footer text on GetPaid admin pages.
211
	 *
212
	 * @since  2.0.0
213
	 * @param  string $footer_text
214
	 * @return string
215
	 */
216
	public function admin_footer_text( $footer_text ) {
217
		global $current_screen;
218
219
		$page    = isset( $_GET['page'] ) ? $_GET['page'] : '';
220
221
        if ( ! empty( $current_screen->post_type ) ) {
222
			$page = $current_screen->post_type;
223
        }
224
225
        // General styles.
226
        if ( apply_filters( 'getpaid_display_admin_footer_text', wpinv_current_user_can_manage_invoicing() ) && false !== stripos( $page, 'wpi' ) ) {
227
228
			// Change the footer text
229
			if ( ! get_user_meta( get_current_user_id(), 'getpaid_admin_footer_text_rated', true ) ) {
230
231
				$rating_url  = esc_url(
232
					wp_nonce_url(
233
						admin_url( 'admin.php?page=wpinv-reports&getpaid-admin-action=rate_plugin' ),
234
						'getpaid-nonce',
235
						'getpaid-nonce'
236
						)
237
				);
238
239
				$footer_text = sprintf(
240
					/* translators: %s: five stars */
241
					__( 'If you like <strong>GetPaid</strong>, please leave us a %s rating. A huge thanks in advance!', 'invoicing' ),
242
					"<a href='$rating_url'>&#9733;&#9733;&#9733;&#9733;&#9733;</a>"
243
				);
244
245
			} else {
246
247
				$footer_text = sprintf(
248
					/* translators: %s: GetPaid */
249
					__( 'Thank you for using %s!', 'invoicing' ),
250
					"<a href='https://wpgetpaid.com/' target='_blank'><strong>GetPaid</strong></a>"
251
				);
252
253
			}
254
255
		}
256
257
		return $footer_text;
258
	}
259
260
	/**
261
	 * Redirects to wp.org to rate the plugin.
262
	 *
263
	 * @since  2.0.0
264
	 */
265
	public function redirect_to_wordpress_rating_page() {
266
		update_user_meta( get_current_user_id(), 'getpaid_admin_footer_text_rated', 1 );
267
		wp_redirect( 'https://wordpress.org/support/plugin/invoicing/reviews?rate=5#new-post' );
268
		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...
269
	}
270
271
    /**
272
	 * Loads payment form js.
273
	 *
274
	 */
275
	protected function load_payment_form_scripts() {
276
        global $post;
277
278
        wp_enqueue_script( 'vue', WPINV_PLUGIN_URL . 'assets/js/vue/vue.js', array(), WPINV_VERSION );
279
		wp_enqueue_script( 'sortable', WPINV_PLUGIN_URL . 'assets/js/sortable.min.js', array(), WPINV_VERSION );
280
		wp_enqueue_script( 'vue_draggable', WPINV_PLUGIN_URL . 'assets/js/vue/vuedraggable.min.js', array( 'sortable', 'vue' ), WPINV_VERSION );
281
282
		$version = filemtime( WPINV_PLUGIN_DIR . 'assets/js/admin-payment-forms.js' );
283
		wp_register_script( 'wpinv-admin-payment-form-script', WPINV_PLUGIN_URL . 'assets/js/admin-payment-forms.js', array( 'wpinv-admin-script', 'vue_draggable' ),  $version );
284
285
		wp_localize_script(
286
            'wpinv-admin-payment-form-script',
287
            'wpinvPaymentFormAdmin',
288
            array(
289
				'elements'      => wpinv_get_data( 'payment-form-elements' ),
290
				'form_elements' => getpaid_get_payment_form_elements( $post->ID ),
291
				'currency'      => wpinv_currency_symbol(),
292
				'position'      => wpinv_currency_position(),
293
				'decimals'      => (int) wpinv_decimals(),
294
				'thousands_sep' => wpinv_thousands_separator(),
295
				'decimals_sep'  => wpinv_decimal_separator(),
296
				'form_items'    => gepaid_get_form_items( $post->ID ),
297
				'is_default'    => $post->ID == wpinv_get_default_payment_form(),
298
            )
299
        );
300
301
        wp_enqueue_script( 'wpinv-admin-payment-form-script' );
302
303
    }
304
305
    /**
306
	 * Add our classes to admin pages.
307
     *
308
     * @param string $classes
309
     * @return string
310
	 *
311
	 */
312
    public function admin_body_class( $classes ) {
313
		global $pagenow, $post, $current_screen;
314
315
316
        $page = isset( $_GET['page'] ) ? $_GET['page'] : '';
317
318
        if ( ! empty( $current_screen->post_type ) ) {
319
			$page = $current_screen->post_type;
320
        }
321
322
        if ( false !== stripos( $page, 'wpi' ) ) {
323
            $classes .= ' wpi-' . sanitize_key( $page );
324
        }
325
326
        if ( in_array( $page, wpinv_parse_list( 'wpi_invoice wpi_payment_form wpi_quote' ) ) ) {
327
            $classes .= ' wpinv-cpt wpinv';
328
		}
329
		
330
		if ( getpaid_is_invoice_post_type( $page ) ) {
331
            $classes .= ' getpaid-is-invoice-cpt';
332
        }
333
334
		return $classes;
335
    }
336
337
    /**
338
	 * Maybe show the AyeCode Connect Notice.
339
	 */
340
	public function init_ayecode_connect_helper(){
341
342
        new AyeCode_Connect_Helper(
343
            array(
344
				'connect_title' => __("WP Invoicing - an AyeCode product!","invoicing"),
345
				'connect_external'  => __( "Please confirm you wish to connect your site?","invoicing" ),
346
				'connect'           => sprintf( __( "<strong>Have a license?</strong> Forget about entering license keys or downloading zip files, connect your site for instant access. %slearn more%s","invoicing" ),"<a href='https://ayecode.io/introducing-ayecode-connect/' target='_blank'>","</a>" ),
347
				'connect_button'    => __("Connect Site","invoicing"),
348
				'connecting_button'    => __("Connecting...","invoicing"),
349
				'error_localhost'   => __( "This service will only work with a live domain, not a localhost.","invoicing" ),
350
				'error'             => __( "Something went wrong, please refresh and try again.","invoicing" ),
351
            ),
352
            array( 'wpi-addons' )
353
        );
354
355
    }
356
357
	/**
358
	 * Redirect users to settings on activation.
359
	 *
360
	 * @return void
361
	 */
362
	public function activation_redirect() {
363
364
		$redirected = get_option( 'wpinv_redirected_to_settings' );
365
366
		if ( ! empty( $redirected ) || wp_doing_ajax() || ! current_user_can( 'manage_options' ) ) {
367
			return;
368
		}
369
370
		// Bail if activating from network, or bulk
371
		if ( is_network_admin() || isset( $_GET['activate-multi'] ) ) {
372
			return;
373
		}
374
375
	    update_option( 'wpinv_redirected_to_settings', 1 );
376
377
        wp_safe_redirect( admin_url( 'admin.php?page=wpinv-settings&tab=general' ) );
378
        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...
379
380
	}
381
382
    /**
383
     * Fires an admin action after verifying that a user can fire them.
384
     */
385
    public function maybe_do_admin_action() {
386
387
        if ( wpinv_current_user_can_manage_invoicing() && isset( $_REQUEST['getpaid-admin-action'] ) && isset( $_REQUEST['getpaid-nonce'] ) && wp_verify_nonce( $_REQUEST['getpaid-nonce'], 'getpaid-nonce' ) ) {
388
            $key = sanitize_key( $_REQUEST['getpaid-admin-action'] );
389
            do_action( "getpaid_authenticated_admin_action_$key", $_REQUEST );
390
        }
391
392
    }
393
394
	/**
395
     * Sends a payment reminder to a customer.
396
	 * 
397
	 * @param array $args
398
     */
399
    public function send_customer_invoice( $args ) {
400
		$sent = getpaid()->get( 'invoice_emails' )->user_invoice( new WPInv_Invoice( $args['invoice_id'] ), true );
401
402
		if ( $sent ) {
403
			$this->show_success( __( 'Invoice was successfully sent to the customer', 'invoicing' ) );
404
		} else {
405
			$this->show_error( __( 'Could not send the invoice to the customer', 'invoicing' ) );
406
		}
407
408
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce', 'invoice_id' ) ) );
409
		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...
410
	}
411
412
	/**
413
     * Sends a payment reminder to a customer.
414
	 * 
415
	 * @param array $args
416
     */
417
    public function send_customer_payment_reminder( $args ) {
418
		$sent = getpaid()->get( 'invoice_emails' )->force_send_overdue_notice( new WPInv_Invoice( $args['invoice_id'] ) );
419
420
		if ( $sent ) {
421
			$this->show_success( __( 'Payment reminder was successfully sent to the customer', 'invoicing' ) );
422
		} else {
423
			$this->show_error( __( 'Could not sent payment reminder to the customer', 'invoicing' ) );
424
		}
425
426
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce', 'invoice_id' ) ) );
427
		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...
428
	}
429
430
	/**
431
     * Resets tax rates.
432
	 * 
433
     */
434
    public function admin_reset_tax_rates() {
435
436
		update_option( 'wpinv_tax_rates', wpinv_get_data( 'tax-rates' ) );
437
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
438
		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...
439
440
	}
441
442
	/**
443
     * Resets admin pages.
444
	 * 
445
     */
446
    public function admin_create_missing_pages() {
447
		$installer = new GetPaid_Installer();
448
		$installer->create_pages();
449
		$this->show_success( __( 'GetPaid pages updated.', 'invoicing' ) );
450
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
451
		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...
452
	}
453
454
	/**
455
     * Creates an missing admin tables.
456
	 * 
457
     */
458
    public function admin_create_missing_tables() {
459
		global $wpdb;
460
		$installer = new GetPaid_Installer();
461
462
		if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}wpinv_subscriptions'" ) != $wpdb->prefix . 'wpinv_subscriptions' ) {
463
			$installer->create_subscriptions_table();
464
465
			if ( $wpdb->last_error !== '' ) {
466
				$this->show_error( __( 'Your GetPaid tables have been updated:', 'invoicing' ) . ' ' . $wpdb->last_error );
467
			}
468
		}
469
470
		if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}getpaid_invoices'" ) != $wpdb->prefix . 'getpaid_invoices' ) {
471
			$installer->create_invoices_table();
472
473
			if ( $wpdb->last_error !== '' ) {
474
				$this->show_error( __( 'Your GetPaid tables have been updated:', 'invoicing' ) . ' ' . $wpdb->last_error );
475
			}
476
		}
477
478
		if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}getpaid_invoice_items'" ) != $wpdb->prefix . 'getpaid_invoice_items' ) {
479
			$installer->create_invoice_items_table();
480
481
			if ( $wpdb->last_error !== '' ) {
482
				$this->show_error( __( 'Your GetPaid tables have been updated:', 'invoicing' ) . ' ' . $wpdb->last_error );
483
			}
484
		}
485
486
		if ( ! $this->has_notices() ) {
487
			$this->show_success( __( 'Your GetPaid tables have been updated.', 'invoicing' ) );
488
		}
489
490
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
491
		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...
492
	}
493
494
	/**
495
     * Migrates old invoices to the new database tables.
496
	 * 
497
     */
498
    public function admin_migrate_old_invoices() {
499
500
		// Migrate the invoices.
501
		$installer = new GetPaid_Installer();
502
		$installer->migrate_old_invoices();
503
504
		// Show an admin message.
505
		$this->show_success( __( 'Your invoices have been migrated.', 'invoicing' ) );
506
507
		// Redirect the admin.
508
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
509
		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...
510
511
	}
512
513
	/**
514
     * Download customers.
515
	 * 
516
     */
517
    public function admin_download_customers() {
518
		global $wpdb;
519
520
		$output = fopen( 'php://output', 'w' ) or die( __( 'Unsupported server', 'invoicing' ) );
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...
521
522
		header( "Content-Type:text/csv" );
523
		header( "Content-Disposition:attachment;filename=customers.csv" );
524
525
		$post_types = '';
526
527
		foreach ( array_keys( getpaid_get_invoice_post_types() ) as $post_type ) {
528
			$post_types .= $wpdb->prepare( "post_type=%s OR ", $post_type );
529
		}
530
531
		$post_types = rtrim( $post_types, ' OR' );
532
533
		$customers = $wpdb->get_col(
534
			$wpdb->prepare(
535
				"SELECT DISTINCT( post_author ) FROM $wpdb->posts WHERE $post_types"
536
			)
537
		);
538
539
		$columns = array(
540
			'name'     => __( 'Name', 'invoicing' ),
541
			'email'    => __( 'Email', 'invoicing' ),
542
			'country'  => __( 'Country', 'invoicing' ),
543
			'state'    => __( 'State', 'invoicing' ),
544
			'city'     => __( 'City', 'invoicing' ),
545
			'zip'      => __( 'ZIP', 'invoicing' ),
546
			'address'  => __( 'Address', 'invoicing' ),
547
			'phone'    => __( 'Phone', 'invoicing' ),
548
			'company'  => __( 'Company', 'invoicing' ),
549
			'invoices' => __( 'Invoices', 'invoicing' ),
550
			'total'    => __( 'Total Spend', 'invoicing' ),
551
			'signup'   => __( 'Date created', 'invoicing' ),
552
		);
553
554
		// Output the csv column headers.
555
		fputcsv( $output, array_values( $columns ) );
556
557
		// Loop through
558
		$table = new WPInv_Customers_Table();
559
		foreach ( $customers as $customer_id ) {
560
561
			$user = get_user_by( 'id', $customer_id );
562
			$row  = array();
563
			if ( empty( $user ) ) {
564
				continue;
565
			}
566
567
			foreach ( array_keys( $columns ) as $column ) {
568
569
				$method = 'column_' . $column;
570
571
				if ( 'name' == $column ) {
572
					$value = sanitize_text_field( $user->display_name );
573
				} else if( 'email' == $column ) {
574
					$value = sanitize_email( $user->user_email );
575
				} else if ( is_callable( array( $table, $method ) ) ) {
576
					$value = strip_tags( $table->$method( $user ) );
577
				}
578
579
				if ( empty( $value ) ) {
580
					$value = sanitize_text_field( get_user_meta( $user->ID, '_wpinv_' . $column, true ) );
0 ignored issues
show
Bug introduced by
It seems like get_user_meta($user->ID,...pinv_' . $column, true) can also be of type false; however, parameter $str of sanitize_text_field() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

580
					$value = sanitize_text_field( /** @scrutinizer ignore-type */ get_user_meta( $user->ID, '_wpinv_' . $column, true ) );
Loading history...
581
				}
582
583
				$row[] = $value;
584
585
			}
586
587
			fputcsv( $output, $row );
588
		}
589
590
		fclose( $output );
591
		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...
592
593
	}
594
595
	/**
596
     * Installs a plugin.
597
	 *
598
	 * @param array $data
599
     */
600
    public function admin_install_plugin( $data ) {
601
602
		if ( ! empty( $data['plugins'] ) ) {
603
			include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
604
			wp_cache_flush();
605
606
			foreach ( $data['plugins'] as $slug => $file ) {
607
				$plugin_zip = esc_url( 'https://downloads.wordpress.org/plugin/' . $slug . '.latest-stable.zip' );
608
				$upgrader   = new Plugin_Upgrader( new Automatic_Upgrader_Skin() );
609
				$installed  = $upgrader->install( $plugin_zip );
610
611
				if ( ! is_wp_error( $installed ) && $installed ) {
612
					activate_plugin( $file, '', false, true );
613
				} else {
614
					wpinv_error_log( $upgrader->skin->get_upgrade_messages(), false );
0 ignored issues
show
Bug introduced by
$upgrader->skin->get_upgrade_messages() of type array 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

614
					wpinv_error_log( /** @scrutinizer ignore-type */ $upgrader->skin->get_upgrade_messages(), false );
Loading history...
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

614
					wpinv_error_log( $upgrader->skin->/** @scrutinizer ignore-call */ get_upgrade_messages(), false );
Loading history...
615
				}
616
617
			}
618
619
		}
620
621
		$redirect = isset( $data['redirect'] ) ? esc_url_raw( $data['redirect'] ) : admin_url( 'wp-admin/plugins.php' );
622
		wp_safe_redirect( $redirect );
623
		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...
624
625
	}
626
627
	/**
628
     * Recalculates discounts.
629
	 * 
630
     */
631
    public function admin_recalculate_discounts() {
632
		global $wpdb;
633
634
		// Fetch all invoices that have discount codes.
635
		$table    = $wpdb->prefix . 'getpaid_invoices';
636
		$invoices = $wpdb->get_col( "SELECT `post_id` FROM `$table` WHERE `discount` = 0 && `discount_code` <> ''" );
637
638
		foreach ( $invoices as $invoice ) {
639
640
			$invoice = new WPInv_Invoice( $invoice );
641
642
			if ( ! $invoice->exists() ) {
643
				continue;
644
			}
645
646
			// Abort if the discount does not exist or does not apply here.
647
			$discount = new WPInv_Discount( $invoice->get_discount_code() );
648
			if ( ! $discount->exists() ) {
649
				continue;
650
			}
651
652
			$invoice->add_discount( getpaid_calculate_invoice_discount( $invoice, $discount ) );
653
			$invoice->recalculate_total();
654
655
			if ( $invoice->get_total_discount() > 0 ) {
656
				$invoice->save();
657
			}
658
659
		}
660
661
		// Show an admin message.
662
		$this->show_success( __( 'Discounts have been recalculated.', 'invoicing' ) );
663
664
		// Redirect the admin.
665
		wp_safe_redirect( remove_query_arg( array( 'getpaid-admin-action', 'getpaid-nonce' ) ) );
666
		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...
667
668
	}
669
670
    /**
671
	 * Returns an array of admin notices.
672
	 *
673
	 * @since       1.0.19
674
     * @return array
675
	 */
676
	public function get_notices() {
677
		$notices = get_option( 'wpinv_admin_notices' );
678
        return is_array( $notices ) ? $notices : array();
679
	}
680
681
	/**
682
	 * Checks if we have any admin notices.
683
	 *
684
	 * @since       2.0.4
685
     * @return array
686
	 */
687
	public function has_notices() {
688
		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...
689
	}
690
691
	/**
692
	 * Clears all admin notices
693
	 *
694
	 * @access      public
695
	 * @since       1.0.19
696
	 */
697
	public function clear_notices() {
698
		delete_option( 'wpinv_admin_notices' );
699
	}
700
701
	/**
702
	 * Saves a new admin notice
703
	 *
704
	 * @access      public
705
	 * @since       1.0.19
706
	 */
707
	public function save_notice( $type, $message ) {
708
		$notices = $this->get_notices();
709
710
		if ( empty( $notices[ $type ] ) || ! is_array( $notices[ $type ]) ) {
711
			$notices[ $type ] = array();
712
		}
713
714
		$notices[ $type ][] = $message;
715
716
		update_option( 'wpinv_admin_notices', $notices );
717
	}
718
719
	/**
720
	 * Displays a success notice
721
	 *
722
	 * @param       string $msg The message to qeue.
723
	 * @access      public
724
	 * @since       1.0.19
725
	 */
726
	public function show_success( $msg ) {
727
		$this->save_notice( 'success', $msg );
728
	}
729
730
	/**
731
	 * Displays a error notice
732
	 *
733
	 * @access      public
734
	 * @param       string $msg The message to qeue.
735
	 * @since       1.0.19
736
	 */
737
	public function show_error( $msg ) {
738
		$this->save_notice( 'error', $msg );
739
	}
740
741
	/**
742
	 * Displays a warning notice
743
	 *
744
	 * @access      public
745
	 * @param       string $msg The message to qeue.
746
	 * @since       1.0.19
747
	 */
748
	public function show_warning( $msg ) {
749
		$this->save_notice( 'warning', $msg );
750
	}
751
752
	/**
753
	 * Displays a info notice
754
	 *
755
	 * @access      public
756
	 * @param       string $msg The message to qeue.
757
	 * @since       1.0.19
758
	 */
759
	public function show_info( $msg ) {
760
		$this->save_notice( 'info', $msg );
761
	}
762
763
	/**
764
	 * Show notices
765
	 *
766
	 * @access      public
767
	 * @since       1.0.19
768
	 */
769
	public function show_notices() {
770
771
        $notices = $this->get_notices();
772
        $this->clear_notices();
773
774
		foreach ( $notices as $type => $messages ) {
775
776
			if ( ! is_array( $messages ) ) {
777
				continue;
778
			}
779
780
            $type  = sanitize_key( $type );
781
			foreach ( $messages as $message ) {
782
                $message = wp_kses_post( $message );
783
				echo "<div class='notice notice-$type is-dismissible'><p>$message</p></div>";
784
            }
785
786
        }
787
788
		foreach ( array( 'checkout_page', 'invoice_history_page', 'success_page', 'failure_page', 'invoice_subscription_page' ) as $page ) {
789
790
			if ( ! is_numeric( wpinv_get_option( $page, false ) ) ) {
791
				$url     = wp_nonce_url(
792
					add_query_arg( 'getpaid-admin-action', 'create_missing_pages' ),
793
					'getpaid-nonce',
794
					'getpaid-nonce'
795
				);
796
				$message  = __( 'Some GetPaid pages are missing. To use GetPaid without any issues, click the button below to generate the missing pages.', 'invoicing' );
797
				$message2 = __( 'Generate Pages', 'invoicing' );
798
				echo "<div class='notice notice-warning is-dismissible'><p>$message<br><br><a href='$url' class='button button-primary'>$message2</a></p></div>";
799
				break;
800
			}
801
802
		}
803
804
	}
805
806
}
807