Opened 13 years ago
Closed 12 years ago
#18752 closed enhancement (fixed)
Allow category preference in permalinks
Reported by: | aaroncampbell | Owned by: | nacin |
---|---|---|---|
Milestone: | 3.5 | Priority: | normal |
Severity: | normal | Version: | 3.2 |
Component: | General | Keywords: | has-patch commit |
Focuses: | Cc: |
Description
I know that the general consensus is that a post should be assigned to a single category and have many tags. However, we ALLOW a user to set as many categories as they want and I'm constantly facing customers that use multiple categories and are frustrated that they can't set a "preferred" category for their permalinks. The category in the permalink is simply determined by the lowest ID with this code:
usort($cats, '_usort_terms_by_ID');
If we add a filter just after that, or better yet change it to a filter and add the usort USING the filter, then a plugin could use business logic to decide what category belongs in the permalink instead of being forced to use one that may make no sense.
Attachments (5)
Change History (28)
#4
@
13 years ago
The comment was already there, I just copy/pasted the line. It's probably not a big deal to leave it there.
I'm testing this patch on a site and it seems to be working exactly as expected. I'm using this code to NOT use 'publications' as the category in the permalink if there are other options:
function da_remove_publications_cat( $cat ) { return ( 'publications' != $cat->slug ); } function da_permalink_categories( $cats ) { if ( count( $cats ) > 1 ) $cats = array_filter( $cats, 'da_remove_publications_cat' ); return $cats; } add_filter( 'post_link_categories', 'da_permalink_categories', 9 );
#5
@
13 years ago
The comment was already there, I just copy/pasted the line. It's probably not a big deal to leave it there.
It's also probably not a big deal to remove it either. :P
#6
@
13 years ago
Sorry, yes I agree that it could be removed...I just didn't think it was worth the time to make another patch just to remove it. However, since it seems to be becoming an issue I just re-made it.
#8
in reply to:
↑ 7
@
13 years ago
Replying to scribu:
Hm... won't this trip up the canonical redirect stuff?
Nope, because get_permalink() will return the proper URL and canonical will think it's on the correct page.
#9
@
13 years ago
It has the potential to change exiting permalinks but only if someone specifically writes code (like in my comment above) to do that. If they *do* then as nacin said, the new permalink will match the canonical URL. However, URLs changed in this way will NOT get redirected with redirect_canonical()
because when it deals with %category%
it checks if the cat in the current URL is valid for the post and if it is it doesn't try to redirect. Since the previous category would be valid (even if not preferred) it would not redirect. However, this is consistent with what happens currently (if a post is in 3 categories it has three URLs that will work and not redirect, but only one that is canonical), and you could force a redirect with your own function hooking into template_redirect
for these situations.
Having had the chance to test it a lot more today...it's working really well for my use cases.
#11
@
13 years ago
The site that I needed this form is getting really close to going live. I'd really like to see this get put in (or a lead say that it will) before I put this code into the wild. Anyone have any concerns?
#12
@
13 years ago
- Type changed from defect (bug) to enhancement
Looks solid. If it were by me, I'd get it into 3.3.
#15
@
12 years ago
After coming back to this, I think this can be implemented in a much simpler and more obvious way.
What we're doing is exposing an array of categories to be sorted however someone would like. But no matter what happens, we only care about the first value. (And actually, we care about the key of 0, so if someone wanted to do some kind of sorting or pushing they would need to make sure keys did get reset, which wouldn't always be the case depending on the method.)
So what about 18752.3.diff? A filter specifically on the category object. It expects a category object in return. (We could also do IDs.) Whichever object we get back, gets used.
#16
follow-up:
↓ 17
@
12 years ago
Replying to nacin:
That works for me, but it looks like you missed another reference to $cats[0]
on the very next line. If I return a category object to your filter, it'll be prepended with the parents of $cats[0]
if it has any. 18752.4.diff should fix that.
#17
in reply to:
↑ 16
@
12 years ago
- Keywords commit added
- Milestone changed from Future Release to 3.5
Replying to aaroncampbell:
Replying to nacin:
That works for me, but it looks like you missed another reference to
$cats[0]
on the very next line.
You got the gist, anyway. :-)
Let's test it out and commit. Any thoughts on a category object versus an ID? If we run $cat through get_term(), it should force an object if given an ID, the same way we'd do it with get_post().
#18
@
12 years ago
18752.5.diff passes the return from the filter through get_term. I'd been testing .4 and it worked great for me. I re-ran all the tests with .5 passing back IDs instead and it worked well there too. I was testing with this:
function essence_post_link_category( $cat, $cats, $post ) { //return $cats[1]; //return $cats[2]; //return $cats[3]; //return $cats[4]; //return $cats[1]->term_id; //return $cats[2]->term_id; //return $cats[3]->term_id; return $cats[4]->term_id; } add_filter( 'post_link_category', 'essence_post_link_category', null, 3 );
I was testing with a post with 5 categories and the fifth had parents that were set properly as well. I think it's ready to go in, but check it out and let me know what you think.
#19
@
12 years ago
Worth highlighting the canonical code for this:
} elseif ( is_single() && strpos($wp_rewrite->permalink_structure, '%category%') !== false && $cat = get_query_var( 'category_name' ) ) { $category = get_category_by_path( $cat ); $post_terms = wp_get_object_terms($wp_query->get_queried_object_id(), 'category', array('fields' => 'tt_ids')); if ( (!$category || is_wp_error($category)) || ( !is_wp_error($post_terms) && !empty($post_terms) && !in_array($category->term_taxonomy_id, $post_terms) ) ) $redirect_url = get_permalink($wp_query->get_queried_object_id()); }
A good test would be what happens if you choose to use a category that isn't actually assigned to the post.
#20
@
12 years ago
Sorry, I see that it's not in my paste up there, but I did test that. It did what *I* would want it to do, which is that the permalink used the category even though the post wasn't in it and it is NOT canonically redirected. Since you're manually overriding this, I think that would be the expected response.
#21
@
12 years ago
Thea reason it isn't canonically redirected is that when it finds that the category is NOT one of the post terms, it uses get_permalink()
to generate the URL to redirect to. Since our filter applies to that URL as well, toward the end of redirect_canonical()
it checks $redirect_url == $requested_url
and returns false instead of redirecting.
+1.
The
// order by ID
comment is redundant, though.