How to Add a Custom Price Break-Up in WooCommerce

Support for Making Charges, GST, and Extra Taxes for Simple and Variable Products.

Overview

By default, WooCommerce allows you to set a single price for a product. However, for industries like jewelry, electronics, or specialized manufacturing, you often need to show a clear Price Break-up. This includes manufacturing costs (Making Charges), government taxes (GST), and additional surcharges.

This tutorial provides a complete PHP solution to integrate these fields directly into your WooCommerce dashboard and display them automatically on the front end.

How It Works

  • Admin Integration: New fields are added to both Simple and Variable product settings.
  • Dynamic Logic: The GST field can be set as a Fixed Amount or a Percentage of the base price.
  • Cart Recalculation: The plugin hooks into woocommerce_before_calculate_totals to ensure the cart total reflects the sum of the base price and all additional charges.
  • Checkout Transparency: All extra charges are listed as metadata in the cart and checkout pages so customers know exactly what they are paying for.

The Plugin Code

Copy the code below into a new file named woocommerce-price-breakup.php and upload it to your wp-content/plugins folder, or paste it into your theme's functions.php file.

<?php
/**
 * Plugin Name: WooCommerce Price Break-Up
 * Description: Adds Making Charge, GST (fixed or %), and Extra Tax with cart, checkout & variable product support.
 * Version: 1.1.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/* ======================================================
 * SIMPLE PRODUCT FIELDS
 * ====================================================== */

add_action( 'woocommerce_product_options_pricing', 'prefix_add_simple_price_breakup_fields' );
function prefix_add_simple_price_breakup_fields() {

    woocommerce_wp_text_input( array(
        'id' => '_making_charge',
        'label' => 'Making Charge',
        'type' => 'number',
        'custom_attributes' => array( 'step' => 'any', 'min' => '0' ),
    ) );

    woocommerce_wp_select( array(
        'id' => '_gst_type',
        'label' => 'GST Type',
        'options' => array(
            'fixed'   => 'Fixed',
            'percent' => 'Percentage',
        ),
    ) );

    woocommerce_wp_text_input( array(
        'id' => '_gst_amount',
        'label' => 'GST Value',
        'type' => 'number',
        'custom_attributes' => array( 'step' => 'any', 'min' => '0' ),
    ) );

    woocommerce_wp_text_input( array(
        'id' => '_extra_tax',
        'label' => 'Extra Tax',
        'type' => 'number',
        'custom_attributes' => array( 'step' => 'any', 'min' => '0' ),
    ) );
}

/* ======================================================
 * SAVE SIMPLE PRODUCT
 * ====================================================== */

add_action( 'woocommerce_admin_process_product_object', 'prefix_save_simple_price_breakup_fields' );
function prefix_save_simple_price_breakup_fields( $product ) {

    $product->update_meta_data( '_making_charge', wc_clean( $_POST['_making_charge'] ?? 0 ) );
    $product->update_meta_data( '_gst_type', wc_clean( $_POST['_gst_type'] ?? 'fixed' ) );
    $product->update_meta_data( '_gst_amount', wc_clean( $_POST['_gst_amount'] ?? 0 ) );
    $product->update_meta_data( '_extra_tax', wc_clean( $_POST['_extra_tax'] ?? 0 ) );
}

/* ======================================================
 * VARIATION FIELDS
 * ====================================================== */

add_action( 'woocommerce_variation_options_pricing', 'prefix_add_variation_price_breakup_fields', 10, 3 );
function prefix_add_variation_price_breakup_fields( $loop, $variation_data, $variation ) {

    woocommerce_wp_text_input( array(
        'id'    => '_making_charge[' . $variation->ID . ']',
        'label' => 'Making Charge',
        'type'  => 'number',
        'value' => get_post_meta( $variation->ID, '_making_charge', true ),
        'custom_attributes' => array( 'step' => 'any', 'min' => '0' ),
    ) );

    woocommerce_wp_select( array(
        'id'    => '_gst_type[' . $variation->ID . ']',
        'label' => 'GST Type',
        'value' => get_post_meta( $variation->ID, '_gst_type', true ),
        'options' => array(
            'fixed'   => 'Fixed',
            'percent' => 'Percentage',
        ),
    ) );

    woocommerce_wp_text_input( array(
        'id'    => '_gst_amount[' . $variation->ID . ']',
        'label' => 'GST Value',
        'type'  => 'number',
        'value' => get_post_meta( $variation->ID, '_gst_amount', true ),
        'custom_attributes' => array( 'step' => 'any', 'min' => '0' ),
    ) );

    woocommerce_wp_text_input( array(
        'id'    => '_extra_tax[' . $variation->ID . ']',
        'label' => 'Extra Tax',
        'type'  => 'number',
        'value' => get_post_meta( $variation->ID, '_extra_tax', true ),
        'custom_attributes' => array( 'step' => 'any', 'min' => '0' ),
    ) );
}

/* ======================================================
 * SAVE VARIATIONS
 * ====================================================== */

add_action( 'woocommerce_save_product_variation', 'prefix_save_variation_price_breakup_fields', 10, 2 );
function prefix_save_variation_price_breakup_fields( $variation_id, $i ) {

    update_post_meta( $variation_id, '_making_charge', wc_clean( $_POST['_making_charge'][ $variation_id ] ?? 0 ) );
    update_post_meta( $variation_id, '_gst_type', wc_clean( $_POST['_gst_type'][ $variation_id ] ?? 'fixed' ) );
    update_post_meta( $variation_id, '_gst_amount', wc_clean( $_POST['_gst_amount'][ $variation_id ] ?? 0 ) );
    update_post_meta( $variation_id, '_extra_tax', wc_clean( $_POST['_extra_tax'][ $variation_id ] ?? 0 ) );
}

/* ======================================================
 * PRICE CALCULATION (CART)
 * ====================================================== */

add_action( 'woocommerce_before_calculate_totals', 'prefix_apply_price_breakup_cart', 20 );
function prefix_apply_price_breakup_cart( $cart ) {

    if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
        return;
    }

    foreach ( $cart->get_cart() as $cart_item ) {

        if ( isset( $cart_item['breakup_done'] ) ) {
            continue;
        }

        $product = $cart_item['data'];
        $product_id = $product->get_id();

        $base = (float) $product->get_price();
        $making = (float) get_post_meta( $product_id, '_making_charge', true );
        $gst_type = get_post_meta( $product_id, '_gst_type', true );
        $gst_val = (float) get_post_meta( $product_id, '_gst_amount', true );
        $extra = (float) get_post_meta( $product_id, '_extra_tax', true );

        $gst = ( $gst_type === 'percent' ) ? ( $base * $gst_val / 100 ) : $gst_val;

        $product->set_price( $base + $making + $gst + $extra );
        $cart_item['breakup_done'] = true;
    }
}

/* ======================================================
 * SINGLE PRODUCT PAGE BREAKUP
 * ====================================================== */

add_action( 'woocommerce_before_add_to_cart_form', 'prefix_show_price_breakup_single' );
function prefix_show_price_breakup_single() {
    global $product;

    $id = $product->get_id();
    $base = (float) $product->get_price();

    $making = (float) get_post_meta( $id, '_making_charge', true );
    $gst_type = get_post_meta( $id, '_gst_type', true );
    $gst_val = (float) get_post_meta( $id, '_gst_amount', true );
    $extra = (float) get_post_meta( $id, '_extra_tax', true );

    if ( ! $making && ! $gst_val && ! $extra ) {
        return;
    }

    $gst = ( $gst_type === 'percent' ) ? ( $base * $gst_val / 100 ) : $gst_val;
    ?>
    <div class="wc-price-breakup" style="margin: 20px 0; padding: 15px; border: 1px dashed #ccc; border-radius: 5px; background: #fafafa;">
        <strong>Price Break-up</strong>
        <ul style="list-style: none; padding: 0; margin: 10px 0 0 0;">
            <?php if ( $making ) : ?><li>Making Charge: <?php echo wc_price( $making ); ?></li><?php endif; ?>
            <?php if ( $gst ) : ?><li>GST: <?php echo wc_price( $gst ); ?></li><?php endif; ?>
            <?php if ( $extra ) : ?><li>Extra Tax: <?php echo wc_price( $extra ); ?></li><?php endif; ?>
            <li style="margin-top: 5px; border-top: 1px solid #ddd; padding-top: 5px;"><strong>Final Price: <?php echo wc_price( $base + $making + $gst + $extra ); ?></strong></li>
        </ul>
    </div>
    <?php
}

/* ======================================================
 * CART + CHECKOUT DISPLAY
 * ====================================================== */

add_filter( 'woocommerce_get_item_data', 'prefix_show_breakup_cart_checkout', 10, 2 );
function prefix_show_breakup_cart_checkout( $data, $cart_item ) {

    $id = $cart_item['data']->get_id();
    $base = (float) $cart_item['data']->get_price();

    $making = (float) get_post_meta( $id, '_making_charge', true );
    $gst_type = get_post_meta( $id, '_gst_type', true );
    $gst_val = (float) get_post_meta( $id, '_gst_amount', true );
    $extra = (float) get_post_meta( $id, '_extra_tax', true );

    $gst = ( $gst_type === 'percent' ) ? ( $base * $gst_val / 100 ) : $gst_val;

    if ( $making ) $data[] = array( 'name' => 'Making Charge', 'value' => wc_price( $making ) );
    if ( $gst )    $data[] = array( 'name' => 'GST', 'value' => wc_price( $gst ) );
    if ( $extra )  $data[] = array( 'name' => 'Extra Tax', 'value' => wc_price( $extra ) );

    return $data;
}

Tip: Make sure to test this on a staging site before applying it to your live store. Ensure your WooCommerce currency settings are correctly configured for the wc_price() function to display symbols correctly.