I’ve been playing around with the new options in WordPress 3.0 like the new Menu system and Custom Post types. These are fantastic additions to the WordPress engine. The guys who work on WordPress core really deserve a big hand.
One other item which gets less attention are Taxonomies. When you initiate a new Taxonomy you are basically cloning the existing Post Category or Post Tags logic. With Post Categories you are provided an additional field for parent because post categories are hierarchal. But what if you want to add additional fields to the interface? This is what I intent to disclose in this article.
Before we get into the code example let me provide some background. I’m working on a custom shopping cart for a client. I intent to support the shopping cart system using a Custom Post Type and 3 Custom Taxonomies. The Custom Post Type will be called ‘Products’. Within Product we have at least 3 new Taxonomies. These are ‘Product Categories’, ‘Product Tags’ and ‘Product Packages’. The ‘Product Categories’ and ‘Product Tags’ function similar to the Post Categories and Post Tags but are used for the Products. The third Taxonomy, ‘Product Packages’, is a little more special. A ‘Package’ in terms of the shopping cart functionality will contain information related to the product configurations. For the client a Product is a photograph and is sold in different formats as in 8 x 10 Print, 8 x 10 Matted and Framed Print, Xmas Cards, etc. You may be thinking these are are just categories and you would be correct. The WordPress Taxonomies support 4 basic fields of information Name, Slug, Parent and Description. For the ‘Product Packages’ Taxonomy I also need to store extra fields such as Active status, Unit Sale Price, Unit Ship Price and Unit Quantity.
Here is a screenshot of the actual Product Package detail.
Here is the simple code to define the new Taxonomy ‘Product Packages’. I’ve wrapped this in my init function to make it easier to use.
add_action( 'init', 'product_init' );
function product_init()
{
register_taxonomy( 'product_packages', 'products',
array( 'hierarchical' => true,
'label' => __('Product Packages'),
'query_var' => false
)
);
}
Now we want to hook into some actions created by WordPress when the new Taxonomy is registered. The first action is used to insert extra fields to the Taxonomy item edit form. Note that all Taxonomies offer the quick edit and the full edit form. This is for the full edit form only.
add_action( 'product_packages_edit_form_fields', 'edit_product_packages', 10, 2);
function edit_product_packages($tag, $taxonomy)
{
$product_package_active = get_metadata($tag->taxonomy, $tag->term_id, 'product_package_active', true);
// Check/Set the default value
if (!$product_package_active)
$product_package_active = "Yes";
$product_package_unit_price = get_metadata($tag->taxonomy, $tag->term_id, 'product_package_unit_price', true);
$product_package_ship_price = get_metadata($tag->taxonomy, $tag->term_id, 'product_package_ship_price', true);
// Check/Set the default value
$product_package_ship_unit = get_metadata($tag->taxonomy, $tag->term_id, 'product_package_ship_unit', true);
if (!$product_package_ship_unit)
$product_package_ship_unit = 1;
?>
Marking a Package to 'No' will hide all items in that package.
This is the unit price for the items in this 'package'.
This is the cost per unit to ship the products in this package.
This is the quantity of product items. Normally this will be 1. For cards this number may be 6 or 8.
Let's break down the code some. The 'add_action' is a built-in WordPress function. The first parameter 'product_packages_edit_form_fields' is a dynamic action key which is created based on the Taxonomy key + '_edit_form_fields'. In our case the Taxonomy key is 'product_packages'. This action is executed from the WordPress file wp-admin/edit-tag-form.php line 68. There is also another action on line 67 which is more generic 'edit_tag_form_fields'. But we are only concerned with the edits for our Taxonomy. From edit-tag-form.php line 68 you can see the action will pass your function two argument the Tag being edited and the Taxonomy. So our function 'edit_product_package' also supports two arguments passed into it. Though we really don't need or do anything with the second argument since we know this is our specific Taxonomy 'product_packages'.
Inside the function we call the new WordPress function 'get_metadata' to load in the meta items we will be adding to the bottom of the item edit form. This function replaces the get_post_meta function. Actually if you review the get_post_meta function in wp-includes/post.php line 1196 you will see if calls the get_metadata function. The new get_metadata function takes the same basic arguments. The big difference is the first parameter which needs to be a valid Taxonomy. In our case we pass in the Taxonomy 'product_packages'. Once we have loaded all the item meta information we then display the table row which contain our new form fields. PRetty simply.
Next we add another action hook. This one will activate when the user saves the Taxonomy item. Here is the action code.
add_action( 'edited_product_packages', 'save_product_packages', 10, 2);
function save_product_packages($term_id, $tt_id)
{
if (!$term_id) return;
if (isset($_POST['product_package_active']))
update_metadata($_POST['taxonomy'], $term_id, 'product_package_active',
$_POST['product_package_active']);
if (isset($_POST['product_package_unit_price']))
update_metadata($_POST['taxonomy'], $term_id, 'product_package_unit_price',
sprintf("%01.2f", $_POST['product_package_unit_price']));
if (isset($_POST['product_package_ship_price']))
update_metadata($_POST['taxonomy'], $term_id, 'product_package_ship_price',
sprintf("%01.2f", $_POST['product_package_ship_price']));
if (!isset($_POST['product_package_ship_unit']))
$_POST['product_package_ship_unit'] = 1;
update_metadata($_POST['taxonomy'], $term_id, 'product_package_ship_unit',
$_POST['product_package_ship_unit']);
}
This action is similar to the previous action we discussed. But one gets initiated from wp-includes/taxonomy.php line 1970 and is called after the Taxonomy item has been updated in the database. The action key 'edited_product_packages' is again made up of 'edited_' + our Taxonomy key 'product_packages'. Also like the previous action we tell the action we want to accept the maximum two arguments though we only really care about the first on. Inside the function 'save_product_packages' we check to make sure the 'term_id' was not empty. The rest of the function code simple checked if the $_POST variable was passed in from the form. And if it was the WordPress function 'update_metadata' is called with the Taxonomy key 'product_packages' and the updated value. Again the function 'update_metadata' replaced the function and works similar to 'update_post_meta'.
That is pretty much it for the WordPress coding part. (keep reading)
Not quite. There is one other important topic to discuss. We need to create a new database table to contain out 'product_packages' term meta information. Let me explain why. You might have a guess that our 'update_metadata' function would store the fields into the wp_postmeta table. Well you would be a close guess but wrong. The function 'get_metadata' and 'update'metadata' use the Taxonomy key provided via the first function argument to interact with a specific database table. The name of the database is again determined based on the name of the Taxonomy from the first argument. In our case the table name will be something like 'wp_product_packagesmeta'. Note this depends on your table prefix as defined in your site's wp_config.php. See the similarity in the tables 'wp_postmeta' and our table named 'wp_product_packagesmeta'? It is simply 'wp_' + Taxonomy key + 'meta'. Again the 'wp_' table prefix will be different depending on your settings in your wp_config.php file for the variable '$table_prefix'.
Next we need to define the table structure. Again there is a similar pattern for the column names. If you examine the wp_postmeta table columns you will see the 4 columns meta_id, post_id, meta_key and meta_value. For our table the only change is the name of the second column. Instead of 'post_id' our column will be named 'product_packages_id'. See the pattern? Taxonomy key + '_id'.
Instead of providing the exact SQL CREATE TABLE command I am only going to suggest you copy the wp_postmeta table of your current site.
My reasoning for not providing the SQL CREATE TABLE command are I don't want some people to take this literal SQL command and breaking their system then blaming me.
Copy the table structure only and name the copy 'wp_product_packagesmeta'. Then edit the table structure and rename the second column from 'post_id' to 'product_packages_id'. Once you have the table created and ready you need to tell WordPress where to use it. In the init function 'product_init' we need to make two changes. At the top inside the function add the line 'global $wpdb;'. Then at the very bottom of the function add the line '$wpdb->product_packagesmeta = $wpdb->prefix."product_packagesmeta";'. your final 'product_init' function should look like this
add_action( 'init', 'product_init' );
function product_init()
{
global $wpdb;
register_taxonomy( 'product_packages', 'products',
array( 'hierarchical' => true,
'label' => __('Product Packages'),
'query_var' => false
)
);
$wpdb->product_packagesmeta = $wpdb->prefix."product_packagesmeta";
}
Hope you enjoy this little tip. I'm already working on the next article which will build upon this one. The next article will show you how to customize the table list column when you list out the Product Packages items (see image below). Look for it soon.
You can download all the code used in the article below:
codehooligans_wordpress_taxonomy_meta.zip
You must be logged in to post a comment.