I have used custom product types a couple times in the past for different projects where it made sense (for example for a product rental plugin I created both a ‘simple rental’ and ‘variable rental’ product). It is only recommended to create a custom product type when it is really necessary and it doesn’t fit in the existing options of the current product types.

Getting started

In this post I will be using some examples of how to create a Simple Rental and Variable Rental product types. This will be packed in a small and overly simple plugin.

Register a new class

To get started you first need to create a class that is extending the existing WC_Product class. It is vital to have the product class named the same as in the classes’ parameter product_type, (‘same’ as in same name, each first letter of the class name should be capitalised and should have underscore separators). It is vital because WooCommerce uses the product type to get the class name and if its called differently it will not be recognised.

In my example I called my class WC_Product_Simple_Rental.

On itself, this doesn’t do much as you will not see it in the drop down when you select a product type. To add it do the product type drop down, use the following code.

Thats it!, the most basic form of adding a new product type! You will now be able to select your new product type from the drop down on the edit product pages.woocommerce-custom-product-type

 

In the rest of the post I will show a couple examples how you can further extend your own custom product type.

Regaining the price fields for a custom product type

One of the first things you might notice, is that the price fields are no longer available for your custom product type. Although it isn’t relevant for the Rental product types, it may be for your situation. Unfortunately there is no ‘official’ way of regaining those fields (via hooks for example), so we have to manually display them via a bit of Javascript/jQuery.

Adding a new settings panel for your custom product type

If you examine the code above, you will see that a class name show_if_simple_rental is being added, WooCommerce automatically shows or hides certain elements on the page that have related classes. A couple examples of available HTML classes that you can add to elements;

show_if_simple / hide_if_simple / show_if_variable / show_if_downloadable / hide_if_virtual

Each product type (also virtual and downloadable options) has its own classes to show or hide elements.

You can use the following code to add a new settings panel and it will only show for the new Simple Rental and Variable Rental product types.

WooCommerce will auto-load the values of the new custom fields if the id and the post meta field name (key) are the same.

Hiding an existing data panel for your custom product type

Good chance you will not need all the data panels for your new product type, and under the motto “less is more” it is a good idea to remove the unnecessary data panels. With the following code the “Attributes” data panel will not show for the custom product types we just created.

End result – a small custom product plugin

This is my end result when creating this post and posting the code snippets. It will work, but its a plugin in its utter most basic form. That is why its highly recommended to use this as example work, and not actually use it on your website.

Last words

I would love to hear from you if you found this useful, would like to see something else, missing something or just a simple thank you 🙂

Jeroen Sormani

I'm a professional WordPress plugin developer on a mission to create the best plugins for my clients. I'm specialised in developing general WordPress, WooCommerce and Easy Digital Downloads plugins.

Interested in talking about a WordPress project? Get in touch!

Follow me on Twitter

82 thoughts on “Adding a custom WooCommerce product type

a-coder January 22, 2016 at 11:30 am

Great guide! many thanks

jeroen January 22, 2016 at 10:29 pm

Thanks for commenting 🙂
Glad to hear you like it!

Dave January 29, 2016 at 12:34 am

This is just what I was looking for! One follow-up question: how do you move a field from one tab to another? For example, to simplify for my users I’d like to hide all the existing tabs and just put the fields I want onto one custom tab (for example, just price and weight).

Thanks!

jeroen January 29, 2016 at 7:20 pm

Hi Dave,

Basically it is not possible to move a field from one to another. It is possible to hide the old one and create a new one, but that will give conflicts.
Another hack-ish way of doing so is (re)move the field through Javascript and maybe re-create them, but that won’t be a stable way of doing things..

Am afraid there’s not solid solution for your current wishes…

Jeroen

Adrian February 12, 2016 at 8:30 am

Great Post !!

One question. Are you able to get a button to display on single product page for your custom type ? I tried everything but no luck.

jeroen February 13, 2016 at 11:21 am

(replied over mail :-))

Adrian February 15, 2016 at 6:27 am

Thanks for the reply Jeroen. For anyone else wondering how to display a button on your custom product single page you need something like this.

if (! function_exists( ‘woocommerce_CUSTOMTYPE_add_to_cart’ ) ) {

/**
* Output the simple product add to cart area.
*
* @subpackage Product
*/

function woocommerce_simple_add_to_cart() {

wc_get_template( ‘single-product/add-to-cart/CUSTOMTYPE.php’ );
}
}

You can either throw it into the woocommerce templates directory, or you can create your own template within your plugin directory and have your plugin template be called by following one of Jeroens other tutorials.

Jens February 14, 2016 at 6:55 am

Very helpful! Thanks, quite a lot of valuable info for me.

Small typo: you name simple_rental sometimes simpel_rental. This makes replacing this with your own type a tiny little bit harder.

Cheers, Jens

jeroen February 14, 2016 at 9:29 am

Thanks for noticing Jens, immediately changed it 🙂

torcat February 25, 2016 at 8:07 am

Hi Jeroen!

For my stpecial products ( customizable gifts) i have grouped products 1 main product and the custom products (etc. need crhristmas decoration or easter decoration ) but the child products its same , and its bad for inventory.

I need one custom product type with groups but the in the inventory need use the main product stock

in the normally woocomerce grouped product the main product have not stock quantity,
this product its hidden, need only for stock handling because if one product its out from stock can not deliver another from this groupbecause its same product.
Variation its bad for me, because products from group have anothe image and anthe decription

have you idee?

Natassa March 8, 2016 at 11:59 am

Hello Jeroen,

excellent instructions. Thank you.

One question. In front end I need to check if a product is of my custom product type or simple but if I use the function $product->is_type() it always return simple as product type. The only way to get the right product_type is to use get_the_terms($product_id, ‘product_type’) function.

Do you know why this is happening?

jeroen March 11, 2016 at 2:46 pm

Hi Natassa,

Hmm, it should as you are overwriting the ‘post_type’ property.
Have you tried this code snippet and see if that returns the proper custom product type?
https://gist.githubusercontent.com/JeroenSormani/53e98a9d82362533dbdb/raw/a98be0111477c986506c2372017991953c74b52d/woocommerce-custom-product-mini-plugin.php

Let me know :-),
Jeroen

Jitesh Patil December 16, 2016 at 2:06 pm

I was facing a similar issue.

The problem is I named my class My_Product_Simple_Rental instead of WC_Product_Simple_Rental.

WooCommerce expects the class name to have a WC_Product_ prefix.

Marc March 12, 2016 at 4:22 pm

HI Jeroen,

where should I put woocommerce-custom-product-mini-plugin.php in my wordpress installation, please?

thanks

Marc

jeroen March 13, 2016 at 11:24 am

Hi Marc,

It should go in your (child) themes functions.php

I wrote a blog post about code snippets some time ago here: https://aceplugins.com/how-to-add-a-code-snippet/
Cheers,
Jeroen

Rick March 17, 2016 at 8:56 pm

Hi Jeroen,

Thanks for this – very helpful.

I noticed that the Inventory tab disappears – is there a way to make it come back?

thanks,

Rick

jeroen March 20, 2016 at 12:09 pm

Hi Rick,

It is possible to show the inventory tab for your custom product type, you’d need to add a filter to the woocommerce_product_data_tabs filter hook.
(links: https://github.com/woothemes/woocommerce/blob/beedd1c93020a9678e3d89a03c923e144b84505a/includes/admin/meta-boxes/class-wc-meta-box-product-data.php#L89)

Hope that steers you in the right direction 😉

Cheers,
Jeroen

Vishal April 4, 2016 at 9:42 am

Hi Jeroen,

Thanks for this tutorial, it helps me lot but,

I added function on ‘woocommerce_get_price_html’ action when i am trying to check the product type of my custom product type this $product->is_type() it always return simple as product type.

From other way as @natasa said right product_type get only by using get_the_terms($product_id, ‘product_type’) for me.

I don’t know i am doing wrong or right can you guide me because i need to make changes on product price when it displays on front-end.

Thanks,
Vishal

myth99 May 8, 2016 at 9:30 am

Hi Vishal,

I got it by this code
$args = array(
‘post_type’ => ‘product’,
‘orderby’ => ‘post_title’,
‘order’ => ‘ASC’ ,
‘numberposts’ => -1,
‘tax_query’ => array(
‘relation’ => ‘AND’,
array(
‘taxonomy’ => ‘product_type’,
‘field’ => ‘term_id’,
‘terms’ => 110, // change this to term id in your database *** table name – term_taxonomy
‘include_children’ => false
)
)
);

$the_query = new WP_Query( $args );

Ryan Weiss January 9, 2017 at 1:28 am

The solution I found was to set the product_type in the custom class’s constructor AFTER the call the parent::__construct(), ie:

public function __construct( $product ) {
parent::__construct( $product );
$this->product_type = ‘custom’;
}

myth99 May 8, 2016 at 9:31 am

thanks jeroen 🙂

Andrew May 14, 2016 at 1:59 am

Hello Jeroen,

Thank you for this great article!

And I have a question 🙂 Is there any way to extend a Variable product type? In the beginning of the article you mentioned that you will also create “variable rental” but I have not found it in the code…

Simeoncvetkov June 2, 2016 at 9:00 am

HI Jeroen,
I admire you on what you do have one vapros can I recreate this plugin thanks
http://mreja.net/produkt/woocommerce-lease-calculator-plugin/

Behrad June 6, 2016 at 4:42 pm

Hi Jeroen,

Where I live, Iran, it is almost impossible for anyone to do international shopping, i.e Amazon etc. . So basically what I’m trying to do is building an e-commerce website with two functionalities. One is the classic shop with listed products etc. which Woocommerce handles beautifully. But I would also like to make customers able to order from third-party websites, so basically customers will enter an URL and I’ll do the shopping for them, is it possible to make a Woocommerce product which is simply a URL field? I need it to use Woocommerce because I need each order to be reviewed and saved in each users’ profile.

Thanks,
Behrad

jeroen June 6, 2016 at 8:31 pm

Hi Behrad,

Everything is possible 😉

Though I don’t think a custom product type is the best way to go here. I think just creating a new product and then add a custom field through a plugin like ‘Product Add-Ons’ that allows one to enter the URL would be more fitting for you 😉

Hope that helps.

Cheers,
Jeroen

Behrad June 8, 2016 at 3:38 pm

Thanks for the quick reply.

I tried a few things, including your advice, but unfortunately it seems that no existing plugin is fit for my case! 🙁

It’d seem that I’ll have to go down the dirty road of writing a plugin myself. I tried to use WooCommerce but it’s only capable of classic shopping, select a product, add to cart, checkout, pay and etc.. but in my special case I need the customer to be able place a custom order which is a non-specific webpage, and that should be saved to their profile, without the need for cart, checkout and other hassles. I need to review the order and then disclose the price for them and then they’ll be notified of this and be able to pay. I looked very hard but couldn’t find any setting or plugin that would do this for me. Is there something I’m missing?

Daniele June 7, 2016 at 2:28 pm

hi

Finaly somebody who knows how woocommerce works inside, thanks!
I have a question:

I need to calculate the price of my product on a file uploaded by customer, so i make a ajax call to server to obtain the price in runtime.
Actualy i made this with many hooks and filter but in this way i loose the possibility to use ohter plugins.
So i decide to write my own product class following this tutorial.
The problem is that the product extendeds variable product instead of single product because the price depeneds on the choice of customer and now i don’t know where puts my code to call the ajax api.
Best regards,

Daniele

Matt June 22, 2016 at 10:33 pm

Thanks a bunch, this saved me from trawling through the WC source for another two hours. I love event/hook-driven architecture, but it’s a nightmare to follow when you’re trying to figure out someone else’s code. Little guides like this help a lot.

D November 10, 2016 at 5:01 pm

Nice, clear and complete!
Thank you!

Myles November 18, 2016 at 1:23 am

Thanks for posting this!

Kenneth December 6, 2016 at 10:28 am

Great article!
Just one question: can you show a different product page in the front-end based on the product?

Jeroen December 7, 2016 at 1:57 pm

Hi Kenneth,

It is possible to do something like that, though it would require some extra efforts if you want to setup a whole different product page. You could go two ways about with this:
1) Remove parts that WooCommerce is adding through their hooks on the template page, and add your own here.
2) Completely change the template to start with in the template loader when WordPress is loading the templates you can override this with your own (‘template_include’ hook).

Cheers,
Jeroen

Kenneth December 13, 2016 at 5:28 pm

Hi Jeroen,

I did it slightly different, as it seems to be using the Simple product type parts.
The only thing it is not using is the add-to-cart items in the template.

Any idea why that could be?

Mte90 December 22, 2016 at 7:01 pm

There is a bug in the js code:
`jQuery( ‘.options_group.pricing’ ).removeClass(‘hidden’).addClass( ‘show_if_simple_ticket’ ).addClass(‘hidden’);`
Is the right snippet becase can be problems with the switching if hidden is not the last class for the css rules.

Jeroen December 23, 2016 at 10:04 am

Hi,

Why would it be an issue if the ‘hidden’ isn’t the last class? I’m pretty confident WooCommerce core works either way, and CSS also doesn’t care about that.

Would love to hear your reasoning! 🙂

Cheers,
Jeroen

Caroline January 15, 2017 at 9:38 am

Thank you for a very useful post Jeroen! 🙂
It’s something with that jQuery that doesn’t work entirely right for me either though. If I refresh the page, including when I update the product, with my custom product type selected, then the general tab with the pricing fields disappear. It will only show again if I switch product type from my custom to another and then back again. Any clue of how to get around that? Mte90’s code snippet didn’t solve my problem.

Caroline January 15, 2017 at 11:15 am

Maybe not the best solution, but I finally solved it by adding these lines to the script:

jQuery( ‘#linked_product_data’ ).addClass( ‘hidden’ ).hide(); //Hide Linked Products Data Tab on load
jQuery( ‘#general_product_data’ ).removeClass( ‘hidden’ ).show(); //Show General Products Data Tab on load
jQuery( ‘.general_options’ ).addClass( ‘show_if_bookable active’ ).show(); //Activate General Link in left Menu
jQuery( ‘.linked_product_options’ ).removeClass( ‘active’ ); //Deactivate Linked Products Link in left Menu

Peter February 20, 2017 at 7:42 pm

Hi Caroline,

Thanks for the idea. I was suffering from the same problem as you. I also went a step further and checked that the current product is my custom product, with an if statement.

Here is my code:
// check which product type is selected
var selectedProductType = jQuery(‘#product-type’).val();
if(selectedProductType == ‘simple_non_purchasable’) {
// Deactivate shipping Link in left Menu
jQuery( ‘.shipping_tab’ ).removeClass( ‘active’ );
// Hide Shipping Panel on load
jQuery( ‘#shipping_product_data’ ).addClass( ‘hidden’ ).hide();
// Activate General Link in left Menu
jQuery( ‘.general_tab’ ).addClass( ‘active’ ).show();
// Show General Panel on load
jQuery( ‘#general_product_data’ ).removeClass( ‘hidden’ ).show();
}

This way product types that don’t have the ‘price’ field, won’t be affected, such as ‘grouped’ products.

Chris March 6, 2017 at 4:26 pm

Not sure if this is the same issue you are talking about but I had the issue that Caroline describes, where the general tab doesn’t show when you are editing a product until you toggle the product type selector.

I fixed this by putting the following in the same jQuery block output by simple_rental_custom_js():

jQuery( ‘select#product-type’ ).trigger(‘change’);

It just triggers the change event on that input, which WooCommerce js listens to and updates the displayed fields.

Rakesh January 4, 2017 at 3:34 pm

very useful thanks

Leave a Reply