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/functions/logs.php +925 -0 7.9.3 → 8.0.5 View file →
@@ -1,0 +1,925 @@
1 +<?php
2 +/**
3 + * Logs Functions
4 + *
5 + * @package GamiPress\Logs_Functions
6 + * @author GamiPress <[email protected]>, Ruben Garcia <[email protected]>
7 + * @since 1.0.0
8 + */
9 +// Exit if accessed directly
10 +if( !defined( 'ABSPATH' ) ) exit;
11 +
12 +/**
13 + * Get an array of log types
14 + *
15 + * @since 1.0.0
16 +
17 + * @return array The registered logs types
18 + */
19 +function gamipress_get_log_types() {
20 +
21 + return apply_filters( 'gamipress_logs_types', array(
22 + 'event_trigger' => __( 'Event Trigger', 'gamipress' ),
23 + 'achievement_earn' => __( 'Achievement Earn', 'gamipress' ),
24 + 'achievement_award' => __( 'Achievement Award', 'gamipress' ),
25 + 'points_earn' => __( 'Points Earn', 'gamipress' ),
26 + 'points_deduct' => __( 'Points Deduction', 'gamipress' ),
27 + 'points_expend' => __( 'Points Expend', 'gamipress' ),
28 + 'points_award' => __( 'Points Award', 'gamipress' ),
29 + 'points_revoke' => __( 'Points Revoke', 'gamipress' ),
30 + 'rank_earn' => __( 'Rank Earn', 'gamipress' ),
31 + 'rank_award' => __( 'Rank Award', 'gamipress' ),
32 + ) );
33 +
34 +}
35 +
36 +/**
37 + * Get an array of log pattern tags
38 + *
39 + * @since 1.0.2
40 + * @updated 1.3.7 Added the content parameter
41 + * @updated 1.8.2 Added the {trigger_type_key} tag
42 + *
43 + * @param string $context
44 + *
45 + * @return array The registered log pattern tags
46 + */
47 +function gamipress_get_log_pattern_tags( $context = 'default' ) {
48 +
49 + return apply_filters( 'gamipress_log_pattern_tags', array(
50 + '{user}' => __( 'User assigned.', 'gamipress' ),
51 + '{admin}' => __( 'Admin that awards.', 'gamipress' ),
52 + '{achievement}' => __( 'Achievement user has earned.', 'gamipress' ),
53 + '{achievement_type}' => __( 'Type of the achievement earned.', 'gamipress' ),
54 + '{trigger_type}' => __( 'Event triggered label.', 'gamipress' ),
55 + '{trigger_type_key}' => __( 'Event triggered internal key.', 'gamipress' ),
56 + '{count}' => __( 'Times user triggered this event.', 'gamipress' ),
57 + '{points}' => __( 'Points user has earned.', 'gamipress' ),
58 + '{points_type}' => __( 'Type of the points earned.', 'gamipress' ),
59 + '{total_points}' => __( 'Points user has earned until this log.', 'gamipress' ),
60 + '{rank}' => __( 'Rank user has ranked.', 'gamipress' ),
61 + '{rank_type}' => __( 'Rank type user has ranked.', 'gamipress' ),
62 + '{site_title}' => __( 'Site name.', 'gamipress' ),
63 + ), $context );
64 +
65 +}
66 +
67 +/**
68 + * Get an array of log pattern tags based on custom context
69 + *
70 + * @since 1.3.7
71 + *
72 + * @param array $tags The registered log pattern tags
73 + * @param string $context The context
74 +
75 + * @return array Custom log pattern tags by context
76 + */
77 +function gamipress_get_log_pattern_tags_by_context( $tags, $context = 'default' ) {
78 +
79 + switch( $context ) {
80 + case 'deduct':
81 + $tags['{points}'] = __( 'Points user has lost.', 'gamipress' );
82 + $tags['{points_type}'] = __( 'Type of the points lost.', 'gamipress' );
83 + break;
84 + case 'expend':
85 + $tags['{points}'] = __( 'Points user has expended.', 'gamipress' );
86 + $tags['{points_type}'] = __( 'Type of the points expended.', 'gamipress' );
87 + break;
88 + }
89 +
90 + return $tags;
91 +
92 +}
93 +add_filter( 'gamipress_log_pattern_tags', 'gamipress_get_log_pattern_tags_by_context', 10, 2 );
94 +
95 +/**
96 + * Get a string with the desired log pattern tags html markup
97 + *
98 + * @since 1.0.2
99 + *
100 + * @param array $specific_tags
101 + * @param string $context
102 + *
103 + * @return string Log pattern tags html markup
104 + */
105 +function gamipress_get_log_pattern_tags_html( $specific_tags = array(), $context = 'default' ) {
106 +
107 + $output = '<ul class="gamipress-log-pattern-tags-list">';
108 +
109 + foreach( gamipress_get_log_pattern_tags( $context ) as $tag => $description ) {
110 +
111 + if( ! empty( $specific_tags ) && ! in_array( $tag, $specific_tags ) ) {
112 + continue;
113 + }
114 +
115 + $attr_id = 'tag-' . str_replace( array( '{', '}', '_' ), array( '', '', '-' ), $tag );
116 +
117 + $output .= "<li id='{$attr_id}'><code>{$tag}</code> - {$description}</li>";
118 + }
119 +
120 + $output .= '</ul>';
121 +
122 + return $output;
123 +
124 +}
125 +
126 +/**
127 + * Helper function to easily query logs and centralize code of multiples log query functions
128 + *
129 + * @since 1.6.0
130 + * @updated 1.6.9 Added 'where' and 'get_var' arguments, improvements on query args processing and support to where definition in format: array( 'key' =>'key', 'value' =>'value', 'compare' =>'compare' )
131 + * @updated 1.7.6 Added support for array selects, to group_by parameter and the output parameter
132 + *
133 + * @param array $args
134 + *
135 + * @return mixed
136 + */
137 +function gamipress_query_logs( $args ) {
138 +
139 + global $wpdb;
140 +
141 + $logs = GamiPress()->db->logs;
142 + $logs_meta = GamiPress()->db->logs_meta;
143 +
144 + $args = wp_parse_args( $args, array(
145 + 'select' => 'l.id', // You can pass 'l.*', 'l.{field}', 'COUNT(*)' or an array as select
146 + 'where' => array(), // Supported formats: 'key' =>'value' | array( 'key'=>'key', 'value'=>'value', 'compare'=>'compare', 'type'=>'type' )
147 + 'date_query' => array(), // Supports before and after parameters
148 + 'user_id' => 0,
149 + 'group_by' => '',
150 + 'order_by' => 'l.date',
151 + 'order' => 'DESC',
152 + 'limit' => 0,
153 + 'since' => 0,
154 + 'get_var' => false, // Force the use of get_var() function
155 + 'output' => OBJECT, // Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants.
156 +
157 + // Deprecated
158 + 'meta' => array(),
159 + ) );
160 +
161 + // Backward compatibility
162 + if( isset( $args['meta'] ) && count( $args['meta'] ) ) {
163 + $args['where'] = array_merge( $args['where'], $args['meta'] );
164 + }
165 +
166 + $log_fields = array(
167 + 'log_id',
168 + 'title',
169 + 'type',
170 + 'trigger_type',
171 + 'access',
172 + 'user_id',
173 + 'date',
174 + 'points',
175 + 'points_type',
176 + );
177 +
178 + // Initialize query definitions
179 + $select = array();
180 + $joins = array();
181 + $where = array();
182 + $query_args = array();
183 +
184 + // Select
185 + if( is_array( $args['select'] ) ) {
186 +
187 + foreach( $args['select'] as $key => $value ) {
188 +
189 + if( isset( $value['field'] ) ) {
190 + $field = $value['field'];
191 + } else {
192 + $field = $key;
193 + }
194 +
195 + if( in_array( $field, $log_fields ) ) {
196 + $get_key = "l.{$field}";
197 + } else {
198 +
199 + $index = count( $joins );
200 +
201 + $get_key = "lm{$index}.meta_value";
202 + $joins[] = "INNER JOIN {$logs_meta} AS lm{$index} ON ( lm{$index}.log_id = l.log_id AND lm{$index}.meta_key = %s )";
203 + $query_args[] = $field;
204 + }
205 +
206 + if ( isset( $value['function'] ) && $value['function'] ) {
207 + $get = "{$value['function']}({$get_key})";
208 + } else if ( isset( $value['cast'] ) && $value['cast'] ) {
209 + $get = "CAST({$get_key} AS {$value['cast']})";
210 + } else {
211 + $get = "{$get_key}";
212 + }
213 +
214 + $select[] = "{$get} as `{$key}`";
215 +
216 + }
217 +
218 + $args['select'] = ( ! empty( $select ) ? implode( ', ', $select ) : '' );
219 + }
220 +
221 + // User ID
222 + if( absint( $args['user_id'] ) !== 0 ) {
223 +
224 + $where[] = "l.user_id = %s";
225 +
226 + $query_args[] = $args['user_id'];
227 +
228 + }
229 +
230 + // Where
231 +
232 + if( isset( $args['where'] ) && is_array( $args['where'] ) ) {
233 +
234 + // Loop all log meta to build the where clause
235 + foreach ( $args['where'] as $key => $value ) {
236 +
237 + // Field key
238 + if( is_array( $value ) && isset( $value['key'] ) ) {
239 + $field = $value['key'];
240 + } else {
241 + $field = $key;
242 + }
243 +
244 + // Field value
245 + if( is_array( $value ) && isset( $value['value'] ) ) {
246 + $field_value = $value['value'];
247 + } else {
248 + $field_value = $value;
249 + }
250 +
251 + // Field compare
252 + if( is_array( $field_value ) ) {
253 + $default_compare = 'IN';
254 + } else {
255 + $default_compare = '=';
256 + }
257 +
258 + $compare = ( is_array( $value ) && isset( $value['compare'] ) ? $value['compare'] : $default_compare );
259 +
260 + // Field type
261 + $default_type = 'string';
262 +
263 + $type = ( is_array( $value ) && isset( $value['type'] ) ? $value['type'] : $default_type );
264 +
265 + // Parse common types to an unique one type
266 + switch( $type ) {
267 + case 'int':
268 + case 'integer':
269 + case 'number':
270 + case 'numeric':
271 + $type = 'integer';
272 + break;
273 + case 'text':
274 + case 'string':
275 + case 'char':
276 + case 'varchar':
277 + default:
278 + $type = 'string';
279 + break;
280 + }
281 +
282 + if( in_array( $field, $log_fields ) ) {
283 +
284 + // Query log field
285 +
286 + if( is_array( $field_value ) ) {
287 +
288 + if( $type === 'integer' ) {
289 + $field_value = implode( ", ", $field_value );
290 + } else {
291 + $field_value = "'" . implode( "', '", $field_value ) . "'";
292 + }
293 +
294 + $where[] = "l.{$field} {$compare} ({$field_value})";
295 + } else {
296 +
297 + if( $type === 'integer' ) {
298 + $where[] = "l.{$field} {$compare} %d";
299 + } else {
300 + $where[] = "l.{$field} {$compare} %s";
301 + }
302 +
303 + $query_args[] = $field_value;
304 + }
305 +
306 + } else {
307 +
308 + // Query log meta
309 +
310 + $index = count( $joins );
311 +
312 + $meta_key = '_gamipress_' . sanitize_key( $field );
313 +
314 + // Setup query definitions
315 + $joins[] = "LEFT JOIN {$logs_meta} AS lm{$index} ON ( l.log_id = lm{$index}.log_id AND lm{$index}.meta_key = '{$meta_key}' )";
316 +
317 + // If meta value is an array then need to compare using IN operator
318 + if( is_array( $field_value ) ) {
319 +
320 + if( $type === 'integer' ) {
321 + $field_value = implode( ", ", $field_value );
322 + } else {
323 + $field_value = "'" . implode( "', '", $field_value ) . "'";
324 + }
325 +
326 + $where[] = "lm{$index}.meta_value {$compare} ({$field_value})";
327 +
328 + } else {
329 + // Meta query in format: 'key' =>'value'
330 + if( $type === 'integer' ) {
331 + $where[] = "lm{$index}.meta_value {$compare} %d";
332 + } else {
333 + $where[] = "lm{$index}.meta_value {$compare} %s";
334 + }
335 +
336 + $query_args[] = $field_value;
337 + }
338 +
339 + }
340 +
341 + }
342 +
343 + }
344 +
345 + // Date query before
346 + if( isset( $args['date_query']['before'] ) && ! empty( $args['date_query']['before'] ) ) {
347 + $where[] = "l.date <= %s";
348 + $query_args[] = $args['date_query']['before'];
349 + }
350 +
351 + // Date query after
352 + if( isset( $args['date_query']['after'] ) && ! empty( $args['date_query']['after'] ) ) {
353 + $where[] = "l.date >= %s";
354 + $query_args[] = $args['date_query']['after'];
355 + }
356 +
357 + // Since
358 + if( absint( $args['since'] ) > 0 ) {
359 + $date = date( 'Y-m-d H:i:s', $args['since'] );
360 +
361 + $where[] = "l.date >= %s";
362 + $query_args[] = $date;
363 + }
364 +
365 + // Group By
366 + $group_by = '';
367 +
368 + if( ! empty( $args['group_by'] ) ) {
369 + $group_by = 'GROUP BY ' . $args['group_by'];
370 + }
371 +
372 + // Order By
373 + $order_by = '';
374 +
375 + if( ! empty( $args['order_by'] ) && ! empty( $args['order'] ) ) {
376 + $order_by = 'ORDER BY ' . $args['order_by'] . ' ' . $args['order'];
377 + }
378 +
379 + // Turn arrays into strings
380 + $select = $args['select'];
381 + $joins = implode( ' ', $joins );
382 + $where = ( ! empty( $where ) ? 'WHERE ( ' . implode( ' ) AND ( ', $where ) . ' ) ' : '' );
383 + $limit = ( absint( $args['limit'] ) !== 0 ? 'LIMIT ' . absint( $args['limit'] ) : '' );
384 +
385 + // Prepare the query SQL
386 + $sql = $wpdb->prepare(
387 + "SELECT {$select}
388 + FROM {$logs} AS l
389 + {$joins}
390 + {$where}
391 + {$group_by}
392 + {$order_by}
393 + {$limit}",
394 + $query_args
395 + );
396 +
397 + if( strtoupper( $select ) === 'COUNT(*)' || $args['get_var'] ) {
398 + // If is a count, ensure return an integer
399 + $logs = absint( $wpdb->get_var( $sql ) );
400 + } else {
401 + $logs = $wpdb->get_results( $sql, $args['output'] );
402 + }
403 +
404 + return $logs;
405 +
406 +}
407 +
408 +/**
409 + * Return user logs with the specified meta data
410 + *
411 + * @since 1.3.7
412 + * @updated 1.3.9.6 Added $since parameter
413 + * @updated 1.3.9.8 Improvements on since checks
414 + * @updated 1.6.0 Code moved to gamipress_query_logs() function
415 + *
416 + * @param int $user_id
417 + * @param array $where
418 + * @param int $since
419 + *
420 + * @return array
421 + */
422 +function gamipress_get_user_logs( $user_id = 0, $where = array(), $since = 0 ) {
423 +
424 + return gamipress_query_logs( array(
425 + 'select' => 'l.*',
426 + 'user_id' => $user_id,
427 + 'where' => $where,
428 + 'since' => $since
429 + ) );
430 +
431 +}
432 +
433 +/**
434 + * Return count of user logs with the specified meta data
435 + *
436 + * @since 1.1.8
437 + * @updated 1.3.7 Added support for multiples types
438 + * @updated 1.4.2 Added $since parameter
439 + * @updated 1.6.0 Code moved to gamipress_query_logs() function
440 + *
441 + * @param int $user_id
442 + * @param array $where
443 + *
444 + * @return int
445 + */
446 +function gamipress_get_user_log_count( $user_id = 0, $where = array(), $since = 0 ) {
447 +
448 + return gamipress_query_logs( array(
449 + 'select' => 'COUNT(*)',
450 + 'user_id' => $user_id,
451 + 'where' => $where,
452 + 'since' => $since
453 + ) );
454 +
455 +}
456 +
457 +/**
458 + * Return the last user log with the specified meta data
459 + *
460 + * @since 1.4.2
461 + *
462 + * @param int $user_id
463 + * @param array $where
464 + *
465 + * @return stdClass|false
466 + */
467 +function gamipress_get_user_last_log( $user_id = 0, $where = array() ) {
468 +
469 + $user_logs = gamipress_query_logs( array(
470 + 'select' => 'l.*',
471 + 'user_id' => $user_id,
472 + 'where' => $where,
473 + 'limit' => 1
474 + ) );
475 +
476 + return ( is_array( $user_logs ) && isset( $user_logs[0] ) ? $user_logs[0] : false );
477 +
478 +}
479 +
480 +/**
481 + * Posts a log entry when a user unlocks any achievement post
482 + *
483 + * @since 1.0.0
484 + * @updated 1.2.8 Added $type parameter
485 + * @updated 1.4.7 Added $trigger_type parameter
486 + *
487 + * @param string $type The log type
488 + * @param int $user_id The user ID
489 + * @param string $access Access to this log ( public|private )
490 + * @param string $trigger_type Access to this log ( public|private )
491 + * @param array $log_meta Log meta data
492 + *
493 + * @return int The log ID of the newly created log entry
494 + */
495 +function gamipress_insert_log( $type = '', $user_id = 0, $access = 'public', $trigger_type = '', $log_meta = array() ) {
496 +
497 + global $wpdb;
498 +
499 + // Backward compatibility for functions that called it by the old way
500 + if( is_array( $trigger_type ) && empty( $log_meta ) ) {
501 + $log_meta = $trigger_type;
502 + $trigger_type = '';
503 + }
504 +
505 + // Trigger type is not a meta yet, so update it correctly
506 + if( isset( $log_meta['trigger_type'] ) ) {
507 + $trigger_type = $log_meta['trigger_type'];
508 + unset( $log_meta['trigger_type'] );
509 + }
510 +
511 + // Setup table
512 + $ct_table = ct_setup_table( 'gamipress_logs' );
513 +
514 + // Post data
515 + $log_data = array(
516 + 'title' => '',
517 + 'type' => $type,
518 + 'trigger_type' => $trigger_type,
519 + 'access' => $access,
520 + 'user_id' => $user_id === 0 ? get_current_user_id() : absint( $user_id ),
521 + 'date' => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
522 + );
523 +
524 + $log_data['points'] = ( isset( $log_meta['points'] ) ) ? $log_meta['points'] : 0;
525 + $log_data['points_type'] = ( isset( $log_meta['points_type'] ) ) ? $log_meta['points_type'] : '';
526 +
527 + // Auto-generated post title
528 + $log_data['title'] = gamipress_parse_log_pattern( $log_meta['pattern'], $log_data, $log_meta );
529 +
530 + // Store log entry
531 + $log_id = $ct_table->db->insert( $log_data );
532 +
533 + // Store log meta data
534 + if ( $log_id && ! empty( $log_meta ) ) {
535 +
536 + $metas = array();
537 +
538 + foreach ( (array) $log_meta as $key => $value ) {
539 + // Sanitize vars
540 + $meta_key = '_gamipress_' . sanitize_key( $key );
541 + $meta_key = wp_unslash( $meta_key );
542 + $meta_value = wp_unslash( $value );
543 + $meta_value = esc_sql( $meta_value );
544 + $meta_value = sanitize_meta( $meta_key, $meta_value, $ct_table->name );
545 + $meta_value = maybe_serialize( $meta_value );
546 +
547 + // Setup the insert value
548 + $metas[] = $wpdb->prepare( '%d, %s, %s', array( $log_id, $meta_key, $meta_value ) );
549 + }
550 +
551 + $logs_meta = GamiPress()->db->logs_meta;
552 + $metas = implode( '), (', $metas );
553 +
554 + // Since the log is recently inserted, is faster to run a single query to insert all metas instead of insert them one-by-one
555 + $wpdb->query( "INSERT INTO {$logs_meta} (log_id, meta_key, meta_value) VALUES ({$metas})" );
556 +
557 + }
558 +
559 + // Hook to add custom data
560 + do_action( 'gamipress_insert_log', $log_id, $log_data, $log_meta, $user_id );
561 +
562 + ct_reset_setup_table();
563 +
564 + return $log_id;
565 +
566 +}
567 +
568 +/**
569 + * Parse log pattern replacements
570 + *
571 + * @since 1.0.0
572 + *
573 + * @param string $log_pattern The pattern
574 + * @param array $log_data Log post data
575 + * @param array $log_meta Log meta data
576 + *
577 + * @return integer The post ID of the newly created log entry
578 + */
579 +function gamipress_parse_log_pattern( $log_pattern = '', $log_data = array(), $log_meta = array()) {
580 +
581 + global $gamipress_pattern_replacements;
582 +
583 + // Setup site pattern replacements
584 + $gamipress_pattern_replacements['{site_title}'] = get_bloginfo( 'name' );
585 +
586 + $user = get_userdata( $log_data['user_id'] );
587 +
588 + // Setup user pattern replacements
589 + $gamipress_pattern_replacements['{user_id}'] = ( $user ? $user->ID : '' );
590 + $gamipress_pattern_replacements['{user}'] = ( $user ? $user->display_name : '' );
591 +
592 + // TODO: Add more user tags
593 +
594 + $gamipress_pattern_replacements['{trigger_type}'] = gamipress_get_activity_trigger_label( $log_data['trigger_type'] );
595 + $gamipress_pattern_replacements['{trigger_type_key}'] = $log_data['trigger_type'];
596 +
597 + foreach( $log_meta as $log_meta_key => $log_meta_value ) {
598 +
599 + if( in_array( $log_meta_key, array( 'pattern', 'type' ) ) )
600 + continue;
601 +
602 + // Implode meta value if is an array of values
603 + if( is_array( $log_meta_value ) )
604 + $log_meta_value = implode( ', ', $log_meta_value );
605 +
606 + $gamipress_pattern_replacements['{' . $log_meta_key . '}'] = $log_meta_value;
607 + }
608 +
609 + do_action( 'gamipress_before_parse_log_pattern', $log_data, $log_meta );
610 +
611 + return str_replace( array_keys( $gamipress_pattern_replacements ), $gamipress_pattern_replacements, $log_pattern );
612 +
613 +}
614 +
615 +/**
616 + * Log pattern replacements for achievements earn
617 + *
618 + * @since 1.0.0
619 + *
620 + * @uses global $gamipress_pattern_replacements
621 + *
622 + * @param array $log_data Log post data
623 + * @param array $log_meta Log meta data
624 + */
625 +function gamipress_parse_achievement_log_pattern( $log_data, $log_meta ) {
626 +
627 + // If log has assigned an achievement, then add achievement pattern replacements
628 + if( isset( $log_meta['achievement_id'] ) ) {
629 +
630 + global $gamipress_pattern_replacements;
631 +
632 + // Achievement pattern replacements
633 + $achievement = gamipress_get_post( $log_meta['achievement_id'] );
634 + $achievement_types = gamipress_get_achievement_types();
635 + $achievement_type = ( $achievement && isset( $achievement_types[$achievement->post_type]['singular_name'] ) ) ? $achievement_types[$achievement->post_type]['singular_name'] : '';
636 +
637 + // {achievement} tag
638 + $gamipress_pattern_replacements['{achievement}'] = $achievement->post_title;
639 +
640 + // {achievement_type} tag
641 + $gamipress_pattern_replacements['{achievement_type}'] = $achievement_type;
642 +
643 + if( $log_data['type'] === 'achievement_award' ) {
644 + $admin = get_userdata( $log_meta['admin_id'] );
645 +
646 + // {admin_username} tag
647 + $gamipress_pattern_replacements['{admin}'] = $admin->display_name;
648 + }
649 + }
650 +
651 +}
652 +add_action( 'gamipress_before_parse_log_pattern', 'gamipress_parse_achievement_log_pattern', 10, 2 );
653 +
654 +/**
655 + * Log pattern replacements for points earn/award
656 + *
657 + * @since 1.0.0
658 + *
659 + * @uses global $gamipress_pattern_replacements
660 + *
661 + * @param array $log_data Log post data
662 + * @param array $log_meta Log meta data
663 + */
664 +function gamipress_parse_points_log_pattern( $log_data, $log_meta ) {
665 +
666 + // If log is a points based entry, then add points pattern replacements
667 + if( $log_data['type'] === 'points_award' || $log_data['type'] === 'points_revoke' || $log_data['type'] === 'points_earn' || $log_data['type'] === 'points_deduct' ) {
668 +
669 + global $gamipress_pattern_replacements;
670 +
671 + $points = absint( $log_data['points'] );
672 + $points_type = $log_data['points_type'];
673 +
674 + $points_types = gamipress_get_points_types();
675 +
676 + // Default points label
677 + $points_label = __( 'points', 'gamipress' );
678 +
679 + if( isset( $points_types[$points_type] ) ) {
680 + // Points type label
681 + $points_label = strtolower( $points_types[$points_type]['plural_name'] );
682 + }
683 +
684 + // {points} tag, absint ensures a positive amount to build a pattern like "User expended 100 points" instead of "User expended -100 points"
685 + $gamipress_pattern_replacements['{points}'] = gamipress_format_amount( $points, $points_type );
686 +
687 + // {points_type} tag
688 + $gamipress_pattern_replacements['{points_type}'] = $points_label;
689 +
690 + if( $log_data['type'] === 'points_award' || $log_data['type'] === 'points_revoke' ) {
691 + $admin = get_userdata( $log_meta['admin_id'] );
692 +
693 + // {admin_username} tag
694 + $gamipress_pattern_replacements['{admin}'] = $admin->display_name;
695 + }
696 +
697 + }
698 +
699 +}
700 +add_action( 'gamipress_before_parse_log_pattern', 'gamipress_parse_points_log_pattern', 10, 2 );
701 +
702 +/**
703 + * Log pattern replacements for rank earn/award
704 + *
705 + * @since 1.3.1
706 + *
707 + * @uses global $gamipress_pattern_replacements
708 + *
709 + * @param array $log_data Log post data
710 + * @param array $log_meta Log meta data
711 + */
712 +function gamipress_parse_rank_log_pattern( $log_data, $log_meta ) {
713 +
714 + // If log is a points based entry, then add points pattern replacements
715 + if( $log_data['type'] === 'rank_award' || $log_data['type'] === 'rank_earn' ) {
716 +
717 + global $gamipress_pattern_replacements;
718 +
719 + $rank = gamipress_get_post( $log_meta['rank_id'] );
720 +
721 + // {rank} and {tank_type} tags
722 + $gamipress_pattern_replacements['{rank}'] = $rank ? $rank->post_title : '';
723 + $gamipress_pattern_replacements['{rank_type}'] = $rank ? gamipress_get_rank_type_singular( $rank->post_type, true ) : '';
724 +
725 + if( $log_data['type'] === 'rank_award' ) {
726 + $admin = get_userdata( $log_meta['admin_id'] );
727 +
728 + // {admin_username} tag
729 + $gamipress_pattern_replacements['{admin}'] = $admin->display_name;
730 + }
731 +
732 + }
733 +
734 +}
735 +add_action( 'gamipress_before_parse_log_pattern', 'gamipress_parse_rank_log_pattern', 10, 2 );
736 +
737 +/**
738 + * Update the post title of a log entry.
739 + *
740 + * @since 1.0.0
741 + *
742 + * @param array $object_data An array with new object data.
743 + * @param array $original_object_data An array with the original object data.
744 + * @return array Updated post data.
745 + */
746 +function gamipress_maybe_apply_log_pattern( $object_data = array(), $original_object_data = array() ) {
747 +
748 + global $ct_table;
749 +
750 + // If not is our logs, return
751 + if( $ct_table->name !== 'gamipress_logs' ) {
752 + return $object_data;
753 + }
754 +
755 + if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
756 + return $object_data;
757 + }
758 +
759 + if ( isset( $original_object_data['log_id'] ) && $original_object_data['log_id'] !== 0 ) {
760 +
761 + $log_id = $original_object_data['log_id'];
762 +
763 + // Just update using pattern if title has been changed
764 + if( empty( $object_data['title'] ) ) {
765 + // Check pattern
766 + if( isset( $_POST['_gamipress_pattern'] ) && ! empty( $_POST['_gamipress_pattern'] ) ) {
767 + $pattern = sanitize_text_field( $_POST['_gamipress_pattern'] );
768 + } else {
769 + $pattern = ct_get_object_meta( $log_id, '_gamipress_pattern', true );
770 + }
771 +
772 + // Just parse pattern if not empty
773 + if( ! empty( $pattern ) ) {
774 + $object_data['title'] = gamipress_get_parsed_log( $log_id );
775 + }
776 + }
777 + }
778 +
779 + return $object_data;
780 +
781 +}
782 +add_filter( 'ct_insert_object_data' , 'gamipress_maybe_apply_log_pattern' , 99, 2 );
783 +
784 +
785 +/**
786 + * Get and apply the pattern of a log entry.
787 + *
788 + * @since 1.0.0
789 + *
790 + * @param integer $log_id The log's ID.
791 + *
792 + * @return string Parsed log pattern.
793 + */
794 +function gamipress_get_parsed_log( $log_id = null ) {
795 +
796 + if( $log_id === null ) {
797 + return '';
798 + }
799 +
800 + $prefix = '_gamipress_';
801 +
802 + // Setup table
803 + ct_setup_table( 'gamipress_logs' );
804 +
805 + $log_data = ct_get_object( $log_id, ARRAY_A );
806 +
807 + if( ! $log_data ) {
808 + return '';
809 + }
810 +
811 + $log_meta = array(
812 + 'pattern' => ct_get_object_meta( $log_id, $prefix . 'pattern', true ),
813 + );
814 +
815 + $log_meta = apply_filters( 'gamipress_get_log_meta_data', $log_meta, $log_id, $log_data );
816 +
817 + ct_reset_setup_table();
818 +
819 + return gamipress_parse_log_pattern( $log_meta['pattern'], $log_data, $log_meta );
820 +
821 +}
822 +
823 +/**
824 + * Get log meta data defaults from a log's object ID
825 + *
826 + * @param $log_meta
827 + * @param $log_id
828 + * @param $log_data
829 + *
830 + * @return mixed
831 + */
832 +function gamipress_get_log_meta_data_defaults( $log_meta, $log_id, $log_data ) {
833 +
834 + $prefix = '_gamipress_';
835 +
836 + $meta_keys = array();
837 +
838 + if( $log_data['type'] === 'event_trigger' ) {
839 + // Event trigger meta data
840 + $meta_keys[] = 'count';
841 + } else if( $log_data['type'] === 'achievement_earn' || $log_data['type'] === 'achievement_award' ) {
842 + // Achievement earn meta data
843 + $meta_keys[] = 'achievement_id';
844 +
845 + if( $log_data['type'] === 'achievement_award' ) {
846 + // Specific achievement award meta data
847 + $meta_keys[] = 'admin_id';
848 + }
849 + } else if( $log_data['type'] === 'points_award' || $log_data['type'] === 'points_revoke' || $log_data['type'] === 'points_earn' || $log_data['type'] === 'points_deduct' ) {
850 + // Points earn/deduct/award/revoke meta data
851 + $meta_keys[] = 'points';
852 + $meta_keys[] = 'points_type';
853 + $meta_keys[] = 'total_points';
854 +
855 + if( $log_data['type'] === 'points_award' || $log_data['type'] === 'points_revoke' ) {
856 + // Specific points award meta data
857 + $meta_keys[] = 'admin_id';
858 + }
859 + } else if( $log_data['type'] === 'rank_earn' || $log_data['type'] === 'rank_award' ) {
860 + // Achievement earn meta data
861 + $meta_keys[] = 'rank_id';
862 +
863 + if( $log_data['type'] === 'rank_award' ) {
864 + // Specific rank award meta data
865 + $meta_keys[] = 'admin_id';
866 + }
867 + }
868 +
869 + foreach( $meta_keys as $meta_key ) {
870 + $log_meta[$meta_key] = ct_get_object_meta( $log_id, $prefix . $meta_key, true );
871 + }
872 +
873 + return $log_meta;
874 +
875 +}
876 +add_filter( 'gamipress_get_log_meta_data', 'gamipress_get_log_meta_data_defaults', 10, 3 );
877 +
878 +/**
879 + * Get the log object data
880 + *
881 + * @since 2.1.2
882 + *
883 + * @param int $log_id The log ID
884 + * @param string $meta_key The meta key to retrieve. By default, returns
885 + * data for all keys. Default empty.
886 + * @param bool $single Optional. Whether to return a single value. Default false.
887 + *
888 + * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
889 + */
890 +function gamipress_get_log_meta( $log_id, $meta_key = '', $single = false ) {
891 +
892 + ct_setup_table( 'gamipress_logs' );
893 +
894 + $meta_value = ct_get_object_meta( $log_id, $meta_key, $single );
895 +
896 + ct_reset_setup_table();
897 +
898 + return $meta_value;
899 +
900 +}
901 +
902 +/**
903 + * Update the log object data
904 + *
905 + * @since 2.1.2
906 + *
907 + * @param int $log_id The log ID
908 + * @param string $meta_key Metadata key.
909 + * @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
910 + * @param mixed $prev_value Optional. Previous value to check before removing.
911 + * Default empty.
912 + *
913 + * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
914 + */
915 +function gamipress_update_log_meta( $log_id, $meta_key, $meta_value, $prev_value = '' ) {
916 +
917 + ct_setup_table( 'gamipress_logs' );
918 +
919 + $meta_id = ct_update_object_meta( $log_id, $meta_key, $meta_value, $prev_value );
920 +
921 + ct_reset_setup_table();
922 +
923 + return $meta_id;
924 +
925 +}