Beyond the Basics - dark developer workspace with WooCommerce custom fields code editor

WooCommerce product pages ship with a standard set of fields: title, price, description, SKU, and a handful of attributes. For many stores, that is enough. But the moment you sell configurable products, wholesale goods, or anything that requires additional specifications, you hit a wall. Custom fields solve that problem by letting you attach arbitrary data to any product without modifying the WooCommerce core.

In this guide you will learn three distinct approaches to adding custom fields: a no-code plugin method using Advanced Custom Fields (ACF), a lightweight programmatic approach using the WooCommerce hooks API, and a hybrid method that combines a meta-box framework with manual rendering. By the end, you will know exactly which route fits your project and how to implement it from start to finish.


Custom fields, also called custom meta or post meta, are key-value pairs stored alongside a product in the WordPress database. WooCommerce already uses custom fields internally; the regular price is stored as _regular_price, the SKU as _sku, and so on. When developers talk about adding custom fields, they mean creating new meta entries that WooCommerce does not provide out of the box.

These fields can hold virtually any data type: text strings, numbers, dates, file URLs, boolean toggles, or serialized arrays. The data is saved in the wp_postmeta table (or the newer WooCommerce HPOS tables in version 8.2 and above) and can be queried, displayed on the front end, exported in CSV feeds, and used in conditional logic throughout your store.

Common Use Cases

  • Technical specifications — wattage, dimensions, material composition for electronics or hardware.
  • Wholesale pricing tiers — a separate price field visible only to logged-in wholesale users.
  • Delivery estimates — a per-product lead time that overrides the global shipping estimate.
  • Regulatory data — certifications, country of origin, or hazardous-material flags required by law.
  • Personalization options — custom engraving text, gift messages, or upload fields the customer fills out at checkout.

Advanced Custom Fields is the most popular field-management plugin in the WordPress ecosystem, with more than two million active installations. The free version supports text, number, select, image, and several other field types. ACF Pro adds repeater fields, flexible content layouts, and the options page — features that become useful when your product data model is complex.

Step 1: Install and Activate ACF

Navigate to Plugins > Add New in your WordPress dashboard and search for “Advanced Custom Fields.” Install the plugin by Delicious Brains (formerly Elliot Condon) and activate it. You will see a new ACF menu item in the sidebar.

Step 2: Create a Field Group

Go to ACF > Field Groups > Add New. Give the group a name such as “Product Technical Specs.” Under Location Rules, set the condition to Post Type is equal to Product. This tells ACF to display these fields on every WooCommerce product edit screen.

Add the fields you need. For example:

Field LabelField NameTypeRequired
Materialproduct_materialTextNo
Weight (kg)product_weight_kgNumberNo
Warranty Periodwarranty_periodSelectYes
Certification Documentcert_documentFileNo

Click Publish (or Save Changes in ACF Pro). The fields will now appear below the product editor whenever you create or edit a product.

Step 3: Display ACF Fields on the Product Page

ACF stores data as regular post meta. To display it on the single-product page, add a snippet to your child theme’s functions.php file or a site-specific plugin:

/**
 * Display ACF custom fields on the single product page.
 * Hook into woocommerce_single_product_summary for placement
 * after the price and before the add-to-cart button.
 */
add_action( 'woocommerce_single_product_summary', function() {
    $material = get_field( 'product_material' );
    $weight   = get_field( 'product_weight_kg' );
    $warranty = get_field( 'warranty_period' );

    if ( $material || $weight || $warranty ) {
        echo '<div class="custom-product-specs">';
        echo '<h4>Technical Specifications</h4>';
        echo '<ul>';

        if ( $material ) {
            printf( '<li><strong>Material:</strong> %s</li>', esc_html( $material ) );
        }
        if ( $weight ) {
            printf( '<li><strong>Weight:</strong> %s kg</li>', esc_html( $weight ) );
        }
        if ( $warranty ) {
            printf( '<li><strong>Warranty:</strong> %s</li>', esc_html( $warranty ) );
        }

        echo '</ul></div>';
    }
}, 25 );

The priority 25 places the output after the price (priority 10) and the short description (priority 20). Adjust the number to move the section up or down on the page.


If you prefer to avoid plugin dependencies, WooCommerce provides dedicated hooks for adding fields to the product data panel in the admin. This approach is lightweight, loads no extra assets, and gives you complete control over storage and validation.

Available Product Data Tabs and Their Hooks

WooCommerce organizes the product editor into tabs: General, Inventory, Shipping, Linked Products, and Attributes. Each tab fires its own action hook where you can inject HTML inputs.

TabHookBest For
Generalwoocommerce_product_options_general_product_dataPricing add-ons, custom text
Inventorywoocommerce_product_options_inventory_product_dataStock-related metadata
Shippingwoocommerce_product_options_shipping_product_dataCustom shipping dimensions
Advancedwoocommerce_product_options_advancedMiscellaneous settings
Custom Tabwoocommerce_product_data_tabs + woocommerce_product_data_panelsGrouping many related fields

Step 1: Register the Field in the Admin

The following snippet adds a text input called “Custom Subtitle” to the General tab. Place this code in your child theme or a custom plugin file:

/**
 * Add a custom text field to the General product data tab.
 */
add_action( 'woocommerce_product_options_general_product_data', function() {
    woocommerce_wp_text_input( array(
        'id'          => '_custom_subtitle',
        'label'       => __( 'Custom Subtitle', 'flavor-starter-kit' ),
        'placeholder' => __( 'Enter a subtitle for this product', 'flavor-starter-kit' ),
        'desc_tip'    => true,
        'description' => __( 'Displayed below the product title on the single-product page.', 'flavor-starter-kit' ),
    ) );
} );

Step 2: Save the Field Value

WooCommerce does not automatically save custom fields. Hook into woocommerce_process_product_meta to handle persistence:

/**
 * Save the custom subtitle when the product is saved.
 */
add_action( 'woocommerce_process_product_meta', function( $post_id ) {
    $subtitle = isset( $_POST['_custom_subtitle'] )
        ? sanitize_text_field( wp_unslash( $_POST['_custom_subtitle'] ) )
        : '';

    update_post_meta( $post_id, '_custom_subtitle', $subtitle );
} );

Step 3: Display on the Front End

/**
 * Render the custom subtitle after the product title.
 */
add_action( 'woocommerce_single_product_summary', function() {
    global $product;
    $subtitle = get_post_meta( $product->get_id(), '_custom_subtitle', true );

    if ( $subtitle ) {
        printf(
            '<p class="product-subtitle" style="font-size:1.1em;color:#666;margin-top:-10px;">%s</p>',
            esc_html( $subtitle )
        );
    }
}, 6 ); // Priority 6 = right after the title at priority 5.

When you need more than one or two fields, creating a dedicated tab in the product data panel keeps the admin interface organized. This is the approach most professional WooCommerce extensions use.

Step 1: Register the Tab

/**
 * Add a custom "Specifications" tab to the product data panel.
 */
add_filter( 'woocommerce_product_data_tabs', function( $tabs ) {
    $tabs['specifications'] = array(
        'label'    => __( 'Specifications', 'flavor-starter-kit' ),
        'target'   => 'specifications_product_data',
        'class'    => array(),
        'priority' => 70,
    );
    return $tabs;
} );

Step 2: Add Fields to the Tab Panel

/**
 * Render the fields inside the Specifications tab panel.
 */
add_action( 'woocommerce_product_data_panels', function() {
    echo '<div id="specifications_product_data" class="panel woocommerce_options_panel">';

    woocommerce_wp_text_input( array(
        'id'    => '_spec_dimensions',
        'label' => __( 'Dimensions (L x W x H)', 'flavor-starter-kit' ),
    ) );

    woocommerce_wp_text_input( array(
        'id'    => '_spec_material',
        'label' => __( 'Material', 'flavor-starter-kit' ),
    ) );

    woocommerce_wp_select( array(
        'id'      => '_spec_warranty',
        'label'   => __( 'Warranty', 'flavor-starter-kit' ),
        'options' => array(
            ''         => __( 'Select...', 'flavor-starter-kit' ),
            '6months'  => __( '6 Months', 'flavor-starter-kit' ),
            '1year'    => __( '1 Year', 'flavor-starter-kit' ),
            '2years'   => __( '2 Years', 'flavor-starter-kit' ),
            'lifetime' => __( 'Lifetime', 'flavor-starter-kit' ),
        ),
    ) );

    woocommerce_wp_textarea_input( array(
        'id'    => '_spec_notes',
        'label' => __( 'Additional Notes', 'flavor-starter-kit' ),
    ) );

    echo '</div>';
} );

Step 3: Save All Tab Fields

/**
 * Save all specification fields on product save.
 */
add_action( 'woocommerce_process_product_meta', function( $post_id ) {
    $fields = array(
        '_spec_dimensions',
        '_spec_material',
        '_spec_warranty',
        '_spec_notes',
    );

    foreach ( $fields as $field ) {
        $value = isset( $_POST[ $field ] )
            ? sanitize_text_field( wp_unslash( $_POST[ $field ] ) )
            : '';
        update_post_meta( $post_id, $field, $value );
    }
} );

The methods above show how to get data into the admin and onto the single-product summary. Custom fields can also enhance other parts of the store experience, such as customizing the WooCommerce checkout page with conditional fields. But sometimes you want a dedicated tab on the product page, right next to the default Description and Reviews tabs. Here is how to add a “Specifications” tab on the front end:

/**
 * Add a front-end Specifications tab to the single product page.
 */
add_filter( 'woocommerce_product_tabs', function( $tabs ) {
    global $product;

    // Only show the tab if at least one spec field has data.
    $has_data = get_post_meta( $product->get_id(), '_spec_dimensions', true )
             || get_post_meta( $product->get_id(), '_spec_material', true )
             || get_post_meta( $product->get_id(), '_spec_warranty', true );

    if ( $has_data ) {
        $tabs['specifications'] = array(
            'title'    => __( 'Specifications', 'flavor-starter-kit' ),
            'priority' => 15,
            'callback' => 'render_specifications_tab',
        );
    }

    return $tabs;
} );

/**
 * Callback that outputs the Specifications tab content.
 */
function render_specifications_tab() {
    global $product;
    $id = $product->get_id();

    $specs = array(
        'Dimensions' => get_post_meta( $id, '_spec_dimensions', true ),
        'Material'   => get_post_meta( $id, '_spec_material', true ),
        'Warranty'   => get_post_meta( $id, '_spec_warranty', true ),
        'Notes'      => get_post_meta( $id, '_spec_notes', true ),
    );

    echo '<table class="shop_attributes">';
    foreach ( $specs as $label => $value ) {
        if ( $value ) {
            printf(
                '<tr><th>%s</th><td>%s</td></tr>',
                esc_html( $label ),
                esc_html( $value )
            );
        }
    }
    echo '</table>';
}

If writing PHP is not your preference, several plugins offer a visual interface for creating and managing product fields. Below is a comparison of the most widely used options in 2026.

PluginFree VersionConditional LogicHPOS CompatiblePrice (Pro)
Advanced Custom FieldsYesYesYes (since 6.2)$49/year
WooCommerce Product Add-OnsNoYesYes$49/year
Meta BoxYesPro onlyYes$49/year
PodsYes (full)YesPartialFree
JetEngine by CrocoblockNoYesYes$33/year

For most WooCommerce stores, ACF remains the best balance of flexibility and ease of use. Meta Box is a strong alternative if you need a PHP-first approach with minimal UI overhead. Pods is worth considering when budget is a concern since it is completely free and open source.


Starting with WooCommerce 8.2, the platform introduced High-Performance Order Storage (HPOS) and a similar custom tables approach for product data. If your store has migrated to the new product data tables, custom fields stored via update_post_meta() may not appear in HPOS-compatible queries.

The recommended approach going forward is to use the CRUD methods provided by WooCommerce:

/**
 * HPOS-compatible way to save and retrieve custom product meta.
 */

// Saving:
$product = wc_get_product( $product_id );
$product->update_meta_data( '_custom_subtitle', sanitize_text_field( $value ) );
$product->save();

// Reading:
$product = wc_get_product( $product_id );
$subtitle = $product->get_meta( '_custom_subtitle', true );

Using $product->update_meta_data() and $product->get_meta() ensures your custom fields work regardless of whether the store uses the traditional wp_postmeta table or the newer WooCommerce custom tables. This is the single most important compatibility consideration for any custom field implementation in 2026.


Variable products add a layer of complexity because each variation is a separate post (or HPOS entry). WooCommerce provides variation-specific hooks that let you attach fields to individual variations rather than the parent product.

Register and Save Variation Fields

/**
 * Add a custom field to each product variation.
 */
add_action( 'woocommerce_variation_options_pricing', function( $loop, $variation_data, $variation ) {
    woocommerce_wp_text_input( array(
        'id'    => '_variation_lead_time[' . $loop . ']',
        'label' => __( 'Lead Time (days)', 'flavor-starter-kit' ),
        'value' => get_post_meta( $variation->ID, '_variation_lead_time', true ),
    ) );
}, 10, 3 );

/**
 * Save the variation-level custom field.
 */
add_action( 'woocommerce_save_product_variation', function( $variation_id, $i ) {
    if ( isset( $_POST['_variation_lead_time'][ $i ] ) ) {
        update_post_meta(
            $variation_id,
            '_variation_lead_time',
            absint( $_POST['_variation_lead_time'][ $i ] )
        );
    }
}, 10, 2 );

This pattern works for any field type. The key is to include the $loop index in the field ID so WordPress can distinguish between variations when the form is submitted.


Once your custom fields are in place, you may want to filter products on the shop page or build shortcodes that display products matching specific criteria. WooCommerce queries support meta queries through the standard WP_Query meta parameters.

/**
 * Query products that have a warranty of 2 years or longer.
 */
$args = array(
    'post_type'  => 'product',
    'meta_query' => array(
        array(
            'key'     => '_spec_warranty',
            'value'   => array( '2years', 'lifetime' ),
            'compare' => 'IN',
        ),
    ),
);

$query = new WP_Query( $args );

while ( $query->have_posts() ) {
    $query->the_post();
    // Display product card.
}
wp_reset_postdata();

For HPOS-compatible stores, use wc_get_products() with the meta_query parameter instead. The syntax is nearly identical, but it routes through the WooCommerce data store layer and respects the active storage backend. This querying approach is also essential when building custom feeds for platforms like Google Shopping — see our list of WooCommerce Google Product Feed plugins for automated alternatives.


Custom fields are powerful, but they can become a performance bottleneck if misused. Here are the key things to watch:

  1. Index your meta keys. If you frequently query by a custom field, add a database index on the meta_key and meta_value columns for that key. An unindexed meta query on a catalog of 50,000 products will be noticeably slow.
  2. Avoid serialized data in queryable fields. Serialized arrays cannot be efficiently searched with SQL. If a field value needs to be filterable, store it as a flat string or number.
  3. Cache aggressively. Use the WordPress object cache (wp_cache_get/wp_cache_set) or a persistent cache like Redis to avoid repeated database hits on high-traffic product pages.
  4. Limit meta queries on archive pages. The shop page and category archives already run complex queries. Adding multiple meta conditions can double the query time. Consider using taxonomies for filterable attributes instead of meta fields.
  5. Migrate to HPOS custom tables. The new WooCommerce product tables are designed for faster lookups. If your store runs WooCommerce 8.2 or later, switching to HPOS often improves meta query performance by 30 to 50 percent, according to benchmarks published by the WooCommerce core team.

Any time you accept user input — whether from admin users entering product data or customers filling in personalization fields — security must be top of mind. Follow these rules:

  • Sanitize on save: Always use sanitize_text_field(), absint(), wp_kses_post(), or the appropriate sanitization function before writing to the database.
  • Escape on output: Use esc_html(), esc_attr(), or esc_url() when rendering custom field values in templates.
  • Verify nonces: If you build custom forms that submit field data outside the standard WooCommerce product edit flow, always check wp_verify_nonce() before processing.
  • Check capabilities: Ensure the current user has the edit_products capability before allowing meta updates. This prevents privilege escalation from subscriber or customer roles.

Even experienced developers run into pitfalls when working with WooCommerce custom fields. Here are the problems reported most frequently, along with their solutions.

Fields Not Saving

If your field appears in the admin but the value disappears after saving, confirm that you have hooked into woocommerce_process_product_meta (not save_post) and that the field ID in your save function matches the field ID in your render function exactly. A missing underscore or typo is the most common culprit.

Fields Not Appearing on the Front End

Check that the hook you chose fires on the correct template. woocommerce_single_product_summary only runs on the single-product page, not on archive or category pages. Also verify that your theme has not removed or overridden the hooks in question.

ACF Fields Missing After WooCommerce Update

Major WooCommerce updates occasionally change the product editor layout, especially with the ongoing transition to the block-based editor. If ACF fields vanish, update ACF to the latest version first. ACF 6.2 and above are tested against the latest WooCommerce releases and include HPOS compatibility patches.


Below is a complete, self-contained plugin file that ties together everything covered in this article. You can drop this file into wp-content/plugins/, activate it, and immediately start adding specifications to your products.

<?php
/**
 * Plugin Name: WC Product Specifications
 * Description: Adds a Specifications tab with custom fields to WooCommerce products.
 * Version:     1.0.0
 * Author:      Your Name
 * Requires PHP: 7.4
 */

defined( 'ABSPATH' ) || exit;

// --- Admin: Register Tab ---
add_filter( 'woocommerce_product_data_tabs', function( $tabs ) {
    $tabs['product_specs'] = array(
        'label'    => 'Specifications',
        'target'   => 'product_specs_data',
        'priority' => 70,
    );
    return $tabs;
} );

// --- Admin: Render Fields ---
add_action( 'woocommerce_product_data_panels', function() {
    echo '<div id="product_specs_data" class="panel woocommerce_options_panel">';

    $fields = array(
        '_spec_dimensions' => array( 'label' => 'Dimensions', 'type' => 'text' ),
        '_spec_material'   => array( 'label' => 'Material',   'type' => 'text' ),
        '_spec_color'      => array( 'label' => 'Color',      'type' => 'text' ),
        '_spec_warranty'   => array( 'label' => 'Warranty',   'type' => 'select',
            'options' => array( '' => 'Select...', '6m' => '6 Months', '1y' => '1 Year', '2y' => '2 Years', 'lt' => 'Lifetime' ),
        ),
    );

    foreach ( $fields as $id => $config ) {
        $args = array( 'id' => $id, 'label' => $config['label'] );
        if ( $config['type'] === 'select' ) {
            $args['options'] = $config['options'];
            woocommerce_wp_select( $args );
        } else {
            woocommerce_wp_text_input( $args );
        }
    }

    echo '</div>';
} );

// --- Admin: Save Fields ---
add_action( 'woocommerce_process_product_meta', function( $id ) {
    foreach ( array( '_spec_dimensions', '_spec_material', '_spec_color', '_spec_warranty' ) as $key ) {
        $val = isset( $_POST[ $key ] ) ? sanitize_text_field( wp_unslash( $_POST[ $key ] ) ) : '';
        update_post_meta( $id, $key, $val );
    }
} );

// --- Front End: Add Tab ---
add_filter( 'woocommerce_product_tabs', function( $tabs ) {
    global $product;
    $id   = $product->get_id();
    $keys = array( '_spec_dimensions', '_spec_material', '_spec_color', '_spec_warranty' );
    $show = false;
    foreach ( $keys as $k ) {
        if ( get_post_meta( $id, $k, true ) ) { $show = true; break; }
    }
    if ( $show ) {
        $tabs['specifications'] = array(
            'title' => 'Specifications', 'priority' => 15, 'callback' => 'wcps_render_tab',
        );
    }
    return $tabs;
} );

function wcps_render_tab() {
    global $product;
    $id    = $product->get_id();
    $specs = array(
        'Dimensions' => get_post_meta( $id, '_spec_dimensions', true ),
        'Material'   => get_post_meta( $id, '_spec_material', true ),
        'Color'      => get_post_meta( $id, '_spec_color', true ),
        'Warranty'   => get_post_meta( $id, '_spec_warranty', true ),
    );
    echo '<table class="shop_attributes">';
    foreach ( $specs as $label => $val ) {
        if ( $val ) {
            printf( '<tr><th>%s</th><td>%s</td></tr>', esc_html( $label ), esc_html( $val ) );
        }
    }
    echo '</table>';
}

Can I add custom fields to WooCommerce without a plugin?

Yes. WooCommerce provides hooks like woocommerce_product_options_general_product_data and woocommerce_process_product_meta that let you register, save, and display fields with pure PHP. Method 2 in this article covers the full implementation.

Are ACF custom fields compatible with WooCommerce HPOS?

ACF version 6.2 and above includes HPOS compatibility. If you use an older version, update ACF before enabling HPOS in WooCommerce settings. The data migration will move your field values to the new tables automatically.

How many custom fields can a WooCommerce product have?

There is no hard limit. WordPress and WooCommerce can handle hundreds of meta entries per product. However, performance degrades if you query across many fields on archive pages. For catalogs with 10,000 or more products, keep queryable fields under 10 and use object caching.

Will custom fields appear in WooCommerce REST API responses?

By default, WooCommerce exposes registered meta through the REST API. Fields prefixed with an underscore (like _custom_subtitle) are hidden from the REST API unless you explicitly register them with register_meta() and set show_in_rest to true.

What is the difference between custom fields and product attributes?

Product attributes are stored in the WooCommerce taxonomy system and are designed for variation generation and layered navigation (filtering on the shop page). Custom fields are stored as post meta and are better suited for data that does not need to be filterable, such as internal notes, specifications, or regulatory information. If customers need to filter by a value, use an attribute. For more on working with attributes, see our guide on restricting quantity per product attribute in WooCommerce. If it is display-only or admin-only data, use a custom field.


Custom fields transform WooCommerce from a generic storefront into a tailored product information system. Whether you choose the no-code ACF route, the lightweight hooks approach, or the full custom-tab method, the underlying principle is the same: define the field, save it securely, and render it where your customers need to see it.

Start with a single field on one product. Verify it saves, displays, and survives a WooCommerce update. Then expand your field set incrementally. That measured approach will save you from the debugging headaches that come with deploying dozens of fields at once.

If you need help implementing custom fields on your WooCommerce store or want a tailored solution for complex product data, reach out to our WooCommerce development team for a free consultation.