Attribuut-taxonomieën (WooCommerce)

Uit De Vliegende Brigade
Ga naar: navigatie, zoeken
Database-model van vermoedelijk WordPress 4.4. Ietwat achterhaald, maar prima om een indruk te krijgen

WooCommerce's Attributes (Kenmerken) zijn een bijzondere variant van het algemene Categorie'-taxonomie-systeem. Ze komen in twee smaken:

  • Predefined Attributes
  • Custom Attributes.

Dit hoofdstuk gaat voornamelijk over deze eerste variant.

Database-tabellen

wp_woocommerce_attribute_taxonomies

Tabel wp_woocommerce_attribute_taxonomies bevat alleen beschrijvingen van de taxonomieën. Da's ca. hetzelfde als de 'hoofd-taxons'. Voorbeeld:

SELECT * FROM kbo3.wp_woocommerce_attribute_taxonomies;


attribute_id   attribute_name      attribute_label     attribute_type   attribute_orderby   attribute_public
------------   --------------      -----------------   --------------   -----------------   ----------------
5	       breedte             Breedte	       text	        name_num	    1
6	       diepte	           Diepte	       text	        name_num	    1
7	       lengte	           Lengte	       text	        name_num	    1
8	       automatische_stop   Automatische stop   text	        name	            1

wp_terms

Subtaxons verschijnen gewoon in wp_terms. Dat maakt het gemakkelijk om met subtaxons te werken, want het werkt hetzelfde als voor gewone categorieën.

wp_term_taxonomy

Tabel wp_term_taxonomy verbindt taxons met taxonomieën. Hier kun je zien dat WooCommerce 'onder water' losse taxonomieën defineert voor alle attributen. Je herkent ze aan de prefix pa_. Merk op dat parent=0: Er wordt niet gebruik gemaakt van hierarchie! Ook niet zo vreemd, omdat je bij attributen max. twee lagen hebt. Voorbeeld:

SELECT * FROM kbo3.wp_term_taxonomy where taxonomy like "pa_%";

term_taxonomy_id   term_id   taxonomy     description     parent   count
----------------   -------   ----------   -------------   ------   -----
110                110       pa_breedte   Breedte-taxon   0        0

wp_term_relationships

Tabel wp_term_relationships verbindt taxons met WordPress-objecten.

wp_termmeta

Tabel wp_termmeta lijkt metadata te bevatten: Als je nog iets extra's kwijt wilt over een taxon, kun je dat hier doen. WooCommerce maakt hier bv. voor product_cat-taxonomieën aan, om de count per hoofdtaxon in op te slaan.

Het lijkt vooralsnog niet gebruikt te worden voor attribuut-taxonomieën.

Database-velden

In het algemeen zijn veldnamen binnen een WordPress-instantie niet consistent. Dat kun je zien aan het ER-diagram elders in dit artikel:

  • In tabel wp_users heet de pk ID
  • In tabel wp_usermeta heet dit veld user_id
  • In tabel wp_posts heet dit veld post_author.

Desalniettemin: Rondom taxonomieën lijken veldnamen consistent te zijn. Anders had dit hoofdstuk weinig zin.

term_id

term_id is de pk voor een taxon of term.

term_taxonomy_id

  • term_taxonomy_id is de pk van de tussentabel wp_term_taxonomy, die ervoor zorgt dat je een many-to-many-relatie hebt tussen terms en term_relationships
  • Zo'n veel-veel-relatie ben ik tot op heden nog niet tegengekomen. Vandaar dat deze twee velden steeds dezelfde waardes lijken te hebben: Er zijn dan evenveel records in beide tabellen
  • Overigens: Ik heb geen idee waarom je zo'n veel-veel-relatie wilt hebben, maar daar gaat het nu niet om.

UI-Velden

Dit zijn de velden die ik zoal in de user interface tegenkom. Namen zijn inconsistent en niet-intuïtief

Name - attribute_name

Shown on the front-end

Slug - attribute_label

Max. 28 karakters.

attribute_type

Het soort control dat gebruikt wordt als interface??? Bv.:

  • select - Beperkt aantal keuzes, zoals een lookup-tabel of voor Boolese waarden
  • text - Tekstveld, lijkt me.

Enable Archives

Dus dat je een 'taxon-pagina' hebt. Altijd doen. Voor Attributes-taxonomieën kun je helaas geen afbeelding of tekst toevoegen (itt. gewone Categorieën) [1]

Custom ordering - attribute_orderby

Niet zo spannend:

  • menu_order
  • name
  • etc.

attribute_public

Taxonomieën worden binnen een WordPress-site veelvuldig gebruikt voor interne aangelegenheden. Bv. om vertalingen bij te houden. Vandaar dat je er voor kunt kiezen om attribuut-taxonomieën verborgen te houden voor gebruikers.

Taxonomie toevoegen

Met taxonomie bedoel ik hier hetzelfde als hoofdtaxon .

Toevoegen van een hoofdtaxon/taxonomie, wil niet lukken met bv. wp_insert_term. Aangezien Attributes een speciaal geval is van een categorie, zou je verwachten dat dit werkt. Maar dat doet het niet. Gelukkig kun je dit op een meer low-level fixen mbv. $wpdb. Daar gebruik ik deze functies voor. Deze staat in één van m'n libraries (niet in functions.php). Geïnspireerd op [2]:

function dvb_add_attribute_taxonomy($attribute)
{
    # Add a WooCommerce Attribute-taxonomy
    #######################################################################################################
    #
    # * Somehow, the usual function register_taxonomy doesn't work for WooCommerce Attributes, hence the
    #   lower-level approach in this function
    # * Based on the example https://wordpress.stackexchange.com/questions/244335/creating-custom-woocommerce-attribute-taxonomies-from-a-plugin
    # * Jeroen Strompf, De Vliegende Brigade - April 2019
    # * To be included in functions.php where appropriate


    #######################################################################################################
    # Get acces to $wpdb class
    #######################################################################################################
    #
    global $wpdb;


    #######################################################################################################
    # Verify input
    #######################################################################################################
    #
    if (empty($attribute['attribute_type'])) { $attribute['attribute_type'] = 'text';}
    if (empty($attribute['attribute_orderby'])) { $attribute['attribute_orderby'] = 'menu_order';}
    if (empty($attribute['attribute_public'])) { $attribute['attribute_public'] = 0;}
    if (empty( $attribute['attribute_name'] ) || empty( $attribute['attribute_label'] ) ) 
    {
            return new WP_Error( 'error', __( 'Attribute name and/and slug is missing.', 'woocommerce' ) );
    } 
    elseif ( ( $valid_attribute_name = dvb_check_attribute_name( $attribute['attribute_name'] ) ) && is_wp_error( $valid_attribute_name ) ) 
    {
            return $valid_attribute_name;
    } 
    elseif ( taxonomy_exists( wc_attribute_taxonomy_name( $attribute['attribute_name'] ) ) ) 
    {
            return new WP_Error( 'error', sprintf( __( 'Slug "%s" already in use', 'woocommerce' ), sanitize_title( $attribute['attribute_name'] ) ) );
    }


    #######################################################################################################
    # Insert into WordPress
    #######################################################################################################
    #
    $wpdb->insert( $wpdb->prefix . 'woocommerce_attribute_taxonomies', $attribute );

    do_action( 'woocommerce_attribute_added', $wpdb->insert_id, $attribute );

    flush_rewrite_rules();
    delete_transient( 'wc_attribute_taxonomies' );

    return true;
};

function dvb_check_attribute_name( $attribute_name )
{
    # Check if a given attribute name is valid
    #######################################################################################################
    #
    # * Based on the example https://wordpress.stackexchange.com/questions/244335/creating-custom-woocommerce-attribute-taxonomies-from-a-plugin
    # * Jeroen Strompf, De Vliegende Brigade - April 2019
    # * To be included in functions.php where appropriate

    if ( strlen( $attribute_name ) >= 28 ) 
    {
		return new WP_Error( 'error', sprintf( __( 'Slug "%s" is longer than 28 characters)', 'woocommerce' ), sanitize_title( $attribute_name ) ) );
    } 
    elseif ( wc_check_if_attribute_name_is_reserved( $attribute_name ) ) 
    {
		return new WP_Error( 'error', sprintf( __( 'Slug "%s" is not allowed because it is a reserved term.', 'woocommerce' ), sanitize_title( $attribute_name ) ) );
    }
    return true;
};

Voorbeeld van een aanroep:

<?php

###############################################################
# Call require_once
###############################################################
#
# Functions "dvb_add_attribute_taxonomy" and 
# "dvb_check_attribute_name" have been included in functions.php. 
# They become available through this "require_once" command
#
require_once("/home/strompf/www/example.com/wp-load.php");


###############################################################
# Define new attribute-taxonomy
###############################################################
#
$attribute_definition = array
(
	'attribute_name'	=>	'attribute-naam (2)',
	'attribute_label'	=>	'attribute-plakker (2)',
	'attribute_type'	=>	'text',
	'attribute_orderby'	=>	'menu_order',
	'attribute_public'	=>	false
);


###############################################################
# Create this new attribute-taxonomy
###############################################################
#
dvb_add_attribute_taxonomy($attribute_definition);

Subtaxons toevoegen

  • Attribuut-taxonomieën zijn niet-hiërarchisch, en zitten iets anders in elkaar dan product_cat-taxonomieën:
  • Subtaxons toevoegen, gaat op dezelfde manier als voor product_cat-taxonomieën, met één verschil: De naam van de taxonomie, is de naam, voorafgegaan door pa_
  • De gebruikelijke API-functie hiervoor: wp_insert_term

Voorbeeld uit een SQL-script, waarbij pa_breedte de betreffende taxonomie is:

# Create table
##############
#
create table dim1_taxons_tmp
select distinct 
	dim1,
    concat
    (
	"wp_insert_term('",
        replace(dim1, ".", ","),"'",
        ", 'pa_breedte',",
        " array('description' => 'Alle koolborstels met een breedte van ",replace(dim1, ".", ",")," mm',",
        " 'parent' => 0, 'slug' => 'breedte-",replace(dim1, "," ,""),"' ));"
     ) as dim1_php
from root_tmp;

Je weet de 'pa-naam' pas met zekerheid, nadat er subtaxons zijn aangemaakt. Dan vind je 'm terug met zoiets als dit (in SQL):

SELECT distinct taxonomy FROM example_com.wp_term_taxonomy;

Mochten er nog geen taxons zijn toegevoegd:

  • Voeg er eentje handmatig toe, om het te testen
  • Gebruik je gezond verstand om uit te vogelen wat de naam zou zijn.

Nog één voorbeeld:

<?php
require_once("/var/www/kbo3.dvb/wp-load.php");

wp_insert_term
(
	'Met automatische stop' ,
	'pa_automatische_stop', 
	array
	(
		'description' => 'Alle koolborstels met automatische stop', 
		'parent' => 0, 
		'slug' => 'met-automatische-stop'
	)
);

wp_insert_term
(
	'Zonder automatische stop' ,
	'pa_automatische_stop', 
	array
	(
		'description' => 'Alle koolborstels zonder automatische stop', 
		'parent' => 0, 
		'slug' => 'zonder-automatische-stop'
	)
);

Verwijderen

Hoe kun je alle attribuut-taxonomieën compleet verwijderen? Dus inclusief hoofdtaxons, subtaxons, en koppelen met objecten? Voor een beetje serieuse site, is het geen optie om dit handmatig te doen, vandaar. Ik kwam geen kant-en-klare code tegen, dus lekker zelf doen!

Alles op z'n tijd

De uitdaging is, om de onderdelen in de juiste volgorde te verwijderen, zodat je weet wat-wat is. Als ik bv. terms als laatste verwijder, is er een kans dat ik niet meer weet bij welke taxonomie ze horen. Ik denk dat dit een prima volgorde is:

select * from wp_term_relationships;		     # Taxons <-> Objecten - Vroeg verwijderen
select * from wp_termmeta;			     # Metadata <-> Taxons - Vroeg verwijderen
select * from wp_term_taxonomy;			     # Taxons <-> Taxonomy - Laat verwijderen
select * from wp_terms;				     # Taxons              - Laat verwijderen
select * from wp_woocommerce_attribute_taxonomies;   # Hoofdtaxons         - Als laatste verwijderen

Zie ook

Bronnen