Asked  7 Months ago    Answers:  5   Viewed   57 times

In WooCommerce, I would like to send a request to an API once the customer has successfully checked out. Its basically a website where the client is selling online courses (Like udemy).

When the customer checks out, I would like to send an API request and enroll the user for that particular course. I have tried several WooCommerce hooks but none worked for me.

This is the code that I'm using:

add_action('woocommerce_checkout_order_processed', 'enroll_student', 10, 1);

function enroll_student($order_id)
    echo $order_id;
    echo "Hooked";

I am writing this code for a plugin and to make it easier, I am currently using Cash on Delivery method.

Can anyone point me out where I am going wrong because when I checkout I cant see the message "hooked" that I am printing nor the $order_id?

It takes me to the success page and doesn't show these two things that I am printing.



Update 2 Only For Woocommerce 3+ (added restriction to execute the code only once)

add_action('woocommerce_thankyou', 'enroll_student', 10, 1);
function enroll_student( $order_id ) {
    if ( ! $order_id )

    // Allow code execution only once 
    if( ! get_post_meta( $order_id, '_thankyou_action_done', true ) ) {

        // Get an instance of the WC_Order object
        $order = wc_get_order( $order_id );

        // Get the order key
        $order_key = $order->get_order_key();

        // Get the order number
        $order_key = $order->get_order_number();

            $paid = __('yes');
            $paid = __('no');

        // Loop through order items
        foreach ( $order->get_items() as $item_id => $item ) {

            // Get the product object
            $product = $item->get_product();

            // Get the product Id
            $product_id = $product->get_id();

            // Get the product name
            $product_id = $item->get_name();

        // Output some data
        echo '<p>Order ID: '. $order_id . ' — Order Status: ' . $order->get_status() . ' — Order is paid: ' . $paid . '</p>';

        // Flag the action as done (to avoid repetitions on reload for example)
        $order->update_meta_data( '_thankyou_action_done', true );

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

Related thread:

  • Get Order items and WC_Order_Item_Product in WooCommerce 3
  • How to get WooCommerce order details

The code is tested and works.

Updated (to get the product Id from Orders items as asked in your comment)

May be you could use woocommerce_thankyou hook instead, that will display on order-received page your echoed code, this way:

add_action('woocommerce_thankyou', 'enroll_student', 10, 1);
function enroll_student( $order_id ) {

    if ( ! $order_id )

    // Getting an instance of the order object
    $order = wc_get_order( $order_id );

        $paid = 'yes';
        $paid = 'no';

    // iterating through each order items (getting product ID and the product object) 
    // (work for simple and variable products)
    foreach ( $order->get_items() as $item_id => $item ) {

        if( $item['variation_id'] > 0 ){
            $product_id = $item['variation_id']; // variable product
        } else {
            $product_id = $item['product_id']; // simple product

        // Get the product object
        $product = wc_get_product( $product_id );


    // Ouptput some data
    echo '<p>Order ID: '. $order_id . ' — Order Status: ' . $order->get_status() . ' — Order is paid: ' . $paid . '</p>';

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

The code is tested and works.

Then you can use all class WC_Abstract_Order methods on the $order object.


  • How to get WooCommerce order details
  • Get Order items and WC_Order_Item_Product in WooCommerce 3
    • How to get Customer details from Order in WooCommerce?
Wednesday, March 31, 2021
answered 7 Months ago

You need to make some changes in your code… The following code will display the shipping phone field in:

  • Checkout
  • My Account > Address > Edit shipping address
  • Admin order edit pages

The code will also add the shipping phone to formatted displayed shipping address on emails shipping address section.

// display shipping phone in checkout and my account edit shipping address
add_filter( 'woocommerce_shipping_fields', 'add_shipping_phone_field' );
function add_shipping_phone_field( $fields ) {
   $fields['shipping_phone'] = array(
      'label' => __('Phone (Shipping)'),
      'required' => true,
      'class' => array( 'form-row-wide' ),
      'priority' => 25,
   return $fields;

// Editable field on admin order edit pages inside edit shipping section
add_filter( 'woocommerce_admin_shipping_fields' , 'add_order_admin_edit_shipping_phone' );
function add_order_admin_edit_shipping_phone( $fields ) {
    // Include shipping phone as editable field
    $fields['phone'] = array( 'label' => __("Shipping phone"), 'show' => '0' );

    return $fields;

// Adding custom placeholder to woocommerce formatted address only on Backend
add_filter( 'woocommerce_localisation_address_formats', 'admin_localisation_address_formats', 50, 1 );
function admin_localisation_address_formats( $address_formats ){
    // Only in backend (Admin)
    if( is_admin() || ! is_wc_endpoint_url() ) {
        foreach( $address_formats as $country_code => $address_format ) {
            $address_formats[$country_code] .= "n{phone}";
    return $address_formats;

// Custom placeholder replacement to woocommerce formatted address
add_filter( 'woocommerce_formatted_address_replacements', 'custom_formatted_address_replacements', 10, 2 );
function custom_formatted_address_replacements( $replacements, $args  ) {
    $replacements['{phone}'] = ! empty($args['phone']) ? $args['phone'] : '';

    return $replacements;

// Add the shipping phone value to be displayed on email notifications under shipping address
add_filter( 'woocommerce_order_formatted_shipping_address', 'add_shipping_phone_to_formatted_shipping_address', 100, 2 );
function add_shipping_phone_to_formatted_shipping_address( $shipping_address, $order ) {
    global $pagenow, $post_type;

    // Not on admin order edit pages (as it's already displayed).
    if( ! ( $pagenow === 'post.php' && $post_type === 'shop_order' && isset($_GET['action']) && $_GET['action'] === 'edit' ) ) {
        // Include shipping phone on formatted shipping address
        $shipping_address['phone'] = $order->get_meta('_shipping_phone');
    return $shipping_address;

// Remove double billing phone from email notifications (and admin) under billing address
add_filter( 'woocommerce_order_formatted_billing_address', 'remove_billing_phone_from_formatted_billing_address', 100, 2 );
function remove_billing_phone_from_formatted_billing_address( $billing_address, $order ) {
    return $billing_address;

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

For billing custom fields, you will replace the hooks:

  • woocommerce_shipping_fields by woocommerce_billing_fields
  • woocommerce_admin_shipping_fields by woocommerce_admin_billing_fields
  • woocommerce_order_formatted_shipping_address by woocommerce_order_formatted_billing_address
  • (don't use the last function).

For the front endpoints:

On order received (thank you), order-pay, and myaccount / order-view, you will have to override via your active theme the template order/order-details-customer.php.

You will add inside the html tag <address> after line 52 the following:

        <?php if ( $shipping_phone = $order->get_meta('_shipping_phone') ) : ?>
            <p class="woocommerce-customer-details--phone"><?php echo esc_html( $shipping_phone ); ?></p>
        <?php endif; ?>

On admin side, the shipping phone is displayed and editable:

enter image description here

On order-view, order-received and email notifications, the shipping phone is displayed at the end of the shipping address section:

enter image description here

Wednesday, March 31, 2021
answered 7 Months ago

As you are saving this custom field data, using the meta_key: 'Business Address?'… So you need to use this meta_key to retrieve the data this way:

// Display field value on the admin order edit page
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'custom_checkout_field_display_admin_order_meta', 10, 1 );
function custom_checkout_field_display_admin_order_meta( $order ){
    $business_address = get_post_meta( $order->get_id(), 'Business Address?', true );
    if( ! empty( $business_address ) )
        echo '<p><strong>'.__('Ship to a Business Address', 'woocommerce').': </strong> ' . $business_address . '</p>';

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

Tested on WooCommerce 3 and works.

Wednesday, March 31, 2021
answered 7 Months ago

You can perform postmortem debugging by using a combination of the WER registry keys/values to trap any dump that is produced. I’ve used this method to prevent the WER system from collecting the dump file (.dmp). I’ve also written about this in another similar post. To accomplish this, you will need to create a registry key under

SoftwareMicrosoftWindowsWindows Error Reporting

if one does not already exist. The key should be

LocalDumpsyour application.exe

Once that’s done, modify these keys/values to meet your needs:

DumpCount, DumpFolder, DumpType

You’ll need Administrator rights to create and modify the keys, and, you should reset everything you’ve modified when you’re done debugging.

Wednesday, September 1, 2021
answered 2 Months ago

What is contained in your DataSet?

Maybe the DataTable contained in your DataSet does not have any rows. I would leave AutoGenerateColumns to true and just manually hide what columns you don't want to see. I have never used AutoGenerateColumns = false. However, without more code, it is going to be hard to diagnose. Try swapping those two statements (.DataSource first).

AutoGenerateColumns may have no effect on the corresponding binding source (DataTable from DataSet).

DataSet needs to be filled by DataAdapter:

// Example
DataAdapter = new SqlDataAdapter();
DataAdapter = CreateInventoryAdapter();
DataAdapter.TableMappings.Add("Table", "GARAGE");

myDataView = myDataSet.Tables[0].DefaultView;
dataGridView1.DataSource = myDataView
Wednesday, October 13, 2021
answered 2 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :