WooCommerce新订单检测:低资源替代admin-ajax的方案咨询
Hey there! I totally get the frustration of that CPU spike every time your admin-ajax poll runs—let's swap that inefficient polling setup for something way kinder to your server. Here are the best options, ordered by efficiency:
1. WebSocket Push Notifications (Most Efficient)
Ditch polling entirely and let your server push alerts when a new order comes in. This eliminates repeated HTTP requests entirely, so CPU usage stays flat unless there's actually an order to process.
How to implement:
- Use a lightweight WordPress WebSocket plugin (search the official plugin repo for "WP WebSocket" to find a suitable option) to set up a WebSocket server.
- Add a custom hook in your plugin or theme's
functions.phpthat triggers on WooCommerce'swoocommerce_new_orderaction. When a new order is created, send a WebSocket event to connected admin clients. - On the admin dashboard front-end, add JavaScript to listen for that WebSocket event. When it fires, trigger your alert sound.
Why this works:
No more repeated database checks—only communication happens when an order is placed. CPU usage drops to near zero during idle times.
2. Optimize Your Existing Admin-Ajax Poll (Quick Fix)
If you can't switch to push right now, you can drastically reduce CPU load by optimizing the poll itself:
- Slow down the poll frequency: 10 seconds is aggressive. Try 30 seconds unless you absolutely need instant alerts.
- Simplify the order query: Instead of fetching full order data, only grab the latest order ID/timestamp and compare it to the last known value. Use minimal parameters to lighten the database hit:
// Get only the latest relevant order ID, no extra data $latest_order_id = wc_get_orders([ 'limit' => 1, 'orderby' => 'date', 'order' => 'DESC', 'return' => 'ids', 'status' => ['processing', 'on-hold'] // Target only active order statuses ])[0] ?? null; - Cache the result: Store the latest order timestamp in a transient with a 5-second expiry. This way, your poll only hits the database every other request instead of every 10 seconds.
3. Server-Sent Events (SSE) – Middle Ground
SSE is a simpler alternative to WebSockets for one-way push (perfect for alerts). It uses a persistent HTTP connection, so the server sends updates only when needed.
How to implement:
- Create a custom PHP endpoint (not admin-ajax) with the correct headers to enable SSE:
header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Connection: keep-alive'); $last_order_timestamp = $_GET['last_timestamp'] ?? time(); while (true) { $latest_order = wc_get_orders([ 'limit' => 1, 'orderby' => 'date', 'order' => 'DESC', 'return' => 'objects', 'date_created' => '>' . date('Y-m-d H:i:s', $last_order_timestamp) ])[0] ?? null; if ($latest_order) { echo "data: New order received!\n\n"; flush(); $last_order_timestamp = strtotime($latest_order->get_date_created()); } sleep(5); // Check for new orders every 5 seconds } - On the admin front-end, use
EventSourceto connect to this endpoint and listen for events:const eventSource = new EventSource('/wp-content/plugins/your-plugin/sse-endpoint.php?last_timestamp=' + Date.now()); eventSource.addEventListener('message', (e) => { // Play your alert sound here });
4. Long Polling (Better Than Regular Polling)
Long polling keeps the HTTP connection open until a new order is found or a timeout hits. This cuts down on the number of requests compared to your current 10-second poll.
How to implement:
- Modify your admin-ajax handler to wait for a new order instead of returning immediately. Add a loop that checks for new orders every 2 seconds, up to a 30-second timeout.
- If no order is found in 30 seconds, return an empty response, and your front-end immediately sends a new request. If an order is found, send the alert and let the client reconnect after handling it.
Final Recommendation
Go with WebSockets if you want the most efficient solution long-term. If you need a quicker fix, optimize your existing poll first, then move to SSE or long polling as a middle step.
内容的提问来源于stack exchange,提问作者Zed0121

