Example #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);
}
Example #2
0
/**
 * Retrieves a list of achievement posts matching criteria
 *
 * 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.
 *
 * 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_achievements($args = array())
{
    $defaults = array('ignore_sticky_posts' => true, 'no_found_rows' => true, 'order' => 'ASC', 'orderby' => 'title', 'post_type' => dpa_get_achievement_post_type(), 'posts_per_page' => -1, 'ach_event' => '');
    // 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, 'get_achievements');
    $achievements = new WP_Query();
    return apply_filters('dpa_get_achievements', $achievements->query($args), $args);
}
 /**
  * Merge the widget settings into defaults array.
  *
  * @param array $instance Optional; the instance of the widget.
  * @since Achievements (3.3)
  */
 public function parse_settings(array $instance = array())
 {
     return dpa_parse_args($instance, array('post_id' => 0), 'featured_achievement_widget_settings');
 }
Example #4
0
/**
 * The leaderboard template loop.
 *
 * Doesn't use WP_Query, but the template loop and its data are structured in a vaguely similar
 * way to the dpa_has_achievements() and dpa_has_progress() loops (which do use WP_Query).
 *
 * @param array $args Optional. Associative array of optional arguments. See function for details.
 * @return bool Returns true if the query had any results to loop over
 * @since Achievements (3.4)
 */
function dpa_has_leaderboard($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);
    }
    $defaults = array('paged' => dpa_get_leaderboard_paged(), 'posts_per_page' => dpa_get_leaderboard_items_per_page(), 'user_ids' => array());
    $args = dpa_parse_args($args, $defaults, 'has_leaderboard');
    // Run the query
    achievements()->leaderboard_query = dpa_get_leaderboard($args);
    // Only add pagination if query returned results
    if ((count(achievements()->leaderboard_query['results']) || achievements()->leaderboard_query['total']) && $args['posts_per_page']) {
        // If a top-level /leaderboard/ rewrite is ever added, we can make this use pretty pagination. Also see dpa_get_leaderboard_paged().
        $base = add_query_arg('leaderboard-page', '%#%');
        // Pagination settings with filter
        $leaderboard_pagination = apply_filters('dpa_leaderboard_pagination', array('base' => $base, 'current' => $args['paged'], 'format' => '', 'mid_size' => 1, 'next_text' => is_rtl() ? '←' : '→', 'prev_text' => is_rtl() ? '→' : '←', 'total' => (int) $args['posts_per_page'] === achievements()->leaderboard_query['total'] ? 1 : ceil(achievements()->leaderboard_query['total'] / (int) $args['posts_per_page'])));
        achievements()->leaderboard_query['paged'] = (int) $args['paged'];
        achievements()->leaderboard_query['pagination_links'] = paginate_links($leaderboard_pagination);
        achievements()->leaderboard_query['posts_per_page'] = (int) $args['posts_per_page'];
    }
    // 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_leaderboard', !empty(achievements()->leaderboard_query['results']));
}
 /**
  * Merge the widget settings into defaults array.
  *
  * @param array $instance Optional; the instance of the widget.
  * @since Achievements (3.4)
  */
 public function parse_settings(array $instance = array())
 {
     return dpa_parse_args($instance, array('title' => __('Leaderboard', 'achievements')), 'leaderboard_widget_settings');
 }
 /**
  * Wrapper for deleting Achievements actions from the BuddyPress activity stream.
  *
  * @param array $args Array of arguments for bp_activity_add().
  * @return int|bool Activity ID if successful, false if not.
  * @since Achievements (3.2)
  */
 public function delete_activity($args = array())
 {
     $activity = dpa_parse_args($args, array('component' => $this->component, 'item_id' => false, 'secondary_item_id' => false, 'type' => false, 'user_id' => false), 'delete_activity');
     bp_activity_delete_by_item_id($activity);
 }
Example #7
0
/**
 * Return a fancy description of the achievements on the site, including the
 * number of public and hidden achievements, and the username and avatar of
 * the most recent person who unlocked the achievement.
 *
 * @param mixed $args This function supports these arguments:
 *  - before: Before the text
 *  - after: After the text
 *  - size: Size of the avatar
 * @return string Fancy description
 * @since Achievements (3.0)
 */
function dpa_get_achievements_index_description($args = '')
{
    $defaults = array('after' => '</p></div>', 'before' => '<div class="dpa-template-notice info"><p class="dpa-achievements-description">', 'size' => 14);
    $r = dpa_parse_args($args, $defaults, 'get_achievements_index_description');
    extract($r);
    // Get count of total achievements
    $achievement_count = dpa_get_total_achievement_count();
    $achievement_text = sprintf(_n('%s achievement', '%s achievements', $achievement_count, 'achievements'), number_format_i18n($achievement_count));
    // Get data on the most recent unlocked achievement
    $recent_achievement_id = dpa_stats_get_last_achievement_id();
    $recent_user_id = dpa_stats_get_last_achievement_user_id();
    if (!empty($recent_user_id) && !empty($recent_achievement_id)) {
        // Check user ID is still valid
        $user = get_userdata($recent_user_id);
        if (!empty($user) && dpa_is_user_active($user)) {
            // Check achievement ID is valid
            $achievement = get_post($recent_achievement_id);
            if (!empty($achievement) && 'publish' === $achievement->post_status) {
                // Combine all the things to build the output text
                $retstr = sprintf(__('This site has %1$s, and the last unlocked was <a href="%2$s">%3$s</a> by %4$s.', 'achievements'), $achievement_text, esc_url(get_permalink($achievement->ID)), esc_html(apply_filters('dpa_get_achievement_title', $achievement->post_title, $achievement->ID)), dpa_get_user_avatar_link(array('size' => $size, 'user_id' => $user->ID)));
            }
        }
    }
    // If we haven't set a more specific description, fall back to the default.
    if (!isset($retstr)) {
        $retstr = sprintf(__('This site has %1$s.', 'achievements'), $achievement_text);
    }
    $retstr = $before . $retstr . $after;
    return apply_filters('dpa_get_achievements_index_description', $retstr, $args);
}
Example #8
0
/**
 * Return a link to the profile of the user who the achievement progress belongs to.
 *
 * @param array $args See dpa_get_user_avatar_link() documentation.
 * @return string
 * @since Achievements (3.0)
 */
function dpa_get_progress_user_link($args = array())
{
    $defaults = array('type' => 'name', 'user_id' => dpa_get_progress_author_id());
    $args = dpa_parse_args($args, $defaults, 'get_progress_user_link');
    // Return the user's avatar link
    return apply_filters('dpa_get_progress_user_link', dpa_user_avatar_link($args), $args);
}
Example #9
0
/**
 * Custom page title for Achievements pages
 *
 * @param string $title Optional. The title (not used).
 * @param string $sep Optional, default is '&raquo;'. How to separate each part within the page title.
 * @param string $seplocation Optional. Direction to display title, 'right'.
 * @return string The title
 * @since Achievements (3.0)
 */
function dpa_title($title = '', $sep = '&raquo;', $seplocation = '')
{
    $new_title = array();
    // Achievement archive
    if (dpa_is_achievement_archive()) {
        $new_title['text'] = dpa_get_achievement_archive_title();
        // Single achievement page
    } elseif (dpa_is_single_achievement()) {
        $new_title['text'] = dpa_get_achievement_title();
        $new_title['format'] = esc_attr__('Achievement: %s', 'achievements');
    }
    $new_title = apply_filters('dpa_raw_title_array', $new_title);
    $new_title = dpa_parse_args($new_title, array('format' => '%s', 'text' => $title), 'title');
    // Get the formatted raw title
    $new_title = sprintf($new_title['format'], $new_title['text']);
    $new_title = apply_filters('dpa_raw_title', $new_title, $sep, $seplocation);
    // Compare new title with original title
    if ($new_title === $title) {
        return $title;
    }
    // Temporary separator for accurate flipping, if necessary
    $t_sep = '%WP_TITILE_SEP%';
    $prefix = '';
    if (!empty($new_title)) {
        $prefix = " {$sep} ";
    }
    // Separate on right, so reverse the order
    if ('right' === $seplocation) {
        $new_title_array = explode($t_sep, $new_title);
        $new_title_array = array_reverse($new_title_array);
        $new_title = implode(" {$sep} ", $new_title_array) . $prefix;
        // Separate on left, do not reverse
    } else {
        $new_title_array = explode($t_sep, $new_title);
        $new_title = $prefix . implode(" {$sep} ", $new_title_array);
    }
    // Filter and return
    return apply_filters('dpa_title', $new_title, $sep, $seplocation);
}
 /**
  * Merge the widget settings into defaults array.
  *
  * @param array $instance Optional; the instance of the widget.
  * @since Achievements (3.3)
  */
 public function parse_settings(array $instance = array())
 {
     return dpa_parse_args($instance, array('limit' => 40, 'title' => __('Available achievements', 'achievements')), 'available_achievements_widget_settings');
 }
/**
 * This fun little function fills up some WordPress globals with dummy data to
 * stop your average page template from complaining about it missing.
 *
 * @global WP_Query $wp_query
 * @global object $post
 * @param array $args Optional
 * @since Achievements (3.0)
 */
function dpa_theme_compat_reset_post($args = array())
{
    global $wp_query, $post;
    // Switch defaults if post is set
    if (isset($wp_query->post)) {
        $dummy = dpa_parse_args($args, array('comment_count' => $wp_query->post->comment_count, 'comment_status' => $wp_query->post->comment_status, 'filter' => $wp_query->post->filter, 'guid' => $wp_query->post->guid, 'ID' => $wp_query->post->ID, 'menu_order' => $wp_query->post->menu_order, 'pinged' => $wp_query->post->pinged, 'ping_status' => $wp_query->post->ping_status, 'post_author' => $wp_query->post->post_author, 'post_content' => $wp_query->post->post_content, 'post_content_filtered' => $wp_query->post->post_content_filtered, 'post_date' => $wp_query->post->post_date, 'post_date_gmt' => $wp_query->post->post_date_gmt, 'post_excerpt' => $wp_query->post->post_excerpt, 'post_mime_type' => $wp_query->post->post_mime_type, 'post_modified' => $wp_query->post->post_modified, 'post_modified_gmt' => $wp_query->post->post_modified_gmt, 'post_name' => $wp_query->post->post_name, 'post_parent' => $wp_query->post->post_parent, 'post_password' => $wp_query->post->post_password, 'post_status' => $wp_query->post->post_status, 'post_title' => $wp_query->post->post_title, 'post_type' => $wp_query->post->post_type, 'to_ping' => $wp_query->post->to_ping, 'is_404' => false, 'is_archive' => false, 'is_page' => false, 'is_single' => false, 'is_tax' => false), 'theme_compat_reset_post');
    } else {
        $dummy = dpa_parse_args($args, array('comment_count' => 0, 'comment_status' => 'closed', 'filter' => 'raw', 'ID' => -9999, 'guid' => '', 'menu_order' => 0, 'pinged' => '', 'ping_status' => '', 'post_author' => 0, 'post_content' => '', 'post_content_filtered' => '', 'post_date' => 0, 'post_date_gmt' => 0, 'post_excerpt' => '', 'post_mime_type' => '', 'post_modified' => 0, 'post_modified_gmt' => 0, 'post_name' => '', 'post_parent' => 0, 'post_password' => '', 'post_status' => 'publish', 'post_title' => '', 'post_type' => 'page', 'to_ping' => '', 'is_404' => false, 'is_archive' => false, 'is_page' => false, 'is_single' => false, 'is_tax' => false), 'theme_compat_reset_post');
    }
    // Bail if dummy post is empty
    if (empty($dummy)) {
        return;
    }
    // Set the $post global
    $post = new WP_Post((object) $dummy);
    // Copy the new post global into the main $wp_query
    $wp_query->post = $post;
    $wp_query->posts = array($post);
    // Prevent comments form from appearing
    $wp_query->post_count = 1;
    $wp_query->is_404 = $dummy['is_404'];
    $wp_query->is_page = $dummy['is_page'];
    $wp_query->is_single = $dummy['is_single'];
    $wp_query->is_archive = $dummy['is_archive'];
    $wp_query->is_tax = $dummy['is_tax'];
    unset($dummy);
    // If we are resetting a post, we are in theme compat
    dpa_set_theme_compat_active(true);
}
Example #12
0
/**
 * Get the current state of the leaderboard, sorted by users' karma points.
 *
 * 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.
 *
 * This function accept a 'user_ids' parameter in the $argument, which accepts an array of user IDs.
 * It is only useful if you want to create a leaderboard that only contains the specified users; for example,
 * you and your friends could have your own mini-league, or in BuddyPress, each Group could have its own leaderboard.
 *
 * It is totally useless if you're trying to find the position for one or more specific users in the *overall* leaderboard.
 *
 * @param array $args Optional. Associative array of optional arguments. See function for details.
 * @return array|bool If no results, false. Otherwise, an associative array: array('results' => array([0] => array('rank' => int, 'user_id' => int, 'karma' => int, 'display_name' => string), ...), 'total' => int).
 * @since Achievements (3.4)
 */
function dpa_get_leaderboard(array $args = array())
{
    global $wpdb;
    $defaults = array('paged' => dpa_get_leaderboard_paged(), 'populate_extras' => true, 'posts_per_page' => dpa_get_leaderboard_items_per_page(), 'user_ids' => array());
    $args = dpa_parse_args($args, $defaults, 'get_leaderboard');
    $points_key = "{$wpdb->prefix}_dpa_points";
    $num_users = empty($args['user_ids']) ? 0 : count((array) $args['user_ids']);
    // No, we're not allowing infinite results. This is always a bad idea.
    if ((int) $args['posts_per_page'] < 1) {
        $args['posts_per_page'] = dpa_get_leaderboard_items_per_page();
    }
    // We use this later to help get/set the object cache
    $last_changed = wp_cache_get('last_changed', 'achievements_leaderboard');
    if ($last_changed === false) {
        $last_changed = microtime();
        wp_cache_add('last_changed', $last_changed, 'achievements_leaderboard');
    }
    /**
     * 1) Get all the distinct values of the _dpa_points keys from the usermeta table.
     *
     * We do the SELECT DISTINCT and sorting in PHP because meta_value is not indexed; this would cause use MySQL to use a temp table.
     */
    $points_query = $wpdb->prepare("SELECT meta_value\n\t\tFROM {$wpdb->usermeta}\n\t\tWHERE meta_key = %s", $points_key);
    if ($num_users > 0) {
        $points_query .= $wpdb->prepare(' AND user_id IN (' . implode(',', wp_parse_id_list((array) $args['user_ids'])) . ') LIMIT %d', $num_users);
    }
    // Only query if not in cache
    $points_cache_key = 'get_leaderboard_points' . md5(serialize($points_query)) . ":{$last_changed}";
    $points = wp_cache_get($points_cache_key, 'achievements_leaderboard_ids');
    if ($points === false) {
        $points = $wpdb->get_col($points_query);
        wp_cache_add($points_cache_key, $points, 'achievements_leaderboard_ids');
    }
    if (empty($points)) {
        // If points is empty, no-one has any karma, so bail out.
        return array('results' => array(), 'total' => 0);
    }
    /**
     * Can't use wp_parse_id_list() here because that casts the values to unsigned ints.
     * The leaderboard might contain users with negative karma point totals.
     */
    $points = array_unique(array_map('intval', $points));
    rsort($points, SORT_NUMERIC);
    // Sort descending for FIND_IN_SET
    $points = implode(',', $points);
    // Format for FIND_IN_SET
    /**
     * 2a) Start building the SQL to get each user's rank, user ID, and points total.
     */
    $query = $wpdb->prepare("SELECT SQL_CALC_FOUND_ROWS FIND_IN_SET( karma.meta_value, %s ) as rank, ID as user_id, karma.meta_value as karma\n\t\tFROM {$wpdb->users} AS person\n\t\tINNER JOIN {$wpdb->usermeta} as karma ON person.ID = karma.user_id AND karma.meta_key = %s", $points, $points_key);
    /**
     * 2b) Sort users correctly even if some of them don't have any karma points.
     *
     * `ORDER BY... rank` causes a filesort because usermeta has no index on meta_value :(
     */
    $query .= ' ORDER BY CASE WHEN rank IS NULL THEN 1 ELSE 0 END, rank';
    /**
     * 2c) Handle pagination
     */
    $offset = ((int) $args['paged'] - 1) * (int) $args['posts_per_page'];
    $query .= $wpdb->prepare(' LIMIT %d, %d', $offset, $args['posts_per_page']);
    /**
     * 3) Run the query and cache results
     */
    $cache_key = 'get_leaderboard:' . md5(serialize($query)) . ":{$last_changed}";
    $results = wp_cache_get($cache_key, 'achievements_leaderboard');
    // Only query if not in cache
    if ($results === false) {
        $results = $wpdb->get_results($query);
        $results_found = $wpdb->get_var('SELECT FOUND_ROWS()');
        // All the returned values should be ints, not strings, so cast them here.
        foreach ($results as $result) {
            foreach ($result as &$value) {
                $value = (int) $value;
            }
        }
        $results = array('results' => $results, 'total' => (int) $results_found);
        wp_cache_add($cache_key, $results, 'achievements_leaderboard');
    }
    /**
     * 4) Maybe get users' display names
     */
    if ($args['populate_extras']) {
        $users = get_users(array('fields' => array('ID', 'display_name'), 'include' => wp_list_pluck($results['results'], 'user_id')));
        // For now, handle any cached user IDs for spammers or deleted users by setting a blank display name.
        foreach ($results['results'] as &$leaderboard_user) {
            $leaderboard_user->display_name = '';
        }
        foreach ($users as $user) {
            foreach ($results['results'] as &$leaderboard_user) {
                if ((int) $user->ID === $leaderboard_user->user_id) {
                    $leaderboard_user->display_name = $user->display_name;
                    break;
                }
            }
        }
    }
    // Why an ArrayObject? See http://stackoverflow.com/questions/10454779/php-indirect-modification-of-overloaded-property
    return apply_filters('dpa_get_leaderboard', new ArrayObject($results), $defaults, $args, $points_cache_key, $cache_key);
}