• I’m sorry if this topic comes out pretty often or I come out a little offensive, just had frustrated hacking session with WP Core.

    As the title says, I’d like to implement a system where I’d like to have a term belonging to multiple taxonomies.

    Just in case someone’s wondering “what on earth does he need this for?”, hear me out. I’m trying to implement a UML specification of an entity called “Person” who can act as a speaker, author, interviewer for the posts and custom post types we design. The idea is to be able to tag them just like you add categories/tags, query them in wp-admin, etc.

    So the idea I came up with was to create a term for each “Person”, extend with custom term metas and then make this term part of taxonomies speaker, author and interviewer. Upon reading the DB schema of WP, I was able to make the mental map of how things would work. As you can see in the schema, the table wp_terms has one to many relationship with wp_term_taxonomy, meaning that a term can be part of multiple taxonomies.

    However, when I encountered how the codebase for WP was implemented, I was surprised to find that the WP_Term class implementation throws an error when the term ID is shared across multiple taxonomies. Here’s the code for reference: https://github.com/WordPress/wordpress-develop/blob/6.2/src/wp-includes/class-wp-term.php#L153-L162 As you can see, the class is set to final, so it’s not possible to extend it either.

    This makes me wonder, what was the point of separating the wp_terms and wp_term_taxonomy table in the first place? We could’ve merged them together, instead of creating joins for slugs. As far as I can tell, the design contradicts with the implementation. Has it been overlooked or has it been known, but an obvious choice was made for legacy reasons?

    This, of course, can be a misinterpretation of the things, I am eager to understand if I am mistaken.

    And lastly, what are my best bet for the scenario I’m working on? The other option is that I create 3 different term instances for three type of taxonomies, and make sure that CRUD operations are atomic in nature. My gut says try to avoid it, but if there’s no other way, I’d have to go with that.

Viewing 2 replies - 1 through 2 (of 2 total)
  • Hi,

    you are right that from a database layout perspective a term could be shared between taxonomies. This is what it used to be like before WordPress 4.2. But we ran into problems with this when updating terms, see the Core Trac ticket 5809.

    So since then, even if a term has the same name and could be reused from another taxonomy, a new term will be created. The database layout wasn’t changed to reflect this and I agree that term_taxonomy_id therefore seems redundant (although you still need to follow the table relationship, sometimes term_id and term_taxonomy_id are the same but it’s not guaranteed to be so).

    Technically you could still make a term that’s shared (by inserting it in the database) but since WordPress 4.3, WordPress has a cronjob that will split the terms, so after a short while your term shared between taxonomy will be duplicated.

    One way to deal with your scenario is to make use of term hierarchies. You create a person and child terms with their roles. You then attach those child terms to the posts.

    Something like this:

    $taxonomy = 'person';
    register_taxonomy( $taxonomy, 'post', array( 'hierarchical' => true ) );
    $chakrapani = wp_insert_term( 'Chakrapani', $taxonomy );
    $speaker_chakrapani = wp_insert_term( 'Speaker Chakrapani', $taxonomy, array( 'parent' => $chakrapani['term_id'] ) );
    $author_chakrapani = wp_insert_term( 'Author Chakrapani', $taxonomy, array( 'parent' => $chakrapani['term_id'] ) );
    
    $gautam = wp_insert_term( 'Gautam', $taxonomy );
    $speaker_gautam = wp_insert_term( 'Speaker Gautam', $taxonomy, array( 'parent' => $gautam['term_id'] ) );
    $author_gautam = wp_insert_term( 'Author Gautam', $taxonomy, array( 'parent' => $gautam['term_id'] ) );
    
    $talk_post = wp_insert_post( array( 'post_title' => 'a talk' ) );
    $talk2_post = wp_insert_post( array( 'post_title' => 'another talk' ) );
    $author_post = wp_insert_post( array( 'post_title' => 'a book' ) );
    
    wp_set_object_terms( $talk_post, $speaker_chakrapani['term_id'], $taxonomy );
    wp_set_object_terms( $author_post, $author_chakrapani['term_id'], $taxonomy );
    
    wp_set_object_terms( $talk2_post, $speaker_gautam['term_id'], $taxonomy );
    
    // returns $talk_post and $author_post
    get_objects_in_term( get_term_children( $chakrapani['term_id'], $taxonomy ), $taxonomy );
    
    // returns $talk_post
    get_objects_in_term( $speaker_chakrapani['term_id'], $taxonomy );
    
    // returns $talk2_post
    get_objects_in_term( get_term_children( $gautam['term_id'], $taxonomy ), $taxonomy );

    Finally, two more links for some context of the happenings at the time:

    Hope this helps!

    • This reply was modified 11 months ago by Alex Kirk.
    Thread Starter Chakrapani Gautam

    (@cherrygot)

    Hey, thanks Alex for the insights. This explains a lot about why things are the way they are. Thanks for the ticket, I haven’t read entirely but judging based on the first few responses of the tickets, I think it could’ve been solved with a simple checkbox asking users if they want to split the term if they choose to create the same term in some other taxonomy than the existing one. Or in case of core WP API, a flag in the arguments should’ve done the trick, instead of doing it automatically, no? Smells like over-engineering but I maybe wrong.

    And yeah, thanks for the hierarchical approach, that seems interesting. I’ll explore that too and how well it fits with our use case.

Viewing 2 replies - 1 through 2 (of 2 total)
  • The topic ‘How to make a term belong to multiple taxonomies?’ is closed to new replies.