phpwordpresswoocommercehook-woocommercedatefield

Single product custom date fields not validated and saved in Woocommerce


I've added two customer date inputs to the single product page. I need them to be required and validated before adding to the cart, and would also like the dates to be shown on the cart/checkout page and in the order emails.

I found the snippets needed here, however it was only for one custom field so I adjusted to make it for two: https://www.kathyisawesome.com/add-a-custom-field-to-woocommerce-product/

The input fields show up fine, but once you hit the Add to Cart button it doesn't carry throughout the order.

Here is the code used in my functions.php file:

/*
 * Display inputs on single product page
 */
function amp_custom_option_1(){
    $value = isset( $_POST['_est_delivery'] ) ? sanitize_text_field( $_POST['_est_delivery'] ) : '';
    printf( '<div id="dates"><div class="delivery"><label>%s</label><input name="_est_delivery" value="%s" type="date" required /></div>', __( 'Estimated Delivery Date:', 'amp-plugin-textdomain-1' ), esc_attr( $value ) );
}
add_action( 'woocommerce_before_add_to_cart_form', 'amp_custom_option_1', 9 );

function amp_custom_option_2(){
    $value = isset( $_POST['_est_pickup'] ) ? sanitize_text_field( $_POST['_est_pickup'] ) : '';
    printf( '<div class="pickup"><label>%s</label><input name="_est_pickup" value="%s" type="date" required /></div></div>', __( 'Estimated Pickup Date:', 'amp-plugin-textdomain-2' ), esc_attr( $value ) );
}
add_action( 'woocommerce_before_add_to_cart_form', 'amp_custom_option_2', 9 );


/*
 * Validate when adding to cart
 */
function amp_add_to_cart_validation_1($passed, $product_id, $qty){

    if( isset( $_POST['_est_delivery'] ) && sanitize_text_field( $_POST['_est_delivery'] ) == '' ){
        $product = wc_get_product( $product_id );
        wc_add_notice( sprintf( __( '%s cannot be added to the cart until you enter a delivery date.', 'amp-plugin-textdomain-1' ), $product->get_title() ), 'error' );
        return false;
    }

    return $passed;

}
add_filter( 'woocommerce_add_to_cart_validation', 'amp_add_to_cart_validation_1', 10, 3 );

function amp_add_to_cart_validation_2($passed, $product_id, $qty){

    if( isset( $_POST['_est_pickup'] ) && sanitize_text_field( $_POST['_est_pickup'] ) == '' ){
        $product = wc_get_product( $product_id );
        wc_add_notice( sprintf( __( '%s cannot be added to the cart until you enter a pickup date.', 'amp-plugin-textdomain-2' ), $product->get_title() ), 'error' );
        return false;
    }

    return $passed;

}
add_filter( 'woocommerce_add_to_cart_validation', 'amp_add_to_cart_validation_2', 10, 3 );


/*
 * Add custom data to the cart item
 */
function amp_add_cart_item_data_1( $cart_item, $product_id ){

    if( isset( $_POST['_est_delivery'] ) ) {
        $cart_item['est_delivery'] = sanitize_text_field( $_POST['_est_delivery'] );
    }

    return $cart_item;

}
add_filter( 'woocommerce_add_cart_item_data', 'amp_add_cart_item_data_1', 10, 2 );

function amp_add_cart_item_data_2( $cart_item, $product_id ){

    if( isset( $_POST['_est_pickup'] ) ) {
        $cart_item['est_pickup'] = sanitize_text_field( $_POST['_est_pickup'] );
    }

    return $cart_item;

}
add_filter( 'woocommerce_add_cart_item_data', 'amp_add_cart_item_data_2', 10, 2 );


/*
 * Load cart data from session
 */
function amp_get_cart_item_from_session_1( $cart_item, $values ) {

    if ( isset( $values['est_delivery'] ) ){
        $cart_item['est_delivery'] = $values['est_delivery'];
    }

    return $cart_item;

}
add_filter( 'woocommerce_get_cart_item_from_session', 'amp_get_cart_item_from_session_1', 20, 2 );

function amp_get_cart_item_from_session_2( $cart_item, $values ) {

    if ( isset( $values['est_pickup'] ) ){
        $cart_item['est_pickup'] = $values['est_pickup'];
    }

    return $cart_item;

}
add_filter( 'woocommerce_get_cart_item_from_session', 'amp_get_cart_item_from_session_2', 20, 2 );


/*
 * Add meta to order item
 */
function amp_add_order_item_meta_1( $item_id, $values ) {

    if ( ! empty( $values['est_delivery'] ) ) {
        woocommerce_add_order_item_meta( $item_id, 'est_delivery', $values['est_delivery'] );           
    }
}
add_action( 'woocommerce_add_order_item_meta', 'amp_add_order_item_meta_1', 10, 2 );

function amp_add_order_item_meta_2( $item_id, $values ) {

    if ( ! empty( $values['est_pickup'] ) ) {
        woocommerce_add_order_item_meta( $item_id, 'est_pickup', $values['est_pickup'] );           
    }
}
add_action( 'woocommerce_add_order_item_meta', 'amp_add_order_item_meta_2', 10, 2 );


/*
 * Get item data to display in cart
 */
function amp_get_item_data_1( $other_data, $cart_item ) {

    if ( isset( $cart_item['est_delivery'] ) ){

        $other_data[] = array(
            'name' => __( 'Estimated Delivery Date:', 'amp-plugin-textdomain-1' ),
            'value' => sanitize_text_field( $cart_item['est_delivery'] )
        );

    }

    return $other_data;

}
add_filter( 'woocommerce_get_item_data', 'amp_get_item_data_1', 10, 2 );

function amp_get_item_data_2( $other_data, $cart_item ) {

    if ( isset( $cart_item['est_pickup'] ) ){

        $other_data[] = array(
            'name' => __( 'Estimated Pickup Date', 'amp-plugin-textdomain-2' ),
            'value' => sanitize_text_field( $cart_item['est_pickup'] )
        );

    }

    return $other_data;

}
add_filter( 'woocommerce_get_item_data', 'amp_get_item_data_2', 10, 2 );



/*
 * Show custom field in order overview
 */
function amp_order_item_product_1( $cart_item, $order_item ){

    if( isset( $order_item['est_delivery'] ) ){
        $cart_item_meta['est_delivery'] = $order_item['est_delivery'];
    }

    return $cart_item;

}
add_filter( 'woocommerce_order_item_product', 'amp_order_item_product_1', 10, 2 );

function amp_order_item_product_2( $cart_item, $order_item ){

    if( isset( $order_item['est_pickup'] ) ){
        $cart_item_meta['est_pickup'] = $order_item['est_pickup'];
    }

    return $cart_item;

}
add_filter( 'woocommerce_order_item_product', 'amp_order_item_product_2', 10, 2 );


/* 
 * Add the field to order emails 
 */ 
function amp_email_order_meta_fields_1( $fields ) { 
    $fields['est_delivery'] = __( 'Estimated Delivery Date:', 'amp-plugin-textdomain-1' ); 
    return $fields; 
} 
add_filter('woocommerce_email_order_meta_fields', 'amp_email_order_meta_fields_1');

function amp_email_order_meta_fields_2( $fields ) { 
    $fields['est_delivery'] = __( 'Estimate Pickup Date:', 'amp-plugin-textdomain-2' ); 
    return $fields; 
} 
add_filter('woocommerce_email_order_meta_fields', 'amp_email_order_meta_fields_2');

I'm not sure what is wrong with my code? Any help is appreciated.


Solution

  • There was some errors and mistakes. I have changed and removed some hooks, remove unnecessary code, merged functions, revisited all your code. As Your 2 dates fields are on single product pages, they will be related to cart items and order items (so order items meta data).

    I have set your 2 date fields slugs and labels in the first function, inside an array. Then I call that function everywhere else and I use a foreach loop to process each field. This avoid repetitions, optimize and compact the code.

    The code (commented):

    // Utility function that contain the 2 field keys and labels pairs used on all other functions
    function get_date_label_keys(){
        $text_domain   = 'woocommerce';
        return array( 'est_delivery' => __( 'Estimated Delivery Date', $text_domain ),
                      'est_pickup'   => __( 'Estimated Pickup Date', $text_domain ) );
    }
    
    // Display custom fields on single product page (hook replaced)
    add_action( 'woocommerce_before_add_to_cart_button', 'amp_display_custom_fields', 20 );
    function amp_display_custom_fields(){
        echo '<div id="dates">';
        // Loop through each custom field 
        foreach( get_date_label_keys() as $key => $label ){
            $class = str_replace('est_', '', $key); // The class
            $value = isset($_POST[$key]) ? sanitize_text_field($_POST[$key]) : ''; // Display the value
            printf( '<div class="%s"><label>%s:</label> <input type="date" name="%s" value="%s" required /></div>', $class, $label, $key, $value );
        }
        echo '</div><br clear="all">';
    }
    
    // Add to cart fields validation (in case of need)
    add_filter( 'woocommerce_add_to_cart_validation', 'amp_add_to_cart_validation', 20, 3 );
    function amp_add_to_cart_validation( $passed, $product_id, $qty ){
        // Loop through each custom field 
        foreach( get_date_label_keys() as $key => $label ){
            if( isset( $_POST[$key] ) && empty( $_POST[$key] ) ){
                wc_add_notice( sprintf( __( '%s cannot be added to the cart until you enter a delivery date.', $domain ), get_the_title() ), 'error' );
                $passed = false;
            }
        }
        return $passed;
    }
    
    // Add to cart items the custom data
    add_filter( 'woocommerce_add_cart_item_data', 'amp_add_cart_item_data', 20, 2 );
    function amp_add_cart_item_data( $cart_item, $product_id ){
        // Loop through each custom field 
        foreach( get_date_label_keys() as $key => $label ){
            if( isset( $_POST[$key] ) )
                $cart_item['dates'][$key] = sanitize_text_field( $_POST[$key] );
        }
        return $cart_item;
    }
    
    // Display the dates in cart items on cart and checkout pages
    add_filter( 'woocommerce_get_item_data', 'amp_get_item_data', 20, 2 );
    function amp_get_item_data( $item_data, $cart_item = null ) {
        // Loop through each custom field 
        foreach( get_date_label_keys() as $key => $label ){
            if ( isset( $cart_item['dates'][$key] ) )
                $item_data[] = array(
                    'name' => $label,
                    'value' => sanitize_text_field( $cart_item['dates'][$key] )
                );
        }
        return $item_data;
    }
    
    // Add order item meta data and Display the data in order items (hook replaced)
    add_action( 'woocommerce_checkout_create_order_line_item', 'amp_add_order_item_meta', 20, 4 );
    function amp_add_order_item_meta( $item, $cart_item_key, $values, $order ) {
        foreach( get_date_label_keys() as $key => $label ){
        // Loop through each custom field 
            if ( ! empty( $values['dates'][$key] ) )
                $item->update_meta_data( $label, $values['dates'][$key] );
        }
    }
    

    Code goes in function.php file of your active child theme (or active theme). Tested and works.

    On cart page (and checkout too):

    enter image description here

    Order received and order view pages (in admin order edit pages and email notifications too):

    enter image description here