WooCommerce Product Attributes and the WordPress Taxonomy Inception

I recently explained the very basics of how you actually set up a custom taxonomy in WordPress. Along with custom post types and custom fields — which I thought about telling you about today, but they can wait — they’re what make WordPress a powerful and fully-featured content management system.

CMSes are powerful systems to manage “content”, and that can mean a lot of things. Obviously it means blog posts, articles and other basic writing types. But increasingly WordPress is used in other ways as well. WooCommerce, one of many different e-commerce plugins that allow you to build a whole store inside of WordPress, really showcases this CMS thing well.

If you’re not familiar, WooCommerce adds a new post type to your WordPress site — “Products” — and gives you a lot of features around those. You can set prices, name colors, categorize, tag, and much more that you’d expect for a capable and well-used shop system for WordPress.

WooCommerce Product Attributes

woo-commerce-product-attributesIn addition to product categories and tags — which are obvious but pretty pedestrian uses of taxonomies — WooCommerce has a neat feature called “product attributes”. All the things that you can use a product attribute to do is honestly a bit more than I need or want to cover in this post, but suffice it to say that have a diverse set of possible uses within WooCommerce. And that’s because they’re a pretty interesting and flexible system.

What makes WooCommerce Product Attributes really powerful is that you’re not just using a single taxonomy — like product categories — and then putting your attributes like XL, red with white ribbing, etc. into it in some hierarchical way. What you actually do with WooCommerce product attributes is create a new taxonomy — say size, color, or something more specific to your product category — and then you get to use that as its own taxonomy in WordPress. It’s one dream of content-managers within another.

What’s really interesting and neat to me about this system is that the attributes themselves are a taxonomy — a way to organize data — but they’re not just that. They’re a taxonomy which creates taxonomies. If you create a new product attribute: “Thread Count”, it will then create a taxonomy where you can have your “classes” of thread count: “200-300”, “300-400”, etc. WooCommerce knows that people are likely to want to use those attributes to view all your sheet sets in a given range, so rather than jury-rigging custom fields or some other system to make thread count easy to browse, it’s using the native powers of WordPress to put taxonomies inside of taxonomies.

But how does it work? Diving into PHP


Fair warning: if you’re scared of PHP and don’t really want to know about the internals of this taxonomic inception, you can pretty much put this down. Mention at a cocktail party where WooCommerce comes up, “Hey, you know WooCommerce product attributes create their own taxonomies” and you’ll have sufficiently proven your nerd cred and killed any fledging conversation that may have been going on.

But if you want to know more, read on. I’ve dug into the WooCommerce source enough to find the really interesting bit — where a taxonomy creates another taxonomy — and want to walk through how that’s working.

You ready? I trimmed this down a lot, and it’ll need some contextualization to really make sense, but let’s tear the Band-Aid right off:

Lines 175 - 219
if ( $attribute_taxonomies = wc_get_attribute_taxonomies() ) {
    foreach ( $attribute_taxonomies as $tax ) {
        if ( $name = wc_attribute_taxonomy_name( $tax->attribute_name ) ) {

            $label = ! empty( $tax->attribute_label ) ? $tax->attribute_label : $tax->attribute_name;

            $wc_product_attributes[ $name ] = $tax; // used as a global elsewhere

                apply_filters( 'woocommerce_taxonomy_objects_' . $name, array( 'product' ) ),
                apply_filters( 'woocommerce_taxonomy_args_' . $name, array(/* … sane defaults … */) )

Perhaps against my better judgement, I left all apply_filters() in place. If you’re not familiar, I can point you to this explanation I wrote a few months back about how WordPress hooks and filters work, but you can just understand them as the functional equivalent of using the the second parameter of the function call naked.

We have an array of taxonomies — maybe 1, maybe 100 — and we iterate (perform the same action for each element) over it. That’s what foreach() does in PHP.

So what’s going on here? Well first, we don’t want to go about creating taxonomies for our taxonomy if it’s got nothing in it. In the first line just understand that wc_get_attribute_taxonomies() returns false and the whole block is skipped if there are no taxonomies. If there are, we enter the block and use them as an array stored in the $attribute_taxonomies variable.

Now, we have an array of taxonomies — maybe 1, maybe 100 — and we iterate (perform the same action for each element) over it. That’s what foreach() does in PHP. With that array, we first make sure we get a valid name — our second if — and if we do we set a variable $label that is used when registering the taxonomy. You don’t see that variable appear in the code again, because I hid it in the array() I labelled “sane defaults”.

The setting of the $label variable, if you’re not familiar, is using what computer scientists call an “inline control structure”, which is just a fancy way of saying “an abbreviated if statement”. In PHP, and most languages, an inline control structure can be read as “if the thing to the left of the question mark is true, use the option before the colon, otherwise use the one after”. It’s far more convenient to write, but a bit harder for the unacquainted to understand — the eternal trade-off of programming.

Back on track: then the code socks the taxonomy it’s about to register into an array — this is completely irrelevant to this code block, but I didn’t take it out. It’s used elsewhere in WooCommerce.

yo-dawg-wordpress-taxonomiesFinally, we’re registering our taxonomy. The syntax is much like that I described two weeks ago, but as I mentioned we’ve got some apply_filters() making it more confusing. apply_filters is being used here to make it relatively easy for another plugin or theme to change the way this is all happening if it wants, but otherwise just sits inert.

To Recap…

We got a bit bogged down there inside the code, and it’s easy to forget the big picture: we’re taking a taxonomy which was registered and accessed elsewhere, and then using it to register more taxonomies. We’ve got structure inside our structure. It’s a crazy fun world in WooCommerce.

I hope you learned something if you stuck with us through the whole thing. And if you’ve skipped down here, just remember that it’s crazy weird but totally possible to use taxonomies to make even more taxonomies. There are cases to be made both for and against it, but WooCommerce does it and now you know.

Did I leave something out? Am I not seeing another interesting data relationship or mapping in WooCommerce, or some other plugin? Comments are always open and appreciated, and our email address is easy to find. Happy hacking!

Image credit: ke7dbx