PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.10.4
GiveWP – Donation Plugin and Fundraising Platform v2.10.4
4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / includes / donors / class-give-donor-wall.php
give / includes / donors Last commit date
actions.php 6 years ago backward-compatibility.php 7 years ago class-give-donor-stats.php 6 years ago class-give-donor-wall.php 5 years ago class-give-donors-query.php 5 years ago frontend-donor-functions.php 6 years ago
class-give-donor-wall.php
551 lines
1 <?php
2 /**
3 * Donor Wall
4 *
5 * @package Give
6 * @subpackage Classes/Give_Donor_Wall
7 * @copyright Copyright (c) 2020, 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 /**
19 * Give_Donor_Wall Class
20 *
21 * This class handles donors.
22 *
23 * @since 2.2.0
24 */
25 class Give_Donor_Wall {
26
27 /**
28 * Instance.
29 *
30 * @since 2.2.0
31 * @access private
32 * @var Give_Donor_Wall
33 */
34 private static $instance;
35
36 /**
37 * Singleton pattern.
38 *
39 * @since 2.2.0
40 * @access private
41 */
42 private function __construct() {
43 }
44
45
46 /**
47 * Get instance.
48 *
49 * @since 2.2.0
50 * @access public
51 * @return Give_Donor_Wall
52 */
53 public static function get_instance() {
54 if ( null === static::$instance ) {
55 self::$instance = new static();
56
57 self::$instance->setup_actions();
58 }
59
60 return self::$instance;
61 }
62
63 /**
64 * Setup the default hooks and actions
65 *
66 * @since 2.2.0
67 *
68 * @return void
69 */
70 public function setup_actions() {
71
72 add_shortcode( 'give_donor_wall', [ $this, 'render_shortcode' ] );
73
74 add_action( 'wp_ajax_give_get_donor_comments', [ $this, 'ajax_handler' ] );
75 add_action( 'wp_ajax_nopriv_give_get_donor_comments', [ $this, 'ajax_handler' ] );
76
77 }
78
79
80 /**
81 * Displays donors in a grid layout.
82 *
83 * @since 2.2.0
84 *
85 * @param array $atts {
86 * Optional. Attributes of the donor wall shortcode.
87 *
88 * @type int $donors_per_page Number of donors per page. Default '20'.
89 * @type int $form_id The donation form to filter donors by. Default is all forms (no filter).
90 * @type bool $paged Whether to paginate donors. Default 'true'.
91 * @type string $ids A comma-separated list of donor IDs to display. Default empty.
92 * @type string $columns Maximum columns to display. Default 'best-fit'.
93 * Accepts 'best-fit', '1', '2', '3', '4'.
94 * @type bool $show_avatar Whether to display the donor's gravatar image if available. Default 'true'.
95 * @type bool $show_name Whether to display the donor's full name, first and last. Default 'true'.
96 * @type bool $show_company_name Whether to display the donor's company name. Default 'false'.
97 * @type bool $show_total Whether to display the donor's donation amount. Default 'true'.
98 * @type bool $show_time Whether to display date of the last donation. Default 'true'.
99 * @type bool $show_comments Whether to display the donor's comment if they left one. Default 'true'.
100 * @type int $comment_length The number of words to display for the comments before a "Read more" field
101 * @type int $only_comments Whether to display the donors only with comment. Default 'false'.
102 *
103 * @type string $readmore_text Link label for modal in which donor can read full comment.
104 * @type string $loadmore_text Button label which will load more donor comments.
105 * @type int $avatar_size Avatar image size in pixels without the "px". Default "60"
106 * @type string $orderby The order in which you want the donations to appear.
107 * Currently we are using this attribute internally and it will sort donations by created date.
108 * @type string $order The order in which you want the donors to appear. Accepts "ASC". "DESC".
109 *
110 * }
111 * @return string|bool The markup of the form grid or false.
112 */
113 public function render_shortcode( $atts ) {
114
115 $give_settings = give_get_settings();
116
117 $atts = $this->parse_atts( $atts );
118 $donations = $this->get_donation_data( $atts );
119 $html = '';
120
121 if ( $donations ) {
122
123 ob_start();
124
125 foreach ( $donations as $donation ) {
126 // Give/templates/shortcode-donor-wall.php.
127 give_get_template( 'shortcode-donor-wall', [ $donation, $give_settings, $atts ] );
128 }
129
130 $html = ob_get_clean();
131
132 // Return only donor html.
133 if (
134 isset( $atts['only_donor_html'] )
135 && wp_doing_ajax()
136 && $atts['only_donor_html']
137 ) {
138 return $html;
139 }
140 }
141
142 $temp_atts = $atts;
143 $temp_atts['paged'] = $atts['paged'] + 1;
144
145 $more_btn_html = sprintf(
146 '<input type="hidden" class="give-donor-wall-shortcode-attrs" data-shortcode="%1$s">',
147 rawurlencode( http_build_query( $atts ) )
148 );
149
150 if ( $this->has_donations( $temp_atts ) ) {
151 $more_btn_html .= sprintf(
152 '<button class="give-donor__load_more give-button-with-loader"><span class="give-loading-animation"></span>%1$s</button>',
153 $atts['loadmore_text']
154 );
155 }
156
157 $html = $html
158 ? sprintf(
159 '<div class="give-wrap give-grid-ie-utility"><div class="give-grid give-grid--%1$s">%2$s</div>%3$s</div>',
160 esc_attr( $atts['columns'] ),
161 $html,
162 $more_btn_html
163 )
164 : '';
165
166 return $html;
167 }
168
169 /**
170 * Parse shortcode attributes
171 *
172 * @since 2.2.0
173 * @access public
174 *
175 * @param array $atts Shortcode attributes.
176 *
177 * @return array
178 */
179 public function parse_atts( $atts ) {
180 $atts = shortcode_atts(
181 [
182 'donors_per_page' => 12,
183 'form_id' => 0,
184 'paged' => 1,
185 'ids' => '',
186 'columns' => 'best-fit',
187 'anonymous' => true,
188 'show_avatar' => true,
189 'show_name' => true,
190 'show_company_name' => false,
191 'show_total' => true,
192 'show_time' => true,
193 'show_comments' => true,
194 'comment_length' => 140,
195 'only_comments' => false,
196 'readmore_text' => esc_html__( 'Read more', 'give' ),
197 'loadmore_text' => esc_html__( 'Load more', 'give' ),
198 'avatar_size' => 60,
199 'orderby' => 'post_date',
200 'order' => 'DESC',
201 'hide_empty' => true, // Deprecated in 2.3.0
202 'only_donor_html' => false, // Only for internal use.
203 ],
204 $atts
205 );
206
207 // Validate boolean attributes.
208 $boolean_attributes = [
209 'anonymous',
210 'show_avatar',
211 'show_name',
212 'show_company_name',
213 'show_total',
214 'show_time',
215 'show_comments',
216 'show_comments',
217 'hide_empty',
218 'only_comments',
219 'only_donor_html',
220 ];
221
222 foreach ( $boolean_attributes as $att ) {
223 // Convert numeric to boolean.
224 // It will prevent condition check against boolean value.
225 if ( is_numeric( $atts[ $att ] ) ) {
226 $atts[ $att ] = (bool) $atts[ $att ];
227 }
228
229 $atts[ $att ] = filter_var( $atts[ $att ], FILTER_VALIDATE_BOOLEAN );
230 }
231
232 // Validate numeric attributes.
233 $numeric_attributes = [
234 'donors_per_page',
235 'form_id',
236 'paged',
237 'comment_length',
238 'avatar_size',
239 ];
240
241 foreach ( $numeric_attributes as $att ) {
242 // It will prevent condition check against numeric value.
243 $atts[ $att ] = absint( $atts[ $att ] );
244 }
245
246 // Validate comma separated numeric attributes and keep original data format ( comma separated string).
247 if ( ! empty( $atts['ids'] ) ) {
248 if ( false === strpos( $atts['ids'], ',' ) ) {
249 $tmp = [ absint( $atts['ids'] ) ];
250 } else {
251 $tmp = array_filter(
252 array_map(
253 static function( $id ) {
254 return absint( trim( $id ) ); },
255 explode( ',', $atts['ids'] )
256 )
257 );
258 }
259
260 $atts['ids'] = implode( ',', $tmp );
261 }
262
263 return $atts;
264 }
265
266 /**
267 * Get donors
268 *
269 * @since 2.2.0
270 * @access public
271 *
272 * @param array $donor_query Donor query.
273 *
274 * @return array
275 */
276 public function get_donors( $donor_query ) {
277 $donor_query = new Give_Donors_Query( $donor_query );
278
279 return $donor_query->get_donors();
280 }
281
282
283 /**
284 * Ajax handler
285 *
286 * @since 2.2.0
287 * @access public
288 */
289 public function ajax_handler() {
290 $shortcode_atts = array_map( 'give_clean', wp_parse_args( rawurldecode( $_POST['data'] ) ) ); // @codingStandardsIgnoreLine
291
292 // Get next page donor comments.
293 $shortcode_atts['paged'] = $shortcode_atts['paged'] + 1;
294 $shortcode_atts['only_donor_html'] = true;
295
296 $donors_comment_html = $this->render_shortcode( $shortcode_atts );
297
298 // Check if donor comment remaining.
299 $temp_atts = $shortcode_atts;
300 $temp_atts['paged'] = $shortcode_atts['paged'] + 1;
301 $has_donors = $this->has_donations( $temp_atts ) ? 1 : 0;
302
303 // Remove internal shortcode param.
304 unset( $shortcode_atts['only_donor_html'] );
305
306 wp_send_json(
307 [
308 'shortcode' => rawurlencode( http_build_query( $shortcode_atts ) ),
309 'html' => $donors_comment_html,
310 'remaining' => $has_donors,
311 ]
312 );
313 }
314
315 /**
316 * Get query params
317 *
318 * @since 2.3.0
319 *
320 * @param array $atts
321 *
322 * @return array
323 */
324 private function get_query_param( $atts = [] ) {
325 $valid_order = [ 'ASC', 'DESC' ];
326 $valid_orderby = [ 'post_date', 'donation_amount' ];
327
328 $query_atts = [];
329
330 $query_atts['order'] = in_array( $atts['order'], $valid_order ) ? $atts['order'] : 'DESC';
331 $query_atts['orderby'] = in_array( $atts['orderby'], $valid_orderby ) ? $atts['orderby'] : 'post_date';
332 $query_atts['limit'] = $atts['donors_per_page'];
333 $query_atts['offset'] = $atts['donors_per_page'] * ( $atts['paged'] - 1 );
334 $query_atts['form_id'] = $atts['form_id'];
335 $query_atts['ids'] = implode( '\',\'', explode( ',', $atts['ids'] ) );
336 $query_atts['only_comments'] = ( true === $atts['only_comments'] );
337 $query_atts['anonymous'] = ( true === $atts['anonymous'] );
338
339 return $query_atts;
340 }
341
342 /**
343 * Get donation data.
344 *
345 * @since 2.3.0
346 *
347 * @param array $atts
348 *
349 * @return array
350 */
351 private function get_donation_data( $atts = [] ) {
352 global $wpdb;
353
354 // Bailout if donation does not exist.
355 if ( ! ( $donation_ids = $this->get_donations( $atts ) ) ) {
356 return [];
357 }
358
359 $donation_ids = ! empty( $donation_ids )
360 ? '\'' . implode( '\',\'', $donation_ids ) . '\''
361 : '';
362
363 // Backward compatibility
364 $donation_id_col = Give()->payment_meta->get_meta_type() . '_id';
365
366 $sql = "SELECT m1.*, p1.post_date as donation_date FROM {$wpdb->donationmeta} as m1
367 INNER JOIN {$wpdb->posts} as p1 ON (m1.{$donation_id_col}=p1.ID)
368 WHERE m1.{$donation_id_col} IN ( {$donation_ids} )
369 ORDER BY FIELD( p1.ID, {$donation_ids} )
370 ";
371
372 $results = (array) $wpdb->get_results( $sql );
373
374 if ( ! empty( $results ) ) {
375 $temp = [];
376
377 /* @var stdClass $result */
378 foreach ( $results as $result ) {
379 $temp[ $result->{$donation_id_col} ][ $result->meta_key ] = maybe_unserialize( $result->meta_value );
380
381 // Set donation date.
382 if ( empty( $temp[ $result->{$donation_id_col} ]['donation_date'] ) ) {
383 $temp[ $result->{$donation_id_col} ]['donation_date'] = $result->donation_date;
384 }
385 }
386
387 $comments = $this->get_donor_comments( $temp );
388
389 if ( ! empty( $temp ) ) {
390 foreach ( $temp as $donation_id => $donation_data ) {
391 $temp[ $donation_id ]['donation_id'] = $donation_id;
392
393 $temp[ $donation_id ]['name_initial'] = give_get_name_initial(
394 [
395 'firstname' => $donation_data['_give_donor_billing_first_name'],
396 'lastname' => $donation_data['_give_donor_billing_last_name'],
397 ]
398 );
399
400 $temp[ $donation_id ]['donor_comment'] = ! empty( $comments[ $donation_id ] ) ? $comments[ $donation_id ] : '';
401 }
402 }
403
404 $results = ! empty( $temp ) ? $temp : [];
405 }
406
407 return $results;
408 }
409
410 /**
411 * Get donation list for specific query
412 *
413 * @since 2.3.0
414 *
415 * @param array $atts
416 *
417 * @return array
418 */
419 private function get_donations( $atts = [] ) {
420 global $wpdb;
421
422 // Backward compatibility
423 $donation_id_col = Give()->payment_meta->get_meta_type() . '_id';
424
425 $query_params = $this->get_query_param( $atts );
426
427 $sql = "SELECT p1.ID FROM {$wpdb->posts} as p1";
428 $where = " WHERE p1.post_status IN ('publish') AND p1.post_type = 'give_payment'";
429
430 // exclude donation with zero amount from result.
431 $sql .= " INNER JOIN {$wpdb->donationmeta} as m1 ON (p1.ID = m1.{$donation_id_col})";
432 $where .= " AND m1.meta_key='_give_payment_total' AND m1.meta_value>0";
433
434 if ( $query_params['form_id'] ) {
435 $sql .= " INNER JOIN {$wpdb->donationmeta} as m2 ON (p1.ID = m2.{$donation_id_col})";
436 $where .= " AND m2.meta_key='_give_payment_form_id' AND m2.meta_value={$query_params['form_id']}";
437 }
438
439 // Get donations only from specific donors.
440 if ( $query_params['ids'] ) {
441 $sql .= " INNER JOIN {$wpdb->donationmeta} as m3 ON (p1.ID = m3.{$donation_id_col})";
442 $where .= " AND m3.meta_key='_give_payment_donor_id' AND m3.meta_value IN ('{$query_params['ids']}')";
443 }
444
445 // exclude donations which does not has donor comment.
446 if ( $query_params['only_comments'] ) {
447 $sql .= " INNER JOIN {$wpdb->give_comments} as gc1 ON (p1.ID = gc1.comment_parent)";
448 $where .= " AND gc1.comment_type='donor_donation'";
449 }
450
451 // exclude anonymous donation form query based on query parameters.
452 if (
453 ! $query_params['anonymous']
454 || $query_params['only_comments']
455 ) {
456 $where .= " AND p1.ID NOT IN ( SELECT DISTINCT({$donation_id_col}) FROM {$wpdb->donationmeta} WHERE meta_key='_give_anonymous_donation' AND meta_value='1')";
457 }
458
459 // order by query based on parameter.
460 if ( 'donation_amount' === $query_params['orderby'] ) {
461 $order = " ORDER BY m1.meta_value+0 {$query_params['order']}";
462 } else {
463 $order = " ORDER BY p1.{$query_params['orderby']} {$query_params['order']}, p1.ID {$query_params['order']}";
464 }
465
466 $limit = " LIMIT {$query_params['limit']}";
467 $offset = " OFFSET {$query_params['offset']}";
468
469 $sql .= $where . $order . $limit . $offset;
470
471 return $wpdb->get_col( $sql );
472 }
473
474 /**
475 * Get donor comments
476 *
477 * @since 2.3.0
478 *
479 * @param array $donations_data
480 *
481 * @return array
482 */
483 private function get_donor_comments( $donations_data = [] ) {
484 global $wpdb;
485 $comments = [];
486
487 // Bailout.
488 if ( empty( $donations_data ) ) {
489 return $comments;
490 }
491
492 // Backward compatibility.
493 if (
494 ! give_has_upgrade_completed( 'v230_move_donor_note' )
495 || ! give_has_upgrade_completed( 'v230_move_donation_note' )
496 ) {
497 foreach ( $donations_data as $id => $data ) {
498 $comment = give_get_donor_donation_comment( $id, $data['_give_payment_donor_id'] );
499 $comments[ $id ] = ! empty( $comment ) ? $comment->comment_content : '';
500 }
501
502 return $comments;
503 }
504
505 $sql = "SELECT c1.comment_parent as donation_id, c1.comment_content as comment FROM {$wpdb->give_comments} as c1";
506 $sql .= " INNER JOIN {$wpdb->give_commentmeta} as cm1 ON (c1.comment_ID=cm1.give_comment_id)";
507 $where = [];
508
509 foreach ( $donations_data as $id => $data ) {
510 // Do not fetch comment for anonymous donation.
511 if ( ! empty( $data['_give_anonymous_donation'] ) ) {
512 continue;
513 }
514
515 $where[] = "(c1.comment_parent={$id} AND cm1.meta_key='_give_donor_id' AND cm1.meta_value={$data['_give_payment_donor_id']})";
516 }
517
518 $where = ' WHERE ' . implode( ' OR ', $where );
519 $where .= " AND c1.comment_type='donor_donation'";
520
521 $sql = $sql . $where;
522
523 $comments = (array) $wpdb->get_results( $sql );
524
525 if ( ! empty( $comments ) ) {
526 $comments = array_combine(
527 wp_list_pluck( $comments, 'donation_id' ),
528 wp_list_pluck( $comments, 'comment' )
529 );
530 }
531
532 return $comments;
533 }
534
535 /**
536 * Check if donation exist or not for specific query
537 *
538 * @since 2.3.0
539 *
540 * @param array $atts
541 *
542 * @return bool
543 */
544 private function has_donations( $atts = [] ) {
545 return (bool) $this->get_donations( $atts );
546 }
547 }
548
549 // Initialize shortcode.
550 Give_Donor_Wall::get_instance();
551