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.
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 🙂
82 thoughts on “Adding a custom WooCommerce product type”
Great guide! many thanks
Thanks for commenting 🙂
Glad to hear you like it!
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!
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
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.
(replied over mail :-))
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.
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
Thanks for noticing Jens, immediately changed it 🙂
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?
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?
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
I was facing a similar issue.
The problem is I named my class
My_Product_Simple_Rental
instead ofWC_Product_Simple_Rental
.WooCommerce expects the class name to have a
WC_Product_
prefix.HI Jeroen,
where should I put woocommerce-custom-product-mini-plugin.php in my wordpress installation, please?
thanks
Marc
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
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
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
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
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 );
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’;
}
thanks jeroen 🙂
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…
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/
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
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
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?
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
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.
Nice, clear and complete!
Thank you!
Thanks for posting this!
Great article!
Just one question: can you show a different product page in the front-end based on the product?
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
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?
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.
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
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.
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
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.
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.
very useful thanks