12

I charge my customers flat rate for shipping and I also offer free shipping for orders that are above certain amount. At the moment, customers who qualify for free shipping will also have paid shipping option shown, which may confuse some customers. Does anyone know if there's a way to hide other shipping methods when free shipping method is available?

8 Answers 8

6

I had the same problem.

Remove "Free Shipping" configuration because you don't need it (you already have "Cart Price Rules").

When your customer qualifies for free shipping it happens based on "Flat Rate" not in "Free Shipping".

9

Use the extension ShippingTweaks.

1
  • Hi @vitalli is this module will help me to hide shipping methods based on my product attribute? Commented Feb 18, 2020 at 10:54
6

Write a plugin to disable flat rate shipping method when free shipping is actually enabled based on cart sub total.

<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <type name="Magento\OfflineShipping\Model\Carrier\Flatrate"> <plugin name="disable-flatrate" type="Vendor\ModuleName\Model\Carrier\Flatrate" sortOrder="1" /> </type> </config> 

Write a Model class to process sub total validation.

<?php namespace Vendor\ModuleName\Model\Carrier; class Flatrate { const XML_PATH_FREE_SHIPPING_SUBTOTAL = "carriers/freeshipping/free_shipping_subtotal"; /** * @var \Magento\Checkout\Model\Session */ protected $_checkoutSession; /** * @var \Magento\Framework\App\Config\ScopeConfigInterface */ protected $_scopeConfig; public function __construct( \Magento\Checkout\Model\Session $checkoutSession, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Store\Model\StoreManagerInterface $storeManager ) { $this->_storeManager = $storeManager; $this->_checkoutSession = $checkoutSession; $this->_scopeConfig = $scopeConfig; } public function afterCollectRates(\Magento\OfflineShipping\Model\Carrier\Flatrate $flatRate, $result) { $scopeId = $this->_storeManager->getStore()->getId(); $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORES; // Get MOA value from system configuration. $freeShippingSubTotal = $this->_scopeConfig->getValue(self::XML_PATH_FREE_SHIPPING_SUBTOTAL, $storeScope, $scopeId); // Get cart subtotal from checkout session. $baseSubTotal = $this->_checkoutSession->getQuote()->getBaseSubtotal(); // Validate subtoal should be empty or Zero. if(!empty($baseSubTotal) && !empty($freeShippingSubTotal)) { if($baseSubTotal >= $freeShippingSubTotal) { return false; } } return $result; } } 
4
  • 1
    hi @maniprakash where i need to create di.xml ? Commented Oct 30, 2018 at 11:36
  • 2
    Romba nandri its working fine. Commented Oct 30, 2018 at 13:26
  • 1
    how to hide shipping methods based on product / cart item attribute? Commented Feb 18, 2020 at 10:56
  • can u help me on this magento.stackexchange.com/questions/327438/… Commented Dec 7, 2020 at 12:42
4

etc/di.xml

<type name="Magento\Quote\Model\ShippingMethodManagement"> <plugin name="vendor_module_plugin_model_quote_shipping_method_management" type="Vendor\Module\Plugin\Model\ShippingMethodManagement" disabled="false"/> </type> 

Plugin/Model/ShippingMethodManagement.php

public function afterEstimateByAddress($shippingMethodManagement, $output) { return $this->filterOutput($output); } public function afterEstimateByExtendedAddress($shippingMethodManagement, $output) { return $this->filterOutput($output); } public function afterEstimateByAddressId($shippingMethodManagement, $output) { return $this->filterOutput($output); } private function filterOutput($output) { $free = []; foreach ($output as $shippingMethod) { if ($shippingMethod->getCarrierCode() == 'freeshipping' && $shippingMethod->getMethodCode() == 'freeshipping') { $free[] = $shippingMethod; } } if ($free) { return $free; } return $output; } 
1
1

in response to @Nagaraju and hoping to help to anyone.

The di.xml can be created in any module you have, or if you dont know how and where:

app/code/My_Vendor/MyModule/etc/di.xml -> here is where you put the code of @maniprakash

then you should create the class in:

app/code/My_Vendor/MyModule/Model/Flatrate -> and paste the class code of @maniprakash

Just remember to change the path in type tag on the di.xml

<plugin name="disable-flatrate" type="Vendor\ModuleName\Model\Carrier\Flatrate" sortOrder="1" /> 

the path must match where your Model class is it. in my example should be

<plugin name="disable-flatrate" type="My_Vendor\MyModule\Model\Flatrate" sortOrder="1" /> 

AND that's it! hope it helps! and thanks to @manipakrash , it helps me! =)

0

Hide free shipping on checkout

Vendor/magento/Magento_Checkout/template/shipping-address/shipping-method-item.html

<!-- ko if: method.carrier_code !== 'freeshipping' --> <tr class="row" click="element.selectShippingMethod"> <td class="col col-method"> <input type="radio" class="radio" ifnot="method.error_message" ko-checked="element.isSelected" ko-value="method.carrier_code + '_' + method.method_code" attr="'aria-labelledby': 'label_method_' + method.method_code + '_' + method.carrier_code + ' ' + 'label_carrier_' + method.method_code + '_' + method.carrier_code, 'checked': element.rates().length == 1 || element.isSelected" /> <span class="label"></span> </td> <td class="col col-price"> <each args="element.getRegion('price')" render="" /> </td> <td class="col col-carrier" attr="'id': 'label_carrier_' + method.method_code + '_' + method.carrier_code" text="method.carrier_title" /> 

0

Vendor\Module\etc\di.xml

<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <type name="Magento\OfflineShipping\Model\Carrier\Flatrate"> <plugin name="disable-flaterate" type="Vendor\Module\Model\Carrier\Flatrate" /> </type> </config> 

Vendor\Module\Model\Carrier\Flatrate.php

<?php namespace Vendor\Module\Model\Carrier; class Flatrate{ protected $_scopeConfig; protected $_customerSession; public function __construct( \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\OfflineShipping\Model\Carrier\Tablerate $tablerate, \Magento\Customer\Model\Session $customerSession ) { $this->_storeManager = $storeManager; $this->_scopeConfig = $scopeConfig; $this->tablerate = $tablerate; $this->_customerSession = $customerSession; } public function afterCollectRates(\Magento\OfflineShipping\Model\Carrier\Flatrate $Flatrate, $result, $request) { $regionId = ''; if($request && $request->getDestRegionId()) { $regionId = $request->getDestRegionId(); } $resTableRate = $this->tablerate->collectRates($request); foreach ($resTableRate->getAllRates() as $rate) { if ($rate->getMethod()) { return false; } } $base_subtotal_incl_tax = $request->getData('base_subtotal_incl_tax'); if($base_subtotal_incl_tax > 50) { return false; } $items = $request->getAllItems(); foreach ($items as $key => $item) { $sku = $item->getSku(); } return $result; } } 
0

The most voted approach by @maniprakash-chinnasamy will work fine, except for some edge cases, which may unfortunately break your website entirely. The issue lies with the method of obtaining the quote.

The quote should not be retrieved from the CheckoutSession because it can initiate an infinite loop. Instead, use an approach like this:

  1. Add \Magento\Quote\Model\Quote\Address\RateRequest as an argument to the afterCollectRatesMethod().
  2. Add a getQuote private method.
  3. Refactor how the quote is obtained in the afterCollectRates method body as shown below.
public function afterCollectRates( \Magento\OfflineShipping\Model\Carrier\Flatrate $flatRate, $result, \Magento\Quote\Model\Quote\Address\RateRequest $rateRequest ) { // ... $quote = $this->getQuote($rateRequest); if ($quote === null) { return $result; } $baseSubTotal = $quote->getBaseSubtotal(); // ... } // This method retrieves the Quote from the RateRequest private function getQuote(RateRequest $rateRequest): ?Quote { $quote = null; // It is necessary to obtain a quote instance using this method to prevent an infinite loop in the CheckoutSession. foreach ($rateRequest->getAllItems() as $item) { if ($item->getQuote() instanceof Quote) { $quote = $item->getQuote(); break; } } return $quote; } 

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.