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/filters.php +2324 -0 7.9.9.4 → 8.0.5 View file →
@@ -1,0 +1,2324 @@
1 +<?php
2 +/**
3 + * Filters
4 + *
5 + * @package GamiPress\Filters
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 + * Add filters to remove stuff from our singular pages and add back in how we want it
14 + *
15 + * @since 1.0.0
16 + */
17 +function gamipress_do_single_filters() {
18 + // Check we're in the right place
19 + if ( gamipress_is_single_achievement() || gamipress_is_single_rank() ) {
20 + // Filter out the post title
21 + // add_filter( 'the_title', 'gamipress_remove_to_reformat_entries_title', 10, 2 );
22 +
23 + // and filter out the post image
24 + add_filter( 'post_thumbnail_html', 'gamipress_remove_to_reformat_entries_thumbnail', 10, 2 );
25 + }
26 +}
27 +add_action( 'wp_enqueue_scripts', 'gamipress_do_single_filters' );
28 +
29 +/**
30 + * Filter out the post title/post image and add back (later) how we want it
31 + *
32 + * @since 1.0.0
33 + *
34 + * @param string $html The page content prior to filtering
35 + * @param int $post_id The post ID.
36 + *
37 + * @return string The page content after being filtered
38 + */
39 +function gamipress_remove_to_reformat_entries_title( $html = '', $post_id = 0 ) {
40 +
41 + global $gamipress_template_args;
42 +
43 + // Remove, but only on the main loop!
44 + if ( ( gamipress_is_single_achievement( $post_id ) || gamipress_is_single_rank( $post_id ) ) // Ensure that is an achievement or a rank
45 + && empty( $GLOBALS['gamipress_reformat_title'] ) // Ensure to pass it only one time
46 + && ! is_array( $gamipress_template_args ) // Prevents to pass this check on GamiPress shortcodes
47 + ) {
48 + // Now that we're where we want to be, tell the filters to stop removing
49 + $GLOBALS['gamipress_reformat_title'] = true;
50 + return '';
51 + }
52 +
53 + // Nothing to see here... move along
54 + return $html;
55 +}
56 +
57 +/**
58 + * Filter out the post title/post image and add back (later) how we want it
59 + *
60 + * @since 1.0.0
61 + *
62 + * @param string $html The page content prior to filtering
63 + * @param int $post_id The post ID.
64 + *
65 + * @return string The page content after being filtered
66 + */
67 +function gamipress_remove_to_reformat_entries_thumbnail( $html = '', $post_id = 0 ) {
68 +
69 + global $gamipress_template_args;
70 +
71 + // Remove, but only on the main loop!
72 + if ( ( gamipress_is_single_achievement( $post_id ) || gamipress_is_single_rank( $post_id ) ) // Ensure that is an achievement or a rank
73 + && empty( $GLOBALS['gamipress_reformat_thumbnail'] ) // Ensure to pass it only one time
74 + && ! is_array( $gamipress_template_args ) // Prevents to pass this check on GamiPress shortcodes
75 + ) {
76 + // Now that we're where we want to be, tell the filters to stop removing
77 + $GLOBALS['gamipress_reformat_thumbnail'] = true;
78 + return '';
79 + }
80 +
81 + // Nothing to see here... move along
82 + return $html;
83 +}
84 +
85 +/**
86 + * Filter achievement content to add our removed content back
87 + *
88 + * @since 1.0.0
89 + *
90 + * @param string $content The page content
91 + *
92 + * @return string The page content after reformat
93 + */
94 +function gamipress_reformat_entries( $content ) {
95 +
96 + if ( gamipress_is_single_achievement( get_the_ID() ) ) {
97 +
98 + // Filter content, but only is a single achievement!
99 + return gamipress_apply_single_template( $content, 'single-achievement' );
100 +
101 + } else if ( gamipress_is_single_rank( get_the_ID() ) ) {
102 +
103 + // Filter content, but only is a single rank!
104 + return gamipress_apply_single_template( $content, 'single-rank' );
105 + }
106 +
107 + return $content;
108 +}
109 +add_filter( 'the_content', 'gamipress_reformat_entries' );
110 +
111 +/**
112 + * Apply the given single template
113 + *
114 + * @since 1.3.1
115 + *
116 + * @param string $content
117 + * @param string $single_template
118 + *
119 + * @return string
120 + */
121 +function gamipress_apply_single_template( $content, $single_template = '' ) {
122 +
123 + global $gamipress_template_args;
124 +
125 + // Now that we're where we want to be, tell the filters to stop removing
126 + $GLOBALS['gamipress_reformat_content'] = true;
127 +
128 + // Initialize GamiPress template args global
129 + $gamipress_template_args = array();
130 +
131 + // Get the original post content (to use as achievement description)
132 + $gamipress_template_args['original_content'] = $content;
133 +
134 + // Set the configured layout
135 + $gamipress_template_args['layout'] = gamipress_get_post_meta( get_the_ID(), '_gamipress_layout' );
136 +
137 + // If not layout defined, fallback to left layout
138 + if( empty( $gamipress_template_args['layout'] ) ) {
139 + $gamipress_template_args['layout'] = 'left';
140 + }
141 +
142 + // Set the configured alignment
143 + $gamipress_template_args['align'] = gamipress_get_post_meta( get_the_ID(), '_gamipress_align' );
144 +
145 + // If not alignment defined, fallback to none alignment
146 + if( empty( $gamipress_template_args['align'] ) ) {
147 + $gamipress_template_args['align'] = 'none';
148 + }
149 +
150 + /**
151 + * Single template arguments
152 + *
153 + * @since 7.6.5
154 + *
155 + * @param array $gamipress_template_args
156 + * @param string $single_template
157 + */
158 + $gamipress_template_args = apply_filters( 'gamipress_single_template_args', $gamipress_template_args, $single_template );
159 +
160 + ob_start();
161 +
162 + // Try to load single-{template}-{post_type}.php, if not exists load single-{template}.php
163 + gamipress_get_template_part( $single_template, gamipress_get_post_type( get_the_ID() ) );
164 +
165 + $new_content = ob_get_clean();
166 +
167 + // Ok, we're done reformatting
168 + $GLOBALS['gamipress_reformat_content'] = false;
169 +
170 + return $new_content;
171 +
172 +}
173 +
174 +/**
175 + * Helper function tests that we're in the main loop
176 + *
177 + * @since 1.3.1
178 + *
179 + * @param bool|integer $id The page id
180 + *
181 + * @return boolean A boolean determining if the function is in the main loop
182 + */
183 +function gamipress_is_single_achievement( $id = false ) {
184 +
185 + $slugs = gamipress_get_achievement_types_slugs();
186 +
187 + // only run our filters on the achievement singular page
188 + if ( is_admin() || empty( $slugs ) || ! is_singular( $slugs ) )
189 + return false;
190 + // w/o id, we're only checking template context
191 + if ( ! $id )
192 + return true;
193 +
194 + // Checks several variables to be sure we're in the main loop (and won't effect things like post pagination titles)
195 + return ( ( $GLOBALS['post']->ID == $id ) && in_the_loop() && empty( $GLOBALS['gamipress_reformat_content'] ) );
196 +
197 +}
198 +
199 +/**
200 + * Generate HTML markup for an points type's points awards
201 + *
202 + * @since 1.0.0
203 + *
204 + * @param array $points_awards An points type's points awards
205 + * @param int $user_id The given user's ID
206 + * @param array $template_args The given template args
207 + *
208 + * @return string The markup for our list
209 + */
210 +function gamipress_get_points_awards_for_points_types_list_markup( $points_awards = array(), $user_id = 0, $template_args = array() ) {
211 +
212 + // If we don't have any points awards, or our points awards aren't an array, return nothing
213 + if ( ! $points_awards || ! is_array( $points_awards ) ) {
214 + return null;
215 + }
216 +
217 + $count = count( $points_awards );
218 +
219 + // If we have no points awards, return nothing
220 + if ( ! $count ) {
221 + return null;
222 + }
223 +
224 + // Grab the current user's ID if none was specifed
225 + if ( ! $user_id ) {
226 + $user_id = get_current_user_id();
227 + }
228 +
229 + $a = wp_parse_args( $template_args, gamipress_points_types_shortcode_defaults() );
230 +
231 + // Setup our variables
232 + $output = '';
233 +
234 + if( $a['heading'] === 'yes' ) {
235 +
236 + $points_type = gamipress_get_points_award_points_type( $points_awards[0]->ID );
237 +
238 + if( $points_type ) {
239 + $plural_name = gamipress_get_post_meta( '_gamipress_plural_name', $points_type->ID );
240 +
241 + if( ! $plural_name )
242 + $plural_name = $points_type->post_title;
243 +
244 + $points_awards_heading = sprintf( '%1$d %2$s %3$s', $count, $plural_name, _n( 'Award', 'Awards', $count, 'gamipress' ) ); // 2 Credits Awards
245 + } else {
246 + $points_awards_heading = sprintf( '%1$d %2$s', $count, _n( 'Award', 'Awards', $count, 'gamipress' ) ); // 2 Awards
247 + }
248 +
249 + /**
250 + * Filters the points award heading text
251 + *
252 + * @since 1.0.0
253 + *
254 + * @param string $points_awards_heading The heading text (eg: 2 Points Awards)
255 + * @param array $points_awards The points awards
256 + * @param int $user_id The user's ID
257 + * @param array $template_args The given template args
258 + *
259 + * @return string
260 + */
261 + $points_awards_heading = apply_filters( 'gamipress_points_awards_heading', $points_awards_heading, $points_awards, $user_id, $template_args );
262 + $a['heading_size'] = gamipress_sanitize_title_size_option( $a['heading_size'] );
263 +
264 + $output .= '<' . $a['heading_size'] . ' class="gamipress-points-awards-heading">' . $points_awards_heading . '</' . $a['heading_size'] . '>';
265 +
266 + }
267 +
268 + $output .= '<ul class="gamipress-points-awards">';
269 +
270 + // Concatenate our output
271 + foreach ( $points_awards as $points_award ) {
272 +
273 + if( $user_id === 0 ) {
274 + $earned_status = 'user-has-not-earned';
275 + } else {
276 + // Check if user can earn this points award and add the earned class
277 + $can_earn = gamipress_can_user_earn_requirement( $points_award->ID, $user_id );
278 + $earned_status = $can_earn ? 'user-has-not-earned' : 'user-has-earned';
279 + }
280 +
281 + $title = $points_award->post_title;
282 +
283 + // If points award doesn't have a title, then try to build one
284 + if( empty( $title ) ) {
285 + $title = gamipress_build_requirement_title( $points_award->ID );
286 + }
287 +
288 + /**
289 + * Filters the points award CSS class
290 + *
291 + * @since 1.0.0
292 + *
293 + * @param string $class CSS class based on earned status ('user-has-earned' | 'user-has-not-earned')
294 + * @param stdClass $points_award Requirement object
295 + * @param int $user_id User's ID
296 + * @param array $template_args The given template args
297 + *
298 + * @return string
299 + */
300 + $class = apply_filters( 'gamipress_points_award_class', $earned_status, $points_award, $user_id, $template_args );
301 +
302 + /**
303 + * Filters the points award HTML title to display
304 + *
305 + * @since 1.0.0
306 + *
307 + * @param string $title Title to display
308 + * @param stdClass $points_award Requirement object
309 + * @param int $user_id User's ID
310 + * @param array $template_args The given template args
311 + *
312 + * @return string
313 + */
314 + $title = apply_filters( 'gamipress_points_award_title_display', $title, $points_award, $user_id, $template_args );
315 +
316 + $output .= '<li class="'. esc_attr( $class ) .'">'. $title . '</li>';
317 + }
318 +
319 + $output .= '</ul><!-- .gamipress-points-awards -->';
320 +
321 + // Return our output
322 + return $output;
323 +
324 +}
325 +
326 +/**
327 + * Generate HTML markup for an points type's points deducts
328 + *
329 + * @since 1.3.7
330 + *
331 + * @param array $points_deducts An points type's points deducts
332 + * @param int $user_id The given user's ID
333 + * @param array $template_args The given template args
334 + *
335 + * @return string The markup for our list
336 + */
337 +function gamipress_get_points_deducts_for_points_types_list_markup( $points_deducts = array(), $user_id = 0, $template_args = array() ) {
338 +
339 + // If we don't have any points deducts, or our points deducts aren't an array, return nothing
340 + if ( ! $points_deducts || ! is_array( $points_deducts ) ) {
341 + return null;
342 + }
343 +
344 + $count = count( $points_deducts );
345 +
346 + // If we have no points deducts, return nothing
347 + if ( ! $count ) {
348 + return null;
349 + }
350 +
351 + // Grab the current user's ID if none was specifed
352 + if ( ! $user_id ) {
353 + $user_id = get_current_user_id();
354 + }
355 +
356 + $a = wp_parse_args( $template_args, gamipress_points_types_shortcode_defaults() );
357 +
358 + // Setup our variables
359 + $output = '';
360 +
361 + if( $a['heading'] === 'yes' ) {
362 +
363 + $points_type = gamipress_get_points_deduct_points_type( $points_deducts[0]->ID );
364 +
365 + if( $points_type ) {
366 + $plural_name = gamipress_get_post_meta( '_gamipress_plural_name', $points_type->ID );
367 +
368 + if( ! $plural_name ) {
369 + $plural_name = $points_type->post_title;
370 + }
371 +
372 + $points_deducts_heading = sprintf( '%1$d %2$s %3$s', $count, $plural_name, _n( 'Deduction', 'Deductions', $count, 'gamipress' ) ); // 2 Credits Deducts
373 + } else {
374 + $points_deducts_heading = sprintf( '%1$d %2$s', $count, _n( 'Deduction', 'Deductions', $count, 'gamipress' ) ); // 2 Deductions
375 + }
376 +
377 + /**
378 + * Filters the points deduct heading text
379 + *
380 + * @since 1.3.7
381 + *
382 + * @param string $points_deducts_heading The heading text (eg: 2 Points Deductions)
383 + * @param array $points_deducts The points deducts
384 + * @param int $user_id The user's ID
385 + * @param array $template_args The given template args
386 + *
387 + * @return string
388 + */
389 + $points_deducts_heading = apply_filters( 'gamipress_points_deducts_heading', $points_deducts_heading, $points_deducts, $user_id, $template_args );
390 + $a['heading_size'] = gamipress_sanitize_title_size_option( $a['heading_size'] );
391 +
392 + $output .= '<' . $a['heading_size'] . ' class="gamipress-points-deducts-heading">' . $points_deducts_heading . '</' . $a['heading_size'] . '>';
393 +
394 + }
395 +
396 + $output .= '<ul class="gamipress-points-deducts">';
397 +
398 + // Concatenate our output
399 + foreach ( $points_deducts as $points_deduct ) {
400 +
401 + if( $user_id === 0 ) {
402 + $earned_status = 'user-has-not-earned';
403 + } else {
404 + // Check if user can earn this points deduct and add the earned class
405 + $can_earn = gamipress_can_user_earn_requirement( $points_deduct->ID, $user_id );
406 + $earned_status = $can_earn ? 'user-has-not-earned' : 'user-has-earned';
407 + }
408 +
409 + $title = $points_deduct->post_title;
410 +
411 + // If points deduct doesn't have a title, then try to build one
412 + if( empty( $title ) ) {
413 + $title = gamipress_build_requirement_title( $points_deduct->ID );
414 + }
415 +
416 + /**
417 + * Filters the points deduct CSS class
418 + *
419 + * @since 1.3.7
420 + *
421 + * @param string $class CSS class based on earned status ('user-has-earned' | 'user-has-not-earned')
422 + * @param stdClass $points_deduct Requirement object
423 + * @param int $user_id User's ID
424 + * @param array $template_args The given template args
425 + *
426 + * @return string
427 + */
428 + $class = apply_filters( 'gamipress_points_deduct_class', $earned_status, $points_deduct, $user_id, $template_args );
429 +
430 + /**
431 + * Filters the points deduct HTML title to display
432 + *
433 + * @since 1.3.7
434 + *
435 + * @param string $title Title to display
436 + * @param stdClass $points_deduct Requirement object
437 + * @param int $user_id User's ID
438 + * @param array $template_args The given template args
439 + *
440 + * @return string
441 + */
442 + $title = apply_filters( 'gamipress_points_deduct_title_display', $title, $points_deduct, $user_id, $template_args );
443 +
444 + $output .= '<li class="'. esc_attr( $class ) .'">'. $title . '</li>';
445 + }
446 +
447 + $output .= '</ul><!-- .gamipress-points-deducts -->';
448 +
449 + // Return our output
450 + return $output;
451 +
452 +}
453 +
454 +/**
455 + * Gets achievement's required steps and returns HTML markup for these steps
456 + *
457 + * @since 1.0.0
458 + * @param int $achievement_id The given achievement's post ID
459 + * @param int $user_id A given user's ID
460 + *
461 + * @return string The markup for our list
462 + */
463 +function gamipress_get_required_achievements_for_achievement_list( $achievement_id = 0, $user_id = 0 ) {
464 +
465 + // Grab the current post ID if no achievement_id was specified
466 + if ( ! $achievement_id ) {
467 + global $post;
468 + $achievement_id = $post->ID;
469 + }
470 +
471 + // Grab the current user's ID if none was specifed
472 + if ( ! $user_id )
473 + $user_id = wp_get_current_user()->ID;
474 +
475 + // Grab our achievement's required steps
476 + $steps = gamipress_get_achievement_steps( $achievement_id );
477 +
478 + // Return our markup output
479 + return gamipress_get_required_achievements_for_achievement_list_markup( $steps, $user_id );
480 +
481 +}
482 +
483 +/**
484 + * Generate HTML markup for an achievement's required steps
485 + *
486 + * This will generate an unorderd list (<ul>) if steps are non-sequential
487 + * and an ordered list (<ol>) if steps require sequentiality.
488 + *
489 + * @since 1.0.0
490 + *
491 + * @param array $steps An achievement's required steps
492 + * @param int $achievement_id The given achievement's ID
493 + * @param int $user_id The given user's ID
494 + * @param array $template_args The given template args
495 + *
496 + * @return string The markup for our list
497 + */
498 +function gamipress_get_required_achievements_for_achievement_list_markup( $steps = array(), $achievement_id = 0, $user_id = 0, $template_args = array() ) {
499 +
500 + // If we don't have any steps, or our steps aren't an array, return nothing
501 + if ( ! $steps || ! is_array( $steps ) )
502 + return null;
503 +
504 + // Grab the current post ID if no achievement_id was specified
505 + if ( ! $achievement_id ) {
506 + global $post;
507 + $achievement_id = $post->ID;
508 + }
509 +
510 + $count = count( $steps );
511 +
512 + // If we have no steps, return nothing
513 + if ( ! $count )
514 + return null;
515 +
516 + // Grab the current user's ID if none was specified
517 + if ( ! $user_id )
518 + $user_id = get_current_user_id();
519 +
520 + $a = wp_parse_args( $template_args, gamipress_achievement_shortcode_defaults() );
521 +
522 + // Setup our variables
523 + $output = '';
524 + $container = gamipress_is_achievement_sequential() ? 'ol' : 'ul';
525 +
526 + if( $a['heading'] === 'yes' ) {
527 +
528 + $steps_heading = sprintf( '%1$d %2$s', $count, _n( 'Step', 'Steps', $count, 'gamipress' ) );
529 +
530 + /**
531 + * Filters the steps heading text
532 + *
533 + * @since 1.0.0
534 + *
535 + * @param string $steps_heading The heading text (eg: 2 Steps)
536 + * @param array $steps The achievement steps
537 + * @param int $user_id The user's ID
538 + * @param array $template_args The given template args
539 + *
540 + * @return string
541 + */
542 + $steps_heading = apply_filters( 'gamipress_steps_heading', $steps_heading, $steps, $user_id, $template_args );
543 + $a['heading_size'] = gamipress_sanitize_title_size_option( $a['heading_size'] );
544 +
545 + $output .= '<' . $a['heading_size'] . ' class="gamipress-achievement-steps-heading">' . $steps_heading . '</' . $a['heading_size'] . '>';
546 +
547 + }
548 +
549 + $output .= '<' . $container .' class="gamipress-achievement-steps gamipress-required-achievements">';
550 + $credential = gamipress_get_the_credential();
551 +
552 + // Concatenate our output
553 + foreach ( $steps as $step ) {
554 +
555 + $earned_status = 'user-has-not-earned';
556 +
557 + if( ! $credential ) {
558 +
559 + $can_earn = true;
560 +
561 + if( $user_id === 0 ) {
562 + $earned_status = 'user-has-not-earned';
563 + } else {
564 + // Check if user can earn this step and add the earned class
565 + $can_earn = gamipress_can_user_earn_requirement( $step->ID, $user_id );
566 + $earned_status = $can_earn ? 'user-has-not-earned' : 'user-has-earned';
567 + }
568 +
569 + // Force earned class if user can't earn this step but has earned it in the past
570 + if( ! $can_earn && gamipress_has_user_earned_achievement( $step->ID, $user_id ) ) {
571 + $earned_status = 'user-has-earned';
572 + }
573 +
574 + }
575 +
576 + $title = $step->post_title;
577 +
578 + // If step doesn't have a title, then try to build one
579 + if( empty( $title ) ) {
580 + $title = gamipress_build_requirement_title( $step->ID );
581 + }
582 +
583 + /**
584 + * Filters the step CSS class
585 + *
586 + * @since 1.0.0
587 + *
588 + * @param string $class CSS class based on earned status ('user-has-earned' | 'user-has-not-earned')
589 + * @param stdClass $step Requirement object
590 + * @param int $user_id User's ID
591 + * @param array $template_args The given template args
592 + *
593 + * @return string
594 + */
595 + $class = apply_filters( 'gamipress_step_class', $earned_status, $step, $user_id, $template_args );
596 +
597 + /**
598 + * Filters the step HTML title to display
599 + *
600 + * @since 1.0.0
601 + *
602 + * @param string $title Title to display
603 + * @param stdClass $step Requirement object
604 + * @param int $user_id User's ID
605 + * @param array $template_args The given template args
606 + *
607 + * @return string
608 + */
609 + $title = apply_filters( 'gamipress_step_title_display', $title, $step, $user_id, $template_args );
610 +
611 + $output .= '<li class="'. esc_attr( $class ) .'">'. $title . '</li>';
612 + }
613 +
614 + $output .= '</'. $container .'><!-- .gamipress-required-achievements -->';
615 +
616 + // Return our output
617 + return $output;
618 +
619 +}
620 +
621 +/**
622 + * Filter requirements titles to link to assigned post
623 + *
624 + * @since 1.0.0
625 + * @updated 1.5.0 Improved checks to get correct post permalink and centralize all requirements link functions to this
626 + * @updated 1.8.7 Added permalink to the 'earn-rank' trigger
627 + *
628 + * @param string $title The requirement title
629 + * @param object $requirement The requirement object
630 + *
631 + * @return string Our potentially updated title
632 + */
633 +function gamipress_format_requirement_title_with_post_link( $title = '', $requirement = null ) {
634 +
635 + // Grab our step requirements
636 + $requirement = gamipress_get_requirement_object( $requirement->ID );
637 +
638 + $url = $requirement['url'];
639 +
640 + if( empty( $url ) ) {
641 +
642 + $trigger = $requirement['trigger_type'];
643 + $post_id = 0;
644 + $site_id = get_current_blog_id();
645 +
646 + if ( in_array( $trigger, array( 'earn-rank', 'revoke-rank' ) ) && ! empty( $requirement['rank_required'] ) ) {
647 +
648 + // Set the post ID for the rank required to reach
649 + $post_id = $requirement['rank_required'];
650 + $site_id = ( gamipress_is_network_wide_active() ? get_main_site_id() : get_current_blog_id() );
651 +
652 + } else if ( ! empty( $requirement['achievement_post'] ) ) {
653 +
654 + // Set the post ID for the post assigned
655 + $post_id = $requirement['achievement_post'];
656 + $site_id = $requirement['achievement_post_site_id'];
657 +
658 + }
659 +
660 + // Set the URL to link to a specific post
661 + $url = gamipress_get_specific_activity_trigger_permalink( $post_id, $trigger, $site_id );
662 +
663 + }
664 +
665 + // If we have a URL, update the title to link to it
666 + if ( ! empty( $url ) ) {
667 + $title = '<a href="' . esc_url( $url ) . '">' . $title . '</a>';
668 + }
669 +
670 + return $title;
671 +
672 +}
673 +add_filter( 'gamipress_step_title_display', 'gamipress_format_requirement_title_with_post_link', 10, 2 );
674 +add_filter( 'gamipress_points_award_title_display', 'gamipress_format_requirement_title_with_post_link', 10, 2 );
675 +add_filter( 'gamipress_points_deduct_title_display', 'gamipress_format_requirement_title_with_post_link', 10, 2 );
676 +add_filter( 'gamipress_rank_requirement_title_display', 'gamipress_format_requirement_title_with_post_link', 10, 2 );
677 +
678 +/**
679 + * Generate markup for an achievement's times earned output
680 + *
681 + * @since 1.5.9
682 + *
683 + * @param int $achievement_id The given achievement's ID
684 + * @param array $template_args Achievement template args
685 + *
686 + * @return string The HTML markup for our times earned output
687 + */
688 +function gamipress_achievement_times_earned_markup( $achievement_id = 0, $template_args = array() ) {
689 +
690 + // Grab the current post ID if no achievement_id was specified
691 + if ( ! $achievement_id ) {
692 + global $post;
693 + $achievement_id = $post->ID;
694 + }
695 +
696 + if( ! isset( $template_args['user_id'] ) ) {
697 + $template_args['user_id'] = get_current_user_id();
698 + }
699 +
700 + $user_id = absint( $template_args['user_id'] );
701 +
702 + // Guest not supported yet (basically because they has not earned this achievement)
703 + if( $user_id === 0 ) {
704 + return '';
705 + }
706 +
707 + $maximum_earnings = absint( gamipress_get_post_meta( $achievement_id, '_gamipress_maximum_earnings' ) );
708 +
709 + // Return if maximum earnings configured is 1
710 + if( $maximum_earnings === 1 ) {
711 + return '';
712 + }
713 +
714 + $earned_times = gamipress_get_earnings_count( array( 'user_id' => $user_id, 'post_id' => $achievement_id ) );
715 +
716 + /**
717 + * Filter to override the minimum times required to show the achievement times earned text, by default 1
718 + *
719 + * @since 2.0.0
720 + *
721 + * @param int $minimum_earned_times Minimum times required to show the achievement times earned text, by default 1
722 + * @param int $achievement_id The given achievement's ID
723 + * @param int $user_id The user's ID
724 + * @param int $earned_times The user's times earned this achievement
725 + * @param int $maximum_earnings The achievement's maximum times to be earned
726 + * @param array $template_args Achievement template args
727 + */
728 + $minimum_earned_times = apply_filters( 'gamipress_achievement_times_earned_minimum_times_to_show', 1, $achievement_id, $user_id, $earned_times, $maximum_earnings, $template_args );
729 +
730 + // Return if user hasn't earned this achievement the minimum times required to show
731 + if( $earned_times <= $minimum_earned_times ) {
732 + return '';
733 + }
734 +
735 + // Setup the times earned text based on if achievements has unlimited times to be earned
736 + if( $maximum_earnings === 0 ) {
737 + $times_earned_pattern = __( '%d times earned', 'gamipress' );
738 +
739 + $times_earned_text = sprintf( $times_earned_pattern, $earned_times );
740 + } else {
741 + $times_earned_pattern = __( '%d of %d times earned', 'gamipress' );
742 +
743 + $times_earned_text = sprintf( $times_earned_pattern, $earned_times, $maximum_earnings );
744 + }
745 +
746 + /**
747 + * Filter to override the achievement times earned text
748 + *
749 + * @since 1.5.9
750 + *
751 + * @param string $times_earned_text Times earned text, by default "X times earned"
752 + * @param int $achievement_id The given achievement's ID
753 + * @param int $user_id The user's ID
754 + * @param int $earned_times The user's times earned this achievement
755 + * @param int $maximum_earnings The achievement's maximum times to be earned
756 + * @param array $template_args Achievement template args
757 + */
758 + $times_earned_text = apply_filters( 'gamipress_achievement_times_earned_text', $times_earned_text, $achievement_id, $user_id, $earned_times, $maximum_earnings, $template_args );
759 +
760 + // The time earned markup
761 + $output = '<div class="gamipress-achievement-times-earned">' . $times_earned_text . '</div>';
762 +
763 + /**
764 + * Filter to override the achievement times earned markup
765 + *
766 + * @since 1.5.9
767 + *
768 + * @param string $output Times earned markup
769 + * @param int $achievement_id The given achievement's ID
770 + * @param int $user_id The user's ID
771 + * @param int $earned_times The user's times earned this achievement
772 + * @param int $maximum_earnings The achievement's maximum times to be earned
773 + * @param array $template_args Achievement template args
774 + */
775 + return apply_filters( 'gamipress_achievement_times_earned_markup', $output, $achievement_id, $user_id, $earned_times, $maximum_earnings, $template_args );
776 +
777 +}
778 +
779 +/**
780 + * Generate markup for an achievement's times earned by all users output
781 + *
782 + * @since 2.0.0
783 + *
784 + * @param int $achievement_id The given achievement's ID
785 + * @param array $template_args Achievement template args
786 + *
787 + * @return string The HTML markup for our times earned output
788 + */
789 +function gamipress_achievement_global_times_earned_markup( $achievement_id = 0, $template_args = array() ) {
790 +
791 + global $wpdb;
792 +
793 + // Grab the current post ID if no achievement_id was specified
794 + if ( ! $achievement_id ) {
795 + global $post;
796 + $achievement_id = $post->ID;
797 + }
798 +
799 + $maximum_earnings = absint( gamipress_get_post_meta( $achievement_id, '_gamipress_global_maximum_earnings' ) );
800 +
801 + $user_earnings = GamiPress()->db->user_earnings;
802 +
803 + $earned_times = absint( $wpdb->get_var( $wpdb->prepare(
804 + "SELECT COUNT( DISTINCT ue.user_id ) FROM {$user_earnings} AS ue WHERE ue.post_id = %d",
805 + absint( $achievement_id )
806 + ) ) );
807 +
808 + /**
809 + * Filter to override the minimum times required to show the achievement times earned by all users text, by default 1
810 + *
811 + * @since 2.0.0
812 + *
813 + * @param int $minimum_earned_times Minimum times required to show the achievement times earned text, by default 1
814 + * @param int $achievement_id The given achievement's ID
815 + * @param int $earned_times The user's times earned this achievement
816 + * @param int $maximum_earnings The achievement's global maximum times to be earned
817 + * @param array $template_args Achievement template args
818 + */
819 + $minimum_earned_times = apply_filters( 'gamipress_achievement_global_times_earned_minimum_times_to_show', 1, $achievement_id, $earned_times, $maximum_earnings, $template_args );
820 +
821 + // Return if user hasn't earned this achievement the minimum times required to show
822 + if( $earned_times <= $minimum_earned_times ) {
823 + return '';
824 + }
825 +
826 + $post_type = gamipress_get_post_type( $achievement_id );
827 + $achievement_type_singular = gamipress_get_achievement_type_singular( $post_type );
828 +
829 + // Set up the times earned text based on if achievements has unlimited times to be earned
830 + if( $maximum_earnings === 0 ) {
831 + $times_earned_text = sprintf( __( '%d users have earned this %s', 'gamipress' ),
832 + $earned_times,
833 + $achievement_type_singular
834 + );
835 + } else {
836 + $times_earned_text = sprintf( __( '%d of %d users have earned this %s', 'gamipress' ),
837 + $earned_times,
838 + $maximum_earnings,
839 + $achievement_type_singular
840 + );
841 + }
842 +
843 + /**
844 + * Filter to override the achievement times earned by all users text
845 + *
846 + * @since 1.5.9
847 + *
848 + * @param string $times_earned_text Times earned text, by default "X users have earned this Y"
849 + * @param int $achievement_id The given achievement's ID
850 + * @param int $earned_times The user's times earned this achievement
851 + * @param int $maximum_earnings The achievement's maximum times to be earned
852 + * @param array $template_args Achievement template args
853 + */
854 + $times_earned_text = apply_filters( 'gamipress_achievement_global_times_earned_text', $times_earned_text, $achievement_id, $earned_times, $maximum_earnings, $template_args );
855 +
856 + // The time earned markup
857 + $output = '<div class="gamipress-achievement-global-times-earned">' . $times_earned_text . '</div>';
858 +
859 + /**
860 + * Filter to override the achievement times earned by all users markup
861 + *
862 + * @since 1.5.9
863 + *
864 + * @param string $output Times earned markup
865 + * @param int $achievement_id The given achievement's ID
866 + * @param int $earned_times The user's times earned this achievement
867 + * @param int $maximum_earnings The achievement's maximum times to be earned
868 + * @param array $template_args Achievement template args
869 + */
870 + return apply_filters( 'gamipress_achievement_global_times_earned_markup', $output, $achievement_id, $earned_times, $maximum_earnings, $template_args );
871 +
872 +}
873 +
874 +/**
875 + * Generate markup for an achievement's points output
876 + *
877 + * @since 1.0.0
878 + * @updated 1.5.9 Added $template_args parameter
879 + *
880 + * @param int $achievement_id The given achievement's ID
881 + * @param array $template_args Achievement template args
882 + *
883 + * @return string The HTML markup for our points
884 + */
885 +function gamipress_achievement_points_markup( $achievement_id = 0, $template_args = array() ) {
886 +
887 + // Grab the current post ID if no achievement_id was specified
888 + if ( ! $achievement_id ) {
889 + global $post;
890 + $achievement_id = $post->ID;
891 + }
892 +
893 + $points = absint( gamipress_get_post_meta( $achievement_id, '_gamipress_points' ) );
894 +
895 + // Return if no points configured
896 + if( $points === 0 ) {
897 + return '';
898 + }
899 +
900 + $points_type = gamipress_get_post_meta( $achievement_id, '_gamipress_points_type' );
901 +
902 + // Set the default value for the points awarded thumbnail
903 + if( ! isset( $template_args['points_awarded_thumbnail'] ) ) {
904 + $template_args['points_awarded_thumbnail'] = 'yes';
905 + }
906 +
907 + $output = '<div class="gamipress-achievement-points gamipress-achievement-points-type-' . $points_type . '">'
908 + . ( $template_args['points_awarded_thumbnail'] === 'yes' ? gamipress_get_points_type_thumbnail( $points_type ) . ' ' : '' )
909 + . gamipress_format_points( $points, $points_type )
910 + . '</div>';
911 +
912 + // Return the points awarded output
913 + return apply_filters( 'gamipress_achievement_points_markup', $output, $achievement_id, $points, $points_type, $template_args );
914 +
915 +}
916 +
917 +/**
918 + * Generate markup for an achievement's unlock with points output
919 + *
920 + * @since 1.3.7
921 + *
922 + * @param int $achievement_id The given achievement's ID
923 + * @param array $template_args Achievement template args
924 + *
925 + * @return string The HTML markup for our points
926 + */
927 +function gamipress_achievement_unlock_with_points_markup( $achievement_id = 0, $template_args = array() ) {
928 +
929 + // Grab the current post ID if no achievement_id was specified
930 + if ( ! $achievement_id ) {
931 + $achievement_id = get_the_ID();
932 + }
933 +
934 + $user_id = get_current_user_id();
935 +
936 + // Guest not supported yet (basically because they have no points)
937 + if( $user_id === 0 ) {
938 + return '';
939 + }
940 +
941 + if( ! isset( $template_args['user_id'] ) ) {
942 + $template_args['user_id'] = get_current_user_id();
943 + }
944 +
945 + // Return if user is displaying achievements of another user
946 + if( $user_id !== absint( $template_args['user_id'] ) ) {
947 + return '';
948 + }
949 +
950 + // Return if this option not was enabled
951 + if( ! (bool) gamipress_get_post_meta( $achievement_id, '_gamipress_unlock_with_points' ) ) {
952 + return '';
953 + }
954 +
955 + $points = absint( gamipress_get_post_meta( $achievement_id, '_gamipress_points_to_unlock' ) );
956 +
957 + // Return if no points configured
958 + if( $points === 0 ) {
959 + return '';
960 + }
961 +
962 + $earned = gamipress_achievement_user_exceeded_max_earnings( $user_id, $achievement_id );
963 +
964 + // Return if user has completely earned this achievement
965 + if( $earned ) {
966 + return '';
967 + }
968 +
969 + // Setup vars
970 + $points_type = gamipress_get_post_meta( $achievement_id, '_gamipress_points_type_to_unlock' );
971 +
972 + // Template vars
973 + $achievement_title = gamipress_get_post_field( 'post_title', $achievement_id );
974 + $points_formatted = gamipress_format_points( $points, $points_type );
975 +
976 + /**
977 + * Filters if achievement unlock with points requires confirmation, by default true
978 + *
979 + * @since 1.7.8.1
980 + *
981 + * @param bool $confirmation If the given achievement's ID requires confirmation on unlock using points
982 + * @param int $achievement_id The given achievement's ID
983 + * @param int $user_id The user's ID
984 + * @param int $points Points amount to unlock
985 + * @param string $points_type Points type of points amount to unlock
986 + * @param array $template_args Achievement template args
987 + *
988 + * @return bool Whatever if achievement requires confirmation or not
989 + */
990 + $confirmation = apply_filters( 'gamipress_achievement_unlock_with_points_confirmation', true, $achievement_id, $user_id, $points, $points_type, $template_args );
991 +
992 + $button_text = sprintf( __( 'Unlock using %s', 'gamipress' ), $points_formatted );
993 +
994 + /**
995 + * Filters the achievement unlock with points button text
996 + *
997 + * @since 1.8.6
998 + *
999 + * @param string $button_text The button text, by default "Unlock using 100 points"
1000 + * @param int $achievement_id The given achievement's ID
1001 + * @param int $user_id The user's ID
1002 + * @param int $points Points amount to unlock
1003 + * @param string $points_type Points type of points amount to unlock
1004 + * @param array $template_args Achievement template args
1005 + *
1006 + * @return string Whatever if achievement requires confirmation or not
1007 + */
1008 + $button_text = apply_filters( 'gamipress_achievement_unlock_with_points_button_text', $button_text, $achievement_id, $user_id, $points, $points_type, $template_args );
1009 +
1010 + ob_start(); ?>
1011 + <div class="gamipress-achievement-unlock-with-points" data-id="<?php echo $achievement_id; ?>">
1012 + <button type="button" class="gamipress-achievement-unlock-with-points-button"><?php echo $button_text; ?></button>
1013 + <?php if( $confirmation ) : ?>
1014 + <div class="gamipress-achievement-unlock-with-points-confirmation" style="display: none;">
1015 + <p><?php echo sprintf( __( 'Do you want to unlock %s using %s?', 'gamipress' ), $achievement_title, $points_formatted ); ?></p>
1016 + <button type="button" class="gamipress-achievement-unlock-with-points-confirm-button"><?php echo __( 'Yes', 'gamipress' ); ?></button>
1017 + <button type="button" class="gamipress-achievement-unlock-with-points-cancel-button"><?php echo __( 'No', 'gamipress' ); ?></button>
1018 + </div>
1019 + <?php endif; ?>
1020 + <div class="gamipress-spinner" style="display: none;"></div>
1021 + </div>
1022 + <?php $output = ob_get_clean();
1023 +
1024 + /**
1025 + * Filters the achievement unlock with points markup
1026 + *
1027 + * @since 1.3.7
1028 + *
1029 + * @param string $output The HTML markup for our points
1030 + * @param int $achievement_id The given achievement's ID
1031 + * @param int $user_id The user's ID
1032 + * @param int $points Points amount to unlock
1033 + * @param string $points_type Points type of points amount to unlock
1034 + * @param array $template_args Achievement template args
1035 + *
1036 + * @return string The HTML markup for our points
1037 + */
1038 + $output = apply_filters( 'gamipress_achievement_unlock_with_points_markup', $output, $achievement_id, $user_id, $points, $points_type, $template_args );
1039 +
1040 + // Return the unlock with points output
1041 + return $output;
1042 +
1043 +}
1044 +
1045 +/**
1046 + * Generate markup for an rank's unlock with points output
1047 + *
1048 + * @since 1.3.7
1049 + *
1050 + * @param int $rank_id The given rank's ID
1051 + * @param array $template_args Rank template args
1052 + *
1053 + * @return string The HTML markup for our points
1054 + */
1055 +function gamipress_rank_unlock_with_points_markup( $rank_id = 0, $template_args = array() ) {
1056 +
1057 + // Grab the current post ID if no rank_id was specified
1058 + if ( ! $rank_id ) {
1059 + $rank_id = get_the_ID();
1060 + }
1061 +
1062 + $rank_types = gamipress_get_rank_types();
1063 + $rank_type = gamipress_get_post_type( $rank_id );
1064 +
1065 + if( ! isset( $rank_types[$rank_type] ) ) {
1066 + return '';
1067 + }
1068 +
1069 + $user_id = get_current_user_id();
1070 +
1071 + // Guest not supported yet (basically because they have no points)
1072 + if( $user_id === 0 ) {
1073 + return '';
1074 + }
1075 +
1076 + if( ! isset( $template_args['user_id'] ) ) {
1077 + $template_args['user_id'] = get_current_user_id();
1078 + }
1079 +
1080 + // Return if user is displaying ranks of another user
1081 + if( $user_id !== absint( $template_args['user_id'] ) ) {
1082 + return '';
1083 + }
1084 +
1085 + // Return if this option not was enabled
1086 + if( ! (bool) gamipress_get_post_meta( $rank_id, '_gamipress_unlock_with_points' ) ) {
1087 + return '';
1088 + }
1089 +
1090 + $points = absint( gamipress_get_post_meta( $rank_id, '_gamipress_points_to_unlock' ) );
1091 +
1092 + // Return if no points configured
1093 + if( $points === 0 ) {
1094 + return '';
1095 + }
1096 +
1097 + // Bail if not is the next rank to unlock
1098 + if( gamipress_get_next_user_rank_id( $user_id, $rank_type ) !== $rank_id ) {
1099 + return '';
1100 + }
1101 +
1102 + $user_rank = gamipress_get_user_rank( $user_id, $rank_type );
1103 +
1104 + // Return if user is in a higher rank
1105 + if( gamipress_get_rank_priority( $rank_id ) <= gamipress_get_rank_priority( $user_rank ) ) {
1106 + return '';
1107 + }
1108 +
1109 + // Setup vars
1110 + $points_type = gamipress_get_post_meta( $rank_id, '_gamipress_points_type_to_unlock' );
1111 +
1112 + // Template vars
1113 + $rank_title = gamipress_get_post_field( 'post_title', $rank_id );
1114 + $points_formatted = gamipress_format_points( $points, $points_type );
1115 +
1116 + /**
1117 + * Filters if rank unlock with points requires confirmation, by default true
1118 + *
1119 + * @since 1.7.8.1
1120 + *
1121 + * @param bool $confirmation If the given rank's ID requires confirmation on unlock using points
1122 + * @param int $rank_id The given rank's ID
1123 + * @param int $user_id The user's ID
1124 + * @param int $points Points amount to unlock
1125 + * @param string $points_type Points type of points amount to unlock
1126 + * @param array $template_args Achievement template args
1127 + *
1128 + * @return bool Whatever if achievement requires confirmation or not
1129 + */
1130 + $confirmation = apply_filters( 'gamipress_rank_unlock_with_points_confirmation', true, $rank_id, $user_id, $points, $points_type, $template_args );
1131 +
1132 + $button_text = sprintf( __( 'Unlock using %s', 'gamipress' ), $points_formatted );
1133 +
1134 + /**
1135 + * Filters the rank unlock with points button text
1136 + *
1137 + * @since 1.8.6
1138 + *
1139 + * @param string $button_text The button text, by default "Unlock using 100 points"
1140 + * @param int $rank_id The given rank's ID
1141 + * @param int $user_id The user's ID
1142 + * @param int $points Points amount to unlock
1143 + * @param string $points_type Points type of points amount to unlock
1144 + * @param array $template_args Achievement template args
1145 + *
1146 + * @return string Whatever if achievement requires confirmation or not
1147 + */
1148 + $button_text = apply_filters( 'gamipress_rank_unlock_with_points_button_text', $button_text, $rank_id, $user_id, $points, $points_type, $template_args );
1149 +
1150 + ob_start(); ?>
1151 + <div class="gamipress-rank-unlock-with-points" data-id="<?php echo $rank_id; ?>">
1152 + <button type="button" class="gamipress-rank-unlock-with-points-button"><?php echo $button_text; ?></button>
1153 + <?php if( $confirmation ) : ?>
1154 + <div class="gamipress-rank-unlock-with-points-confirmation" style="display: none;">
1155 + <p><?php echo sprintf( __( 'Do you want to unlock %s using %s?', 'gamipress' ), $rank_title, $points_formatted ); ?></p>
1156 + <button type="button" class="gamipress-rank-unlock-with-points-confirm-button"><?php echo __( 'Yes', 'gamipress' ); ?></button>
1157 + <button type="button" class="gamipress-rank-unlock-with-points-cancel-button"><?php echo __( 'No', 'gamipress' ); ?></button>
1158 + </div>
1159 + <?php endif; ?>
1160 + <div class="gamipress-spinner" style="display: none;"></div>
1161 + </div>
1162 + <?php $output = ob_get_clean();
1163 +
1164 + /**
1165 + * Filters the achievement unlock with points markup
1166 + *
1167 + * @since 1.3.7
1168 + *
1169 + * @param string $output The HTML markup for our points
1170 + * @param int $rank_id The given rank's ID
1171 + * @param int $user_id The user's ID
1172 + * @param int $points Points amount to unlock
1173 + * @param string $points_type Points type of points amount to unlock
1174 + * @param array $template_args Achievement template args
1175 + *
1176 + * @return string The HTML markup for our points
1177 + */
1178 + $output = apply_filters( 'gamipress_rank_unlock_with_points_markup', $output, $rank_id, $user_id, $points, $points_type, $template_args );
1179 +
1180 + // Return our markup
1181 + return $output;
1182 +
1183 +}
1184 +
1185 +/**
1186 + * Checks if should render open graph meta tags
1187 + *
1188 + * @since 1.8.6
1189 + */
1190 +function gamipress_maybe_render_open_graph_meta_tags() {
1191 +
1192 + $allowed_types = array_merge( gamipress_get_achievement_types_slugs(), gamipress_get_rank_types_slugs() );
1193 +
1194 + // Bail if not is a singular achievement type or rank type
1195 + if( ! is_singular( $allowed_types ) ) {
1196 + return;
1197 + }
1198 +
1199 + $enable_open_graph = (bool) gamipress_get_option( 'enable_open_graph_tags', false );
1200 +
1201 + // Bail if open graph meta tags option is not enabled
1202 + if( ! $enable_open_graph ) {
1203 + return;
1204 + }
1205 +
1206 + gamipress_render_open_graph_meta_tags( get_the_ID() );
1207 +
1208 +}
1209 +add_action( 'wp_head', 'gamipress_maybe_render_open_graph_meta_tags' );
1210 +
1211 +
1212 +/**
1213 + * Render open graph meta tags for the received post ID
1214 + *
1215 + * @since 1.8.6
1216 + *
1217 + * @param int $post_id
1218 + */
1219 +function gamipress_render_open_graph_meta_tags( $post_id ) {
1220 +
1221 + $post = get_post( $post_id );
1222 +
1223 + // Get the post information
1224 + $url = get_permalink( $post );
1225 + $title = $post->post_title;
1226 + $description = $post->post_content;
1227 + $image = get_the_post_thumbnail_url( $post );
1228 +
1229 + // Process the description
1230 + $description = apply_filters( 'the_content', $description );
1231 + $description = trim( strip_tags( wp_kses_no_null( $description ) ) );
1232 + ?>
1233 + <meta property="og:url" content="<?php echo esc_url( $url ); ?>"/>
1234 + <meta property="og:title" content="<?php echo esc_attr( $title ); ?>"/>
1235 + <meta property="og:description" content="<?php echo esc_attr( $description ); ?>"/>
1236 + <meta property="og:image" content="<?php echo esc_url( $image ); ?>"/>
1237 + <?php
1238 +}
1239 +
1240 +/**
1241 + * Generate markup for share an achievement's output
1242 + *
1243 + * @since 1.8.6
1244 + *
1245 + * @param int $achievement_id The given achievement's ID
1246 + * @param array $template_args Achievement template args
1247 + *
1248 + * @return string The HTML markup for our points
1249 + */
1250 +function gamipress_achievement_share_markup( $achievement_id = 0, $template_args = array() ) {
1251 +
1252 + // Grab the current post ID if no achievement_id was specified
1253 + if ( ! $achievement_id ) {
1254 + $achievement_id = get_the_ID();
1255 + }
1256 +
1257 + $user_id = get_current_user_id();
1258 +
1259 + // Guest not allowed (basically because they have not earned this)
1260 + if( $user_id === 0 ) {
1261 + return '';
1262 + }
1263 +
1264 + if( ! isset( $template_args['user_id'] ) ) {
1265 + $template_args['user_id'] = get_current_user_id();
1266 + }
1267 +
1268 + // Return if user is displaying achievements of another user
1269 + if( $user_id !== absint( $template_args['user_id'] ) ) {
1270 + return '';
1271 + }
1272 +
1273 + // Bail if share is not enable
1274 + if( ! (bool) gamipress_get_option( 'enable_share', false ) ) {
1275 + return '';
1276 + }
1277 +
1278 + $social_networks = gamipress_get_option( 'social_networks', false );
1279 +
1280 + // Bail if no social networks enabled
1281 + if( empty( $social_networks ) ) {
1282 + return '';
1283 + }
1284 +
1285 + // Check if user has earned this achievement
1286 + $earned = gamipress_has_user_earned_achievement( $achievement_id, $user_id );
1287 +
1288 + if( ! $earned ) {
1289 + return '';
1290 + }
1291 +
1292 + $button_style = gamipress_get_option( 'social_button_style', 'square' );
1293 +
1294 + $titles = array(
1295 + 'facebook' => __( 'Share on Facebook', 'gamipress' ),
1296 + 'twitter' => __( 'Share on Twitter', 'gamipress' ),
1297 + 'linkedin' => __( 'Share on LinkedIn', 'gamipress' ),
1298 + 'pinterest' => __( 'Share on Pinterest', 'gamipress' ),
1299 + );
1300 +
1301 + $names = array(
1302 + 'facebook' => __( 'Facebook', 'gamipress' ),
1303 + 'twitter' => __( 'Twitter', 'gamipress' ),
1304 + 'linkedin' => __( 'LinkedIn', 'gamipress' ),
1305 + 'pinterest' => __( 'Pinterest', 'gamipress' ),
1306 + );
1307 +
1308 + // Setup vars
1309 + $url = gamipress_get_credential_url( $achievement_id, $user_id );
1310 + $title = get_the_title( $achievement_id );
1311 + $image = get_the_post_thumbnail_url( $achievement_id );
1312 +
1313 + // Get the achievement twitter text
1314 + $twitter_text = gamipress_get_option( 'twitter_achievement_text', __( 'I earned the {achievement_type} {achievement_title} on {site_title}', 'gamipress' ) );
1315 +
1316 + // Parse the text
1317 + $twitter_text = gamipress_parse_tags( 'achievement_earned', $achievement_id, $user_id, $twitter_text );
1318 +
1319 + ob_start(); ?>
1320 +
1321 + <p class="gamipress-share-buttons-label"><?php _e( 'Share:', 'gamipress' ); ?></p>
1322 +
1323 + <div class="gamipress-share-buttons"
1324 + data-url="<?php echo esc_attr( $url ); ?>"
1325 + data-title="<?php echo esc_attr( $title ); ?>"
1326 + data-image="<?php echo esc_attr( $image ); ?>"
1327 + data-twitter-text="<?php echo esc_attr( $twitter_text ); ?>">
1328 +
1329 + <?php
1330 + /**
1331 + * Action at top of the share buttons
1332 + *
1333 + * @since 1.8.6
1334 + *
1335 + * @param int $achievement_id The given achievement's ID
1336 + * @param int $user_id The user's ID
1337 + * @param array $template_args Achievement template args
1338 + */
1339 + do_action( 'gamipress_achievement_share_buttons_top', $achievement_id, $user_id, $template_args ) ?>
1340 +
1341 + <?php foreach( $social_networks as $social_network ) : ?>
1342 + <a href="#"
1343 + title="<?php echo ( isset( $titles[$social_network] ) ? $titles[$social_network] : '' ); ?>"
1344 + class="gamipress-share-button gamipress-share-button-<?php echo $button_style; ?> gamipress-share-button-<?php echo $social_network; ?>"
1345 + data-network="<?php echo $social_network; ?>">
1346 + <span><?php echo ( isset( $names[$social_network] ) ? $names[$social_network] : '' ); ?></span>
1347 + </a>
1348 + <?php endforeach; ?>
1349 +
1350 + <?php
1351 + /**
1352 + * Action at bottom of the share buttons
1353 + *
1354 + * @since 1.8.6
1355 + *
1356 + * @param int $achievement_id The given achievement's ID
1357 + * @param int $user_id The user's ID
1358 + * @param array $template_args Achievement template args
1359 + */
1360 + do_action( 'gamipress_achievement_share_buttons_bottom', $achievement_id, $user_id, $template_args ) ?>
1361 +
1362 + </div>
1363 +
1364 + <?php $output = ob_get_clean();
1365 +
1366 + /**
1367 + * Filters the achievement share markup
1368 + *
1369 + * @since 1.8.6
1370 + *
1371 + * @param string $output The HTML markup for social sharing
1372 + * @param int $achievement_id The given achievement's ID
1373 + * @param int $user_id The user's ID
1374 + * @param array $template_args Achievement template args
1375 + *
1376 + * @return string The HTML markup for our points
1377 + */
1378 + $output = apply_filters( 'gamipress_achievement_share_markup', $output, $achievement_id, $user_id, $template_args );
1379 +
1380 + return $output;
1381 +
1382 +}
1383 +
1384 +/**
1385 + * Generate markup for share an rank's output
1386 + *
1387 + * @since 1.8.6
1388 + *
1389 + * @param int $rank_id The given rank's ID
1390 + * @param array $template_args Rank template args
1391 + *
1392 + * @return string The HTML markup for our points
1393 + */
1394 +function gamipress_rank_share_markup( $rank_id = 0, $template_args = array() ) {
1395 +
1396 + // Grab the current post ID if no rank_id was specified
1397 + if ( ! $rank_id ) {
1398 + $rank_id = get_the_ID();
1399 + }
1400 +
1401 + $user_id = get_current_user_id();
1402 +
1403 + // Guest not supported yet (basically because they has not earned this)
1404 + if( $user_id === 0 ) {
1405 + return '';
1406 + }
1407 +
1408 + if( ! isset( $template_args['user_id'] ) ) {
1409 + $template_args['user_id'] = get_current_user_id();
1410 + }
1411 +
1412 + // Return if user is displaying ranks of another user
1413 + if( $user_id !== absint( $template_args['user_id'] ) ) {
1414 + return '';
1415 + }
1416 +
1417 + // Bail if share is not enable
1418 + if( ! (bool) gamipress_get_option( 'enable_share', false ) ) {
1419 + return '';
1420 + }
1421 +
1422 + $social_networks = gamipress_get_option( 'social_networks', false );
1423 +
1424 + // Bail if not social networks enabled
1425 + if( empty( $social_networks ) ) {
1426 + return '';
1427 + }
1428 +
1429 + // Check if user has earned this achievement
1430 + $earned = gamipress_has_user_earned_achievement( $rank_id, $user_id );
1431 +
1432 + if( ! $earned ) {
1433 + return '';
1434 + }
1435 +
1436 + $button_style = gamipress_get_option( 'social_button_style', 'square' );
1437 +
1438 + $titles = array(
1439 + 'facebook' => __( 'Share on Facebook', 'gamipress' ),
1440 + 'twitter' => __( 'Share on Twitter', 'gamipress' ),
1441 + 'linkedin' => __( 'Share on LinkedIn', 'gamipress' ),
1442 + 'pinterest' => __( 'Share on Pinterest', 'gamipress' ),
1443 + );
1444 +
1445 + $names = array(
1446 + 'facebook' => __( 'Facebook', 'gamipress' ),
1447 + 'twitter' => __( 'Twitter', 'gamipress' ),
1448 + 'linkedin' => __( 'LinkedIn', 'gamipress' ),
1449 + 'pinterest' => __( 'Pinterest', 'gamipress' ),
1450 + );
1451 +
1452 + // Setup vars
1453 + $url = gamipress_get_credential_url( $rank_id, $user_id );
1454 + $title = get_the_title( $rank_id );
1455 + $image = get_the_post_thumbnail_url( $rank_id );
1456 +
1457 + // Get the rank twitter text
1458 + $twitter_text = gamipress_get_option( 'twitter_rank_text', __( 'I reached the {rank_type} {rank_title} on {site_title}', 'gamipress' ) );
1459 +
1460 + // Parse the text
1461 + $twitter_text = gamipress_parse_tags( 'rank_earned', $rank_id, $user_id, $twitter_text );
1462 +
1463 + ob_start(); ?>
1464 +
1465 + <p class="gamipress-share-buttons-label"><?php _e( 'Share:', 'gamipress' ); ?></p>
1466 +
1467 + <div class="gamipress-share-buttons"
1468 + data-url="<?php echo esc_attr( $url ); ?>"
1469 + data-title="<?php echo esc_attr( $title ); ?>"
1470 + data-image="<?php echo esc_attr( $image ); ?>"
1471 + data-twitter-text="<?php echo esc_attr( $twitter_text ); ?>">
1472 +
1473 + <?php
1474 + /**
1475 + * Action at top of the share buttons
1476 + *
1477 + * @since 1.8.6
1478 + *
1479 + * @param int $rank_id The given rank's ID
1480 + * @param int $user_id The user's ID
1481 + * @param array $template_args Rank template args
1482 + */
1483 + do_action( 'gamipress_rank_share_buttons_top', $rank_id, $user_id, $template_args ) ?>
1484 +
1485 + <?php foreach( $social_networks as $social_network ) : ?>
1486 + <a href="#"
1487 + title="<?php echo ( isset( $titles[$social_network] ) ? $titles[$social_network] : '' ); ?>"
1488 + class="gamipress-share-button gamipress-share-button-<?php echo $button_style; ?> gamipress-share-button-<?php echo $social_network; ?>"
1489 + data-network="<?php echo $social_network; ?>">
1490 + <span><?php echo ( isset( $names[$social_network] ) ? $names[$social_network] : '' ); ?></span>
1491 + </a>
1492 + <?php endforeach; ?>
1493 +
1494 + <?php
1495 + /**
1496 + * Action at bottom of the share buttons
1497 + *
1498 + * @since 1.8.6
1499 + *
1500 + * @param int $rank_id The given rank's ID
1501 + * @param int $user_id The user's ID
1502 + * @param array $template_args Rank template args
1503 + */
1504 + do_action( 'gamipress_rank_share_buttons_bottom', $rank_id, $user_id, $template_args ) ?>
1505 +
1506 + </div>
1507 +
1508 + <?php $output = ob_get_clean();
1509 +
1510 + /**
1511 + * Filters the rank share markup
1512 + *
1513 + * @since 1.8.6
1514 + *
1515 + * @param string $output The HTML markup for social sharing
1516 + * @param int $rank_id The given rank's ID
1517 + * @param int $user_id The user's ID
1518 + * @param array $template_args Rank template args
1519 + *
1520 + * @return string The HTML markup for our points
1521 + */
1522 + $output = apply_filters( 'gamipress_rank_share_markup', $output, $rank_id, $user_id, $template_args );
1523 +
1524 + return $output;
1525 +
1526 +}
1527 +
1528 +/**
1529 + * Adds "earned"/"not earned" post_class based on viewer's status
1530 + *
1531 + * @param array $classes Post classes
1532 + *
1533 + * @return array Updated post classes
1534 + */
1535 +function gamipress_add_earned_class_single( $classes = array() ) {
1536 +
1537 + if( is_singular( gamipress_get_achievement_types_slugs() ) ) {
1538 + // Single Achievement
1539 +
1540 + // Check if current user has earned the achievement they're viewing
1541 + $classes[] =gamipress_has_user_earned_achievement( get_the_ID(), get_current_user_id() ) ? 'user-has-earned' : 'user-has-not-earned';
1542 +
1543 + } else if( is_singular( gamipress_get_rank_types_slugs() ) ) {
1544 + // Single Rank
1545 +
1546 + // Check if current user has earned the rank they're viewing, rank is earned by default if is the lowest priority of this type
1547 + if( gamipress_is_lowest_priority_rank( get_the_ID() ) ) {
1548 + $earned = true;
1549 + } else {
1550 + $earned = gamipress_has_user_earned_achievement( get_the_ID(), get_current_user_id() );
1551 + }
1552 +
1553 + $classes[] = $earned ? 'user-has-earned' : 'user-has-not-earned';
1554 +
1555 + }
1556 +
1557 + return $classes;
1558 +
1559 +}
1560 +add_filter( 'post_class', 'gamipress_add_earned_class_single' );
1561 +
1562 +/**
1563 + * Returns a message if user has earned the achievement.
1564 + *
1565 + * @since 1.0.0
1566 + *
1567 + * @param int $achievement_id Achievement ID.
1568 + * @param int $user_id User ID.
1569 + *
1570 + * @return string HTML Markup.
1571 + */
1572 +function gamipress_render_earned_achievement_text( $achievement_id = 0, $user_id = 0 ) {
1573 +
1574 + $earned_message = '';
1575 +
1576 + if ( gamipress_has_user_earned_achievement( $achievement_id, $user_id ) ) {
1577 +
1578 + $earned_message .= '<div class="gamipress-achievement-earned"><p>'
1579 + . sprintf( __( 'You have earned this %s!', 'gamipress' ), gamipress_get_achievement_type_singular( gamipress_get_post_type( $achievement_id ), true ) )
1580 + . '</p></div>';
1581 +
1582 + if ( $congrats_text = gamipress_get_post_meta( $achievement_id, '_gamipress_congratulations_text' ) ) {
1583 + $earned_message .= '<div class="gamipress-achievement-congratulations">' . wpautop( $congrats_text ) . '</div>';
1584 + }
1585 + }
1586 +
1587 + /**
1588 + * Available filter to override the message if user has earned the achievement
1589 + *
1590 + * @since 1.0.0
1591 + *
1592 + * @param string $earned_message The earned message HTML markup.
1593 + * @param int $achievement_id Achievement ID.
1594 + * @param int $user_id User ID.
1595 + *
1596 + * @return string HTML Markup.
1597 + */
1598 + return apply_filters( 'gamipress_earned_achievement_message', $earned_message, $achievement_id, $user_id );
1599 +}
1600 +
1601 +/**
1602 + * Check if user has earned a given achievement.
1603 + *
1604 + * @since 1.0.0
1605 + *
1606 + * @param int $achievement_id Achievement ID.
1607 + * @param int $user_id User ID.
1608 + *
1609 + * @return bool True if user has earned the achievement, otherwise false.
1610 + */
1611 +function gamipress_has_user_earned_achievement( $achievement_id = 0, $user_id = 0 ) {
1612 +
1613 + $user_id = absint( $user_id );
1614 + $achievement_id = absint( $achievement_id );
1615 +
1616 + if( $user_id === 0 ) $user_id = get_current_user_id();
1617 + if( $user_id === 0 ) return false;
1618 +
1619 + $cache = gamipress_get_cache( 'has_user_earned_achievement', array(), false );
1620 +
1621 + if( isset( $cache[$user_id] ) && isset( $cache[$user_id][$achievement_id] ) ) {
1622 + // If result already cached, use it
1623 + $earned = $cache[$user_id][$achievement_id];
1624 + } else {
1625 + // Not cached result
1626 + $earned = gamipress_get_earnings_count( array( 'user_id' => $user_id, 'post_id' => $achievement_id ) );
1627 + $earned = $earned > 0;
1628 +
1629 + // Update the cache
1630 + if( ! isset( $cache[$user_id] ) ) $cache[$user_id] = array();
1631 + $cache[$user_id][$achievement_id] = $earned;
1632 +
1633 + gamipress_set_cache( 'has_user_earned_achievement', $cache );
1634 + }
1635 +
1636 + /**
1637 + * Available filter to override the has user earned achievement result.
1638 + *
1639 + * @since 1.0.0
1640 + *
1641 + * @param bool $earned Whatever if user has earned this achievement or not.
1642 + * @param int $achievement_id Achievement ID.
1643 + * @param int $user_id User ID.
1644 + *
1645 + * @return bool True if user has earned the achievement, otherwise false.
1646 + */
1647 + return apply_filters( 'gamipress_has_user_earned_achievement', $earned, $achievement_id, $user_id );
1648 +
1649 +}
1650 +
1651 +
1652 +/**
1653 + * Hide the hidden achievement post link from next and previous post link
1654 + *
1655 + * @since 1.0.0
1656 + *
1657 + * @param string $output The adjacent post link.
1658 + * @param string $format Link anchor format.
1659 + * @param string $link Link permalink format.
1660 + * @param WP_Post $post The adjacent post.
1661 + * @param string $adjacent Whether the post is previous or next.
1662 + *
1663 + * @return string
1664 + */
1665 +function gamipress_hide_next_previous_hidden_achievement_link( $output, $format, $link, $post, $adjacent ) {
1666 +
1667 + $post = get_post();
1668 +
1669 + if( $post && gamipress_is_achievement( $post ) && $output ) {
1670 +
1671 + // Get post link, without hidden achievement
1672 + $output = gamipress_get_post_link_without_hidden_achievement( $post->ID, $adjacent );
1673 +
1674 + }
1675 +
1676 + return $output;
1677 +
1678 +}
1679 +add_filter( 'next_post_link', 'gamipress_hide_next_previous_hidden_achievement_link', 10, 5 );
1680 +add_filter( 'previous_post_link', 'gamipress_hide_next_previous_hidden_achievement_link', 10, 5 );
1681 +
1682 +
1683 +/**
1684 + * Get post link without hidden achievement link
1685 + *
1686 + * @since 1.0.0
1687 + *
1688 + * @param int $achievement_id The achievement ID
1689 + * @param string $rel 'next'|'previous'
1690 + *
1691 + * @return string
1692 + */
1693 +function gamipress_get_post_link_without_hidden_achievement( $achievement_id, $rel ) {
1694 +
1695 + // Check if is an achievement
1696 + if( ! gamipress_is_achievement( $achievement_id ) ) {
1697 + return '';
1698 + }
1699 +
1700 + $link = '';
1701 +
1702 + // Get next post id without hidden achievement id
1703 + $next_post_id = gamipress_get_next_previous_achievement_id( $achievement_id, $rel );
1704 +
1705 + if ( $next_post_id ) {
1706 + // Generate post link
1707 + $link = gamipress_generate_post_link_by_post_id( $next_post_id, $rel );
1708 + }
1709 +
1710 + return $link;
1711 +
1712 +}
1713 +
1714 +/**
1715 + * Get next or previous post id , without hidden achievement id
1716 + *
1717 + * @since 1.0.0
1718 + *
1719 + * @param int $achievement_id The achievement ID
1720 + * @param string $rel 'next'|'previous'
1721 + *
1722 + * @return int|bool
1723 + */
1724 +function gamipress_get_next_previous_achievement_id( $achievement_id , $rel ) {
1725 +
1726 + global $wpdb;
1727 +
1728 + $posts = GamiPress()->db->posts;
1729 +
1730 + // Redirecting user page based on achievements
1731 + $post = gamipress_get_post( absint( $achievement_id ));
1732 +
1733 + //Get hidden achievements ids
1734 + $hidden = gamipress_get_hidden_achievement_ids( $post->post_type );
1735 +
1736 + $operator = ( $rel === 'next' ? '>' : '<' );
1737 + $order = ( $rel === 'next' ? 'ASC' : 'DESC' );
1738 + $hidden_where = ( count( $hidden ) ? "AND ID NOT IN ( " . implode( ', ', $hidden ) . " )" : '' );
1739 +
1740 + $next_id = absint( $wpdb->get_var( $wpdb->prepare(
1741 + "SELECT ID
1742 + FROM {$posts}
1743 + WHERE post_type = %s
1744 + AND post_status = %s
1745 + {$hidden_where}
1746 + AND ID {$operator} %d
1747 + ORDER BY ID {$order}
1748 + LIMIT 1",
1749 + $post->post_type,
1750 + 'publish',
1751 + $post->ID
1752 + ) ) );
1753 +
1754 + // Return next or previous achievement preventing hidden achievements
1755 + return ( $next_id !== absint( $post->ID ) ? $next_id : false );
1756 +
1757 +}
1758 +
1759 +/**
1760 + * Generate the post link based on custom post object
1761 + *
1762 + * @since 1.0.0
1763 + *
1764 + * @param int $post_id
1765 + * @param string $rel
1766 + *
1767 + * @return string
1768 + */
1769 +function gamipress_generate_post_link_by_post_id( $post_id, $rel ) {
1770 +
1771 + $post = gamipress_get_post( $post_id );
1772 +
1773 + if( ! $post ) return '';
1774 +
1775 + // Title of the post
1776 + $title = get_the_title( $post->ID );
1777 +
1778 + if ( empty( $post->post_title ) ) {
1779 + $title = ( $rel === 'next' ) ? __( 'Next Post' ) : __( 'Previous Post' );
1780 + }
1781 +
1782 + $nav = ($rel == 'next') ? '%s <span class="meta-nav">→</span>' : '<span class="meta-nav">←</span> %s';
1783 +
1784 + // Build link
1785 + $link = '<a href="' . get_permalink( $post ) . '" rel="'.$rel.'">' . sprintf( $nav, $title ) . '</a>';
1786 +
1787 + return $link;
1788 +
1789 +}
1790 +
1791 +/**
1792 + * Filters the log title.
1793 + *
1794 + * @param string $title The log title.
1795 + * @param int $id The log ID.
1796 + *
1797 + * @return string The formatted title
1798 + */
1799 +function gamipress_log_title_format( $title, $id = null ) {
1800 +
1801 + if( $id === null ) return $title;
1802 +
1803 + if( empty( $title ) ) $title = gamipress_get_parsed_log( $id );
1804 +
1805 + return $title;
1806 +}
1807 +add_filter( 'gamipress_render_log_title', 'gamipress_log_title_format', 10, 2 );
1808 +
1809 +/**
1810 + * Gets rank's required steps and returns HTML markup for these steps
1811 + *
1812 + * @since 1.0.0
1813 + * @param int $rank_id The given rank's post ID
1814 + * @param int $user_id A given user's ID
1815 + *
1816 + * @return string The markup for our list
1817 + */
1818 +function gamipress_get_rank_requirements_list( $rank_id = 0, $user_id = 0 ) {
1819 +
1820 + // Grab the current post ID if no rank_id was specified
1821 + if ( ! $rank_id ) {
1822 + global $post;
1823 + $rank_id = $post->ID;
1824 + }
1825 +
1826 + // Grab the current user's ID if none was specifed
1827 + if ( ! $user_id )
1828 + $user_id = wp_get_current_user()->ID;
1829 +
1830 + // Grab our rank's required requirements
1831 + $requirements = gamipress_get_rank_requirements( $rank_id );
1832 +
1833 + // Return our markup output
1834 + return gamipress_get_rank_requirements_list_markup( $requirements, $user_id );
1835 +
1836 +}
1837 +
1838 +/**
1839 + * Generate HTML markup for an achievement's required steps
1840 + *
1841 + * This will generate an unorderd list (<ul>) if steps are non-sequential
1842 + * and an ordered list (<ol>) if steps require sequentiality.
1843 + *
1844 + * @since 1.3.1
1845 + *
1846 + * @param array $requirements An rank's required requirements
1847 + * @param int $rank_id The given rank's ID
1848 + * @param int $user_id The given user's ID
1849 + * @param array $template_args The given template args
1850 + *
1851 + * @return string The markup for our list
1852 + */
1853 +function gamipress_get_rank_requirements_list_markup( $requirements = array(), $rank_id = 0, $user_id = 0, $template_args = array() ) {
1854 +
1855 + // If we don't have any steps, or our steps aren't an array, return nothing
1856 + if ( ! $requirements || ! is_array( $requirements ) ) {
1857 + return null;
1858 + }
1859 +
1860 + // Grab the current post ID if no achievement_id was specified
1861 + if ( ! $rank_id ) {
1862 + global $post;
1863 + $rank_id = $post->ID;
1864 + }
1865 +
1866 + $count = count( $requirements );
1867 +
1868 + // If we have no steps, return nothing
1869 + if ( ! $count ) {
1870 + return null;
1871 + }
1872 +
1873 + // Grab the current user's ID if none was specified
1874 + if ( ! $user_id ) {
1875 + $user_id = get_current_user_id();
1876 + }
1877 +
1878 + $a = wp_parse_args( $template_args, gamipress_rank_shortcode_defaults() );
1879 +
1880 + // Setup our variables
1881 + $output = '';
1882 + $container = gamipress_is_achievement_sequential() ? 'ol' : 'ul';
1883 +
1884 + if( $a['heading'] === 'yes' ) {
1885 +
1886 + $requirements_heading = sprintf( '%1$d %2$s', $count, _n( 'Requirement', 'Requirements', $count, 'gamipress' ) );;
1887 +
1888 + /**
1889 + * Filters the steps heading text
1890 + *
1891 + * @since 1.0.0
1892 + *
1893 + * @param string $requirements_heading The heading text (eg: 2 Requirements)
1894 + * @param array $requirements The rank requirements
1895 + * @param int $user_id The user's ID
1896 + * @param array $template_args The given template args
1897 + *
1898 + * @return string
1899 + */
1900 + $requirements_heading = apply_filters( 'gamipress_rank_requirements_heading', $requirements_heading, $requirements, $user_id, $template_args );
1901 + $a['heading_size'] = gamipress_sanitize_title_size_option( $a['heading_size'] );
1902 +
1903 + $output .= '<' . $a['heading_size'] . ' class="gamipress-rank-requirements-heading">' . $requirements_heading . '</' . $a['heading_size'] . '>';
1904 +
1905 + }
1906 +
1907 + $output .= '<' . $container .' class="gamipress-rank-requirements gamipress-required-requirements">';
1908 + $credential = gamipress_get_the_credential();
1909 +
1910 + // Concatenate our output
1911 + foreach ( $requirements as $requirement ) {
1912 + $earned_status = 'user-has-not-earned';
1913 +
1914 + if( ! $credential ) {
1915 + if( $user_id === 0 ) {
1916 + $earned_status = 'user-has-not-earned';
1917 + } else {
1918 + // Check if user can earn this requirement and add the earned class
1919 + $can_earn = gamipress_can_user_earn_requirement( $requirement->ID, $user_id );
1920 + $earned_status = $can_earn ? 'user-has-not-earned' : 'user-has-earned';
1921 + }
1922 + }
1923 +
1924 + $title = $requirement->post_title;
1925 +
1926 + // If step doesn't have a title, then try to build one
1927 + if( empty( $title ) ) {
1928 + $title = gamipress_build_requirement_title( $requirement->ID );
1929 + }
1930 +
1931 + /**
1932 + * Filters the rank requirement CSS class
1933 + *
1934 + * @since 1.3.1
1935 + *
1936 + * @param string $class CSS class based on earned status ('user-has-earned' | 'user-has-not-earned')
1937 + * @param stdClass $requirement Requirement object
1938 + * @param int $user_id User's ID
1939 + * @param array $template_args The given template args
1940 + *
1941 + * @return string
1942 + */
1943 + $class = apply_filters( 'gamipress_rank_requirement_class', $earned_status, $requirement, $user_id, $template_args );
1944 +
1945 + /**
1946 + * Filters the rank requirement HTML title to display
1947 + *
1948 + * @since 1.3.1
1949 + *
1950 + * @param string $title Title to display
1951 + * @param stdClass $requirement Requirement object
1952 + * @param int $user_id User's ID
1953 + * @param array $template_args The given template args
1954 + *
1955 + * @return string
1956 + */
1957 + $title = apply_filters( 'gamipress_rank_requirement_title_display', $title, $requirement, $user_id, $template_args );
1958 +
1959 + $output .= '<li class="'. esc_attr( $class ) .'">'. $title . '</li>';
1960 + }
1961 +
1962 + $output .= '</'. $container .'><!-- .gamipress-requirements -->';
1963 +
1964 + // Return our output
1965 + return $output;
1966 +
1967 +}
1968 +
1969 +/**
1970 + * Helper function tests that we're in the main loop
1971 + *
1972 + * @since 1.3.1
1973 + *
1974 + * @param bool|integer $id The page id
1975 + *
1976 + * @return boolean A boolean determining if the function is in the main loop
1977 + */
1978 +function gamipress_is_single_rank( $id = false ) {
1979 +
1980 + $slugs = gamipress_get_rank_types_slugs();
1981 +
1982 + // only run our filters on the rank singular page
1983 + if ( is_admin() || empty( $slugs ) || ! is_singular( $slugs ) )
1984 + return false;
1985 + // w/o id, we're only checking template context
1986 + if ( ! $id )
1987 + return true;
1988 +
1989 + // Checks several variables to be sure we're in the main loop (and won't effect things like post pagination titles)
1990 + return ( ( $GLOBALS['post']->ID == $id ) && in_the_loop() && empty( $GLOBALS['gamipress_reformat_content'] ) );
1991 +
1992 +}
1993 +
1994 +/**
1995 + * Returns a message if user has earned the rank.
1996 + *
1997 + * @since 1.3.1
1998 + *
1999 + * @param int $rank_id Rank ID.
2000 + * @param int $user_id User ID.
2001 + *
2002 + * @return string HTML Markup.
2003 + */
2004 +function gamipress_render_earned_rank_text( $rank_id = 0, $user_id = 0 ) {
2005 +
2006 + $earned_message = '';
2007 +
2008 + if ( gamipress_has_user_earned_rank( $rank_id, $user_id ) ) {
2009 +
2010 + $earned_message .= '<div class="gamipress-rank-earned"><p>'
2011 + . sprintf( __( 'You have reached this %s!', 'gamipress' ), gamipress_get_rank_type_singular( gamipress_get_post_type( $rank_id ), true ) )
2012 + . '</p></div>';
2013 +
2014 + if ( $congrats_text = gamipress_get_post_meta( $rank_id, '_gamipress_congratulations_text' ) ) {
2015 + $earned_message .= '<div class="gamipress-rank-congratulations">' . wpautop( $congrats_text ) . '</div>';
2016 + }
2017 + }
2018 +
2019 + /**
2020 + * Available filter to override the message if user has earned the rank
2021 + *
2022 + * @since 1.0.0
2023 + *
2024 + * @param string $earned_message The earned message HTML markup.
2025 + * @param int $rank_id Rank ID.
2026 + * @param int $user_id User ID.
2027 + *
2028 + * @return string HTML Markup.
2029 + */
2030 + return apply_filters( 'gamipress_earned_rank_message', $earned_message, $rank_id, $user_id );
2031 +
2032 +}
2033 +
2034 +/**
2035 + * Check if user has earned a given achievement.
2036 + *
2037 + * @since 1.3.1
2038 + *
2039 + * @param int $rank_id Rank ID.
2040 + * @param int $user_id User ID.
2041 + *
2042 + * @return bool True if user has earned the rank, otherwise false.
2043 + */
2044 +function gamipress_has_user_earned_rank( $rank_id = 0, $user_id = 0 ) {
2045 +
2046 + $user_id = absint( $user_id );
2047 + $rank_id = absint( $rank_id );
2048 +
2049 + if( $user_id === 0 ) {
2050 + $user_id = get_current_user_id();
2051 + }
2052 +
2053 + if( $user_id === 0 ) {
2054 + return false;
2055 + }
2056 +
2057 + $earned = gamipress_get_earnings_count( array( 'user_id' => $user_id, 'post_id' => $rank_id ) );
2058 + $earned = $earned > 0;
2059 +
2060 + /**
2061 + * Available filter to override the has user earned rank result.
2062 + *
2063 + * @since 1.0.0
2064 + *
2065 + * @param bool $earned Whatever if user has earned this rank or not.
2066 + * @param int $rank_id Rank ID.
2067 + * @param int $user_id User ID.
2068 + *
2069 + * @return bool True if user has earned the rank, otherwise false.
2070 + */
2071 + return apply_filters( 'gamipress_has_user_earned_rank', $earned, $rank_id, $user_id );
2072 +
2073 +}
2074 +
2075 +/**
2076 + * Auto flush permalinks wth a soft flush when a 404 error is detected on an GamiPress page
2077 + *
2078 + * Taken from Easy Digital Downloads
2079 + *
2080 + * @since 1.3.3
2081 + * @return string
2082 + */
2083 +function gamipress_refresh_permalinks_on_bad_404() {
2084 +
2085 + global $wp;
2086 +
2087 + if( ! is_404() ) {
2088 + return;
2089 + }
2090 +
2091 + if( isset( $_GET['gamipress-flush'] ) ) {
2092 + return;
2093 + }
2094 +
2095 + if( false === get_transient( 'gamipress_refresh_404_permalinks' ) ) {
2096 +
2097 + $gamipress_slugs = array();
2098 +
2099 + $gamipress_slugs = array_merge( $gamipress_slugs, gamipress_get_achievement_types() );
2100 + $gamipress_slugs = array_merge( $gamipress_slugs, gamipress_get_points_types() );
2101 + $gamipress_slugs = array_merge( $gamipress_slugs, gamipress_get_rank_types() );
2102 +
2103 + $parts = explode( '/', $wp->request );
2104 +
2105 + $is_a_gamipress_page = false;
2106 +
2107 + foreach( $parts as $part ) {
2108 +
2109 + if( isset( $gamipress_slugs[$part] ) ) {
2110 + $is_a_gamipress_page = true;
2111 + break;
2112 + }
2113 +
2114 + }
2115 +
2116 + if( ! $is_a_gamipress_page ) {
2117 + return;
2118 + }
2119 +
2120 + flush_rewrite_rules( false );
2121 +
2122 + set_transient( 'gamipress_refresh_404_permalinks', 1, HOUR_IN_SECONDS * 12 );
2123 +
2124 + wp_redirect( home_url( add_query_arg( array( 'gamipress-flush' => 1 ), $wp->request ) ) ); exit;
2125 +
2126 + }
2127 +}
2128 +add_action( 'template_redirect', 'gamipress_refresh_permalinks_on_bad_404' );
2129 +
2130 +/**
2131 + * Render earnings column
2132 + *
2133 + * @since 1.0.0
2134 + *
2135 + * @param string $column_output Default column output
2136 + * @param string $column_name The column name
2137 + * @param stdClass $user_earning The column name
2138 + * @param array $template_args Template received arguments
2139 + *
2140 + * @return string
2141 + */
2142 +function gamipress_earnings_render_column( $column_output, $column_name, $user_earning, $template_args ) {
2143 +
2144 + // Setup vars
2145 + $requirement_types = gamipress_get_requirement_types();
2146 + $points_types = gamipress_get_points_types();
2147 + $achievement_types = gamipress_get_achievement_types();
2148 + $rank_types = gamipress_get_rank_types();
2149 +
2150 + switch( $column_name ) {
2151 + case 'user':
2152 +
2153 + $user = get_userdata( $user_earning->user_id );
2154 +
2155 + if( $user ) {
2156 + $column_output = get_avatar( $user_earning->user_id ) . $user->display_name;
2157 + }
2158 +
2159 + break;
2160 + case 'thumbnail':
2161 +
2162 + if( in_array( $user_earning->post_type, gamipress_get_requirement_types_slugs() ) ) {
2163 +
2164 + if( $user_earning->post_type === 'step' && $achievement = gamipress_get_step_achievement( $user_earning->post_id ) ) {
2165 + // Step
2166 +
2167 + // Get the achievement thumbnail and build a link to the achievement
2168 + $column_output = gamipress_get_achievement_post_thumbnail( $achievement->ID );
2169 +
2170 + } else if( ( $user_earning->post_type === 'points-award' || $user_earning->post_type === 'points-deduct' ) && $points_type = gamipress_get_points_award_points_type( $user_earning->post_id ) ) {
2171 + // Points Award and Deduction
2172 +
2173 + // Get the points type thumbnail
2174 + $column_output = gamipress_get_points_type_thumbnail( $points_type->ID );
2175 +
2176 + } else if( $user_earning->post_type === 'rank-requirement' && $rank = gamipress_get_rank_requirement_rank( $user_earning->post_id ) ) {
2177 + // Rank requirement
2178 +
2179 + // Get the rank thumbnail
2180 + $column_output = gamipress_get_rank_post_thumbnail( $rank->ID );
2181 + }
2182 +
2183 + } else if( in_array( $user_earning->post_type, gamipress_get_achievement_types_slugs() ) ) {
2184 + // Achievement
2185 +
2186 + // Get the achievement thumbnail
2187 + $column_output = gamipress_get_achievement_post_thumbnail( $user_earning->post_id );
2188 +
2189 + } else if( in_array( $user_earning->post_type, gamipress_get_rank_types_slugs() ) ) {
2190 + // Rank
2191 +
2192 + // Get the rank thumbnail
2193 + $column_output = gamipress_get_rank_post_thumbnail( $user_earning->post_id );
2194 +
2195 + } else {
2196 + // Default
2197 +
2198 + // Get the points type thumbnail
2199 + $column_output = gamipress_get_points_type_thumbnail( $user_earning->post_id );
2200 + }
2201 +
2202 + break;
2203 + case 'description':
2204 +
2205 + $earning_title = $user_earning->title;
2206 + $earning_description = '';
2207 +
2208 + if( in_array( $user_earning->post_type, gamipress_get_requirement_types_slugs() ) ) {
2209 +
2210 + $earning_description = '';
2211 +
2212 + if( $user_earning->post_type === 'step' && $achievement = gamipress_get_step_achievement( $user_earning->post_id ) ) {
2213 + // Step
2214 +
2215 + // Build a link to the achievement
2216 + $earning_description = sprintf( '%s %s: <a href="%s">%s</a>',
2217 + $achievement_types[$achievement->post_type]['singular_name'],
2218 + __( 'Step', 'gamipress' ),
2219 + get_post_permalink( $achievement->ID ),
2220 + $user_earning->title
2221 + );
2222 +
2223 + } else if( ( $user_earning->post_type === 'points-award' || $user_earning->post_type === 'points-deduct' ) && $points_type = gamipress_get_points_award_points_type( $user_earning->post_id ) ) {
2224 + // Points Award and Deduction
2225 +
2226 + $earning_description = sprintf( '%s %s',
2227 + $points_types[$points_type->post_name]['plural_name'],
2228 + ( $user_earning->post_type === 'points-award' ? __( 'Award', 'gamipress' ) : __( 'Deduction', 'gamipress' ) )
2229 + );
2230 +
2231 + } else if( $user_earning->post_type === 'rank-requirement' && $rank = gamipress_get_rank_requirement_rank( $user_earning->post_id ) ) {
2232 + // Rank requirement
2233 +
2234 + // Build a link to the rank
2235 + $earning_description = sprintf( '%s %s: <a href="%s">%s</a>',
2236 + $rank_types[$rank->post_type]['singular_name'],
2237 + __( 'Requirement', 'gamipress' ),
2238 + get_post_permalink( $rank->ID ),
2239 + $user_earning->title
2240 + );
2241 + }
2242 +
2243 + } else if( in_array( $user_earning->post_type, gamipress_get_achievement_types_slugs() ) ) {
2244 + // Achievement
2245 +
2246 + // Build a link to the achievement
2247 + $earning_title = sprintf( '<a href="%s">%s</a>',
2248 + get_post_permalink( $user_earning->post_id ),
2249 + gamipress_get_post_field( 'post_title', $user_earning->post_id )
2250 + );
2251 + $earning_description = $achievement_types[$user_earning->post_type]['singular_name'];
2252 +
2253 + } else if( in_array( $user_earning->post_type, gamipress_get_rank_types_slugs() ) ) {
2254 + // Rank
2255 +
2256 + // Build a link to the rank
2257 + $earning_title = sprintf( '<a href="%s">%s</a>',
2258 + get_post_permalink( $user_earning->post_id ),
2259 + gamipress_get_post_field( 'post_title', $user_earning->post_id )
2260 + );
2261 + $earning_description = $rank_types[$user_earning->post_type]['singular_name'];
2262 +
2263 + }
2264 +
2265 + // Default description for custom user earnings with points assigned
2266 + if( empty( $earning_description ) ) {
2267 +
2268 + $points = (int) $user_earning->points;
2269 +
2270 + if( $points !== 0 && isset( $points_types[$user_earning->points_type] ) ) {
2271 +
2272 + $earning_description = sprintf( '%s %s',
2273 + $points_types[$user_earning->points_type]['plural_name'],
2274 + ( $points > 0 ? __( 'Award', 'gamipress' ) : __( 'Deduction', 'gamipress' ) )
2275 + );
2276 +
2277 + }
2278 +
2279 + }
2280 +
2281 + $column_output = sprintf( '<strong class="gamipress-earning-title">%s</strong>'
2282 + . '<br>'
2283 + . '<span class="gamipress-earning-description">%s</span>',
2284 + $earning_title,
2285 + $earning_description
2286 + );
2287 +
2288 + break;
2289 + case 'points':
2290 +
2291 + $points = (int) $user_earning->points;
2292 +
2293 + if( $points !== 0 && isset( $points_types[$user_earning->points_type] ) ) {
2294 +
2295 + // Setup the output as %d point(s)
2296 + $column_output = gamipress_format_points( $points, $user_earning->points_type );
2297 +
2298 + // For points deducts turn amount to negative
2299 + if( $user_earning->post_type === 'points-deduct' && $points > 0 ) {
2300 + $negative_points = $points * -1;
2301 + $column_output = gamipress_format_points( $negative_points, $user_earning->points_type );;
2302 + }
2303 +
2304 + }
2305 +
2306 + break;
2307 + case 'date':
2308 +
2309 + $column_output = date_i18n( get_option( 'date_format' ), strtotime( $user_earning->date ) );
2310 +
2311 + break;
2312 + case 'actions':
2313 +
2314 + $render_credential = ( gamipress_is_achievement( $user_earning->post_type ) || gamipress_is_rank( $user_earning->post_type ) );
2315 +
2316 + $column_output .= $render_credential ? gamipress_get_credential_link( $user_earning ) : '';
2317 +
2318 + break;
2319 + }
2320 +
2321 + return $column_output;
2322 +
2323 +}
2324 +add_action( 'gamipress_earnings_render_column', 'gamipress_earnings_render_column', 10, 4 );