shortcodes.php ➔ give_donation_history()   C
last analyzed

Complexity

Conditions 13
Paths 6

Size

Total Lines 89

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
nc 6
nop 2
dl 0
loc 89
rs 5.5333
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
850
			$form_args['tax_query'][] = array(
851
				'taxonomy' => 'give_forms_category',
852
				'terms'    => $term_ids,
853
			);
854
855
		}
856
857
		$term_slug = array_unique( array_filter( array_diff( $cats, $term_ids ) ) );
858
		if ( $term_slug ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $term_slug of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
859
			$form_args['tax_query'][] = array(
860
				'taxonomy' => 'give_forms_category',
861
				'field'    => 'slug',
862
				'terms'    => $term_slug,
863
			);
864
865
		}
866
	}
867
868
	// Maybe filter by form tag.
869 View Code Duplication
	if ( ! empty( $atts['tags'] ) ) {
0 ignored issues
show
Duplication introduced by
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...
870
		$tags = array_filter( array_map( 'trim', explode( ',', $atts['tags'] ) ) );
871
872
		// Backward compatibility for term_ids.
873
		$tag_ids = array_unique( array_filter( $tags, 'is_numeric' ) );
874
		if ( $tag_ids ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tag_ids of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
875
			$form_args['tax_query'][] = array(
876
				'taxonomy' => 'give_forms_tag',
877
				'terms'    => $tag_ids,
878
			);
879
880
		}
881
882
		$tag_slug = array_unique( array_filter( array_diff( $tags, $tag_ids ) ) );
883
		if ( $tag_slug ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tag_slug of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
884
			$form_args['tax_query'][] = array(
885
				'taxonomy' => 'give_forms_tag',
886
				'field'    => 'slug',
887
				'terms'    => $tag_slug,
888
			);
889
890
		}
891
	}
892
893
	/**
894
	 * Filter to modify WP Query for Total Goal.
895
	 *
896
	 * @since 2.1.4
897
	 *
898
	 * @param array $form_args WP query argument for Grid.
899
	 *
900
	 * @return array $form_args WP query argument for Grid.
901
	 */
902
	$form_args = (array) apply_filters( 'give_form_grid_shortcode_query_args', $form_args );
903
904
	// Maybe filter by form Amount Donated or Number of Donations.
905
	switch ( $atts['orderby'] ) {
906
		case 'amount_donated':
907
			$form_args['meta_key'] = '_give_form_earnings';
908
			$form_args['orderby']  = 'meta_value_num';
909
			break;
910
		case 'number_donations':
911
			$form_args['meta_key'] = '_give_form_sales';
912
			$form_args['orderby']  = 'meta_value_num';
913
			break;
914
		case 'closest_to_goal':
915
			if ( give_has_upgrade_completed( 'v240_update_form_goal_progress' ) ) {
916
				$form_args['meta_key'] = '_give_form_goal_progress';
917
				$form_args['orderby']  = 'meta_value_num';
918
			}
919
			break;
920
	}
921
922
	// Query to output donation forms.
923
	$form_query = new WP_Query( $form_args );
924
925
	if ( $form_query->have_posts() ) {
926
		ob_start();
927
928
		add_filter( 'add_give_goal_progress_class', 'add_give_goal_progress_class', 10, 1 );
929
		add_filter( 'add_give_goal_progress_bar_class', 'add_give_goal_progress_bar_class', 10, 1 );
930
		add_filter( 'give_form_wrap_classes', 'add_class_for_form_grid', 10, 3 );
931
		add_action( 'give_donation_form_top', 'give_is_form_grid_page_hidden_field', 10, 3 );
932
933
		echo '<div class="give-wrap">';
934
		echo '<div class="give-grid give-grid--' . esc_attr( $atts['columns'] ) . '">';
935
936
		while ( $form_query->have_posts() ) {
937
			$form_query->the_post();
938
939
			// Give/templates/shortcode-form-grid.php.
940
			give_get_template( 'shortcode-form-grid', array( $give_settings, $atts ) );
941
942
		}
943
944
		wp_reset_postdata();
945
946
		echo '</div><!-- .give-grid -->';
947
948
		remove_filter( 'add_give_goal_progress_class', 'add_give_goal_progress_class' );
949
		remove_filter( 'add_give_goal_progress_bar_class', 'add_give_goal_progress_bar_class' );
950
		remove_filter( 'give_form_wrap_classes', 'add_class_for_form_grid', 10 );
951
		remove_action( 'give_donation_form_top', 'give_is_form_grid_page_hidden_field', 10 );
952
953
		if ( false !== $atts['paged'] ) {
954
			$paginate_args = array(
955
				'current'   => max( 1, get_query_var( 'paged' ) ),
956
				'total'     => $form_query->max_num_pages,
957
				'show_all'  => false,
958
				'end_size'  => 1,
959
				'mid_size'  => 2,
960
				'prev_next' => true,
961
				'prev_text' => __( '« Previous', 'give' ),
962
				'next_text' => __( 'Next »', 'give' ),
963
				'type'      => 'plain',
964
				'add_args'  => false,
965
			);
966
967
			printf(
968
				'<div class="give-page-numbers">%s</div>',
969
				paginate_links( $paginate_args )
970
			);
971
		}
972
		echo '</div><!-- .give-wrap -->';
973
974
		return ob_get_clean();
975
	} // End if().
976
}
977
978
add_shortcode( 'give_form_grid', 'give_form_grid_shortcode' );
979