How to Order Posts by Category Name

Creating custom Sort for Posts (or any other custom post type) within categories is an easy task using the Advanced Post Types Order plugin, a visual drag & drop interface is easy to set-up and self explanatory. The order can be customized for individual categories which apply accordingly on front side when view such area (e.g. category link).

But how to automatically re-order the Posts, when view the archive, by category name it belong? Or by child category name (in case to view a category which include child terms)?
For example we have the following categories:

  • Arts
  • Books
  • Movies

When view the archive (all posts) the default order of posts is set to Date, or to custom defined order if created. In this scenario we require the sorting of posts to be by category name, meaning all posts for Arts category comes first, then the posts from Books and lastly from the Movies. Even more, we need to apply the order of posts set-up for each category (if created).

This is not something easy to achieve and require basic level of adjustments at the code level, so the functionality does not come integrated into the core. The plugin contain the necessarily tools to use and implement such feature, mainly relaying on User Function sorting callback
First the order should be switched to Automatic and the Order By selection should be set for Custom Function The function name which will be used in current example is called sort_by_category_name so it should be updated accordingly with your.

Further a custom code which return the required order need to be implemented. The code block should be included with theme functions.php or a custom plugin. The function need to use the same name as defined in above interface.

    * Sort the elements by category name, or customised catgory order
    * @param mixed $sort_list
    * @param mixed $sort_view_id
    * @param mixed $orderBy
    * @param mixed $query
    function sort_by_category_name( $post_order_list, $sort_view_id, $orderBy, $query )
            //Change to required taxonomy
            $_apply_for_taxonomy    =   "category";

In this example, the code will sort by categories taxonomy, but this can be changed to anything else, accordingly to required results. This can be done by changing the above line 13 at variable $_apply_for_taxonomy

			if ( count($post_order_list) > 1 ) 
			return $post_order_list; 
		//check if is archive or a taxonomy view 
		if ( count ($query->tax_query->queries) > 1 )
                	return $post_order_list;
            //avoid endless loop in case using this function on multiple level terms
            global $_SCN_in_the_loop;
            if  ( $_SCN_in_the_loop )
                return $post_order_list;
            $_is_archive    =   FALSE;
            $_is_term       =   FALSE;

The sorting by category name functionality can be used for Archive selection (all posts), also it can be set-up for individual Categories as well, as long they include child terms which can be used to order by. The following code part check on that:

	if  ( count ($query->tax_query->queries) > 0 )
                    //ensure there's a single term
                    $tax    =   current($query->tax_query->queries);
                    if  ( is_array($tax['terms'])   &&  count ($tax['terms'])  > 1 )
                        return $post_order_list;
                    $_is_term   =   TRUE;
                $_is_archive    =   TRUE;
            //retrive the terms
            $args   =   array(
                                        'taxonomy'  =>  $_apply_for_taxonomy,
                                        'orderby'   => 'name',

For retrieving the terms list, the code use an orderby argument by name. In case a custom order of categories is required to be used instead, the Advanced taxonomy Terms Order plugin can be used to change the order of categories. Then the orderby should be update to term_order in above code block at line 18

            if  ( $_is_term ) 
                    //retrieve a list of existing terms
                    $tax    =   current($query->tax_query->queries);
                    if  ( is_array( $tax['terms'] ))
                            reset( $tax['terms'] );
                            $term_id    =   current( $tax['terms'] );
                            $term_id    =   $tax['terms'];
                    if ( $tax['field']  ==  'slug'  ||  $tax['field']  ==  'name' )
                            $term_data      =   get_term_by( $tax['field'], $term_id, $_apply_for_taxonomy );
                            $term_id        =   $term_data->term_id;
                    $args['child_of']   =   $term_id;  


At this point retrieve the categories (terms) which will be used to sort and build the ordered list of posts which will be returned:

	$terms  =   get_terms( $args );
            //retrieve a list of items for each of the terms
            if ( count ( $terms )   < 1 ) return $post_order_list; $_SCN_in_the_loop = TRUE; global $APTO; $sort_view_post = get_post( $sort_view_id ); $sort_list_settings = $APTO->functions->get_sort_settings( $sort_view_post->post_parent );
            $posts_list =   array();
            foreach ( $terms as  $term )
                    $args =   array(
                                            'post_type'         =>  $sort_list_settings['_rules']['post_type'][0],
                                            'posts_per_page'    =>  -1,
                                            'fields'            =>  'ids',
                                            'orderby'           =>  'menu_order',
                                            'order'             =>  'ASC',
                                            'tax_query'         => array(
                                                                                'taxonomy' =>   $_apply_for_taxonomy,
                                                                                'field'    =>   'id',
                                                                                'terms'    =>   array( $term->term_id ),
                    $term_posts_query  =  new WP_Query( $args );
                    $posts_list =   array_merge ( $posts_list , array_values( $term_posts_query->posts ));
            $_SCN_in_the_loop = FALSE;
            return $posts_list; 

The order list is returned to the plugin core and applied to the query.

This is a functionality which require a bit more resources than a regular ordering, specially on very large sites with thousand of posts, but can be easily overtaken using a cache plugin. This way the code will be process once, further being served by a static cached data.