PluginProbe
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI / 8.0.2
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI v8.0.2
8.0.1 8.0.2 8.0.0 7.9.9.7 7.9.9.6 7.9.9.5 7.9.9.4 7.9.9.3 7.9.9.2 7.9.9.1 7.9.9 7.9.8 7.9.7 7.9.6 7.9.5 7.9.4 7.9.3 7.9.2 7.9.1 7.9.0 7.8.9 7.8.8 7.8.7 7.8.6 7.8.5 All 44 releases
gamipress / includes / functions / points.php

points.php in GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI 8.0.2, at includes/functions/points.php

1,394 lines 43.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Points-related Functions
4 *
5 * @package GamiPress\Points_Functions
6 * @author GamiPress <contact@gamipress.com>, Ruben Garcia <rubengcdev@gmail.com>
7 * @since 1.0.0
8 */
9 // Exit if accessed directly
10 if( !defined( 'ABSPATH' ) ) exit;
11
12 /**
13 * Return a user's points
14 *
15 * @since 1.0.0
16 * @updated 1.6.9 Added $args argument
17 *
18 * @param integer $user_id The given user's ID
19 * @param string $points_type The points type
20 * @param array $args Extra arguments
21 *
22 * @return integer $user_points The user's current points
23 */
24 function gamipress_get_user_points( $user_id = 0, $points_type = '', $args = array() ) {
25
26 // Use current user's ID if none specified
27 if ( ! $user_id ) {
28 $user_id = get_current_user_id();
29 }
30
31 $args = wp_parse_args( $args, array(
32 'date_query' => array(), // Limit user points balance on a specific date query, accepts before and after params
33 ) );
34
35 // Shorthand
36 $date_query = $args['date_query'];
37
38 // Retrieve the user points balance from logs based on date query given
39 if( ( isset( $date_query['before'] ) && ! empty( $date_query['before'] ) )
40 || ( isset( $date_query['after'] ) && ! empty( $date_query['after'] ) ) ) {
41
42 return absint( gamipress_query_logs( array(
43 'select' => 'GREATEST( IFNULL( SUM( l.points ), 0 ), 0 )',
44 'get_var' => true,
45 'user_id' => $user_id,
46 'where' => array(
47 array(
48 'key' => 'points',
49 'value' => '0',
50 'compare' => '!=',
51 ),
52 'points_type' => $points_type
53 ),
54 'date_query' => $date_query
55 ) ) );
56
57 }
58
59 // Default points
60 $user_meta = '_gamipress_points';
61
62 if( ! empty( $points_type ) ) {
63 $user_meta = "_gamipress_{$points_type}_points";
64 }
65
66 // Fetch our user's points
67 $raw_points = gamipress_get_user_meta( $user_id, $user_meta );
68
69 // Transform points to a non-negative integer (sanely falls back to 0 if empty)
70 $user_points = absint( $raw_points );
71
72 /**
73 * User points amount filter
74 *
75 * @param int $user_points The user's points (falls back to 0 if empty)
76 * @param string $raw_points The original points (as fetched from the database)
77 * @param int $user_id The ID of the user whose points were requested
78 * @param string $user_meta The user meta field name that holds the user's points
79 */
80 return apply_filters( 'gamipress_get_user_points', $user_points, $raw_points, $user_id, $user_meta );
81
82 }
83
84 /**
85 * Return a user's points awarded
86 *
87 * @since 1.3.7
88 * @updated 1.3.9.6 Added $since parameter
89 *
90 * @param integer $user_id The given user's ID
91 * @param string $points_type The points type
92 * @param integer $since
93 *
94 * @return integer $user_points_awarded The user's current points awarded
95 */
96 function gamipress_get_user_points_awarded( $user_id = 0, $points_type = '', $since = 0 ) {
97
98 // Use current user's ID if none specified
99 if ( ! $user_id )
100 $user_id = wp_get_current_user()->ID;
101
102 // Default points
103 $user_meta = '_gamipress_points_awarded';
104
105 if( ! empty( $points_type ) ) {
106 $user_meta = "_gamipress_{$points_type}_points_awarded";
107 }
108
109 $points_awarded = gamipress_get_user_meta( $user_id, $user_meta );
110
111 // If user meta not exists or since parameter is defined, recalculate it
112 if( empty( $points_awarded ) || $since > 0 ) {
113
114 $points_awarded = 0;
115
116 // Get the user earns and awards from log
117 $user_points_logs = gamipress_get_user_logs( $user_id, array(
118 'type' => array( 'points_earn', 'points_award' ),
119 'points_type' => $points_type,
120 ), $since );
121
122 ct_setup_table( 'gamipress_logs' );
123
124 // Loop all logs to retrieve the amount of points awarded
125 foreach( $user_points_logs as $user_points_log ) {
126 $points_awarded += absint( ct_get_object_meta( $user_points_log->log_id, '_gamipress_points', true ) );
127 }
128
129 ct_reset_setup_table();
130
131 // If since parameter has been set, return the points awarded since this date without update it
132 if( $since > 0 ) {
133 return $points_awarded;
134 }
135
136 // Finally update the user meta
137 gamipress_update_user_meta( $user_id, $user_meta, $points_awarded );
138
139 }
140
141 // Return our user's points awarded as an integer (sanely falls back to 0 if empty)
142 return absint( $points_awarded );
143 }
144
145 /**
146 * Return a user's points deducted
147 *
148 * @since 1.3.7
149 * @updated 1.3.9.6 Added $since parameter
150 *
151 * @param integer $user_id The given user's ID
152 * @param string $points_type The points type
153 * @param integer $since
154 *
155 * @return integer $user_points_deducted The user's current points deducted
156 */
157 function gamipress_get_user_points_deducted( $user_id = 0, $points_type = '', $since = 0 ) {
158
159 // Use current user's ID if none specified
160 if ( ! $user_id )
161 $user_id = wp_get_current_user()->ID;
162
163 // Default points
164 $user_meta = '_gamipress_points_deducted';
165
166 if( ! empty( $points_type ) ) {
167 $user_meta = "_gamipress_{$points_type}_points_deducted";
168 }
169
170 $points_deducted = gamipress_get_user_meta( $user_id, $user_meta );
171
172 // If user meta not exists or since parameter is defined, recalculate it
173 if( empty( $points_deducted ) || $since > 0 ) {
174
175 $points_deducted = 0;
176
177 // Get the user earns and deducts from log
178 $user_points_logs = gamipress_get_user_logs( $user_id, array(
179 'type' => array( 'points_deduct', 'points_revoke' ),
180 'points_type' => $points_type,
181 ), $since );
182
183 ct_setup_table( 'gamipress_logs' );
184
185 // Loop all logs to retrieve the amount of points deducted
186 foreach( $user_points_logs as $user_points_log ) {
187 $points_deducted += absint( ct_get_object_meta( $user_points_log->log_id, '_gamipress_points', true ) );
188 }
189
190 ct_reset_setup_table();
191
192 // If since parameter has been set, return the points deducted since this date without update it
193 if( $since > 0 ) {
194 return $points_deducted;
195 }
196
197 // Finally update the user meta
198 gamipress_update_user_meta( $user_id, $user_meta, $points_deducted );
199
200 }
201
202 // Return our user's points deducted as an integer (sanely falls back to 0 if empty)
203 return absint( $points_deducted );
204 }
205
206 /**
207 * Return a user's points expended
208 *
209 * @since 1.3.7
210 * @updated 1.3.9.6 Added $since parameter
211 *
212 * @param integer $user_id The given user's ID
213 * @param string $points_type The points type
214 * @param integer $since
215 *
216 * @return integer $user_points_expended The user's current points expended
217 */
218 function gamipress_get_user_points_expended( $user_id = 0, $points_type = '', $since = 0 ) {
219
220 // Use current user's ID if none specified
221 if ( ! $user_id )
222 $user_id = wp_get_current_user()->ID;
223
224 // Default points
225 $user_meta = '_gamipress_points_expended';
226
227 if( ! empty( $points_type ) ) {
228 $user_meta = "_gamipress_{$points_type}_points_expended";
229 }
230
231 $points_expended = gamipress_get_user_meta( $user_id, $user_meta );
232
233 // If user meta not exists or since parameter is defined, recalculate it
234 if( empty( $points_expended ) || $since > 0 ) {
235
236 $points_expended = 0;
237
238 // Get the user earns and expends from log
239 $user_points_logs = gamipress_get_user_logs( $user_id, array(
240 'type' => 'points_expend',
241 'points_type' => $points_type,
242 ), $since );
243
244 ct_setup_table( 'gamipress_logs' );
245
246 // Loop all logs to retrieve the amount of points expended
247 foreach( $user_points_logs as $user_points_log ) {
248 $points_expended += absint( ct_get_object_meta( $user_points_log->log_id, '_gamipress_points', true ) );
249 }
250
251 ct_reset_setup_table();
252
253 // If since parameter has been set, return the points expended since this date without update it
254 if( $since > 0 ) {
255 return $points_expended;
256 }
257
258 // Finally update the user meta
259 gamipress_update_user_meta( $user_id, $user_meta, $points_expended );
260
261 }
262
263 // Return our user's points expended as an integer (sanely falls back to 0 if empty)
264 return absint( $points_expended );
265
266 }
267
268 /**
269 * Return site's points (sum of all user points)
270 *
271 * @since 1.5.9
272 * @updated 1.6.9 Added $args argument
273 *
274 * @param string $points_type The points type
275 * @param array $args Extra arguments
276 *
277 * @return int $site_points The site's current points
278 */
279 function gamipress_get_site_points( $points_type = '', $args = array() ) {
280
281 $args = wp_parse_args( $args, array(
282 'date_query' => array(), // Limit user points balance on a specific date query, accepts before and after params
283 ) );
284
285 // Shorthand
286 $date_query = $args['date_query'];
287
288 // Retrieve the site points from logs based on date query given
289 if( ( isset( $date_query['before'] ) && ! empty( $date_query['before'] ) )
290 || ( isset( $date_query['after'] ) && ! empty( $date_query['after'] ) ) ) {
291
292 return absint( gamipress_query_logs( array(
293 'select' => 'GREATEST( IFNULL( SUM( l.points ), 0 ), 0 )',
294 'get_var' => true,
295 'where' => array(
296 array(
297 'key' => 'points',
298 'value' => '0',
299 'compare' => '!=',
300 ),
301 'points_type' => $points_type
302 ),
303 'date_query' => $date_query
304 ) ) );
305
306 }
307
308 // Default points
309 $user_meta = '_gamipress_points';
310
311 if( ! empty( $points_type ) ) {
312 $user_meta = "_gamipress_{$points_type}_points";
313 }
314
315 // Return site's points as an integer (sanely falls back to 0 if empty)
316 return absint( gamipress_get_user_meta_sum( $user_meta ) );
317
318 }
319
320 /**
321 * Return site's points awarded (sum of all user points awarded)
322 *
323 * @since 1.5.9
324 *
325 * @param string $points_type The points type
326 *
327 * @return int $site_points The site's points awarded
328 */
329 function gamipress_get_site_points_awarded( $points_type = '' ) {
330
331 // Default points
332 $user_meta = '_gamipress_points_awarded';
333
334 if( ! empty( $points_type ) ) {
335 $user_meta = "_gamipress_{$points_type}_points_awarded";
336 }
337
338 // Return site's points awarded as an integer (sanely falls back to 0 if empty)
339 return absint( gamipress_get_user_meta_sum( $user_meta ) );
340
341 }
342
343 /**
344 * Return site's points deducted (sum of all user points deducted)
345 *
346 * @since 1.5.9
347 *
348 * @param string $points_type The points type
349 *
350 * @return int $site_points The site's points deducted
351 */
352 function gamipress_get_site_points_deducted( $points_type = '' ) {
353
354 // Default points
355 $user_meta = '_gamipress_points_deducted';
356
357 if( ! empty( $points_type ) ) {
358 $user_meta = "_gamipress_{$points_type}_points_deducted";
359 }
360
361 // Return site's points deducted as an integer (sanely falls back to 0 if empty)
362 return absint( gamipress_get_user_meta_sum( $user_meta ) );
363
364 }
365
366 /**
367 * Return site's points expended (sum of all user points expended)
368 *
369 * @since 1.5.9
370 *
371 * @param string $points_type The points type
372 *
373 * @return int $site_points The site's points expended
374 */
375 function gamipress_get_site_points_expended( $points_type = '' ) {
376
377 // Default points
378 $user_meta = '_gamipress_points_expended';
379
380 if( ! empty( $points_type ) ) {
381 $user_meta = "_gamipress_{$points_type}_points_expended";
382 }
383
384 // Return site's points expended as an integer (sanely falls back to 0 if empty)
385 return absint( gamipress_get_user_meta_sum( $user_meta ) );
386
387 }
388
389 /**
390 * Award points to a user
391 *
392 * @since 1.3.6
393 *
394 * @param integer $user_id The given user's ID
395 * @param integer $points The points the user is being awarded
396 * @param string|WP_Post $points_type The points type
397 * @param array $args Array of extra arguments
398 *
399 * @return integer The user's updated points total
400 */
401 function gamipress_award_points_to_user( $user_id = 0, $points = 0, $points_type = '', $args = array() ) {
402
403 // Initialize args
404 $args = wp_parse_args( $args, array(
405 'admin_id' => 0,
406 'achievement_id' => null,
407 'reason' => '',
408 'log_type' => '',
409 ) );
410
411 // If points are negative, turn them to positive
412 if( $points < 0 && $args['admin_id'] === 0 ) {
413 $points *= -1;
414 }
415
416 // Use current user's ID if none specified
417 if ( ! $user_id )
418 $user_id = get_current_user_id();
419
420 // If the points type is a WP_Post, then get the slug
421 if( is_object( $points_type ) )
422 $points_type = $points_type->post_name;
423
424 /**
425 * Filter to allow award points to user
426 *
427 * @since 7.0.5
428 *
429 * @param bool
430 * @param integer $user_id The given user's ID
431 * @param integer $points The points the user is being awarded
432 * @param string|WP_Post $points_type The points type
433 * @param array $args Array of extra arguments
434 *
435 * @return bool
436 */
437 $allow = apply_filters( 'gamipress_allow_award_points_to_user', true, $user_id, $points, $points_type, $args );
438
439 if ( ! $allow ) {
440 return gamipress_get_user_points( $user_id, $points_type );
441 }
442
443 // Available action for triggering other processes
444 do_action( 'gamipress_award_points_to_user', $user_id, $points, $points_type, $args );
445
446 return gamipress_update_user_points( $user_id, $points, $args['admin_id'], $args['achievement_id'], $points_type, $args['reason'], $args['log_type'] );
447
448 }
449
450 /**
451 * Deduct points to a user
452 *
453 * @since 1.3.6
454 *
455 * @param integer $user_id The given user's ID
456 * @param integer $points The points the user is being awarded
457 * @param string|WP_Post $points_type The points type
458 * @param array $args Array of extra arguments
459 *
460 * @return integer The user's updated points total
461 */
462 function gamipress_deduct_points_to_user( $user_id = 0, $points = 0, $points_type = '', $args = array() ) {
463
464 // Initialize args
465 $args = wp_parse_args( $args, array(
466 'admin_id' => 0,
467 'achievement_id' => null,
468 'reason' => '',
469 'log_type' => '',
470 ) );
471
472 // If points are positive, turn them to negative
473 if( $points > 0 && $args['admin_id'] === 0 ) {
474 $points *= -1;
475 }
476
477 // Use current user's ID if none specified
478 if ( ! $user_id )
479 $user_id = get_current_user_id();
480
481 // If the points type is a WP_Post, then get the slug
482 if( is_object( $points_type ) )
483 $points_type = $points_type->post_name;
484
485 /**
486 * Filter to allow deduct points to user
487 *
488 * @since 7.0.5
489 *
490 * @param bool
491 * @param integer $user_id The given user's ID
492 * @param integer $points The points the user is being awarded
493 * @param string|WP_Post $points_type The points type
494 * @param array $args Array of extra arguments
495 *
496 * @return bool
497 */
498 $allow = apply_filters( 'gamipress_allow_deduct_points_to_user', true, $user_id, $points, $points_type, $args );
499
500 if ( ! $allow ) {
501 return gamipress_get_user_points( $user_id, $points_type );
502 }
503
504 // Available action for triggering other processes
505 do_action( 'gamipress_deduct_points_to_user', $user_id, $points, $points_type, $args );
506
507 return gamipress_update_user_points( $user_id, $points, $args['admin_id'], $args['achievement_id'], $points_type, $args['reason'], $args['log_type'] );
508
509 }
510
511 /**
512 * Posts a log entry when a user earns points
513 *
514 * @since 1.0.0
515 * @updated 1.3.6 Added $reason parameter
516 * @updated 1.3.7 Added $og_type parameter
517 * @updated 1.3.9.4 Now stores _gamipress_{$points_type}_points for user total and _gamipress_{$points_type}_new_points for last awarded or deducted points
518 *
519 * @param integer $user_id The given user's ID
520 * @param integer $new_points The new points the user is being awarded/deducted
521 * @param integer $admin_id If being awarded by an admin, the admin's user ID
522 * @param integer $achievement_id The achievement that generated the points movement, if applicable
523 * @param string|WP_Post $points_type The points type
524 * @param string $reason Custom reason to override default log pattern
525 * @param string $log_type Log type
526 *
527 * @return integer The user's updated points total
528 */
529 function gamipress_update_user_points( $user_id = 0, $new_points = 0, $admin_id = 0, $achievement_id = null, $points_type = '', $reason = '', $log_type = '' ) {
530
531 // Use current user's ID if none specified
532 if ( ! $user_id )
533 $user_id = get_current_user_id();
534
535 // If the points type is a WP_Post, then get the slug
536 if( is_object( $points_type ) )
537 $points_type = $points_type->post_name;
538
539 // Grab the user's current points
540 $current_points = gamipress_get_user_points( $user_id, $points_type );
541
542 // If we're getting an admin ID, $new_points is actually the final total, so subtract the current points
543 if ( $admin_id ) {
544 $new_points = $new_points - $current_points;
545 }
546
547 // Default points meta
548 $points_meta = '_gamipress_points';
549 $new_points_meta = '_gamipress_new_points';
550
551 // Points meta by type
552 if( ! empty( $points_type ) ) {
553 $points_meta = "_gamipress_{$points_type}_points";
554 $new_points_meta = "_gamipress_{$points_type}_new_points";
555 }
556
557 // Update our user's total
558 $total_points = max( $current_points + $new_points, 0 );
559
560 // Update user's points total
561 gamipress_update_user_meta( $user_id, $points_meta, $total_points );
562
563 // Update a meta as flag to meet how many points has been awarded or deducted
564 gamipress_update_user_meta( $user_id, $new_points_meta, $new_points );
565
566 // Available action for triggering other processes
567 do_action( 'gamipress_update_user_points', $user_id, $new_points, $total_points, $admin_id, $achievement_id, $points_type, $reason, $log_type );
568
569 // Maybe award some points-based achievements
570 foreach ( gamipress_get_points_based_achievements( $points_type ) as $achievement ) {
571 gamipress_maybe_award_achievement_to_user( $achievement->ID, $user_id );
572 }
573
574 return $total_points;
575 }
576
577 /**
578 * Return a user's latest points awarded or deducted
579 *
580 * @since 1.3.9.4
581 *
582 * @param integer $user_id The given user's ID
583 * @param string $points_type The points type
584 *
585 * @return integer $user_points The user's last updated points
586 */
587 function gamipress_get_last_updated_user_points( $user_id = 0, $points_type = '' ) {
588
589 // Use current user's ID if none specified
590 if ( ! $user_id )
591 $user_id = wp_get_current_user()->ID;
592
593 // Default points
594 $user_meta = '_gamipress_new_points';
595
596 if( ! empty( $points_type ) ) {
597 $user_meta = "_gamipress_{$points_type}_new_points";
598 }
599
600 // Return our user's latest points as an integer (sanely falls back to 0 if empty)
601 return absint( gamipress_get_user_meta( $user_id, $user_meta ) );
602 }
603
604 /**
605 * Update user points awarded
606 *
607 * @since 1.3.7
608 *
609 * @param integer $user_id The given user's ID
610 * @param integer $points The points the user is being awarded
611 * @param string|WP_Post $points_type The points type
612 * @param array $args Array of extra arguments
613 *
614 * @return integer The user's updated points awarded
615 */
616 function gamipress_update_user_points_awarded( $user_id = 0, $points = 0, $points_type = '', $args = array() ) {
617
618 // If points are negative, turn them to positive
619 if( $points < 0 )
620 $points *= -1;
621
622 $current_points = gamipress_get_user_points_awarded( $user_id, $points_type );
623
624 // Default points
625 $user_meta = '_gamipress_points_awarded';
626
627 if( ! empty( $points_type ) )
628 $user_meta = "_gamipress_{$points_type}_points_awarded";
629
630 // Update our user's total
631 $total_points = $current_points + $points;
632 gamipress_update_user_meta( $user_id, $user_meta, $total_points );
633
634 return $total_points;
635
636 }
637
638 /**
639 * Used on rules engine, this function returns the points amount that user has earned subtracting the used on the different checks
640 *
641 * @since 1.7.6.3
642 * @updated 1.8.1 Force function to correctly pass the date query to gamipress_get_user_points() function
643 *
644 * @param int $user_id The given user's ID
645 * @param string $points_type The points type
646 * @param int $requirement_id The requirement ID that is already in the loop
647 *
648 * @return integer $user_points The user's points on the current rules engine loop
649 */
650 function gamipress_get_user_points_awarded_in_loop( $user_id = 0, $points_type = '', $requirement_id = 0 ) {
651
652 $multiple_awarded_key = "gamipress_multiple_{$points_type}_awarded";
653 $last_points_key = "gamipress_{$points_type}_last_points";
654
655 // Initialize the last points earned array
656 if( ! isset( $GLOBALS[$last_points_key] ) ){
657 $GLOBALS[$last_points_key] = array();
658 }
659
660 $requirement_key = $requirement_id;
661
662 // Special condition for ranks that all rank requirements follow the earn points event
663 if( gamipress_get_post_type( $requirement_id ) === 'rank-requirement' ) {
664
665 // Set as requirement key the rank type instead
666 $rank_id = gamipress_get_post_field( 'post_parent', $requirement_id );
667 $requirement_key = gamipress_get_post_type( $rank_id );
668
669 }
670
671 if( ! isset( $GLOBALS[$last_points_key][$requirement_key] ) ) {
672 // Initialize the last points earned for this requirement
673
674 // Get the last activity of the current in use achievement
675 $last_activity = absint( gamipress_achievement_last_user_activity( $requirement_id, $user_id ) );
676
677 // If user hasn't earned this yet, then get activity count from publish date
678 if( $last_activity === 0 ) {
679 $last_activity = strtotime( gamipress_get_post_date( $requirement_id ) );
680 }
681
682 $args = array(
683 'date_query' => array(
684 'after' => date( 'Y-m-d H:i:s', $last_activity )
685 )
686 );
687
688 // Get user points earned since last time has earning the achievement
689 $GLOBALS[$last_points_key][$requirement_key] = gamipress_get_user_points( $user_id, $points_type, $args );
690 }
691
692 // Initialize the awarded points array
693 if( ! isset( $GLOBALS[$multiple_awarded_key] ) ) {
694 $GLOBALS[$multiple_awarded_key] = array();
695 }
696
697 if( ! isset( $GLOBALS[$multiple_awarded_key][$user_id] ) )
698 $GLOBALS[$multiple_awarded_key][$user_id] = array();
699
700 // Initialize the awarded points count for this requirement
701 if( ! isset( $GLOBALS[$multiple_awarded_key][$user_id][$requirement_key] ) ) {
702 $GLOBALS[$multiple_awarded_key][$user_id][$requirement_key] = 0;
703 }
704
705 return ( $GLOBALS[$last_points_key][$requirement_key] - $GLOBALS[$multiple_awarded_key][$user_id][$requirement_key] );
706
707 }
708
709 /**
710 * Used on rules engine, update the points amount used on the different checks
711 *
712 * @since 1.7.6.3
713 *
714 * @param int $new_points New points to apply to the already checked amoount
715 * @param string $points_type The points type
716 * @param int $requirement_id The requirement ID that is already in the loop
717 *
718 * @return integer $user_points The user's points on the current rules engine loop
719 */
720 function gamipress_update_user_points_awarded_in_loop( $new_points = 0, $points_type = '', $requirement_id = 0, $user_id = 0 ) {
721
722 $multiple_awarded_key = "gamipress_multiple_{$points_type}_awarded";
723
724 // Initialize the awarded points array
725 if( ! isset( $GLOBALS[$multiple_awarded_key] ) )
726 $GLOBALS[$multiple_awarded_key] = array();
727
728 // Initialize the last points earned array per user
729 if( ! isset( $GLOBALS[$multiple_awarded_key][$user_id] ) )
730 $GLOBALS[$multiple_awarded_key][$user_id] = array();
731
732 $requirement_key = $requirement_id;
733
734 // Special condition for ranks that all rank requiements follow the earn points event
735 if( gamipress_get_post_type( $requirement_id ) === 'rank-requirement' ) {
736
737 // Set as requirement key the rank type instead
738 $rank_id = gamipress_get_post_field( 'post_parent', $requirement_id );
739 $requirement_key = gamipress_get_post_type( $rank_id );
740
741 }
742
743 // Initialize the awarded points count for this requirement
744 if( ! isset( $GLOBALS[$multiple_awarded_key][$user_id][$requirement_key] ) )
745 $GLOBALS[$multiple_awarded_key][$user_id][$requirement_key] = 0;
746
747 $GLOBALS[$multiple_awarded_key][$user_id][$requirement_key] += $new_points;
748
749 return $GLOBALS[$multiple_awarded_key][$user_id][$requirement_key];
750
751 }
752
753 /**
754 * Update user points deducted
755 *
756 * @since 1.3.7
757 *
758 * @param integer $user_id The given user's ID
759 * @param integer $points The points the user is being deducted
760 * @param string|WP_Post $points_type The points type
761 * @param array $args Array of extra arguments
762 *
763 * @return integer The user's updated points deducted
764 */
765 function gamipress_update_user_points_deducted( $user_id = 0, $points = 0, $points_type = '', $args = array() ) {
766
767 // If points are negative, turn them to positive
768 if( $points < 0 ) {
769 $points *= -1;
770 }
771
772 $current_points = gamipress_get_user_points_deducted( $user_id, $points_type );
773
774 // Default points
775 $user_meta = '_gamipress_points_deducted';
776
777 if( ! empty( $points_type ) ) {
778 $user_meta = "_gamipress_{$points_type}_points_deducted";
779 }
780
781 // Update our user's total
782 $total_points = $current_points + $points;
783 gamipress_update_user_meta( $user_id, $user_meta, $total_points );
784
785 return $total_points;
786
787 }
788
789 /**
790 * Update user points expended
791 *
792 * @since 1.3.7
793 *
794 * @param integer $user_id The given user's ID
795 * @param integer $points The points the user is being expended
796 * @param string|WP_Post $points_type The points type
797 * @param array $args Array of extra arguments
798 *
799 * @return integer The user's updated points expended
800 */
801 function gamipress_update_user_points_expended( $user_id = 0, $points = 0, $points_type = '', $args = array() ) {
802
803 // If points are negative, turn them to positive
804 if( $points < 0 ) {
805 $points *= -1;
806 }
807
808 $current_points = gamipress_get_user_points_expended( $user_id, $points_type );
809
810 // Default points
811 $user_meta = '_gamipress_points_expended';
812
813 if( ! empty( $points_type ) ) {
814 $user_meta = "_gamipress_{$points_type}_points_expended";
815 }
816
817 // Update our user's total
818 $total_points = $current_points + $points;
819 gamipress_update_user_meta( $user_id, $user_meta, $total_points );
820
821 return $total_points;
822
823 }
824
825 /**
826 * Log a user's updated points
827 *
828 * @since 1.0.0
829 * @updated 1.3.6 Support for deduct/revoke points
830 *
831 * @param integer $user_id The user ID
832 * @param integer $new_points Points added/deducted to the user's total
833 * @param integer $total_points The user's updated total points
834 * @param integer $admin_id An admin ID (if admin-awarded)
835 * @param integer $achievement_id The associated achievement ID
836 * @param string $points_type The points type
837 * @param string $reason Custom reason to override default log pattern
838 * @param string $log_type Custom log type
839 */
840 function gamipress_log_user_points( $user_id, $new_points, $total_points, $admin_id, $achievement_id, $points_type = '', $reason = '', $log_type = '' ) {
841
842 $log_meta = array(
843 'achievement_id' => $achievement_id,
844 'points' => $new_points,
845 'points_type' => $points_type,
846 'total_points' => number_format( $total_points ),
847 );
848
849 $access = 'public';
850
851 if( ! empty( $log_type ) ) {
852 $type = $log_type;
853
854 if ( $admin_id ) {
855 $access = 'private';
856 $log_meta['admin_id'] = $admin_id;
857 }
858 } else {
859
860 // Alter our log pattern if this was an admin action
861 if ( $admin_id ) {
862
863 $access = 'private';
864 $log_meta['admin_id'] = $admin_id;
865
866 if( $new_points > 0 ) {
867 // Points awarded
868 $type = 'points_award';
869 $log_meta['pattern'] = apply_filters( 'gamipress_points_awarded_log_pattern', __( '{admin} awarded {user} {points} {points_type} for a new total of {total_points} {points_type}', 'gamipress' ) );
870 } else {
871 // Points revoked
872 $type = 'points_revoke';
873 $log_meta['pattern'] = apply_filters( 'gamipress_points_revoked_log_pattern', __( '{admin} revoked {user} {points} {points_type} for a new total of {total_points} {points_type}', 'gamipress' ) );
874 }
875
876 } else {
877
878 if( $new_points > 0 ) {
879 // Points earned
880 $type = 'points_earn';
881 $log_meta['pattern'] = apply_filters( 'gamipress_points_earned_log_pattern', __( '{user} earned {points} {points_type} for a new total of {total_points} {points_type}', 'gamipress' ) );
882 } else {
883 // Points deducted
884 $type = 'points_deduct';
885 $log_meta['pattern'] = apply_filters( 'gamipress_points_deducted_log_pattern', __( '{user} deducted {points} {points_type} for a new total of {total_points} {points_type}', 'gamipress' ) );
886 }
887
888 }
889 }
890
891 if( ! empty( $reason ) ) {
892 $log_meta['pattern'] = $reason;
893 }
894
895 // Update user counts
896 if( $type === 'points_award' || $type === 'points_earn' ) {
897 gamipress_update_user_points_awarded( $user_id, $new_points, $points_type );
898 }
899
900 if( $type === 'points_revoke' || $type === 'points_deduct' ) {
901 gamipress_update_user_points_deducted( $user_id, $new_points, $points_type );
902 }
903
904 if( $type === 'points_expend' ) {
905 gamipress_update_user_points_expended( $user_id, $new_points, $points_type );
906 }
907
908 // Decide trigger type value based on log type
909 switch( $type ) {
910 case 'points_earn':
911 $trigger = 'gamipress_earn_points';
912 break;
913 case 'points_deduct':
914 $trigger = 'gamipress_deduct_points';
915 break;
916 case 'points_award':
917 $trigger = 'gamipress_award_points';
918 break;
919 case 'points_revoke':
920 $trigger = 'gamipress_revoke_points';
921 break;
922 default:
923 $trigger = __( '(no trigger)', 'gamipress' );
924 break;
925 }
926
927 // Create the log entry
928 gamipress_insert_log( $type, $user_id, $access, $trigger, $log_meta );
929
930 }
931 add_action( 'gamipress_update_user_points', 'gamipress_log_user_points', 10, 8 );
932
933 /**
934 * Get Points Type Points Awards
935 *
936 * @since 1.0.0
937 * @updated 1.4.6 Added $post_status parameter
938 *
939 * @param integer|string $points_type The points type's post ID or the points type slug
940 * @param string $post_status The points awards status (publish by default)
941 *
942 * @return array|bool Array of WP_Post of the points awards, or false if none
943 */
944 function gamipress_get_points_type_points_awards( $points_type = 0, $post_status = 'publish' ) {
945
946 // Try to find the points type by slug
947 if( ! is_numeric( $points_type ) && ! empty( $points_type ) ) {
948 $points_types = gamipress_get_points_types();
949
950 if( isset( $points_types[$points_type] ) ) {
951 $points_type = $points_types[$points_type]['ID'];
952 }
953 }
954
955 // Grab the current post ID if no points_type_id was specified
956 if ( ! $points_type ) {
957 global $post;
958 $points_type = $post->ID;
959 }
960
961 $cache = gamipress_get_cache( 'points_type_points_awards', array(), false );
962
963 // If result already cached, return it
964 if( isset( $cache[$points_type] ) && isset( $cache[$points_type][$post_status] ) ) {
965 return $cache[$points_type][$post_status];
966 }
967
968 $points_awards = get_posts( array(
969 'post_type' => 'points-award',
970 'post_parent' => $points_type,
971 'post_status' => $post_status,
972 'orderby' => 'menu_order',
973 'order' => 'ASC',
974 'posts_per_page' => -1,
975 'suppress_filters' => false,
976 ) );
977
978 // Cache function result
979 if( ! isset( $cache[$points_type] ) ){
980 $cache[$points_type] = array();
981 }
982
983 $cache[$points_type][$post_status] = $points_awards;
984
985 gamipress_set_cache( 'points_type_points_awards', $cache );
986
987 // If it has a points type, return it, otherwise return false
988 if ( ! empty( $points_awards ) )
989 return $points_awards;
990 else
991 return false;
992
993 }
994
995 /**
996 * Get Points Award Points Type
997 *
998 * @since 1.0.0
999 *
1000 * @param integer $points_award_id The given points award's post ID
1001 * @return object|bool The post object of the points type, or false if none
1002 */
1003 function gamipress_get_points_award_points_type( $points_award_id = 0 ) {
1004
1005 // Grab the current post ID if no points_award_id was specified
1006 if ( ! $points_award_id ) {
1007 global $post;
1008 $points_award_id = $post->ID;
1009 }
1010
1011 // The points award's points type is the post parent
1012 $points_type_id = absint( gamipress_get_post_field( 'post_parent', $points_award_id ) );
1013
1014 if( $points_type_id !== 0 ) {
1015 // If has parent, return his post object
1016 return gamipress_get_post( $points_type_id );
1017 } else {
1018 return false;
1019 }
1020
1021 }
1022
1023 /**
1024 * Get Points Type Points Deductions
1025 *
1026 * @since 1.3.7
1027 * @updated 1.4.6 Added $post_status parameter
1028 *
1029 * @param integer|string $points_type The points type's post ID or the points type slug
1030 * @param string $post_status The points deducts status (publish by default)
1031 *
1032 *
1033 * @return array|bool Array of WP_Post of the points deducts, or false if none
1034 */
1035 function gamipress_get_points_type_points_deducts( $points_type = 0, $post_status = 'publish' ) {
1036
1037 // Try to find the points type by slug
1038 if( ! is_numeric( $points_type ) && ! empty( $points_type ) ) {
1039 $points_types = gamipress_get_points_types();
1040
1041 if( isset( $points_types[$points_type] ) ) {
1042 $points_type = $points_types[$points_type]['ID'];
1043 }
1044 }
1045
1046 // Grab the current post ID if no points_type_id was specified
1047 if ( ! $points_type ) {
1048 global $post;
1049 $points_type = $post->ID;
1050 }
1051
1052 $cache = gamipress_get_cache( 'points_type_points_deducts', array(), false );
1053
1054 // If result already cached, return it
1055 if( isset( $cache[$points_type] ) && isset( $cache[$points_type][$post_status] ) ) {
1056 return $cache[$points_type][$post_status];
1057 }
1058
1059 $points_deducts = get_posts( array(
1060 'post_type' => 'points-deduct',
1061 'post_parent' => $points_type,
1062 'post_status' => $post_status,
1063 'orderby' => 'menu_order',
1064 'order' => 'ASC',
1065 'posts_per_page' => -1,
1066 'suppress_filters' => false,
1067 ) );
1068
1069 // Cache function result
1070 if( ! isset( $cache[$points_type] ) ){
1071 $cache[$points_type] = array();
1072 }
1073
1074 $cache[$points_type][$post_status] = $points_deducts;
1075
1076 gamipress_set_cache( 'points_type_points_deducts', $cache );
1077
1078 // If it has a points type, return it, otherwise return false
1079 if ( ! empty( $points_deducts ) )
1080 return $points_deducts;
1081 else
1082 return false;
1083
1084 }
1085
1086 /**
1087 * Get Points Deduction Points Type
1088 *
1089 * @since 1.3.7
1090 *
1091 * @param integer $points_deduct_id The given points deduct's post ID
1092 * @return object|bool The post object of the points type, or false if none
1093 */
1094 function gamipress_get_points_deduct_points_type( $points_deduct_id = 0 ) {
1095
1096 // Grab the current post ID if no points_award_id was specified
1097 if ( ! $points_deduct_id ) {
1098 global $post;
1099 $points_deduct_id = $post->ID;
1100 }
1101
1102 // The points award's points type is the post parent
1103 $points_type_id = absint( gamipress_get_post_field( 'post_parent', $points_deduct_id ) );
1104
1105 if( $points_type_id !== 0 ) {
1106 // If has parent, return his post object
1107 return get_post( $points_type_id );
1108 } else {
1109 return false;
1110 }
1111
1112 }
1113
1114 /**
1115 * Update all dependent data if points type name has changed.
1116 *
1117 * @since 1.0.0
1118 *
1119 * @param array $data Post data.
1120 * @param array $post_args Post args.
1121 * @return array Updated post data.
1122 */
1123 function gamipress_maybe_update_points_type( $data = array(), $post_args = array() ) {
1124
1125 // Bail if not is main site, on network wide installs points are just available on main site
1126 if( gamipress_is_network_wide_active() && ! is_main_site() ) {
1127 return $data;
1128 }
1129
1130 // Bail if not is a points type
1131 if( $post_args['post_type'] !== 'points-type') {
1132 return $data;
1133 }
1134
1135 // If user set an empty slug, then generate it
1136 if( empty( $post_args['post_name'] ) ) {
1137 $post_args['post_name'] = wp_unique_post_slug(
1138 sanitize_title( $post_args['post_title'] ),
1139 $post_args['ID'],
1140 $post_args['post_status'],
1141 $post_args['post_type'],
1142 $post_args['post_parent']
1143 );
1144 }
1145
1146 // Sanitize post_name
1147 $post_args['post_name'] = gamipress_sanitize_slug( $post_args['post_name'] );
1148
1149 if ( gamipress_points_type_changed( $post_args ) ) {
1150
1151 $original_type = get_post( $post_args['ID'] )->post_name;
1152 $new_type = $post_args['post_name'];
1153
1154 $data['post_name'] = gamipress_update_points_types( $original_type, $new_type );
1155
1156 add_filter( 'redirect_post_location', 'gamipress_points_type_rename_redirect', 99 );
1157
1158 }
1159
1160 return $data;
1161 }
1162 add_filter( 'wp_insert_post_data' , 'gamipress_maybe_update_points_type' , 99, 2 );
1163
1164 /**
1165 * Check if a points type name has changed.
1166 *
1167 * @since 1.0.0
1168 *
1169 * @param array $post_args Post args.
1170 * @return bool True if name has changed, otherwise false.
1171 */
1172 function gamipress_points_type_changed( $post_args = array() ) {
1173 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
1174 return false;
1175 }
1176
1177 $original_post = ( !empty( $post_args['ID'] ) && isset( $post_args['ID'] ) ) ? get_post( $post_args['ID'] ) : null;
1178 $status = false;
1179 if ( is_object( $original_post ) ) {
1180 if (
1181 'points-type' === $post_args['post_type']
1182 && $original_post->post_status !== 'auto-draft'
1183 && ! empty( $original_post->post_name )
1184 && $original_post->post_name !== $post_args['post_name']
1185 ) {
1186 $status = true;
1187 }
1188 }
1189
1190 return $status;
1191 }
1192
1193 /**
1194 * Replace all instances of one points type with another.
1195 *
1196 * @since 1.0.0
1197 *
1198 * @param string $original_type Original points type.
1199 * @param string $new_type New points type.
1200 * @return string New points type.
1201 */
1202 function gamipress_update_points_types( $original_type = '', $new_type = '' ) {
1203
1204 // Sanity check to prevent alterating core posts
1205 if ( empty( $original_type ) || in_array( $original_type, array( 'post', 'page', 'attachment', 'revision', 'nav_menu_item' ) ) ) {
1206 return $new_type;
1207 }
1208
1209 gamipress_update_post_meta_points_type( $original_type, $new_type );
1210 gamipress_update_user_meta_points_types( $original_type, $new_type );
1211 gamipress_update_logs_metas_points_types( $original_type, $new_type );
1212 gamipress_update_user_earnings_points_types( $original_type, $new_type );
1213 gamipress_flush_rewrite_rules();
1214
1215 return $new_type;
1216 }
1217
1218 /**
1219 * Replace all posts metas with old points type with the new one.
1220 *
1221 * @since 1.2.7
1222 *
1223 * @param string $original_type Original points type.
1224 * @param string $new_type New points type.
1225 *
1226 * @return array|object|null Post metas updated.
1227 */
1228 function gamipress_update_post_meta_points_type( $original_type = '', $new_type = '' ) {
1229
1230 global $wpdb;
1231
1232 $postmeta = GamiPress()->db->postmeta;
1233
1234 return $wpdb->get_results( $wpdb->prepare(
1235 "UPDATE {$postmeta}
1236 SET meta_value = %s
1237 WHERE meta_key = %s
1238 AND meta_value = %s",
1239 $new_type,
1240 "_gamipress_points_type",
1241 $original_type
1242 ) );
1243
1244 }
1245
1246 /**
1247 * Replace all user metas with old points type with the new one.
1248 *
1249 * @since 1.0.0
1250 *
1251 * @param string $original_type Original points type.
1252 * @param string $new_type New points type.
1253 *
1254 * @return array|object|null User metas updated.
1255 */
1256 function gamipress_update_user_meta_points_types( $original_type = '', $new_type = '' ) {
1257
1258 global $wpdb;
1259
1260 return $wpdb->get_results( $wpdb->prepare(
1261 "UPDATE {$wpdb->usermeta}
1262 SET meta_key = %s
1263 WHERE meta_key = %s",
1264 "_gamipress_{$new_type}_points",
1265 "_gamipress_{$original_type}_points"
1266 ) );
1267
1268 }
1269
1270 /**
1271 * Replace all logs metas with old points type with the new one.
1272 *
1273 * @since 1.7.5
1274 *
1275 * @param string $original_type Original points type.
1276 * @param string $new_type New points type.
1277 *
1278 * @return array|object|null Logs metas updated.
1279 */
1280 function gamipress_update_logs_metas_points_types( $original_type = '', $new_type = '' ) {
1281
1282 global $wpdb;
1283
1284 $logs_meta = GamiPress()->db->logs_meta;
1285
1286 $result = $wpdb->get_results( $wpdb->prepare(
1287 "UPDATE {$logs_meta}
1288 SET meta_value = %s
1289 WHERE meta_key = %s
1290 AND meta_value = %s",
1291 $new_type,
1292 "_gamipress_points_type",
1293 $original_type
1294 ) );
1295
1296 return $result;
1297
1298 }
1299
1300 /**
1301 * Replace all user earnings with old points type with the new one.
1302 *
1303 * @since 1.7.5
1304 *
1305 * @param string $original_type Original points type.
1306 * @param string $new_type New points type.
1307 *
1308 * @return array|object|null User earnings updated.
1309 */
1310 function gamipress_update_user_earnings_points_types( $original_type = '', $new_type = '' ) {
1311
1312 global $wpdb;
1313
1314 $user_earnings = GamiPress()->db->user_earnings;
1315
1316 $result = $wpdb->get_results( $wpdb->prepare(
1317 "UPDATE {$user_earnings}
1318 SET points_type = %s
1319 WHERE points_type = %s",
1320 $new_type,
1321 $original_type
1322 ) );
1323
1324 return $result;
1325
1326 }
1327
1328 /**
1329 * Redirect to include custom rename message.
1330 *
1331 * @since 1.0.0
1332 *
1333 * @param string $location Original URI.
1334 * @return string Updated URI.
1335 */
1336 function gamipress_points_type_rename_redirect( $location = '' ) {
1337
1338 remove_filter( 'redirect_post_location', __FUNCTION__, 99 );
1339
1340 return add_query_arg( 'message', 99, $location );
1341
1342 }
1343
1344 /**
1345 * Filter the "post updated" messages to include support for points types.
1346 *
1347 * @since 1.0.0
1348 *
1349 * @param array $messages Array of messages to display.
1350 *
1351 * @return array $messages Compiled list of messages.
1352 */
1353 function gamipress_points_type_update_messages( $messages ) {
1354
1355 $messages['points-type'] = array_fill( 1, 10, __( 'Points Type saved successfully.', 'gamipress' ) );
1356 $messages['points-type']['99'] = sprintf( __('Points Type renamed successfully. <p>All user points of this type have been updated <strong>automatically</strong>.</p> All shortcodes, %s, and URIs that reference the old points type slug must be updated <strong>manually</strong>.', 'gamipress'), '<a href="' . esc_url( admin_url( 'widgets.php' ) ) . '">' . __( 'widgets', 'gamipress' ) . '</a>' );
1357
1358 return $messages;
1359
1360 }
1361 add_filter( 'post_updated_messages', 'gamipress_points_type_update_messages' );
1362
1363 /**
1364 * Helper function to retrieve a points post thumbnail
1365 *
1366 * @since 1.3.7
1367 *
1368 * @param integer|string $points_type The points type's post ID or slug
1369 * @param string $image_size The name of a registered custom image size
1370 * @param string $class A custom class to use for the image tag
1371 *
1372 * @return string Our formatted image tag
1373 */
1374 function gamipress_get_points_type_thumbnail( $points_type = '', $image_size = 'gamipress-points', $class = 'gamipress-points-thumbnail' ) {
1375
1376 if( gettype( $points_type ) === 'integer' ) {
1377 $post_id = $points_type;
1378 } else if( absint( $points_type ) !== 0 ) {
1379 $post_id = $points_type;
1380 } else {
1381 $points_types = gamipress_get_points_types();
1382
1383 if( ! isset( $points_types[$points_type] ) ) {
1384 return '';
1385 }
1386
1387 $post_id = $points_types[$points_type]['ID'];
1388 }
1389
1390 // Return our image tag with custom size
1391 return gamipress_get_the_post_thumbnail( $post_id, $image_size, array( 'class' => $class ) );
1392
1393 }
1394