processing/on-hold done by the gateway after the hooks above. add_action( 'woocommerce_order_status_changed', 'orderping_on_status_changed', 20, 3 ); } /** * Classic checkout hook. * * @param int $order_id Order ID. */ function orderping_on_checkout_processed( $order_id ) { $order = wc_get_order( $order_id ); orderping_mark_capture_eligible( $order ); orderping_capture_order( $order ); } /** * Blocks checkout hook. * * @param WC_Order $order Order. */ function orderping_on_store_api_processed( $order ) { orderping_mark_capture_eligible( $order ); orderping_capture_order( $order ); } /** * Marks an order placed at checkout while capture is enabled. The status-change * path requires this, so an order that existed before install (or while capture * was off) and later moves processing -> completed never sends a confirmation. * * @param WC_Order|false|null $order Order. */ function orderping_mark_capture_eligible( $order ) { try { if ( ! $order instanceof WC_Order || null === orderping_connection() || ! orderping_order_in_scope( $order ) ) { return; } $order->update_meta_data( ORDERPING_CAPTURE_ELIGIBLE_META, '1' ); $order->save(); } catch ( \Throwable $e ) { return; // Checkout must never fail because of this plugin. } } /** * Status-change hook. * * @param int $order_id Order ID. * @param string $from Previous status. * @param string $to New status. */ function orderping_on_status_changed( $order_id, $from, $to ) { if ( in_array( $to, ORDERPING_PLACED_STATUSES, true ) ) { orderping_capture_order( wc_get_order( $order_id ) ); } } /** * Emits `order_placed` once for a real placed order. Safe to call repeatedly * and from concurrent requests: the outbox event key is unique per order. * Never makes an HTTP request and never throws into checkout. * * @param WC_Order|false|null $order Order. */ function orderping_capture_order( $order ) { try { if ( ! $order instanceof WC_Order || null === orderping_connection() || ! orderping_order_in_scope( $order ) ) { return; } if ( ! in_array( $order->get_status(), ORDERPING_PLACED_STATUSES, true ) ) { return; // checkout-draft, pending, failed, cancelled, trash, refunded... } // Admin-created or imported orders and old orders are not new customer orders. if ( ! in_array( $order->get_created_via(), ORDERPING_CHECKOUT_SOURCES, true ) ) { return; } // Only orders that were placed at checkout while capture was enabled. if ( '1' !== (string) $order->get_meta( ORDERPING_CAPTURE_ELIGIBLE_META ) ) { return; } $order_id = (int) $order->get_id(); $key = 'placed-' . $order_id; $enqueued = orderping_outbox_enqueue( $key, $order_id, array( 'type' => 'order_placed', 'event_id' => $key, 'contract_version' => ORDERPING_CONTRACT_VERSION, 'plugin_version' => ORDERPING_VERSION, 'order' => orderping_order_payload( $order ), ) ); // Baseline for later edit detection (see updates.php). Only when this call // persisted the placed event: on a repeat, edits since then may be unreported. if ( true === $enqueued ) { orderping_remember_fingerprint( $order ); } } catch ( \Throwable $e ) { // Checkout must never fail because of this plugin. return; } } /** * Order fields sent to the backend. Money is integer minor units. * * @param WC_Order $order Order. * @return array */ function orderping_order_payload( WC_Order $order ) { $decimals = (int) wc_get_price_decimals(); $items = array(); foreach ( $order->get_items() as $item ) { $product = $item->is_type( 'line_item' ) ? $item->get_product() : null; $items[] = array( 'name' => wp_strip_all_tags( $item->get_name() ), 'variant_title' => null, 'sku' => $product ? (string) $product->get_sku() : null, 'quantity' => (int) $item->get_quantity(), ); } return array( 'id' => (string) $order->get_id(), 'number' => (string) $order->get_order_number(), 'status' => $order->get_status(), 'currency' => $order->get_currency(), 'currency_decimals' => $decimals, // String math: wc_format_decimal gives a fixed-decimals string; dropping the dot yields minor units. 'total_minor' => (int) str_replace( '.', '', wc_format_decimal( $order->get_total(), $decimals ) ), 'payment_method' => (string) $order->get_payment_method(), 'payment_method_title' => (string) $order->get_payment_method_title(), 'line_items' => $items, 'shipping' => array( 'address_1' => $order->get_shipping_address_1(), 'address_2' => $order->get_shipping_address_2(), 'city' => $order->get_shipping_city(), 'state' => $order->get_shipping_state(), 'postcode' => $order->get_shipping_postcode(), 'country' => $order->get_shipping_country(), ), 'permission' => orderping_permission_payload( $order ), 'billing' => array( 'first_name' => $order->get_billing_first_name(), 'phone' => $order->get_billing_phone(), 'country' => $order->get_billing_country(), ), ); }