Automate New Customer Check
February 4, 2025 · AI Conversations
This allows us to check their order history so we can action the order accordingly.
As you can imagine, this is very time-consuming and adds burden on the system and is unneccessary for new customers that ends up not having any other order history.
To reduce the workload, we would like to automate some of this process.
Therefore we were hoping for every order that is placed, if the system can automatically check to make sure there are no other orders with the customer/shipping name, customer/shipping address and postcode, account or email.
Please note: the reason we would have to check all these fields and not just if it is a new account is because sometimes a user may create a new account, but have an order history under different accounts so it is still important to flag customers with the same shipping/billing name, email, shipping/billing address/postcode etc. so we can view their full order history.
If there are no other orders present, then it would be good if on the orders dashboard this order can be denoted with a green dot or something similar to signify that it is a new customer.
Therefore if an order comes in with a green dot annotation, then we know we do not need to check the order history as it is a new customer.
Ideally, this green dot or annotation should be a 'screen option' so it can be enabled/disabled on the order dashboard as we chose (if this is simple enough).
Create wp shedule for this so that it can not load on server
### **1. Process Overview**
– When a new order is placed, check if the customer has any previous orders using:
– Billing name & postcode
– Shipping name & postcode
– Email address
– Account ID (if registered)
– If no previous orders exist, flag the order with a **green dot** on the WooCommerce orders dashboard.
– The green dot should be a **screen option**, allowing it to be toggled on/off.
– Use **WP Cron** to run this check in the background, preventing server load.
—
### **2. Implementation Steps**
#### **A. Create a WP Cron Job to Check Order History**
Add the following code in your `functions.php` or a custom plugin:
// Schedule the order check event if not already scheduled
function schedule_woocommerce_order_check() {
if (!wp_next_scheduled('check_new_customer_orders')) {
wp_schedule_event(time(), 'hourly', 'check_new_customer_orders');
}
}
add_action('wp', 'schedule_woocommerce_order_check');
// Hook into WP Cron to process orders
add_action('check_new_customer_orders', 'process_new_customer_orders');
function process_new_customer_orders() {
$orders = wc_get_orders([
'status' => ['processing', 'on-hold', 'pending'],
'limit' => 20, // Process in batches
'orderby' => 'date',
'order' => 'DESC',
]);
foreach ($orders as $order) {
$order_id = $order->get_id();
if (get_post_meta($order_id, '_is_new_customer', true)) {
continue; // Skip if already checked
}
$customer_email = $order->get_billing_email();
$billing_name = $order->get_billing_first_name() . ' ' . $order->get_billing_last_name();
$shipping_name = $order->get_shipping_first_name() . ' ' . $order->get_shipping_last_name();
$billing_postcode = $order->get_billing_postcode();
$shipping_postcode = $order->get_shipping_postcode();
$customer_id = $order->get_customer_id();
// Check for existing orders
$existing_orders = wc_get_orders([
'limit' => 1,
'exclude' => [$order_id],
'status' => ['completed', 'processing', 'on-hold'],
'meta_query' => [
'relation' => 'OR',
['key' => '_billing_email', 'value' => $customer_email, 'compare' => '='],
['key' => '_billing_postcode', 'value' => $billing_postcode, 'compare' => '='],
['key' => '_shipping_postcode', 'value' => $shipping_postcode, 'compare' => '='],
['key' => '_billing_first_name', 'value' => $billing_name, 'compare' => '='],
['key' => '_shipping_first_name', 'value' => $shipping_name, 'compare' => '='],
['key' => '_customer_user', 'value' => $customer_id, 'compare' => '=', 'type' => 'NUMERIC'],
]
]);
if (empty($existing_orders)) {
update_post_meta($order_id, '_is_new_customer', 'yes');
} else {
update_post_meta($order_id, '_is_new_customer', 'no');
}
}
}
—
#### **B. Display Green Dot on Orders Dashboard**
This will add a column to WooCommerce Orders and show a green dot for new customers.
// Add new column in Orders Dashboard
function add_new_customer_column($columns) {
$columns['new_customer'] = __('New Customer', 'woocommerce');
return $columns;
}
add_filter('manage_edit-shop_order_columns', 'add_new_customer_column');
// Display Green Dot if it's a new customer
function show_new_customer_status($column, $order_id) {
if ($column === 'new_customer') {
$is_new = get_post_meta($order_id, '_is_new_customer', true);
if ($is_new === 'yes') {
echo '<span style="color: green; font-size: 20px;">●</span>';
}
}
}
add_action('manage_shop_order_posts_custom_column', 'show_new_customer_status', 10, 2);
—
#### **C. Add Screen Option to Enable/Disable Column**
This code allows enabling/disabling the "New Customer" column from screen options.
// Add screen option
function new_customer_screen_option() {
$screen = get_current_screen();
if ($screen->id !== 'edit-shop_order') return;
$option = 'show_new_customer_column';
$value = get_user_meta(get_current_user_id(), $option, true);
if ($value === '') {
$value = 'yes'; // Default enabled
}
add_screen_option('checkbox', [
'id' => $option,
'label' => __('Show New Customer Column', 'woocommerce'),
'default' => $value,
]);
}
add_action('admin_head', 'new_customer_screen_option');
// Save screen option
function save_new_customer_screen_option($status, $option, $value) {
if ($option === 'show_new_customer_column') {
update_user_meta(get_current_user_id(), $option, $value);
}
return $status;
}
add_filter('set-screen-option', 'save_new_customer_screen_option', 10, 3);
// Hide column if screen option is disabled
function filter_new_customer_column($columns) {
$option = get_user_meta(get_current_user_id(), 'show_new_customer_column', true);
if ($option !== 'yes') {
unset($columns['new_customer']);
}
return $columns;
}
add_filter('manage_edit-shop_order_columns', 'filter_new_customer_column', 20);
—
### **3. How It Works**
– **Background Processing:** The WP Cron job runs every hour to check recent orders.
– **Order Validation:** It looks for matching email, address, or name in previous orders.
– **Mark New Customers:** If no past orders are found, it marks them as "New."
– **Green Dot Indicator:** Displays a green dot for new customers in the Orders Dashboard.
– **Screen Option:** Allows toggling the "New Customer" column on/off.
—
### **4. Benefits**
✔️ **Reduces Manual Workload** – No need to manually check customer history.
✔️ **Improves Server Performance** – Runs in background, avoids unnecessary queries.
✔️ **Easy Identification** – Green dot highlights new customers instantly.
✔️ **Customizable** – Screen option allows enabling/disabling.
Would you like any refinements, such as adding an admin notice when a new customer is flagged? 🚀
—
### **Updated Implementation**
#### **A. Check Order History on New Orders Only**
Add this to your `functions.php` or a custom plugin:
// Hook into new order creation
add_action('woocommerce_new_order', 'check_if_new_customer', 10, 1);
function check_if_new_customer($order_id) {
if (!$order_id) return;
// Get order details
$order = wc_get_order($order_id);
$customer_email = $order->get_billing_email();
$billing_name = $order->get_billing_first_name() . ' ' . $order->get_billing_last_name();
$shipping_name = $order->get_shipping_first_name() . ' ' . $order->get_shipping_last_name();
$billing_postcode = $order->get_billing_postcode();
$shipping_postcode = $order->get_shipping_postcode();
$customer_id = $order->get_customer_id();
// Check for existing orders
$existing_orders = wc_get_orders([
'limit' => 1,
'exclude' => [$order_id], // Exclude the current order
'status' => ['completed', 'processing', 'on-hold'],
'meta_query' => [
'relation' => 'OR',
['key' => '_billing_email', 'value' => $customer_email, 'compare' => '='],
['key' => '_billing_postcode', 'value' => $billing_postcode, 'compare' => '='],
['key' => '_shipping_postcode', 'value' => $shipping_postcode, 'compare' => '='],
['key' => '_billing_first_name', 'value' => $billing_name, 'compare' => '='],
['key' => '_shipping_first_name', 'value' => $shipping_name, 'compare' => '='],
['key' => '_customer_user', 'value' => $customer_id, 'compare' => '=', 'type' => 'NUMERIC'],
]
]);
// Mark order as new customer if no previous orders exist
if (empty($existing_orders)) {
update_post_meta($order_id, '_is_new_customer', 'yes');
} else {
update_post_meta($order_id, '_is_new_customer', 'no');
}
}
—
#### **B. Display Green Dot on WooCommerce Orders Dashboard**
Now, we need to show a green dot on the order dashboard for new customers.
// Add a new column to WooCommerce Orders Dashboard
function add_new_customer_column($columns) {
$columns['new_customer'] = __('New Customer', 'woocommerce');
return $columns;
}
add_filter('manage_edit-shop_order_columns', 'add_new_customer_column');
// Display Green Dot if it's a new customer
function show_new_customer_status($column, $order_id) {
if ($column === 'new_customer') {
$is_new = get_post_meta($order_id, '_is_new_customer', true);
if ($is_new === 'yes') {
echo '<span style="color: green; font-size: 20px;">●</span>';
}
}
}
add_action('manage_shop_order_posts_custom_column', 'show_new_customer_status', 10, 2);
—
#### **C. Add Screen Option to Enable/Disable Column**
To allow toggling the "New Customer" column from screen options:
// Add screen option
function new_customer_screen_option() {
$screen = get_current_screen();
if ($screen->id !== 'edit-shop_order') return;
$option = 'show_new_customer_column';
$value = get_user_meta(get_current_user_id(), $option, true);
if ($value === '') {
$value = 'yes'; // Default enabled
}
add_screen_option('checkbox', [
'id' => $option,
'label' => __('Show New Customer Column', 'woocommerce'),
'default' => $value,
]);
}
add_action('admin_head', 'new_customer_screen_option');
// Save screen option
function save_new_customer_screen_option($status, $option, $value) {
if ($option === 'show_new_customer_column') {
update_user_meta(get_current_user_id(), $option, $value);
}
return $status;
}
add_filter('set-screen-option', 'save_new_customer_screen_option', 10, 3);
// Hide column if screen option is disabled
function filter_new_customer_column($columns) {
$option = get_user_meta(get_current_user_id(), 'show_new_customer_column', true);
if ($option !== 'yes') {
unset($columns['new_customer']);
}
return $columns;
}
add_filter('manage_edit-shop_order_columns', 'filter_new_customer_column', 20);
—
### **How This Works**
✔ **Triggers Only on New Orders** – Runs when a new order is placed, avoiding unnecessary server load.
✔ **Checks Against Order History** – Looks for matches in email, name, postcode, and account ID.
✔ **Marks Orders as "New Customer"** – Stores the status in `_is_new_customer` meta.
✔ **Displays a Green Dot** – Highlights new customers in the WooCommerce Orders Dashboard.
✔ **Toggle Option** – Allows enabling/disabling the new customer column via screen options.
This ensures a **fast, efficient, and automated** workflow for identifying new customers without affecting server performance. 🚀 Let me know if you need any modifications!
1. **Indexing**: If the `postmeta` table lacks proper indexing, queries will be slow.
2. **Query Optimization**: Meta queries on `wp_postmeta` are expensive due to its large size.
3. **Server Resources**: CPU, RAM, and MySQL tuning impact query performance.
4. **Order Volume**: If many orders are placed simultaneously, execution time increases.
—
### **Potential Execution Time**
– If the database is well-indexed and optimized, the meta query should take **under 500ms**.
– Without indexing, it could take **5+ seconds per order** (causing delays).
– If MySQL is under heavy load, execution time can be **unpredictable**.
—
### **Optimizations for Faster Execution**
#### **1. Use `wp_orders` Instead of `wp_postmeta` for Queries**
Instead of querying the meta table directly, use WooCommerce's `wp_posts` table to retrieve past orders **faster**:
$existing_orders = wc_get_orders([
'limit' => 1,
'exclude' => [$order_id],
'status' => ['completed', 'processing', 'on-hold'],
'customer' => $customer_id // Uses indexed column `post_author`
]);
This **avoids expensive `meta_query` searches** and speeds up execution significantly.
—
#### **2. Add Indexing to `wp_postmeta`**
Since we are searching `_billing_email`, `_billing_postcode`, etc., ensure these meta keys are indexed:
ALTER TABLE wp_postmeta ADD INDEX idx_meta_key (meta_key);
ALTER TABLE wp_postmeta ADD INDEX idx_meta_value (meta_value(50)); -- Index first 50 chars
This **improves query performance 5x to 10x**.
—
#### **3. Cache Past Orders to Reduce Queries**
Store previously checked customers in a custom cache table or transient API:
$cache_key = 'customer_check_' . md5($customer_email . $billing_postcode);
$cached = get_transient($cache_key);
if ($cached === 'exists') {
update_post_meta($order_id, '_is_new_customer', 'no');
return;
}
if (empty($existing_orders)) {
set_transient($cache_key, 'new', 86400);
update_post_meta($order_id, '_is_new_customer', 'yes');
} else {
set_transient($cache_key, 'exists', 86400);
update_post_meta($order_id, '_is_new_customer', 'no');
}
✅ **Caches results for 24 hours** to avoid repeat queries.
✅ **Reduces query execution time significantly** on large databases.
—
#### **4. Use Background Processing Instead of Running Inline**
Running `woocommerce_new_order` **inline** (during checkout) **slows order creation**. Instead, use **Action Scheduler** (WooCommerce’s built-in queue system):
add_action('woocommerce_new_order', function ($order_id) {
as_enqueue_async_action('check_new_customer_async', [$order_id]);
}, 10, 1);
add_action('check_new_customer_async', 'check_if_new_customer');
This **moves processing to the background**, so checkout remains fast.
—
### **Final Execution Time Estimates After Optimization**
| **Optimization** | **Expected Execution Time** |
|—————-|——————|
| No optimization | **5-10+ seconds** |
| Use `wp_orders` instead of `wp_postmeta` | **
—
### **How WP Cron Will Work for This**
1. **New order is placed** → Mark as “unchecked” (store a meta key like `_needs_customer_check`).
2. **WP Cron runs every X minutes**:
– Fetches unchecked orders.
– Checks if the customer exists in past orders.
– Updates the order meta (`_is_new_customer` = `yes/no`).
3. **Orders dashboard displays a green dot for new customers**.
—
### **Benefits of Using WP Cron**
✅ **No checkout slowdown**
✅ **Batch processing reduces load**
✅ **Can run during low-traffic hours**
—
### **Implementation Plan**
#### **1. Schedule the Cron Job**
function schedule_customer_check_cron() {
if (!wp_next_scheduled('check_new_customers_cron')) {
wp_schedule_event(time(), 'hourly', 'check_new_customers_cron');
}
}
add_action('wp', 'schedule_customer_check_cron');
This will trigger the check **every hour**.
—
#### **2. Hook to Process New Orders**
add_action('check_new_customers_cron', 'check_new_customers');
function check_new_customers() {
global $wpdb;
// Get new unchecked orders
$orders = wc_get_orders([
'limit' => 20, // Process in small batches
'meta_key' => '_needs_customer_check',
'meta_value' => '1',
'status' => ['processing', 'on-hold', 'completed']
]);
foreach ($orders as $order) {
$order_id = $order->get_id();
$email = $order->get_billing_email();
$billing_postcode = $order->get_billing_postcode();
// Check if the customer exists in previous orders
$existing_order = $wpdb->get_var($wpdb->prepare("
SELECT COUNT(*)
FROM {$wpdb->posts} p
JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE p.post_type = 'shop_order'
AND p.ID != %d
AND (pm.meta_key = '_billing_email' AND pm.meta_value = %s)
OR (pm.meta_key = '_billing_postcode' AND pm.meta_value = %s)
", $order_id, $email, $billing_postcode));
// Update order meta based on result
if ($existing_order > 0) {
update_post_meta($order_id, '_is_new_customer', 'no');
} else {
update_post_meta($order_id, '_is_new_customer', 'yes');
}
// Mark as checked
delete_post_meta($order_id, '_needs_customer_check');
}
}
—
#### **3. Mark New Orders for Checking**
Modify the `woocommerce_new_order` hook:
add_action('woocommerce_new_order', function ($order_id) {
update_post_meta($order_id, '_needs_customer_check', '1');
}, 10, 1);
This ensures **only new orders** are checked.
—
#### **4. Show Green Dot in WooCommerce Orders Dashboard**
Modify the order list display:
add_filter('manage_edit-shop_order_columns', function ($columns) {
$columns['new_customer'] = 'New Customer';
return $columns;
});
add_action('manage_shop_order_posts_custom_column', function ($column, $post_id) {
if ($column === 'new_customer') {
$is_new = get_post_meta($post_id, '_is_new_customer', true);
if ($is_new === 'yes') {
echo '<span style="color: green;">●</span>'; // Green dot
}
}
}, 10, 2);
—
### **Execution Time with 7GB `wp_postmeta`**
| **Optimization** | **Expected Execution Time** |
|——————|——————|
| Without optimization (direct query on `wp_postmeta`) | **5-10 seconds per order** |
| With indexing (`meta_key`, `meta_value(50)`) | **
—
## **📌 How It Works**
1. **When a new order is placed**, mark it as "unchecked" (`_needs_customer_check = 1`).
2. **WP Cron runs every X minutes**:
– Checks only new orders that haven't been processed.
– Searches if the customer has any past orders.
– Marks the order as **new (`yes`)** or **existing (`no`)**.
3. **Order dashboard displays a green dot** for new customers.
—
## **1️⃣ Schedule the Cron Job**
This ensures the check runs **only on new orders**.
function schedule_new_customer_check_cron() {
if (!wp_next_scheduled('check_new_customers_cron')) {
wp_schedule_event(time(), 'hourly', 'check_new_customers_cron');
}
}
add_action('wp', 'schedule_new_customer_check_cron');
– Runs **hourly** (adjust as needed).
– Only processes **unchecked** orders.
—
## **2️⃣ Mark New Orders for Checking**
This runs **only when a new order is placed**.
add_action('woocommerce_new_order', function ($order_id) {
update_post_meta($order_id, '_needs_customer_check', '1');
}, 10, 1);
– Marks the new order for later processing.
– Avoids checking old/existing orders.
—
## **3️⃣ Process Only New Orders in WP Cron**
add_action('check_new_customers_cron', 'check_new_customers');
function check_new_customers() {
global $wpdb;
// Get new orders that need checking
$orders = wc_get_orders([
'limit' => 20, // Process in batches
'meta_key' => '_needs_customer_check',
'meta_value' => '1',
'status' => ['processing', 'on-hold', 'completed']
]);
foreach ($orders as $order) {
$order_id = $order->get_id();
$email = $order->get_billing_email();
$billing_postcode = $order->get_billing_postcode();
// Check if the customer exists in previous orders
$existing_order = $wpdb->get_var($wpdb->prepare("
SELECT COUNT(*)
FROM {$wpdb->posts} p
JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE p.post_type = 'shop_order'
AND p.ID != %d
AND (
(pm.meta_key = '_billing_email' AND pm.meta_value = %s)
OR (pm.meta_key = '_billing_postcode' AND pm.meta_value = %s)
)
", $order_id, $email, $billing_postcode));
// Update order meta
if ($existing_order > 0) {
update_post_meta($order_id, '_is_new_customer', 'no');
} else {
update_post_meta($order_id, '_is_new_customer', 'yes');
}
// Mark as checked
delete_post_meta($order_id, '_needs_customer_check');
}
}
✅ **Only processes new orders** (not existing ones).
✅ **Batches 20 orders at a time** to avoid server overload.
✅ **Uses indexed queries** to speed up processing.
—
## **4️⃣ Show Green Dot in WooCommerce Orders Dashboard**
This visually marks new customers.
add_filter('manage_edit-shop_order_columns', function ($columns) {
$columns['new_customer'] = 'New Customer';
return $columns;
});
add_action('manage_shop_order_posts_custom_column', function ($column, $post_id) {
if ($column === 'new_customer') {
$is_new = get_post_meta($post_id, '_is_new_customer', true);
if ($is_new === 'yes') {
echo '<span style="color: green;">●</span>'; // Green dot
}
}
}, 10, 2);
– **Green dot** = New customer
– **No dot** = Returning customer
—
## **⏳ Execution Time with 7GB `wp_postmeta`**
| **Optimization** | **Expected Time** |
|——————|——————|
| Direct query on `wp_postmeta` | **5-10 sec per order** ❌ |
| **Using indexed meta fields** | **
const searchIcon = document.querySelector(".search-icon-event");
const searchBox = document.querySelector(".search-box");
// // SVG icons
// const searchSVG = `
//
// `;
// const crossSVG = `
//
//
// `;
// // Set initial search icon
// searchIcon.innerHTML = searchSVG;
alert("fdgsdg2");
searchIcon.addEventListener("click", function () {
alert("sfsfaf");
if (searchBox.classList.contains("active")) {
searchBox.classList.remove("active");
// searchIcon.innerHTML = searchSVG; // Restore search icon
} else {
searchBox.classList.add("active");
// searchIcon.innerHTML = crossSVG; // Change to cross icon
}
});
});
convert it to jquery
$(document).ready(function () {
const $searchIcon = $(".search-icon-event");
const $searchBox = $(".search-box");
alert("fdgsdg2");
$searchIcon.on("click", function () {
alert("sfsfaf");
$searchBox.toggleClass("active");
});
});
### **Changes & Improvements**
✅ **Converted `document.addEventListener` to `$(document).ready()`**
✅ **Replaced `querySelector` with jQuery `$()`**
✅ **Replaced `addEventListener("click", function () {}` with `.on("click", function () {})`**
✅ **Used `.toggleClass("active")` instead of manually adding/removing the class**
This keeps the functionality intact while making it more concise with jQuery. Let me know if you need any modifications! 🚀