I would like to sort posts by tags in category and archive pages. (Unfortunately there isn’t an orderby
parameter for tags. That would make things so easy!)
So a category page would be like this:
Category name
- Post 1 (Tag 1)
- Post 2 (Tag 1)
- Post 3 (Tag 1)
- Post 4 (Tag 2)
- Post 5 (Tag 2)
- Post 6 (Tag 2)
- Post 7 (Tag 3)
- Post 8 (Tag 3)
- Post 9 (Tag 3)
…
Or, even better:
Category name
Tag 1
- Post 1
- Post 2
- Post 3
Tag 2
- Post 4
- Post 5
- Post 6
Tag 3
- Post 7
- Post 8
- Post 9
…
The tags would appear in alphabetical order. The posts below the tags would also appear in alphabetical order.
When a post has more than one tag, it needs to appear multiple times (one for each tag).
Is there any way to do that?
I thought about doing something like this, but I couldn’t come up with a solution that would show only the posts and tags in the category. (The linked code shows all posts and tags.)
Or maybe there is a way to treat tags as a meta_value
? Then I could simply use pre_get_posts
like this:
add_action( 'pre_get_posts', 'archive_post_order');
function archive_post_order($query){
if(is_archive()):
$query->set( 'orderby', 'meta_value' );
$query->set( 'metakey', 'tag' );
$query->set( 'order', 'ASC' );
endif;
}
Any ideas are welcome. Thanks in advance.
2 Answers
There really is no sane way to accomplish this, specially if you have posts that are assigned to more than one tag (which is almost always the case). What is very sure, you have you work cut out for you.
Here are some thought and ideas you can persue:
POSTS WITH MULTIPLE TERMS
If posts have more than one tag (or any term for that matter) assigned to them, it means that there are more than one relationship to another post or set of posts, and grouping those together will either: (a). Be impossible without duplication, or (b). Be possible, with duplication of posts.
The terms (tags in this case) assigned to a post from a specific taxonomy (post_tag
in this case) is ordered in a specific way when more than one term exists. Simply grabbing the first term might not always be the term you would want to use.
Sorting tags from get_the_tags()
(or the more generic get_the_terms()
) would require additional PHP sorting to sort the returned array of tag object to suite your needs, or you would want to use a function like wp_get_post_tags()
to do the sorting via SQL, but it would require an extra db call.
If you want to sort by the first tag only, then it is quite easy if you sorted the tag array to suite or needs. I’ll post example code later
WORKAROUND
If you have posts with multiple tags, you will need to find a specific unique relationship between posts, and according to that, either:
-
assign a custom field with a sortable value to a set of posts and then use
pre_get_posts
to sort your category pages according to custom field value -
create a specific taxonomy for this, and then assign a special term to a set of posts and then use the
the_posts
filter, which I will post, to sort the returned array of posts
If you do not mind post duplication, you have a look at this post, this was however done for custom fields, so you would need to break it down and modify it to work with tags, but in essence, the principle by building a multidimentional array, flatten it later and then return a sorted array with duplicate posts remains the same
POSTS WITH SINGLE TAGS
If you have posts assigned to one tag only (or you are happy to sort by first tag only), it is quite easy to sort the posts accordingly by using the the_posts
filter. You can try the following then (UNTESTED and very basic)
add_filter( 'the_posts', function ( $posts, \WP_Query $q )
{
// Make sure we only target the main query on category pages
if ( !is_admin()
&& $q->is_main_query()
&& $q->is_category()
) {
// Use usort to sort the posts
usort( $posts, function( $a, $b )
{
return strcasecmp(
get_the_tags( $a->ID )[0]->name,
get_the_tags( $b->ID )[0]->name
);
});
}
}, 10, 2 );