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 / triggers.php

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

1,684 lines 58.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Activity Triggers, used for triggering achievement earning
4 *
5 * @package GamiPress\Triggers
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 * GamiPress activity triggers
14 *
15 * @since 1.0.0
16 *
17 * @return array Array of all activity triggers
18 */
19 function gamipress_get_activity_triggers() {
20
21 GamiPress()->activity_triggers = apply_filters( 'gamipress_activity_triggers',
22 array(
23 // WordPress
24 __( 'WordPress', 'gamipress' ) => array(
25 'gamipress_register' => __( 'Register to website', 'gamipress' ),
26 'gamipress_login' => __( 'Log in to website', 'gamipress' ),
27 'gamipress_new_comment' => __( 'Comment on a post', 'gamipress' ),
28 'gamipress_specific_new_comment' => __( 'Comment on a specific post', 'gamipress' ),
29 'gamipress_new_comment_post_type' => __( 'Comment on a post of a type', 'gamipress' ),
30 'gamipress_user_post_comment' => __( 'Get a comment on a post', 'gamipress' ),
31 'gamipress_user_specific_post_comment' => __( 'Get a comment on a specific post', 'gamipress' ),
32 'gamipress_user_post_comment_post_type' => __( 'Get a comment on a post of a type', 'gamipress' ),
33 'gamipress_spam_comment' => __( 'Get a comment marked as spam', 'gamipress' ),
34 'gamipress_specific_spam_comment' => __( 'Get a comment of a specific post marked as spam', 'gamipress' ),
35 'gamipress_spam_comment_post_type' => __( 'Get a comment on a post of a type marked as spam', 'gamipress' ),
36 'gamipress_publish_post' => __( 'Publish a new post', 'gamipress' ),
37 'gamipress_delete_post' => __( 'Delete a post', 'gamipress' ),
38 'gamipress_publish_page' => __( 'Publish a new page', 'gamipress' ),
39 'gamipress_delete_page' => __( 'Delete a page', 'gamipress' ),
40 'gamipress_publish_post_type' => __( 'Publish a new post of a type', 'gamipress' ),
41 'gamipress_delete_post_type' => __( 'Delete a post of a type', 'gamipress' ),
42 'gamipress_add_role' => __( 'Get added to any role', 'gamipress' ),
43 'gamipress_add_specific_role' => __( 'Get added to specific role', 'gamipress' ),
44 'gamipress_set_role' => __( 'Get assigned to any role', 'gamipress' ),
45 'gamipress_set_specific_role' => __( 'Get assigned to specific role', 'gamipress' ),
46 'gamipress_remove_role' => __( 'Get removed from any role', 'gamipress' ),
47 'gamipress_remove_specific_role' => __( 'Get removed from a specific role', 'gamipress' ),
48 'gamipress_update_user_meta_any_value' => __( 'Get user meta updated with any value', 'gamipress' ),
49 'gamipress_update_user_meta_specific_value' => __( 'Get user meta updated with a value', 'gamipress' ),
50 'gamipress_update_post_meta_any_value' => __( 'Post meta updated with any value', 'gamipress' ),
51 'gamipress_update_post_meta_specific_value' => __( 'Post meta updated with a value', 'gamipress' ),
52 ),
53 // Site Interactions
54 __( 'Site Interactions', 'gamipress' ) => array(
55 'gamipress_site_visit' => __( 'Daily visit the website', 'gamipress' ),
56 'gamipress_post_visit' => __( 'Daily visit any post', 'gamipress' ),
57 'gamipress_specific_post_visit' => __( 'Daily visit a specific post', 'gamipress' ),
58 'gamipress_post_type_visit' => __( 'Daily visit a post of a type', 'gamipress' ),
59 'gamipress_user_post_visit' => __( 'Get visits on any post', 'gamipress' ),
60 'gamipress_user_specific_post_visit' => __( 'Get visits on a specific post', 'gamipress' ),
61 'gamipress_user_post_type_visit' => __( 'Get visits on a post of a type', 'gamipress' ),
62 ),
63 // GamiPress
64 'GamiPress' => array(
65 'specific-achievement' => __( 'Unlock a specific achievement', 'gamipress' ),
66 'any-achievement' => __( 'Unlock any achievement of type', 'gamipress' ),
67 'all-achievements' => __( 'Unlock all Achievements of type', 'gamipress' ),
68 'revoke-specific-achievement' => __( 'Get a specific achievement revoked', 'gamipress' ),
69 'revoke-any-achievement' => __( 'Get any achievement of type revoked', 'gamipress' ),
70 'earn-points' => __( 'Earn an amount of points', 'gamipress' ),
71 'points-balance' => __( 'Reach a points balance', 'gamipress' ),
72 'gamipress_expend_points' => __( 'Expend an amount of points', 'gamipress' ),
73 'earn-rank' => __( 'Reach a rank', 'gamipress' ),
74 'revoke-rank' => __( 'Get a rank revoked', 'gamipress' ),
75 ),
76 )
77 );
78
79 return GamiPress()->activity_triggers;
80
81 }
82
83 /**
84 * GamiPress specific activity triggers
85 *
86 * @since 1.0.0
87 *
88 * @return array Array of all specific activity triggers
89 */
90 function gamipress_get_specific_activity_triggers() {
91
92 // Get all public post types which means they are visitable
93 $public_post_types = get_post_types( array( 'public' => true ) );
94
95 // Remove attachment from public post types
96 if( isset( $public_post_types['attachment'] ) ) {
97 unset( $public_post_types['attachment'] );
98 }
99
100 // Remove keys
101 $public_post_types = array_values( $public_post_types );
102
103 // Get all post types with comments support
104 $comments_post_types = get_post_types_by_support( 'comments' );
105
106 // Remove attachment from post types with comments support
107 if( $index = array_search( 'attachment', $comments_post_types ) ) {
108 unset( $comments_post_types[$index] );
109 }
110
111 // Remove keys
112 $comments_post_types = array_values( $comments_post_types );
113
114 return apply_filters( 'gamipress_specific_activity_triggers', array(
115 'gamipress_specific_new_comment' => $comments_post_types,
116 'gamipress_user_specific_post_comment' => $comments_post_types,
117 'gamipress_specific_spam_comment' => $comments_post_types,
118 'gamipress_specific_post_visit' => $public_post_types,
119 'gamipress_user_specific_post_visit' => $public_post_types,
120 ) );
121
122 }
123
124 /**
125 * GamiPress triggers for the points and points type selector
126 *
127 * @since 2.2.6
128 *
129 * @return array Array of all points triggers
130 */
131 function gamipress_get_points_triggers() {
132
133 return apply_filters( 'gamipress_points_triggers', array(
134 'earn-points',
135 'points-balance',
136 'gamipress_expend_points',
137 ) );
138
139 }
140
141 /**
142 * GamiPress triggers for the achievement type selector
143 *
144 * @since 2.2.6
145 *
146 * @return array Array of all achievement type triggers
147 */
148 function gamipress_get_achievement_type_triggers() {
149
150 return apply_filters( 'gamipress_achievement_type_triggers', array(
151 'specific-achievement',
152 'any-achievement',
153 'all-achievements',
154 'revoke-specific-achievement',
155 'revoke-any-achievement'
156 ) );
157
158 }
159
160 /**
161 * GamiPress triggers for the rank type selector
162 *
163 * @since 2.2.6
164 *
165 * @return array Array of all rank type triggers
166 */
167 function gamipress_get_rank_type_triggers() {
168
169 return apply_filters( 'gamipress_rank_type_triggers', array(
170 'earn-rank',
171 'revoke-rank',
172 ) );
173
174 }
175
176 /**
177 * GamiPress triggers for the post type selector
178 *
179 * @since 2.2.6
180 *
181 * @return array Array of all post type triggers
182 */
183 function gamipress_get_post_type_triggers() {
184
185 return apply_filters( 'gamipress_post_type_triggers', array(
186 'gamipress_new_comment_post_type',
187 'gamipress_user_post_comment_post_type',
188 'gamipress_spam_comment_post_type',
189 'gamipress_spam_comment_post_type',
190 'gamipress_publish_post_type',
191 'gamipress_delete_post_type',
192 'gamipress_post_type_visit',
193 'gamipress_user_post_type_visit',
194 ) );
195
196 }
197
198 /**
199 * GamiPress triggers for the user role selector
200 *
201 * @since 2.2.6
202 *
203 * @return array Array of all user role triggers
204 */
205 function gamipress_get_user_role_triggers() {
206
207 return apply_filters( 'gamipress_user_role_triggers', array(
208 'gamipress_add_specific_role',
209 'gamipress_set_specific_role',
210 'gamipress_remove_specific_role',
211 ) );
212
213 }
214
215 /**
216 * GamiPress specific activity triggers query args (used on requirements UI and on ajax get posts)
217 *
218 * @since 1.3.6
219 *
220 * @param array|string $query_args
221 * @param string $activity_trigger
222 *
223 * @return array|string
224 */
225 function gamipress_get_specific_activity_triggers_query_args( $query_args, $activity_trigger ) {
226
227 /**
228 * Specific activity triggers query args (used on requirements UI and on ajax get posts)
229 *
230 * Note: Use $_REQUEST for all given parameters
231 * @see gamipress_ajax_get_posts()
232 *
233 * @since 1.3.6
234 *
235 * @param array|string $query_args
236 * @param string $activity_trigger
237 *
238 * @return array|string
239 */
240 return apply_filters( 'gamipress_specific_activity_triggers_query_args', $query_args, $activity_trigger );
241
242 }
243
244 /**
245 * Helper function for returning an activity trigger label
246 *
247 * @since 1.0.0
248 *
249 * @param string $activity_trigger
250 *
251 * @return string
252 */
253 function gamipress_get_activity_trigger_label( $activity_trigger ) {
254
255 $label = '';
256 $activity_triggers = gamipress_get_activity_triggers();
257
258 foreach( $activity_triggers as $group => $group_triggers ) {
259 if( isset( $group_triggers[$activity_trigger] ) ) {
260 $label = $group_triggers[$activity_trigger];
261 }
262 }
263
264 if( gamipress_starts_with( $activity_trigger, 'gamipress_unlock_' ) ) {
265
266 // Check if trigger is for unlocking ANY and ALL posts of an achievement type
267 $achievement_type = $activity_trigger;
268 $achievement_type = str_replace( 'gamipress_unlock_all_', '', $achievement_type );
269 $achievement_type = str_replace( 'gamipress_unlock_', '', $achievement_type );
270 $data = gamipress_get_achievement_type( $achievement_type );
271
272 if ( $data ) {
273 if( gamipress_starts_with( $activity_trigger, 'gamipress_unlock_all_' ) )
274 $label = sprintf( __( 'Unlocked all %s', 'gamipress' ), $data['plural_name'] );
275 else
276 $label = sprintf( __( 'Unlocked a %s', 'gamipress' ), $data['singular_name'] );
277 }
278
279 } else if( gamipress_starts_with( $activity_trigger, 'gamipress_revoke_' ) ) {
280
281 // Check if trigger is for revoking ANY posts of an achievement type
282 $achievement_type = $activity_trigger;
283 $achievement_type = str_replace( 'gamipress_revoke_', '', $achievement_type );
284 $data = gamipress_get_achievement_type( $achievement_type );
285
286 if ( $data ) {
287 $label = sprintf( __( 'Get a %s revoked', 'gamipress' ), $data['singular_name'] );
288 }
289
290 }
291
292 /**
293 * Available filter to override an activity trigger label
294 *
295 * @since 1.9.9
296 *
297 * @param string $label
298 * @param string $activity_trigger
299 *
300 * @return string
301 */
302 return apply_filters( 'gamipress_get_activity_trigger_label', $label, $activity_trigger );
303
304 }
305
306 /**
307 * Helper function for returning a specific activity trigger label
308 *
309 * @since 1.0.0
310 *
311 * @param string $activity_trigger
312 *
313 * @return string
314 */
315 function gamipress_get_specific_activity_trigger_label( $activity_trigger ) {
316
317 $specific_activity_trigger_labels = apply_filters( 'gamipress_specific_activity_trigger_label', array(
318 'gamipress_specific_new_comment' => __( 'Comment on %s', 'gamipress' ),
319 'gamipress_user_specific_post_comment' => __( 'Get a comment on %s', 'gamipress' ),
320 'gamipress_specific_spam_comment' => __( 'Get a comment on %s marked as spam', 'gamipress' ),
321 'gamipress_specific_post_visit' => __( 'Visit %s', 'gamipress' ),
322 'gamipress_user_specific_post_visit' => __( '%s gets visited', 'gamipress' ),
323 ) );
324
325 if( isset( $specific_activity_trigger_labels[$activity_trigger] ) ) {
326 return $specific_activity_trigger_labels[$activity_trigger];
327 }
328
329 return '';
330
331 }
332
333 /**
334 * Helper function to get the title of a given specific ID for a specific activity trigger
335 *
336 * @since 1.4.0
337 * @updated 1.4.8 Added $site_id parameter
338 *
339 * @param integer $specific_id The specific ID
340 * @param string $trigger_type The requirement trigger type
341 * @param integer $site_id The site ID
342 *
343 * @return string The specific title
344 */
345 function gamipress_get_specific_activity_trigger_post_title( $specific_id, $trigger_type, $site_id ) {
346
347 $override = apply_filters( 'gamipress_specific_activity_trigger_post_title', 'no_override', $specific_id, $trigger_type, $site_id );
348
349 if( $override !== 'no_override' ) {
350 return $override;
351 }
352
353 if( gamipress_is_network_wide_active() && $site_id !== get_current_blog_id() ) {
354
355 // Switch to the given site to get the post title from this site
356 switch_to_blog( $site_id );
357
358 $post_title = get_post_field( 'post_title', $specific_id );
359
360 // Restore the current blog
361 restore_current_blog();
362
363 return $post_title;
364
365 }
366
367 return get_post_field( 'post_title', $specific_id );
368
369 }
370
371 /**
372 * Helper function to determine if a given specific ID is public to get his permalink
373 *
374 * @since 1.5.0
375 *
376 * @param integer $specific_id The specific ID
377 * @param string $trigger_type The requirement trigger type
378 * @param integer $site_id The site ID
379 *
380 * @return bool
381 */
382 function gamipress_is_specific_activity_trigger_post_type_public( $specific_id, $trigger_type, $site_id ) {
383
384 $override = apply_filters( 'gamipress_specific_activity_trigger_is_post_type_public', 'no_override', $specific_id, $trigger_type, $site_id );
385
386 if( $override !== 'no_override' ) {
387 return (bool) $override;
388 }
389
390 // Get all public registered post types
391 $public_post_types = get_post_types( array( 'public' => true ) );
392
393 if( gamipress_is_network_wide_active() && $site_id !== get_current_blog_id() ) {
394
395 // Switch to the given site to get the post title from this site
396 switch_to_blog( $site_id );
397
398 $post_type = get_post_field( 'post_type', $specific_id );
399
400 // Restore the current blog
401 restore_current_blog();
402
403 } else {
404 $post_type = get_post_field( 'post_type', $specific_id );
405 }
406
407 return in_array( $post_type, $public_post_types );
408
409 }
410
411 /**
412 * Helper function to get the permalink of a given specific ID for a specific activity trigger
413 *
414 * @since 1.5.0
415 *
416 * @param integer $specific_id The specific ID
417 * @param string $trigger_type The requirement trigger type
418 * @param integer $site_id The site ID
419 *
420 * @return false|string The specific permalink
421 */
422 function gamipress_get_specific_activity_trigger_permalink( $specific_id, $trigger_type, $site_id ) {
423
424 $override = apply_filters( 'gamipress_specific_activity_trigger_permalink', 'no_override', $specific_id, $trigger_type, $site_id );
425
426 if( $override !== 'no_override' ) {
427 return $override;
428 }
429
430 if( ! gamipress_is_specific_activity_trigger_post_type_public( $specific_id, $trigger_type, $site_id ) ) {
431 return false;
432 }
433
434 if( absint( $specific_id ) === 0 ) {
435 return false;
436 }
437
438 if( gamipress_is_network_wide_active() && $site_id !== get_current_blog_id() ) {
439
440 // Switch to the given site to get the post title from this site
441 switch_to_blog( $site_id );
442
443 $permalink = get_permalink( $specific_id );
444
445 // Restore the current blog
446 restore_current_blog();
447
448 return $permalink;
449
450 }
451
452 return get_permalink( $specific_id );
453
454 }
455
456 /**
457 * Load activity triggers to hook them
458 *
459 * @since 1.0.0
460 */
461 function gamipress_hook_activity_triggers() {
462
463 // GamiPress requires to load activity triggers early to hook them
464 // To prevent any errors and since in this function labels are not required
465 // Lets to prevent load text domains and avoid warnings
466 // Next, gamipress_load_activity_triggers will load them again with their labels at the init hook
467
468 // Prevent to load text domains here
469 add_filter( 'lang_dir_for_domain', 'gamipress_prevent_load_textdoamin' );
470
471 // Grab our activity triggers
472 $activity_triggers = gamipress_get_activity_triggers();
473 $excluded_to_load = gamipress_get_activity_triggers_excluded_to_load();
474
475 // Restore text domains load
476 remove_filter( 'lang_dir_for_domain', 'gamipress_prevent_load_textdoamin' );
477
478 // Loop through each achievement type and add triggers for unlocking/revoking them
479 foreach ( gamipress_get_achievement_types() as $achievement_type => $data ) {
480 // Add trigger for unlocking/revoking ANY and ALL posts for each achievement type
481 $activity_triggers['GamiPress']['gamipress_unlock_' . $achievement_type] = ''; // Label not required here
482 $activity_triggers['GamiPress']['gamipress_unlock_all_' . $achievement_type] = ''; // Label not required here
483 $activity_triggers['GamiPress']['gamipress_revoke_' . $achievement_type] = ''; // Label not required here
484 }
485
486 // Loop through each trigger and add our trigger event to the hook
487 foreach ( $activity_triggers as $group => $group_triggers ) {
488 foreach( $group_triggers as $trigger => $label ) {
489 // Hook if trigger is not excluded to be loaded
490 if( ! in_array( $trigger, $excluded_to_load ) ) {
491 add_action( $trigger, 'gamipress_trigger_event', 10, 20 );
492 }
493 }
494 }
495
496 }
497 add_action( 'gamipress_init', 'gamipress_hook_activity_triggers' );
498
499 // Just a return false function to hook it on text domains
500 function gamipress_prevent_load_textdoamin() {
501 return false;
502 }
503
504 /**
505 * Load activity triggers text domains
506 *
507 * @since 1.0.0
508 */
509 function gamipress_load_activity_triggers() {
510
511 gamipress_get_activity_triggers();
512
513 }
514 add_action( 'init', 'gamipress_load_activity_triggers' );
515
516 /**
517 * Get activity triggers excluded to be loaded automatically from gamipress_load_activity_triggers()
518 *
519 * @since 1.0.0
520 *
521 * @return array
522 */
523 function gamipress_get_activity_triggers_excluded_to_load() {
524
525 return apply_filters( 'gamipress_activity_triggers_excluded_to_load', array(
526 'gamipress_login',
527 'gamipress_register'
528 ) );
529
530 }
531
532 /**
533 * Get activity triggers excluded from activity time limits
534 *
535 * @since 1.5.9
536 *
537 * @return array
538 */
539 function gamipress_get_activity_triggers_excluded_from_activity_limit() {
540
541 return apply_filters( 'gamipress_activity_triggers_excluded_from_activity_limit', array(
542 'gamipress_register',
543 'earn-points',
544 'points-balance',
545 'earn-rank',
546 'revoke-rank'
547 ) );
548
549 }
550
551 /**
552 * Handle each of our activity triggers
553 *
554 * If method is called directly, pass an array of arguments with next items:
555 * array(
556 * 'event' => 'gamipress_login',
557 * 'user_id' => 1,
558 * 'specific_id' => 100 // Just if is an specific trigger
559 * )
560 *
561 * @since 1.0.0
562 * @updated 1.4.3 Added the ability to be called directly
563 *
564 * @return mixed Returns an array will all achievements awarded or false if none has been awarded
565 */
566 function gamipress_trigger_event() {
567
568 // Get the current site
569 $site_id = get_current_blog_id();
570
571 $args = func_get_args();
572
573 // Check if method has been called directly
574 if( isset( $args[0] ) && is_array( $args[0] ) && isset( $args[0]['event'] ) ) {
575 $args = $args[0];
576 }
577
578 // Grab our current trigger
579 $trigger = ( isset( $args['event'] ) ? $args['event'] : current_filter() );
580
581 // gamipress_unlock_all_{type}, gamipress_unlock_{type} and gamipress_revoke_{type} are excluded from this check
582 if( ! ( gamipress_starts_with( $trigger, 'gamipress_unlock_' ) || gamipress_starts_with( $trigger, 'gamipress_revoke_' ) ) ) {
583
584 /**
585 * Filter to decide if GamiPress should log all events triggered (filter in replacement to the option "log_all_events")
586 *
587 * @since 2.5.3
588 *
589 * @param bool $log_all_events
590 *
591 * @return bool
592 */
593 $log_all_events = apply_filters( 'gamipress_log_all_events', false );
594
595 // Check if log all events is enabled
596 if( ! $log_all_events ) {
597
598 // If not achievements listening it, then return
599 if( ! gamipress_trigger_has_listeners( $trigger, $site_id, $args ) ) {
600 return false;
601 }
602
603 }
604
605 }
606
607 // Grab the user ID
608 $user_id = ( isset( $args['user_id'] ) ? $args['user_id'] : gamipress_trigger_get_user_id( $trigger, $args ) );
609 $user_data = get_user_by( 'id', $user_id );
610
611 // Sanity check, if we don't have a user object, bail here
612 if ( ! is_object( $user_data ) ) {
613 return false;
614 }
615
616 // If the user doesn't satisfy the trigger requirements, bail here
617 if ( ! apply_filters( 'gamipress_user_deserves_trigger', true, $user_id, $trigger, $site_id, $args ) ) {
618 return false;
619 }
620
621 // Update hook count for this user
622 gamipress_update_user_trigger_count( $user_id, $trigger, $site_id, $args );
623
624 // Register event triggered in logs
625 gamipress_log_event_triggered( $user_id, $trigger, $site_id, $args );
626
627 // Check if any achievements are earned based on this trigger event
628 $triggered_achievements = gamipress_get_triggered_requirements( $user_id, $trigger, $site_id, $args );
629
630 $awarded_achievements = array();
631
632 foreach ( $triggered_achievements as $achievement ) {
633
634 $award_result = gamipress_maybe_award_achievement_to_user( $achievement->ID, $user_id, $trigger, $site_id, $args );
635
636 if( $award_result === true ) {
637 $awarded_achievements[] = $achievement->ID;
638 }
639 }
640
641 return ( count( $awarded_achievements ) ? $awarded_achievements : false );
642
643 }
644
645 /**
646 * Gets the event arg parameter
647 *
648 * @since 1.8.8
649 *
650 * @param array $args Event args
651 * @param string $key The args key to get
652 * @param int $index The index key to fallback
653 *
654 * @return mixed
655 */
656 function gamipress_get_event_arg( $args = array(), $key = '', $index = 0 ) {
657 return ( isset( $args[$key] ) ? $args[$key] : ( isset( $args[$index] ) ? $args[$index] : '' ) );
658 }
659
660 /**
661 * Logs the event triggered ono gamipress_trigger_event() function
662 *
663 * @since 1.6.2
664 *
665 * @param int $user_id
666 * @param string $trigger
667 * @param int $site_id
668 * @param array $args
669 */
670 function gamipress_log_event_triggered( $user_id, $trigger, $site_id, $args ) {
671
672 // Log meta data
673 $log_meta = array(
674 'pattern' => apply_filters( 'gamipress_trigger_log_pattern', __( '{user} triggered {trigger_type} (x{count})', 'gamipress' ) ),
675 'count' => gamipress_get_user_trigger_count( $user_id, $trigger, 0, $site_id, $args ),
676 //'trigger_type' => $trigger, // Removed since 1.4.7
677 );
678
679 // On multisite, search for site logs
680 if( is_multisite() && gamipress_is_network_wide_active() ) {
681 $log_meta['site_id'] = $site_id;
682 }
683
684 // If is specific trigger then try to get the attached id
685 if( in_array( $trigger, array_keys( gamipress_get_specific_activity_triggers() ) ) ) {
686
687 $specific_id = ( isset( $args['specific_id'] ) ? $args['specific_id'] : gamipress_specific_trigger_get_id( $trigger, $args ) );
688
689 // If there is a specific id, then add it to the log meta data
690 if( $specific_id !== 0 ) {
691 $log_meta['achievement_post'] = $specific_id;
692 $log_meta['achievement_post_site_id'] = $site_id;
693 }
694
695 }
696
697 /**
698 * Available filter to insert custom meta data
699 *
700 * @since 1.6.2
701 *
702 * @param array $log_meta
703 * @param int $user_id
704 * @param string $trigger
705 * @param int $site_id
706 * @param array $args
707 *
708 * @return array
709 */
710 $log_meta = apply_filters( 'gamipress_log_event_trigger_meta_data', $log_meta, $user_id, $trigger, $site_id, $args );
711
712 // Mark the count in the log entry
713 gamipress_insert_log( 'event_trigger', $user_id, 'private', $trigger, $log_meta );
714
715 }
716
717 /**
718 * Extended meta data for event trigger logging
719 *
720 * @since 1.1.8
721 *
722 * @param array $log_meta
723 * @param integer $user_id
724 * @param string $trigger
725 * @param integer $site_id
726 * @param array $args
727 *
728 * @return array
729 */
730 function gamipress_log_event_trigger_extended_meta_data( $log_meta, $user_id, $trigger, $site_id, $args ) {
731
732 switch ( $trigger ) {
733 case 'gamipress_publish_post':
734 case 'gamipress_publish_page':
735 case 'gamipress_delete_post':
736 case 'gamipress_delete_page':
737 case 'gamipress_post_visit':
738 case 'gamipress_specific_post_visit':
739 // Add the published/deleted/visited post ID
740 $log_meta['post_id'] = gamipress_get_event_arg( $args, 'post_id', 0 );
741 break;
742 case 'gamipress_publish_post_type':
743 case 'gamipress_delete_post_type':
744 case 'gamipress_post_type_visit':
745 case 'gamipress_user_post_type_visit':
746 // Add the post ID and type
747 $log_meta['post_id'] = gamipress_get_event_arg( $args, 'post_id', 0 );
748 $log_meta['post_type'] = gamipress_get_event_arg( $args, 'post_type', 2 );
749 break;
750 case 'gamipress_user_post_visit':
751 case 'gamipress_user_specific_post_visit':
752 // Add the visited post ID
753 $log_meta['post_id'] = gamipress_get_event_arg( $args, 'post_id', 0 );
754 $log_meta['visitor_id'] = gamipress_get_event_arg( $args, 'user_id', 2 );
755 break;
756 case 'gamipress_new_comment':
757 case 'gamipress_specific_new_comment':
758 case 'gamipress_user_post_comment':
759 case 'gamipress_user_specific_post_comment':
760 case 'gamipress_spam_comment':
761 case 'gamipress_specific_spam_comment':
762 // Add the comment ID and post commented ID
763 $log_meta['comment_id'] = gamipress_get_event_arg( $args, 'comment_id', 0 );
764 $log_meta['comment_post_id'] = gamipress_get_event_arg( $args, 'post_id', 2 );
765 break;
766 case 'gamipress_new_comment_post_type':
767 case 'gamipress_user_post_comment_post_type':
768 case 'gamipress_spam_comment_post_type':
769 // Add the comment ID, post commented ID and type
770 $log_meta['comment_id'] = gamipress_get_event_arg( $args, 'comment_id', 0 );
771 $log_meta['comment_post_id'] = gamipress_get_event_arg( $args, 'post_id', 2 );
772 $log_meta['comment_post_type'] = gamipress_get_event_arg( $args, 'post_type', 3 );
773 break;
774 case 'gamipress_expend_points':
775 // Add the post ID, the amount of points and the points type
776 $log_meta['post_id'] = gamipress_get_event_arg( $args, 'post_id', 0 );
777 $log_meta['points'] = gamipress_get_event_arg( $args, 'points', 2 );
778 $log_meta['points_type'] = gamipress_get_event_arg( $args, 'points_type', 3 );
779 break;
780 case gamipress_starts_with( $trigger, 'gamipress_unlock_' ):
781 if( ! gamipress_starts_with( $trigger, 'gamipress_unlock_all_' ) ) {
782 $log_meta['post_id'] = gamipress_get_event_arg( $args, 'post_id', 1 );
783 }
784 break;
785 case gamipress_starts_with( $trigger, 'gamipress_revoke_' ):
786 $log_meta['post_id'] = gamipress_get_event_arg( $args, 'post_id', 1 );
787 break;
788 case 'gamipress_login':
789 case 'gamipress_register':
790 case 'gamipress_site_visit':
791 default:
792 // Nothing to store
793 break;
794 }
795
796 return $log_meta;
797 }
798 add_filter( 'gamipress_log_event_trigger_meta_data', 'gamipress_log_event_trigger_extended_meta_data', 10, 5 );
799
800 /**
801 * Extended meta data to filter the logs count
802 *
803 * @since 2.0.5
804 *
805 * @param array $log_meta The meta data to filter the logs count
806 * @param int $user_id The given user's ID
807 * @param string $trigger The given trigger we're checking
808 * @param int $since The since timestamp where retrieve the logs
809 * @param int $site_id The desired Site ID to check
810 * @param array $args The triggered args or requirement object
811 *
812 * @return array The meta data to filter the logs count
813 */
814 function gamipress_get_user_trigger_count_log_extended_meta( $log_meta, $user_id, $trigger, $since, $site_id, $args ) {
815
816 switch ( $trigger ) {
817 case 'gamipress_publish_post_type':
818 case 'gamipress_delete_post_type':
819 case 'gamipress_post_type_visit':
820 case 'gamipress_user_post_type_visit':
821 // Filter by the post type
822 $log_meta['post_type'] = gamipress_get_event_arg( $args, 'post_type', 2 );
823
824 // $args could be a requirement object
825 if( isset( $args['post_type_required'] ) ) {
826 $log_meta['post_type'] = $args['post_type_required'];
827 }
828 break;
829 case 'gamipress_new_comment_post_type':
830 case 'gamipress_user_post_comment_post_type':
831 case 'gamipress_spam_comment_post_type':
832 // Filter by the post type
833 $log_meta['comment_post_type'] = gamipress_get_event_arg( $args, 'post_type', 3 );
834
835 // $args could be a requirement object
836 if( isset( $args['post_type_required'] ) ) {
837 $log_meta['comment_post_type'] = $args['post_type_required'];
838 }
839 break;
840 case 'specific-achievement':
841 // Filter by the post ID
842 $log_meta['post_id'] = gamipress_get_event_arg( $args, 'post_id', 1 );
843
844 if( isset( $args['achievement_post'] ) && absint( $log_meta['achievement_post'] ) === 0 ) {
845 $log_meta['post_id'] = $args['achievement_post'];
846 }
847
848 // Update the trigger type
849 $log_meta['trigger_type'] = 'gamipress_unlock_' . gamipress_get_post_type( $log_meta['post_id'] );
850 break;
851 case 'revoke-specific-achievement':
852 // Filter by the post ID
853 $log_meta['post_id'] = gamipress_get_event_arg( $args, 'post_id', 1 );
854
855 if( isset( $args['achievement_post'] ) && absint( $log_meta['achievement_post'] ) === 0 ) {
856 $log_meta['post_id'] = $args['achievement_post'];
857 }
858
859 // Update the trigger type
860 $log_meta['trigger_type'] = 'gamipress_revoke_' . gamipress_get_post_type( $log_meta['post_id'] );
861 break;
862 }
863
864 return $log_meta;
865
866 }
867 add_filter( 'gamipress_get_user_trigger_count_log_meta', 'gamipress_get_user_trigger_count_log_extended_meta', 10, 6 );
868
869 /**
870 * Extra filter to check duplicated activity
871 *
872 * @since 1.1.8
873 *
874 * @param bool $return
875 * @param integer $user_id
876 * @param string $trigger
877 * @param integer $site_id
878 * @param array $args
879 *
880 * @return bool True if user deserves trigger, else false
881 */
882 function gamipress_trigger_duplicity_check( $return, $user_id, $trigger, $site_id, $args ) {
883
884 $log_meta = array(
885 'type' => 'event_trigger',
886 'trigger_type' => $trigger,
887 );
888
889 // On multisite, search for site logs
890 if( is_multisite() && gamipress_is_network_wide_active() ) {
891 $log_meta['site_id'] = $site_id;
892 }
893
894 switch ( $trigger ) {
895 case 'gamipress_publish_post':
896 case 'gamipress_publish_page':
897 case 'gamipress_publish_post_type':
898 case 'gamipress_delete_post':
899 case 'gamipress_delete_page':
900 case 'gamipress_delete_post_type':
901 // User can not publish/delete same post more times, so check it
902 $log_meta['post_id'] = gamipress_get_event_arg( $args, 'post_id', 0 );
903 $return = (bool) ( gamipress_get_user_last_log( $user_id, $log_meta ) === false );
904 break;
905 case 'gamipress_user_post_visit':
906 case 'gamipress_user_specific_post_visit':
907 // Prevent award author for receive repeated visits
908 $log_meta['post_id'] = $args[0];
909 $log_meta['visitor_id'] = $args[2];
910
911 // Guests are allowed to trigger the visit unlimited times
912 if( $log_meta['visitor_id'] !== 0 ) {
913 $return = (bool) ( gamipress_get_user_last_log( $user_id, $log_meta ) === false );
914 }
915 break;
916 case 'gamipress_new_comment':
917 case 'gamipress_specific_new_comment':
918 case 'gamipress_new_comment_post_type':
919 case 'gamipress_user_post_comment':
920 case 'gamipress_user_specific_post_comment':
921 case 'gamipress_user_post_comment_post_type':
922 case 'gamipress_spam_comment':
923 case 'gamipress_specific_spam_comment':
924 case 'gamipress_spam_comment_post_type':
925 // User can not publish same comment more times, so check it
926 $log_meta['comment_id'] = $args[0];
927 $return = (bool) ( gamipress_get_user_last_log( $user_id, $log_meta ) === false );
928 break;
929 }
930
931 return apply_filters( 'gamipress_trigger_duplicity_check', $return, $user_id, $trigger, $site_id, $args );
932
933 }
934 add_filter( 'gamipress_user_deserves_trigger', 'gamipress_trigger_duplicity_check', 10, 5 );
935
936 /**
937 * Get user for a given trigger action.
938 *
939 * @since 1.0.0
940 *
941 * @param string $trigger Trigger name.
942 * @param array $args Passed trigger args.
943 *
944 * @return integer User ID.
945 */
946 function gamipress_trigger_get_user_id( $trigger = '', $args = array() ) {
947
948 // If gamipress_trigger_event() has called directly, then get user ID from args
949 if( isset( $args['event'] ) && isset( $args['user_id'] ) ) {
950 return $args['user_id'];
951 }
952
953 switch ( $trigger ) {
954 case 'gamipress_login':
955 case 'gamipress_register':
956 case 'gamipress_site_visit':
957 case 'gamipress_add_role':
958 case 'gamipress_add_specific_role':
959 case 'gamipress_set_role':
960 case 'gamipress_set_specific_role':
961 case 'gamipress_remove_role':
962 case 'gamipress_remove_specific_role':
963 case gamipress_starts_with( $trigger, 'gamipress_unlock_' ):
964 case gamipress_starts_with( $trigger, 'gamipress_revoke_' ):
965 case 'gamipress_update_user_meta_any_value':
966 case 'gamipress_update_user_meta_specific_value':
967 case 'gamipress_update_post_meta_any_value':
968 case 'gamipress_update_post_meta_specific_value':
969 $user_id = $args[0];
970 break;
971 case 'gamipress_publish_post':
972 case 'gamipress_publish_page':
973 case 'gamipress_publish_post_type':
974 case 'gamipress_delete_post':
975 case 'gamipress_delete_page':
976 case 'gamipress_delete_post_type':
977 case 'gamipress_new_comment':
978 case 'gamipress_specific_new_comment':
979 case 'gamipress_new_comment_post_type':
980 case 'gamipress_user_post_comment':
981 case 'gamipress_user_specific_post_comment':
982 case 'gamipress_user_post_comment_post_type':
983 case 'gamipress_spam_comment':
984 case 'gamipress_specific_spam_comment':
985 case 'gamipress_spam_comment_post_type':
986 case 'gamipress_post_visit':
987 case 'gamipress_specific_post_visit':
988 case 'gamipress_post_type_visit':
989 case 'gamipress_user_post_visit':
990 case 'gamipress_user_specific_post_visit':
991 case 'gamipress_user_post_type_visit':
992 case 'gamipress_expend_points':
993 $user_id = $args[1];
994 break;
995 default :
996 $user_id = get_current_user_id();
997 break;
998 }
999
1000 return apply_filters( 'gamipress_trigger_get_user_id', $user_id, $trigger, $args );
1001 }
1002
1003 /**
1004 * Get the id for a given specific trigger action.
1005 *
1006 * @since 1.0.8
1007 *
1008 * @param string $trigger Trigger name.
1009 * @param array $args Passed trigger args.
1010 *
1011 * @return integer Specific ID.
1012 */
1013 function gamipress_specific_trigger_get_id( $trigger = '', $args = array() ) {
1014
1015 // If gamipress_trigger_event() has called directly, then get user ID from args
1016 if( isset( $args['event'] ) && isset( $args['specific_id'] ) ) {
1017 return $args['specific_id'];
1018 }
1019
1020 switch ( $trigger ) {
1021 case 'gamipress_specific_new_comment':
1022 case 'gamipress_user_specific_post_comment':
1023 case 'gamipress_specific_spam_comment':
1024 $specific_id = $args[2];
1025 break;
1026 case 'gamipress_specific_post_visit':
1027 case 'gamipress_user_specific_post_visit':
1028 default :
1029 $specific_id = $args[0];
1030 break;
1031 }
1032
1033 return absint( apply_filters( 'gamipress_specific_trigger_get_id', $specific_id, $trigger, $args ) );
1034 }
1035
1036 /**
1037 * Check if trigger has listeners
1038 *
1039 * @since 1.0.8
1040 *
1041 * @param string $trigger
1042 * @param integer $site_id
1043 * @param array $args
1044 *
1045 * @return bool
1046 */
1047 function gamipress_trigger_has_listeners( $trigger, $site_id, $args ) {
1048
1049 global $wpdb;
1050
1051 $posts = GamiPress()->db->posts;
1052 $postmeta = GamiPress()->db->postmeta;
1053
1054 $triggers_count = gamipress_get_triggers_listeners_count();
1055 $listeners_count = ( isset( $triggers_count[$trigger] ) ? $triggers_count[$trigger] : 0 );
1056
1057 // If is specific trigger then try to get the attached id
1058 if( in_array( $trigger, array_keys( gamipress_get_specific_activity_triggers() ) ) && isset( $triggers_count[$trigger] ) ) {
1059
1060 // Reset the listeners count since is a specific trigger
1061 $listeners_count = 0;
1062 $specific_id = 0;
1063
1064 // If isset this key it means $args is a requirement object
1065 if( isset( $args['achievement_post'] ) ) {
1066 $specific_id = absint( $args['achievement_post'] );
1067 } else if( ! empty( $args ) ) {
1068 $specific_id = gamipress_specific_trigger_get_id( $trigger, $args );
1069 }
1070
1071 // If there is a specific id, then try to find the count
1072 if( $specific_id !== 0 ) {
1073
1074 $cache = gamipress_get_cache( "{$trigger}_{$specific_id}_listeners_count", false );
1075
1076 // If result already cached, return it
1077 if( $cache !== false ) {
1078 $listeners_count = absint( $cache );
1079 } else {
1080 $listeners_count = $wpdb->get_var( $wpdb->prepare(
1081 "SELECT COUNT(*)
1082 FROM {$posts} AS p
1083 LEFT JOIN {$postmeta} AS pm ON ( p.ID = pm.post_id AND pm.meta_key = '_gamipress_trigger_type' )
1084 LEFT JOIN {$postmeta} AS pm2 ON ( p.ID = pm2.post_id AND pm2.meta_key = '_gamipress_achievement_post' )
1085 WHERE p.post_status = 'publish'
1086 AND p.post_type IN ( '" . implode( "', '", gamipress_get_requirement_types_slugs() ) . "' )
1087 AND pm.meta_value = %s
1088 AND pm2.meta_value = %s",
1089 $trigger,
1090 $specific_id
1091 ) );
1092
1093 // Cache listeners count
1094 gamipress_save_cache( "{$trigger}_{$specific_id}_listeners_count", $listeners_count );
1095 }
1096
1097 }
1098
1099 }
1100
1101 $has_listeners = ( absint( $listeners_count ) > 0 );
1102
1103 /**
1104 * Filter to override if trigger has listeners
1105 *
1106 * @since 1.0.8
1107 *
1108 * @param bool $has_listeners
1109 * @param string $trigger
1110 * @param integer $site_id
1111 * @param array $args
1112 *
1113 * @return bool
1114 */
1115 return apply_filters( 'gamipress_trigger_has_listeners', $has_listeners, $trigger, $site_id, $args );
1116 }
1117
1118 /**
1119 * Get all triggers listeners count
1120 *
1121 * @since 1.8.0
1122 *
1123 * @return array
1124 */
1125 function gamipress_get_triggers_listeners_count() {
1126
1127 $cache = gamipress_get_cache( 'gamipress_triggers_listeners_count', false );
1128
1129 // If result already cached, return it
1130 if( is_array( $cache ) ) {
1131 return $cache;
1132 }
1133
1134 global $wpdb;
1135
1136 $posts = GamiPress()->db->posts;
1137 $postmeta = GamiPress()->db->postmeta;
1138
1139 // Get an array with each trigger count
1140 $results = $wpdb->get_results(
1141 "SELECT pm.meta_value AS 'trigger', COUNT(*) AS 'count'
1142 FROM {$postmeta} AS pm
1143 LEFT JOIN {$posts} AS p ON ( pm.post_id = p.ID )
1144 WHERE p.post_status = 'publish'
1145 AND p.post_type IN ( '" . implode( "', '", gamipress_get_requirement_types_slugs() ) . "' )
1146 AND pm.meta_key = '_gamipress_trigger_type'
1147 AND pm.meta_value != ''
1148 GROUP BY pm.meta_value"
1149 );
1150
1151 $listeners_count = array();
1152
1153 // Turn the results array into a more accessible associative array
1154 foreach( $results as $result )
1155 $listeners_count[$result->trigger] = absint( $result->count );
1156
1157 // Cache listeners count
1158 gamipress_save_cache( "gamipress_triggers_listeners_count", $listeners_count );
1159
1160 /**
1161 * Filter to override if triggers listeners count
1162 *
1163 * @since 1.8.0
1164 *
1165 * @param array $listeners_count
1166 *
1167 * @return array
1168 */
1169 return apply_filters( 'gamipress_get_triggers_listeners_count', $listeners_count );
1170
1171 }
1172
1173 /**
1174 * Return triggered requirements by a specific trigger
1175 *
1176 * @since 1.6.1
1177 * @updated 1.7.9 Improvement on requirements with specific triggers querying them by the specific ID to reduce the amount of triggered requirements
1178 * @updated 1.7.9 Added $user_id, $site_id and $args parameters
1179 *
1180 * @param int $user_id The User ID
1181 * @param string $trigger The trigger type
1182 * @param int $site_id The site ID where event has been triggered
1183 * @param array $args The event arguments
1184 *
1185 * @return array
1186 */
1187 function gamipress_get_triggered_requirements( $user_id, $trigger, $site_id, $args ) {
1188
1189 $triggered_requirements = array();
1190 $proceed = true;
1191 $cache_key = "{$trigger}_triggered_requirements";
1192 $query_args = array(
1193 'fields' => 'ids',
1194 'post_status' => 'publish',
1195 'meta_query' => array(
1196 '_gamipress_trigger_type' => $trigger,
1197 ),
1198 );
1199
1200 // If is specific trigger then try to get the attached id
1201 if( in_array( $trigger, array_keys( gamipress_get_specific_activity_triggers() ) ) ) {
1202
1203 $specific_id = 0;
1204
1205 // If isset this key it means $args is a requirement object
1206 if( isset( $args['achievement_post'] ) ) {
1207 $specific_id = absint( $args['achievement_post'] );
1208 } else if( ! empty( $args ) ) {
1209 $specific_id = gamipress_specific_trigger_get_id( $trigger, $args );
1210 }
1211
1212 // If there is a specific id, then try to find the count
1213 if( $specific_id !== 0 ) {
1214
1215 $cache_key = "{$trigger}_{$specific_id}_triggered_requirements";
1216
1217 // Add the achievement post ID
1218 $query_args['meta_query']['_gamipress_achievement_post'] = $specific_id;
1219
1220 } else {
1221 // Set proceed to false since the assigned post is not correctly assigned
1222 $proceed = false;
1223 }
1224
1225 } else if( gamipress_starts_with( $trigger, 'gamipress_unlock_' ) ) {
1226 // Check if trigger is for unlocking ANY and ALL posts of an achievement type
1227
1228 $event_trigger = $trigger;
1229
1230 // Events for unlock an achievement of type or all requires to change the trigger
1231 if( gamipress_starts_with( $trigger, 'gamipress_unlock_all_' ) ) {
1232 // Replace "gamipress_unlock_all_{achievement-type}" to "all-achievements"
1233 $event_trigger = 'all-achievements';
1234 } else if( gamipress_starts_with( $trigger, 'gamipress_unlock_' ) ) {
1235 // Replace "gamipress_unlock_{achievement-type}" to "any-achievement"
1236 $event_trigger = 'any-achievement';
1237 }
1238
1239 // Update the trigger with the correct trigger
1240 $query_args['meta_query']['_gamipress_trigger_type'] = $event_trigger;
1241
1242 // Get the achievement type
1243 $achievement_type = str_replace( 'gamipress_unlock_all_', '', $trigger );
1244 $achievement_type = str_replace( 'gamipress_unlock_', '', $achievement_type );
1245
1246 // Add the achievement type
1247 $query_args['meta_query']['_gamipress_achievement_type'] = $achievement_type;
1248
1249 } else if( gamipress_starts_with( $trigger, 'gamipress_revoke_' ) ) {
1250 // Check if trigger is for revoking ANY posts of an achievement type
1251
1252 $event_trigger = $trigger;
1253
1254 // Get the achievement type
1255 $achievement_type = str_replace( 'gamipress_revoke_', '', $trigger );
1256
1257 if( in_array( $achievement_type, gamipress_get_achievement_types_slugs() ) ) {
1258 // Replace "gamipress_revoke_{achievement-type}" to "revoke-any-achievement"
1259 $event_trigger = 'revoke-any-achievement';
1260
1261 // Add the achievement type
1262 $query_args['meta_query']['_gamipress_achievement_type'] = $achievement_type;
1263 }
1264
1265 // Update the trigger with the correct trigger
1266 $query_args['meta_query']['_gamipress_trigger_type'] = $event_trigger;
1267
1268 }
1269
1270 /**
1271 * Filter to modify triggered requirements cache key
1272 *
1273 * @since 1.8.8
1274 *
1275 * @param bool $proceed
1276 * @param int $user_id The User ID
1277 * @param string $trigger The trigger type
1278 * @param int $site_id The site ID where event has been triggered
1279 * @param array $args The event arguments
1280 *
1281 * @return bool
1282 */
1283 $proceed = apply_filters( 'gamipress_get_triggered_requirements_proceed', $proceed, $user_id, $trigger, $site_id, $args );
1284
1285 /**
1286 * Filter to modify triggered requirements cache key
1287 *
1288 * @since 1.8.8
1289 *
1290 * @param string $cache_key The cache key to store cached results
1291 * @param int $user_id The User ID
1292 * @param string $trigger The trigger type
1293 * @param int $site_id The site ID where event has been triggered
1294 * @param array $args The event arguments
1295 *
1296 * @return string
1297 */
1298 $cache_key = apply_filters( 'gamipress_get_triggered_requirements_cache_key', $cache_key, $user_id, $trigger, $site_id, $args );
1299
1300 /**
1301 * Filter to modify triggered requirements query args
1302 *
1303 * @since 1.8.8
1304 *
1305 * @see gamipress_query_requirements()
1306 *
1307 * @param array $query_args The query args to query triggered requirements
1308 * @param int $user_id The User ID
1309 * @param string $trigger The trigger type
1310 * @param int $site_id The site ID where event has been triggered
1311 * @param array $args The event arguments
1312 *
1313 * @return array
1314 */
1315 $query_args = apply_filters( 'gamipress_get_triggered_requirements_query_args', $query_args, $user_id, $trigger, $site_id, $args );
1316
1317 if( $proceed ) {
1318
1319 $cache = gamipress_get_cache( $cache_key, false );
1320
1321 // If result already cached, return it
1322 if( $cache !== false && is_array( $cache ) ) {
1323 $triggered_requirements = $cache;
1324 } else {
1325 // Get requirements with this query args
1326 $triggered_requirements = gamipress_query_requirements( $query_args );
1327
1328 // Cache function result
1329 gamipress_save_cache( $cache_key, $triggered_requirements );
1330
1331 }
1332
1333 }
1334
1335 /**
1336 * Filter to modify triggered requirements by a specific trigger
1337 *
1338 * @since 1.6.1
1339 * @updated 1.7.9 Added $user_id, $site_id and $args parameters
1340 *
1341 * @param array $triggered_requirements
1342 * @param int $user_id The User ID
1343 * @param string $trigger The trigger type
1344 * @param int $site_id The site ID where event has been triggered
1345 * @param array $args The event arguments
1346 *
1347 * @return array
1348 */
1349 $triggered_requirements = apply_filters( 'gamipress_get_triggered_requirements', $triggered_requirements, $user_id, $trigger, $site_id, $args );
1350
1351 return $triggered_requirements;
1352
1353 }
1354
1355 /**
1356 * Sort triggered requirements by rank priority in order to send them ordered to the awards engine
1357 *
1358 * @since 1.6.2
1359 *
1360 * @param array $triggered_requirements
1361 * @param integer $user_id
1362 * @param string $trigger
1363 * @param integer $site_id
1364 * @param array $args
1365 *
1366 * @return array
1367 */
1368 function gamipress_sort_triggered_rank_requirements( $triggered_requirements, $user_id = 0, $trigger = '', $site_id = 0, $args = array() ) {
1369 $reordered_requirements = array();
1370
1371 // Loop all triggered requirements
1372 foreach( $triggered_requirements as $index => $requirement ) {
1373
1374 // If is rank requirement, add it to the reordered requirements array
1375 if( gamipress_get_post_type( $requirement->ID ) === 'rank-requirement' ) {
1376
1377 // Get the requirement's rank ID
1378 $rank_id = absint( gamipress_get_post_field( 'post_parent', $requirement->ID ) );
1379
1380 if( $rank_id !== 0 ) {
1381
1382 // Get the rank's priority and add the requirement to reordered requirements array
1383 $priority = gamipress_get_rank_priority( $rank_id );
1384
1385 if( ! isset( $reordered_requirements[$priority] ) )
1386 $reordered_requirements[$priority] = array();
1387
1388 $reordered_requirements[$priority][] = $requirement;
1389
1390 // Remove requirement from triggered requirements (will be added after again)
1391 unset( $triggered_requirements[$index] );
1392
1393 }
1394
1395 }
1396
1397 }
1398
1399 // To order the requirements by priority
1400 ksort( $reordered_requirements );
1401
1402 // Append rank requirements reordered to the triggered requirements array
1403 foreach( $reordered_requirements as $requirements ) {
1404 $triggered_requirements = array_merge( $triggered_requirements, $requirements );
1405 }
1406
1407 return $triggered_requirements;
1408
1409 }
1410 add_filter( 'gamipress_get_triggered_requirements', 'gamipress_sort_triggered_rank_requirements', 10, 5 );
1411
1412 /**
1413 * Delete cache of a specific trigger
1414 *
1415 * @since 1.6.1
1416 * @updated 1.7.9 Added support to the brand new triggered requirements cache
1417 *
1418 * @param string $trigger
1419 *
1420 * @return bool
1421 */
1422 function gamipress_delete_trigger_cache( $trigger ) {
1423
1424 global $wpdb;
1425
1426 // Bail if empty trigger
1427 if( empty( $trigger ) ) {
1428 return false;
1429 }
1430
1431 // Listeners count cache varies if is specific trigger
1432 if( in_array( $trigger, array_keys( gamipress_get_specific_activity_triggers() ) ) ) {
1433
1434 // Cache prefix and suffix
1435 $trigger = sanitize_text_field( $trigger );
1436 $prefix = "gamipress_cache_{$trigger}_";
1437 $triggered_suffix = '_triggered_requirements';
1438 $listeners_suffix = '_listeners_count';
1439
1440 // Delete listeners count cache for specific trigger
1441
1442 if( gamipress_is_network_wide_active() ) {
1443 // Multi site installs
1444 $wpdb->query( "DELETE FROM {$wpdb->sitemeta} WHERE meta_key LIKE '{$prefix}%' AND ( meta_key LIKE '%{$triggered_suffix}' OR meta_key LIKE '%{$listeners_suffix}' )");
1445 } else {
1446 // Single site installs
1447 $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '{$prefix}%' AND ( option_name LIKE '%{$triggered_suffix}' OR option_name LIKE '%{$listeners_suffix}' )" );
1448 }
1449
1450 } else if ( $trigger === 'any-achievement' || $trigger === 'all-achievements' || $trigger === 'revoke-any-achievement' ) {
1451
1452 // Cache prefix and suffix
1453 $prefix = 'gamipress_cache_gamipress_unlock_';
1454 $triggered_suffix = '_triggered_requirements';
1455 $listeners_suffix = '_listeners_count';
1456
1457 if( $trigger === 'revoke-any-achievement' ) {
1458 $prefix = 'gamipress_cache_gamipress_revoke_';
1459 }
1460
1461 // Delete listeners count cache for unlock all/specific achievement
1462 if( gamipress_is_network_wide_active() ) {
1463 // Multi site installs
1464 $wpdb->query( "DELETE FROM {$wpdb->sitemeta} WHERE meta_key LIKE '{$prefix}%' AND ( meta_key LIKE '%{$triggered_suffix}' OR meta_key LIKE '%{$listeners_suffix}' )");
1465 } else {
1466 // Single site installs
1467 $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '{$prefix}%' AND ( option_name LIKE '%{$triggered_suffix}' OR option_name LIKE '%{$listeners_suffix}' )" );
1468 }
1469
1470 } else {
1471
1472 // Delete triggered requirements cache
1473 gamipress_delete_cache( "{$trigger}_triggered_requirements" );
1474
1475 // Delete listeners count cache for not specific trigger
1476 gamipress_delete_cache( "{$trigger}_listeners_count" );
1477 }
1478
1479 // Delete all listeners count cache
1480 gamipress_delete_cache( 'gamipress_triggers_listeners_count' );
1481
1482 return true;
1483
1484 }
1485
1486 /**
1487 * Wrapper function for returning a user's array of sprung triggers
1488 *
1489 * @since 1.0.0
1490 *
1491 * @param integer $user_id The given user's ID
1492 * @param integer $site_id The desired Site ID to check
1493 *
1494 * @return array An array of the triggers a user has triggered
1495 */
1496 function gamipress_get_user_triggers( $user_id = 0, $site_id = 0 ) {
1497
1498 // Grab all of the user's triggers
1499 $user_triggers = ( $exists = gamipress_get_user_meta( $user_id, '_gamipress_triggered_triggers' ) ) ? $exists : array( $site_id => array() );
1500
1501 // Use current site ID if site ID is not set, AND not explicitly set to false
1502 if ( ! $site_id && false !== $site_id ) {
1503 $site_id = get_current_blog_id();
1504 }
1505
1506 // Return only the triggers that are relevant to the provided $site_id
1507 if ( $site_id && isset( $user_triggers[ $site_id ] ) ) {
1508 return $user_triggers[ $site_id ];
1509
1510 // Otherwise, return the full array of all triggers across all sites
1511 } else {
1512 return $user_triggers;
1513 }
1514 }
1515
1516 /**
1517 * Get the count of the number of times a user has triggered a particular trigger
1518 *
1519 * @since 1.0.0
1520 * @updated 1.6.2 Added use of gamipress_get_user_triggers() function when $since is 0
1521 * @updated 1.6.3 Revert back 1.6.2 and full function refactoring to make use of gamipress_get_user_log_count() function and added new filters
1522 *
1523 * @param int $user_id The given user's ID
1524 * @param string $trigger The given trigger we're checking
1525 * @param int $since The since timestamp where retrieve the logs
1526 * @param int $site_id The desired Site ID to check
1527 * @param array $args The triggered args or requirement object
1528 *
1529 * @return int The total number of times a user has triggered the trigger
1530 */
1531 function gamipress_get_user_trigger_count( $user_id, $trigger, $since = 0, $site_id = 0, $args = array() ) {
1532
1533 // Set to current site id
1534 if ( ! $site_id ) {
1535 $site_id = get_current_blog_id();
1536 }
1537
1538 // Setup the meta data to filter the logs count
1539 $log_meta = array(
1540 'type' => 'event_trigger',
1541 'trigger_type' => $trigger,
1542 );
1543
1544 // If is specific trigger then try to get the attached id
1545 if( in_array( $trigger, array_keys( gamipress_get_specific_activity_triggers() ) ) ) {
1546
1547 $specific_id = 0;
1548
1549 // If isset this key it means $args is a requirement object
1550 if( isset( $args['achievement_post'] ) ) {
1551 $specific_id = absint( $args['achievement_post'] );
1552 } else if( ! empty( $args ) ) {
1553 $specific_id = gamipress_specific_trigger_get_id( $trigger, $args );
1554 }
1555
1556 // If there is a specific id, then try to find the count
1557 if( $specific_id !== 0 ) {
1558 $log_meta['achievement_post'] = $specific_id;
1559 }
1560
1561 }
1562
1563 /**
1564 * Filter to override the meta data to filter the logs count
1565 *
1566 * @since 1.6.3
1567 *
1568 * @param array $log_meta The meta data to filter the logs count
1569 * @param int $user_id The given user's ID
1570 * @param string $trigger The given trigger we're checking
1571 * @param int $since The since timestamp where retrieve the logs
1572 * @param int $site_id The desired Site ID to check
1573 * @param array $args The triggered args or requirement object
1574 *
1575 * @return array The meta data to filter the logs count
1576 */
1577 $log_meta = apply_filters( 'gamipress_get_user_trigger_count_log_meta', $log_meta, $user_id, $trigger, $since, $site_id, $args );
1578
1579 // Get the trigger count
1580 $trigger_count = gamipress_get_user_log_count( absint( $user_id ), $log_meta, $since );
1581
1582 /**
1583 * Filter to override the number of times a user has triggered a particular trigger
1584 *
1585 * @since 1.6.3
1586 *
1587 * @param int $trigger_count The total number of times a user has triggered the trigger
1588 * @param int $user_id The given user's ID
1589 * @param string $trigger The given trigger we're checking
1590 * @param int $since The since timestamp where retrieve the logs
1591 * @param int $site_id The desired Site ID to check
1592 * @param array $args The triggered args or requirement object
1593 *
1594 * @return int The total number of times a user has triggered the trigger
1595 */
1596 $trigger_count = apply_filters( 'gamipress_get_user_trigger_count', absint( $trigger_count ), $user_id, $trigger, $since, $site_id, $args );
1597
1598 // Return the current count for the given trigger
1599 return absint( $trigger_count );
1600
1601 }
1602
1603 /**
1604 * Update the user's trigger count for a given trigger by 1
1605 *
1606 * @since 1.0.0
1607 *
1608 * @param integer $user_id The given user's ID
1609 * @param string $trigger The trigger we're updating
1610 * @param integer $site_id The desired Site ID to update
1611 * @param array $args The triggered args
1612 *
1613 * @return integer The updated trigger count
1614 */
1615 function gamipress_update_user_trigger_count( $user_id, $trigger, $site_id = 0, $args = array() ) {
1616
1617 // Set to current site id
1618 if ( ! $site_id ) {
1619 $site_id = get_current_blog_id();
1620 }
1621
1622 // Get the user triggered triggers
1623 $user_triggers = gamipress_get_user_triggers( $user_id, $site_id );
1624
1625 // Check to ensure is an array
1626 if ( !is_array( $user_triggers ) )
1627 return;
1628
1629 if( isset( $user_triggers[$site_id][$trigger] ) ) {
1630 // If already have this count, just retrieve it
1631 $trigger_count = absint( $user_triggers[$site_id][$trigger] );
1632 } else {
1633 // Grab the current count directly from the database
1634 $trigger_count = absint( gamipress_get_user_trigger_count( $user_id, $trigger, 0, $site_id, $args ) );
1635 }
1636
1637 // Increase the current count by 1
1638 $trigger_count += (int) apply_filters( 'gamipress_update_user_trigger_count', 1, $user_id, $trigger, $site_id, $args );
1639
1640 // Update the triggers array with the new count
1641 $user_triggers[$site_id][$trigger] = $trigger_count;
1642 gamipress_update_user_meta( $user_id, '_gamipress_triggered_triggers', $user_triggers );
1643
1644 // Send back our trigger count for other purposes
1645 return $trigger_count;
1646
1647 }
1648
1649 /**
1650 * Reset a user's trigger count for a given trigger to 0 or reset ALL triggers
1651 *
1652 * @since 1.0.0
1653 *
1654 * @param integer $user_id The given user's ID
1655 * @param string $trigger The trigger we're updating (or "all" to dump all triggers)
1656 * @param integer $site_id The desired Site ID to update (or "all" to dump across all sites)
1657 */
1658 function gamipress_reset_user_trigger_count( $user_id, $trigger, $site_id = 0 ) {
1659
1660 // Set to current site id
1661 if ( ! $site_id )
1662 $site_id = get_current_blog_id();
1663
1664 // Grab the user's current triggers
1665 $user_triggers = gamipress_get_user_triggers( $user_id, false );
1666
1667 // If we're deleteing all triggers...
1668 if ( 'all' == $trigger ) {
1669 // For all sites
1670 if ( 'all' == $site_id )
1671 $user_triggers = array();
1672 // For a specific site
1673 else
1674 $user_triggers[$site_id] = array();
1675 // Otherwise, reset the specific trigger back to zero
1676 } else {
1677 $user_triggers[$site_id][$trigger] = 0;
1678 }
1679
1680 // Finally, update our user meta
1681 gamipress_update_user_meta( $user_id, '_gamipress_triggered_triggers', $user_triggers );
1682
1683 }
1684