PluginProbe
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI / 8.0.5
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI v8.0.5
8.0.5 8.0.4 8.0.3 8.0.1 8.0.2 8.0.0 7.9.9.7 7.9.9.6 7.9.9.5 7.9.9.4 7.9.9.3 7.9.9.2 7.9.9.1 7.9.9 7.9.8 7.9.7 7.9.6 7.9.5 7.9.4 7.9.3 7.9.2 7.9.1 7.9.0 7.8.9 7.8.8 All 47 releases
← All changes | includes/triggers.php +1683 -0 7.9.0 → 8.0.5 View file →
@@ -1,0 +1,1683 @@
1 +<?php
2 +/**
3 + * Activity Triggers, used for triggering achievement earning
4 + *
5 + * @package GamiPress\Triggers
6 + * @author GamiPress <[email protected]>, Ruben Garcia <[email protected]>
7 + * @since 1.0.0
8 + */
9 +// Exit if accessed directly
10 +if( !defined( 'ABSPATH' ) ) exit;
11 +
12 +/**
13 + * 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 +}