3

WP lets us register_taxonomy() with users as the object type, thus creating taxonomies mapped to user IDs rather than post IDs.

Unfortunately this method is poorly documented and many features don't function like we'd expect based on post taxonomies.

What are all the fixes needed to make user taxonomies work and behave similar to post taxonomies?

This 2011 post by Justin Tadlock on the subject is the best source available, but it is somewhat out of date and many important solutions are only available in the comments section.

  • What are you trying to achieve that you cannot do now? This doesn't look very fleshed out in the WP_Query_Object so I wouldn't expect much without a ton of 'hacking' together things. meta_query is in place though but not a taxonomy or tax_query. Maybe try using this plugin. – Howdy_McGee Feb 23 '16 at 0:35
  • 1
    My goal is to answer my own question with all the solutions I've found (esp. based on that justintadlock.com post). Still working on it but will hopefully post soon. the lh-user-taxonomies plugin is based on the same post, but IMHO isn't a very versatile solution. – jerclarke Feb 23 '16 at 0:48
4

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.