phpwoocommercemetadatacrudorders

Order custom field added via checkout is lost after WooCommerce HPOS sync


My website have custom field in /checkout page in Woocommerce is: Link (Facebook/Zalo/Telegram), but I have problem when active HPOS, when click button Sync and active Compatibility mode of HPOS, it will lost field: Link (Facebook/Zalo/Telegram), I can't find this again in any Order after click button Sync xxx order.

My code is:

add_action('woocommerce_after_checkout_billing_form', 'custom_checkout_field');
function custom_checkout_field($checkout)
{
    $key_field = 'fbhoaczalo';
echo '<div id="custom_checkout_field">';
woocommerce_form_field('fbhoaczalo', array(
'type' => 'textarea',
'id' => 'fb_zalo',
'class' => array(
'my-field-class form-row-wide'
) ,
'label' => ('<strong style="color: #ffdf30;font-size: 120%;">Your contact [ <code>Facebook</code>, <code>Zalo</code>, <code>Telegram</code> ] :</strong>') ,
'required'      => true,
'placeholder' => ('This field is require') ,
) ,
$checkout->get_value($key_field) ? $checkout->get_value($key_field) : WC()->session->get($key_field) );
echo '</div>';
}
add_action('woocommerce_checkout_process', 'customised_checkout_field_process');

// Save checkout custom field value in a WC_Session variable 
add_action( 'woocommerce_checkout_create_order', 'action_checkout_create_order', 10, 2 );
function action_checkout_create_order( $order, $data  ) {
    $key_field = 'fbhoaczalo';
    
    if( isset($_POST[$key_field]) ) {
        WC()->session->set($key_field, sanitize_text_field($_POST[$key_field]));
    }
}

// Save checkout custom field value as user meta data
add_action( 'woocommerce_checkout_update_customer', 'action_checkout_update_customer', 10, 2 );
function action_checkout_update_customer( $customer, $data  ) {
    $key_field = $key_field;
    
    if( isset($_POST['fbhoaczalo']) ) {
        $customer->add_meta_data($key_field, sanitize_text_field($_POST[$key_field])); 
    }
}

function customised_checkout_field_process()
{
// Show an error message if the field is not set.
if (!$_POST['fbhoaczalo']) {
    wc_add_notice(__('This field is not blank. Please type your contact') , 'error'); 
}
}
add_action('woocommerce_checkout_update_order_meta', 'custom_checkout_field_update_order_meta');
function custom_checkout_field_update_order_meta($order_id)
{
    if (!empty($_POST['fbhoaczalo'])) {
    update_post_meta($order_id, 'fbhoaczalo',sanitize_text_field($_POST['fbhoaczalo']));
    }
}
add_action( 'woocommerce_checkout_update_order_meta', 'codeastrology_save_new_checkout_field' );
function codeastrology_save_new_checkout_field( $order_id ) { 
    if ( $_POST['fbhoaczalo'] ) update_post_meta( $order_id, '_fbhoaczalo', esc_attr( $_POST['fbhoaczalo'] ) );
}
add_action( 'woocommerce_admin_order_data_after_billing_address', 'codeastrology_show_new_checkout_field_order', 10, 1 );
function codeastrology_show_new_checkout_field_order( $order ) {    
   $order_id = $order->get_id();
   if ( get_post_meta( $order_id, '_fbhoaczalo', true ) ) echo '<p><strong>Link Facebook/Zalo/Tele:</strong> ' . get_post_meta( $order_id, '_fbhoaczalo', true ) . '</p>';
}
add_action( 'woocommerce_email_after_order_table', 'codeastrology_show_new_checkout_field_emails', 20, 4 );
function codeastrology_show_new_checkout_field_emails( $order, $sent_to_admin, $plain_text, $email ) {
    if ( get_post_meta( $order->get_id(), '_fbhoaczalo', true ) ) echo '<p><strong>Link Facebook/Zalo/Tele:</strong> ' . get_post_meta( $order->get_id(), '_fbhoaczalo', true ) . '</p>';
}

This will show look like this in https://mysite/checkout/ page:

enter image description here

When user fill in this, in Admin of Order, I can see that field and know contact of customer, look like this:

enter image description here

All working perfect but problem is when I turn on feature: HPOS in WooCommerce. Tick at: Enable compatibility mode (synchronizes orders to the posts table). and click button Sync 2.394 pending orders in There are 2394 orders pending sync. You can switch order data storage only when the posts and orders tables are in sync..

enter image description here

When I click on any Order, the field Link Facebook/Zalo/Tele is lost. I can't find this field so I can't contact to my customer if have any problem with Order.

Have any suggest to keep this custom field (Link Facebook/Zalo/Tele) after Sync pending order to HPOS?


Solution

  • High Performance Order Storage (HPOS) require using exclusively WooCommerce CRUD methods, but not anymore WordPress post meta functions, as WooCommerce uses its own database tables.

    Also, there are some mistakes in your code.

    Try to replace your code with the following:

    // Add a custom checkout field
    add_action('woocommerce_after_checkout_billing_form', 'custom_checkout_field');
    function custom_checkout_field( $checkout ) {
        $key_field = 'fbhoaczalo';
    
        echo '<div id="custom_checkout_field">';
    
        woocommerce_form_field($key_field, array(
            'type'          => 'textarea',
            'id'            => 'fb_zalo',
            'class'         => array('my-field-class form-row-wide'),
            'label'         => '<strong style="color: #ffdf30;font-size: 120%;">Your contact [ <code>Facebook</code>, <code>Zalo</code>, <code>Telegram</code> ] :</strong>',
            'required'      => true,
            'placeholder'   => __('This field is required'),
        ), $checkout->get_value($key_field) );
    
        echo '</div>';
    }
    
    // Custom checkout field validation
    add_action('woocommerce_checkout_process', 'custom_checkout_field_validation');
    function custom_checkout_field_validation(){
        $key_field = 'fbhoaczalo';
        
        if ( isset($_POST[$key_field]) && empty($_POST[$key_field])) {
            wc_add_notice(__('Please fill in your contact, as this is a required field') , 'error'); 
        }
    }
    
    // Save custom checkout field value as order metadata
    add_action( 'woocommerce_checkout_create_order', 'save_custom_checkout_field_as_order_meta', 10, 2 );
    function save_custom_checkout_field_as_order_meta( $order, $data  ) {
        $key_field = 'fbhoaczalo';
    
        if( isset($_POST[$key_field]) && !empty($_POST[$key_field]) ) {
            $order->update_meta_data('_'.$key_field, sanitize_textarea_field($_POST[$key_field])); 
        }
    }
    
    // Save custom checkout field value as user metadata
    add_action( 'woocommerce_checkout_update_customer', 'save_custom_checkout_field_as_user_meta', 10, 2 );
    function save_custom_checkout_field_as_user_meta( $customer, $data  ) {
        $key_field = 'fbhoaczalo';
    
        if( isset($_POST['fbhoaczalo']) ) {
            $customer->update_meta_data($key_field, sanitize_textarea_field($_POST[$key_field])); 
        }
    }
    
    // Display the custom field value to admin order and email notifications
    add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_order_custom_field_value', 10, 1 );
    add_action( 'woocommerce_email_after_order_table', 'display_order_custom_field_value', 20, 1 );
    function display_order_custom_field_value( $order ) {   
        if ( $fbhoaczalo = $order->get_meta('_fbhoaczalo') ) {
            printf('<p><strong>%s:</strong> %s</p>', __('Link Facebook/Zalo/Tele'), $fbhoaczalo);
        }
    }
    

    Now it will work with HPOS, without requiring additional sync process.

    You should also retrieve back disappeared custom field value.