예제 #1
0
/**
 * Retrieves a list of progress posts matching criteria
 *
 * If you try to use this function, you will need to implement your own switch_to_blog and wp_reset_postdata() handling if running in a multisite
 * and in a dpa_is_running_networkwide() configuration, otherwise the data won't be fetched from the appropriate site.
 *
 * @param array|string $args All the arguments supported by {@link WP_Query}, and some more.
 * @return array Posts
 * @since Achievements (3.0)
 */
function dpa_get_progress($args = array())
{
    $defaults = array('no_found_rows' => true, 'order' => 'DESC', 'orderby' => 'date', 'post_type' => dpa_get_progress_post_type(), 'posts_per_page' => -1, 'post_status' => array(dpa_get_locked_status_id(), dpa_get_unlocked_status_id()));
    $args = dpa_parse_args($args, $defaults, 'get_progress');
    $progress = new WP_Query();
    return apply_filters('dpa_get_progress', $progress->query($args), $args);
}
 /**
  * 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']));
 }
예제 #3
0
/**
 * Called before a post is deleted; if an achievement post, we tidy up any related Progress posts.
 * 
 * This function is supplemental to the actual achievement deletion which is handled by WordPress core API functions.
 * It is used to clean up after an achievement that is being deleted.
 *
 * @param int $post_id Optional; post ID that is being deleted.
 * @since Achievements (3.0)
 */
function dpa_before_achievement_deleted($post_id = 0)
{
    $post_id = dpa_get_achievement_id($post_id);
    if (empty($post_id) || !dpa_is_achievement($post_id)) {
        return;
    }
    do_action('dpa_before_achievement_deleted', $post_id);
    // An achievement is being permanently deleted, so any related Progress posts have to go, too.
    $progress = new WP_Query(array('fields' => 'id=>parent', 'nopaging' => true, 'post_parent' => $post_id, 'post_status' => array(dpa_get_locked_status_id(), dpa_get_unlocked_status_id()), 'post_type' => dpa_get_progress_post_type(), 'posts_per_page' => -1));
    if (empty($progress)) {
        return;
    }
    foreach ($progress->posts as $post) {
        wp_delete_post($post->ID, true);
    }
}
예제 #4
0
/**
 * The achievement post type loop.
 *
 * Most of the values that $args can accept are documented in {@link WP_Query}. The custom
 * values added by Achievements are as follows:
 *
 * 'ach_event'             - string   - Loads achievements for a specific event. Matches a slug from the dpa_event tax. Default is empty.
 * 'ach_populate_progress' - bool|int - Populate a user/users' progress for the results.
 *                                    - bool: True - uses the logged in user (default). False - don't fetch progress.
 *                                    - int: pass a user ID (single user).
 * 'ach_progress_status'   - array    - array: Post status IDs for the Progress post type.
 *
 * @param array|string $args All the arguments supported by {@link WP_Query}, and some more.
 * @return bool Returns true if the query has any results to loop over
 * @since Achievements (1.0)
 */
function dpa_has_achievements($args = 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);
    }
    $default_post_parent = dpa_is_single_achievement() ? dpa_get_achievement_id() : 'any';
    $default_progress_status = dpa_is_single_user_achievements() ? array(dpa_get_unlocked_status_id()) : array(dpa_get_locked_status_id(), dpa_get_unlocked_status_id());
    $defaults = array('ignore_sticky_posts' => true, 'order' => 'ASC', 'orderby' => 'title', 'max_num_pages' => false, 'paged' => dpa_get_paged(), 'perm' => 'readable', 'post_parent' => $default_post_parent, 'post_type' => dpa_get_achievement_post_type(), 'posts_per_page' => dpa_get_achievements_per_page(), 'ach_progress_status' => $default_progress_status, 's' => !empty($_GET['achievements']) ? wp_unslash($_GET['achievements']) : '', 'ach_event' => '', 'ach_populate_progress' => false);
    // Load achievements for a specific event
    if (!empty($args['ach_event'])) {
        $args['tax_query'] = array(array('field' => 'slug', 'taxonomy' => dpa_get_event_tax_id(), 'terms' => $args['ach_event']));
        unset($args['ach_event']);
    }
    $args = dpa_parse_args($args, $defaults, 'has_achievements');
    extract($args);
    // Run the query
    achievements()->achievement_query = new WP_Query($args);
    // User to popular progress for
    $progress_user_ids = false;
    if (isset($args['ach_populate_progress'])) {
        if (true === $args['ach_populate_progress']) {
            if (dpa_is_single_user_achievements()) {
                $progress_user_ids = dpa_get_displayed_user_id();
            } elseif (is_user_logged_in()) {
                $progress_user_ids = get_current_user_id();
            }
        } else {
            $progress_user_ids = (int) $args['ach_populate_progress'];
        }
    }
    // If no limit to posts per page, set it to the current post_count
    if (-1 === $posts_per_page) {
        $posts_per_page = achievements()->achievement_query->post_count;
    }
    // Add pagination values to query object
    achievements()->achievement_query->posts_per_page = $posts_per_page;
    achievements()->achievement_query->paged = $paged;
    // Only add pagination if query returned results
    if (((int) achievements()->achievement_query->post_count || (int) achievements()->achievement_query->found_posts) && (int) achievements()->achievement_query->posts_per_page) {
        // Limit the number of achievements shown based on maximum allowed pages
        if (!empty($max_num_pages) && achievements()->achievement_query->found_posts > achievements()->achievement_query->max_num_pages * achievements()->achievement_query->post_count) {
            achievements()->achievement_query->found_posts = achievements()->achievement_query->max_num_pages * achievements()->achievement_query->post_count;
        }
        // If pretty permalinks are enabled, make our pagination pretty
        if ($GLOBALS['wp_rewrite']->using_permalinks()) {
            // Page or single post
            if (is_page() || is_single()) {
                $base = get_permalink();
            } elseif (dpa_is_achievement_archive()) {
                $base = dpa_get_achievements_url();
            } else {
                $base = get_permalink($post_parent);
            }
            // Use pagination base
            $base = trailingslashit($base) . user_trailingslashit($GLOBALS['wp_rewrite']->pagination_base . '/%#%/');
            // Unpretty pagination
        } else {
            $base = add_query_arg('paged', '%#%');
        }
        // Pagination settings with filter
        $achievement_pagination = apply_filters('dpa_achievement_pagination', array('base' => $base, 'current' => (int) achievements()->achievement_query->paged, 'format' => '', 'mid_size' => 1, 'next_text' => is_rtl() ? '&larr;' : '&rarr;', 'prev_text' => is_rtl() ? '&rarr;' : '&larr;', 'total' => $posts_per_page == achievements()->achievement_query->found_posts ? 1 : ceil((int) achievements()->achievement_query->found_posts / (int) $posts_per_page)));
        // Add pagination to query object
        achievements()->achievement_query->pagination_links = paginate_links($achievement_pagination);
        // Remove first page from pagination
        achievements()->achievement_query->pagination_links = str_replace($GLOBALS['wp_rewrite']->pagination_base . "/1/'", "'", achievements()->achievement_query->pagination_links);
    }
    // Populate extra progress information for the achievements
    if (!empty($progress_user_ids) && achievements()->achievement_query->have_posts()) {
        $progress_post_ids = wp_list_pluck((array) achievements()->achievement_query->posts, 'ID');
        // Args for progress query
        $progress_args = array('author' => $progress_user_ids, 'no_found_rows' => true, 'post_parent' => $progress_post_ids, 'post_status' => $args['ach_progress_status'], 'posts_per_page' => -1);
        // Run the query
        dpa_has_progress($progress_args);
    }
    // If multisite and running network-wide, undo the switch_to_blog
    if (is_multisite() && dpa_is_running_networkwide()) {
        restore_current_blog();
    }
    return apply_filters('dpa_has_achievements', achievements()->achievement_query->have_posts());
}
예제 #5
0
/**
 * If the specified achievement's criteria has been met, we unlock the
 * achievement. Otherwise we record progress for the achievement for next time.
 *
 * $skip_validation is the second parameter for backpat with Achievements 2.x
 *
 * @param int     $user_id
 * @param string  $skip_validation  Optional. Set to "skip_validation" to skip Achievement validation (unlock achievement regardless of criteria).
 * @param object  $progress_obj     Optional. The Progress post object. Defaults to Progress object in the Progress loop.
 * @param object  $achievement_obj  Optional. The Achievement post object to maybe_unlock. Defaults to current object in Achievement loop.
 * @since Achievements (2.0)
 */
function dpa_maybe_unlock_achievement($user_id, $skip_validation = '', $progress_obj = null, $achievement_obj = null)
{
    // Only proceed if the specified user is active (logged in and not a spammer)
    if (!dpa_is_user_active($user_id)) {
        return;
    }
    // Only proceed if the specified user can create progress posts
    if (!user_can($user_id, 'publish_achievement_progresses')) {
        return;
    }
    // Default to current object in the achievement loop
    if (empty($achievement_obj)) {
        $achievement_obj = achievements()->achievement_query->post;
    }
    // Default to progress object in the progress loop
    if (empty($progress_obj) && !empty(achievements()->progress_query->posts)) {
        $progress_obj = wp_filter_object_list(achievements()->progress_query->posts, array('post_parent' => $achievement_obj->ID));
        $progress_obj = array_shift($progress_obj);
    }
    // Has the user already unlocked the achievement?
    if (!empty($progress_obj) && dpa_get_unlocked_status_id() === $progress_obj->post_status) {
        return;
    }
    // Prepare default values to create/update a progress post
    $progress_args = array('comment_status' => 'closed', 'ping_status' => 'closed', 'post_author' => $user_id, 'post_parent' => $achievement_obj->ID, 'post_title' => $achievement_obj->post_title, 'post_type' => dpa_get_progress_post_type());
    // If achievement already has some progress, grab the ID so we update the post later
    if (!empty($progress_obj->ID)) {
        $progress_args['ID'] = $progress_obj->ID;
    }
    // If the achievement does not have a target set, this is an award achievement.
    $achievement_target = dpa_get_achievement_target($achievement_obj->ID);
    if ($achievement_target) {
        // Increment progress count
        $progress_args['post_content'] = apply_filters('dpa_maybe_unlock_achievement_progress_increment', 1);
        if (!empty($progress_obj)) {
            $progress_args['post_content'] = (int) $progress_args['post_content'] + (int) $progress_obj->post_content;
        }
    }
    // Does the progress count now meet the achievement target?
    if ('skip_validation' === $skip_validation || $achievement_target && (int) $progress_args['post_content'] >= $achievement_target) {
        // Yes. Unlock achievement.
        $progress_args['post_status'] = dpa_get_unlocked_status_id();
        // No, user needs to make more progress. Make sure the locked status is set correctly.
    } else {
        $progress_args['post_status'] = dpa_get_locked_status_id();
    }
    // Create or update the progress post
    $progress_id = wp_insert_post($progress_args);
    // If the achievement was just unlocked, do stuff.
    if (dpa_get_unlocked_status_id() === $progress_args['post_status']) {
        // Achievement was unlocked. Notifications and points updates are hooked to this function.
        do_action('dpa_unlock_achievement', $achievement_obj, $user_id, $progress_id);
    }
}
예제 #6
0
 /**
  * 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();
     }
 }
예제 #7
0
 /**
  * Register the post statuses used by Achievements
  *
  * @since Achievements (3.0)
  */
 public function register_post_statuses()
 {
     // Locked
     register_post_status(dpa_get_locked_status_id(), apply_filters('dpa_register_locked_post_status', array('label' => _x('Locked', 'achievement', 'achievements'), 'label_count' => _nx_noop('Locked <span class="count">(%s)</span>', 'Locked <span class="count">(%s)</span>', 'achievement', 'achievements'), 'public' => false, 'exclude_from_search' => true, 'show_in_admin_status_list' => true, 'show_in_admin_all_list' => true)));
     // Unlocked
     register_post_status(dpa_get_unlocked_status_id(), apply_filters('dpa_register_unlocked_post_status', array('label' => _x('Unlocked', 'achievement', 'achievements'), 'label_count' => _nx_noop('Unlocked <span class="count">(%s)</span>', 'Unlocked <span class="count">(%s)</span>', 'achievement', 'achievements'), 'public' => false, 'exclude_from_search' => true, 'show_in_admin_status_list' => true, 'show_in_admin_all_list' => true)));
 }