Not directly, but I have a need for this functionality as well, as part of a plugin I’m writing for a client and have what I think is a pretty good start on an implementation.
The approach I’m taking is to store a term meta when the term is disabled and then to hook into the get_terms_defaults
filter to strip disabled terms that would be returned by WP Core’s calls to get_terms()
, get_the_terms()
, etc.
My plugin encapsulates all of this into a class which serves as a wrapper around register_taxonomy()
. The following is a stripped down version of that class (for the plugin I’m writing, this wrapper does a lot more with custom taxonomies).
See Custom_Taxonomy::enable_term()
and Custom_Taxonmy::disable_term()
for the code that adds/deletes the relevant term meta; and see Custom_Taxonomy::strip_disabled_terms()
for the code that strips disabled terms.
Hopefully, I’ve left in all of the relevant code from this class when I stripped out the stuff that doesn’t apply to this question 🙂
/**
* this class is a wrapper around register_taxonomy(), that adds additional functionality
* to allow terms in the taxonomy so registered to be "disabled".
*
* Disabled terms will NOT be returned by the various WP Core functions like get_terms(),
* get_the_terms(), etc.
*
* TODO: make sure that this works correctly given WP Core's object caching, see Custom_Taxonomy::strip_disabled_terms()
*/
class
Custom_Taxonomy
{
const DISABLED_TERM_META_KEY = '_shc_disabled' ;
public $name ;
public $can_disable_terms = false ;
/**
* construct an instance of Custom_Taxonomy
*
* @param $taxonomy string Taxonomy key, must not exceed 32 characters
* @param $post_types array|string post type or array of post types with which the taxonomy should be associated
* @param $args array Array or query string of arguments for registering a taxonomy
*
* params are the same as WP's register_taxonomy() except that $args may have extra keys:
*
* 'can_disable_terms' => true|false
*/
function
__construct ($taxonomy, $post_types, $args)
{
$this->name = $taxonomy ;
// modify args, if needed
$default_args = array (
'can_disable_terms' => false,
) ;
$args = wp_parse_args ($args, $default_args) ;
$this->can_disable_terms = $args['can_disable_terms'] ;
unset ($args['can_disable_terms']) ;
if ($this->can_disable_terms) {
// TODO: is there a better filter to hook into than 'get_terms_defaults'?
// I've tried 'get_terms_args', but that seems to be called too late
// in the process of builing the WP_Term_Query used by get_terms(), etc
// to have the meta_query that is added by $this->strip_disabled_terms()
add_filter ('get_terms_defaults', array ($this, 'strip_disabled_terms'), 10, 2) ;
}
// register the taxonomy
register_taxonomy ($taxonomy, $post_types, $args) ;
return ;
}
/**
* disable a term
*
* disabling a term will make it appear as if the term does not exist, without actually deleting it
*
* @param $term int|string|WP_Term the term to disable
* @param $taxonomy string the taxonomy term is in
* @return int|WP_Error|bool Meta ID on success. WP_Error when term_id is ambiguous between taxonomies. False on failure
*/
function
disable_term ($term, $taxonomy = '', $field = 'name')
{
if (!$this->can_disable_terms) {
return ;
}
$taxonomy = $taxonomy ? $taxonomy : $this->name ;
if (is_string ($term)) {
$term = get_term_by ($field, $term, $taxonomy) ;
}
else {
$term = get_term ($term, $taxonomy) ;
}
return (add_term_meta ($term->term_id, self::DISABLED_TERM_META_KEY, true, true)) ;
}
/**
* enable a term
*
* @param $term int|WP_Term the term to disable
* @param $taxonomy string the taxonomy term is in
* @return bool True on success, false on failure
*/
function
enable_term ($term, $taxonomy = '', $field = 'name')
{
if (!$this->can_disable_terms) {
return ;
}
$taxonomy = $taxonomy ? $taxonomy : $this->name ;
if (is_string ($term)) {
$term = get_term_by ($field, $term, $taxonomy) ;
}
else {
$term = get_term ($term, $taxonomy) ;
}
return (delete_term_meta ($term->term_id, self::DISABLED_TERM_META_KEY)) ;
}
/**
* strip disabled terms from e.g., get_terms() and get_the_terms()
*
* TODO: make sure that this works correctly given WP Core's object caching
*
* @param $term int|WP_Term the term to disable
* @param $taxonomy string the taxonomy term is in
* @return bool True on success, false on failure
*/
function
strip_disabled_terms ($args, $taxonomies)
{
if (!$this->can_disable_terms) {
return ($args) ;
}
// I *think* the count('taxonomy') check is necesary because get_terms_args() is
// applied by the WP Core object_term caching infrastructure by
// passing all taxonomies for a given post_type, and we only want to
// add this restriction when we are getting the terms for just the
// this taxonomy
if (count ($args['taxonomy']) != 1 || !in_array ($this->name, $args['taxonomy'])) {
return ($args) ;
}
$args['meta_query'] = array (
array (
'key' => self::DISABLED_TERM_META_KEY,
'compare' => 'NOT EXISTS',
)
) ;
return ($args) ;
}
}
My use case
I’ve got 2 custom post types, type_a
and type_b
. type_b
has a custom taxonomy, taxonomy_b
, the terms of which are the post_title’s of all of the posts of type type_a
.
Only those posts of type_a
whose post_status
is publish
should have their corresponding terms in taxonomy_b
enabled. I accomplish this by hooking into save_post_type_a
to insert the terms (if they don’t already exist) and enable/disable them, and hook into delete_post
to delete them.
If your use case for disabled terms is at all similar, them the above should at least point you in one possible direction.
Questions I still have
I’m still working on this plugin and there are a few open issues around it’s implementation.
-
is the
get_terms_defaults
filter that I hook into to add the meta_query toWP_Term_Query
the best hook to use? I’ve triedget_terms_args
, but that seems to be called too late in the process of builing the WP_Term_Query used by get_terms(), etc. to correctly process the meta_query that is added byCustom_taxonomy::strip_disabled_terms()
. -
I’m not sure how this interacts with WP Core’s object caching. For example, if a term is disabled when a call to
get_terms()
caches the terms in the taxonomy, and them the term is enabled in the same execution ofwp()
will a subsequent call toget_terms()
include the term or will it return the cached terms…which wouldn’t include the term. But it seems to be working in the tests I’ve done thus far.
If anyone reading this has any suggestions for improvements on this class, especially about the object caching aspect, please, chime in!