Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Custom product fields in the admin panel

The standard product properties are not always enough: you may need a lead time, a supplier, a link to a manual. WooCommerce lets you add a field right into the product editor — a manager fills it in the admin panel and the code reads it from meta data.

Where to write the code

Create the includes/admin.php file and include it in acme-shop.php. Everything that changes the admin panel goes there.

A field in the editor

// wp-content/plugins/acme-shop/includes/admin.php
add_action('woocommerce_product_options_general_product_data', function () {
    woocommerce_wp_text_input([
        'id' => '_acme_lead_time',
        'label' => 'Lead time, days',
        'type' => 'number',
        'custom_attributes' => ['min' => 0, 'step' => 1],
    ]);
});

Open any product in the admin panel: a number field has appeared in the Product data box on the General tab, under the prices. woocommerce_wp_text_input() draws the field itself and fills in the saved value from the meta data whose key equals id.

Saving

The field itself saves nothing. The value is written in a hook that fires when the product is saved:

// wp-content/plugins/acme-shop/includes/admin.php
add_action('woocommerce_admin_process_product_object', function (WC_Product $product) {
    $days = isset($_POST['_acme_lead_time']) ? absint($_POST['_acme_lead_time']) : 0;
 
    $product->update_meta_data('_acme_lead_time', $days);
});

Enter 3 in the field and press Update — the value stays in the field after the reload. absint() turns the input into a non-negative integer. There is no need to call save(): WooCommerce saves the product itself right after the hook, and it has already checked the user's permissions.

Showing it in the storefront

The value is read where the customer needs it:

// wp-content/plugins/acme-shop/includes/storefront.php
add_action('woocommerce_single_product_summary', function () {
    global $product;
 
    $days = (int) $product->get_meta('_acme_lead_time');
 
    if ($days > 0) {
        printf('<p class="acme-lead-time">Made in %d days</p>', $days);
    }
}, 25);

On the product page the line Made in 3 days appears between the short description and the button.

Other fields and tabs

FunctionField
woocommerce_wp_text_input()A string or a number
woocommerce_wp_textarea_input()Multi-line text
woocommerce_wp_select()A dropdown, values in options
woocommerce_wp_checkbox()A checkbox, stores yes or no
HookTab of the Product data box
woocommerce_product_options_general_product_dataGeneral
woocommerce_product_options_inventory_product_dataInventory
woocommerce_product_options_shippingShipping
woocommerce_product_options_advancedAdvanced

A column in the product list

// wp-content/plugins/acme-shop/includes/admin.php
add_filter('manage_edit-product_columns', function (array $columns): array {
    $columns['acme_lead_time'] = 'Lead time';
 
    return $columns;
});
 
add_action('manage_product_posts_custom_column', function (string $column, int $postId) {
    if ($column === 'acme_lead_time') {
        $product = wc_get_product($postId);
 
        echo esc_html($product ? $product->get_meta('_acme_lead_time') : '');
    }
}, 10, 2);

The filter adds the column heading, the action fills the cells. A Lead time column with the number of days appears in the Products list.

Common mistake

The field was added but the save hook was not: the value disappears after pressing Update. A field and its saving are always two separate functions with the same key. The second cause of a vanished field is the new block-based product editor being enabled (WooCommerce → Settings → Advanced → Features): the woocommerce_product_options_... hooks do not work in it.

Thanks for reading!

Donate to the site — we work hard for you.