How-To: Achievement Categories
-
I have compiled all the code to add categories to achievements without affecting the plugin. Paul, please feel free to adopt this code at your discretion into the plugin in a future update.
What this code does:
– adds achievement categories that are specific to achievements, so as not to interfere with anything else.
– allows sorting by achievement categoryStep 1: In you child theme add the following code to your functions.php (if you don’t have one, simply create one):
/* Re-Register Custom Post Type for Achievements for WordPress ****************/ function objectToArray($d) { if (is_object($d)) { $d = get_object_vars($d); } if (is_array($d)) { return array_map(__FUNCTION__, $d); } else { return $d; } } function register_achievements_custom_taxonomy() { $labels = array( 'name' => _x( 'Achievement Categories', 'taxonomy general name' ), 'singular_name' => _x( 'Achievement Category', 'taxonomy singular name' ), 'search_items' => __( 'Search Achievement Categories' ), 'all_items' => __( 'All Achievement Categories' ), 'parent_item' => __( 'Parent Achievement Category' ), 'parent_item_colon' => __( 'Parent Achievement Category:' ), 'edit_item' => __( 'Edit Achievement Category' ), 'update_item' => __( 'Update Achievement Category' ), 'add_new_item' => __( 'Add New Achievement Category' ), 'new_item_name' => __( 'New Achievement Category' ), 'menu_name' => __( 'Categories' ), ); $args = array( 'labels' => $labels, 'hierarchical' => true, 'show_admin_column' => true, 'show_ui' => true, ); register_taxonomy( 'dpa_achievement_category', array(dpa_get_achievement_post_type(), dpa_get_progress_post_type()), $args ); } add_action( 'init', 'register_achievements_custom_taxonomy', 0 ); function register_achievements_post_type_override() { global $wp_post_types; $achievements = objectToArray(get_post_types(array('name'=>dpa_get_achievement_post_type()), 'objects')); $progresses = objectToArray(get_post_types(array('name'=>dpa_get_progress_post_type()), 'objects')); $achievements = $achievements[dpa_get_achievement_post_type()]; $progresses = $achievements[dpa_get_progress_post_type()]; $achievements["taxonomies"] = array('dpa_achievement_category'); $progresses["taxonomies"] = array('dpa_achievement_category'); unset($wp_post_types[dpa_get_achievement_post_type()]); unset($wp_post_types[dpa_get_progress_post_type()]); register_post_type( dpa_get_achievement_post_type(), $achievements ); register_post_type( dpa_get_progress_post_type(), $progresses ); } add_action( 'dpa_register_post_types', 'register_achievements_post_type_override', 6 ); function achievement_with_category_edit_columns( $columns ) { $columns = array( 'cb' => '<input type="checkbox" />', 'title' => __( 'Title', 'dpa' ), 'achievement_type' => _x( 'Type', 'Type of the achievement; award or badge', 'dpa' ), 'category' => _x('Category', 'Achievement category', 'dpa'), 'karma' => __( 'Karma Points', 'dpa' ), 'date' => __( 'Date', 'dpa' ), ); return $columns; } add_filter("manage_edit-achievement_columns", "achievement_with_category_edit_columns"); function achievement_with_category_custom_columns( $column ) { global $post; switch( $column ) { case "description": the_excerpt(); break; case "category": echo get_the_term_list( $post->ID, 'dpa_achievement_category', '', ', ', '' ); break; } } add_action("manage_posts_custom_column", "achievement_with_category_custom_columns"); function dpa_has_progress_custom( $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( 'max_num_pages' => false, // Maximum number of pages to show 'order' => 'DESC', // 'ASC', 'DESC 'orderby' => 'date', // 'meta_value', 'author', 'date', 'title', 'modified', 'parent', 'rand' 'paged' => dpa_get_paged(), // Page number 'post_status' => dpa_get_unlocked_status_id(), // Get posts in the unlocked status by default. 'post_type' => dpa_get_progress_post_type(), // Only retrieve progress posts 's' => '', // No search // Conditional defaults // If on a user's achievements page, use that author's user ID. 'author' => dpa_is_single_user_achievements() ? dpa_get_displayed_user_id() : null, // If on single achievement page, use that post's ID. 'post_parent' => dpa_is_single_achievement() ? dpa_get_achievement_id() : null, // If on a single achievement page, don't paginate progresses. //'posts_per_page' => dpa_is_single_achievement() ? -1 : dpa_get_progresses_per_page(), // Above commented out for 3.1; see https://github.com/paulgibbs/achievements/issues/70 for details 'posts_per_page' => -1, // If on a user's achievements page, fetch the achievements if we haven't got them already 'ach_populate_achievements' => dpa_is_single_user_achievements() && ! is_a( achievements()->achievement_query, 'WP_Query' ), ); $args = dpa_parse_args( $args, $defaults, 'has_progress' ); // Run the query achievements()->progress_query = new WP_Query( $args ); //var_dump(achievements()->progress_query); // If no limit to posts per page, set it to the current post_count if ( -1 == $args['posts_per_page'] ) $args['posts_per_page'] = achievements()->progress_query->post_count; // Add pagination values to query object achievements()->progress_query->posts_per_page = $args['posts_per_page']; achievements()->progress_query->paged = $args['paged']; // Only add pagination if query returned results if ( ( (int) achievements()->progress_query->post_count || (int) achievements()->progress_query->found_posts ) && (int) achievements()->progress_query->posts_per_page ) { // Limit the number of achievements shown based on maximum allowed pages if ( ( ! empty( $args['max_num_pages'] ) ) && achievements()->progress_query->found_posts > achievements()->progress_query->max_num_pages * achievements()->progress_query->post_count ) achievements()->progress_query->found_posts = achievements()->progress_query->max_num_pages * achievements()->progress_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(); // User achievements page elseif ( dpa_is_single_user_achievements() ) $base = dpa_get_user_avatar_link( array( 'type' => 'url', 'user_id' => dpa_get_displayed_user_id() ) ); // Default else $base = get_permalink( $args['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 $progress_pagination = apply_filters( 'dpa_progress_pagination', array( 'base' => $base, 'current' => (int) achievements()->progress_query->paged, 'format' => '', 'mid_size' => 1, 'next_text' => '→', 'prev_text' => '←', 'total' => ( $args['posts_per_page'] == achievements()->progress_query->found_posts ) ? 1 : ceil( (int) achievements()->progress_query->found_posts / (int) $args['posts_per_page'] ), ) ); // Add pagination to query object achievements()->progress_query->pagination_links = paginate_links( $progress_pagination ); // Remove first page from pagination achievements()->progress_query->pagination_links = str_replace( $GLOBALS['wp_rewrite']->pagination_base . "/1/'", "'", achievements()->progress_query->pagination_links ); } // If on a user's achievements page, we need to fetch the achievements if ( $args['ach_populate_achievements'] && achievements()->progress_query->have_posts() ) { $achievement_ids = wp_list_pluck( (array) achievements()->progress_query->posts, 'post_parent' ); $achievement_args = array( 'post__in' => $achievement_ids, // Only get achievements that relate to the progressses we've got. 'posts_per_page' => -1, // No pagination 'orderby' => $args['orderby'], 'order' => $args['order'], ); $achievement_args = dpa_parse_args( $args_filters, $achievement_args, 'has_achievement' ); // Run the query dpa_has_achievements_custom( $achievement_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_progress', achievements()->progress_query->have_posts() ); } function dpa_has_achievements_custom( $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( // Standard WP_Query params 'order' => 'ASC', // 'ASC', 'DESC 'orderby' => 'title', // 'meta_value', 'author', 'date', 'title', 'modified', 'parent', rand' 'max_num_pages' => false, // Maximum number of pages to show 'paged' => dpa_get_paged(), // Page number 'perm' => 'readable', // Query var value to provide statuses 'post_parent' => $default_post_parent, // Post parent 'post_type' => dpa_get_achievement_post_type(), // Only retrieve achievement posts 'posts_per_page' => dpa_get_achievements_per_page(), // Achievements per page 'ach_progress_status' => $default_progress_status, // On single user achievement page, default to only showing unlocked achievements 's' => ! empty( $_REQUEST['dpa'] ) ? $_REQUEST['dpa'] : '', // Achievements search @todo Is this implemented correctly? // Achievements params 'ach_event' => '', // Load achievements for a specific event 'ach_populate_progress' => false, // Progress post type: populate user progress for the results. 'tax_query' => array( array( 'taxonomy' => 'dpa_achievement_category', 'field' => 'id', 'terms' => get_terms( 'dpa_achievement_category', array( 'fields' => 'ids' )) )), ); // 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 ); //var_dump(achievements()->achievement_query); // 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 = achievements()->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(); // Achievements archive elseif ( dpa_is_achievement_archive() ) $base = dpa_get_achievements_url(); // Default 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' => '→', 'prev_text' => '←', '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, // Posts belonging to these author(s) 'no_found_rows' => true, // Disable SQL_CALC_FOUND_ROWS (used for pagination queries) 'post_parent' => $progress_post_ids, // Fetch progress posts with parent_id matching these 'post_status' => $args['ach_progress_status'], // Get posts in these post statuses 'posts_per_page' => -1, // No pagination ); // 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() ); }
Note that the above code creates custom versions of dpa_has_progress() and dpa_has_achievements() functions of the plugin. These custom functions might break when the plugin is updated in the future. Not sure if there is a more elegant way. The important changes here are passing the order and orderby arguments to the achievement query, and including the taxonomy in the achievement query, in total only about 10 lines of code between the two functions. Please let me know if there is a better way to do this.
Step 2: update the template file in your child theme to display achievements as needed. In my case I added /wp-content/themes/{child-theme}/achievements/loop-achievements.php, which has the following code:
<?php /** * Achievements loop * * @package Achievements * @subpackage ThemeCompatibility */ // Exit if accessed directly if ( ! defined( 'ABSPATH' ) ) exit; ?> <?php do_action( 'dpa_template_before_achievements_loop_block' ); ?> <?php do_action( 'dpa_template_before_achievements_loop' ); $previous_achievment_category = ""; while ( dpa_achievements() ) { dpa_the_achievement(); $current_category = ""; $categories = get_the_terms($post_id, 'dpa_achievement_category'); foreach($categories as $category) { if (strlen($current_category) > 0) { $current_category .= ", "; } $current_category .= $category->name; } if ($current_category != $previous_achievment_category) { $previous_achievment_category = $current_category; ?> <h3><?php echo $current_category; ?></h3> <?php } dpa_get_template_part( 'loop-single-achievement' ); } do_action( 'dpa_template_after_achievements_loop' ); ?> <?php do_action( 'dpa_template_after_achievements_loop_block' ); ?>
Step 3: add a customized content-author-achievement.php to the same directory as step two. Mine orders by taxonomy to group the different categories together, as shown in the above code in step 2.
<?php /** * Author Achievement content part * * @package Achievements * @subpackage ThemeCompatibility * */ // Exit if accessed directly if ( ! defined( 'ABSPATH' ) ) exit; ?> <div id="dpa-achievements"> <?php do_action( 'dpa_template_before_author_achievements' ); if ( dpa_has_progress_custom(array("author"=>bbp_get_user_id( null, true, false ), "ach_populate_achievements"=>true, "orderby"=>"konb_term_relationships.term_taxonomy_id")) && ! empty( achievements()->achievement_query->posts ) ) { //dpa_get_template_part( 'pagination-author-achievements' ); dpa_get_template_part( 'loop-achievements'); //dpa_get_template_part( 'pagination-author-achievements' ); } else { dpa_get_template_part( 'feedback-no-achievements' ); } do_action( 'dpa_template_after_author_achievements' ); ?> </div>
Note that in the above code, the args
"author"=>bbp_get_user_id( null, true, false ), "ach_populate_achievements"=>true
are necessary to display achievements on bbpress user profiles. On normal pages and posts I believe these can be left off.I hope this helps others — better yet, would be great if Paul can integrate this into his plugin! ?? Thanks Paul for all your work on an excellent plugin!
~Mike
- The topic ‘How-To: Achievement Categories’ is closed to new replies.