#18106 closed feature request (wontfix)
get_terms of posts in a specific post_type
Reported by: | braydonf | Owned by: | |
---|---|---|---|
Milestone: | Priority: | normal | |
Severity: | normal | Version: | |
Component: | Taxonomy | Keywords: | close needs-patch |
Focuses: | Cc: |
Description
I have searched most everywhere to find how to use get_terms for a specific post type, and have only found this article: http://wordpress.stackexchange.com/questions/14331/get-terms-by-taxonomy-and-post-type However this is doing a query for posts and getting the terms for those posts rather than doing a straight SQL statement, so it's not as efficient or ideal.
Adding an additional argument for additional where statements or a argument to specific a post_type, are two solutions I can imagine.
Change History (14)
#2
@
13 years ago
I was looking to do the same thing - it would be nice if this was a built-in function. I couldn't get your function to work exactly as you have it above. Maybe when you copied it in some quotes were added or changed. The INs in the WHERE clause seemed to be causing issues. I think your back quotes might have turned into regular quotes. I think I have it working correctly.
#3
@
13 years ago
I've been working more on the above, and have included it as part of another plugin here: http://code.braydon.com/p/awe/source/tree/master/class-awe.php#L46
I think you're probably right about the quotes.
#4
@
12 years ago
- Cc contact@… added
Someone asked how to do this on WordPress Stack Exchange http://wordpress.stackexchange.com/a/57449/9364. After implementing the above solution (with validation, cache etc). I realised a better way *might* be to use a wrapper around get_terms
and make use of the filter.
This wrapper function takes the same arguments as get_terms
, plus a 'post_types'
key in the $args
array. This takes a string|array of post types. It works for the defaults - but I haven't verified it for all arguments...
Not exactly future proof (neither solutions are) - but would be great to see this feature added at some point. I should image that count
will cause problems as this is stored in the db. The workaround below replaces it with an SQL COUNT(*)
.
function wpse57444_get_terms($taxonomies, $args=array() ){ if( !empty($args['post_types']) ){ $args['post_types'] = (array) $args['post_types']; add_filter( 'terms_clauses','wpse_filter_terms_by_cpt',10,3); function wpse_filter_terms_by_cpt( $pieces, $tax, $args){ global $wpdb; //Don't use db count $pieces['fields'] .=", COUNT(*) " ; //Join extra tables to restrict by post type. $pieces['join'] .=" INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id "; //Restrict by post type and Group by term_id for COUNTing. $post_types_str = implode(',',$args['post_types']); $pieces['where'].= $wpdb->prepare(" AND p.post_type IN(%s) GROUP BY t.term_id", $post_types_str); return $pieces; } } $terms = get_terms($taxonomies, $args); remove_filter( 'terms_clauses','wpse_filter_terms_by_cpt',10); return $terms; }
#5
@
11 years ago
- Keywords close needs-patch added
There is probably going to be no unslow way to do this in core
#7
@
10 years ago
- Milestone Awaiting Review deleted
- Resolution set to wontfix
- Status changed from new to closed
get_terms()
never makes reference to wp_term_relationships
, so probably isn't the place for this kind of argument. It belongs somewhere like wp_get_post_terms()
.
The simplest way to implement this: in wp_get_post_terms()
, if $post_id
is empty and $args['post_type']
is not, then fetch the IDs of the posts in the post type(s) and pass them to wp_get_object_terms()
. This is probably going to perform very slowly on large sites, and if your site is large enough you may even experience the joy of a seg fault. I don't think this is something we'd want to put into core.
It's hard to think of a more robust solution that won't look pretty hackish. wp_get_object_terms()
is designed to be agnostic about the object type (post, user, etc). But filtering by post_type is very specific to posts. So, you can imagine passing a 'primary_id_column' and 'primary_table' column to wp_get_object_terms()
to build the necessary JOIN clause, but it's hard to imagine the generic logic that would be necessary to build a WHERE clause like p.post_type IN ('post','page')
. It'd be out of keeping with the rest of WP to have functions passing chunks of SQL between each other. At the same time, it doesn't make a lot of architectural sense to put logic directly into wp_get_object_terms()
that is specific to posts (or, worse, post_type). And even if we did, we'd be looking at a query that'd be pretty slow for large numbers of posts.
On the basis of this, I'm closing as wontfix. Official recommendation for now is to query for post IDs on your own and pass to wp_get_object_terms()
. If someone shows up here with a dynamite patch that proves me wrong, I'll eat my foot and dub you the champion of WordPress.
#9
follow-up:
↓ 10
@
9 years ago
Why not make a change so that tags are a property of the posts @boonebgorges?
I understand this would inevitably be a big adjustment.
Or is this completely silly?
#10
in reply to:
↑ 9
@
9 years ago
Replying to atomicjack:
Why not make a change so that tags are a property of the posts @boonebgorges?
Tags *are* a property of posts. That's why it's problematic to add a 'post_type' argument to get_terms()
, a function that is designed to get information about terms, not posts. Fetching terms based on object relationships means two additional table joins, which will scale poorly on many installations. So there are both performance problems and conceptual problems (scope creep of get_terms()
).
Pending a rearchitecture, if you need the terms belonging to a set of posts, use wp_get_object_terms()
.
#11
follow-up:
↓ 13
@
8 years ago
- Resolution wontfix deleted
- Status changed from closed to reopened
How about adding a 'post_type' and 'category' argument to get_tags()
& get _terms()
so tags can be listed for different post types or categories? The only way to do that now is to use the include or exclude parameters.
#13
in reply to:
↑ 11
@
8 years ago
- Milestone Awaiting Review deleted
- Resolution set to wontfix
- Status changed from reopened to closed
Replying to wordpresssites:
How about adding a 'post_type' and 'category' argument to
get_tags()
orget _terms()
orget_categories
so tags can be listed for different post types or categories? The only way to do that now is to use the include or exclude parameters.
The technical explanation for 'post_type' can be found in my comment above. I'm not sure what 'category' would mean in this context: show all tags that belong to posts that are also in a given category? That kind of query would be even *more* resource-intensive than the 'post_type' query - I think that about 7 database tables would be involved. That kind of use case is specific enough that I think that a custom implementation using 'include' is probably the most appropriate.
I'm going to close this ticket again, as I think that the reasoning from comment 7 still stands. If anyone is able to work up a way of handling this so that it has a reasonable chance of scaling, please feel free to reopen with those details.
Here is SQL to achieve something similar:
Perhaps better for another function all together.