Issues (4296)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/class-give-cli-commands.php (41 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * GIVE WP_CLI commands
4
 *
5
 * @package give
6
 * @since   1.7
7
 */
8
9
// Exit if accessed directly.
10
if ( ! defined( 'ABSPATH' ) ) {
11
	exit;
12
}
13
14
// Add give command.
15
WP_CLI::add_command( 'give', 'GIVE_CLI_COMMAND' );
16
17
18
/**
19
 * Work with Give through WP-CLI
20
 *
21
 * Adds CLI support to Give through WP-CLI
22
 *
23
 * @since 1.7
24
 */
25
class GIVE_CLI_COMMAND {
26
27
	/**
28
	 * This param uses to count process/step inside loop.
29
	 *
30
	 * @var int $counter Counter.
31
	 */
32
	private static $counter;
33
34
	/**
35
	 * This helps to get information give plugin data.
36
	 *
37
	 * @var Give_API Object.
38
	 */
39
	private $api;
40
41
	/**
42
	 * This helps to get unique name.
43
	 *
44
	 * @since 1.8.17
45
	 * @var array
46
	 */
47
	private $new_donor_names = array();
48
49
50
	/**
51
	 * GIVE_CLI_Command constructor.
52
	 */
53
	public function __construct() {
54
		$this->api = new Give_API();
55
	}
56
57
58
	/**
59
	 * Get Give logo
60
	 *
61
	 * ## OPTIONS
62
	 *
63
	 * None. for a fun surprise.
64
	 *
65
	 * ## EXAMPLES
66
	 *
67
	 * wp give logo
68
	 *
69
	 * @since         1.7
70
	 * @access        public
71
	 *
72
	 * @param        string $args       Command Data.
73
	 * @param        array  $assoc_args List of command data.
74
	 *
75
	 * @return        void
76
	 *
77
	 * @subcommand    logo
78
	 */
79
	public function ascii( $args, $assoc_args ) {
0 ignored issues
show
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $assoc_args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
80
		WP_CLI::log( file_get_contents( GIVE_PLUGIN_DIR . 'assets/dist/images/give-ascii-logo.txt' ) );
0 ignored issues
show
file_get_contents is highly discouraged, please use wpcom_vip_file_get_contents() instead.
Loading history...
81
	}
82
83
84
	/**
85
	 * Get Give details
86
	 *
87
	 * ## OPTIONS
88
	 *
89
	 * None. Returns basic info regarding your Give instance.
90
	 *
91
	 * ## EXAMPLES
92
	 *
93
	 * wp give details
94
	 *
95
	 * @since         1.7
96
	 * @access        public
97
	 *
98
	 * @param        string $args       Command Data.
99
	 * @param        array  $assoc_args List of command data.
100
	 *
101
	 * @return        void
102
	 *
103
	 * @subcommand    details
104
	 */
105
	public function details( $args, $assoc_args ) {
0 ignored issues
show
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $assoc_args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
106
107
		/**
108
		 * Plugin Information
109
		 */
110
		WP_CLI::log( $this->color_message( __( 'Give Version: ', 'give' ) ) . GIVE_VERSION );
0 ignored issues
show
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'GIVE_VERSION'
Loading history...
111
112
		/**
113
		 * General Information.
114
		 */
115
		WP_CLI::log( "\n####   " . $this->color_message( __( 'General information', 'give' ) ) . '   ####' );
116
117
		$success_page = give_get_option( 'success_page' );
118
		$failure_page = give_get_option( 'failure_page' );
119
		$history_page = give_get_option( 'history_page' );
120
121
		WP_CLI::log( $this->color_message( sprintf( __( 'Success Page: ', 'give' ) ) ) . ( $success_page ? "[{$success_page}] " . get_permalink( $success_page ) : __( 'Not Set', 'give' ) ) );
0 ignored issues
show
Expected next thing to be a escaping function, not '('
Loading history...
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'get_permalink'
Loading history...
122
		WP_CLI::log( $this->color_message( __( 'Failed Donation Page: ', 'give' ) ) . ( $failure_page ? "[{$failure_page}] " . get_permalink( $failure_page ) : __( 'Not Set', 'give' ) ) );
0 ignored issues
show
Expected next thing to be a escaping function, not '('
Loading history...
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'get_permalink'
Loading history...
123
		WP_CLI::log( $this->color_message( __( 'Donation History Page: ', 'give' ) ) . ( $history_page ? "[{$history_page}] " . get_permalink( $history_page ) : __( 'Not Set', 'give' ) ) );
0 ignored issues
show
Expected next thing to be a escaping function, not '('
Loading history...
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'get_permalink'
Loading history...
124
		WP_CLI::log( $this->color_message( __( 'Country: ', 'give' ) ) . give_get_country() );
0 ignored issues
show
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'give_get_country'
Loading history...
125
126
		/**
127
		 * Currency Information.
128
		 */
129
		$default_gateway = give_get_option( 'default_gateway' );
130
131
		WP_CLI::log( "\n####   " . $this->color_message( __( 'Currency Information', 'give' ) ) . '   ####' );
132
133
		WP_CLI::log( $this->color_message( __( 'Currency: ', 'give' ), give_get_currency() ) );
134
		WP_CLI::log( $this->color_message( __( 'Currency Position: ', 'give' ), give_get_currency_position() ) );
135
		WP_CLI::log( $this->color_message( __( 'Thousand Separator: ', 'give' ), give_get_price_thousand_separator() ) );
136
		WP_CLI::log( $this->color_message( __( 'Decimal Separator: ', 'give' ), give_get_price_decimal_separator() ) );
137
		WP_CLI::log( $this->color_message( __( 'Number of Decimals: ', 'give' ), give_get_price_decimals() ) );
138
		WP_CLI::log( $this->color_message( __( 'Test Mode: ', 'give' ), ( give_get_option( 'test_mode' ) ? __( 'Yes', 'give' ) : __( 'No', 'give' ) ) ) );
139
		WP_CLI::log( $this->color_message( __( 'Default Gateway: ', 'give' ), ( $default_gateway ? $default_gateway : __( 'Not Set', 'give' ) ) ) );
140
141
		// Payment gateways Information.
142
		$gateways = give_get_ordered_payment_gateways( give_get_payment_gateways() );
143
		WP_CLI::log( $this->color_message( __( 'Enabled Gateways: ', 'give' ) ) );
144
145
		if ( ! empty( $gateways ) ) {
146
			self::$counter = 1;
147
			foreach ( $gateways as $gateway ) {
148
				WP_CLI::log( '  ' . $this->color_message( self::$counter, $gateway['admin_label'] ) );
149
				self::$counter ++;
150
			}
151
		} else {
152
			WP_CLI::log( __( 'Not any payment gateways found', 'give' ) );
153
		}
154
	}
155
156
157
	/**
158
	 * Get the forms currently posted on your Give site
159
	 *
160
	 * ## OPTIONS
161
	 *
162
	 * [--id=<form_id>]
163
	 * : A specific form ID to retrieve
164
	 *
165
	 * [--number=<form_count>]
166
	 * : Number of form to retrieve
167
	 *
168
	 * ## EXAMPLES
169
	 *
170
	 * wp give forms
171
	 * wp give forms --id=103
172
	 * wp give forms --number=103
173
	 *
174
	 * @since         1.7
175
	 * @access        public
176
	 *
177
	 * @param        string $args       Command Data.
178
	 * @param        array  $assoc_args List of command data.
179
	 *
180
	 * @return        void
181
	 *
182
	 * @subcommand    forms
183
	 */
184
	public function forms( $args, $assoc_args ) {
0 ignored issues
show
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
185
		global $wp_query;
186
		$form_id = isset( $assoc_args ) && array_key_exists( 'id', $assoc_args ) ? absint( $assoc_args['id'] ) : false;
187
		$number  = isset( $assoc_args ) && array_key_exists( 'number', $assoc_args ) ? absint( $assoc_args['number'] ) : 10;
188
		$start   = time();
0 ignored issues
show
$start is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
189
190
		// Cache previous number query var.
191
		$is_set_number = $cache_per_page = false;
192 View Code Duplication
		if ( isset( $wp_query->query_vars['number'] ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
193
			$cache_per_page = $wp_query->query_vars['number'];
194
			$is_set_number  = true;
195
		}
196
197
		// Change number query var.
198
		$wp_query->query_vars['number'] = $number;
199
200
		// Get forms.
201
		$forms = $form_id ? $this->api->get_forms( $form_id ) : $this->api->get_forms();
202
203
		// Reset number query var.
204
		if ( $is_set_number ) {
205
			$wp_query->query_vars['number'] = $cache_per_page;
206
		}
207
208
		// Bailout.
209
		if ( array_key_exists( 'error', $forms ) ) {
210
211
			WP_CLI::warning( $forms['error'] );
212
213
			return;
214
		} elseif ( empty( $forms['forms'] ) ) {
215
216
			WP_CLI::error( __( 'No forms found.', 'give' ) );
217
218
			return;
219
		}
220
221
		// Param to check if form typeis already showed or not.
222
		$is_show_form_type = false;
223
224
		if ( 1 === count( $forms ) && $form_id ) {
225
			// Show single form.
226
			foreach ( $forms['forms'][0] as $key => $info ) {
227
				switch ( $key ) {
228
					case 'stats':
229
						$this->color_main_heading( ucfirst( $key ) );
230
231
						foreach ( $info as $heading => $data ) {
232
							$this->color_sub_heading( ucfirst( $heading ) );
233
							switch ( $heading ) {
234
								default:
0 ignored issues
show
default: foreach ($d...data)); } } does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
235
									foreach ( $data as $subheading => $subdata ) {
236
237
										switch ( $subheading ) {
238
											case 'earnings':
239
												WP_CLI::log( $this->color_message( $subheading . ': ', give_currency_filter( $subdata ) ) );
240
												break;
241
											default:
242
												WP_CLI::log( $this->color_message( $subheading . ': ', $subdata ) );
243
										}
244
									}
245
							}
246
						}
247
						break;
248
249
					case 'pricing':
250
					case 'info':
251
					default:
252
						$this->color_main_heading( ucfirst( $key ) );
253
254
						// Show form type.
255
						if ( ! $is_show_form_type ) {
256
							$form              = new Give_Donate_Form( $form_id );
257
							$is_show_form_type = true;
258
259
							WP_CLI::log( $this->color_message( __( 'form type', 'give' ), $form->get_type() ) );
260
						}
261
262
						foreach ( $info as $heading => $data ) {
263
264
							switch ( $heading ) {
265
								case 'id':
266
									WP_CLI::log( $this->color_message( $heading, $data ) );
267
									break;
268
269
								default:
270
									$data = empty( $data ) ? __( 'Not set', 'give' ) : $data;
271
									WP_CLI::log( $this->color_message( $heading, $data ) );
272
							}
273
						}
274
				}// End switch().
275
			}// End foreach().
276
		} else {
277
			// Show multiple form.
278
			$table_data             = array();
279
			$is_table_first_row_set = false;
280
			$table_column_count     = 0;
0 ignored issues
show
$table_column_count is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
281
282
			WP_CLI::line( $this->color_message( sprintf( __( '%d donation forms found', 'give' ), count( $forms['forms'] ) ), '', false ) );
283
284
			foreach ( $forms['forms'] as $index => $form_data ) {
285
286
				// Default table data.
287
				$table_first_row = array();
288
				$table_row       = array();
289
290
				foreach ( $form_data['info'] as $key => $form ) {
291
292
					// Do not show thumbnail, content and link in table.
293
					if ( in_array( $key, array( 'content', 'thumbnail', 'link' ), true ) ) {
294
						continue;
295
					}
296
297
					if ( ! $is_table_first_row_set ) {
298
						$table_first_row[] = $key;
299
					}
300
301
					$table_row[] = $form;
302
303
					if ( 'status' === $key ) {
304
						// First array item will be an form id in our case.
305
						$form = new Give_Donate_Form( absint( $table_row[0] ) );
306
307
						$table_row[] = $form->get_type();
308
					}
309
				}
310
311
				// Set table first row.
312
				if ( ! $is_table_first_row_set ) {
313
314
					// Add extra column to table.
315
					$table_first_row[] = 'type';
316
317
					$table_data[]           = $table_first_row;
318
					$is_table_first_row_set = true;
319
				}
320
321
				// set table data.
322
				$table_data[] = $table_row;
323
			}// End foreach().
324
325
			$this->display_table( $table_data );
326
		}// End if().
327
	}
328
329
330
	/**
331
	 * Get the donors currently on your Give site. Can also be used to create donors records
332
	 *
333
	 * ## OPTIONS
334
	 *
335
	 * [--id=<donor_id>]
336
	 * : A specific donor ID to retrieve
337
	 *
338
	 * [--email=<donor_email>]
339
	 * : The email address of the donor to retrieve
340
	 *
341
	 * [--number=<donor_count>]
342
	 * : The number of donor to retrieve
343
	 *
344
	 * [--create=<number>]
345
	 * : The number of arbitrary donors to create. Leave as 1 or blank to create a
346
	 * donor with a specific email
347
	 *
348
	 * [--form-id=<donation_form_id>]
349
	 * : Get list of donors of specific donation form
350
	 *
351
	 * [--name=<name_of_donor>]
352
	 * : Name with which you want to create new donor
353
	 *
354
	 * [--format=<output_format>]
355
	 * : In which format you want to see results. Valid formats: table, json, csv
356
	 *
357
	 * ## EXAMPLES
358
	 *
359
	 * wp give donors
360
	 * wp give donors --id=103
361
	 * wp give donors [email protected]
362
	 * wp give donors --create=1 [email protected]
363
	 * wp give donors --create=1 [email protected] --name="John Doe"
364
	 * wp give donors --create=1000
365
	 * wp give donors --number=1000
366
	 * wp give donors --form-id=1024
367
	 *
368
	 * @since         1.7
369
	 * @access        public
370
	 *
371
	 * @param        string $args       Command Data.
372
	 * @param        array  $assoc_args List of command data.
373
	 *
374
	 * @return        void
375
	 *
376
	 * @subcommand    donors
377
	 */
378
	public function donors( $args, $assoc_args ) {
0 ignored issues
show
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
379
		global $wp_query;
380
		$donor_id = isset( $assoc_args ) && array_key_exists( 'id', $assoc_args ) ? absint( $assoc_args['id'] ) : false;
381
		$email    = isset( $assoc_args ) && array_key_exists( 'email', $assoc_args ) ? $assoc_args['email'] : false;
382
		$name     = isset( $assoc_args ) && array_key_exists( 'name', $assoc_args ) ? $assoc_args['name'] : '';
383
		$create   = isset( $assoc_args ) && array_key_exists( 'create', $assoc_args ) ? $assoc_args['create'] : false;
384
		$number   = isset( $assoc_args ) && array_key_exists( 'number', $assoc_args ) ? $assoc_args['number'] : 10;
385
		$form_id  = isset( $assoc_args ) && array_key_exists( 'form-id', $assoc_args ) ? $assoc_args['form-id'] : 0;
386
		$format   = isset( $assoc_args ) && array_key_exists( 'format', $assoc_args ) ? $assoc_args['format'] : 'table';
387
		$start    = time();
388
389
		if ( $create ) {
390
			if ( 80 < $create ) {
391
				WP_CLI::warning( 'Currently we can only generate maximum 80 donors.', 'give' );
392
				$create = 80;
393
			}
394
395
			$number = 1;
396
397
			if ( isset( $assoc_args['email'] ) && ! is_email( $email ) ) {
398
				WP_CLI::warning( 'Wrong email address provided.', 'give' );
399
400
				return;
401
			}
402
403
			// Create one or more donors.
404
			if ( ! $email ) {
405
				// If no email is specified, look to see if we are generating arbitrary donor accounts.
406
				$number = is_numeric( $create ) ? absint( $create ) : 1;
407
			}
408
409
			for ( $i = 0; $i < $number; $i ++ ) {
410
				$name  = $name ? $name : $this->get_random_name();
411
				$email = $email ? $email : $this->get_random_email( $name );
412
413
				$args = array(
414
					'email' => $email,
415
					'name'  => $name,
416
				);
417
418
				$donor_id = Give()->donors->add( $args );
419
420
				if ( $donor_id ) {
421
					WP_CLI::line( $this->color_message( sprintf( __( 'Donor #%d created successfully', 'give' ), $donor_id ) ) );
422
				} else {
423
					WP_CLI::error( __( 'Failed to create donor', 'give' ) );
424
				}
425
426
				// Reset email and name to false so it is generated on the next loop (if creating donors).
427
				$email = $name = false;
428
			}
429
430
			WP_CLI::line( $this->color_message( sprintf( __( '%1$d donors created in %2$d seconds', 'give' ), $number, time() - $start ) ) );
431
432
		} else {
433
			// Counter.
434
			self::$counter = 1;
435
436
			// Search for customers.
437
			$search = $donor_id ? $donor_id : $email;
438
439
			/**
440
			 * Get donors.
441
			 */
442
			// Cache previous number query var.
443
			$is_set_number = $cache_per_page = false;
444 View Code Duplication
			if ( isset( $wp_query->query_vars['number'] ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
445
				$cache_per_page = $wp_query->query_vars['number'];
446
				$is_set_number  = true;
447
			}
448
449
			// Change number query var.
450
			$wp_query->query_vars['number'] = $number;
451
452
			// Get donors.
453
			if ( $form_id ) {
454
				// @TODO: Allow user to get a list of donors by donation status.
455
				$donors = $this->get_donors_by_form_id( $form_id );
456
			} else {
457
				$donors = $this->api->get_donors( $search );
458
			}
459
460
			// Reset number query var.
461
			if ( $is_set_number ) {
462
				$wp_query->query_vars['number'] = $cache_per_page;
463
			}
464
465
			if ( isset( $donors['error'] ) ) {
466
				WP_CLI::error( $donors['error'] );
467
			}
468
469
			if ( empty( $donors ) ) {
470
				WP_CLI::error( __( 'No donors found.', 'give' ) );
471
472
				return;
473
			}
474
475
			$table_data             = array();
476
			$is_table_first_row_set = false;
477
478
			foreach ( $donors['donors'] as $donor_data ) {
479
				// Set default table row data.
480
				$table_first_row = array( __( 's_no', 'give' ) );
481
				$table_row       = array( self::$counter );
482
483
				foreach ( $donor_data as $key => $donor ) {
484
					switch ( $key ) {
485
						case 'stats':
486
							foreach ( $donor as $heading => $data ) {
487
488
								// Get first row.
489
								if ( ! $is_table_first_row_set ) {
490
									$table_first_row[] = $heading;
491
								}
492
493
								switch ( $heading ) {
494
									case 'total_spent':
495
										$table_row[] = give_currency_filter( $data );
496
										break;
497
498
									default:
499
										$table_row[] = $data;
500
								}
501
							}
502
							break;
503
504
						case 'info':
505
						default:
506
							foreach ( $donor as $heading => $data ) {
507
508
								// Get first row.
509
								if ( ! $is_table_first_row_set ) {
510
									$table_first_row[] = $heading;
511
								}
512
513
								$table_row[] = $data;
514
							}
515
					}
516
				}
517
518
				// Add first row data to table data.
519
				if ( ! $is_table_first_row_set ) {
520
					$table_data[]           = $table_first_row;
521
					$is_table_first_row_set = true;
522
				}
523
524
				// Add table row data.
525
				$table_data[] = $table_row;
526
527
				// Increase counter.
528
				self::$counter ++;
529
			}// End foreach().
530
531
			switch ( $format ) {
532
				case 'json':
533
					$table_column_name = $table_data[0];
534
					unset( $table_data[0] );
535
536
					$new_table_data = array();
537
					foreach ( $table_data as $index => $data ) {
538
						foreach ( $data as $key => $value ) {
539
							$new_table_data[ $index ][ $table_column_name[ $key ] ] = $value;
540
						}
541
					}
542
543
					WP_CLI::log( json_encode( $new_table_data ) );
544
					break;
545
546
				case 'csv':
547
					$file_path = trailingslashit( WP_CONTENT_DIR ) . 'uploads/give_donors_' . date( 'Y_m_d_s', current_time( 'timestamp' ) ) . '.csv';
548
					$fp        = fopen( $file_path, 'w' );
549
550
					if ( is_writable( $file_path ) ) {
0 ignored issues
show
Filesystem writes are forbidden, you should not be using is_writable()
Loading history...
551
						foreach ( $table_data as $fields ) {
552
							fputcsv( $fp, $fields );
0 ignored issues
show
Filesystem writes are forbidden, you should not be using fputcsv()
Loading history...
553
						}
554
555
						fclose( $fp );
556
557
						WP_CLI::success( "Donors list csv created successfully: {$file_path}" );
558
					} else {
559
						WP_CLI::warning( "Unable to create donors list csv file: {$file_path} (May folder do not have write permission)" );
560
					}
561
562
					break;
563
564
				default:
565
					$this->display_table( $table_data );
566
			}// End switch().
567
		}// End if().
568
	}
569
570
571
	/**
572
	 * Get the recent donations for your Give site
573
	 *
574
	 * ## OPTIONS
575
	 *
576
	 * [--number=<donation_count>]
577
	 * : The number of donations to retrieve
578
	 *
579
	 *
580
	 * ## EXAMPLES
581
	 *
582
	 * wp give donations
583
	 * wp give donations --number=100
584
	 *
585
	 * @since         1.7
586
	 * @access        public
587
	 *
588
	 * @param        string $args       Command Data.
589
	 * @param        array  $assoc_args List of command data.
590
	 *
591
	 * @return        void
592
	 *
593
	 * @subcommand    donations
594
	 */
595
	public function donations( $args, $assoc_args ) {
0 ignored issues
show
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
596
		global $wp_query;
597
		$number = isset( $assoc_args ) && array_key_exists( 'number', $assoc_args ) ? $assoc_args['number'] : 10;
598
599
		// Cache previous number query var.
600
		$is_set_number = $cache_per_page = false;
601 View Code Duplication
		if ( isset( $wp_query->query_vars['number'] ) ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
602
			$cache_per_page = $wp_query->query_vars['number'];
603
			$is_set_number  = true;
604
		}
605
606
		// Change number query var.
607
		$wp_query->query_vars['number'] = $number;
608
609
		// Get donations.
610
		$donations = $this->api->get_recent_donations();
611
612
		// Reset number query var.
613
		if ( $is_set_number ) {
614
			$wp_query->query_vars['number'] = $cache_per_page;
615
		}
616
617
		if ( empty( $donations ) ) {
618
			WP_CLI::error( __( 'No donations found.', 'give' ) );
619
620
			return;
621
		}
622
623
		self::$counter = 1;
624
625
		foreach ( $donations['donations'] as $key => $donation ) {
626
			$this->color_main_heading( sprintf( __( '%1$s. Donation #%2$s', 'give' ), self::$counter, $donation['ID'] ), 'Y' );
627
			self::$counter ++;
628
629
			foreach ( $donation as $column => $data ) {
630
631
				if ( is_array( $data ) ) {
632
					$this->color_sub_heading( $column );
633
					foreach ( $data as $subcolumn => $subdata ) {
634
635
						// Decode html codes.
636
						switch ( $subcolumn ) {
637
							case 'name':
638
								$subdata = html_entity_decode( $subdata );
639
								break;
640
						}
641
642
						// @TODO Check if multi dimension array information is importent to show or not. For example inside donation array we have array for fees data inside payment meta.
643
						if ( is_array( $subdata ) ) {
644
							continue;
645
						}
646
647
						WP_CLI::log( $this->color_message( $subcolumn, $subdata ) );
648
					}
649
					continue;
650
				}
651
652
				WP_CLI::log( $this->color_message( $column, $data ) );
653
			}
654
		}
655
	}
656
657
	/**
658
	 * Get give plugin report.
659
	 *
660
	 * ## OPTIONS
661
	 *
662
	 * [--id=<donation_form_id>]
663
	 * : The ID of a specific donation_form to retrieve stats for, or all
664
	 *
665
	 * [--date=<range|this_month|last_month|today|yesterday|this_quarter|last_quarter|this_year|last_year>]
666
	 * : A specific date range to retrieve stats for
667
	 *
668
	 * [--start-date=<date>]
669
	 * : The start date of a date range to retrieve stats for. Date format is MM/DD/YYYY
670
	 *
671
	 * [--end-date=<date>]
672
	 * : The end date of a date range to retrieve stats for. Date format is MM/DD/YYYY
673
	 *
674
	 * ## EXAMPLES
675
	 *
676
	 * wp give report
677
	 * wp give report --date=this_month
678
	 * wp give report --start-date=01/02/2014 --end-date=02/23/2014
679
	 * wp give report --date=last_year
680
	 * wp give report --date=last_year --id=15
681
	 *
682
	 * @since         1.7
683
	 * @access        public
684
	 *
685
	 * @param        string $args       Command Data.
686
	 * @param        array  $assoc_args List of command data.
687
	 *
688
	 * @subcommand    report
689
	 *
690
	 * @return        void
691
	 */
692
	public function report( $args, $assoc_args ) {
0 ignored issues
show
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
693
		$stats      = new Give_Payment_Stats();
694
		$date       = isset( $assoc_args ) && array_key_exists( 'date', $assoc_args ) ? $assoc_args['date'] : false;
695
		$start_date = isset( $assoc_args ) && array_key_exists( 'start-date', $assoc_args ) ? $assoc_args['start-date'] : false;
696
		$end_date   = isset( $assoc_args ) && array_key_exists( 'end-date', $assoc_args ) ? $assoc_args['end-date'] : false;
697
		$form_id    = isset( $assoc_args ) && array_key_exists( 'id', $assoc_args ) ? $assoc_args['id'] : 0;
698
699
		if ( ! empty( $date ) ) {
700
			$start_date = $date;
701
			$end_date   = false;
702
		} elseif ( empty( $date ) && empty( $start_date ) ) {
703
			$start_date = 'this_month';
704
			$end_date   = false;
705
		}
706
707
		// Get stats.
708
		$earnings = $stats->get_earnings( $form_id, $start_date, $end_date );
709
		$sales    = $stats->get_sales( $form_id, $start_date, $end_date );
710
711
		WP_CLI::line( $this->color_message( __( 'Earnings', 'give' ), give_currency_filter( $earnings, array( 'decode_currency' => true ) ) ) );
712
		WP_CLI::line( $this->color_message( __( 'Sales', 'give' ), $sales ) );
713
	}
714
715
716
	/**
717
	 * Delete cache (transient).
718
	 *
719
	 * ## OPTIONS
720
	 *
721
	 * --action=<cache_action>
722
	 * : Value of this parameter can be delete (in case you want to delete all stat cache).
723
	 *
724
	 * ## EXAMPLES
725
	 *
726
	 *    # See form report
727
	 *    wp give cache --action=delete
728
	 *
729
	 * @since         1.7
730
	 * @access        public
731
	 *
732
	 * @param        string $args       Command Data.
733
	 * @param        array  $assoc_args List of command data.
734
	 *
735
	 * @return        void
736
	 *
737
	 * @subcommand    cache
738
	 */
739
	public function cache( $args, $assoc_args ) {
0 ignored issues
show
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
740
		$action = isset( $assoc_args ) && array_key_exists( 'action', $assoc_args ) ? $assoc_args['action'] : false;
741
742
		// Bailout.
743
		if ( ! $action || ! in_array( $action, array( 'delete' ), true ) ) {
744
			WP_CLI::warning( __( 'Type wp give cache --action=delete to delete all stat transients', 'give' ) );
745
746
			return;
747
		}
748
749
		switch ( $action ) {
750
			case 'delete':
751
				// Reset counter.
752
				self::$counter = 1;
753
754
				if ( $this->delete_stats_transients() ) {
755
					// Report .eading.
756
					WP_CLI::success( 'Give cache deleted.' );
757
				} else {
758
					// Report .eading.
759
					WP_CLI::warning( 'We did not find any Give plugin cache to delete :)' );
760
				}
761
				break;
762
		}
763
764
	}
765
766
	/**
767
	 * Delete all form stat transient
768
	 *
769
	 * @since     1.7
770
	 * @access    private
771
	 *
772
	 * @return    bool
773
	 */
774
	private function delete_stats_transients() {
775
		global $wpdb;
776
777
		$stat_option_names = $wpdb->get_results(
0 ignored issues
show
Usage of a direct database call is discouraged.
Loading history...
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
778
			$wpdb->prepare(
779
				"SELECT option_name FROM {$wpdb->options} where (option_name LIKE '%%%s%%' OR option_name LIKE '%%%s%%')",
780
				array(
781
					'_transient_give_stats_',
782
					'give_cache',
783
				)
784
			),
785
			ARRAY_A
786
		);
787
788
		if ( ! empty( $stat_option_names ) ) {
789
790
			foreach ( $stat_option_names as $option_name ) {
791
				$error       = false;
0 ignored issues
show
$error is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
792
				$option_name = $option_name['option_name'];
793
794 View Code Duplication
				switch ( true ) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
795
					case ( false !== strpos( $option_name, 'transient' ) ):
796
						$option_name = str_replace( '_transient_', '', $option_name );
797
						$error       = delete_transient( $option_name );
798
						break;
799
800
					default:
801
						$error = delete_option( $option_name );
802
				}
803
804
				if ( $error ) {
805
					WP_CLI::log( $this->color_message( self::$counter, $option_name ) );
806
					self::$counter ++;
807
				} else {
808
					WP_CLI::log( $this->color_message( __( 'Error while deleting this transient', 'give' ), $option_name ) );
809
				}
810
			}
811
812
			return true;
813
		}
814
815
		return false;
816
	}
817
818
819
	/**
820
	 * Return colored message
821
	 *
822
	 * @param    string $heading Message heading.
823
	 * @param    string $message Message content.
824
	 * @param    bool   $colon   Check if add colon between heading and message.
825
	 * @param    string $color   Heading color.
826
	 *
827
	 * @return   string
828
	 */
829
	private function color_message( $heading, $message = '', $colon = true, $color = 'g' ) {
830
		// Add colon.
831
		if ( $colon ) {
832
			$heading = $heading . ': ';
833
		}
834
835
		return WP_CLI::colorize( "%{$color}" . $heading . '%n' ) . $message;
836
	}
837
838
839
	/**
840
	 * Output section heading.
841
	 *
842
	 * @since     1.7
843
	 * @access    private
844
	 *
845
	 * @param    string $heading Heading.
846
	 * @param    string $color   Color.
847
	 *
848
	 * @return    void
849
	 */
850
	private function color_main_heading( $heading, $color = 'g' ) {
851
		WP_CLI::log( "\n######   " . $this->color_message( $heading, '', false, $color ) . '   ######' );
852
	}
853
854
	/**
855
	 * Output section sub heading.
856
	 *
857
	 * @since     1.7
858
	 * @access    private
859
	 *
860
	 * @param    string $subheading Sub heading.
861
	 *
862
	 * @return    void
863
	 */
864
	private function color_sub_heading( $subheading ) {
865
		WP_CLI::log( "\n--->" . $subheading . '', '', false );
866
	}
867
868
869
	/**
870
	 * Display data in table format.
871
	 *
872
	 * @since     1.7
873
	 * @access    private
874
	 *
875
	 * @param    array $data Array of table data.
876
	 *
877
	 * @return    void
878
	 */
879
	private function display_table( $data ) {
880
		$table = new \cli\Table();
881
882
		// Set table header.
883
		$table->setHeaders( $data[0] );
884
885
		// Remove table header.
886
		unset( $data[0] );
887
888
		// Set table data.
889
		$table->setRows( $data );
890
891
		// Display table.
892
		$table->display();
893
	}
894
895
896
	/**
897
	 * Get donors by form id.
898
	 *
899
	 * @since 1.8
900
	 *
901
	 * @param int $form_id From id.
902
	 *
903
	 * @return array
904
	 */
905
906
	private function get_donors_by_form_id( $form_id ) {
907
		$donors = array();
908
909
		$donations = new Give_Payments_Query(
910
			array(
911
				'give_forms' => array( $form_id ),
912
				'number'     => - 1,
913
				'status'     => array( 'publish' ),
914
			)
915
		);
916
917
		$donations   = $donations->get_payments();
918
		$skip_donors = array();
919
920
		/* @var Give_Payment|object $donation Payment object. */
921
		foreach ( $donations as $donation ) {
922
923
			if ( in_array( $donation->customer_id, $skip_donors, true ) ) {
924
				continue;
925
			}
926
927
			if ( ! empty( $donors ) ) {
928
				$donors['donors'][] = current( current( $this->api->get_donors( (int) $donation->customer_id ) ) );
929
			} else {
930
				$donors = array_merge( $donors, $this->api->get_donors( (int) $donation->customer_id ) );
931
			}
932
933
			$skip_donors[] = $donation->customer_id;
934
		}
935
936
		return $donors;
937
	}
938
939
	/**
940
	 * Get random user name
941
	 *
942
	 * @since 1.8.17
943
	 * @return string
944
	 */
945
	private function get_random_name() {
946
		// First names.
947
		$names = array(
948
			'Devin',
949
			'Christopher',
950
			'Ryan',
951
			'Ethan',
952
			'John',
953
			'Zoey',
954
			'Sarah',
955
			'Michelle',
956
			'Samantha',
957
		);
958
959
		// Surnames.
960
		$surnames = array(
961
			'Walker',
962
			'Josh',
963
			'Thompson',
964
			'Anderson',
965
			'Johnson',
966
			'Tremblay',
967
			'Peltier',
968
			'Cunningham',
969
			'Simpson',
970
			'Mercado',
971
			'Sellers',
972
		);
973
974
		// Generate a random forename.
975
		$random_name = $names[ mt_rand( 0, sizeof( $names ) - 1 ) ];
976
977
		// Generate a random surname.
978
		$random_surname = $surnames[ mt_rand( 0, sizeof( $surnames ) - 1 ) ];
979
980
		// Generate name.
981
		$name = "{$random_name} {$random_surname}";
982
983
		if ( in_array( $name, $this->new_donor_names ) ) {
984
			$name = $this->get_random_name();
985
		}
986
987
		// Collect new donor names.
988
		$this->new_donor_names[] = $name;
989
990
		return $name;
991
	}
992
993
	/**
994
	 * Get random email
995
	 *
996
	 * @since 1.8.17
997
	 *
998
	 * @param string $name
999
	 *
1000
	 * @return string
1001
	 */
1002
	private function get_random_email( $name ) {
1003
		return implode( '.', explode( ' ', strtolower( $name ) ) ) . '@test.com';
1004
	}
1005
1006
	/**
1007
	 * Toggle settings for Give's test mode.
1008
	 *
1009
	 * [--enable]
1010
	 * : Enable Give's test mode
1011
	 *
1012
	 * [--disable]
1013
	 * : Enable Give's test mode
1014
	 *
1015
	 * @when after_wp_load
1016
	 * @subcommand test-mode
1017
	 */
1018
	public function test_mode( $args, $assoc ) {
0 ignored issues
show
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1019
1020
		// Return if associative arguments are not specified.
1021
		if ( empty( $assoc ) ) {
1022
			WP_CLI::error( "--enable or --disable flag is missing." );
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal --enable or --disable flag is missing. does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
1023
			return;
1024
		}
1025
1026
		$enabled_gateways = give_get_option( 'gateways' );
1027
		$default_gateway  = give_get_option( 'default_gateway' );
1028
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1029
1030
		// Enable Test Mode.
1031
		if ( true === WP_CLI\Utils\get_flag_value( $assoc, 'enable' ) ) {
1032
1033
			// Set `Test Mode` to `enabled`.
1034
			give_update_option( 'test_mode', 'enabled' );
1035
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1036
1037
			// Enable `Test Donation` gateway.
1038
			$enabled_gateways['manual'] = "1";
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal 1 does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
1039
			give_update_option( 'gateways', $enabled_gateways );
1040
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1041
1042
			// Set `Test Donation` as default gateway.
1043
			add_option( 'give_test_mode_default_gateway', $default_gateway );
1044
			give_update_option( 'default_gateway', 'manual' );
1045
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1046
1047
			// Show success message on completion.
1048
			WP_CLI::success( 'Give Test mode enabled' );
1049
		}
1050
1051
		// Disable Test Mode.
1052
		if ( true === WP_CLI\Utils\get_flag_value( $assoc, 'disable' ) ) {
1053
1054
			// Set `Test Mode` to `disabled`.
1055
			give_update_option( 'test_mode', 'disabled' );
1056
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1057
1058
			// Disable `Test Donation` gateway.
1059
			unset( $enabled_gateways['manual'] );
1060
			give_update_option( 'gateways', $enabled_gateways );
1061
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1062
1063
			// Backup `Default Gateway` setting for restore on test mode disable.
1064
			$default_gateway_backup = get_option( 'give_test_mode_default_gateway' );
1065
			give_update_option( 'default_gateway', $default_gateway_backup );
1066
			delete_option( 'give_test_mode_default_gateway' );
1067
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1068
1069
			// Show success message on completion.
1070
			WP_CLI::success( 'Give Test mode disabled' );
1071
		}
1072
	}
1073
1074
1075
	/**
1076
	 * Checks if the given path has a give repository installed
1077
	 * or not.
1078
	 *
1079
	 * @param string $repo_path Path to a Give Addon.
1080
	 *
1081
	 * @since 2.1.3
1082
	 *
1083
	 * @return boolean
1084
	 */
1085
	private function is_git_repo( $repo_path ) {
1086
		if ( is_dir( "{$repo_path}.git" ) ) {
1087
			return true;
1088
		}
1089
1090
		return false;
1091
	}
1092
1093
1094
	/**
1095
	 * Gets the current branch name of a Give Addon.
1096
	 *
1097
	 * @param string $repo_path Path to a Give Addon.
1098
	 *
1099
	 * @since 2.1.3
1100
	 *
1101
	 * @return string
1102
	 */
1103
	private function get_git_current_branch( $repo_path ) {
1104
1105
		exec( "cd $repo_path && git branch | grep '\*'", $branch_names );
1106
1107
		$branch_name = trim( strtolower( str_replace( '* ', '', $branch_names[0] ) ) );
1108
1109
		return $branch_name;
1110
	}
1111
1112
1113
	/**
1114
	 * Updates the current branch of Give Addons.
1115
	 * Uses the remote origin to pull the latest code.
1116
	 *
1117
	 * ## OPTIONS
1118
	 *
1119
	 * [--name=<name>]
1120
	 * : Update a single addon.
1121
	 *
1122
	 * [--exclude=<names>]
1123
	 * : Names of addons that should be excluded from updating.
1124
	 *
1125
	 * ## EXAMPLES
1126
	 * 	wp give addon-update
1127
	 * 	wp give addon-update --name="Give-Stripe"
1128
	 * 	wp give addon-update --exclude="Give-Stripe, Give-Recurring-Donations"
1129
	 *
1130
	 * @param array $pos   Array of positional arguments.
1131
	 * @param array $assoc Array of associative arguments.
1132
	 *
1133
	 * @since 2.1.3
1134
	 *
1135
	 * @subcommand addon-update
1136
	 */
1137
	public function addon_update( $pos, $assoc ) {
0 ignored issues
show
The parameter $pos is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1138
1139
		/**
1140
		 * Only 1 associative argument should be passed.
1141
		 * It can be either `--name` or `--exclude`
1142
		 */
1143
		if ( count( $assoc ) > 1 ) {
1144
			WP_CLI::error( __( 'Too many associative arguments.', 'give' ) );
1145
		}
1146
1147
		/**
1148
		 * Update a single Give addon.
1149
		 */
1150
		if ( false !== ( $addon_name = WP_CLI\Utils\get_flag_value( $assoc, 'name', false ) ) ) {
1151
			$give_addon_path = glob( WP_CONTENT_DIR . "/plugins/$addon_name/" , GLOB_ONLYDIR );
1152
1153
			/**
1154
			 * Display error if the plugin (addon) name entered does
1155
			 * not exist.
1156
			 */
1157
			if ( empty( $give_addon_path ) ) {
1158
				WP_CLI::error( sprintf( __( "The Give addon '%s' does not exist.", 'give' ), $addon_name ) );
1159
			}
1160
1161
			/**
1162
			 * If the directory does not contain a Git
1163
			 * repository, then display error and halt.
1164
			 */
1165
			if ( ! $this->is_git_repo( $give_addon_path[0] ) ) {
1166
				WP_CLI::error( __( 'This is not a Git repo', 'give' ) );
1167
			}
1168
1169
			/**
1170
			 * Get the current branch name. This branch will be updated next.
1171
			 */
1172
			$branch_name = $this->get_git_current_branch( $give_addon_path[0] );
1173
1174
			/**
1175
			 * Take the latest pull of the current branch, i.e.;
1176
			 * sync it with origin.
1177
			 */
1178
			passthru( "cd $give_addon_path[0] && git pull origin $branch_name", $return_var );
1179
1180
			/**
1181
			 * Show success/error messages depending on whether the
1182
			 * current branch of the addon was updated or not.
1183
			 */
1184
			if ( 0 === $return_var ) {
1185
				WP_CLI::success( sprintf( __( "The Give addon '%s' is up-to-date with origin." ), $addon_name ) );
1186
1187
				return;
1188
			} elseif ( 1 === $return_var ) {
1189
				WP_CLI::error( sprintf( __( "The Give addon '%s' was not updated." ), $addon_name ) );
1190
			}
1191
		}
1192
1193
		/**
1194
		 * Convert the comma-separated string of Give-addons in the
1195
		 * excluded list into array.
1196
		 */
1197
		$addon_names = WP_CLI\Utils\get_flag_value( $assoc, 'exclude', array() );
1198
		if ( ! empty( $addon_names ) ) {
1199
			$addon_names = array_map( 'trim', explode( ',', $addon_names ) );
1200
		}
1201
1202
		/**
1203
		 * Get directory paths of all the addons including
1204
		 * Give Core.
1205
		 */
1206
		$give_addon_directories = glob( WP_CONTENT_DIR . '/plugins/[gG]ive*/' , GLOB_ONLYDIR );
1207
1208
		foreach ( $give_addon_directories as $repo ) {
1209
1210
			/**
1211
			 * Extract the plugin/addon folder name
1212
			 * from the absolute path.
1213
			 */
1214
			$plugin_name = basename( $repo );
1215
1216
			/**
1217
			 * If the Give addon directory does not contain
1218
			 * a Git repo, then continue.
1219
			 */
1220
			if ( ! $this->is_git_repo( $repo ) ) {
1221
				WP_CLI::line(
1222
					sprintf(
1223
						__( "%s: '%s' does not contain git repo.", 'give' ),
1224
						WP_CLI::colorize( '%RError%n' ),
1225
						$plugin_name
1226
					)
1227
				);
1228
1229
				continue;
1230
			}
1231
1232
			/**
1233
			 * Continue if the Give addon name is in the exlusion list.
1234
			 */
1235
			if ( in_array( $plugin_name, $addon_names, true ) ) {
1236
				continue;
1237
			}
1238
1239
			/* Get the current branch name */
1240
			$branch_name = $this->get_git_current_branch( $repo );
1241
1242
			/**
1243
			 * Show a colorized (CYAN) title for each addon/plugin
1244
			 * before a pull.
1245
			 */
1246
			WP_CLI::line( WP_CLI::colorize( "> %CUpdating $plugin_name | $branch_name%n" ) );
1247
1248
			/**
1249
			 * Git pull from the current branch using
1250
			 * remote `origin`.
1251
			 */
1252
			if ( ! empty( $branch_name ) ) {
1253
				passthru( "cd $repo && git pull origin $branch_name", $return_var );
1254
			}
1255
1256
			$items[] = array(
1257
				'Give Addon' => $plugin_name,
1258
				'Branch'     => $branch_name,
1259
				'Remote'     => 'origin',
1260
				'Status'     => ( 0 === $return_var )
1261
					? __( 'Success', 'give' )
1262
					: __( 'Failed', 'give' ),
1263
			);
1264
1265
			/**
1266
			 * Leave a blank line for aesthetics.
1267
			 */
1268
			WP_CLI::line();
1269
		}
1270
1271
		/**
1272
		 * Display final results in a tabular format.
1273
		 */
1274
		WP_CLI\Utils\format_items(
1275
			'table',
1276
			$items,
1277
			array(
1278
				'Give Addon',
1279
				'Branch',
1280
				'Remote',
1281
				'Status',
1282
			)
1283
		);
1284
	}
1285
}
1286