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/shortcodes.php (28 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 Shortcodes
4
 *
5
 * @package     Give
6
 * @subpackage  Shortcodes
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
9
 * @since       1.0
10
 */
11
12
// Exit if accessed directly.
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Donation History Shortcode
19
 *
20
 * Displays a user's donation history.
21
 *
22
 * @since  1.0
23
 *
24
 * @param array       $atts
25
 * @param string|bool $content
26
 *
27
 * @return string|bool
28
 */
29
function give_donation_history( $atts, $content = false ) {
30
31
	$donation_history_args = shortcode_atts( array(
32
		'id'             => true,
33
		'date'           => true,
34
		'donor'          => false,
35
		'amount'         => true,
36
		'status'         => false,
37
		'payment_method' => false,
38
	), $atts, 'donation_history' );
39
40
	// Always show receipt link.
41
	$donation_history_args['details'] = true;
42
43
	// Set Donation History Shortcode Arguments in session variable.
44
	Give()->session->set( 'give_donation_history_args', $donation_history_args );
45
46
	// If payment_key query arg exists, return receipt instead of donation history.
47
	if ( isset( $_GET['payment_key'] ) ) {
0 ignored issues
show
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
48
		ob_start();
49
50
		echo give_receipt_shortcode( array() );
0 ignored issues
show
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'give_receipt_shortcode'
Loading history...
51
52
		// Display donation history link only if Receipt Access Session is available.
53
		if ( give_get_receipt_session() ) {
54
			echo sprintf(
0 ignored issues
show
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'sprintf'
Loading history...
55
				'<a href="%s">%s</a>',
56
				esc_url( give_get_history_page_uri() ),
57
				__( '&laquo; Return to All Donations', 'give' )
58
			);
59
		}
60
61
		return ob_get_clean();
62
	}
63
64
	$email_access = give_get_option( 'email_access' );
65
66
	ob_start();
67
68
	/**
69
	 * Determine access
70
	 *
71
	 * a. Check if a user is logged in or does a session exists
72
	 * b. Does an email-access token exist?
73
	 */
74
	if (
75
		is_user_logged_in()
76
		|| false !== Give()->session->get_session_expiration()
77
		|| ( give_is_setting_enabled( $email_access ) && Give()->email_access->token_exists )
78
		|| true === give_get_history_session()
79
	) {
80
		give_get_template_part( 'history', 'donations' );
81
82
		if ( ! empty( $content ) ) {
83
			echo do_shortcode( $content );
0 ignored issues
show
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'do_shortcode'
Loading history...
84
		}
0 ignored issues
show
Blank line found after control structure
Loading history...
85
86
	} elseif ( give_is_setting_enabled( $email_access ) ) {
87
		// Is Email-based access enabled?
88
		give_get_template_part( 'email', 'login-form' );
89
90 View Code Duplication
	} else {
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...
91
92
		echo apply_filters( 'give_donation_history_nonuser_message', Give()->notices->print_frontend_notice( __( 'You must be logged in to view your donation history. Please login using your account or create an account using the same email you used to donate with.', 'give' ), false ) );
0 ignored issues
show
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'apply_filters'
Loading history...
93
		echo do_shortcode( '[give_login]' );
0 ignored issues
show
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'do_shortcode'
Loading history...
94
	}
95
96
	/**
97
	 * Filter to modify donation history HTMl
98
	 *
99
	 * @since 2.1
100
	 *
101
	 * @param string HTML content
102
	 * @param array  $atts
103
	 * @param string $content content pass between enclose content
104
	 *
105
	 * @return string HTML content
106
	 */
107
	return apply_filters( 'give_donation_history_shortcode_html', ob_get_clean(), $atts, $content );
108
}
109
110
add_shortcode( 'donation_history', 'give_donation_history' );
111
112
/**
113
 * Donation Form Shortcode
114
 *
115
 * Show the Give donation form.
116
 *
117
 * @since  1.0
118
 *
119
 * @param  array $atts Shortcode attributes
120
 *
121
 * @return string
122
 */
123
function give_form_shortcode( $atts ) {
124
	$atts = shortcode_atts( array(
125
		'id'                    => '',
126
		'show_title'            => true,
127
		'show_goal'             => true,
128
		'show_content'          => '',
129
		'float_labels'          => '',
130
		'display_style'         => '',
131
		'continue_button_title' => '',
132
	), $atts, 'give_form' );
133
134
	// Convert string to bool.
135
	$atts['show_title'] = filter_var( $atts['show_title'], FILTER_VALIDATE_BOOLEAN );
136
	$atts['show_goal']  = filter_var( $atts['show_goal'], FILTER_VALIDATE_BOOLEAN );
137
138
	// get the Give Form
139
	ob_start();
140
	give_get_donation_form( $atts );
141
	$final_output = ob_get_clean();
142
143
	return apply_filters( 'give_donate_form', $final_output, $atts );
144
}
145
146
add_shortcode( 'give_form', 'give_form_shortcode' );
147
148
/**
149
 * Donation Form Goal Shortcode.
150
 *
151
 * Show the Give donation form goals.
152
 *
153
 * @since  1.0
154
 *
155
 * @param  array $atts Shortcode attributes.
156
 *
157
 * @return string
158
 */
159
function give_goal_shortcode( $atts ) {
160
	$atts = shortcode_atts( array(
161
		'id'        => '',
162
		'show_text' => true,
163
		'show_bar'  => true,
164
	), $atts, 'give_goal' );
165
166
	// get the Give Form.
167
	ob_start();
168
169
	// Sanity check 1: ensure there is an ID Provided.
170
	if ( empty( $atts['id'] ) ) {
171
		Give()->notices->print_frontend_notice( __( 'The shortcode is missing Donation Form ID attribute.', 'give' ), true );
172
	}
173
174
	// Sanity check 2: Check the form even has Goals enabled.
175
	if ( ! give_is_setting_enabled( give_get_meta( $atts['id'], '_give_goal_option', true ) ) ) {
176
177
		Give()->notices->print_frontend_notice( __( 'The form does not have Goals enabled.', 'give' ), true );
178
	} else {
179
		// Passed all sanity checks: output Goal.
180
		give_show_goal_progress( $atts['id'], $atts );
181
	}
182
183
	$final_output = ob_get_clean();
184
185
	return apply_filters( 'give_goal_shortcode_output', $final_output, $atts );
186
}
187
188
add_shortcode( 'give_goal', 'give_goal_shortcode' );
189
190
191
/**
192
 * Login Shortcode.
193
 *
194
 * Shows a login form allowing users to users to log in. This function simply
195
 * calls the give_login_form function to display the login form.
196
 *
197
 * @since  1.0
198
 *
199
 * @param  array $atts Shortcode attributes.
200
 *
201
 * @uses   give_login_form()
202
 *
203
 * @return string
204
 */
205
function give_login_form_shortcode( $atts ) {
206
207
	$atts = shortcode_atts( array(
208
		// Add backward compatibility for redirect attribute.
209
		'redirect'        => '',
210
		'login-redirect'  => '',
211
		'logout-redirect' => '',
212
	), $atts, 'give_login' );
213
214
	// Check login-redirect attribute first, if it empty or not found then check for redirect attribute and add value of this to login-redirect attribute.
215
	$atts['login-redirect'] = ! empty( $atts['login-redirect'] ) ? $atts['login-redirect'] : ( ! empty( $atts['redirect'] ) ? $atts['redirect'] : '' );
216
217
	return give_login_form( $atts['login-redirect'], $atts['logout-redirect'] );
218
}
219
220
add_shortcode( 'give_login', 'give_login_form_shortcode' );
221
222
/**
223
 * Register Shortcode.
224
 *
225
 * Shows a registration form allowing users to users to register for the site.
226
 *
227
 * @since  1.0
228
 *
229
 * @param  array $atts Shortcode attributes.
230
 *
231
 * @uses   give_register_form()
232
 *
233
 * @return string
234
 */
235
function give_register_form_shortcode( $atts ) {
236
	$atts = shortcode_atts( array(
237
		'redirect' => '',
238
	), $atts, 'give_register' );
239
240
	return give_register_form( $atts['redirect'] );
241
}
242
243
add_shortcode( 'give_register', 'give_register_form_shortcode' );
244
245
/**
246
 * Receipt Shortcode.
247
 *
248
 * Shows a donation receipt.
249
 *
250
 * @since  1.0
251
 *
252
 * @param  array $atts Shortcode attributes.
253
 *
254
 * @return string
255
 */
256
function give_receipt_shortcode( $atts ) {
257
258
	global $give_receipt_args;
259
	$payment_key = '';
260
261
	$give_receipt_args = shortcode_atts( array(
262
		'error'          => __( 'You are missing the payment key to view this donation receipt.', 'give' ),
263
		'price'          => true,
264
		'donor'          => true,
265
		'date'           => true,
266
		'payment_key'    => false,
267
		'payment_method' => true,
268
		'payment_id'     => true,
269
		'payment_status' => false,
270
		'company_name'   => false,
271
		'status_notice'  => true,
272
	), $atts, 'give_receipt' );
273
274
	// set $session var
275
	$session = give_get_purchase_session();
276
277
	// set payment key var
278
	if ( isset( $_GET['payment_key'] ) ) {
279
		$payment_key = urldecode( $_GET['payment_key'] );
0 ignored issues
show
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
Detected usage of a non-sanitized input variable: $_GET
Loading history...
280
	} elseif ( $session ) {
281
		$payment_key = $session['purchase_key'];
282
	} elseif ( $give_receipt_args['payment_key'] ) {
283
		$payment_key = $give_receipt_args['payment_key'];
284
	}
285
286
	if( ! wp_doing_ajax() ) {
0 ignored issues
show
Space after opening control structure is required
Loading history...
No space before opening parenthesis is prohibited
Loading history...
287
		ob_start();
288
		give_get_template_part( 'receipt/placeholder' );
289
		$placeholder = ob_get_clean();
290
291
		return sprintf(
292
			'<div id="give-receipt" data-shortcode="%s" data-donation-key="%s">%s</div>',
293
			urlencode_deep( wp_json_encode( $atts ) ),
294
			$payment_key,
295
			$placeholder
296
		);
297
	}
298
299
	$email_access = give_get_option( 'email_access' );
300
301
	// No payment_key found & Email Access is Turned on.
302
	if ( ! isset( $payment_key ) && give_is_setting_enabled( $email_access ) && ! Give()->email_access->token_exists ) {
303
304
		ob_start();
305
306
		give_get_template_part( 'email-login-form' );
307
308
		return ob_get_clean();
309
310
	} elseif ( ! isset( $payment_key ) ) {
311
312
		return Give()->notices->print_frontend_notice( $give_receipt_args['error'], false, 'error' );
313
314
	}
315
316
	$user_can_view = give_can_view_receipt( $payment_key );
317
318
	// Key was provided, but user is logged out. Offer them the ability to login and view the receipt.
319
	if ( ! $user_can_view && give_is_setting_enabled( $email_access ) && ! Give()->email_access->token_exists ) {
320
321
		ob_start();
322
323
		give_get_template_part( 'email-login-form' );
324
325
		return ob_get_clean();
326
327
	} elseif ( ! $user_can_view ) {
328
329
		global $give_login_redirect;
330
331
		$give_login_redirect = give_get_current_page_url();
332
333
		ob_start();
334
335
		Give()->notices->print_frontend_notice( apply_filters( 'give_must_be_logged_in_error_message', __( 'You must be logged in to view this donation receipt.', 'give' ) ) );
336
337
		give_get_template_part( 'shortcode', 'login' );
338
339
		$login_form = ob_get_clean();
340
341
		return $login_form;
342
	}
343
344
	/**
345
	 * Check if the user has permission to view the receipt.
346
	 *
347
	 * If user is logged in, user ID is compared to user ID of ID stored in payment meta
348
	 * or if user is logged out and donation was made as a guest, the donation session is checked for
349
	 * or if user is logged in and the user can view sensitive shop data.
350
	 */
351
	if ( ! apply_filters( 'give_user_can_view_receipt', $user_can_view, $give_receipt_args ) ) {
352
		return Give()->notices->print_frontend_notice( $give_receipt_args['error'], false, 'error' );
353
	}
354
355
	ob_start();
356
357
	give_get_template_part( 'shortcode', 'receipt' );
358
359
	$display = ob_get_clean();
360
361
	return $display;
362
}
363
364
add_shortcode( 'give_receipt', 'give_receipt_shortcode' );
365
366
/**
367
 * Profile Editor Shortcode.
368
 *
369
 * Outputs the Give Profile Editor to allow users to amend their details from the
370
 * front-end. This function uses the Give templating system allowing users to
371
 * override the default profile editor template. The profile editor template is located
372
 * under templates/profile-editor.php, however, it can be altered by creating a
373
 * file called profile-editor.php in the give_template directory in your active theme's
374
 * folder. Please visit the Give Documentation for more information on how the
375
 * templating system is used.
376
 *
377
 * @since  1.0
378
 *
379
 * @param  array $atts Shortcode attributes.
380
 *
381
 * @return string Output generated from the profile editor
382
 */
383
function give_profile_editor_shortcode( $atts ) {
0 ignored issues
show
The parameter $atts 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...
384
385
	ob_start();
386
387
	// Restrict access to donor profile, if donor and user are disconnected.
388
	$is_donor_disconnected = get_user_meta( get_current_user_id(), '_give_is_donor_disconnected', true );
0 ignored issues
show
get_user_meta() usage is highly discouraged, check VIP documentation on "Working with wp_users"
Loading history...
389
	if ( is_user_logged_in() && $is_donor_disconnected ) {
390
		Give()->notices->print_frontend_notice( __( 'Your Donor and User profile are no longer connected. Please contact the site administrator.', 'give' ), true, 'error' );
391
392
		return false;
393
	}
394
395
	give_get_template_part( 'shortcode', 'profile-editor' );
396
397
	$display = ob_get_clean();
398
399
	return $display;
400
}
401
402
add_shortcode( 'give_profile_editor', 'give_profile_editor_shortcode' );
403
404
/**
405
 * Process Profile Updater Form.
406
 *
407
 * Processes the profile updater form by updating the necessary fields.
408
 *
409
 * @since  1.0
410
 *
411
 * @param  array $data Data sent from the profile editor.
412
 *
413
 * @return bool
414
 */
415
function give_process_profile_editor_updates( $data ) {
416
	// Profile field change request.
417
	if ( empty( $_POST['give_profile_editor_submit'] ) && ! is_user_logged_in() ) {
0 ignored issues
show
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
418
		return false;
419
	}
420
421
	// Nonce security.
422
	if ( ! wp_verify_nonce( $data['give_profile_editor_nonce'], 'give-profile-editor-nonce' ) ) {
423
		return false;
424
	}
425
426
	$user_id       = get_current_user_id();
427
	$old_user_data = get_userdata( $user_id );
428
429
	/* @var Give_Donor $donor */
430
	$donor            = new Give_Donor( $user_id, true );
431
	$old_company_name = $donor->get_company_name();
432
433
	$display_name     = isset( $data['give_display_name'] ) ? sanitize_text_field( $data['give_display_name'] ) : $old_user_data->display_name;
434
	$first_name       = isset( $data['give_first_name'] ) ? sanitize_text_field( $data['give_first_name'] ) : $old_user_data->first_name;
435
	$last_name        = isset( $data['give_last_name'] ) ? sanitize_text_field( $data['give_last_name'] ) : $old_user_data->last_name;
436
	$company_name     = ! empty( $data['give_company_name'] ) ? sanitize_text_field( $data['give_company_name'] ) : $old_company_name;
437
	$email            = isset( $data['give_email'] ) ? sanitize_email( $data['give_email'] ) : $old_user_data->user_email;
438
	$password         = ! empty( $data['give_new_user_pass1'] ) ? $data['give_new_user_pass1'] : '';
439
	$confirm_password = ! empty( $data['give_new_user_pass2'] ) ? $data['give_new_user_pass2'] : '';
440
441
	$userdata = array(
442
		'ID'           => $user_id,
443
		'first_name'   => $first_name,
444
		'last_name'    => $last_name,
445
		'display_name' => $display_name,
446
		'user_email'   => $email,
447
		'user_pass'    => $password,
448
		'company_name' => $company_name,
449
	);
450
451
	/**
452
	 * Fires before updating user profile.
453
	 *
454
	 * @since 1.0
455
	 *
456
	 * @param int   $user_id  The ID of the user.
457
	 * @param array $userdata User info, including ID, first name, last name, display name and email.
458
	 */
459
	do_action( 'give_pre_update_user_profile', $user_id, $userdata );
460
461
	// Make sure to validate first name of existing donors.
462
	if ( empty( $first_name ) ) {
463
		// Empty First Name.
464
		give_set_error( 'empty_first_name', __( 'Please enter your first name.', 'give' ) );
465
	}
466
467
	// Make sure to validate passwords for existing Donors.
468
	give_validate_user_password( $password, $confirm_password );
469
470
	if ( empty( $email ) ) {
471
		// Make sure email should not be empty.
472
		give_set_error( 'email_empty', __( 'The email you entered is empty.', 'give' ) );
473
474
	} elseif ( ! is_email( $email ) ) {
475
		// Make sure email should be valid.
476
		give_set_error( 'email_not_valid', __( 'The email you entered is not valid. Please use another', 'give' ) );
477
478
	} elseif ( $email != $old_user_data->user_email ) {
479
		// Make sure the new email doesn't belong to another user.
480
		if ( email_exists( $email ) ) {
481
			give_set_error( 'user_email_exists', __( 'The email you entered belongs to another user. Please use another.', 'give' ) );
482
		} elseif ( Give()->donors->get_donor_by( 'email', $email ) ) {
483
			// Make sure the new email doesn't belong to another user.
484
			give_set_error( 'donor_email_exists', __( 'The email you entered belongs to another donor. Please use another.', 'give' ) );
485
		}
486
	}
487
488
	// Check for errors.
489
	$errors = give_get_errors();
490
491
	if ( $errors ) {
492
		// Send back to the profile editor if there are errors.
493
		wp_redirect( $data['give_redirect'] );
494
		give_die();
495
	}
496
497
	// Update Donor First Name and Last Name.
498
	Give()->donors->update( $donor->id, array(
499
		'name' => trim( "{$first_name} {$last_name}" ),
500
	) );
501
	Give()->donor_meta->update_meta( $donor->id, '_give_donor_first_name', $first_name );
502
	Give()->donor_meta->update_meta( $donor->id, '_give_donor_last_name', $last_name );
503
	Give()->donor_meta->update_meta( $donor->id, '_give_donor_company', $company_name );
504
505
	$current_user = wp_get_current_user();
506
507
	// Compares new values with old values to detect change in values.
508
	$email_update        = ( $email !== $current_user->user_email ) ? true : false;
509
	$display_name_update = ( $display_name !== $current_user->display_name ) ? true : false;
510
	$first_name_update   = ( $first_name !== $current_user->first_name ) ? true : false;
511
	$last_name_update    = ( $last_name !== $current_user->last_name ) ? true : false;
512
	$company_name_update = ( $company_name !== $old_company_name ) ? true : false;
513
	$update_code         = 0;
514
515
	/**
516
	 * True if update is done in display name, first name, last name or email.
517
	 *
518
	 * @var boolean
519
	 */
520
	$profile_update = ( $email_update || $display_name_update || $first_name_update || $last_name_update || $company_name_update );
521
522
	/**
523
	 * True if password fields are filled.
524
	 *
525
	 * @var boolean
526
	 */
527
	$password_update = ( ! empty( $password ) && ! empty( $confirm_password ) );
528
529
	if ( $profile_update ) {
530
531
		// If only profile fields are updated.
532
		$update_code = '1';
533
534
		if ( $password_update ) {
535
536
			// If profile fields AND password both are updated.
537
			$update_code = '2';
538
		}
539
	} elseif ( $password_update ) {
540
541
		// If only password is updated.
542
		$update_code = '3';
543
	}
544
545
	// Update the user.
546
	$updated = wp_update_user( $userdata );
547
548
	if ( $updated ) {
549
550
		/**
551
		 * Fires after updating user profile.
552
		 *
553
		 * @since 1.0
554
		 *
555
		 * @param int   $user_id  The ID of the user.
556
		 * @param array $userdata User info, including ID, first name, last name, display name and email.
557
		 */
558
		do_action( 'give_user_profile_updated', $user_id, $userdata );
559
560
		$profile_edit_redirect_args = array(
561
			'updated'     => 'true',
562
			'update_code' => $update_code,
563
		);
564
565
		/**
566
		 * Update codes '2' and '3' indicate a password change.
567
		 * If the password is changed, then logout and redirect to the same page.
568
		 */
569
		if ( '2' === $update_code || '3' === $update_code ) {
570
			wp_logout( wp_redirect( add_query_arg( $profile_edit_redirect_args, $data['give_redirect'] ) ) );
571
		} else {
572
			wp_redirect( add_query_arg( $profile_edit_redirect_args, $data['give_redirect'] ) );
573
		}
574
575
		give_die();
576
	}
577
578
	return false;
579
}
580
581
add_action( 'give_edit_user_profile', 'give_process_profile_editor_updates' );
582
583
/**
584
 * Give totals Shortcode.
585
 *
586
 * Shows a donation total.
587
 *
588
 * @since  2.1
589
 *
590
 * @param  array $atts Shortcode attributes.
591
 *
592
 * @return string
593
 */
594
function give_totals_shortcode( $atts ) {
595
	$total = get_option( 'give_earnings_total', false );
596
597
	$message = apply_filters( 'give_totals_message', __( 'Hey! We\'ve raised {total} of the {total_goal} we are trying to raise for this campaign!', 'give' ) );
598
599
	$atts = shortcode_atts( array(
600
		'total_goal'   => 0, // integer
601
		'ids'          => 0, // integer|array
602
		'cats'         => 0, // integer|array
603
		'tags'         => 0, // integer|array
604
		'message'      => $message,
605
		'link'         => '', // URL
606
		'link_text'    => __( 'Donate Now', 'give' ), // string,
607
		'progress_bar' => true, // boolean
608
	), $atts, 'give_totals' );
609
610
	// Total Goal.
611
	$total_goal = give_maybe_sanitize_amount( $atts['total_goal'] );
612
613
	/**
614
	 * Give Action fire before the shortcode is rendering is started.
615
	 *
616
	 * @since 2.1.4
617
	 *
618
	 * @param array $atts shortcode attribute.
619
	 */
620
	do_action( 'give_totals_goal_shortcode_before_render', $atts );
621
622
	// Build query based on cat, tag and Form ids.
623
	if ( ! empty( $atts['cats'] ) || ! empty( $atts['tags'] ) || ! empty( $atts['ids'] ) ) {
624
625
		$form_ids = array();
626 View Code Duplication
		if ( ! empty( $atts['ids'] ) ) {
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...
627
			$form_ids = array_filter( array_map( 'trim', explode( ',', $atts['ids'] ) ) );
628
		}
629
630
		/**
631
		 * Filter to modify WP Query for Total Goal.
632
		 *
633
		 * @since 2.1.4
634
		 *
635
		 * @param array WP query argument for Total Goal.
636
		 */
637
		$form_args = array(
638
			'post_type'        => 'give_forms',
639
			'post_status'      => 'publish',
640
			'post__in'         => $form_ids,
641
			'posts_per_page'   => - 1,
642
			'fields'           => 'ids',
643
			'tax_query'        => array(
0 ignored issues
show
Detected usage of tax_query, possible slow query.
Loading history...
644
				'relation' => 'AND',
645
			),
646
		);
647
648 View Code Duplication
		if ( ! empty( $atts['cats'] ) ) {
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...
649
			$cats                     = array_filter( array_map( 'trim', explode( ',', $atts['cats'] ) ) );
650
			$form_args['tax_query'][] = array(
651
				'taxonomy' => 'give_forms_category',
652
				'terms'    => $cats,
653
			);
654
		}
655
656 View Code Duplication
		if ( ! empty( $atts['tags'] ) ) {
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...
657
			$tags                     = array_filter( array_map( 'trim', explode( ',', $atts['tags'] ) ) );
658
			$form_args['tax_query'][] = array(
659
				'taxonomy' => 'give_forms_tag',
660
				'terms'    => $tags,
661
			);
662
		}
663
664
		/**
665
		 * Filter to modify WP Query for Total Goal.
666
		 *
667
		 * @since 2.1.4
668
		 *
669
		 * @param array $form_args WP query argument for Total Goal.
670
		 *
671
		 * @return array $form_args WP query argument for Total Goal.
672
		 */
673
		$form_args = (array) apply_filters( 'give_totals_goal_shortcode_query_args', $form_args );
674
675
		$forms = new WP_Query( $form_args );
676
677
		if ( isset( $forms->posts ) ) {
678
			$total = 0;
679
			foreach ( $forms->posts as $post ) {
680
				$form_earning = give_get_meta( $post, '_give_form_earnings', true );
681
				$form_earning = ! empty( $form_earning ) ? $form_earning : 0;
682
683
				/**
684
				 * Update Form earnings.
685
				 *
686
				 * @since 2.1
687
				 *
688
				 * @param int $post Form ID.
689
				 * @param string $form_earning Total earning of Form.
690
				 */
691
				$total += apply_filters( 'give_totals_form_earning', $form_earning, $post );
692
			}
693
		}
0 ignored issues
show
Blank line found after control structure
Loading history...
694
695
	}
696
697
	// Append link with text.
698
	$donate_link = '';
699
	if ( ! empty( $atts['link'] ) ) {
700
		$donate_link = sprintf( ' <a class="give-totals-text-link" href="%1$s">%2$s</a>', esc_url( $atts['link'] ), esc_html( $atts['link_text'] ) );
701
	}
702
703
	// Replace {total} in message.
704
	$message = str_replace( '{total}', give_currency_filter(
705
		give_format_amount( $total,
706
			array( 'sanitize' => false )
707
		)
708
	), esc_html( $atts['message'] ) );
709
710
	// Replace {total_goal} in message.
711
	$message = str_replace( '{total_goal}', give_currency_filter(
712
		give_format_amount( $total_goal,
713
			array( 'sanitize' => true )
714
		)
715
	), $message );
716
717
	/**
718
	 * Update Give totals shortcode output.
719
	 *
720
	 * @since 2.1
721
	 *
722
	 * @param string $message Shortcode Message.
723
	 * @param array $atts ShortCode attributes.
724
	 */
725
	$message = apply_filters( 'give_totals_shortcode_message', $message, $atts );
726
727
	ob_start();
728
	?>
729
	<div class="give-totals-shortcode-wrap">
730
		<?php
731
		// Show Progress Bar if progress_bar set true.
732
		$show_progress_bar = isset( $atts['progress_bar'] ) ? filter_var( $atts['progress_bar'], FILTER_VALIDATE_BOOLEAN ) : true;
733
		if ( $show_progress_bar ) {
734
			give_show_goal_totals_progress( $total, $total_goal );
735
		}
736
737
		echo sprintf( $message ) . $donate_link;
0 ignored issues
show
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'sprintf'
Loading history...
Expected next thing to be a escaping function, not '$donate_link'
Loading history...
738
		?>
739
	</div>
740
	<?php
741
	$give_totals_output = ob_get_clean();
742
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
743
744
	/**
745
	 * Give Action fire after the total goal shortcode rendering is end.
746
	 *
747
	 * @since 2.1.4
748
	 *
749
	 * @param array  $atts               shortcode attribute.
750
	 * @param string $give_totals_output shortcode output.
751
	 */
752
	do_action( 'give_totals_goal_shortcode_after_render', $atts, $give_totals_output );
753
754
	/**
755
	 * Give Totals Shortcode output.
756
	 *
757
	 * @since 2.1
758
	 *
759
	 * @param string $give_totals_output
760
	 */
761
	return apply_filters( 'give_totals_shortcode_output', $give_totals_output );
762
763
}
764
765
add_shortcode( 'give_totals', 'give_totals_shortcode' );
766
767
768
/**
769
 * Displays donation forms in a grid layout.
770
 *
771
 * @since  2.1.0
772
 *
773
 * @param array $atts                {
774
 *                                   Optional. Attributes of the form grid shortcode.
775
 *
776
 * @type int    $forms_per_page      Number of forms per page. Default '12'.
777
 * @type bool   $paged               Whether to paginate forms. Default 'true'.
778
 * @type string $ids                 A comma-separated list of form IDs to display. Default empty.
779
 * @type string exclude              A comma-separated list of form IDs to exclude from display. Default empty.
780
 * @type string $cats                A comma-separated list of form categories to display. Default empty.
781
 * @type string $tags                A comma-separated list of form tags to display. Default empty.
782
 * @type string $columns             Maximum columns to display. Default 'best-fit'.
783
 *                                       Accepts 'best-fit', '1', '2', '3', '4'.
784
 * @type bool   $show_title          Whether to display form title. Default 'true'.
785
 * @type bool   $show_goal           Whether to display form goal. Default 'true'.
786
 * @type bool   $show_excerpt        Whether to display form excerpt. Default 'true'.
787
 * @type bool   $show_featured_image Whether to display featured image. Default 'true'.
788
 * @type string $image_size          Featured image size. Default 'medium'. Accepts WordPress image sizes.
789
 * @type string $image_height        Featured image height. Default 'auto'. Accepts valid CSS heights.
790
 * @type int    $excerpt_length      Number of words before excerpt is truncated. Default '16'.
791
 * @type string $display_style       How the form is displayed, either in new page or modal popup.
792
 *                                       Default 'redirect'. Accepts 'redirect', 'modal'.
793
 * }
794
 * @return string|bool The markup of the form grid or false.
795
 */
796
function give_form_grid_shortcode( $atts ) {
797
798
	$give_settings = give_get_settings();
799
800
	$atts = shortcode_atts( array(
801
		'forms_per_page'      => 12,
802
		'paged'               => true,
803
		'ids'                 => '',
804
		'exclude'             => '',
805
		'cats'                => '',
806
		'tags'                => '',
807
		'columns'             => 'best-fit',
808
		'show_title'          => true,
809
		'show_goal'           => true,
810
		'show_excerpt'        => true,
811
		'show_featured_image' => true,
812
		'image_size'          => 'medium',
813
		'image_height'        => 'auto',
814
		'excerpt_length'      => 16,
815
		'display_style'       => 'modal_reveal',
816
		'status'              => '', // open or closed
817
	), $atts );
818
819
	// Validate integer attributes.
820
	$atts['forms_per_page'] = intval( $atts['forms_per_page'] );
821
	$atts['excerpt_length'] = intval( $atts['excerpt_length'] );
822
823
	// Validate boolean attributes.
824
	$boolean_attributes = array(
825
		'paged',
826
		'show_title',
827
		'show_goal',
828
		'show_excerpt',
829
		'show_featured_image',
830
	);
831
832
	foreach ( $boolean_attributes as $att ) {
833
		$atts[ $att ] = filter_var( $atts[ $att ], FILTER_VALIDATE_BOOLEAN );
834
	}
835
836
	// Set default form query args.
837
	$form_args = array(
838
		'post_type'      => 'give_forms',
839
		'post_status'    => 'publish',
840
		'posts_per_page' => $atts['forms_per_page'],
841
		'tax_query'      => array(
0 ignored issues
show
Detected usage of tax_query, possible slow query.
Loading history...
842
			'relation' => 'AND',
843
		),
844
	);
845
846
	// Filter results of form grid based on form status.
847
	$form_closed_status = trim( $atts['status'] );
848
849
	if ( ! empty( $form_closed_status ) ) {
850
		$form_args['meta_query'] = array(
0 ignored issues
show
Detected usage of meta_query, possible slow query.
Loading history...
851
			array(
852
				'key'   => '_give_form_status',
853
				'value' => $form_closed_status,
854
			),
855
		);
856
	}
857
858
	// Maybe add pagination.
859
	if ( true === $atts['paged'] ) {
860
		$form_args['paged'] = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
861
	}
862
863
	// Maybe filter forms by IDs.
864 View Code Duplication
	if ( ! empty( $atts['ids'] ) ) {
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...
865
		$form_args['post__in'] = array_filter( array_map( 'trim', explode( ',', $atts['ids'] ) ) );
866
	}
867
868
	// Convert comma-separated form IDs into array.
869
	if ( ! empty( $atts['exclude'] ) ) {
870
		$form_args['post__not_in'] = array_filter( array_map( function( $item ) {
871
			return intval( trim( $item ) );
872
		}, explode( ',', $atts['exclude'] ) ) );
873
	}
874
875
	// Maybe filter by form category.
876 View Code Duplication
	if ( ! empty( $atts['cats'] ) ) {
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...
877
		$cats                     = array_filter( array_map( 'trim', explode( ',', $atts['cats'] ) ) );
878
		$tax_query                = array(
879
			'taxonomy' => 'give_forms_category',
880
			'terms'    => $cats,
881
		);
882
		$form_args['tax_query'][] = $tax_query;
883
	}
884
885
	// Maybe filter by form tag.
886 View Code Duplication
	if ( ! empty( $atts['tags'] ) ) {
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...
887
		$tags                     = array_filter( array_map( 'trim', explode( ',', $atts['tags'] ) ) );
888
		$tax_query                = array(
889
			'taxonomy' => 'give_forms_tag',
890
			'terms'    => $tags,
891
		);
892
		$form_args['tax_query'][] = $tax_query;
893
	}
894
895
	// Query to output donation forms.
896
	$form_query = new WP_Query( $form_args );
897
898
	if ( $form_query->have_posts() ) {
899
		ob_start();
900
901
		add_filter( 'add_give_goal_progress_class', 'add_give_goal_progress_class', 10, 1 );
902
		add_filter( 'add_give_goal_progress_bar_class', 'add_give_goal_progress_bar_class', 10, 1 );
903
		add_filter( 'give_form_wrap_classes', 'add_class_for_form_grid', 10, 3 );
904
		add_action( 'give_donation_form_top', 'give_is_form_grid_page_hidden_field', 10, 3 );
905
906
		echo '<div class="give-wrap">';
907
		echo '<div class="give-grid give-grid--' . esc_attr( $atts['columns'] ) . '">';
908
909
		while ( $form_query->have_posts() ) {
910
			$form_query->the_post();
911
912
			// Give/templates/shortcode-form-grid.php.
913
			give_get_template( 'shortcode-form-grid', array( $give_settings, $atts ) );
914
915
		}
916
917
		wp_reset_postdata();
918
919
		echo '</div><!-- .give-grid -->';
920
921
		remove_filter( 'add_give_goal_progress_class', 'add_give_goal_progress_class' );
922
		remove_filter( 'add_give_goal_progress_bar_class', 'add_give_goal_progress_bar_class' );
923
		remove_filter( 'give_form_wrap_classes', 'add_class_for_form_grid', 10 );
924
		remove_action( 'give_donation_form_top', 'give_is_form_grid_page_hidden_field', 10 );
925
926
		if ( false !== $atts['paged'] ) {
927
			$paginate_args = array(
928
				'current'   => max( 1, get_query_var( 'paged' ) ),
929
				'total'     => $form_query->max_num_pages,
930
				'show_all'  => false,
931
				'end_size'  => 1,
932
				'mid_size'  => 2,
933
				'prev_next' => true,
934
				'prev_text' => __( '« Previous', 'give' ),
935
				'next_text' => __( 'Next »', 'give' ),
936
				'type'      => 'plain',
937
				'add_args'  => false,
938
			);
939
940
			printf(
941
				'<div class="give-page-numbers">%s</div>',
942
				paginate_links( $paginate_args )
943
			);
944
		}
945
		echo '</div><!-- .give-wrap -->';
946
947
		return ob_get_clean();
948
	}
949
}
950
951
add_shortcode( 'give_form_grid', 'give_form_grid_shortcode' );
952