← Back to Logbook
April 19, 2026 by Quartermaster

WooCommerce Custom Fields: The Complete Code-First Guide to Product Metadata

woocommerce custom fields — featured hero image

WooCommerce custom fields are extra pieces of metadata you attach to products — things like materials, warranty info, custom labels, or tech specs that WooCommerce doesn’t support out of the box. You add them using WordPress’s postmeta system and WooCommerce’s own hooks, no third-party plugin required.

Most tutorials will tell you to install ACF or Meta Box. That’s the SaaS way — pay forever, pray they don’t change their pricing, lose your data when you cancel. The AODN way is different: own your code, use the hooks WooCommerce already gives you, and ship something that actually belongs to you.

⚡ Key Takeaways

  • WooCommerce custom fields are product metadata stored in wp_postmeta — no plugin needed to add them.
  • Use woocommerce_product_options_general_product_data to add fields to the product editor.
  • Use woocommerce_process_product_meta to save and sanitize field data properly.
  • Display woocommerce custom fields on the frontend with the woocommerce_single_product_summary hook.
  • Always prefix your meta keys and sanitize every input — no exceptions.
  • Variable products use their own hooks: woocommerce_product_after_variable_attributes and woocommerce_save_product_variation.
  • WooCommerce’s CRUD API ($product->update_meta_data()) is safer and more future-proof than raw update_post_meta().

What Are WooCommerce Custom Fields?

woocommerce custom fields — 8-bit treasure chest full of product metadata

WooCommerce custom fields are product-level metadata that extend what a product record can store beyond the built-in title, price, SKU, and description. They live in WordPress’s wp_postmeta table, attached to the product’s post ID.

The use cases are endless. Retailers add material composition, country of origin, warranty length, or compliance certifications. Tech stores add spec sheets, compatibility lists, and part numbers. Custom woocommerce custom fields let you attach any structured data to any product.

It’s worth separating woocommerce custom fields from product attributes. Attributes are filterable, variation-driving values shown in the attribute tab. Custom fields are freeform metadata — usually not filterable by default, but available anywhere in your template stack via PHP.

How WooCommerce Stores Custom Field Data

Every WooCommerce product is a WordPress post of type product. Its metadata lives in wp_postmeta as key-value pairs. Understanding this table structure is foundational — if you want to go deeper, read our guide on WordPress database structure explained.

WooCommerce also maintains its own product data tables (wc_product_meta_lookup and friends) for performance, but for custom field storage, wp_postmeta is still the primary home. The WooCommerce CRUD layer abstracts the raw SQL behind clean methods.

6.5M+

Active WooCommerce installations — custom fields are the #1 way developers extend product data without touching core.

Source: WooCommerce.com

How WooCommerce Custom Fields Work Under the Hood

woocommerce custom fields — 8-bit database diagram showing wp_postmeta structure

Every woocommerce custom field is a row in wp_postmeta with four columns: meta_id, post_id, meta_key, and meta_value. That’s it. The entire system is that simple under the hood.

The WooCommerce product editor is split into tabs — General, Inventory, Shipping, Linked Products, Advanced. Each tab is powered by specific action hooks that let you inject additional fields without hacking core files. Understanding WooCommerce hooks and filters is the foundation for everything in this guide.

The key difference between using raw WordPress functions and the WooCommerce CRUD API: the CRUD methods fire the right actions, keep caches in sync, and survive WooCommerce major version upgrades far better than calling update_post_meta() directly on product IDs.

How to Create & Display WooCommerce Custom Fields & Taxonomies

Add WooCommerce Custom Fields to the Product Editor

woocommerce custom fields — 8-bit product editor with custom field being added via hook

The hook woocommerce_product_options_general_product_data is your entry point for adding woocommerce custom fields to the General tab of the product editor. It fires inside the General product data panel, right after the built-in price and tax fields.

WooCommerce ships several helper functions that render properly styled, accessible form fields inside the product editor. Using them means your woocommerce custom fields look native — no custom CSS needed for the admin UI.

Text Input Field

add_action( 'woocommerce_product_options_general_product_data', 'aodn_add_custom_text_field' );

function aodn_add_custom_text_field() {
    woocommerce_wp_text_input( array(
        'id'          => '_aodn_material',
        'label'       => __( 'Material', 'aodn' ),
        'placeholder' => 'e.g. 100% Organic Cotton',
        'description' => __( 'Enter the primary material for this product.', 'aodn' ),
        'desc_tip'    => true,
    ) );
}

The id key doubles as the meta key in the database. Prefixing it with an underscore (_aodn_material) hides it from the generic WordPress Custom Fields metabox in the classic editor — cleaner UX, no duplicate editing surfaces.

Checkbox, Select, and Textarea Fields

WooCommerce gives you four primary field helpers for woocommerce custom fields: woocommerce_wp_text_input(), woocommerce_wp_checkbox(), woocommerce_wp_select(), and woocommerce_wp_textarea_input(). Each accepts the same options array structure.

// Checkbox
woocommerce_wp_checkbox( array(
    'id'    => '_aodn_is_handmade',
    'label' => __( 'Handmade Product', 'aodn' ),
) );

// Select / Dropdown
woocommerce_wp_select( array(
    'id'      => '_aodn_warranty',
    'label'   => __( 'Warranty', 'aodn' ),
    'options' => array(
        ''         => __( 'Select warranty', 'aodn' ),
        '6_months' => __( '6 Months', 'aodn' ),
        '1_year'   => __( '1 Year', 'aodn' ),
        '2_years'  => __( '2 Years', 'aodn' ),
    ),
) );

// Textarea
woocommerce_wp_textarea_input( array(
    'id'    => '_aodn_care_instructions',
    'label' => __( 'Care Instructions', 'aodn' ),
    'rows'  => 4,
) );

🏴‍☠️ PIRATE TIP: Always prefix your meta keys with your project slug (like _aodn_). It prevents collisions with WooCommerce, other plugins, and your future self. Unprefixed woocommerce custom fields are a landmine waiting to explode on update day.

Save WooCommerce Custom Fields Data

woocommerce custom fields — 8-bit floppy disk saving product metadata to database

Use the woocommerce_process_product_meta hook to save your woocommerce custom fields when the product is published or updated. This hook fires during product save and passes the post ID as its argument.

Never skip sanitization. Every value coming through $_POST is untrusted input. Use sanitize_text_field() for plain strings, wp_kses_post() for HTML content, and absint() or floatval() for numeric values.

add_action( 'woocommerce_process_product_meta', 'aodn_save_custom_fields' );

function aodn_save_custom_fields( $post_id ) {
    $product = wc_get_product( $post_id );

    // Text field
    if ( isset( $_POST['_aodn_material'] ) ) {
        $product->update_meta_data(
            '_aodn_material',
            sanitize_text_field( $_POST['_aodn_material'] )
        );
    }

    // Checkbox — checkbox POSTs 'yes' when checked, nothing when unchecked
    $is_handmade = isset( $_POST['_aodn_is_handmade'] ) ? 'yes' : 'no';
    $product->update_meta_data( '_aodn_is_handmade', $is_handmade );

    // Select
    if ( isset( $_POST['_aodn_warranty'] ) ) {
        $product->update_meta_data(
            '_aodn_warranty',
            sanitize_text_field( $_POST['_aodn_warranty'] )
        );
    }

    // Textarea
    if ( isset( $_POST['_aodn_care_instructions'] ) ) {
        $product->update_meta_data(
            '_aodn_care_instructions',
            wp_kses_post( $_POST['_aodn_care_instructions'] )
        );
    }

    $product->save();
}

WooCommerce CRUD API vs Raw update_post_meta

Use $product->update_meta_data() and always call $product->save() after your updates. This is the WooCommerce-recommended approach and it keeps object caches, lookup tables, and action hooks firing correctly.

Raw update_post_meta( $post_id, '_key', $value ) still works, but it bypasses the WooCommerce object layer. For woocommerce custom fields on products, the CRUD API is always the safer bet. Read more about the WordPress metadata system in our complete guide to WordPress custom fields and meta boxes.

“Custom fields are the #1 way to extend product data without modifying core — but only if you sanitize the input and own the code.”

AI Or Die Now

Display WooCommerce Custom Fields on the Frontend

woocommerce custom fields — 8-bit product page displaying custom field data on frontend

Hook into woocommerce_single_product_summary to output your woocommerce custom fields on the single product page. This action fires inside the product summary column, after the default elements. Control the position with the priority parameter.

add_action( 'woocommerce_single_product_summary', 'aodn_display_custom_fields', 25 );

function aodn_display_custom_fields() {
    global $product;

    $material = $product->get_meta( '_aodn_material' );
    $warranty = $product->get_meta( '_aodn_warranty' );
    $care     = $product->get_meta( '_aodn_care_instructions' );

    if ( ! $material && ! $warranty && ! $care ) {
        return;
    }

    echo '<div class="aodn-product-meta">';

    if ( $material ) {
        echo '<p><strong>' . esc_html__( 'Material:', 'aodn' ) . '</strong> ' . esc_html( $material ) . '</p>';
    }

    if ( $warranty ) {
        echo '<p><strong>' . esc_html__( 'Warranty:', 'aodn' ) . '</strong> ' . esc_html( $warranty ) . '</p>';
    }

    if ( $care ) {
        echo '<p><strong>' . esc_html__( 'Care Instructions:', 'aodn' ) . '</strong> ' . wp_kses_post( $care ) . '</p>';
    }

    echo '</div>';
}

Styling the Output

Target the .aodn-product-meta class in your theme’s stylesheet or child theme. If you need a quick guide on injecting custom styles without gutting your theme, see our tutorial on how to add custom CSS to WordPress.

Always escape output. Use esc_html() for plain text, wp_kses_post() for HTML-containing values. Your woocommerce custom fields are only as safe as the escaping on both ends of the pipeline.

💡 If this is the kind of overpriced tool you are tired of paying for — we built a pirate version. Check the Arsenal.

Add WooCommerce Custom Fields to Different Product Data Tabs

woocommerce custom fields — 8-bit product data tabs with custom fields in inventory and shipping panels

WooCommerce exposes separate hooks for each product data tab, so your woocommerce custom fields can live exactly where they make logical sense — not all crammed into the General tab.

The key tab-specific hooks are:

  • woocommerce_product_options_inventory_product_data — Inventory tab
  • woocommerce_product_options_shipping — Shipping tab
  • woocommerce_product_options_advanced — Advanced tab
  • woocommerce_product_options_related — Linked Products tab

Swap in the right hook and the woocommerce_wp_text_input() call stays identical — only the hook name changes.

Creating a Custom Product Data Tab

If your woocommerce custom fields are numerous enough to deserve their own space, create a custom product tab using the woocommerce_product_data_tabs filter and woocommerce_product_data_panels action.

// Register the tab
add_filter( 'woocommerce_product_data_tabs', 'aodn_add_custom_product_tab' );

function aodn_add_custom_product_tab( $tabs ) {
    $tabs['aodn_specs'] = array(
        'label'    => __( 'Specs', 'aodn' ),
        'target'   => 'aodn_specs_data',
        'class'    => array(),
        'priority' => 60,
    );
    return $tabs;
}

// Render the tab panel
add_action( 'woocommerce_product_data_panels', 'aodn_render_custom_tab_panel' );

function aodn_render_custom_tab_panel() {
    echo '<div id="aodn_specs_data" class="panel woocommerce_options_panel">';
    woocommerce_wp_text_input( array(
        'id'    => '_aodn_voltage',
        'label' => __( 'Voltage (V)', 'aodn' ),
    ) );
    woocommerce_wp_text_input( array(
        'id'    => '_aodn_wattage',
        'label' => __( 'Wattage (W)', 'aodn' ),
    ) );
    echo '</div>';
}

This is the same pattern WooCommerce uses internally for all its built-in tabs. Your custom tab panel gets a proper icon slot — target it with .aodn_specs_tab a::before in your admin CSS using a Dashicons unicode character.

WooCommerce Custom Fields for Variable Products

woocommerce custom fields — 8-bit variable product editor showing per-variation custom fields

Variable products require a different hook set because variations are child posts, not the parent product. To add woocommerce custom fields at the variation level, use woocommerce_product_after_variable_attributes to display and woocommerce_save_product_variation to save.

The display hook passes three arguments: the loop index, an array of variation data, and the variation post object. This lets you output uniquely named fields for each variation row.

add_action( 'woocommerce_product_after_variable_attributes', 'aodn_add_variation_custom_field', 10, 3 );

function aodn_add_variation_custom_field( $loop, $variation_data, $variation ) {
    woocommerce_wp_text_input( array(
        'id'            => '_aodn_color_code[' . $variation->ID . ']',
        'name'          => '_aodn_color_code[' . $variation->ID . ']',
        'value'         => get_post_meta( $variation->ID, '_aodn_color_code', true ),
        'label'         => __( 'Hex Color Code', 'aodn' ),
        'desc_tip'      => true,
        'description'   => __( 'Enter hex color for this variation.', 'aodn' ),
        'wrapper_class' => 'form-row form-row-full',
    ) );
}

add_action( 'woocommerce_save_product_variation', 'aodn_save_variation_custom_field', 10, 2 );

function aodn_save_variation_custom_field( $variation_id, $i ) {
    if ( isset( $_POST['_aodn_color_code'][ $variation_id ] ) ) {
        update_post_meta(
            $variation_id,
            '_aodn_color_code',
            sanitize_text_field( $_POST['_aodn_color_code'][ $variation_id ] )
        );
    }
}

WooCommerce’s official documentation covers variation custom fields in detail at the WooCommerce Developer Docs. Cross-reference it with this code to understand the full lifecycle.

🏴‍☠️ PIRATE TIP: When saving variation woocommerce custom fields, use raw update_post_meta() on the variation ID — not the parent product CRUD object. Variations are their own posts and the parent product’s save() won’t touch them.

Display WooCommerce Custom Fields in the Shop Loop

woocommerce custom fields — 8-bit shop loop archive page with custom fields displayed on product cards

To show woocommerce custom fields on category and archive pages, hook into woocommerce_after_shop_loop_item. This fires inside each product card in the loop, after the default content.

add_action( 'woocommerce_after_shop_loop_item', 'aodn_show_material_in_loop', 5 );

function aodn_show_material_in_loop() {
    global $product;
    $material = $product->get_meta( '_aodn_material' );
    if ( $material ) {
        echo '<p class="aodn-loop-material">' . esc_html( $material ) . '</p>';
    }
}

Never run database queries inside a loop without caching. The code above uses $product->get_meta() which reads from the already-loaded product object — no extra query. If you need data from a related post, fetch it outside the loop or use a transient. For performance debugging help, check our guide on how to debug WordPress.

Also consider what woocommerce custom fields actually make sense in the loop. Cluttered product cards hurt conversion. Show one signal — material, warranty badge, or a custom label — not a full spec sheet.

WooCommerce Custom Fields Best Practices

woocommerce custom fields — 8-bit pirate captain reviewing best practices checklist for product metadata

Clean woocommerce custom fields implementation comes down to four non-negotiable rules: prefix your keys, sanitize all input, use the CRUD API, and never query inside loops. Every other decision is secondary.

Prefix Every Meta Key

Use a unique prefix tied to your project: _aodn_, _mytheme_, _clientslug_. Without a prefix, your woocommerce custom fields can collide with other plugins, WooCommerce core updates, or even WordPress itself. The underscore prefix also hides the key from the generic custom fields UI — intentional and clean.

Sanitize Everything, Escape Everything

Sanitize on save with sanitize_text_field(), absint(), floatval(), or wp_kses_post() depending on field type. Escape on output with esc_html(), esc_attr(), or wp_kses_post(). If you’re fuzzy on how actions and filters work beneath this, our guide on WordPress hooks explained closes that gap fast.

Use the WooCommerce CRUD API

The WordPress Plugin Handbook documents the meta box and metadata APIs thoroughly at developer.wordpress.org. But for woocommerce custom fields specifically, $product->update_meta_data() and $product->get_meta() are the right tools — they respect WooCommerce’s internal object lifecycle.

Performance: No Queries Inside Loops

Each extra query inside a product loop compounds fast. Fifty products on a category page means fifty extra database hits if you’re not careful. Stick to $product->get_meta() on already-loaded objects, or preload data with a single get_post_meta() call keyed on an array of IDs before the loop starts.

Keep Your Code Organized

As your woocommerce custom fields grow, organize them into a dedicated class or at minimum a separate include file. Don’t dump everything into functions.php. If you’re building something bigger with custom post types alongside products, our WordPress custom post types tutorial gives you the structural patterns to keep it clean.

And if you’re wiring woocommerce custom fields into a headless setup or syncing product data via API, you’ll want our WordPress REST API beginners guide to understand how postmeta exposes (or hides) through the REST layer.

⚔️ Pirate Verdict

WooCommerce custom fields don’t need a premium plugin. They never did. WooCommerce ships with every hook, helper function, and CRUD method you need to add, save, and display product metadata — and it’s been that way for years. The plugin vendors just never told you. Every dollar you’re spending on ACF Pro or Meta Box for basic woocommerce custom fields is a dollar you rented instead of owned. Write the twenty lines of code. Put it in a plugin you control. Prefix your keys, sanitize your data, use the CRUD API, and ship something that belongs to you. That’s the AODN way — no subscription required.

WooCommerce Custom Fields FAQ

What is the difference between WooCommerce custom fields and product attributes?

Product attributes are structured, variation-driving values managed through the Attributes tab — they power variable products and are filterable in the WooCommerce layered nav widget. WooCommerce custom fields are freeform postmeta that you define and display however you want — they’re not filterable by default but give you complete control over the data structure and display logic.

Do I need a plugin to add WooCommerce custom fields?

No. WooCommerce ships with all the hooks and helper functions you need — woocommerce_product_options_general_product_data, woocommerce_wp_text_input(), woocommerce_process_product_meta, and the full CRUD API. Plugins like ACF or Meta Box add convenience features, but for straightforward woocommerce custom fields, pure code is leaner, faster, and owned by you.

Where do WooCommerce custom fields get stored in the database?

WooCommerce custom fields are stored in the wp_postmeta table as key-value pairs. Each field is a row with meta_key and meta_value columns, linked to the product by its post_id. The WooCommerce CRUD layer reads from this table through $product->get_meta() behind the scenes.

Can I add WooCommerce custom fields to variable product variations?

Yes. Use the woocommerce_product_after_variable_attributes hook to display fields per variation and woocommerce_save_product_variation to save them. Each variation is its own post, so woocommerce custom fields on variations use the variation ID — not the parent product ID.

How do I display WooCommerce custom fields on the single product page?

Hook into woocommerce_single_product_summary and use $product->get_meta( '_your_key' ) to retrieve the value. Output it with proper escaping using esc_html() for text or wp_kses_post() for HTML content. The hook priority controls where your woocommerce custom fields appear relative to other elements.

Adding woocommerce custom fields to your WooCommerce products is one of the most fundamental development skills in the WooCommerce ecosystem. You don’t need a plugin subscription, you don’t need a third-party framework, and you don’t need anyone’s permission. WooCommerce gives you the hooks. WordPress gives you the database. The only thing left is writing the code — and now you know exactly how to do it.

If this guide saved you from buying yet another premium plugin for woocommerce custom fields, that’s the whole point. Own your code. Own your store. What WooCommerce feature are you building next? Drop it in the comments.

← Custom WooCommerce Email Template: The Complete Code-First Guide WooCommerce Without Page Builder: Set Up Your Store With Native Blocks →
The Quartermaster
> THE QUARTERMASTER
Identify yourself, pirate. What brings ye to the command deck?