Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Cart item data

Sometimes a customer specifies the product before buying: an engraving text, a delivery date, gift wrapping. Such data travels a four-step path: a field on the product page, saving in the cart item, showing in the cart, writing into the order item. Each step has its own hook.

The code of this lesson goes into includes/cart.php.

Step 1. A field on the product page

// wp-content/plugins/acme-shop/includes/cart.php
add_action('woocommerce_before_add_to_cart_button', function () {
    echo '<p class="acme-engraving">
        <label for="acme_engraving">Engraving (up to 20 characters)</label>
        <input type="text" id="acme_engraving" name="acme_engraving" maxlength="20">
    </p>';
});

The hook fires inside the purchase form, so the field is submitted when Add to cart is pressed. Open a product page — a text field has appeared above the button.

Step 2. Saving in the item

// wp-content/plugins/acme-shop/includes/cart.php
add_filter('woocommerce_add_cart_item_data', function (array $data, int $productId): array {
    $text = sanitize_text_field(wp_unslash($_POST['acme_engraving'] ?? ''));
 
    if ($text !== '') {
        $data['acme_engraving'] = mb_substr($text, 0, 20);
    }
 
    return $data;
}, 10, 2);

The filter receives the array of the item's custom data and returns it extended. sanitize_text_field() strips tags and extra spaces from the input. Products with different texts land in the cart as separate items: the data takes part in the item key.

Step 3. Showing in the cart

// wp-content/plugins/acme-shop/includes/cart.php
add_filter('woocommerce_get_item_data', function (array $rows, array $item): array {
    if (isset($item['acme_engraving'])) {
        $rows[] = [
            'key' => 'Engraving',
            'value' => $item['acme_engraving'],
        ];
    }
 
    return $rows;
}, 10, 2);

Type For Anna into the field, press Add to cart and open /cart/: the line Engraving: For Anna appears under the product name. The same line is visible on the checkout page.

Step 4. Writing into the order

The cart disappears after checkout, so the data is carried into the order item:

// wp-content/plugins/acme-shop/includes/cart.php
add_action('woocommerce_checkout_create_order_line_item', function (WC_Order_Item_Product $item, string $cartItemKey, array $values) {
    if (isset($values['acme_engraving'])) {
        $item->add_meta_data('Engraving', $values['acme_engraving']);
    }
}, 10, 3);

The third argument, $values, is that very cart item with your data. Place an order: the text is visible in the customer's email, on the Order received page and in the admin panel in WooCommerce → Orders under the product name.

Reading from the order

foreach ($order->get_items() as $item) {
    $text = $item->get_meta('Engraving');
}

A meta key without a leading underscore is shown to the customer and the manager as a label. A key with an underscore, for example _acme_engraving_font, is hidden — that is how service values are kept.

A surcharge for engraving

Item data is available when the price is calculated too:

// wp-content/plugins/acme-shop/includes/cart.php
add_action('woocommerce_before_calculate_totals', function (WC_Cart $cart) {
    foreach ($cart->get_cart() as $item) {
        if (isset($item['acme_engraving'])) {
            $item['data']->set_price((float) $item['data']->get_regular_price() + 2);
        }
    }
});

A mug with engraving becomes €2 more expensive.

Common mistake

Only the first three steps are done. The text is visible in the cart, the order is placed — but it is not in the order, and the craftsman does not know what to engrave. Cart data does not get into the order by itself: the fourth step with woocommerce_checkout_create_order_line_item is mandatory.

Thanks for reading!

Donate to the site — we work hard for you.