update_post_meta() not working on WooCommerce checkout when submmitting an order

I've created a bespoke plugin for a client of mine but I am running into some problems. I tested the plugin on my own sandbox site before sending it to the client and it worked perfectly. However, on their site, which is built differently, I am running into a couple of problems. One of the files runs functions using common Woocommerce hooks. <?php if (!defined('ABSPATH')) { exit; } class WC_PM_Checkout_Fields { public function __construct() { add_action('woocommerce_after_order_notes', array($this, 'add_patient_dropdown_and_custom_fields_to_checkout'), 999); add_action('woocommerce_checkout_update_order_meta', array($this, 'save_or_create_patient_on_checkout'), 999); add_action('woocommerce_thankyou', array($this, 'display_patient_information_on_thank_you_page'), 999); add_action('woocommerce_email_order_meta', array($this, 'add_patient_info_to_order_email'), 999, 3); add_action('woocommerce_admin_order_data_after_billing_address', array($this, 'display_patient_fields_in_admin_order'), 999, 1); } public function add_patient_dropdown_and_custom_fields_to_checkout($checkout) { if( !is_checkout() ) { return; } $args = array( 'post_type' => 'patient', 'author' => get_current_user_id(), 'posts_per_page' => -1, ); $patients = new WP_Query($args); echo '<div id="patient_dropdown"><h3>' . __('Select Existing Patient') . '</h3>'; echo '<select name="selected_patient_id" id="selected_patient_id">'; echo '<option value="">' . __('Select a patient or enter new details below') . '</option>'; if ($patients->have_posts()) : while ($patients->have_posts()) : $patients->the_post(); echo '<option value="' . get_the_ID() . '">' . get_the_title() . '</option>'; endwhile; wp_reset_postdata(); endif; echo '</select></div>'; echo '<div id="custom_patient_checkout_fields"><h3>' . __('Or Enter New Patient Information') . '</h3>'; if (function_exists('woocommerce_form_field')) { // First Name field woocommerce_form_field('wcpm_patient_first_name', array( 'type' => 'text', 'class' => array('form-row-wide'), 'label' => __('Patient First Name'), 'required' => true, 'placeholder' => __('Enter patient first name'), ), $checkout->get_value('wcpm_patient_first_name')); // Last Name field woocommerce_form_field('wcpm_patient_last_name', array( 'type' => 'text', 'class' => array('form-row-wide'), 'label' => __('Patient Last Name'), 'required' => true, 'placeholder' => __('Enter patient last name'), ), $checkout->get_value('wcpm_patient_last_name')); // Date of Birth field woocommerce_form_field('wcpm_patient_dob', array( 'type' => 'text', 'class' => array('form-row-wide'), 'label' => __('Date of Birth'), 'required' => true, 'placeholder' => __('Select date of birth'), 'input_class' => array('datepicker'), ), $checkout->get_value('wcpm_patient_dob')); // Prescription Dosage field woocommerce_form_field('wcpm_patient_dosage', array( 'type' => 'text', 'class' => array('form-row-wide'), 'label' => __('Prescription Dosage'), 'required' => true, 'placeholder' => __('Enter prescription dosage'), ), $checkout->get_value('wcpm_patient_dosage')); // Prescription Date field woocommerce_form_field('wcpm_patient_prescription_date', array( 'type' => 'text', 'class' => array('form-row-wide'), 'label' => __('Prescription Date'), 'required' => true, 'placeholder' => __('Select prescription date'), 'input_class' => array('datepicker'), ), $checkout->get_value('wcpm_patient_prescription_date')); } echo '</div>'; } public function save_or_create_patient_on_checkout($order_id) { $selected_patient_id = !empty($_POST['selected_patient_id']) ? intval($_POST['selected_patient_id']) : null; $patient_first_name = sanitize_text_field($_POST['wcpm_patient_first_name']); $patient_last_name = sanitize_text_field($_POST['wcpm_patient_last_name']); $patient_dob = !empty($_POST['wcpm_patient_dob']) ? date('Y-m-d', strtotime(str_replace('/', '-', $_POST['wcpm_patient_dob']))) : ''; $patient_dosage = sanitize_text_field($_POST['wcpm_patient_dosage']); $patient_prescription_date = !empty($_POST['wcpm_patient_prescription_date']) ? date('Y-m-d', strtotime(str_replace('/', '-', $_POST['wcpm_patient_prescription_date']))) : ''; if ($selected_patient_id) { // An existing patient was selected $patient_id = $selected_patient_id; } else { // Create a new patient post $patient_title = $patient_first_name . ' ' . $patient_last_name; $current_user_id = get_current_user_id(); $existing_patient = get_posts(array( 'post_type' => 'patient', 'author' => $current_user_id, 'post_status'=> 'publish', 'meta_query' => array( array( 'key' => 'wcpm_patient_first_name', 'value' => ucwords($patient_first_name), 'compare' => '=' ), array( 'key' => 'wcpm_patient_last_name', 'value' => ucwords($patient_last_name), 'compare' => '=' ) ) )); if ($existing_patient) { $patient_id = $existing_patient[0]->ID; } else { $patient_post = array( 'post_title' => $patient_title, 'post_type' => 'patient', 'post_status' => 'publish', 'post_author' => $current_user_id, ); $patient_id = wp_insert_post($patient_post); // Save the custom fields for the new patient update_post_meta($patient_id, 'wcpm_patient_first_name', ucwords($patient_first_name)); update_post_meta($patient_id, 'wcpm_patient_last_name', ucwords($patient_last_name)); update_post_meta($patient_id, 'wcpm_patient_dob', $patient_dob); } } // Save patient information to the order meta update_post_meta($order_id, '_selected_patient_id', $patient_id); update_post_meta($order_id, 'wcpm_patient_first_name', ucwords($patient_first_name)); update_post_meta($order_id, 'wcpm_patient_last_name', ucwords($patient_last_name)); update_post_meta($order_id, 'wcpm_patient_dob', $patient_dob); update_post_meta($order_id, 'wcpm_patient_dosage', $patient_dosage); update_post_meta($order_id, 'wcpm_patient_prescription_date', $patient_prescription_date); } public function display_patient_information_on_thank_you_page($order_id) { $selected_patient_id = get_post_meta($order_id, '_selected_patient_id', true); if ($selected_patient_id) { $patient_first_name = get_post_meta($selected_patient_id, 'wcpm_patient_first_name', true); $patient_last_name = get_post_meta($selected_patient_id, 'wcpm_patient_last_name', true); $patient_dob = get_post_meta($selected_patient_id, 'wcpm_patient_dob', true); } else { $patient_first_name = get_post_meta($order_id, 'wcpm_patient_first_name', true); $patient_last_name = get_post_meta($order_id, 'wcpm_patient_last_name', true); $patient_dob = get_post_meta($order_id, 'wcpm_patient_dob', true); } $patient_dosage = get_post_meta($order_id, 'wcpm_patient_dosage', true); $patient_prescription_date = get_post_meta($order_id, 'wcpm_patient_prescription_date', true); $dob_formatted = !empty($patient_dob) ? date('d/m/Y', strtotime($patient_dob)) : ''; $prescription_date_formatted = !empty($patient_prescription_date) ? date('d/m/Y', strtotime($patient_prescription_date)) : ''; echo '<h2>' . __('Patient Information') . '</h2>'; echo '<p><strong>' . __('First Name') . ':</strong> ' . esc_html(ucwords($patient_first_name)) . '</p>'; echo '<p><strong>' . __('Last Name') . ':</strong> ' . esc_html(ucwords($patient_last_name)) . '</p>'; echo '<p><strong>' . __('Date of Birth') . ':</strong> ' . esc_html($dob_formatted) . '</p>'; echo '<p><strong>' . __('Prescription Dosage') . ':</strong> ' . esc_html($patient_dosage) . '</p>'; echo '<p><strong>' . __('Prescription Date') . ':</strong> ' . esc_html($prescription_date_formatted) . '</p>'; } public function add_patient_info_to_order_email($order, $sent_to_admin, $plain_text) { $this->display_patient_information_on_thank_you_page($order->get_id()); } public function display_patient_fields_in_admin_order($order) { $this->display_patient_information_on_thank_you_page($order->get_id()); } } new WC_PM_Checkout_Fields(); The first function adds extra fields which can either be populated by entering new information or by using a dropdown list that pulls information from a custom post type. Once the order is submitted a new patient, if it doesn't already exist, is created and all these extra fields are added to the confirmation page, the email and the order meta. However, the order meta doesn't appear to be updating therefore it shows the field names but no values. I created a test function that just runs on 'admin_init' and added my own order_id and this worked perfectly. There is something causing a conflict but can't seem to find the cause. Plugins on the site: Advanced Custom Fields PRO Advanced Shipment Tracking Pro Avada Builder Avada Core Code Snippets Custom User Registration Fields for WooCommerce Digital Signature Checkout For Woocommerce Duplicator Identity Verification for WooCommerce Redirection Stop User Enumeration TrackShip for WooCommerce User Role Editor WooCommerce for Logged-in Users WooCommerce Opayo Payment Suite WooCommerce Zapier Worldpay eCommerce for WooCommerce WP Fastest Cache WP Mail SMTP Yoast SEO I've checked code snippets but don't see anything in there that would cause problems. I haven't used Avada before.

Comment (1)

Jese Leos

August 23, 2024

Verified user

First note that High-Performance Order Storage (HPOS) is now enabled by default in WooCommerce, and requires using some other hooks with CRUD objects getter and setter methods instead of WordPress Post meta functions. Also, be sure that your client doesn't use newly checkout blocks, that doesn't allow these kinds of customizations. First, try to replace the old hook woocommerce_checkout_update_order_meta from: add_action('woocommerce_checkout_update_order_meta', array($this, 'save_or_create_patient_on_checkout'), 999); with: add_action('woocommerce_checkout_create_order', array($this, 'save_or_create_patient_on_checkout'), 10, 1 ); Then replace your related function with something like (the function argument is now $order, which is the WC_order object): public function save_or_create_patient_on_checkout( $order ) { $selected_patient_id = !empty($_POST['selected_patient_id']) ? intval($_POST['selected_patient_id']) : null; $patient_first_name = sanitize_text_field($_POST['wcpm_patient_first_name']); $patient_last_name = sanitize_text_field($_POST['wcpm_patient_last_name']); $patient_dob = !empty($_POST['wcpm_patient_dob']) ? date('Y-m-d', strtotime(str_replace('/', '-', $_POST['wcpm_patient_dob']))) : ''; $patient_dosage = sanitize_text_field($_POST['wcpm_patient_dosage']); $patient_prescription_date = !empty($_POST['wcpm_patient_prescription_date']) ? date('Y-m-d', strtotime(str_replace('/', '-', $_POST['wcpm_patient_prescription_date']))) : ''; if ($selected_patient_id) { // An existing patient was selected $patient_id = $selected_patient_id; } else { // Create a new patient post $patient_title = $patient_first_name . ' ' . $patient_last_name; $current_user_id = get_current_user_id(); $existing_patient = get_posts(array( 'post_type' => 'patient', 'author' => $current_user_id, 'post_status'=> 'publish', 'meta_query' => array( array( 'key' => 'wcpm_patient_first_name', 'value' => ucwords($patient_first_name), 'compare' => '=' ), array( 'key' => 'wcpm_patient_last_name', 'value' => ucwords($patient_last_name), 'compare' => '=' ) ) )); if ($existing_patient) { $patient_id = $existing_patient[0]->ID; } else { $patient_post = array( 'post_title' => $patient_title, 'post_type' => 'patient', 'post_status' => 'publish', 'post_author' => $current_user_id, ); $patient_id = wp_insert_post($patient_post); // Save the custom fields for the new patient update_post_meta($patient_id, 'wcpm_patient_first_name', ucwords($patient_first_name)); update_post_meta($patient_id, 'wcpm_patient_last_name', ucwords($patient_last_name)); update_post_meta($patient_id, 'wcpm_patient_dob', $patient_dob); } } // Save patient information as order metadata (compatible with HPOS) $order->update_meta_data('_selected_patient_id', $patient_id); $order->update_meta_data('wcpm_patient_first_name', ucwords($patient_first_name)); $order->update_meta_data('wcpm_patient_last_name', ucwords($patient_last_name)); $order->update_meta_data('wcpm_patient_dob', $patient_dob); $order->update_meta_data('wcpm_patient_dosage', $patient_dosage); $order->update_meta_data('wcpm_patient_prescription_date', $patient_prescription_date); } And to make the thankyou page display HPOS compatible, replace the related function with: public function display_patient_information_on_thank_you_page($order_id) { $order = wc_get_order($order_id); // Get the WC_Order object $selected_patient_id = $order->get_meta('_selected_patient_id'); // HPOS compatible if ($selected_patient_id) { $patient_first_name = get_post_meta($selected_patient_id, 'wcpm_patient_first_name', true); $patient_last_name = get_post_meta($selected_patient_id, 'wcpm_patient_last_name', true); $patient_dob = get_post_meta($selected_patient_id, 'wcpm_patient_dob', true); } else { $patient_first_name = $order->get_meta('wcpm_patient_first_name'); // HPOS compatible $patient_last_name = $order->get_meta('wcpm_patient_last_name'); // HPOS compatible $patient_dob = $order->get_meta('wcpm_patient_dob'); // HPOS compatible } $patient_dosage = $order->get_meta('wcpm_patient_dosage'); // HPOS compatible $patient_prescription_date = $order->get_meta('wcpm_patient_prescription_date'); // HPOS compatible $dob_formatted = !empty($patient_dob) ? date('d/m/Y', strtotime($patient_dob)) : ''; $prescription_date_formatted = !empty($patient_prescription_date) ? date('d/m/Y', strtotime($patient_prescription_date)) : ''; echo '<h2>' . __('Patient Information') . '</h2>'; echo '<p><strong>' . __('First Name') . ':</strong> ' . esc_html(ucwords($patient_first_name)) . '</p>'; echo '<p><strong>' . __('Last Name') . ':</strong> ' . esc_html(ucwords($patient_last_name)) . '</p>'; echo '<p><strong>' . __('Date of Birth') . ':</strong> ' . esc_html($dob_formatted) . '</p>'; echo '<p><strong>' . __('Prescription Dosage') . ':</strong> ' . esc_html($patient_dosage) . '</p>'; echo '<p><strong>' . __('Prescription Date') . ':</strong> ' . esc_html($prescription_date_formatted) . '</p>'; } Now your code is compatible with High-Performance Order Storage and should work with or without HPOS enabled. So to resume, for WooCommerce orders metadata: to Read metadata, use get_meta() Method from the WC_Order object. to Update metadata, use update_meta_data() Method from the WC_Order object. When updating order metadata the save() method is required, except with: woocommerce_checkout_create_order action hook, as it's included afterward.

You’ll be in good company