If a customer types a PO Box (or APO/FPO/DPO) as the shipping address, UPS and FedEx won't deliver. The cleanest fix is to automatically hide all non-USPS rates whenever a PO Box is detected. You can do this with a tiny, safe, copy-paste "must-use" plugin — no paid plugins required.
Why This Matters
- USPS delivers to PO Boxes.
- UPS/FedEx do not — you'll get delivery failures, manual re-shipments, or angry emails.
- Many stores leave all carriers visible, which confuses customers and creates support headaches.
The goal: If PO Box → only show USPS. Easy for the customer, safe for you.
Do You Need This?
Check these quick signs:
- You see orders with "PO Box" in the shipping address.
- You've had delivery failures because a non-USPS service was chosen for a PO Box.
- You want to prevent mistakes instead of catching them after the label prints.
If that's you, keep reading — this takes 5 minutes.
The Fast, Free Solution (No Coding Skills Required)
We'll add a tiny "must-use" (MU) plugin. MU plugins are just PHP files you drop into a folder — no settings screen, no updates to break it, and you can delete it anytime.
Step 1 — Open your site files
Go to your hosting File Manager (or SFTP) and navigate to: wp-content/
Step 2 — Create the MU plugins folder (if it doesn't exist)
Create a folder named: mu-plugins
Step 3 — Create a new file
Inside mu-plugins, create ccms-po-box-filter.php
Step 4 — Copy-paste this code and save
<?php
/**
* Plugin Name: CCMS – PO Box filter (USPS-only)
* Description: If the ship-to address is a PO Box (incl. APO/FPO/DPO), remove all non-USPS rates.
* Version: 1.0.0
* Author: CCMS
*/
add_filter('woocommerce_package_rates', function ($rates, $package) {
$is_po_box = (function(array $dest): bool {
$fields = [];
foreach (['address_1','address_2','company'] as $k) {
if (!empty($dest[$k])) $fields[] = (string)$dest[$k];
}
if (!$fields) return false;
$hay = strtolower(trim(preg_replace('/\s+/', ' ', implode(' ', $fields))));
$norm = preg_replace('/[\.#,\-]/', ' ', $hay);
$norm = preg_replace('/\s+/', ' ', $norm);
$patterns = [
'/\b(p\s*\.?\s*o\s*\.?\s*|po\s+|p\s+o\s+)(box|bx)\b/i',
'/\bpost\s+office\s+box\b/i',
'/\b(p\s*\.?\s*o\s*\.?\s*b(?:ox)?)\b/i',
'/\b(apo|fpo|dpo)\b/i',
];
foreach ($patterns as $rx) {
if (preg_match($rx, $norm)) return true;
}
return false;
})($package['destination'] ?? []);
if (!$is_po_box) return $rates;
foreach ($rates as $id => $rate) {
$label = method_exists($rate,'get_label') ? $rate->get_label() : ($rate->label ?? '');
$lab = strtolower((string)$label);
$is_usps = (strpos($lab,'usps') !== false) || (strpos($lab,'stamps.com') !== false);
if (!$is_usps) { unset($rates[$id]); continue; }
}
return $rates;
}, 1200, 2);
That's it. When a PO Box is present, checkout will show USPS-only. For normal addresses, nothing changes.
How to Test
- Go to checkout and use a test address: Address 1: P.O. Box 123
- Check the shipping methods: only USPS should show.
- Switch Address 1 to a normal street (e.g., 123 Main St) and re-calculate: UPS/FedEx should reappear.
If something looks off, just delete the file — everything goes back to normal.
FAQs
Will this break APO/FPO/DPO military addresses?
No — those are treated like PO Boxes and will see USPS-only options, which is correct.
What about hybrid services (like "Ground Saver" / "SmartPost")?
Those aren't reliable for PO Boxes in standard Woo setups. Hiding non-USPS across the board for PO Boxes is the safest choice.
Can I undo this easily?
Yes. Delete ccms-po-box-filter.php from mu-plugins.
Will this conflict with my other shipping rules?
No. The filter runs after most rules (priority 1200) and only removes non-USPS when a PO Box is detected.