hotchand / module-always-ship
Magento 2 module that allows out-of-stock products to be added to the cart and ordered. Compatible with Magento 2.4.x MSI (Multi-Source Inventory).
Package info
github.com/Hotchand/Magento-2-Allow-Out-of-Stock-Products-to-Be-Added-to-Cart
Type:magento2-module
pkg:composer/hotchand/module-always-ship
Requires
- php: >=8.1.0
- magento/framework: >=103.0.0
- magento/module-catalog: >=104.0.0
- magento/module-catalog-inventory: >=100.4.0
- magento/module-checkout: >=100.4.0
- magento/module-inventory-sales-api: >=1.0.0
- magento/module-quote: >=101.2.0
- magento/module-store: >=101.0.0
This package is auto-updated.
Last update: 2026-08-02 14:09:16 UTC
README
Magento 2 — Allow Out-of-Stock Products to Be Added to Cart
A Magento 2 module that removes the stock barrier at checkout, out-of-stock products can be added to the cart, purchased, and fulfilled when stock becomes available. Built for Magento 2.4.x with full MSI (Multi-Source Inventory) compatibility.
The Problem
By default, Magento 2 blocks out-of-stock products at every level:
- The "Add to Cart" button is hidden on product and category pages
- Even if a customer somehow reaches the cart, Magento rejects the add with a stock error
- The MSI layer and the legacy CatalogInventory layer both independently enforce the block
There is no native Magento way to simply say:
"Let customers buy this product now. We will ship it when stock arrives."
Enabling backorders in Magento requires editing each product individually or changing global config that affects stock calculations in unintended ways.
The Solution
Hotchand_AlwaysShip intercepts all three stock validation layers simultaneously and allows out-of-stock products to flow through the full purchase journey — from the product page to the order confirmation — without any changes to individual product records.
One toggle in the admin panel. That is all.
Features
- ✅ Add to Cart button always visible — out-of-stock products show the button on all page types (product detail, category grid, search results, related products, upsells)
- ✅ Cart add always succeeds — no stock error blocks the add-to-cart action
- ✅ Checkout always completes — order placement is not blocked by stock status
- ✅ Full MSI compatibility — intercepts all three Magento 2.4.x stock validation layers
- ✅ Product page notice — configurable "ships when in stock" message on out-of-stock product pages
- ✅ Cart page notice — configurable banner when the cart contains out-of-stock items
- ✅ Per-store-view config — different settings per website, store, or store view
- ✅ Enable / disable instantly — no product data changes, no reindex required
- ✅ No third-party dependencies — pure Magento 2 plugin implementation
- ✅ Compatible with Magento 2.4.4 through 2.4.8 and upward
How It Works
Magento 2.4.x enforces stock restrictions at three independent layers. This module intercepts all three:
Customer clicks "Add to Cart"
│
▼
┌─────────────────────────────────────────────────────────┐
│ Layer 1 — Product::isSalable() │
│ Controls button visibility on product / category pages │
│ Plugin: ProductIsSalablePlugin → always returns true │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Layer 2 — MSI IsProductSalableInterface │
│ Central MSI gate used across all of Magento 2.4.x │
│ Plugin: IsProductSalablePlugin → always returns true │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Layer 2b — MSI IsProductSalableForRequestedQtyInterface│
│ Checks whether the requested quantity is available │
│ Plugin: filters out all "not salable" results │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Layer 3 — CatalogInventory QuantityValidator │
│ Legacy validator that runs during quote/cart operations │
│ Plugin: skips validation, clears any existing errors │
└─────────────────────────────────────────────────────────┘
│
▼
✅ Product added to cart successfully
All four plugin interceptions are required. Missing any single layer will still result in a block in certain Magento 2.4.x versions or configurations.
Requirements
| Dependency | Version |
|---|---|
| PHP | 8.1 or higher |
| Magento Open Source / Adobe Commerce | 2.4.4 and above |
Magento_InventorySalesApi |
Included in Magento 2.4.x |
Magento_CatalogInventory |
Included in Magento 2.x |
Installation
Composer (Recommended)
composer require hotchand/module-always-ship php bin/magento module:enable Hotchand_AlwaysShip php bin/magento setup:upgrade php bin/magento setup:di:compile php bin/magento setup:static-content:deploy -f php bin/magento cache:flush
Manual Installation
- Create the directory
app/code/Hotchand/AlwaysShip/ - Copy all module files into that directory
- Run:
php bin/magento module:enable Hotchand_AlwaysShip php bin/magento setup:upgrade php bin/magento setup:di:compile php bin/magento setup:static-content:deploy -f php bin/magento cache:flush
Configuration
Navigate to:
Stores → Configuration → Hotchand → AlwaysShip
General Settings
| Field | Description | Default |
|---|---|---|
| Enable AlwaysShip | Master on/off switch for the entire module | No |
| Show Notice on Product Page | Show an informational message on out-of-stock product pages | Yes |
| Product Page Notice Text | The message shown on the product page | Available to order — ships when in stock. |
| Show Notice on Cart Page | Show a banner on the cart when out-of-stock items are present | Yes |
| Cart Page Notice Text | The message shown on the cart page | One or more items in your cart are currently out of stock and will ship when available. |
All fields support Default / Website / Store View scope, so you can configure AlwaysShip differently per store.
Customer-Facing Experience
Product Page (out-of-stock item)
[ Product Name ]
⚠ Available to order — ships when in stock.
[ Add to Cart ]
The notice is displayed below the stock status area. The "Add to Cart" button is fully functional.
Cart Page
⚠ One or more items in your cart are currently out of stock
and will ship when available.
┌─────────────────────────────────────────────┐
│ Product Name Qty: 1 $XX.XX │
└─────────────────────────────────────────────┘
The cart notice banner appears above the cart items table whenever the cart contains at least one out-of-stock product.
Module Structure
app/code/Hotchand/AlwaysShip/
├── registration.php
├── composer.json
├── etc/
│ ├── module.xml # Module declaration, MSI dependency sequence
│ ├── config.xml # Default configuration values
│ ├── acl.xml # Admin panel access control
│ ├── di.xml # All plugin registrations
│ └── adminhtml/
│ └── system.xml # Admin configuration form
├── Model/
│ └── Config.php # Reads admin config values
├── Plugin/
│ ├── Catalog/
│ │ └── ProductIsSalablePlugin.php # Layer 1: button visibility
│ ├── InventorySales/
│ │ ├── IsProductSalablePlugin.php # Layer 2: MSI check
│ │ └── IsProductSalableForRequestedQtyPlugin.php # Layer 2b: MSI qty check
│ └── CatalogInventory/
│ └── QuantityValidatorPlugin.php # Layer 3: legacy qty validation
├── Block/
│ ├── Product/
│ │ └── OutOfStockNotice.php # Product page notice block
│ └── Cart/
│ └── OutOfStockNotice.php # Cart page notice block
└── view/frontend/
├── layout/
│ ├── catalog_product_view.xml # Injects notice on product page
│ └── checkout_cart_index.xml # Injects notice on cart page
└── templates/
├── product/
│ └── out-of-stock-notice.phtml
└── cart/
└── out-of-stock-notice.phtml
Important Considerations
Stock Levels Are Not Modified
AlwaysShip does not change your product stock quantities, backorder settings, or any inventory data. It only bypasses the stock validation gates. Your actual stock levels in the Magento admin remain unchanged.
Orders Will Show as Out of Stock Internally
When an out-of-stock product is ordered through AlwaysShip, Magento's internal stock deduction will attempt to run as normal. The product will remain at 0 (or negative if backorders are configured). You will need to manage fulfillment and stock replenishment manually or through your ERP/WMS.
Combine With a Backorder Notification Workflow
For the best customer experience, consider pairing AlwaysShip with an email notification workflow that alerts customers when their backordered item ships. Magento's built-in order shipment email handles this automatically once you create a shipment for the order.
Not a Substitute for Proper Inventory Management
AlwaysShip is designed for stores that actively manage their backorder fulfilment — such as B2B hardware resellers, specialty retailers, and made-to-order merchants. It is not intended for stores that should never sell beyond available stock.
Troubleshooting
"Add to Cart" button still not appearing
- Confirm the module is enabled in admin config and cache is flushed
- Run
php bin/magento setup:di:compile— the plugin interceptors require DI compilation - Clear generated code:
rm -rf generated/code/Hotchandthen recompile - Check if another module is overriding
Product::isSalable()with higher plugin priority
Product can be added to cart but order fails at checkout
This usually means a payment method or order management plugin is performing an additional stock check. Check your system logs at var/log/system.log for the specific exception. A custom shipping or payment module may need its own stock bypass.
Notice not appearing on product page
- Confirm Show Notice on Product Page is set to Yes in admin config
- Verify the product is actually out of stock in
Catalog → Products - Check if your theme overrides the
product.info.maincontainer — the block is injected there
Module conflicts with another inventory extension
If you have a third-party inventory extension (e.g. Amasty Multi Inventory, Mageworx Inventory, etc.), their plugins may re-apply stock checks after ours. Set the sortOrder of our plugins in di.xml to a high number (e.g. sortOrder="9999") to ensure our plugins run last:
<plugin name="hotchand_alwaysship_product_is_salable" type="Hotchand\AlwaysShip\Plugin\Catalog\ProductIsSalablePlugin" sortOrder="9999"/>
Frequently Asked Questions
Does enabling AlwaysShip affect in-stock products? No. The plugins check the result of the original stock validation and only override when a product would otherwise be blocked. In-stock products are not affected.
Will this work with configurable products?
Yes. The isSalable() check applies to all product types. However, if all child simple products of a configurable are out of stock, Magento may still hide the swatch/option selector. This is controlled by a separate layer in the configurable product type model. A future version will address this.
Does AlwaysShip affect the stock status shown in the admin? No. Admin stock status, inventory levels, and reports are not touched. Only the customer-facing validation is bypassed.
Can I enable this for specific products or categories only? The current version applies globally when enabled. Per-product or per-category control is on the roadmap for a future release.
What happens to the customer's order if we never restock the item? The order is created normally in Magento. You will need to manage this through your standard order management process — either fulfilling when stock arrives, cancelling the order, or refunding through Magento's order management tools.
Is this compatible with Magento B2B / Adobe Commerce? Yes. The module uses standard Magento plugin interception which works identically on both Magento Open Source and Adobe Commerce (B2B edition).
Will this affect inventory reservations in MSI?
Magento's MSI creates a reservation when an order is placed. With AlwaysShip, the reservation will still be created, which may push your stock into negative territory (showing e.g. -3 in stock). This is expected and normal for backorder scenarios.
Roadmap
- Per-product enable/disable attribute
- Per-category enable/disable
- Configurable product child option display fix
- Admin order grid column indicating AlwaysShip orders
- Backorder notification email template
Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch:
git checkout -b feature/my-feature - Commit your changes:
git commit -m 'Add my feature' - Push to the branch:
git push origin feature/my-feature - Open a Pull Request
License
Author
Hotchand Sajnani Senior PHP / Magento Engineer ConnectResale LLC
Related Modules
- Hotchand_CspManager — Manage CSP whitelists from the Magento admin panel
- Hotchand_FreeShippingWeightLimit — Free shipping up to a weight limit with flat rate fallback
Changelog
1.0.0 — 2026-01-01
- Initial release
- Three-layer MSI + CatalogInventory stock bypass
- Add to Cart button always visible for out-of-stock products
- Configurable product page notice
- Configurable cart page notice
- Per-store-view configuration support
- Magento 2.4.4 – 2.4.8+ compatibility