/** * Delete a user's progress for an achievement. Essentially, un-reward the achievement for this user. * * @param int $achievement_id Achievement ID * @param int $user_id User ID * @since Achievements (3.0) */ function dpa_delete_achievement_progress($achievement_id, $user_id) { $achievement_id = dpa_get_achievement_id($achievement_id); if (empty($achievement_id) || !dpa_is_achievement($achievement_id)) { return; } $progress_id = dpa_get_progress(array('author' => $user_id, 'fields' => 'ids', 'no_found_rows' => true, 'nopaging' => true, 'numberposts' => 1, 'post_parent' => $achievement_id)); if (empty($progress_id)) { return; } $progress_id = apply_filters('dpa_delete_achievement_progress', array_pop($progress_id), $achievement_id, $user_id); do_action('dpa_before_delete_achievement_progress', $progress_id, $achievement_id, $user_id); wp_delete_post($progress_id, true); // Check that the delete achievement isn't in the user's pending notifications $notifications = dpa_get_user_notifications($user_id); if (isset($notifications[$achievement_id])) { unset($notifications[$achievement_id]); } // Update the user's notifications in case we cleared any above dpa_update_user_notifications($notifications, $user_id); // Decrease user unlocked count dpa_update_user_unlocked_count($user_id, dpa_get_user_unlocked_count($user_id) - 1); /** * If the progress was linked to an achievement that is the same achievement that is stored in * this user's "last unlocked" meta, then clear the "last unlocked" meta, too. */ if ((int) dpa_get_user_last_unlocked($user_id) === $achievement_id) { dpa_update_user_last_unlocked($user_id, 0); } do_action('dpa_after_delete_achievement_progress', $progress_id, $achievement_id, $user_id); }
/** * Award an achievement to a user * * @alias add * @since Achievements (3.4) * @synopsis --user_id=<id> --achievement=<postname> */ public function award($args, $assoc_args) { if (!$assoc_args['user_id'] || !get_userdata($assoc_args['user_id'])) { WP_CLI::error('Invalid User ID specified.'); } // Get the achievement ID $achievement_id = $this->_get_achievement_id_by_post_name($assoc_args['achievement']); if (!$achievement_id) { WP_CLI::error(sprintf('Achievement ID not found for post_name: %1$s', $achievement_id)); } // If the user has already unlocked this achievement, bail out. if (dpa_has_user_unlocked_achievement($assoc_args['user_id'], $achievement_id)) { WP_CLI::warning(sprintf('User ID %1$s has already unlocked achievement ID %2$s', $assoc_args['user_id'], $achievement_id)); return; } $achievement_obj = dpa_get_achievements(array('no_found_rows' => true, 'nopaging' => true, 'numberposts' => 1, 'p' => $achievement_id)); $achievement_obj = $achievement_obj[0]; // Find any still-locked progress for this achievement for this user, as dpa_maybe_unlock_achievement() needs it. $progress_obj = dpa_get_progress(array('author' => $assoc_args['user_id'], 'no_found_rows' => true, 'nopaging' => true, 'numberposts' => 1, 'post_status' => dpa_get_locked_status_id())); if (empty($progress_obj)) { $progress_obj = array(); } // Award the achievement dpa_maybe_unlock_achievement($assoc_args['user_id'], 'skip_validation', $progress_obj, $achievement_obj); WP_CLI::success(sprintf('Achievement ID %1$s has been awarded to User ID %2$s', $achievement_id, $assoc_args['user_id'])); }
/** * Has a specific user unlocked a specific achievement? * * @param int $user_id * @param int $achievement_id * @return bool True if user has unlocked the achievement * @since Achievements (3.4) */ function dpa_has_user_unlocked_achievement($user_id, $achievement_id) { if (!dpa_is_user_active($user_id)) { return false; } $achievement_id = dpa_get_achievement_id($achievement_id); if (empty($achievement_id) || !dpa_is_achievement($achievement_id)) { return false; } // Try to fetched an unlocked progress item for this user pair/achievement pair $progress = dpa_get_progress(array('author' => $user_id, 'fields' => 'ids', 'no_found_rows' => true, 'nopaging' => true, 'numberposts' => 1, 'post_parent' => $achievement_id, 'post_status' => dpa_get_unlocked_status_id())); return apply_filters('dpa_has_user_unlocked_achievement', !empty($progress), $progress, $user_id, $achievement_id); }
/** * Update the user's "User Points" meta information when the Edit User page has been saved, * and modify the user's current achievements as appropriate. * * The action that this function is hooked to is only executed on a succesful update, * which is behind a nonce and capability check (see wp-admin/user-edit.php). * * @param int $user_id * @since Achievements (3.0) */ public function save_profile_fields($user_id) { if (!isset($_POST['dpa_achievements']) || !is_super_admin()) { return; } if (!isset($_POST['dpa_user_achievements'])) { $_POST['dpa_user_achievements'] = array(); } // If multisite and running network-wide, switch_to_blog to the data store site if (is_multisite() && dpa_is_running_networkwide()) { switch_to_blog(DPA_DATA_STORE); } // Update user's points dpa_update_user_points((int) $_POST['dpa_achievements'], $user_id); // Get unlocked achievements $unlocked_achievements = dpa_get_progress(array('author' => $user_id, 'post_status' => dpa_get_unlocked_status_id())); $old_unlocked_achievements = wp_list_pluck($unlocked_achievements, 'post_parent'); $new_unlocked_achievements = array_filter(wp_parse_id_list($_POST['dpa_user_achievements'])); // Figure out which achievements to add or remove $achievements_to_add = array_diff($new_unlocked_achievements, $old_unlocked_achievements); $achievements_to_remove = array_diff($old_unlocked_achievements, $new_unlocked_achievements); // Remove achievements :( if (!empty($achievements_to_remove)) { foreach ($achievements_to_remove as $achievement_id) { dpa_delete_achievement_progress($achievement_id, $user_id); } } // Award achievements! :D if (!empty($achievements_to_add)) { // Get achievements to add $new_achievements = dpa_get_achievements(array('post__in' => $achievements_to_add, 'posts_per_page' => count($achievements_to_add))); // Get any still-locked progress for this user $existing_progress = dpa_get_progress(array('author' => $user_id, 'post_status' => dpa_get_locked_status_id())); foreach ($new_achievements as $achievement_obj) { $progress_obj = array(); // If we have existing progress, pass that to dpa_maybe_unlock_achievement(). foreach ($existing_progress as $progress) { if ($achievement_obj->ID === $progress->post_parent) { $progress_obj = $progress; break; } } dpa_maybe_unlock_achievement($user_id, 'skip_validation', $progress_obj, $achievement_obj); } } // If multisite and running network-wide, undo the switch_to_blog if (is_multisite() && dpa_is_running_networkwide()) { restore_current_blog(); } }