Kemp.rest / Examples / Code / Merged order history

KEMP.REST / EXAMPLES / CODE

Merged order history

Written by Kevin Kemp in PHP. JSON REST and WooCommerce account templates, for a proprietary back office .NET points system.

View the code

A customer could have orders in WooCommerce and older or parallel orders in the .NET back office. My Account showed only the local ones. A visit from an ad or an affiliate also dropped its referrer and UTM values before checkout. This file builds one order list and keeps those visit parameters on the order.

Type of code

WordPress and WooCommerce functions. One part replaces the My Account orders screen. Another stores marketing parameters from the landing URL onto the order.

Technology

PHP, WooCommerce account hooks and order objects, the back office JSON REST order API (/V2/Order?EmailOrMemberId=) with a bearer token from Advanced Custom Fields, the WooCommerce orders template, PHP sessions, and order meta. The API host in the sample is api.example.com. The access token is not in the file.

What it does

Problem it solved

One My Account page showed store orders and back office orders together, with shipment detail on the matching rows. Affiliate and campaign values from the landing URL were still on the order after checkout.

Code

Back to summary · woo_functions.php

<?php

if ( ! defined( 'BACKOFFICE_API_BASE_URL' ) ) {
    define('BACKOFFICE_API_BASE_URL','https://api.example.com');
}


add_filter( 'woocommerce_my_account_my_address_formatted_address', function( $args, $customer_id, $name ){
    $args['phone'] = get_user_meta( $customer_id, $name . '_phone', true );
    return $args;
}, 10, 3 );

add_filter( 'woocommerce_localisation_address_formats', function( $formats ){
    foreach ( $formats as $key => &$format ) {
        $format .= "\n{phone}";
    }
    return $formats;
} );

add_filter( 'woocommerce_formatted_address_replacements', function( $replacements, $args ){
    $replacements['{phone}'] = $args['phone'];
    return $replacements;
}, 10, 2 );


function compare_by_date($a, $b) {
    // Convert the date strings to timestamps
    $a_date = strtotime($a['date']);
    $b_date = strtotime($b['date']);

    // Compare the timestamps
    if ($a_date == $b_date) {
        return 0; // Equal
    } else if ($a_date > $b_date) {
        return -1; // $a is newer than $b
    } else {
        return 1; // $a is older than $b
    }
}


//---------------------------------------- order History

//add_filter( 'woocommerce_my_account_my_orders_query', 'change_my_orders_query', 10, 1 );
function change_my_orders_query( $query ) {
    $date = new DateTime();
    $date->modify( '-1 week' );
    $query['date_query'] = array(
        'after' => $date->format( 'Y-m-d' )
    );
    return $query;
}


//add_filter( 'woocommerce_my_account_my_orders_columns', 'add_office_order_columns', 10, 1 );
function add_office_order_columns( $columns ) {
    $columns['office_order_status'] = __( 'Back Office Order Status', 'textdomain' );
    return $columns;
}


//add_action( 'woocommerce_account_orders_endpoint', 'output_office_orders', 10, 0 );
function output_office_orders() {
    $current_user_id  = get_current_user_id();

    $args = array(
        'customer_id' => $current_user_id,
        'limit' => -1, // to retrieve _all_ orders by this user
    );
    $customer_orders = wc_get_orders($args);
    //$access_token = get_user_meta($current_user_id, 'auth0_access_token',true);
    $access_token = get_field('access_token','option');
    $user_info = get_userdata($current_user_id);
    $email_user = $user_info->user_email;

    $offset = isset($_GET['offset']) ? $_GET['offset'] : 0;
    $limit = 10;
    
    $api_url = BACKOFFICE_API_BASE_URL.'/V2/Order?EmailOrMemberId='.$email_user.'&Offset=' . $offset . '&Limit=' . $limit;
    
    $response = wp_remote_get($api_url, array(
        'headers' => array('Authorization' => 'Bearer ' . $access_token)
    ));

    if ( is_wp_error( $response ) ) {
        echo '<p>' . __( 'There was an error fetching the back office orders. Please try again later.', 'textdomain' ) . '</p>';
        return;
    }
    $response_body = wp_remote_retrieve_body($response);
    $orders = json_decode( $response_body, true );

    if ( ! isset( $orders ) || ! is_array( $orders ) ) {
        echo '<p>' . __( 'There was an error parsing the back office orders. Please try again later.', 'textdomain' ) . '</p>';
        return;
    }
   // $orders = json_decode( $response_body, true );

    echo '<h2>' . __( 'Back Office Orders', 'textdomain' ) . '</h2>';
    echo '<table class="woocommerce-orders-table woocommerce-MyAccount-orders shop_table shop_table_responsive my_account_orders account-orders-table">';
    echo '<thead><tr>';
    echo '<th class="woocommerce-orders-table__header woocommerce-orders-table__header-order-number"><span class="nobr">' . __( 'Order Number', 'textdomain' ) . '</span></th>';
    echo '<th class="woocommerce-orders-table__header woocommerce-orders-table__header-order-date"><span class="nobr">' . __( 'Order Date', 'textdomain' ) . '</span></th>';
    echo '<th class="woocommerce-orders-table__header woocommerce-orders-table__header-order-status"><span class="nobr">' . __( 'Order Status', 'textdomain' ) . '</span></th>';
    echo '<th class="woocommerce-orders-table__header woocommerce-orders-table__header-order-total"><span class="nobr">' . __( 'Order Total', 'textdomain' ) . '</span></th>';
    echo '</tr></thead>';
    echo '<tbody>';

    foreach ( $orders as $order ) {
        echo '<tr class="woocommerce-orders-table__row woocommerce-orders-table__row--status-' . esc_attr( $order['status'] ) . ' order">';
        echo '<td class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-number" data-title="' . esc_attr__( 'Order Number', 'textdomain' ) . '">';
        echo '<a href="' . esc_url( $order['url'] ) . '">' . esc_html( $order['orderId'] ) . '</a>';
        echo '</td>';
        echo '<td class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-date" data-title="' . esc_attr__( 'Order Date', 'textdomain' ) . '">';
        echo '<time datetime="' . esc_attr( $order['orderDate'] ) . '" title="' . esc_attr( $order['orderDate'] ) . '">' . esc_html( $order['orderDate'] ) . '</time>';
        echo '</td>';
        echo '<td class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-status" data-title="' . esc_attr__( 'Order Status', 'textdomain' ) . '" style="text-align:left; white-space:nowrap;">';
        echo '<mark class="order-status ' . esc_attr( sanitize_html_class( 'status-' . $order['orderStatus'] ) ) . '"><span>' . esc_html( $order['orderStatus'] ) . '</span></mark>';
        echo '</td>';
        echo '<td class="woocommerce-orders-table__cell woocommerce-orders-table__cell-order-total" data-title="' . esc_attr__( 'Order Total', 'textdomain' ) . '">';
        echo '<span class="woocommerce-Price-amount amount">' . esc_html( $order['orderTotal'] ) . '</span>';
        echo '</td>';
        echo '</tr>';
    }
    echo '</tbody>';
    echo '</table>';

    echo '<div class="woocommerce-pagination woocommerce-pagination--without-numbers woocommerce-Pagination">';
    echo '<a class="woocommerce-button woocommerce-button--previous woocommerce-Button woocommerce-Button--previous button" href="' . esc_url( add_query_arg( 'offset', max( 0, $offset - $limit ) ) ) . '">' . __( 'Previous', 'textdomain' ) . '</a>';
    echo '<a class="woocommerce-button woocommerce-button--next woocommerce-Button woocommerce-Button--next button" href="' . esc_url( add_query_arg( 'offset', $offset + $limit ) ) . '">' . __( 'Next', 'textdomain' ) . '</a>';
    echo '</div>';
}


remove_action( 'woocommerce_account_orders_endpoint', 'woocommerce_account_orders' );
add_action( 'woocommerce_account_orders_endpoint', 'backoffice_woocommerce_account_orders' );


function backoffice_woocommerce_account_orders( $current_page ) {
    $current_page    = empty( $current_page ) ? 1 : absint( $current_page );
    $current_user_id  = get_current_user_id();

    $args = array(
        'customer_id' => $current_user_id,
        'limit' => -1, // to retrieve _all_ orders by this user
    );
    $customer_orders = wc_get_orders($args);
    //$access_token = get_user_meta($current_user_id, 'auth0_access_token',true);
    $access_token = get_field('access_token','option');
    $user_info = get_userdata($current_user_id);
    $billing_email = get_user_meta($current_user_id, 'billing_email' , true);
    $shipping_email = get_user_meta($current_user_id, 'shipping_email' , true);
    $email_user = $user_info->user_email;
    if($email_user) {
        $email_order = $email_user;
    }elseif($billing_email) {
        $email_order = $billing_email;
    }elseif($shipping_email) {
        $email_order = $shipping_email;
    }
    $offset = isset($_GET['offset']) ? $_GET['offset'] : 0;
    $limit = 10;
    
    $api_url = BACKOFFICE_API_BASE_URL.'/V2/Order?EmailOrMemberId='.$email_order.'&Offset=' . $offset . '&Limit=' . $limit;
    $response = wp_remote_get($api_url, array(
        'headers' => array('Authorization' => 'Bearer ' . $access_token)
    ));

    if ( is_wp_error( $response ) ) {
        echo '<p>' . __( 'There was an error fetching orders. Please try again later.', 'textdomain' ) . '</p>';
        return;
    }
    
    $status_code = wp_remote_retrieve_response_code( $response );
    
    if ( $status_code == 500 ) {
        $c_orders = array();
        foreach ($customer_orders as $customer_order){
            $order      = wc_get_order( $customer_order );
            $order_id = $order->id;
            $order_id_prefix = $order->get_order_number();
            $c_orders[] = array(
                'id' => $order_id,
                'order_id_prefix' => $order_id_prefix,
                'view_url' => $order->get_view_order_url(),
                'item_count' => $order->get_item_count() - $order->get_item_count_refunded(),
                'date' => wc_format_datetime( $order->get_date_created() ),
                'status' => wc_get_order_status_name( $order->get_status() ),
                'total' => $order->get_formatted_order_total(),
                'actions' => wc_get_account_orders_actions( $order ),
                'packages' => array(),
                'order_type' => 'woo',
            );
        }
    }else {    
    
        $response_body = wp_remote_retrieve_body($response);
        $backoffice_orders = json_decode( $response_body, true );
        
        $one_week_ago = strtotime('-1 week');
        $c_orders = array();
        foreach ($customer_orders as $customer_order){
            $order      = wc_get_order( $customer_order );
            $order_id = $order->id;
            $order_id_prefix = $order->get_order_number();
            $c_orders[] = array(
                'id' => $order_id,
                'order_id_prefix' => $order_id_prefix,
                'view_url' => $order->get_view_order_url(),
                'item_count' => $order->get_item_count() - $order->get_item_count_refunded(),
                'date' => wc_format_datetime( $order->get_date_created() ),
                'status' => wc_get_order_status_name( $order->get_status() ),
                'total' => $order->get_formatted_order_total(),
                'actions' => wc_get_account_orders_actions( $order ),
                'packages' => array(),
                'order_type' => 'woo',
            );
        }
    
        $t_orders = array();
        if($backoffice_orders != '' && empty($backoffice_orders['errors'])) {
            if(count($backoffice_orders)){
                foreach ($backoffice_orders as $backoffice_order){
                    $date = wc_string_to_datetime($backoffice_order['orderDate']);
                    $t_orders[] = array(
                        'id' => $backoffice_order['id'],
                        'office_order_id' => $backoffice_order['orderId'],
                        'view_url' => '',
                        'item_count' => count($backoffice_order['products']),
                        'date' => wc_format_datetime( $date ),
                        'status' => wc_get_order_status_name( $backoffice_order['orderStatus'] ),
                        'total' => wc_price(str_replace('$','',$backoffice_order['orderTotal'])),
                        'actions' => '',
                        'packages' => $backoffice_order['packages'],
                        'order_type' => 'office',
                    );
                }
            }
    
            if($c_orders && $t_orders){
                $filtered_c_orders = array();
                foreach ($c_orders as $c_order) {
                    $c_order_date = strtotime($c_order['date']);
                    if (!(!in_array($c_order['id'], array_column($t_orders, 'id')) && $c_order_date < $one_week_ago)) {
                        $filtered_c_orders[] = $c_order;
                    }
                }
                $c_orders = $filtered_c_orders;
    
                foreach ($c_orders as $key_c => $order_c) {
                    foreach ($t_orders as $key_t => $order_t) {
                        if ($order_c['id'] == $order_t['id']) {
                            $c_orders[$key_c]['packages'] = $order_t['packages'];
                            unset($t_orders[$key_t]);
                            break;
                        }
                    }
                }
    
                $c_orders = array_values($c_orders);
                $t_orders = array_values($t_orders);
            }
    
            $orders = array_merge($c_orders,$t_orders);
            usort($orders, 'compare_by_date');
        }
        else {
            $orders = $c_orders;
        }
    }
    
    



//    $all_orders = array_filter($orders, function($order) use ($oneWeekAgo) {
//        return !($order && strtotime($order['date']) < $oneWeekAgo);
//    });

    wc_get_template(
        'myaccount/orders.php',
        array(
            'current_page'    => absint( $current_page ),
            'orders'      => $orders,
            'has_orders'      => 0 < $orders,
            'wp_button_class' => wc_wp_theme_get_element_class_name( 'button' ) ? ' ' . wc_wp_theme_get_element_class_name( 'button' ) : '',
        )
    );
}


add_action('woocommerce_new_order', 'trivia_add_referrer_to_order_meta', 10, 1);

function trivia_add_referrer_to_order_meta($order_id) {

    $session = WC()->session;
    if ( $session ) {

        $referrer = $session->get('referrer');
        if ($referrer) {
            update_post_meta($order_id, '_referrer', $referrer);
        }
    }

}

add_action('woocommerce_admin_order_data_after_billing_address', 'display_referrer_order_meta', 10, 1);

function display_referrer_order_meta($order) {
    $referrer = get_post_meta($order->get_id(), '_referrer', true);

    if ($referrer) {
        echo '<p><strong>Referrer:</strong> ' . esc_html($referrer) . '</p>';
    }
}



// added by Kevin
add_action('init', 'capture_url_parameters');

function capture_url_parameters() {
    ob_start();
    // Check if all URL parameters are set
    session_start([
        'read_and_close' => true
    ]); // Start the session if not already started

    // Check if each parameter exists in the URL before storing in session
    if(isset($_GET['referrer'])) {
        $_SESSION['referrer'] = $_GET['referrer'];
    }
    if(isset($_GET['affiliateID'])) {
        $_SESSION['affiliateID'] = $_GET['affiliateID'];
    }
    if(isset($_GET['utm_content'])) {
        $_SESSION['utm_content'] = $_GET['utm_content'];
    }
    if(isset($_GET['utm_medium'])) {
        $_SESSION['utm_medium'] = $_GET['utm_medium'];
    }
    if(isset($_GET['utm_source'])) {
        $_SESSION['utm_source'] = $_GET['utm_source'];
    }
    if(isset($_GET['utm_campaign'])) {
        $_SESSION['utm_campaign'] = $_GET['utm_campaign'];
    }
    if(isset($_GET['utm_term'])) {
        $_SESSION['utm_term'] = $_GET['utm_term'];
    }
    if(isset($_GET['sourceID'])) {
        $_SESSION['sourceID'] = $_GET['sourceID'];
    }
    if(isset($_GET['couponcode'])) {
        $_SESSION['couponcode'] = $_GET['couponcode'];
    }
    if(isset($_GET['promocode'])) {
        $_SESSION['promocode'] = $_GET['promocode'];
    }
}


add_action( 'woocommerce_thankyou', 'custom_utm_fields_hook', 10, 1 );

function custom_utm_fields_hook( $order_id ) {
    $order = wc_get_order( $order_id ); // phpcs:ignore.

    session_start([
        'read_and_close' => true
    ]);

    if(isset($_SESSION['referrer'])) {
        update_post_meta( $order_id, 'referrer', $_SESSION['referrer'] );
        unset($_SESSION['referrer']);
    }
    if(isset($_SESSION['affiliateID'])) {
        update_post_meta( $order_id, 'affiliateID', $_SESSION['affiliateID'] );
        unset($_SESSION['affiliateID']);
    }
    if(isset($_SESSION['utm_content'])) {
        update_post_meta( $order_id, 'utm_content', $_SESSION['utm_content'] );
        unset($_SESSION['utm_content']);
    }
    if(isset($_SESSION['utm_medium'])) {
        update_post_meta( $order_id, 'utm_medium', $_SESSION['utm_medium'] );
        unset($_SESSION['utm_medium']);
    }
    if(isset($_SESSION['utm_source'])) {
        update_post_meta( $order_id, 'utm_source', $_SESSION['utm_source'] );
        unset($_SESSION['utm_source']);
    }
    if(isset($_SESSION['utm_campaign'])) {
        update_post_meta( $order_id, 'utm_campaign', $_SESSION['utm_campaign'] );
        unset($_SESSION['utm_campaign']);
    }
    if(isset($_SESSION['utm_term'])) {
        update_post_meta( $order_id, 'utm_term', $_SESSION['utm_term'] );
        unset($_SESSION['utm_term']);
    }
    if(isset($_SESSION['sourceID'])) {
        update_post_meta( $order_id, 'sourceID', $_SESSION['sourceID'] );
        unset($_SESSION['sourceID']);
    }
    if(isset($_SESSION['couponcode'])) {
        update_post_meta( $order_id, 'couponcode', $_SESSION['couponcode'] );
        unset($_SESSION['couponcode']);
    }
    if(isset($_SESSION['promocode'])) {
        update_post_meta( $order_id, 'promocode', $_SESSION['promocode'] );
        unset($_SESSION['promocode']);
    }



}