0

I have a site with about 1,000 posts spread out over 70 or 80 categories. Some of these categories require the posts be sorted by a custom field, others not.

I've got a working solution by having 60+ category template files defined (e.g. category-123.php, category-124.php) and each of those calls a separate loop file:

get_template_part( 'loop-123', 'category' );

The loop-123 file then runs a new query and sorts it correctly before passing it to the loop:

<?php
$the_query = new WP_Query("cat=123&meta_key=programnumber&orderby=meta_value&order=ASC");
?>
<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>

However, there has to be a more efficient way to do this than to create 60+ file pairs. I'm just not seeing it, though.

2 Answers 2

2

I would suggest to hook onto pre_get_posts and alter the query, rather than firing off your own in the template (it keeps your template tidy, and you'll avoid doubling your database queries!).

Below demonstrates this, plus a bonus settings field in the admin (under "Reading") to select the categories that "special sorting" applies to - see how easy the settings API really is!

/**
 * Intercept the query & attach our own parameters if the conditions are met.
 */
function wpse_42457_custom_category_order( $wp_query )
{
    if ( ! $wp_query->is_category() ) // save proceeding processing
        return;

    $special_categories = wp_parse_id_list( get_option( 'sorted_categories' ) );
    if ( $wp_query->is_category( $special_categories ) ) {

        // We've got a winner - set our special params.
        $wp_query->set( 'meta_key', 'programnumber' );
        $wp_query->set( 'orderby', 'meta_value' );
        $wp_query->set( 'order', 'ASC' );
    }
}
add_action( 'pre_get_posts', 'wpse_42457_custom_category_order' );

/**
 * Register the sorted categories option & the settings field.
 */
function wpse_42457_admin_init()
{
    add_settings_field( 'sorted_categories', 'Special Categories', 'wpse_42457_setting_field', 'reading', 'default' );
    register_setting( 'reading', 'sorted_categories', 'wpse_42457_setting_sanitize' );
}
add_action( 'admin_init', 'wpse_42457_admin_init' );

/**
 * Sanitize our checked categories by turning back to a comma-delimited string.
 *
 * This'll save bytes in the options table, plus it can be "unserialized" more
 * efficiently with wp_parse_id_list() when it's actually needed.
 */
function wpse_42457_setting_sanitize()
{
    // wp_terms_checklist uses "post_category" POST name.
    if ( isset( $_POST['post_category'] ) )
        $value = $_POST['post_category'];
    else
        $value = array(); // none checked

    return implode( ',', wp_parse_id_list( $value ) );
}

/**
 * Display the sorted categories field.
 */
function wpse_42457_setting_field()
{
    // Please forgive me for this dirty HTML!
    ?>

<style>#sorted_categories li li { margin: 0 0 0 15px }</style>
<ul id="sorted_categories">
    <?php
        wp_terms_checklist( 0, array(
            'selected_cats' => wp_parse_id_list( get_option( 'sorted_categories' ) ),
            'checked_ontop' => false,
            'taxonomy' => 'category'
        ));
    ?>
</ul>

    <?php
}

Whilst I always feel like I should encourage others to take steps for themselves, this proved easier to code up than walk through - hopefully it'll be educational nontheless!


You'll need to drop this in a custom plugin, or your theme's functions.php.

1
  • Whoa. Wasn't expecting THAT! Thanks @TheDeadMedic, that's some good stuff.
    – JCL1178
    Feb 15, 2012 at 22:07
1

How about this, create an option in the options table (in the database) with an array of categories ids that need a custom sorting ex:

<?php
$cats_to_sort = array(21,33,43,66); //add as many as you need.
update_option('cats_to_sort',$cats_to_sort);
?>

then creat a single category.php file with a simple loop but before the loop check if this category needs to be sorted by a custom field ex:

<?php
//get the saved array
$cats_to_sort = get_option('cats_to_sort');
//get the category id, this works for custom taxonomies as well.
$term_slug = get_query_var( 'term' );
$taxonomyName = get_query_var( 'taxonomy' );
$term = get_term_by( 'slug', $term_slug, $taxonomyName );
if (in_array($term->term_id,$cats_to_sort)){
    query_posts("cat=".$term->term_id."&meta_key=programnumber&orderby=meta_value&order=ASC");
}
//you loop here
?>
1
  • I can see what you are going for but I couldn't seem to get it to work.
    – JCL1178
    Feb 15, 2012 at 22:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.