| 1 |
<?php |
| 2 |
/** |
| 3 |
* Recount Activity Tool |
| 4 |
* |
| 5 |
* @package GamiPress\Admin\Tools\Recount_Activity |
| 6 |
* @author GamiPress <contact@gamipress.com>, Ruben Garcia <rubengcdev@gmail.com> |
| 7 |
* @since 1.1.8 |
| 8 |
*/ |
| 9 |
// Exit if accessed directly |
| 10 |
if( !defined( 'ABSPATH' ) ) exit; |
| 11 |
|
| 12 |
/** |
| 13 |
* Register Recount Activity Tool meta boxes |
| 14 |
* |
| 15 |
* @since 1.1.8 |
| 16 |
* |
| 17 |
* @param array $meta_boxes |
| 18 |
* |
| 19 |
* @return array |
| 20 |
*/ |
| 21 |
function gamipress_recount_activity_tool_meta_boxes( $meta_boxes ) { |
| 22 |
|
| 23 |
/** |
| 24 |
* Hook to add recountable activity triggers (login or daily visits are not recountable because they aren't stored in database) |
| 25 |
* |
| 26 |
* @since 1.1.8 |
| 27 |
* |
| 28 |
* @param array $activity_triggers Activity triggers that can be recounted |
| 29 |
* |
| 30 |
* @return array |
| 31 |
*/ |
| 32 |
$recountable_activity_triggers = apply_filters( 'gamipress_recountable_activity_triggers', |
| 33 |
array( |
| 34 |
'' => __( 'Choose the activity to recount', 'gamipress' ), |
| 35 |
// WordPress |
| 36 |
__( 'WordPress', 'gamipress' ) => array( |
| 37 |
'comments' => __( 'Recount comments', 'gamipress' ), |
| 38 |
'published_content' => __( 'Recount content publishing', 'gamipress' ), |
| 39 |
), |
| 40 |
) |
| 41 |
); |
| 42 |
|
| 43 |
$meta_boxes['recount-activity'] = array( |
| 44 |
'title' => gamipress_dashicon( 'backup' ) . __( 'Recount Activity', 'gamipress' ), |
| 45 |
'fields' => apply_filters( 'gamipress_recount_activity_tool_fields', array( |
| 46 |
'recount_activity_desc' => array( |
| 47 |
'content' => __( 'This tool will try to sync old activity with your already configured GamiPress install. GamiPress logs will be updated with all the activity stored in the database and the already configured points awards and deducts and achievements will be awarded or deducted too.', 'gamipress' ) |
| 48 |
. '<br>' . __( '<strong>Note:</strong> Some activity may not be possible to recount (like user log ins or daily visits) because there are not registries stored in the database.', 'gamipress' ) |
| 49 |
. '<br>' . __( '<strong>Important:</strong> If emails to notify users about new earnings are enabled is possible that users will receive a lot of emails so is recommendable to deactivate them temporally.', 'gamipress' ), |
| 50 |
'type' => 'html', |
| 51 |
), |
| 52 |
'activity_to_recount' => array( |
| 53 |
'name' => __( 'Activity to recount', 'gamipress' ), |
| 54 |
'tooltip' => __( 'Choose the activity to recount.', 'gamipress' ), |
| 55 |
'label_cb' => 'cmb_tooltip_label_cb', |
| 56 |
'type' => 'advanced_select', |
| 57 |
'options' => $recountable_activity_triggers, |
| 58 |
), |
| 59 |
'entries_per_loop' => array( |
| 60 |
'name' => __( 'Entries per loop', 'gamipress' ), |
| 61 |
'tooltip' => __( 'To prevent block your site, this tool performs the recount in small groups of entries. Set the number of entries to recount in each loop (by default, 100).', 'gamipress' ), |
| 62 |
'label_cb' => 'cmb_tooltip_label_cb', |
| 63 |
'desc' => __( '<strong>Note:</strong> If the recount process fails, try to reduce this setting to a lower number to 50, 20 or 10 entries per loop.', 'gamipress' ), |
| 64 |
'type' => 'text', |
| 65 |
'attributes' => array( |
| 66 |
'type' => 'number', |
| 67 |
'min' => '10', |
| 68 |
'step' => '5' |
| 69 |
), |
| 70 |
'default' => '100' |
| 71 |
), |
| 72 |
'recount_activity' => array( |
| 73 |
'label' => __( 'Recount Activity', 'gamipress' ), |
| 74 |
'type' => 'button', |
| 75 |
'button' => 'primary' |
| 76 |
), |
| 77 |
) ) |
| 78 |
); |
| 79 |
|
| 80 |
return $meta_boxes; |
| 81 |
|
| 82 |
} |
| 83 |
add_filter( 'gamipress_tools_general_meta_boxes', 'gamipress_recount_activity_tool_meta_boxes' ); |
| 84 |
|
| 85 |
/** |
| 86 |
* AJAX handler for the recount activity tool |
| 87 |
* |
| 88 |
* @since 1.1.8 |
| 89 |
* @updated 1.4.2 Added the run again utility |
| 90 |
*/ |
| 91 |
function gamipress_ajax_recount_activity_tool() { |
| 92 |
// Security check, forces to die if not security passed |
| 93 |
check_ajax_referer( 'gamipress_admin', 'nonce' ); |
| 94 |
|
| 95 |
// Check user capabilities |
| 96 |
if( ! current_user_can( gamipress_get_manager_capability() ) ) { |
| 97 |
wp_send_json_error( __( 'You are not allowed to perform this action.', 'gamipress' ) ); |
| 98 |
} |
| 99 |
|
| 100 |
// Check parameters received |
| 101 |
if( ! isset( $_POST['activity'] ) || empty( $_POST['activity'] ) ) { |
| 102 |
wp_send_json_error( __( 'You need to choose an activity to recount.', 'gamipress' ) ); |
| 103 |
} |
| 104 |
|
| 105 |
ignore_user_abort( true ); |
| 106 |
|
| 107 |
if ( ! gamipress_is_function_disabled( 'set_time_limit' ) ) { |
| 108 |
set_time_limit( 0 ); |
| 109 |
} |
| 110 |
|
| 111 |
// Setup a global var to make other functions meet that next awards comes from recount activity tool |
| 112 |
define( 'GAMIPRESS_DOING_ACTIVITY_RECOUNT', true ); |
| 113 |
|
| 114 |
$response = array( |
| 115 |
'success' => true, |
| 116 |
'run_again' => false, |
| 117 |
'message' => __( 'Activity recount process has been done successfully.', 'gamipress' ), |
| 118 |
'log' => '', |
| 119 |
); |
| 120 |
|
| 121 |
$activity = sanitize_text_field( $_POST['activity'] ); |
| 122 |
$loop = ( isset( $_POST['loop'] ) ? absint( $_POST['loop'] ) : 0 ); |
| 123 |
$limit = ( isset( $_POST['limit'] ) ? absint( $_POST['limit'] ) : 100 ); |
| 124 |
$offset = $limit * $loop; |
| 125 |
|
| 126 |
/** |
| 127 |
* Hook to process activity recount |
| 128 |
* |
| 129 |
* @since 1.1.8 |
| 130 |
* @updated 1.4.2 Added $loop parameter |
| 131 |
* @updated 1.8.2 Added $limit and $offset parameters |
| 132 |
* |
| 133 |
* @param array $response Response to return. Response format: array( |
| 134 |
* success => true|false, |
| 135 |
* run_again => true|false, |
| 136 |
* message => string, |
| 137 |
* log => string, |
| 138 |
* ) |
| 139 |
* @param int $loop Parameter to meet in which loop is the tool (just increased if run_again is set to true). |
| 140 |
* Important: First loop will be 0. |
| 141 |
* |
| 142 |
* @param int $limit Limit per loop, by default 100 |
| 143 |
* @param int $offset Current offset |
| 144 |
*/ |
| 145 |
$response = apply_filters( "gamipress_activity_recount_$activity", $response, $loop, $limit, $offset ); |
| 146 |
|
| 147 |
if( ! is_array( $response ) ) { |
| 148 |
wp_send_json_error( 'Activity recount process has failed!', 'gamipress' ); |
| 149 |
} |
| 150 |
|
| 151 |
// Return the full response |
| 152 |
if( $response['run_again'] ) { |
| 153 |
wp_send_json_success( $response ); |
| 154 |
} |
| 155 |
|
| 156 |
// Return the process response |
| 157 |
if( $response['success'] === true ) { |
| 158 |
wp_send_json_success( $response['message'] ); |
| 159 |
} else { |
| 160 |
wp_send_json_error( $response['message'] ); |
| 161 |
} |
| 162 |
|
| 163 |
} |
| 164 |
add_action( 'wp_ajax_gamipress_recount_activity_tool', 'gamipress_ajax_recount_activity_tool' ); |
| 165 |
|
| 166 |
/** |
| 167 |
* Recount comments activity |
| 168 |
* |
| 169 |
* @since 1.1.8 |
| 170 |
* @updated 1.4.2 Added $loop parameter |
| 171 |
* |
| 172 |
* @param array $response |
| 173 |
* @param int $loop |
| 174 |
* @param int $limit |
| 175 |
* @param int $offset |
| 176 |
* |
| 177 |
* @return array $response |
| 178 |
*/ |
| 179 |
function gamipress_activity_recount_comments( $response, $loop, $limit, $offset ) { |
| 180 |
|
| 181 |
global $wpdb; |
| 182 |
|
| 183 |
// Get all approved comments count |
| 184 |
$comments_count = absint( $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->comments} WHERE comment_approved = '1'" ) ); |
| 185 |
|
| 186 |
// On first loop send an informational text |
| 187 |
if( $loop === 0 && $comments_count > $limit ) { |
| 188 |
$response['run_again'] = true; |
| 189 |
$response['message'] = sprintf( __( '%d comments found, recounting...', 'gamipress' ), $comments_count ); |
| 190 |
$response['log'] = sprintf( __( '%d comments found, recounting...', 'gamipress' ), $comments_count ) . "<br>\n"; |
| 191 |
|
| 192 |
// Return early to inform |
| 193 |
return $response; |
| 194 |
} |
| 195 |
|
| 196 |
// Get all approved comments |
| 197 |
$comments = $wpdb->get_results( "SELECT * FROM {$wpdb->comments} WHERE comment_approved = '1' LIMIT {$offset}, {$limit}" ); |
| 198 |
|
| 199 |
foreach( $comments as $comment ) { |
| 200 |
|
| 201 |
$comment_id = (int) $comment->comment_ID; |
| 202 |
$user_id = (int) $comment->user_id; |
| 203 |
$post_id = (int) $comment->comment_post_ID; |
| 204 |
$post_type = get_post_type( $post_id ); |
| 205 |
|
| 206 |
// Skip wrong comments |
| 207 |
if( $comment_id === 0 ) continue; |
| 208 |
|
| 209 |
// Skip not user assigned comments |
| 210 |
if( $user_id === 0 ) continue; |
| 211 |
|
| 212 |
// Trigger comment actions to user |
| 213 |
do_action( 'gamipress_new_comment', $comment_id, $user_id, $post_id, $comment ); |
| 214 |
do_action( 'gamipress_specific_new_comment', $comment_id, $user_id, $post_id, $comment ); |
| 215 |
do_action( 'gamipress_new_comment_post_type', $comment_id, $user_id, $post_id, $post_type, $comment ); |
| 216 |
|
| 217 |
$response['log'] .= sprintf( __( '[Comment on a post] Comment: %s User: %s Post: %s', 'gamipress' ), |
| 218 |
$comment_id, |
| 219 |
'<a href="' . get_edit_user_link( $user_id ) . '" target="_blank">' . $user_id . '</a>', |
| 220 |
'<a href="' . get_edit_post_link( $post_id ) . '" target="_blank">' . $post_id . '</a>' |
| 221 |
) . "<br>\n"; |
| 222 |
|
| 223 |
if( $post_id !== 0 ) { |
| 224 |
|
| 225 |
$post_author = absint( get_post_field( 'post_author', $post_id ) ); |
| 226 |
|
| 227 |
// Trigger comment actions to author |
| 228 |
do_action( 'gamipress_user_post_comment', $comment_id, $post_author, $post_id, $comment ); |
| 229 |
do_action( 'gamipress_user_specific_post_comment', $comment_id, $post_author, $post_id, $comment ); |
| 230 |
do_action( 'gamipress_user_post_comment_post_type', $comment_id, $post_author, $post_id, $post_type, $comment ); |
| 231 |
|
| 232 |
$response['log'] .= sprintf( __( '[Get a comment on a post] Comment: %s User: %s Post: %s', 'gamipress' ), |
| 233 |
$comment_id, |
| 234 |
'<a href="' . get_edit_user_link( $post_author ) . '" target="_blank">' . $post_author . '</a>', |
| 235 |
'<a href="' . get_edit_post_link( $post_id ) . '" target="_blank">' . $post_id . '</a>' |
| 236 |
) . "<br>\n"; |
| 237 |
} |
| 238 |
} |
| 239 |
|
| 240 |
$recounted_comments = $limit * ( $loop + 1 ); |
| 241 |
|
| 242 |
// Check remaining comments |
| 243 |
if( $recounted_comments < $comments_count ) { |
| 244 |
$response['run_again'] = true; |
| 245 |
$response['message'] = sprintf( __( '%d remaining comments to finish recount', 'gamipress' ), ( $comments_count - $recounted_comments ) ); |
| 246 |
} |
| 247 |
|
| 248 |
return $response; |
| 249 |
|
| 250 |
} |
| 251 |
add_filter( 'gamipress_activity_recount_comments', 'gamipress_activity_recount_comments', 10, 4 ); |
| 252 |
|
| 253 |
/** |
| 254 |
* Recount published content |
| 255 |
* |
| 256 |
* @since 1.1.8 |
| 257 |
* @updated 1.4.2 Added $loop parameter |
| 258 |
* |
| 259 |
* @param array $response |
| 260 |
* @param int $loop |
| 261 |
* @param int $limit |
| 262 |
* @param int $offset |
| 263 |
* |
| 264 |
* @return array $response |
| 265 |
*/ |
| 266 |
function gamipress_activity_recount_published_content( $response, $loop, $limit, $offset ) { |
| 267 |
|
| 268 |
global $wpdb; |
| 269 |
|
| 270 |
// Get all public post types which means they are visitable |
| 271 |
$public_post_types = get_post_types( array( 'public' => true ) ); |
| 272 |
|
| 273 |
// Remove attachment from public post types |
| 274 |
if( isset( $public_post_types['attachment'] ) ) |
| 275 |
unset( $public_post_types['attachment'] ); |
| 276 |
|
| 277 |
// Get all published posts |
| 278 |
$posts_count = absint( $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type IN ( '" . implode( "', '", $public_post_types ) . "' )" ) ); |
| 279 |
|
| 280 |
// On first loop send an informational text |
| 281 |
if( $loop === 0 && $posts_count > $limit ) { |
| 282 |
$response['run_again'] = true; |
| 283 |
$response['message'] = sprintf( __( '%d posts found, recounting...', 'gamipress' ), $posts_count ); |
| 284 |
$response['log'] = sprintf( __( '%d posts found, recounting...', 'gamipress' ), $posts_count ) . "<br>\n"; |
| 285 |
|
| 286 |
// Return early to inform |
| 287 |
return $response; |
| 288 |
} |
| 289 |
|
| 290 |
// Get all published posts |
| 291 |
$posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type IN ( '" . implode( "', '", $public_post_types ) . "' ) LIMIT {$offset}, {$limit}" ); |
| 292 |
|
| 293 |
foreach( $posts as $post ) { |
| 294 |
// Trigger content publishing action for each post |
| 295 |
gamipress_trigger_event( array( |
| 296 |
'event' => "gamipress_publish_{$post->post_type}", |
| 297 |
'post_id' => $post->ID, |
| 298 |
'user_id' => $post->post_author, |
| 299 |
'post' => $post, |
| 300 |
) ); |
| 301 |
|
| 302 |
// Trigger post type publishing actions |
| 303 |
gamipress_trigger_event( array( |
| 304 |
'event' => 'gamipress_publish_post_type', |
| 305 |
'post_id' => $post->ID, |
| 306 |
'user_id' => $post->post_author, |
| 307 |
'post_type' => $post->post_type, |
| 308 |
'post' => $post, |
| 309 |
) ); |
| 310 |
|
| 311 |
$response['log'] .= sprintf( __( '[Publish a post] Post: %s User: %s Post Type: %s', 'gamipress' ), |
| 312 |
'<a href="' . get_edit_post_link( $post->ID ) . '" target="_blank">' . $post->ID . '</a>', |
| 313 |
'<a href="' . get_edit_user_link( $post->post_author ) . '" target="_blank">' . $post->post_author . '</a>', |
| 314 |
$post->post_type |
| 315 |
) . "<br>\n"; |
| 316 |
} |
| 317 |
|
| 318 |
$recounted_posts = $limit * ( $loop + 1 ); |
| 319 |
|
| 320 |
// Check remaining posts |
| 321 |
if( $recounted_posts < $posts_count ) { |
| 322 |
$response['run_again'] = true; |
| 323 |
$response['message'] = sprintf( __( '%d remaining posts to finish recount', 'gamipress' ), ( $posts_count - $recounted_posts ) ); |
| 324 |
} |
| 325 |
|
| 326 |
return $response; |
| 327 |
|
| 328 |
} |
| 329 |
add_filter( 'gamipress_activity_recount_published_content', 'gamipress_activity_recount_published_content', 10, 4 ); |