PluginProbe
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI / 7.9.8
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI v7.9.8
8.0.4 8.0.3 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 All 46 releases
gamipress / includes / functions / points.php

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

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