Search code examples
phpwordpresswoocommerceproducthook-woocommerce

Customize WooCommerce single product with an additional input field


Well, I have a problem, I am wondering how I can create additional inputs above the "quantity of items" and "add to cart" sections so that the customer can personalize their product for themselves. I'd like to be able to do this myself in my theme without plugins unless any actually meet these goals.

I am wondering if a good choice is to use the 'woocommerce_before_add_to_cart_button' hookup? How do I later add the values of these inputs to this product to be able to display them in the order summary?

Currently I have this code that adds the field itself.

Unfortunately, these fields do not display either in the shopping cart, the order summary or the order in the ACP. What am I doing wrong? Is this the right way to go?

function my_personalization_field() {
    $html = '<div class="personalization-field">';
        $html .= '<label for="personalization">Personalization:</label>';
        $html .= '<input type="text" id="personalization" name="my_personalization" />';
    $html .= '</div>';

    echo $html;
}
add_action('woocommerce_before_add_to_cart_button', 'my_personalization_field');


function my_adding_custom_data_in_order_items_meta( $item_id, $values, $cart_item_key ) {
    if ( isset($values['my_personalization']) ) {
        $custom_value = $values['my_personalization'];
        wc_add_order_item_meta($item_id, 'my_personalization', $custom_value );
    }
}
add_action('woocommerce_add_order_item_meta','my_adding_custom_data_in_order_items_meta', 10, 3 );

function my_display_personalization_data_in_cart($product_name, $cart_item, $cart_item_key) {
    if(isset($cart_item['my_personalization'])) {
        $product_name .= '<br><small>Personalization: ' . esc_html($cart_item['my_personalization']) . '</small>';
    }

    return $product_name;
}
add_filter('woocommerce_cart_item_name', 'my_display_personalization_data_in_cart', 10, 3);

Solution

  • Your code is a bit outdated and incomplete. Try use the following replacement code to display your custom field value in cart, checkout, orders and email notifications:

    add_action('woocommerce_before_add_to_cart_button', 'single_product_custom_field_display');
    function single_product_custom_field_display() {
        echo '<div class="personalization-field">
        <label for="personalization">'.__('Personalization:').'</label>
        <input type="text" id="personalization" name="personalization" />
        </div>';
    }
    
    // Save custom fields as custom cart item data
    add_filter('woocommerce_add_cart_item_data', 'add_custom_cart_item_data', 20, 2 );
    function add_custom_cart_item_data( $cart_item_data, $product_id ) {
        if ( isset($_POST['personalization']) ) {
            $cart_item_data['personalization'] = sanitize_text_field($_POST['personalization']);
        }
        return $cart_item_data;
    }
    
    // Display custom fields in Cart and Checkout
    add_filter( 'woocommerce_get_item_data', 'display_custom_cart_item_data', 20, 2 );
    function display_custom_cart_item_data( $cart_data, $cart_item ) {
        if( isset($cart_item['personalization']) ) {
            $cart_data[] = array(
                'key'   => __('Personalization'),
                'value' => $cart_item['personalization'],
            );
        }
        return $cart_data;
    }
    
    // Save and display custom fields (custom order item metadata)
    add_action( 'woocommerce_checkout_create_order_line_item', 'save_order_item_custom_meta_data6', 10, 4 );
    function save_order_item_custom_meta_data6( $item, $cart_item_key, $values, $order ) {
        if( isset($values['personalization']) ) {
            $item->update_meta_data('personalization', $values['personalization']); 
        }
    }
    
    // Add readable "meta key" label name replacement
    add_filter('woocommerce_order_item_display_meta_key', 'filter_wc_order_item_display_meta_key6', 10, 3 );
    function filter_wc_order_item_display_meta_key6( $display_key, $meta, $item ) {
        if( $item->get_type() === 'line_item' ) {
            if( $meta->key === 'personalization' ) {
                $display_key = __('Personalization');
            }
        }
        return $display_key;
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and works.

    You will get:

    On cart and checkout pages:

    enter image description here

    On customer order pages:

    enter image description here

    On email notifications:

    enter image description here

    On admin orders pages:

    enter image description here