PluginProbe
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI / trunk
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI vtrunk
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 / ranks.php

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

1,443 lines 41.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Rank Functions
4 *
5 * @package GamiPress\Rank_Functions
6 * @author GamiPress <contact@gamipress.com>, Ruben Garcia <rubengcdev@gmail.com>
7 * @since 1.3.1
8 */
9 // Exit if accessed directly
10 if( !defined( 'ABSPATH' ) ) exit;
11
12 /**
13 * Check if post is a registered GamiPress rank.
14 *
15 * @since 1.3.1
16 *
17 * @param object|int|string $post Post object or ID.
18 * @return bool True if post is an rank, otherwise false.
19 */
20 function gamipress_is_rank( $post = null ) {
21
22 $return = true;
23
24 if( gettype($post) === 'string' ) {
25 if( is_numeric($post) ) {
26 $post_type = gamipress_get_post_type( $post );
27 } else {
28 $post_type = $post;
29 }
30 } else {
31 $post_type = gamipress_get_post_type( $post );
32 }
33
34 // If post type is NOT a registered rank type, it cannot be an rank
35 if ( ! in_array( $post_type, gamipress_get_rank_types_slugs() ) ) {
36 $return = false;
37 }
38
39 // If we pass both previous tests, this is a valid rank (with filter to override)
40 return apply_filters( 'gamipress_is_rank', $return, $post, $post_type );
41
42 }
43
44 /**
45 * Return registered ranks
46 *
47 * @since 1.3.1
48 *
49 * @return array Array of ranks as WP_Post
50 */
51 function gamipress_get_ranks( $args = array() ) {
52
53 // Setup our defaults
54 $defaults = array(
55 'post_type' => array_merge( gamipress_get_rank_types_slugs(), gamipress_get_requirement_types_slugs() ),
56 'numberposts' => -1,
57 'orderby' => 'menu_order',
58 'suppress_filters' => false,
59 'rank_relationship' => 'any',
60 );
61
62 $args = wp_parse_args( $args, $defaults );
63
64 // Since 1.5.1, requirements has their parent stored in the post_parent field, so it isn't required at all
65 if ( isset( $args['parent_of'] ) ) {
66
67 $post_parent = absint( gamipress_get_post_field( 'post_parent', $args['parent_of'] ) );
68
69 if( $post_parent === 0 ) {
70 return array();
71 }
72
73 $args['post__in'] = array( $post_parent );
74
75 }
76
77 // Since 1.5.1, requirements has their parent stored in the post_parent field, so it isn't required at all
78 if ( isset( $args['children_of'] ) ) {
79
80 $args['post_parent'] = $args['children_of'];
81
82 // When looking to get rank requirements, order is important to sequential requirements
83 $args['orderby'] = 'menu_order';
84 $args['order'] = 'ASC';
85
86 }
87
88 // Get our ranks posts
89 $ranks = get_posts( $args );
90
91 return $ranks;
92
93 }
94
95 /**
96 * Return user current rank id
97 *
98 * @since 1.3.1
99 *
100 * @param integer $user_id The given user's ID
101 * @param string $rank_type The rank type
102 *
103 * @return integer
104 */
105 function gamipress_get_user_rank_id( $user_id = null, $rank_type = '' ) {
106
107 global $wpdb;
108
109 if( $user_id === null ) {
110 $user_id = get_current_user_id();
111 }
112
113 $meta = '_gamipress_rank';
114
115 if( ! empty( $rank_type ) ) {
116 $meta = "_gamipress_{$rank_type}_rank";
117 }
118
119 $current_rank_id = absint( gamipress_get_user_meta( $user_id, $meta ) );
120 $is_rank = $current_rank_id > 0 ? gamipress_is_rank( $current_rank_id ) : false;
121
122 if( ! $is_rank ) {
123
124 $posts = GamiPress()->db->posts;
125
126 // Get lowest priority rank as default rank to all users
127 $current_rank_id = $wpdb->get_var( $wpdb->prepare(
128 "SELECT p.ID
129 FROM {$posts} AS p
130 WHERE p.post_type = %s
131 AND p.post_status = %s
132 ORDER BY menu_order ASC
133 LIMIT 1",
134 $rank_type,
135 'publish'
136 ) );
137
138 }
139
140 return apply_filters( 'gamipress_get_user_rank_id', $current_rank_id, $user_id );
141
142 }
143
144 /**
145 * Return user current rank
146 *
147 * @since 1.3.1
148 *
149 * @param integer $user_id The given user's ID
150 * @param string $rank_type The rank type
151 *
152 * @return bool|WP_Post
153 */
154 function gamipress_get_user_rank( $user_id = null, $rank_type = '' ) {
155
156 global $wpdb;
157
158 if( $user_id === null ) {
159 $user_id = get_current_user_id();
160 }
161
162 $current_rank_id = gamipress_get_user_rank_id( $user_id, $rank_type );
163
164 $rank = gamipress_get_post( $current_rank_id );
165
166 if( $rank ) {
167 return apply_filters( 'gamipress_get_user_rank', $rank, $user_id, $current_rank_id );
168 }
169
170 return false;
171
172 }
173
174 /**
175 * Return user next rank id
176 *
177 * @since 1.3.1
178 *
179 * @param integer $user_id The given user's ID
180 * @param string $rank_type The rank type
181 *
182 * @return integer
183 */
184 function gamipress_get_next_user_rank_id( $user_id = null, $rank_type = '' ) {
185
186 global $wpdb;
187
188 if( $user_id === null ) {
189 $user_id = get_current_user_id();
190 }
191
192 $current_rank_id = gamipress_get_user_rank_id( $user_id, $rank_type );
193
194 $next_rank_id = gamipress_get_next_rank_id( $current_rank_id );
195
196 return apply_filters( 'gamipress_get_next_user_rank_id', absint( $next_rank_id ), $user_id, $rank_type, $current_rank_id );
197
198 }
199
200 /**
201 * Return user next rank
202 *
203 * @since 1.3.1
204 *
205 * @param integer $user_id The given user's ID
206 * @param string $rank_type The rank type
207 *
208 * @return bool|WP_Post
209 */
210 function gamipress_get_next_user_rank( $user_id = null, $rank_type = '' ) {
211
212 global $wpdb;
213
214 if( $user_id === null ) {
215 $user_id = get_current_user_id();
216 }
217
218 $current_rank_id = gamipress_get_user_rank_id( $user_id, $rank_type );
219
220 $next_rank = gamipress_get_next_rank( $current_rank_id );
221
222 if( $next_rank ) {
223 return apply_filters( 'gamipress_get_next_user_rank', $next_rank, $user_id, $rank_type, $current_rank_id );
224 }
225
226 return false;
227
228 }
229
230 /**
231 * Return next rank id based of given rank priority
232 *
233 * @since 1.3.1
234 *
235 * @param integer $rank_id The given rank's ID
236 *
237 * @return integer
238 */
239 function gamipress_get_next_rank_id( $rank_id = null ) {
240
241 global $wpdb;
242
243 if( $rank_id === null ) {
244 $rank_id = get_the_ID();
245 }
246
247 $cache = gamipress_get_cache( 'next_rank_id', array(), false );
248
249 // If result already cached, return it
250 if( isset( $cache[$rank_id] ) ) {
251 return $cache[$rank_id];
252 }
253
254 $rank_type = gamipress_get_post_type( $rank_id );
255
256 $posts = GamiPress()->db->posts;
257
258 // Get lowest priority rank but bigger than current one
259 $next_rank_id = $wpdb->get_var( $wpdb->prepare(
260 "SELECT p.ID
261 FROM {$posts} AS p
262 WHERE p.post_type = %s
263 AND p.post_status = %s
264 AND p.menu_order > %s
265 ORDER BY menu_order ASC
266 LIMIT 1",
267 $rank_type,
268 'publish',
269 gamipress_get_post_field( 'menu_order', $rank_id )
270 ) );
271
272 $next_rank_id = absint( $next_rank_id );
273
274 if( $next_rank_id === $rank_id ) {
275 $next_rank_id = 0;
276 }
277
278 $next_rank_id = apply_filters( 'gamipress_get_next_rank_id', $next_rank_id, $rank_id );
279
280 // Cache function result
281 $cache[$rank_id] = $next_rank_id;
282
283 gamipress_set_cache( 'next_rank_id', $cache );
284
285 return $next_rank_id;
286
287 }
288
289 /**
290 * Return next rank based of given rank priority
291 *
292 * @since 1.3.1
293 *
294 * @param integer $rank_id The given rank's ID
295 *
296 * @return bool|WP_Post
297 */
298 function gamipress_get_next_rank( $rank_id = null ) {
299
300 if( $rank_id === null ) {
301 $rank_id = get_the_ID();
302 }
303
304 $next_rank_id = gamipress_get_next_rank_id( $rank_id );
305
306 if( $next_rank_id === 0 ) {
307 return false;
308 }
309
310 $rank = gamipress_get_post( $next_rank_id );
311
312 if( $rank ) {
313 return apply_filters( 'gamipress_get_next_rank', $rank, $next_rank_id, $rank_id );
314 }
315
316 return false;
317
318 }
319
320 /**
321 * Return previous rank id based of given rank priority
322 *
323 * @since 1.3.1
324 *
325 * @param integer $rank_id The given rank's ID
326 *
327 * @return integer
328 */
329 function gamipress_get_prev_rank_id( $rank_id = null ) {
330
331 global $wpdb;
332
333 if( $rank_id === null ) {
334 $rank_id = get_the_ID();
335 }
336
337 $cache = gamipress_get_cache( 'prev_rank_id', array(), false );
338
339 // If result already cached, return it
340 if( isset( $cache[$rank_id] ) ) {
341 return $cache[$rank_id];
342 }
343
344 $rank_type = gamipress_get_post_type( $rank_id );
345
346 $posts = GamiPress()->db->posts;
347
348 // Get highest priority rank but less than current one
349 $prev_rank_id = $wpdb->get_var( $wpdb->prepare(
350 "SELECT p.ID
351 FROM {$posts} AS p
352 WHERE p.post_type = %s
353 AND p.post_status = %s
354 AND p.menu_order < %s
355 ORDER BY menu_order DESC
356 LIMIT 1",
357 $rank_type,
358 'publish',
359 gamipress_get_post_field( 'menu_order', $rank_id )
360 ) );
361
362 $prev_rank_id = absint( $prev_rank_id );
363
364 if( $prev_rank_id === $rank_id ) {
365 $prev_rank_id = 0;
366 }
367
368 $prev_rank_id = apply_filters( 'gamipress_get_prev_rank_id', $prev_rank_id, $rank_id );
369
370 // Cache function result
371 $cache[$rank_id] = $prev_rank_id;
372
373 gamipress_set_cache( 'prev_rank_id', $cache );
374
375 return $prev_rank_id;
376
377 }
378
379 /**
380 * Return previous rank based of given rank priority
381 *
382 * @since 1.3.1
383 *
384 * @param integer $rank_id The given rank's ID
385 *
386 * @return bool|WP_Post
387 */
388 function gamipress_get_prev_rank( $rank_id = null ) {
389
390 if( $rank_id === null ) {
391 $rank_id = get_the_ID();
392 }
393
394 $prev_rank_id = gamipress_get_prev_rank_id( $rank_id );
395
396 if( $prev_rank_id === 0 ) {
397 return false;
398 }
399
400 $rank = gamipress_get_post( $prev_rank_id );
401
402 if( $rank ) {
403 return apply_filters( 'gamipress_get_prev_rank', $rank, $prev_rank_id, $rank_id );
404 }
405
406 return false;
407
408 }
409
410 /**
411 * Return previous user rank
412 *
413 * @since 1.4.3
414 *
415 * @param integer $user_id The given user's ID
416 * @param string $rank_type The given rank's type
417 *
418 * @return bool|int
419 */
420 function gamipress_get_prev_user_rank_id( $user_id = null, $rank_type = '' ) {
421
422 if( $user_id === null ) {
423 $user_id = get_current_user_id();
424 }
425
426 $old_meta = "_gamipress_{$rank_type}_previous_rank";
427 $prev_user_rank_id = absint( gamipress_get_user_meta( $user_id, $old_meta ) );
428
429 // Check if there is a previous rank stored, if not, try to get previous rank of current user rank
430 if( $prev_user_rank_id === 0 ) {
431
432 $user_rank_id = gamipress_get_user_rank_id( $user_id, $rank_type );
433
434 // If there is not previous rank and not current rank, return lowest priority rank ID
435 if( ! $user_rank_id ) {
436 return gamipress_get_lowest_priority_rank_id( $rank_type );
437 }
438
439 $prev_user_rank_id = gamipress_get_prev_rank_id( $user_rank_id );
440 }
441
442 if( $prev_user_rank_id ) {
443 return apply_filters( 'gamipress_get_prev_user_rank_id', $prev_user_rank_id, $user_id, $rank_type );
444 }
445
446 return false;
447
448 }
449
450 /**
451 * Helper function to check if a rank is the lowest priority rank (aka the default rank to anyone)
452 *
453 * @since 1.3.6
454 *
455 * @param integer $rank_id The given rank's ID
456 *
457 * @return bool
458 */
459 function gamipress_is_lowest_priority_rank( $rank_id = null ) {
460
461 if( $rank_id === null ) {
462 $rank_id = get_the_ID();
463 }
464
465 $prev_rank_id = gamipress_get_prev_rank_id( $rank_id );
466
467 // Return true if previous rank is 0 or the same that given one
468 return (bool) ( $rank_id === $prev_rank_id || $prev_rank_id === 0 );
469
470 }
471
472 /**
473 * Get the lowest priority rank ID of a rank type
474 *
475 * @since 1.4.3
476 *
477 * @param string $rank_type The given rank's type
478 *
479 * @return int
480 */
481 function gamipress_get_lowest_priority_rank_id( $rank_type = null ) {
482
483 global $wpdb;
484
485 $posts = GamiPress()->db->posts;
486
487 // Get the lowest priority rank
488 $rank_id = $wpdb->get_var( $wpdb->prepare(
489 "SELECT p.ID
490 FROM {$posts} AS p
491 WHERE p.post_type = %s
492 AND p.post_status = %s
493 ORDER BY menu_order ASC
494 LIMIT 1",
495 $rank_type,
496 'publish'
497 ) );
498
499 // Return true if previous rank is 0 or the same that given one
500 return apply_filters( 'gamipress_get_lowest_priority_rank_id', absint( $rank_id ), $rank_type );
501
502 }
503
504 /**
505 * Award rank to a user
506 *
507 * @since 1.4.3
508 *
509 * @param integer $rank_id The rank is being awarded
510 * @param integer $user_id The given user's ID
511 * @param array $args Array of extra arguments
512 *
513 * @return bool|WP_Post WP Post object of newly rank awarded, false if process fails
514 */
515 function gamipress_award_rank_to_user( $rank_id = 0, $user_id = 0, $args = array() ) {
516
517 // Bail if not is a valid rank
518 if( ! gamipress_is_rank( $rank_id ) ) {
519 return false;
520 }
521
522 // Initialize args
523 $args = wp_parse_args( $args, array(
524 'admin_id' => 0,
525 'achievement_id' => null,
526 ) );
527
528 // Available action for triggering other processes
529 do_action( 'gamipress_award_rank_to_user', $user_id, $rank_id, $args );
530
531 return gamipress_update_user_rank( $user_id, $rank_id, $args['admin_id'], $args['achievement_id'] );
532
533 }
534
535 /**
536 * Revoke rank to a user
537 *
538 * @since 1.4.3
539 *
540 * @param integer $user_id The given user's ID
541 * @param integer $rank_id The rank is being revoked
542 * @param integer $new_rank_id The new user rank, if not provided user will get the previous rank
543 * @param array $args Array of extra arguments
544 *
545 * @return bool|WP_Post WP Post object of newly rank revoked, false if process fails
546 */
547 function gamipress_revoke_rank_to_user( $user_id = 0, $rank_id = 0, $new_rank_id = 0, $args = array() ) {
548
549 // Bail if not is a valid rank
550 if( ! gamipress_is_rank( $rank_id ) ) {
551 return false;
552 }
553
554 // Initialize args
555 $args = wp_parse_args( $args, array(
556 'admin_id' => 0,
557 'achievement_id' => null,
558 ) );
559
560 // If not new rank provided, then get the previous user rank
561 if( $new_rank_id === 0 ) {
562 $rank_type = gamipress_get_post_type( $rank_id );
563
564 $new_rank_id = gamipress_get_prev_user_rank_id( $user_id, $rank_type );
565 }
566
567 // Available action for triggering other processes
568 do_action( 'gamipress_revoke_rank_to_user', $user_id, $rank_id, $new_rank_id, $args );
569
570 // Removes the rank from the user earnings table
571 gamipress_revoke_achievement_to_user( $rank_id, $user_id );
572
573 // Set the new rank to the user
574 return gamipress_update_user_rank( $user_id, $new_rank_id, $args['admin_id'], $args['achievement_id'] );
575
576 }
577
578 /**
579 * Upgrade the given user to the next rank of a rank type
580 *
581 * @since 1.4.3
582 *
583 * @param int $user_id The given user's ID
584 * @param string $rank_type The given rank's type
585 *
586 * @return bool|WP_Post WP Post object of newly rank upgraded, false if process fails
587 */
588 function gamipress_upgrade_user_to_next_rank( $user_id = 0, $rank_type = '' ) {
589
590 // Bail if not is a valid rank type
591 if( ! gamipress_is_rank( $rank_type ) ) {
592 return false;
593 }
594
595 $user_rank_id = gamipress_get_user_rank_id( $user_id, $rank_type );
596 $next_rank_id = gamipress_get_next_rank_id( $user_rank_id );
597
598 // User is already on higher rank, so bail here
599 if( $next_rank_id === $user_rank_id ) {
600 return false;
601 }
602
603 // Award the next rank to the user
604 return gamipress_award_rank_to_user( $next_rank_id, $user_id );
605
606 }
607
608 /**
609 * Downgrade the given user to the previous rank of a rank type
610 *
611 * @since 1.4.3
612 *
613 * @param int $user_id The given user's ID
614 * @param string $rank_type The given rank's type
615 *
616 * @return bool|WP_Post WP Post object of newly rank downgraded, false if process fails
617 */
618 function gamipress_downgrade_user_to_prev_rank( $user_id = 0, $rank_type = '' ) {
619
620 // Bail if not is a valid rank type
621 if( ! gamipress_is_rank( $rank_type ) ) {
622 return false;
623 }
624
625 $user_rank_id = gamipress_get_user_rank_id( $user_id, $rank_type );
626 $prev_rank_id = gamipress_get_prev_rank_id( $user_rank_id );
627
628 // User is already on lowest rank, so bail here
629 if( $prev_rank_id === $user_rank_id ) {
630 return false;
631 }
632
633 // Award the previous rank to the user
634 return gamipress_revoke_rank_to_user( $user_id, $user_rank_id, $prev_rank_id );
635
636 }
637
638 /**
639 * Update user rank to the given one
640 *
641 * @since 1.3.1
642 *
643 * @param integer $user_id The given user's ID
644 * @param integer $rank_id The new rank the user is being awarded
645 * @param integer $admin_id If being awarded by an admin, the admin's user ID
646 * @param integer $achievement_id The achievement that generated the rank upgrade, if applicable
647 *
648 * @return bool|WP_Post
649 */
650 function gamipress_update_user_rank( $user_id = 0, $rank_id = 0, $admin_id = 0, $achievement_id = null ) {
651
652 if( ! $rank_id )
653 return false;
654
655 if( ! $user_id )
656 $user_id = get_current_user_id();
657
658 $new_rank = gamipress_get_post( $rank_id );
659
660 // Get user old rank if has one
661 $old_rank = gamipress_get_user_rank( $user_id, $new_rank->post_type );
662
663 // If is the same rank, return
664 if( $old_rank && $new_rank && $new_rank->ID === $old_rank->ID )
665 return $new_rank;
666
667 // Check if is a valid rank and is not the same rank as current one
668 if( $new_rank && gamipress_is_rank( $new_rank ) ) {
669
670 $meta = "_gamipress_{$new_rank->post_type}_rank";
671
672 // Update the user rank and the time when this rank has been earned
673 gamipress_update_user_meta( $user_id, $meta, $new_rank->ID );
674 gamipress_update_user_meta( $user_id, $meta . '_earned_time', current_time( 'timestamp' ) );
675
676 if( $old_rank ) {
677
678 // Stores the user old rank to meet it for revokes
679 $old_meta = "_gamipress_{$new_rank->post_type}_previous_rank";
680 gamipress_update_user_meta( $user_id, $old_meta, $old_rank->ID );
681
682 }
683
684 // Available action for triggering other processes
685 do_action( 'gamipress_update_user_rank', $user_id, $new_rank, $old_rank, $admin_id, $achievement_id );
686
687 // Maybe award some points-based achievements
688 foreach ( gamipress_get_rank_based_achievements() as $achievement ) {
689 gamipress_maybe_award_achievement_to_user( $achievement->ID, $user_id );
690 }
691
692 return $new_rank;
693 }
694
695 return false;
696
697 }
698
699 /**
700 * Register a user's updated rank as user earning
701 *
702 * @since 1.3.1
703 *
704 * @param integer $user_id The user ID
705 * @param WP_Post $new_rank New rank post object
706 * @param WP_Post $old_rank Old rank post object
707 * @param integer $admin_id An admin ID (if admin-awarded)
708 * @param integer $achievement_id Achievement that has been triggered it
709 */
710 function gamipress_register_user_rank_earning( $user_id, $new_rank, $old_rank, $admin_id = 0, $achievement_id = null ) {
711
712 // Setup our achievement object
713 $achievement_object = gamipress_build_achievement_object( $new_rank->ID );
714
715 // Update user's earned achievements
716 gamipress_update_user_achievements( array( 'user_id' => $user_id, 'new_achievements' => array( $achievement_object ) ) );
717
718 }
719 add_action( 'gamipress_update_user_rank', 'gamipress_register_user_rank_earning', 10, 5 );
720
721 /**
722 * Log a user's updated rank
723 *
724 * @since 1.3.1
725 *
726 * @param integer $user_id The user ID
727 * @param WP_Post $new_rank New rank post object
728 * @param WP_Post $old_rank Old rank post object
729 * @param integer $admin_id An admin ID (if admin-awarded)
730 * @param integer $achievement_id Achievement that has been triggered it
731 */
732 function gamipress_log_user_rank( $user_id, $new_rank, $old_rank, $admin_id = 0, $achievement_id = null ) {
733
734 $log_meta = array(
735 'rank_id' => ( $new_rank ? $new_rank->ID : 0 ),
736 'old_rank_id' => ( $old_rank ? $old_rank->ID : 0 ),
737 );
738
739 $access = 'public';
740 $trigger = '';
741
742 // Alter our log pattern if this was an admin action
743 if ( $admin_id ) {
744 $type = 'rank_award';
745 $access = 'private';
746
747 $log_meta['pattern'] = apply_filters( 'gamipress_rank_awarded_log_pattern', __( '{admin} ranked {user} to {rank_type} {rank}', 'gamipress' ) );
748 $log_meta['admin_id'] = $admin_id;
749 $trigger = 'gamipress_award_rank';
750 } else {
751 $type = 'rank_earn';
752 $log_meta['pattern'] = apply_filters( 'gamipress_rank_earned_log_pattern', __( '{user} ranked to {rank_type} {rank}', 'gamipress' ) );
753
754 if( $achievement_id ) {
755 $log_meta['achievement_id'] = $achievement_id;
756 $trigger = gamipress_get_post_meta( $achievement_id, '_gamipress_trigger_type' );
757 }
758
759 if( empty( $trigger ) ) {
760 $trigger = 'gamipress_unlock_rank';
761 }
762 }
763
764 // Create the log entry
765 gamipress_insert_log( $type, $user_id, $access, $trigger, $log_meta );
766
767 }
768 add_action( 'gamipress_update_user_rank', 'gamipress_log_user_rank', 10, 5 );
769
770 /**
771 * Get rank requirement's rank
772 *
773 * @since 1.3.1
774 *
775 * @param integer $rank_requirement_id The given rank requirement's post ID
776 *
777 * @return object|bool The post object of the rank, or false if none
778 */
779 function gamipress_get_rank_requirement_rank( $rank_requirement_id = 0 ) {
780
781 // Grab the current post ID if no rank requirement ID was specified
782 if ( ! $rank_requirement_id ) {
783 global $post;
784 $rank_requirement_id = $post->ID;
785 }
786
787 // The rank requirement's rank is the post parent
788 $rank_id = absint( gamipress_get_post_field( 'post_parent', $rank_requirement_id ) );
789
790 // If has parent, return his post object
791 if( $rank_id !== 0 )
792 return gamipress_get_post( $rank_id );
793 else
794 return false;
795 }
796
797 /**
798 * Get Rank Earned Time
799 *
800 * @since 1.3.1
801 *
802 * @param integer $user_id The given rank requirement's post ID
803 * @param string $rank_type The given rank requirement's post ID
804 *
805 * @return integer Timestamp of user has earned the last rank of this type, if not, fall back to the rank created date
806 */
807 function gamipress_get_rank_earned_time( $user_id = 0, $rank_type = '' ) {
808
809 $earned_time = absint( gamipress_get_user_meta( $user_id, "_gamipress_{$rank_type}_rank_earned_time" ) );
810
811 // If user has not earned a rank of this type, try to get the lowest priority rank and get its publish date
812 if( $earned_time === 0 ) {
813 $rank = gamipress_get_user_rank( $user_id, $rank_type );
814
815 if( $rank )
816 $earned_time = strtotime( $rank->post_date );
817 }
818
819 return $earned_time;
820
821 }
822
823 /**
824 * Get rank requirements
825 *
826 * @since 1.3.1
827 * @updated 1.5.1 Added $post_status parameter
828 *
829 * @param integer $rank_id The given rank requirement's post ID
830 * @param string $post_status The rank requirements status (publish by default)
831 *
832 * @return array An array of post objects with the rank requirements
833 */
834 function gamipress_get_rank_requirements( $rank_id = 0, $post_status = 'publish' ) {
835
836 // Grab the current post ID if no rank_id was specified
837 if ( ! $rank_id ) {
838 global $post;
839 $rank_id = $post->ID;
840 }
841
842 $cache = gamipress_get_cache( 'rank_requirements', array(), false );
843
844 // If result already cached, return it
845 if( isset( $cache[$rank_id] ) && isset( $cache[$rank_id][$post_status] ) ) {
846 return $cache[$rank_id][$post_status];
847 }
848
849 $requirements = get_posts( array(
850 'post_type' => 'rank-requirement',
851 'post_parent' => $rank_id,
852 'post_status' => $post_status,
853 'orderby' => 'menu_order',
854 'order' => 'ASC',
855 'posts_per_page' => -1,
856 'suppress_filters' => false,
857 ) );
858
859 // Cache function result
860 if( ! isset( $cache[$rank_id] ) ){
861 $cache[$rank_id] = array();
862 }
863
864 $cache[$rank_id][$post_status] = $requirements;
865
866 gamipress_set_cache( 'rank_requirements', $cache );
867
868 // Return rank requirements array
869 return $requirements;
870
871 }
872
873 /**
874 * Helper function to retrieve an rank post thumbnail
875 *
876 * @since 1.3.1
877 *
878 * @param integer $post_id The rank's post ID
879 * @param string|array $image_size Image size to use. Accepts any valid image size, or
880 * an array of width and height values in pixels (in that order).
881 * Default 'gamipress-rank'.
882 * @param string $class A custom class to use for the image tag
883 *
884 * @return string Our formatted image tag
885 */
886 function gamipress_get_rank_post_thumbnail( $post_id = 0, $image_size = 'gamipress-rank', $class = 'gamipress-rank-thumbnail' ) {
887
888 // Get our rank thumbnail
889 $image = gamipress_get_the_post_thumbnail( $post_id, $image_size, array( 'class' => $class ) );
890
891 // If we don't have an image...
892 if ( ! $image ) {
893
894 // Grab our rank type's post thumbnail
895 $rank = get_page_by_path( gamipress_get_post_type( $post_id ), OBJECT, 'rank-type' );
896 $image = is_object( $rank ) ? gamipress_get_the_post_thumbnail( $rank->ID, $image_size, array( 'class' => $class ) ) : false;
897
898 // If we still have no image
899 if ( ! $image ) {
900
901 // If we already have an array for image size
902 if ( is_array( $image_size ) ) {
903 // Write our sizes to an associative array
904 $image_sizes['width'] = $image_size[0];
905 $image_sizes['height'] = $image_size[1];
906
907 // Otherwise, attempt to grab the width/height from our specified image size
908 } else {
909 global $_wp_additional_image_sizes;
910 if ( isset( $_wp_additional_image_sizes[$image_size] ) )
911 $image_sizes = $_wp_additional_image_sizes[$image_size];
912 }
913
914 // If we can't get the defined width/height, set our own
915 if ( empty( $image_sizes ) ) {
916 $image_sizes = array(
917 'width' => 100,
918 'height' => 100
919 );
920 }
921
922 // Available filter: 'gamipress_default_rank_post_thumbnail'
923 $default_thumbnail = apply_filters( 'gamipress_default_rank_post_thumbnail', '', $rank, $image_sizes );
924
925 if( ! empty( $default_thumbnail ) ) {
926 $image = '<img src="' . $default_thumbnail . '" width="' . $image_sizes['width'] . '" height="' . $image_sizes['height'] . '" class="' . $class . '">';
927 }
928
929 }
930 }
931
932 // Return our image tag
933 return $image;
934 }
935
936 /**
937 * Get an array of all users who have currently on a given rank
938 *
939 * @since 1.3.1
940 * @updated 1.6.7 Added $args parameter
941 * @updated 1.6.9 Make earner list work on default ranks
942 *
943 * @param int $rank_id The given rank's post ID
944 * @param array $args Array of arguments that modifies the earners list result
945 *
946 * @return array Array of user objects
947 */
948 function gamipress_get_rank_earners( $rank_id = 0, $args = array() ) {
949
950 global $wpdb;
951
952 // Setup the meta_key
953 $rank_type = gamipress_get_post_type( $rank_id );
954
955 $meta = '_gamipress_rank';
956
957 if( ! empty( $rank_type ) ) {
958 $meta = "_gamipress_{$rank_type}_rank";
959 }
960
961 if ( is_multisite() && ! gamipress_is_network_wide_active() ) {
962 $meta = $wpdb->get_blog_prefix() . $meta;
963 }
964
965 // Setup vars
966 $from = "{$wpdb->usermeta} AS u RIGHT JOIN {$wpdb->users} AS usr ON (usr.ID = u.user_id)";
967 $where = "u.meta_key = '{$meta}' AND u.meta_value = '{$rank_id}' ";
968
969 // On multisite, get earners only of the current site
970 if( is_multisite() && ! gamipress_is_network_wide_active() ) {
971 $from .= "RIGHT JOIN {$wpdb->usermeta} AS umcap ON (
972 umcap.user_id = u.user_id
973 AND umcap.meta_key = '" . $wpdb->get_blog_prefix( gamipress_get_original_site_id() ) . "capabilities'
974 ) ";
975 }
976
977
978 // If is lowest priority rank then requires an extra check to get users that doesn't have the rank meta
979 if( gamipress_is_lowest_priority_rank( $rank_id ) ) {
980
981 $where .= "OR NOT EXISTS (
982 SELECT meta.*
983 FROM {$wpdb->usermeta} as meta
984 WHERE meta.meta_key = '{$meta}'
985 AND meta.user_id = u.user_id
986 ) ";
987
988 }
989
990 $group_by = "u.user_id";
991 $order_by = '';
992 $limit = '';
993
994 // Setup default args
995 $defaults = array(
996 'limit' => -1,
997 'orderby' => 'u.user_id',
998 'order' => 'DESC',
999 );
1000
1001 /**
1002 * Filters the earners args
1003 *
1004 * @since 1.6.7
1005 *
1006 * @param array $args Array of given arguments
1007 * @param int $rank_id The given rank's post ID
1008 *
1009 * @return array
1010 */
1011 $args = apply_filters( 'gamipress_get_rank_earners_args', $args, $rank_id );
1012
1013 $args = wp_parse_args( $args, $defaults );
1014
1015 // Setup FROM
1016 if( ! empty( $args['from'] ) ) {
1017 $from .= $args['from'];
1018 }
1019
1020 // Setup WHERE
1021 if( ! empty( $args['where'] ) ) {
1022 $where .= $args['where'];
1023 }
1024
1025 // Setup LIMIT
1026 if( $args['limit'] > 0 ) {
1027 $limit = '0, ' . $args['limit'];
1028 }
1029
1030 // Setup ORDER BY
1031 if( ! empty( $args['orderby'] ) ) {
1032 $order_by = $args['orderby'] . ' ' . $args['order'];
1033 }
1034
1035 $earners = $wpdb->get_col(
1036 "SELECT u.user_id
1037 FROM {$from}
1038 WHERE {$where}
1039 GROUP BY {$group_by} "
1040 . ( ! empty( $order_by ) ? "ORDER BY {$order_by} " : '' )
1041 . ( ! empty( $limit ) ? "LIMIT {$limit} " : '' )
1042 );
1043
1044 // Build an array of wp users based of IDs found
1045 $earned_users = array();
1046
1047 foreach( $earners as $earner_id ) {
1048
1049 if( absint( $earner_id ) === 0 ) {
1050 continue;
1051 }
1052
1053 $earned_users[] = new WP_User( $earner_id );
1054 }
1055
1056 return $earned_users;
1057
1058 }
1059
1060 /**
1061 * Build an unordered list of users who have earned a given rank
1062 *
1063 * @since 1.3.1
1064 * @updated 1.6.7 Added $args parameter
1065 *
1066 * @param int $rank_id The given rank's post ID
1067 * @param array $args Array of arguments that modifies the earners list result
1068 *
1069 * @return string Concatenated markup
1070 */
1071 function gamipress_get_rank_earners_list( $rank_id = 0, $args = array() ) {
1072
1073 /**
1074 * Filters the earners list args
1075 *
1076 * @since 1.6.7
1077 *
1078 * @param array $args Array of given arguments
1079 * @param int $rank_id The given rank's post ID
1080 *
1081 * @return array
1082 */
1083 $args = apply_filters( 'gamipress_get_rank_earners_list_args', $args, $rank_id );
1084
1085 // Grab our users
1086 $earners = gamipress_get_rank_earners( $rank_id, $args );
1087 $output = '';
1088
1089 // Only generate output if we have earners
1090 if ( ! empty( $earners ) ) {
1091
1092 /**
1093 * Filters the rank earners heading text
1094 *
1095 * @since 1.8.6
1096 *
1097 * @param string $heading_text The heading text
1098 * @param int $rank_id The given rank's post ID
1099 * @param array $args Array of given arguments
1100 *
1101 * @return string
1102 */
1103 $heading_text = apply_filters( 'gamipress_rank_earners_heading', __( 'People who have reached this:', 'gamipress' ), $rank_id, $args );
1104
1105 // Loop through each user and build our output
1106 $output .= '<h4>' . $heading_text . '</h4>';
1107
1108 $output .= '<ul class="gamipress-rank-earners-list rank-' . $rank_id . '-earners-list">';
1109
1110 foreach ( $earners as $user ) {
1111
1112 $user_url = get_author_posts_url( $user->ID );
1113
1114 /**
1115 * Filters the rank earner url
1116 *
1117 * @since 1.8.6
1118 *
1119 * @param string $user_url The user URl, by default the get_author_posts_url()
1120 * @param int $user_id The rendered user ID
1121 * @param int $rank_id The given rank's post ID
1122 * @param array $args Array of given arguments
1123 *
1124 * @return string
1125 */
1126 $user_url = apply_filters( 'gamipress_rank_earner_user_url', $user_url, $user->ID, $rank_id, $args );
1127
1128 /**
1129 * Filters the rank earner display
1130 *
1131 * @since 1.8.6
1132 *
1133 * @param string $user_display The user display, by default the user display name
1134 * @param int $user_id The rendered user ID
1135 * @param int $rank_id The given rank's post ID
1136 * @param array $args Array of given arguments
1137 *
1138 * @return string
1139 */
1140 $user_display = apply_filters( 'gamipress_rank_earner_user_display', $user->display_name, $user->ID, $rank_id, $args );
1141
1142 $user_content = '<li>'
1143 . '<a href="' . $user_url . '">'
1144 . get_avatar( $user->ID )
1145 . '<span class="earner-display-name">' . $user_display . '</span>'
1146 . '</a>'
1147 . '</li>';
1148
1149 /**
1150 * Filters the earners list user output
1151 *
1152 * @since 1.0.0
1153 * @updated 1.6.7 Added $rank_id and $args arguments
1154 *
1155 * @param string $user_content User output
1156 * @param int $user_id The rendered user ID
1157 * @param int $rank_id The given rank's post ID
1158 * @param array $args Array of given arguments
1159 *
1160 * @return string
1161 */
1162 $output .= apply_filters( 'gamipress_get_rank_earners_list_user', $user_content, $user->ID, $rank_id, $args );
1163 }
1164
1165 $output .= '</ul>';
1166
1167 }
1168
1169 /**
1170 * Filters the rank earners list output
1171 *
1172 * @since 1.0.0
1173 *
1174 * @param string $output Achievement earners list output
1175 * @param int $rank_id The given rank's post ID
1176 * @param array $args Array of given arguments
1177 * @param array $earners Array of rank earners
1178 *
1179 * @return string
1180 */
1181 return apply_filters( 'gamipress_get_rank_earners_list', $output, $rank_id, $args, $earners );
1182 }
1183
1184 /**
1185 * Return the given rank's priority
1186 *
1187 * @since 1.3.7
1188 *
1189 * @param integer|WP_Post $rank_id The given rank's post ID or rank's post object
1190 *
1191 * @return integer The given rank's priority
1192 */
1193 function gamipress_get_rank_priority( $rank_id = 0 ) {
1194
1195 global $wpdb;
1196
1197 if( gamipress_get_post_field( 'post_status', $rank_id ) === 'auto-draft' ) {
1198
1199 $rank_type = gamipress_get_post_type( $rank_id );
1200
1201 $posts = GamiPress()->db->posts;
1202
1203 // Get higher menu order
1204 $last = $wpdb->get_var( $wpdb->prepare(
1205 "SELECT p.menu_order
1206 FROM {$posts} AS p
1207 WHERE p.post_type = %s
1208 AND p.post_status = %s
1209 ORDER BY menu_order DESC
1210 LIMIT 1",
1211 $rank_type,
1212 'publish'
1213 ) );
1214
1215 return absint( $last ) + 1;
1216 }
1217
1218 return absint( gamipress_get_post_field( 'menu_order', $rank_id ) );
1219
1220 }
1221
1222 /**
1223 * Flush rewrite rules whenever an rank type is published.
1224 *
1225 * @since 1.3.1
1226 *
1227 * @param string $new_status New status.
1228 * @param string $old_status Old status.
1229 * @param object $post Post object.
1230 */
1231 function gamipress_flush_rewrite_on_published_rank( $new_status, $old_status, $post ) {
1232 if ( 'rank-type' === $post->post_type && 'publish' === $new_status && 'publish' !== $old_status ) {
1233 gamipress_flush_rewrite_rules();
1234 }
1235 }
1236 add_action( 'transition_post_status', 'gamipress_flush_rewrite_on_published_rank', 10, 3 );
1237
1238 /**
1239 * Update all dependent data if rank type name has changed.
1240 *
1241 * @since 1.3.1
1242 *
1243 * @param array $data Post data.
1244 * @param array $post_args Post args.
1245 * @return array Updated post data.
1246 */
1247 function gamipress_maybe_update_rank_type( $data = array(), $post_args = array() ) {
1248
1249 // Bail if not is main site, on network wide installs ranks are just available on main site
1250 if( gamipress_is_network_wide_active() && ! is_main_site() ) {
1251 return $data;
1252 }
1253
1254 // Bail if not is a points type
1255 if( $post_args['post_type'] !== 'rank-type') {
1256 return $data;
1257 }
1258
1259 // If user set an empty slug, then generate it
1260 if( empty( $post_args['post_name'] ) ) {
1261 $post_args['post_name'] = wp_unique_post_slug(
1262 sanitize_title( $post_args['post_title'] ),
1263 $post_args['ID'],
1264 $post_args['post_status'],
1265 $post_args['post_type'],
1266 $post_args['post_parent']
1267 );
1268 }
1269
1270 // Sanitize post_name
1271 $post_args['post_name'] = gamipress_sanitize_slug( $post_args['post_name'] );
1272
1273 if ( gamipress_rank_type_changed( $post_args ) ) {
1274
1275 $original_type = gamipress_get_post( $post_args['ID'] )->post_name;
1276 $new_type = $post_args['post_name'];
1277
1278 $data['post_name'] = gamipress_update_rank_types( $original_type, $new_type );
1279
1280 add_filter( 'redirect_post_location', 'gamipress_rank_type_rename_redirect', 99 );
1281
1282 }
1283
1284 return $data;
1285 }
1286 add_filter( 'wp_insert_post_data' , 'gamipress_maybe_update_rank_type' , 99, 2 );
1287
1288 /**
1289 * Check if an rank type name has changed.
1290 *
1291 * @since 1.3.1
1292 *
1293 * @param array $post_args Post args.
1294 * @return bool True if name has changed, otherwise false.
1295 */
1296 function gamipress_rank_type_changed( $post_args = array() ) {
1297
1298 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
1299 return false;
1300 }
1301
1302 $original_post = ( !empty( $post_args['ID'] ) && isset( $post_args['ID'] ) ) ? get_post( $post_args['ID'] ) : null;
1303 $status = false;
1304
1305 if ( is_object( $original_post ) ) {
1306 if (
1307 'rank-type' === $post_args['post_type']
1308 && $original_post->post_status !== 'auto-draft'
1309 && ! empty( $original_post->post_name )
1310 && $original_post->post_name !== $post_args['post_name']
1311 ) {
1312 $status = true;
1313 }
1314 }
1315
1316 return $status;
1317 }
1318
1319 /**
1320 * Replace all instances of one rank type with another.
1321 *
1322 * @since 1.3.1
1323 *
1324 * @param string $original_type Original rank type.
1325 * @param string $new_type New rank type.
1326 * @return string New rank type.
1327 */
1328 function gamipress_update_rank_types( $original_type = '', $new_type = '' ) {
1329
1330 // Sanity check to prevent alterating core posts
1331 if ( empty( $original_type ) || in_array( $original_type, array( 'post', 'page', 'attachment', 'revision', 'nav_menu_item' ) ) ) {
1332 return $new_type;
1333 }
1334
1335 gamipress_update_ranks_rank_types( $original_type, $new_type );
1336 gamipress_update_earned_meta_rank_types( $original_type, $new_type );
1337
1338 /**
1339 * Action triggered when a rank type gets updated (called before flush rewrite rules)
1340 *
1341 * @since 1.5.1
1342 *
1343 * @param string $original_type The original type slug.
1344 * @param string $new_type The new type slug.
1345 */
1346 do_action( 'gamipress_update_rank_type', $original_type, $new_type );
1347
1348 gamipress_flush_rewrite_rules();
1349
1350 return $new_type;
1351
1352 }
1353
1354 /**
1355 * Change all ranks of one type to a new type.
1356 *
1357 * @since 1.3.1
1358 *
1359 * @param string $original_type Original rank type.
1360 * @param string $new_type New rank type.
1361 */
1362 function gamipress_update_ranks_rank_types( $original_type = '', $new_type = '' ) {
1363
1364 $items = get_posts( array(
1365 'posts_per_page' => -1,
1366 'post_status' => 'any',
1367 'post_type' => $original_type,
1368 'fields' => 'id',
1369 'suppress_filters' => false,
1370 ) );
1371
1372 foreach ( $items as $item ) {
1373 set_post_type( $item->ID, $new_type );
1374 }
1375
1376 }
1377
1378 /**
1379 * Change all earned meta from one rank type to another.
1380 *
1381 * @since 1.3.1
1382 *
1383 * @param string $original_type Original rank type.
1384 * @param string $new_type New rank type.
1385 */
1386 function gamipress_update_earned_meta_rank_types( $original_type = '', $new_type = '' ) {
1387
1388 // Setup CT object
1389 $ct_table = ct_setup_table( 'gamipress_user_earnings' );
1390
1391 $ct_table->db->update(
1392 array( 'post_type' => $new_type ),
1393 array( 'post_type' => $original_type )
1394 );
1395
1396 ct_reset_setup_table();
1397
1398 global $wpdb;
1399
1400 $wpdb->get_results( $wpdb->prepare(
1401 "UPDATE {$wpdb->usermeta}
1402 SET meta_key = %s
1403 WHERE meta_key = %s",
1404 "_gamipress_{$new_type}_rank",
1405 "_gamipress_{$original_type}_rank"
1406 ) );
1407
1408 }
1409
1410 /**
1411 * Redirect to include custom rename message.
1412 *
1413 * @since 1.3.1
1414 *
1415 * @param string $location Original URI.
1416 * @return string Updated URI.
1417 */
1418 function gamipress_rank_type_rename_redirect( $location = '' ) {
1419
1420 remove_filter( 'redirect_post_location', __FUNCTION__, 99 );
1421
1422 return add_query_arg( 'message', 99, $location );
1423
1424 }
1425
1426 /**
1427 * Filter the "post updated" messages to include support for rank types.
1428 *
1429 * @since 1.3.1
1430 *
1431 * @param array $messages Array of messages to display.
1432 *
1433 * @return array $messages Compiled list of messages.
1434 */
1435 function gamipress_rank_type_update_messages( $messages ) {
1436
1437 $messages['rank-type'] = array_fill( 1, 10, __( 'Rank Type saved successfully.', 'gamipress' ) );
1438 $messages['rank-type']['99'] = sprintf( __('Rank Type renamed successfully. <p>All ranks of this type, and all active and earned user ranks, have been updated <strong>automatically</strong>.</p> All shortcodes, %s, and URIs that reference the old rank type slug must be updated <strong>manually</strong>.', 'gamipress'), '<a href="' . esc_url( admin_url( 'widgets.php' ) ) . '">' . __( 'widgets', 'gamipress' ) . '</a>' );
1439
1440 return $messages;
1441
1442 }
1443 add_filter( 'post_updated_messages', 'gamipress_rank_type_update_messages' );