includes/. Return values must match the type of the default — filters are applied with (int), (string), (bool) or (float) casts as noted.
The ship payload chain — fshipping_ship_payload
The centerpiece. Applied to the instant-mode ship request (array $payload, WC_Order $order, array $shipping) at HTTP/Shipment.php:808; return the modified payload array.
| Priority | Class | Adds |
|---|---|---|
| 10 | Events\SpecialServicesInjector | Special service types (e.g. signature options) |
| 20 | Events\ETDOrchestrator | Electronic trade documents attachment |
| 25 | Trade\CommercialInvoiceBuilder | Commercial invoice + commodity lines |
| 30 | Events\AdvancedServicesInjector | Advanced services enrichment |
| 35 | Events\ProductBoxPayloadInjector | Product Box multi-package packing |
add_filter( 'fshipping_ship_payload', function ( $payload, $order, $shipping ) {
$payload['requestedShipment']['declaredValue'] = 500;
return $payload;
}, 40, 3 );
Guards & checkout flow
| Hook | Type | Fires | Args → return |
|---|---|---|---|
fshipping_pre_ship_check | filter | Twice per instant label: during woocommerce_checkout_process (Checkout.php:77) and again immediately before the Ship call (:222) | (bool true, $order, array $shipping) → return false to abort the label purchase (used by Events\ShipmentGuard for Global Trade compliance). The two calls pass different order objects: at checkout-process time arg 2 is a lightweight order proxy built by Checkout::build_precheck_order_proxy() (no order exists yet); at ship time it is the real WC_Order |
fshipping_allow_shipment_without_address_validation | filter | After address validation fails (Checkout.php:469) | (bool $fail_open_setting, WC_Order $order) → return true to ship anyway (default is the fshipping_address_validation_allow_on_failure setting) |
fshipping_address_validation_override | filter | Address-validation gate (Checkout.php:456) | (bool false, WC_Order $order) → return true to skip validation entirely (same as order meta _fshipping_address_validation_override) |
fshipping_address_validation_payload | filter | Before the Address Validation request (HTTP/AddressValidation.php:63) | (array $payload, array $addresses) → reshape the addressesToValidate body |
fshipping_openship_throw_on_checkout_start_failure | filter | Advanced-mode draft start failed at checkout (Checkout.php:513) | (bool true, WC_Order $order, array $result, array $shipping) → return false to swallow the failure (order completes with a note, no draft); default true rethrows |
fshipping_safety_net_fallback | filter | Rates returned empty and staging SafetyNet is active (Events/RuntimeIntegrator.php:82) | (array [], string $method, array $package) → return a fallback rates array |
Quota
| Hook | Type | Fires | Args → return |
|---|---|---|---|
fshipping_daily_shipment_limit | filter | Every quota check (Licensing/ShipmentQuota.php:116) | (int $limit, string $plan_slug) → return the daily cap; 0 means unlimited. $plan_slug is the Freemius slug: free, core, pro, agency, or the legacy premium / golden aliases |
fshipping_quota_reached_checkout_message | filter | Quota message render (ShipmentQuota.php:125) | (string $message) → replacement for “Checkout limit has been exceeded for today. Please try tomorrow.” |
Rates
| Hook | Type | Fires | Args → return |
|---|---|---|---|
fshipping_rates_cache_ttl | filter | Before each checkout rate lookup (HTTP/Shipping.php:47) | (int 600, array $package) → TTL in seconds; 0 disables the quote cache |
fshipping_calculate_shipping_rates | filter | After HTTP\Shipping::get_shipping_rates() returns, before rates are added to the cart (Frontend/Shipping.php:77) | (array $response, WC_Shipping_Method $method, array $package) → rates array. In-plugin subscribers: Events\RuntimeIntegrator::safety_net_fallback (10), Shipping\OneRateComparator::augment_with_one_rate (20) |
fshipping_rates_payload | filter | The /rate/v1/rates/quotes request body — checkout (HTTP/Shipping.php:298) and HTTP\Rates (Rates.php:100) | (array $payload, array $package_or_args) → payload array |
fshipping_rates_package_line_items | filter | The single aggregated “virtual package” line item (HTTP/Shipping.php:244) | (array $line_items, array $package) → requestedPackageLineItems array |
fshipping_rates_retry_on_transient_http | filter | HTTP 502/503/504 with no rates (HTTP/Shipping.php:87) | (bool true, int $status_code, array $data, array $package) → return false to skip the single retry |
fshipping_rates_transient_retry_delay_us | filter | Same retry path (HTTP/Shipping.php:88) | (int 500000) → microseconds to sleep before retry; values above 2 s are ignored |
fshipping_fedex_money_usd_line_item | filter | Money normalization of the order line item (Utils/FedExMoneyUsd.php:44) | (array $line_item, WC_Order $order, array $package) |
fshipping_residential_surcharge_amount | filter | Savings-meter estimate (Events/RuntimeIntegrator.php:113) | (float 5.95) → estimated surcharge |
Units
| Hook | Type | Fires | Args → return |
|---|---|---|---|
fshipping_fedex_weight_unit | filter | Weight-unit resolution (Utils/Helper.php:42) | (string 'KG') → KG or LB |
fshipping_fedex_measurement_system | filter | Dimension-unit resolution (Utils/Helper.php:52) | (string 'metric'|'imperial') → measurement system |
fshipping_ship_effective_units | filter | Ship payload unit selection (HTTP/Shipment.php:855) | (array $effective, WC_Order $order, array $shipment, array $context) → ['weight_unit' => 'KG'|'LB', 'dimension_unit' => 'CM'|'IN']; $context carries origin/dest country, service type, and domestic flags |
Ship payload weight floors (freight services)
FedEx Express Freight package services reject line weights below a service minimum; the plugin clamps each package line before sending (HTTP/Shipment.php:918-984).
| Hook | Default | Args → return |
|---|---|---|
fshipping_ship_freight_min_package_weight_enabled | true when the service name contains FREIGHT | (bool, string $service_type) |
fshipping_ship_freight_min_package_weight_lb | 150.01 | (float, string $service_type, array $payload) |
fshipping_ship_freight_min_package_weight_kg | 68.05 | (float, string $service_type, array $payload) |
fshipping_ship_freight_min_package_weight_skip_for_product_boxes | false (clamping applies to packed boxes too) | (bool, WC_Order $order, array $payload) → return true to keep Product Box weights untouched |
International / trade
| Hook | Type | Fires | Args → return |
|---|---|---|---|
fshipping_auto_commercial_invoice | filter | Per order, before the auto invoice is built (Trade/CommercialInvoiceBuilder.php:55) | (bool true, WC_Order $order) → false disables the auto invoice |
fshipping_invoice_purpose | filter | Invoice build (CommercialInvoiceBuilder.php:78) | (string 'SOLD', WC_Order $order) |
fshipping_invoice_terms_of_sale | filter | Invoice build (CommercialInvoiceBuilder.php:77) | (string 'DDU', WC_Order $order) |
fshipping_duties_payment_type | filter | Invoice build (CommercialInvoiceBuilder.php:99) | (string 'SENDER', WC_Order $order) — this is the switch behind Who pays import duties |
fshipping_commodity_country_of_manufacture | filter | Per commodity line (CommercialInvoiceBuilder.php:159) | (string $origin_country, array $item, WC_Order $order) → ISO country code |
fshipping_trade_documents_endpoint | filter | ETD upload URL resolution (HTTP/TradeDocuments.php:363) | (string $default, array $meta) → absolute URL |
fshipping_trade_documents_retry_singular_document_path | filter | After a multi-document upload failure (TradeDocuments.php:265) | (bool false, string $endpoint, array $decoded) → true retries the single-document path |
Open Ship (advanced mode)
Session start (HTTP/OpenShip.php:2366-2404, :671-720, :847, :1054, :246-286):
| Hook | Default | Args → return |
|---|---|---|
fshipping_openship_start_account_number | the fshipping_acc_number setting | (string $account, array $args) |
fshipping_fedex_shared_sandbox_account_number | the public FedEx sandbox test account | (string $account) — substituted during sandbox retry flows |
fshipping_openship_start_open_shipment_action | CREATE_PACKAGE | (string $action, array $args) — the openShipmentAction on create |
fshipping_openship_create_index | generated session index | (string $index, array $args) — the root index sent on create |
fshipping_openship_create_version | null | (mixed $version, array $args) |
fshipping_openship_start_payload | assembled create body | (array $payload, array $args) — final body before POST /ship/v1/openshipments/create |
fshipping_openship_start_requested_shipment | order-derived requestedShipment | (array $requested_shipment, WC_Order $order) — applied twice, before and after the minimal-payload decision |
fshipping_openship_start_strip_special_services | true | (bool, array $requested_shipment, WC_Order $order) → false keeps special services in the start body |
fshipping_openship_use_minimal_start_payload | true | (bool, array $requested_shipment, WC_Order $order) |
fshipping_openship_start_keep_full_requested_shipment | false | (bool, array $requested_shipment, WC_Order $order) — return true to send the full requestedShipment on start (OpenShip.php:717) |
fshipping_openship_ship_datestamp | computed ship date | (string $datestamp, array $requested_shipment, WC_Order $order) |
fshipping_openship_retry_start_with_doc_sandbox_account | true | (bool, array $decoded, array $args) — retry create with the shared sandbox account after a create failure |
HTTP/OpenShip.php:623-631, :1054):
| Hook | Default | Args → return |
|---|---|---|
fshipping_openship_treat_errors_as_create_success | false | (bool, array $decoded) → true treats a create response containing errors as success (session extraction continues) |
fshipping_openship_create_success_without_transaction_shipments | false | (bool, array $decoded, array $out) → true accepts a create with no transactionShipments |
fshipping_openship_create_max_attempts_on_index_error | 2 | (int, WC_Order $order, array $shipping) — retries when FedEx rejects the session index |
HTTP/OpenShip.php:1376-1406, :1458, :2145-2333; OpenShip/Draft.php:219, :797-829):
| Hook | Args → return |
|---|---|
fshipping_openship_requested_shipment | (array $requested_shipment, WC_Order $order) — session-level requestedShipment from the draft (Draft.php:219) |
fshipping_openship_package_line_item | (array $line_item, array $package, WC_Order $order) |
fshipping_openship_add_package_payload | (array $payload, string $shipment_index, array $package, string $shipment_id_index) — POST /openshipments/packages body |
fshipping_openship_modify_package_payload | same args — PUT /openshipments/packages body |
fshipping_openship_put_update_payload | (array $payload, WC_Order $order, string $shipment_index, string $shipment_id_index) — PUT /openshipments session update body |
fshipping_openship_put_update_shipment_before_packages | (bool true, WC_Order $order, array $packages, array $session) → false skips the session update before package pushes (Draft.php:797) |
fshipping_openship_use_put_modify_for_existing | (bool true, array $package, WC_Order $order, int $n) → false re-adds instead of modifying a package FedEx already knows (Draft.php:816) |
fshipping_openship_retry_add_after_modify_tracking_error | (bool true, array $put_error, array $package, WC_Order $order, int $n) (Draft.php:829) |
fshipping_openship_delete_payload | (array $payload, string $shipment_index) — session delete body |
fshipping_openship_delete_package_path_id | (string $package_id, string $shipment_index, string $shipment_id_index) — legacy hook name; maps the package id into the delete payload |
fshipping_openship_delete_tracking_id_payload | (array $tracking_id, string $tracking_number) — the trackingIds entry on package delete |
OpenShip/OpenShipPushValidator.php:29-209, HTTP/OpenShip.php:1828-1905; OpenShip/PackageLineExtras.php:130; Admin/OpenShipPackageExtrasMarkup.php:179):
| Hook | Default | Args → return |
|---|---|---|
fshipping_openship_push_validation | validator result | (array $errors, array $packages) → return the blocking-error list for the REST/order-box push |
fshipping_openship_validate_blocking_combos | true | (bool, array $special_service_types, array $package_special_services, array $extras, int $n, array $package) → false skips a blocking-combination check |
fshipping_openship_allow_group_package_count | false | (bool, array $extras, array $package, int $n) |
fshipping_openship_allow_cod_for_service_type | COD capability check | (bool $allowed, string $service_type, array $package_special_services, array $package) — legacy hook; non-bool returns are ignored |
fshipping_openship_can_use_cod | ground-like service + US destination | (bool $allowed, string $service, string $country) |
fshipping_openship_customer_reference_value_max_length | computed from the reference type | (int $length, string $type, string $service_type) |
fshipping_openship_special_service_type_options | PackageLineExtras::SPECIAL_SERVICE_TYPES | (array $options) — admin per-box special-service dropdown |
HTTP/OpenShip.php:2062-2086; OpenShip/Draft.php:501):
| Hook | Default | Args → return |
|---|---|---|
fshipping_openship_confirm_label_response_options | URL_ONLY | (string, string $shipment_index, string $shipment_id_index) |
fshipping_openship_confirm_merge_ship_document_spec | true | (bool, WC_Order $order, string $shipment_index, string $shipment_id_index) → merges the Ship-API shippingDocumentSpecification (ETD) into the confirm body |
fshipping_openship_confirm_payload | assembled confirm body | (array $payload, string $shipment_index, string $shipment_id_index, WC_Order $order) |
fshipping_openship_public_tracking_url | FedEx tracking URL | (string $url, string $tracking_number) — customer-facing tracking link format |
HTTP/OpenShip.php:435-436, :1988, :2023-2030, :2096, :2160). Note: the underlying debug-log writers are no-ops in this build — see Logging.
| Hook | Default | Args → return |
|---|---|---|
fshipping_openship_debug_log_push | FSHIPPING_OPENSHIP_LOG_PUSH, else WP_DEBUG && WP_DEBUG_LOG | (bool) → force Open Ship push logging on/off |
fshipping_openship_force_log_on_fedex_errors | true | (bool, array $decoded) |
fshipping_openship_log_create_for_order | true | (bool, array $args, array $payload, null) — create wire-JSON block for order-scoped creates |
fshipping_openship_log_exact_wire_json_before_create | false | (bool, array $args, array $payload) |
fshipping_openship_log_confirm_request_response | true | (bool, string $shipment_index, string $shipment_id_index, array $payload, array $decoded) |
fshipping_openship_log_delete_request_response | should_log_openship_push_debug() | (bool, string $shipment_index, array $payload, array $decoded, int $order_id, bool $force_audit_log) |
Other FedEx clients
| Hook | Fires | Args → return |
|---|---|---|
fshipping_pickup_max_days_ahead | Pickup date-picker bound (Ajax.php:967) | (int 2) → days ahead allowed |
fshipping_locations_payload | Locations API finder request (HTTP/Locations.php:99) | (array $payload, array $args) |
Actions
| Hook | Fired when | Args |
|---|---|---|
fshipping_aiv_event_received | Each accepted AIV webhook event (Ajax/TrackingWebhookReceiver.php:89) | (string $tracking_number, array $event) — consumed by Events\DeliveryUpdates, Events\CustomsAlerts, Events\TrackingTimelineRecorder |
fshipping_send_shipment_confirmation_mail | Instant label persisted (Utils/Shipment.php:29) | (int $post_id, array $api_data) — Schedule\Shipment turns this into the cron event |
fshipping_send_shipment_email | WP-Cron, ~5 min after an instant label (Schedule/Shipment.php:28-37) | (int $post_id, array $api_data) — handler Email\ShipmentConfirmation sends the customer email |
fshipping_calculate_shipping_start | Start of every calculate_shipping() (Frontend/Shipping.php:66) | (object $method, array $package) — consumed for staging-mode logging |
fshipping_address_classified | HTTP\AddressValidation::classify() (AddressValidation.php:84) | (array $address, string $class) — note: classify() currently has no runtime caller, so this never fires from checkout |
fshipping_freemius_loaded | After the bundled Freemius SDK instance is created (Licensing/Freemius.php:84) | (object $sdk) |
fshipping_fs_loaded | Immediately after Freemius init in the plugin bootstrap (feedex-shipping.php:131) | none — fired with no arguments |
WooCommerce core hooks the plugin uses
Not extension points, but relevant when debugging:woocommerce_shipping_methods (registers fshipping_custom), woocommerce_cart_shipping_packages at priority 99 (tags every package with fshipping_config_ver so a settings save forces one recalculation), update_option_fshipping_options (bumps fshipping_rates_config_version), wc_order_statuses (adds the two advanced-mode statuses), map_meta_cap (shipment deletion guard).
Logging
Where each hook’s output lands, and the WP_DEBUG gates.
Architecture
The classes behind these hooks and when they load.