WooCommerce ships with several default product types, including simple products, grouped products, external or affiliate products, and variable products. Beyond those built-in types, we can also register our own custom product types to fit specific business needs.
For example, we might create a custom product type called Coupon product so customers can purchase coupon-based products and automatically receive coupons after checkout.
Register a new product type class
The first step is to create a new product type class and register it on init. Once that class exists, WooCommerce will know that a product type named coupon exists.
add_action( 'init', function () {
class WC_Product_Coupon extends WC_Product {
public function __construct( $product ) {
$this->product_type = 'coupon';
parent::__construct( $product );
}
}
} );
Add the new product type to the product type selector
Creating the class is not enough. We also need to add the product type to the product-type dropdown in the product editor so that store managers can actually choose it.
add_filter( 'product_type_selector', function ( $types ) {
$types['coupon'] = __( 'Coupon product', 'coupon_product' );
return $types;
} );
Add a new product type tab
A custom product type usually needs data that does not exist on the standard product types. One clean way to manage that is to add a new tab to the product data meta box.
add_filter( 'woocommerce_product_data_tabs', function ( $tabs ) {
$tabs['coupon'] = [
'label' => __( 'Coupon Product', 'coupon_product' ),
'target' => 'coupon_product_options',
'class' => 'show_if_coupon_product',
];
return $tabs;
} );
Add fields to the custom tab
Once the tab exists, we can add custom fields to it. The example below adds a text field called coupon_product_info to the custom product type tab.
add_action( 'woocommerce_product_data_panels', function () {
?>
<div id="coupon_product_options" class="panel woocommerce_options_panel">
<div class="options_group">
<?php
woocommerce_wp_text_input(
[
'id' => 'coupon_product_info',
'label' => __( 'Coupon product info', 'coupon_product' ),
]
);
?>
</div>
</div>
<?php
} );
Save the custom field value
When the product is saved, the custom field value must be saved at the same time.
add_action( 'woocommerce_process_product_meta_coupon_product', function ( $post_id ) {
$coupon_product_info = $_POST['coupon_product_info'];
if ( ! empty( $coupon_product_info ) ) {
update_post_meta( $post_id, 'coupon_product_info', esc_attr( $coupon_product_info ) );
}
} );
Display front-end data based on the product type
After the custom data is saved, we can render it on the front end. In the example below, a dedicated coupon product template is loaded when the current product type is coupon.
add_action( 'woocommerce_single_product_summary', function () {
global $product;
if ( 'coupon' === $product->get_type() ) {
$template_path = plugin_dir_path( __FILE__ ) . 'templates/';
wc_get_template( 'single-product/coupon.php', [], '', $template_path );
}
} );
That is the basic workflow for adding a custom WooCommerce product type. After the type exists, the rest depends on your own business logic, and that part will differ from one project to another.
