PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.18.0
GiveWP – Donation Plugin and Fundraising Platform v4.18.0
4.18.0 4.17.0 4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 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 All 257 releases
← All changes | includes/donors/class-give-donor-wall.php +325 -138 2.3.0 → 4.18.0 View file →
@@ -1,18 +1,20 @@
1 1 <?php
2 2 /**
3 - * Donors Gravatars
3 + * Donor Wall
4 4 *
5 5 * @package Give
6 - * @subpackage Classes/Give_Donors_Gravatars
7 - * @copyright Copyright (c) 2016, WordImpress
6 + * @subpackage Classes/Give_Donor_Wall
7 + * @copyright Copyright (c) 2020, GiveWP
8 8 * @license https://opensource.org/licenses/gpl-license GNU Public License
9 9 * @since 1.0
10 10 */
11 11
12 12 // Exit if accessed directly.
13 -if ( ! defined( 'ABSPATH' ) ) {
14 - exit;
13 +use Give\Donations\ValueObjects\DonationMetaKeys;
14 +
15 +if (!defined('ABSPATH')) {
16 + exit;
15 17 }
16 18
17 19
18 20 /**
@@ -22,8 +24,9 @@
22 24 *
23 25 * @since 2.2.0
24 26 */
25 27 class Give_Donor_Wall {
28 +
26 29 /**
27 30 * Instance.
28 31 *
29 32 * @since 2.2.0
@@ -29,9 +32,9 @@
29 32 * @since 2.2.0
30 33 * @access private
31 34 * @var Give_Donor_Wall
32 35 */
33 - static private $instance;
36 + private static $instance;
34 37
35 38 /**
36 39 * Singleton pattern.
37 40 *
@@ -67,53 +70,61 @@
67 70 * @return void
68 71 */
69 72 public function setup_actions() {
70 73
71 - add_shortcode( 'give_donor_wall', array( $this, 'render_shortcode' ) );
74 + add_shortcode( 'give_donor_wall', [ $this, 'render_shortcode' ] );
72 75
73 - add_action( 'wp_ajax_give_get_donor_comments', array( $this, 'ajax_handler' ) );
74 - add_action( 'wp_ajax_nopriv_give_get_donor_comments', array( $this, 'ajax_handler' ) );
76 + add_action( 'wp_ajax_give_get_donor_comments', [ $this, 'ajax_handler' ] );
77 + add_action( 'wp_ajax_nopriv_give_get_donor_comments', [ $this, 'ajax_handler' ] );
75 78
76 79 }
77 80
78 81
79 - /**
80 - * Displays donors in a grid layout.
81 - *
82 - * @since 2.2.0
83 - *
84 - * @param array $atts {
85 - * Optional. Attributes of the donor wall shortcode.
86 - *
87 - * @type int $donors_per_page Number of donors per page. Default '20'.
88 - * @type int $form_id The donation form to filter donors by. Default is all forms (no filter).
89 - * @type bool $paged Whether to paginate donors. Default 'true'.
90 - * @type string $ids A comma-separated list of donor IDs to display. Default empty.
91 - * @type string $columns Maximum columns to display. Default 'best-fit'.
92 - * Accepts 'best-fit', '1', '2', '3', '4'.
93 - * @type bool $show_avatar Whether to display the donor's gravatar image if available. Default 'true'.
94 - * @type bool $show_name Whether to display the donor's full name, first and last. Default 'true'.
95 - * @type bool $show_total Whether to display the donor's donation amount. Default 'true'.
96 - * @type bool $show_time Whether to display date of the last donation. Default 'true'.
97 - * @type bool $show_comments Whether to display the donor's comment if they left one. Default 'true'.
98 - * @type int $comment_length The number of words to display for the comments before a "Read more" field
99 - * @type int $only_comments Whether to display the donors only with comment. Default 'false'.
100 - *
101 - * @type string $readmore_text Link label for modal in which donor can read full comment.
102 - * @type string $loadmore_text Button label which will load more donor comments.
103 - * @type int $avatar_size Avatar image size in pixels without the "px". Default "60"
104 - * @type string $orderby The order in which you want the donors to appear. Accepts "donation_amount", "donation_count",
105 - * if donor donated same value for orderby attribute then they will short by created date (fallback)
106 - * @type string $order The order in which you want the donors to appear. Accepts "ASC". "DESC".
107 - *
108 - * }
109 - * @return string|bool The markup of the form grid or false.
110 - */
82 + /**
83 + * Displays donors in a grid layout.
84 + *
85 + * @since 4.16.9 Added additional sanitization to donor output.
86 + * @since 4.13.2 add strip_shortcodes to the html output
87 + * @since 4.3.1 remove redundant _give_redirect_form_id() function.
88 + * @since 3.7.0 Sanitize attributes
89 + * @since 2.27.0 Moved AJAX nonce verification to ajax_handler method.
90 + * @since 2.2.0
91 + *
92 + * @param array $atts {
93 + * Optional. Attributes of the donor wall shortcode.
94 + *
95 + * @type int $donors_per_page Number of donors per page. Default '20'.
96 + * @type int $form_id The donation form to filter donors by. Default is all forms (no filter).
97 + * @type bool $paged Whether to paginate donors. Default 'true'.
98 + * @type string $ids A comma-separated list of donor IDs to display. Default empty.
99 + * @type string $columns Maximum columns to display. Default 'best-fit'.
100 + * Accepts 'best-fit', '1', '2', '3', '4'.
101 + * @type bool $show_avatar Whether to display the donor's gravatar image if available. Default 'true'.
102 + * @type bool $show_name Whether to display the donor's full name, first and last. Default 'true'.
103 + * @type bool $show_company_name Whether to display the donor's company name. Default 'false'.
104 + * @type bool $show_total Whether to display the donor's donation amount. Default 'true'.
105 + * @type bool $show_comments Whether to display the donor's comment if they left one. Default 'true'.
106 + * @type int $comment_length The number of words to display for the comments before a "Read more" field
107 + * @type int $only_comments Whether to display the donors only with comment. Default 'false'.
108 + * @type bool $show_time Whether to display date of the last donation. Default 'true'.
109 + *
110 + * @type string $readmore_text Link label for modal in which donor can read full comment.
111 + * @type string $loadmore_text Button label which will load more donor comments.
112 + * @type int $avatar_size Avatar image size in pixels without the "px". Default "75"
113 + * @type string $orderby The order in which you want the donations to appear.
114 + * Currently we are using this attribute internally and, it will sort donations by created date.
115 + * @type string $order The order in which you want the donors to appear. Accepts "ASC". "DESC".
116 + *
117 + * }
118 + * @return string|bool The markup of the form grid or false.
119 + */
111 120 public function render_shortcode( $atts ) {
121 + $atts = give_clean($atts);
112 122
113 123 $give_settings = give_get_settings();
114 124
115 125 $atts = $this->parse_atts( $atts );
126 +
116 127 $donations = $this->get_donation_data( $atts );
117 128 $html = '';
118 129
119 130 if ( $donations ) {
@@ -120,16 +131,28 @@
120 131
121 132 ob_start();
122 133
123 134 foreach ( $donations as $donation ) {
124 - // Give/templates/shortcode-donor-wall.php.
125 - give_get_template( 'shortcode-donor-wall', array( $donation, $give_settings, $atts ) );
126 - }
135 + $donor = new Give_Donor($donation['_give_payment_donor_id']);
136 + // Give/templates/shortcode-donor-wall.php.
137 + give_get_template(
138 + 'shortcode-donor-wall',
139 + [
140 + $donation,
141 + $give_settings,
142 + $atts,
143 + $donor
144 + ]
145 + );
146 + }
127 147
128 148 $html = ob_get_clean();
129 149
130 - // Return only donor html.
131 - if (
150 + // Strip shortcodes to prevent execution of user-supplied shortcode syntax.
151 + $html = give_strip_shortcodes_deep($html);
152 +
153 + // Return only donor html.
154 + if (
132 155 isset( $atts['only_donor_html'] )
133 156 && wp_doing_ajax()
134 157 && $atts['only_donor_html']
135 158 ) {
@@ -140,10 +163,11 @@
140 163 $temp_atts = $atts;
141 164 $temp_atts['paged'] = $atts['paged'] + 1;
142 165
143 166 $more_btn_html = sprintf(
144 - '<input type="hidden" class="give-donor-wall-shortcode-attrs" data-shortcode="%1$s">',
145 - rawurlencode( http_build_query( $atts ) )
167 + '<input type="hidden" class="give-donor-wall-shortcode-attrs" data-shortcode="%s" data-nonce="%s">',
168 + rawurlencode( http_build_query( $atts ) ),
169 + wp_create_nonce( 'givewp-donor-wall-more' )
146 170 );
147 171
148 172 if ( $this->has_donations( $temp_atts ) ) {
149 173 $more_btn_html .= sprintf(
@@ -166,8 +190,9 @@
166 190
167 191 /**
168 192 * Parse shortcode attributes
169 193 *
194 + * @since 2.30.0
170 195 * @since 2.2.0
171 196 * @access public
172 197 *
173 198 * @param array $atts Shortcode attributes.
@@ -175,44 +200,54 @@
175 200 * @return array
176 201 */
177 202 public function parse_atts( $atts ) {
178 203 $atts = shortcode_atts(
179 - array(
180 - 'donors_per_page' => 12,
181 - 'form_id' => 0,
182 - 'paged' => 1,
183 - 'ids' => '',
184 - 'columns' => 'best-fit',
185 - 'show_avatar' => true,
186 - 'show_name' => true,
187 - 'show_total' => true,
188 - 'show_time' => true,
189 - 'show_comments' => true,
190 - 'comment_length' => 140,
191 - 'only_comments' => false,
192 - 'readmore_text' => esc_html__( 'Read more', 'give' ),
193 - 'loadmore_text' => esc_html__( 'Load more', 'give' ),
194 - 'avatar_size' => 60,
195 - 'orderby' => 'post_date', // Only for internal use.
196 - 'order' => 'DESC',
197 - 'hide_empty' => true, // Deprecated in 2.3.0
198 - 'only_donor_html' => false, // Only for internal use.
199 - ), $atts
204 + [
205 + 'donors_per_page' => 12,
206 + 'form_id' => 0,
207 + 'paged' => 1,
208 + 'ids' => '',
209 + 'cats' => '',
210 + 'tags' => '',
211 + 'columns' => '3',
212 + 'anonymous' => true,
213 + 'show_avatar' => true,
214 + 'show_name' => true,
215 + 'show_company_name' => false,
216 + 'show_form' => false,
217 + 'show_total' => true,
218 + 'show_comments' => true,
219 + 'show_tributes' => true,
220 + 'comment_length' => 140,
221 + 'only_comments' => false,
222 + 'readmore_text' => esc_html__( 'Read more', 'give' ),
223 + 'loadmore_text' => esc_html__( 'Load more', 'give' ),
224 + 'avatar_size' => 75,
225 + 'color' => "#219653",
226 + 'orderby' => 'post_date',
227 + 'order' => 'DESC',
228 + 'hide_empty' => true, // Deprecated in 2.3.0
229 + 'only_donor_html' => false, // Only for internal use.,
230 + 'show_time' => true,
231 + ],
232 + $atts,
233 + 'give_donor_wall'
200 234 );
201 235
202 -
203 236 // Validate boolean attributes.
204 - $boolean_attributes = array(
237 + $boolean_attributes = [
238 + 'anonymous',
205 239 'show_avatar',
206 240 'show_name',
241 + 'show_company_name',
207 242 'show_total',
208 - 'show_time',
209 243 'show_comments',
210 - 'show_comments',
244 + 'show_tributes',
211 245 'hide_empty',
212 246 'only_comments',
213 247 'only_donor_html',
214 - );
248 + 'show_time'
249 + ];
215 250
216 251 foreach ( $boolean_attributes as $att ) {
217 252 // Convert numeric to boolean.
218 253 // It will prevent condition check against boolean value.
@@ -222,8 +257,41 @@
222 257
223 258 $atts[ $att ] = filter_var( $atts[ $att ], FILTER_VALIDATE_BOOLEAN );
224 259 }
225 260
261 + // Validate numeric attributes.
262 + $numeric_attributes = [
263 + 'donors_per_page',
264 + 'paged',
265 + 'comment_length',
266 + 'avatar_size',
267 + ];
268 +
269 + foreach ( $numeric_attributes as $att ) {
270 + // It will prevent condition check against numeric value.
271 + $atts[ $att ] = absint( $atts[ $att ] );
272 + }
273 +
274 + // Validate comma separated numeric attributes and keep original data format ( comma separated string).
275 + if ( ! empty( $atts['ids'] ) ) {
276 + $atts['ids'] = implode( ',', $this->split_string($atts['ids'], 'absint') );
277 + }
278 +
279 + // Validate Form IDs
280 + if ( ! empty( $atts['form_id'] ) ) {
281 + $atts['form_id'] = implode( ',', $this->split_string($atts['form_id'], 'absint') );
282 + }
283 +
284 + // Donation form categories
285 + if ( ! empty( $atts['cats'] ) ) {
286 + $atts['cats'] = $this->split_string($atts['cats']);
287 + }
288 +
289 + // Donation form tags
290 + if ( ! empty( $atts['tags'] ) ) {
291 + $atts['tags'] = $this->split_string($atts['tags']);
292 + }
293 +
226 294 return $atts;
227 295 }
228 296
229 297 /**
@@ -231,33 +299,35 @@
231 299 *
232 300 * @since 2.2.0
233 301 * @access public
234 302 *
235 - * @param array $donor_query Dorno query.
303 + * @param array $donor_query Donor query.
236 304 *
237 305 * @return array
238 306 */
239 307 public function get_donors( $donor_query ) {
240 308 $donor_query = new Give_Donors_Query( $donor_query );
241 - $donors = $donor_query->get_donors();
242 309
243 - return $donors;
310 + return $donor_query->get_donors();
244 311 }
245 312
246 313
247 314 /**
248 - * Ajax handler
315 + * This function should return donor comment for ajax request.
249 316 *
317 + * @since 2.27.0 Check nonce for AJAX request to prevent scrapping, see https://github.com/impress-org/givewp/issues/6374.
250 318 * @since 2.2.0
251 319 * @access public
252 320 */
253 321 public function ajax_handler() {
254 - $shortcode_atts = wp_parse_args( give_clean( rawurldecode( $_POST['data'] ) ) ); // @codingStandardsIgnoreLine
322 + $shortcode_atts = array_map( 'give_clean', wp_parse_args( rawurldecode( $_POST['data'] ) ) ); // @codingStandardsIgnoreLine
255 323
256 324 // Get next page donor comments.
257 325 $shortcode_atts['paged'] = $shortcode_atts['paged'] + 1;
258 326 $shortcode_atts['only_donor_html'] = true;
259 327
328 + check_ajax_referer( 'givewp-donor-wall-more', 'nonce' );
329 +
260 330 $donors_comment_html = $this->render_shortcode( $shortcode_atts );
261 331
262 332 // Check if donor comment remaining.
263 333 $temp_atts = $shortcode_atts;
@@ -267,13 +337,13 @@
267 337 // Remove internal shortcode param.
268 338 unset( $shortcode_atts['only_donor_html'] );
269 339
270 340 wp_send_json(
271 - array(
341 + [
272 342 'shortcode' => rawurlencode( http_build_query( $shortcode_atts ) ),
273 343 'html' => $donors_comment_html,
274 344 'remaining' => $has_donors,
275 - )
345 + ]
276 346 );
277 347 }
278 348
279 349 /**
@@ -278,8 +348,9 @@
278 348
279 349 /**
280 350 * Get query params
281 351 *
352 + * @since 2.24.1
282 353 * @since 2.3.0
283 354 *
284 355 * @param array $atts
285 356 *
@@ -284,41 +355,49 @@
284 355 * @param array $atts
285 356 *
286 357 * @return array
287 358 */
288 - private function get_query_param( $atts = array() ) {
289 - $valid_order = array( 'ASC', 'DESC' );
290 - $valid_orderby = array( 'post_date' );
359 + private function get_query_param( $atts = [] ) {
360 + $valid_order = [ 'ASC', 'DESC' ];
361 + $valid_orderby = [ 'post_date', 'donation_amount' ];
291 362
292 - $query_atts = array();
363 + $query_atts = [];
293 364
294 365 $query_atts['order'] = in_array( $atts['order'], $valid_order ) ? $atts['order'] : 'DESC';
295 366 $query_atts['orderby'] = in_array( $atts['orderby'], $valid_orderby ) ? $atts['orderby'] : 'post_date';
296 - $query_atts['limit'] = $atts['donors_per_page'];
297 - $query_atts['offset'] = $atts['donors_per_page'] * ( $atts['paged'] - 1 );
298 - $query_atts['form_id'] = $atts['form_id'];
367 + $query_atts['limit'] = absint( $atts['donors_per_page'] );
368 + $query_atts['offset'] = absint( $atts['donors_per_page'] * ( $atts['paged'] - 1 ) );
369 + $query_atts['form_id'] = implode( '\',\'', array_map( 'absint', explode( ',', $atts['form_id'] ) ) );
370 + $query_atts['ids'] = implode( '\',\'', array_map( 'absint', explode( ',', $atts['ids'] ) ) );
371 + $query_atts['cats'] = $atts['cats'];
372 + $query_atts['tags'] = $atts['tags'];
299 373 $query_atts['only_comments'] = ( true === $atts['only_comments'] );
374 + $query_atts['anonymous'] = ( true === $atts['anonymous'] );
300 375
376 +
377 +
301 378 return $query_atts;
302 379 }
303 380
304 - /**
305 - * Get donation data.
306 - *
307 - * @since 2.3.0
308 - *
309 - * @param array $atts
310 - *
311 - * @return array
312 - */
313 - private function get_donation_data( $atts = array() ) {
381 + /**
382 + * Get donation data.
383 + *
384 + * @since 4.18.0 Read meta values as stored instead of unserializing them, and read the donor
385 + * comment from the fetched rows instead of a per-donation meta lookup.
386 + * @since 4.16.7.2 Restrict unserialize to prevent object instantiation.
387 + * @since 2.27.0 Change to read comment from donations meta table
388 + * @since 2.3.0
389 + *
390 + * @param array $atts
391 + *
392 + * @return array
393 + */
394 + private function get_donation_data( $atts = [] ) {
314 395 global $wpdb;
315 396
316 - $query_params = $this->get_query_param( $atts );
317 -
318 397 // Bailout if donation does not exist.
319 398 if ( ! ( $donation_ids = $this->get_donations( $atts ) ) ) {
320 - return array();
399 + return [];
321 400 }
322 401
323 402 $donation_ids = ! empty( $donation_ids )
324 403 ? '\'' . implode( '\',\'', $donation_ids ) . '\''
@@ -326,40 +405,45 @@
326 405
327 406 // Backward compatibility
328 407 $donation_id_col = Give()->payment_meta->get_meta_type() . '_id';
329 408
330 - $sql = "SELECT * FROM {$wpdb->donationmeta} as m1
409 + $sql = "SELECT m1.*, p1.post_date as donation_date FROM {$wpdb->donationmeta} as m1
331 410 INNER JOIN {$wpdb->posts} as p1 ON (m1.{$donation_id_col}=p1.ID)
332 411 WHERE m1.{$donation_id_col} IN ( {$donation_ids} )
333 - ORDER BY p1.post_date {$query_params['order']}, p1.ID {$query_params['order']}
412 + ORDER BY FIELD( p1.ID, {$donation_ids} )
334 413 ";
335 414
336 415 $results = (array) $wpdb->get_results( $sql );
337 416
338 417 if ( ! empty( $results ) ) {
339 - $temp = array();
418 + $temp = [];
340 419
341 420 /* @var stdClass $result */
342 421 foreach ( $results as $result ) {
343 - $temp[ $result->{$donation_id_col} ][ $result->meta_key ] = maybe_unserialize( $result->meta_value );
422 + $temp[ $result->{$donation_id_col} ][ $result->meta_key ] = $result->meta_value;
423 +
424 + // Set donation date.
425 + if ( empty( $temp[ $result->{$donation_id_col} ]['donation_date'] ) ) {
426 + $temp[ $result->{$donation_id_col} ]['donation_date'] = $result->donation_date;
427 + }
344 428 }
345 429
346 - $comments = $this->get_donor_comments($temp);
347 -
348 430 if ( ! empty( $temp ) ) {
349 431 foreach ( $temp as $donation_id => $donation_data ) {
350 432 $temp[ $donation_id ]['donation_id'] = $donation_id;
351 433
352 - $temp[ $donation_id ]['name_initial'] = give_get_name_initial( array(
353 - 'firstname' => $donation_data['_give_donor_billing_first_name'],
354 - 'lastname' => $donation_data['_give_donor_billing_last_name'],
355 - ) );
434 + $temp[ $donation_id ]['name_initial'] = give_get_name_initial(
435 + [
436 + 'firstname' => $donation_data['_give_donor_billing_first_name'],
437 + 'lastname' => $donation_data['_give_donor_billing_last_name'],
438 + ]
439 + );
356 440
357 - $temp[ $donation_id ]['donor_comment'] = ! empty( $comments[$donation_id] ) ? $comments[$donation_id] : '';
441 + $temp[ $donation_id ]['donor_comment'] = $donation_data[ DonationMetaKeys::COMMENT ] ?? '';
358 442 }
443 +
444 + $results = ! empty( $temp ) ? $temp : [];
359 445 }
360 -
361 - $results = ! empty( $temp ) ? $temp : array();
362 446 }
363 447
364 448 return $results;
365 449 }
@@ -366,8 +450,9 @@
366 450
367 451 /**
368 452 * Get donation list for specific query
369 453 *
454 + * @since 3.17.2 fix - filter by only_comments attr
370 455 * @since 2.3.0
371 456 *
372 457 * @param array $atts
373 458 *
@@ -372,9 +457,9 @@
372 457 * @param array $atts
373 458 *
374 459 * @return array
375 460 */
376 - private function get_donations( $atts = array() ) {
461 + private function get_donations( $atts = [] ) {
377 462 global $wpdb;
378 463
379 464 // Backward compatibility
380 465 $donation_id_col = Give()->payment_meta->get_meta_type() . '_id';
@@ -387,32 +472,94 @@
387 472 // exclude donation with zero amount from result.
388 473 $sql .= " INNER JOIN {$wpdb->donationmeta} as m1 ON (p1.ID = m1.{$donation_id_col})";
389 474 $where .= " AND m1.meta_key='_give_payment_total' AND m1.meta_value>0";
390 475
391 -
392 476 if ( $query_params['form_id'] ) {
393 477 $sql .= " INNER JOIN {$wpdb->donationmeta} as m2 ON (p1.ID = m2.{$donation_id_col})";
394 - $where .= " AND m2.meta_key='_give_payment_form_id' AND m2.meta_value={$query_params['form_id']}";
478 + $where .= " AND m2.meta_key='_give_payment_form_id' AND m2.meta_value IN ('{$query_params['form_id']}')";
395 479 }
396 480
481 + // Get donations only from specific donors.
482 + if ( $query_params['ids'] ) {
483 + $sql .= " INNER JOIN {$wpdb->donationmeta} as m3 ON (p1.ID = m3.{$donation_id_col})";
484 + $where .= " AND m3.meta_key='_give_payment_donor_id' AND m3.meta_value IN ('{$query_params['ids']}')";
485 + }
486 +
397 487 // exclude donations which does not has donor comment.
398 488 if ( $query_params['only_comments'] ) {
399 - $sql .= " INNER JOIN {$wpdb->give_comments} as gc1 ON (p1.ID = gc1.comment_parent)";
400 - $where .= " AND gc1.comment_type='donor_donation'";
489 + $sql .= " INNER JOIN {$wpdb->donationmeta} as m4 ON (p1.ID = m4.{$donation_id_col})";
490 + $where .= " AND m4.meta_key='_give_donation_comment'";
401 491 }
402 492
403 - // exclude anonymous donation form query.
404 - $where .= " AND p1.ID NOT IN ( SELECT DISTINCT({$donation_id_col}) FROM {$wpdb->donationmeta} WHERE meta_key='_give_anonymous_donation' AND meta_value='1')";
493 + // exclude anonymous donation form query based on query parameters.
494 + if (
495 + ! $query_params['anonymous']
496 + || $query_params['only_comments']
497 + ) {
498 + $where .= " AND p1.ID NOT IN ( SELECT DISTINCT({$donation_id_col}) FROM {$wpdb->donationmeta} WHERE meta_key='_give_anonymous_donation' AND meta_value='1')";
499 + }
405 500
406 - $order = " ORDER BY p1.{$query_params['orderby']} {$query_params['order']}, p1.ID {$query_params['order']}";
501 + // Handle Taxonomy
502 + $args = [
503 + 'post_type' => 'give_forms',
504 + 'posts_per_page' => -1,
505 + 'fields' => 'ids',
506 + 'tax_query' => [],
507 + ];
508 +
509 + // Categories
510 + if ( is_array($atts['cats'])) {
511 + $args['tax_query']['conditions'] = ['relation' => 'OR'];
512 +
513 + foreach ($atts['cats'] as $category) {
514 + $args['tax_query']['conditions'][] = [
515 + 'operator' => 'IN',
516 + 'taxonomy' => 'give_forms_category',
517 + 'field' => 'slug',
518 + 'terms' => $category,
519 + ];
520 + }
521 + }
522 +
523 + // Tags
524 + if ( is_array($atts['tags'])) {
525 + if (empty($args['tax_query'])) {
526 + $args['tax_query']['conditions'] = ['relation' => 'OR'];
527 + }
528 +
529 + foreach($atts['tags'] as $tag) {
530 + $args['tax_query']['conditions'][] = [
531 + 'operator' => 'IN',
532 + 'taxonomy' => 'give_forms_tag',
533 + 'field' => 'slug',
534 + 'terms' => $tag,
535 + ];
536 + }
537 + }
538 +
539 + if ( ! empty( $args['tax_query'] ) ) {
540 + $query = new WP_Query( $args );
541 +
542 + if ( ! empty($query->posts) ) {
543 + $form_ids = implode("','", $query->posts );
544 + $sql .= " INNER JOIN {$wpdb->donationmeta} as m4 ON (p1.ID = m4.{$donation_id_col})";
545 + $where .= " AND m4.meta_key='_give_payment_form_id' AND m4.meta_value IN ('{$form_ids}')";
546 + }
547 + }
548 +
549 + // order by query based on parameter.
550 + if ( 'donation_amount' === $query_params['orderby'] ) {
551 + $order = " ORDER BY m1.meta_value+0 {$query_params['order']}";
552 + } else {
553 + $order = " ORDER BY p1.{$query_params['orderby']} {$query_params['order']}, p1.ID {$query_params['order']}";
554 + }
555 +
407 556 $limit = " LIMIT {$query_params['limit']}";
408 557 $offset = " OFFSET {$query_params['offset']}";
409 558
410 - $sql = $sql . $where . $order . $limit . $offset;
559 + $sql .= $where . $order . $limit . $offset;
411 560
412 - $donation_ids = $wpdb->get_col( $sql );
413 -
414 - return $donation_ids;
561 + return $wpdb->get_col( $sql );
415 562 }
416 563
417 564 /**
418 565 * Get donor comments
@@ -422,14 +569,14 @@
422 569 * @param array $donations_data
423 570 *
424 571 * @return array
425 572 */
426 - private function get_donor_comments( $donations_data = array() ) {
573 + private function get_donor_comments( $donations_data = [] ) {
427 574 global $wpdb;
428 - $comments = array();
575 + $comments = [];
429 576
430 577 // Bailout.
431 - if( empty( $donations_data ) ) {
578 + if ( empty( $donations_data ) ) {
432 579 return $comments;
433 580 }
434 581
435 582 // Backward compatibility.
@@ -437,31 +584,36 @@
437 584 ! give_has_upgrade_completed( 'v230_move_donor_note' )
438 585 || ! give_has_upgrade_completed( 'v230_move_donation_note' )
439 586 ) {
440 587 foreach ( $donations_data as $id => $data ) {
441 - $comment = give_get_donor_donation_comment( $id, $data['_give_payment_donor_id'] );
442 - $comments[$id] = ! empty( $comment ) ? $comment->comment_content : '';
588 + $comment = give_get_donor_donation_comment( $id, $data['_give_payment_donor_id'] );
589 + $comments[ $id ] = ! empty( $comment ) ? $comment->comment_content : '';
443 590 }
444 591
445 592 return $comments;
446 593 }
447 594
448 - $sql = "SELECT c1.comment_parent as donation_id, c1.comment_content as comment FROM {$wpdb->give_comments} as c1";
449 - $sql .= " INNER JOIN {$wpdb->give_commentmeta} as cm1 ON (c1.comment_ID=cm1.give_comment_id)";
450 - $where = array();
595 + $sql = "SELECT c1.comment_parent as donation_id, c1.comment_content as comment FROM {$wpdb->give_comments} as c1";
596 + $sql .= " INNER JOIN {$wpdb->give_commentmeta} as cm1 ON (c1.comment_ID=cm1.give_comment_id)";
597 + $where = [];
451 598
452 599 foreach ( $donations_data as $id => $data ) {
600 + // Do not fetch comment for anonymous donation.
601 + if ( ! empty( $data['_give_anonymous_donation'] ) ) {
602 + continue;
603 + }
604 +
453 605 $where[] = "(c1.comment_parent={$id} AND cm1.meta_key='_give_donor_id' AND cm1.meta_value={$data['_give_payment_donor_id']})";
454 606 }
455 607
456 - $where = ' WHERE '. implode( ' OR ', $where );
608 + $where = ' WHERE ' . implode( ' OR ', $where );
457 609 $where .= " AND c1.comment_type='donor_donation'";
458 610
459 - $sql = $sql.$where;
611 + $sql = $sql . $where;
460 612
461 613 $comments = (array) $wpdb->get_results( $sql );
462 614
463 - if( ! empty( $comments ) ) {
615 + if ( ! empty( $comments ) ) {
464 616 $comments = array_combine(
465 617 wp_list_pluck( $comments, 'donation_id' ),
466 618 wp_list_pluck( $comments, 'comment' )
467 619 );
@@ -478,11 +630,46 @@
478 630 * @param array $atts
479 631 *
480 632 * @return bool
481 633 */
482 - private function has_donations( $atts = array() ) {
634 + private function has_donations( $atts = [] ) {
483 635 return (bool) $this->get_donations( $atts );
484 636 }
637 +
638 + /**
639 + * @since 2.20.0
640 + *
641 + * @param string $string
642 + * @param null|callable $filter
643 + * @param string $separator
644 + *
645 + * @return array
646 + */
647 + private function split_string($string, $filter = null, $separator = ',') {
648 + if ( false === strpos( $string, $separator ) ) {
649 + $string = trim( $string );
650 +
651 + if (is_callable($filter)) {
652 + $string = $filter($string);
653 + }
654 +
655 + return [$string];
656 + }
657 +
658 + return array_filter(
659 + array_map(
660 + static function( $value ) use ($filter) {
661 + $value = trim( $value );
662 +
663 + if (is_callable($filter)) {
664 + return $filter($value);
665 + }
666 + return $value;
667 + },
668 + explode( $separator, $string )
669 + )
670 + );
671 + }
485 672 }
486 673
487 674 // Initialize shortcode.
488 675 Give_Donor_Wall::get_instance();