PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.7.3
GiveWP – Donation Plugin and Fundraising Platform v2.7.3
4.16.4 4.16.3 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 6 years ago class-give-donors-query.php 6 years ago frontend-donor-functions.php 6 years ago
class-give-donor-wall.php
548 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_total Whether to display the donor's donation amount. Default 'true'.
97 * @type bool $show_time Whether to display date of the last donation. Default 'true'.
98 * @type bool $show_comments Whether to display the donor's comment if they left one. Default 'true'.
99 * @type int $comment_length The number of words to display for the comments before a "Read more" field
100 * @type int $only_comments Whether to display the donors only with comment. Default 'false'.
101 *
102 * @type string $readmore_text Link label for modal in which donor can read full comment.
103 * @type string $loadmore_text Button label which will load more donor comments.
104 * @type int $avatar_size Avatar image size in pixels without the "px". Default "60"
105 * @type string $orderby The order in which you want the donations to appear.
106 * Currently we are using this attribute internally and it will sort donations by created date.
107 * @type string $order The order in which you want the donors to appear. Accepts "ASC". "DESC".
108 *
109 * }
110 * @return string|bool The markup of the form grid or false.
111 */
112 public function render_shortcode( $atts ) {
113
114 $give_settings = give_get_settings();
115
116 $atts = $this->parse_atts( $atts );
117 $donations = $this->get_donation_data( $atts );
118 $html = '';
119
120 if ( $donations ) {
121
122 ob_start();
123
124 foreach ( $donations as $donation ) {
125 // Give/templates/shortcode-donor-wall.php.
126 give_get_template( 'shortcode-donor-wall', [ $donation, $give_settings, $atts ] );
127 }
128
129 $html = ob_get_clean();
130
131 // Return only donor html.
132 if (
133 isset( $atts['only_donor_html'] )
134 && wp_doing_ajax()
135 && $atts['only_donor_html']
136 ) {
137 return $html;
138 }
139 }
140
141 $temp_atts = $atts;
142 $temp_atts['paged'] = $atts['paged'] + 1;
143
144 $more_btn_html = sprintf(
145 '<input type="hidden" class="give-donor-wall-shortcode-attrs" data-shortcode="%1$s">',
146 rawurlencode( http_build_query( $atts ) )
147 );
148
149 if ( $this->has_donations( $temp_atts ) ) {
150 $more_btn_html .= sprintf(
151 '<button class="give-donor__load_more give-button-with-loader"><span class="give-loading-animation"></span>%1$s</button>',
152 $atts['loadmore_text']
153 );
154 }
155
156 $html = $html
157 ? sprintf(
158 '<div class="give-wrap give-grid-ie-utility"><div class="give-grid give-grid--%1$s">%2$s</div>%3$s</div>',
159 esc_attr( $atts['columns'] ),
160 $html,
161 $more_btn_html
162 )
163 : '';
164
165 return $html;
166 }
167
168 /**
169 * Parse shortcode attributes
170 *
171 * @since 2.2.0
172 * @access public
173 *
174 * @param array $atts Shortcode attributes.
175 *
176 * @return array
177 */
178 public function parse_atts( $atts ) {
179 $atts = shortcode_atts(
180 [
181 'donors_per_page' => 12,
182 'form_id' => 0,
183 'paged' => 1,
184 'ids' => '',
185 'columns' => 'best-fit',
186 'anonymous' => true,
187 'show_avatar' => true,
188 'show_name' => true,
189 'show_total' => true,
190 'show_time' => true,
191 'show_comments' => true,
192 'comment_length' => 140,
193 'only_comments' => false,
194 'readmore_text' => esc_html__( 'Read more', 'give' ),
195 'loadmore_text' => esc_html__( 'Load more', 'give' ),
196 'avatar_size' => 60,
197 'orderby' => 'post_date',
198 'order' => 'DESC',
199 'hide_empty' => true, // Deprecated in 2.3.0
200 'only_donor_html' => false, // Only for internal use.
201 ],
202 $atts
203 );
204
205 // Validate boolean attributes.
206 $boolean_attributes = [
207 'anonymous',
208 'show_avatar',
209 'show_name',
210 'show_total',
211 'show_time',
212 'show_comments',
213 'show_comments',
214 'hide_empty',
215 'only_comments',
216 'only_donor_html',
217 ];
218
219 foreach ( $boolean_attributes as $att ) {
220 // Convert numeric to boolean.
221 // It will prevent condition check against boolean value.
222 if ( is_numeric( $atts[ $att ] ) ) {
223 $atts[ $att ] = (bool) $atts[ $att ];
224 }
225
226 $atts[ $att ] = filter_var( $atts[ $att ], FILTER_VALIDATE_BOOLEAN );
227 }
228
229 // Validate numeric attributes.
230 $numeric_attributes = [
231 'donors_per_page',
232 'form_id',
233 'paged',
234 'comment_length',
235 'avatar_size',
236 ];
237
238 foreach ( $numeric_attributes as $att ) {
239 // It will prevent condition check against numeric value.
240 $atts[ $att ] = absint( $atts[ $att ] );
241 }
242
243 // Validate comma separated numeric attributes and keep original data format ( comma separated string).
244 if ( ! empty( $atts['ids'] ) ) {
245 if ( false === strpos( $atts['ids'], ',' ) ) {
246 $tmp = [ absint( $atts['ids'] ) ];
247 } else {
248 $tmp = array_filter(
249 array_map(
250 static function( $id ) {
251 return absint( trim( $id ) ); },
252 explode( ',', $atts['ids'] )
253 )
254 );
255 }
256
257 $atts['ids'] = implode( ',', $tmp );
258 }
259
260 return $atts;
261 }
262
263 /**
264 * Get donors
265 *
266 * @since 2.2.0
267 * @access public
268 *
269 * @param array $donor_query Donor query.
270 *
271 * @return array
272 */
273 public function get_donors( $donor_query ) {
274 $donor_query = new Give_Donors_Query( $donor_query );
275
276 return $donor_query->get_donors();
277 }
278
279
280 /**
281 * Ajax handler
282 *
283 * @since 2.2.0
284 * @access public
285 */
286 public function ajax_handler() {
287 $shortcode_atts = array_map( 'give_clean', wp_parse_args( rawurldecode( $_POST['data'] ) ) ); // @codingStandardsIgnoreLine
288
289 // Get next page donor comments.
290 $shortcode_atts['paged'] = $shortcode_atts['paged'] + 1;
291 $shortcode_atts['only_donor_html'] = true;
292
293 $donors_comment_html = $this->render_shortcode( $shortcode_atts );
294
295 // Check if donor comment remaining.
296 $temp_atts = $shortcode_atts;
297 $temp_atts['paged'] = $shortcode_atts['paged'] + 1;
298 $has_donors = $this->has_donations( $temp_atts ) ? 1 : 0;
299
300 // Remove internal shortcode param.
301 unset( $shortcode_atts['only_donor_html'] );
302
303 wp_send_json(
304 [
305 'shortcode' => rawurlencode( http_build_query( $shortcode_atts ) ),
306 'html' => $donors_comment_html,
307 'remaining' => $has_donors,
308 ]
309 );
310 }
311
312 /**
313 * Get query params
314 *
315 * @since 2.3.0
316 *
317 * @param array $atts
318 *
319 * @return array
320 */
321 private function get_query_param( $atts = [] ) {
322 $valid_order = [ 'ASC', 'DESC' ];
323 $valid_orderby = [ 'post_date', 'donation_amount' ];
324
325 $query_atts = [];
326
327 $query_atts['order'] = in_array( $atts['order'], $valid_order ) ? $atts['order'] : 'DESC';
328 $query_atts['orderby'] = in_array( $atts['orderby'], $valid_orderby ) ? $atts['orderby'] : 'post_date';
329 $query_atts['limit'] = $atts['donors_per_page'];
330 $query_atts['offset'] = $atts['donors_per_page'] * ( $atts['paged'] - 1 );
331 $query_atts['form_id'] = $atts['form_id'];
332 $query_atts['ids'] = implode( '\',\'', explode( ',', $atts['ids'] ) );
333 $query_atts['only_comments'] = ( true === $atts['only_comments'] );
334 $query_atts['anonymous'] = ( true === $atts['anonymous'] );
335
336 return $query_atts;
337 }
338
339 /**
340 * Get donation data.
341 *
342 * @since 2.3.0
343 *
344 * @param array $atts
345 *
346 * @return array
347 */
348 private function get_donation_data( $atts = [] ) {
349 global $wpdb;
350
351 // Bailout if donation does not exist.
352 if ( ! ( $donation_ids = $this->get_donations( $atts ) ) ) {
353 return [];
354 }
355
356 $donation_ids = ! empty( $donation_ids )
357 ? '\'' . implode( '\',\'', $donation_ids ) . '\''
358 : '';
359
360 // Backward compatibility
361 $donation_id_col = Give()->payment_meta->get_meta_type() . '_id';
362
363 $sql = "SELECT m1.*, p1.post_date as donation_date FROM {$wpdb->donationmeta} as m1
364 INNER JOIN {$wpdb->posts} as p1 ON (m1.{$donation_id_col}=p1.ID)
365 WHERE m1.{$donation_id_col} IN ( {$donation_ids} )
366 ORDER BY FIELD( p1.ID, {$donation_ids} )
367 ";
368
369 $results = (array) $wpdb->get_results( $sql );
370
371 if ( ! empty( $results ) ) {
372 $temp = [];
373
374 /* @var stdClass $result */
375 foreach ( $results as $result ) {
376 $temp[ $result->{$donation_id_col} ][ $result->meta_key ] = maybe_unserialize( $result->meta_value );
377
378 // Set donation date.
379 if ( empty( $temp[ $result->{$donation_id_col} ]['donation_date'] ) ) {
380 $temp[ $result->{$donation_id_col} ]['donation_date'] = $result->donation_date;
381 }
382 }
383
384 $comments = $this->get_donor_comments( $temp );
385
386 if ( ! empty( $temp ) ) {
387 foreach ( $temp as $donation_id => $donation_data ) {
388 $temp[ $donation_id ]['donation_id'] = $donation_id;
389
390 $temp[ $donation_id ]['name_initial'] = give_get_name_initial(
391 [
392 'firstname' => $donation_data['_give_donor_billing_first_name'],
393 'lastname' => $donation_data['_give_donor_billing_last_name'],
394 ]
395 );
396
397 $temp[ $donation_id ]['donor_comment'] = ! empty( $comments[ $donation_id ] ) ? $comments[ $donation_id ] : '';
398 }
399 }
400
401 $results = ! empty( $temp ) ? $temp : [];
402 }
403
404 return $results;
405 }
406
407 /**
408 * Get donation list for specific query
409 *
410 * @since 2.3.0
411 *
412 * @param array $atts
413 *
414 * @return array
415 */
416 private function get_donations( $atts = [] ) {
417 global $wpdb;
418
419 // Backward compatibility
420 $donation_id_col = Give()->payment_meta->get_meta_type() . '_id';
421
422 $query_params = $this->get_query_param( $atts );
423
424 $sql = "SELECT p1.ID FROM {$wpdb->posts} as p1";
425 $where = " WHERE p1.post_status IN ('publish') AND p1.post_type = 'give_payment'";
426
427 // exclude donation with zero amount from result.
428 $sql .= " INNER JOIN {$wpdb->donationmeta} as m1 ON (p1.ID = m1.{$donation_id_col})";
429 $where .= " AND m1.meta_key='_give_payment_total' AND m1.meta_value>0";
430
431 if ( $query_params['form_id'] ) {
432 $sql .= " INNER JOIN {$wpdb->donationmeta} as m2 ON (p1.ID = m2.{$donation_id_col})";
433 $where .= " AND m2.meta_key='_give_payment_form_id' AND m2.meta_value={$query_params['form_id']}";
434 }
435
436 // Get donations only from specific donors.
437 if ( $query_params['ids'] ) {
438 $sql .= " INNER JOIN {$wpdb->donationmeta} as m3 ON (p1.ID = m3.{$donation_id_col})";
439 $where .= " AND m3.meta_key='_give_payment_donor_id' AND m3.meta_value IN ('{$query_params['ids']}')";
440 }
441
442 // exclude donations which does not has donor comment.
443 if ( $query_params['only_comments'] ) {
444 $sql .= " INNER JOIN {$wpdb->give_comments} as gc1 ON (p1.ID = gc1.comment_parent)";
445 $where .= " AND gc1.comment_type='donor_donation'";
446 }
447
448 // exclude anonymous donation form query based on query parameters.
449 if (
450 ! $query_params['anonymous']
451 || $query_params['only_comments']
452 ) {
453 $where .= " AND p1.ID NOT IN ( SELECT DISTINCT({$donation_id_col}) FROM {$wpdb->donationmeta} WHERE meta_key='_give_anonymous_donation' AND meta_value='1')";
454 }
455
456 // order by query based on parameter.
457 if ( 'donation_amount' === $query_params['orderby'] ) {
458 $order = " ORDER BY m1.meta_value+0 {$query_params['order']}";
459 } else {
460 $order = " ORDER BY p1.{$query_params['orderby']} {$query_params['order']}, p1.ID {$query_params['order']}";
461 }
462
463 $limit = " LIMIT {$query_params['limit']}";
464 $offset = " OFFSET {$query_params['offset']}";
465
466 $sql .= $where . $order . $limit . $offset;
467
468 return $wpdb->get_col( $sql );
469 }
470
471 /**
472 * Get donor comments
473 *
474 * @since 2.3.0
475 *
476 * @param array $donations_data
477 *
478 * @return array
479 */
480 private function get_donor_comments( $donations_data = [] ) {
481 global $wpdb;
482 $comments = [];
483
484 // Bailout.
485 if ( empty( $donations_data ) ) {
486 return $comments;
487 }
488
489 // Backward compatibility.
490 if (
491 ! give_has_upgrade_completed( 'v230_move_donor_note' )
492 || ! give_has_upgrade_completed( 'v230_move_donation_note' )
493 ) {
494 foreach ( $donations_data as $id => $data ) {
495 $comment = give_get_donor_donation_comment( $id, $data['_give_payment_donor_id'] );
496 $comments[ $id ] = ! empty( $comment ) ? $comment->comment_content : '';
497 }
498
499 return $comments;
500 }
501
502 $sql = "SELECT c1.comment_parent as donation_id, c1.comment_content as comment FROM {$wpdb->give_comments} as c1";
503 $sql .= " INNER JOIN {$wpdb->give_commentmeta} as cm1 ON (c1.comment_ID=cm1.give_comment_id)";
504 $where = [];
505
506 foreach ( $donations_data as $id => $data ) {
507 // Do not fetch comment for anonymous donation.
508 if ( ! empty( $data['_give_anonymous_donation'] ) ) {
509 continue;
510 }
511
512 $where[] = "(c1.comment_parent={$id} AND cm1.meta_key='_give_donor_id' AND cm1.meta_value={$data['_give_payment_donor_id']})";
513 }
514
515 $where = ' WHERE ' . implode( ' OR ', $where );
516 $where .= " AND c1.comment_type='donor_donation'";
517
518 $sql = $sql . $where;
519
520 $comments = (array) $wpdb->get_results( $sql );
521
522 if ( ! empty( $comments ) ) {
523 $comments = array_combine(
524 wp_list_pluck( $comments, 'donation_id' ),
525 wp_list_pluck( $comments, 'comment' )
526 );
527 }
528
529 return $comments;
530 }
531
532 /**
533 * Check if donation exist or not for specific query
534 *
535 * @since 2.3.0
536 *
537 * @param array $atts
538 *
539 * @return bool
540 */
541 private function has_donations( $atts = [] ) {
542 return (bool) $this->get_donations( $atts );
543 }
544 }
545
546 // Initialize shortcode.
547 Give_Donor_Wall::get_instance();
548