WP_Posts_List_Table::extra_tablenav() applies restrict_manage_posts, which can be used by a plugin to output extra dropdowns (or other markup) that allow filtering the posts in the table by arbitrary criteria.
Similarly, WP_(Users|Comments)_List_Table
have a resttric_manage_(users|comment)
action for similar purposes.
However, as far as I can tell, WP_Terms_List_Table does not. Is this correct?
I’m writing a plugin that relies heavily on termmeta
on various custom taxonomies. My plugin adds custom columns to edit-tags.php?taxonomy=my_custom_tax
that display the value(s) of the various termmeta
for each term. It would greatly enhance the UX of my plugin if users were able to filter the term list by the distinct meta_value
‘s for my meta_key
‘s.
Before I open a Trac ticket that proposes adding a WP_Terms_List_Table::extra_tablenav()
method and restrict_manage_terms
filter so that it would be possible to do what I want to do, I wanted to see if anyone here on WPSE knows:
- is there a viable work around (that doesn’t involve something like hijacking
edit-tags.php?taxonomy=my_custom_tax
to redirect to a custom page that uses a custom subclass of WP_Terms_List_Table
)?
- is there a (good) reason
WP_Terms_List_Table
doesn’t currently support this functionality?
- I realize for core there is no (good) reason to filter by any of the standard
WP_Term_List_Table
columns, but adding custom columns to it is fairly common and I can’t believe I’m the only one who’s ever wanted to filter by the values in custom columns.
Edit
I should note that I when displaying the meta_value
in the custom column, I am outputting it as a link which effectively filters the term list by that value. The the reason the UX would be enchanced if users could choose from a dropdown (like in WP_Posts_List_Table
) is that not all values of the meta_value
are always visible on any given page of terms displayed in the list table. What I do to use the links to filter by a value that is not currently displayed on the current page is click on a random link, then edit the resulting URL in the browser’s address field to have the meta_value
I want to filter by. Not only is that a pain, but not all user’s are savy enough to realize they can do this.
I’ve been searching around for the same answer to your question and running into the exact same issues, and really appreciate your thorough research. I’m definitely +1 here for proposing this addition!
To attempt to answer 2) – I don’t think there’s a good reason to exclude it. I think WordPress’s taxonomy terms are woefully lacking in features compared to the post and user entities (seeing as how term meta came much later, after post and user meta), and would like to see that change.
To answer 1) – I don’t know how much better this is than your solution, but the workaround I’ve come up with involves filtering the taxonomy list via the get_terms_args
filter, and then manually inserting a select dropdown + filter button in client-side JS. Here’s a sample of my setup (modified to not use my specific classes or constants), which is filtering by a certain term meta field:
PHP Logic
// @see https://developer.wordpress.org/reference/hooks/get_terms_args/
add_filter( 'get_terms_args', 'taxonomy_filter', 10, 2 );
function taxonomy_filter( $args, $taxonomies ) {
global $pagenow;
if ( 'edit-tags.php' !== $pagenow || ! in_array( 'taxonomy-name', $taxonomies, true ) ) { return $args; }
// Sort by most recently added terms, instead of alphabetically
$args['orderby'] = 'term_id';
$args['order'] = 'desc';
// Filter by term meta
$meta_key = ( isset( $_GET['meta_key'] ) ) ? sanitize_text_field( $_GET['meta_key'] ) : null;
$meta_value = ( isset( $_GET['meta_value'] ) ) ? sanitize_text_field( $_GET['meta_value'] ) : null;
if ( 'meta-filter' === $meta_key && $meta_value ) {
$args['meta_key'] = $meta_key;
$args['meta_value'] = $meta_value;
}
// Note: for more complex filtering, use the $args['meta_query'] array.
return $args;
}
At this point, you should be able to see this working simply by going to (e.g.) yoursite.com/wp-admin/edit-tags.php?taxonomy=taxonomy-name&meta_key=meta-filter&meta_value=foobar
.
Client-side jQuery logic
(Make sure you include this file in wp_enqueue_script()
, but only when $pagenow === 'edit-tags.php'
).
/**
* Param helpers
*/
// Get params in a JS object
var params = {};
window.location.search.substr(1).split( '&' ).forEach(function(item) {
params[ item.split( '=' )[0] ] = item.split( '=' )[1];
});
// Return param string based on the params object
function setParams() {
var string = '?';
for ( key in params ) {
var value = params[ key ];
string += key + '=' + value + '&';
}
return string.slice(0, -1); // Remove trailing &
}
/**
* Add dropdown filters + functionality to term tables
*/
if ( 'taxonomy-name' === params.taxonomy ) {
// Create the dropdown menu & HTML
$( document.querySelector( '.tablenav .bulkactions' ) ).after( '\
<div class="alignleft actions"> \
<select id="js-filter-dropdown"> \
<option value="">Term Meta Filter</option> \
<option value="foo">Foo</option> \
<option value="bar">Bar</option> \
<option value="baz">Baz</option> \
</select> \
<button id="js-filter" class="button" type="button">Filter</button> \
</div> \
' );
// If we're already filtering the view, have the dropdown reflect that
var value = decodeURIComponent( params.meta_value ).replace(/\+/g, ' ');
$( '#js-filter-dropdown' ).find( 'option[value="' + value + '"]' ).prop( 'selected', true );
// Set up the button action - see taxonomy_filter() for server-side filtering
$( '#js-filter' ).click(function() {
var value = $( '#js-filter-dropdown' ).val();
if ( value ) {
params.meta_key = 'meta-filter';
params.meta_value = encodeURIComponent( value );
} else {
delete params.meta_key;
delete params.meta_value;
}
window.location.search = setParams();
});
}
Screenshot of the Filtering UI
Screenshot of the filtered table