Custom taxonomy on users with UI

Answering this question is, by design, a multi-part process. There are several things you (or a plugin/library) need to do to make User Taxonomies behave similarly to Post Taxonomies, even after you have (successfully) registered it.

This answer is a work-in-progress to some degree. Please add other answers with solutions to any aspects that are missing from mine.

Add term management admin page and fix parentage

The first thing you’ll notice is missing after registering a taxonomy for ‘users’ is the admin menu item, which won’t exist at all.

Adding the management page

Justin Tadlock found that using the edit-tags.php admin page (intended for post taxonomies) works surprisingly well, with the caveat that we need to add another filter to the parent_file hook to make the new admin page show as child of Users rather than Posts.

/**
 * Creates the admin page for the taxonomy under the 'Users' menu.  
 * 
 * It works the same as any other taxonomy page in the admin by using edit-tags.php
 * 
 * ISSUE: When clicking on the menu item in the admin, WordPress' menu system thinks
 * you're viewing something under 'Posts' instead of 'Users'.
 * SO: When you are on the edit-tags page the "Posts" section of the sidebar is open, 
 * but the taxonomy's name isn't there, it's still under users. 
 * 
 * @see filter_user_taxonomy_admin_page_parent_file() which fixes the issue with menu parent
 */
function add_user_taxonomy_admin_page() {

    $tax = get_taxonomy( 'YOUR_TAXONOMY_NAME' );

    if (!is_object($tax) OR is_wp_error($tax)) 
        return;

    add_users_page(
        esc_attr( $tax->labels->menu_name ),
        esc_attr( $tax->labels->menu_name ),
        $tax->cap->manage_terms,
        'edit-tags.php?taxonomy=' . $tax->name
    );
}

This hooks into the admin_menu action:

add_action( 'admin_menu', 'add_user_taxonomy_admin_page');

Fixing the parentage

As stated above the fix above works, but the page will be confused in the sidebar. It will show as Users > TAXONOMYNAME but when you click it, the Users menu won’t be open, instead the Posts section of the sidebar will be expanded even though the current page (TAXONOMYNAME) isn’t in there. The reason is WP thinks the current parent page is Posts because we are using edit-tags.php.

Thus the solution is to filter parent_file with a callback that ensures users.php is always used as the parent when our taxonomy is loaded into edit-tags.php:

/**
 * Fix position of user taxonomy in admin menu to be under Users by filtering parent_file
 * 
 * Should be used with 'parent_file' filter.
 * 
 * This is a fix to make edit-tags.php work as an editor of user taxonomies, it solves a 
 * problem where the "Posts" sidebar item is expanded rather than "Users". 
 * 
 * @see add_user_taxonomy_admin_page() which registers the user taxonomy page as edit-tags.php
 * @global string $pagenow Filename of current page (like edit-tags.php)
 * @param string $parent_file Filename of admin page being filtered
 * @return string Filtered filename
 */
function filter_user_taxonomy_admin_page_parent_file( $parent_file="" ) {
    global $pagenow;

    /**
     * Only filter the parent if we are on a the taxonomy screen for 
     */
    if ( ! empty( $_GET['taxonomy'] ) && ($_GET['taxonomy'] == 'YOUR_TAXONOMY_NAME') && $pagenow == 'edit-tags.php' ) {
        $parent_file="users.php";
    }

    return $parent_file;
}

We register the filter like this:

add_filter( 'parent_file', 'filter_user_taxonomy_admin_page_parent_file');

Add term picker to user profile screen and handle input on user save

Register and use custom update_count_callback function

The update_count_callback for a taxonomy is a function that counts the number of times a term has been used so that it’s “count” can be updated.

Customizing this value in your call to register_taxonomy() is extremely vital because the default one is specifically for posts.

Justin Tadlock found this function worked well and so far I’ve found it works with any user taxonomy.

/**
 * Function for updating a user taxonomy count.  
 * 
 * What this does is update the count of a specific term by the number of users that have been given the term. 
 *
 * See the _update_post_term_count() function in WordPress for more info.
 *
 * @see https://web.archive.org/web/20150327042855/http://justintadlock.com/archives/2011/10/20/custom-user-taxonomies-in-wordpress
 * @param array $terms List of Term taxonomy IDs
 * @param object $taxonomy Current taxonomy object of terms
 */
function user_taxonomy_update_count_callback( $terms, $taxonomy ) {
    global $wpdb;

    foreach ( (array) $terms as $term ) {
        $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term ) );

        do_action( 'edit_term_taxonomy', $term, $taxonomy );
        $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
        do_action( 'edited_term_taxonomy', $term, $taxonomy );
    }
}   

To use this as your callback, update your call to register_taxonomy() and add the update_count_callback argument:

$args['update_count_callback'] = 'user_taxonomy_update_count_callback';

Filter usernames to avoid permalink collisions

Leave a Comment