Magento 1 Tutorials Automatically Set the Shipping Method in Magento 2

First Published: March 30, 2021

There's tons of article showing how to do this already but none of them worked for me and missed out a key line. The below code will automatically set the country ID and then set the first shipping method generated (which will be the most applicable based on the shipping rules).

You'll need to create your own module for this and setup the below file as a plugin on the \Magento\Checkout\Controller\Cart object.

<?php
/**
 *
 */
namespace FishPig\Delivery\Plugin\Magento\Checkout\Controller;

use Magento\Checkout\Controller\Cart;
use Magento\Shipping\Model\Config as ShippingConfig;

class CartPlugin
{
    /**
     *
     */
    public function __construct(
        \Magento\Checkout\Model\Session $checkoutSession,
        \Magento\Quote\Model\ShippingMethodManagement $shippingMethodManager,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
    ) {
        $this->checkoutSession = $checkoutSession;
        $this->shippingMethodManager = $shippingMethodManager;
        $this->scopeConfig = $scopeConfig;
    }
    
    /**
     *
     */
    public function beforeExecute(Cart $subject)
    {
        if (!($countryId = $this->getDefaultCountryId())) {
            // No country ID set so we cannot generate shipping method automatically
            return [];
        }

        $quote = $this->checkoutSession->getQuote();

        if (!$quote->getId()) {
            return [];
        }

        $shippingAddress = $quote->getShippingAddress();
        
        if ($shippingAddress->getShippingMethod()) {
            return [];
        }
        
        $shippingAddress->setCollectShippingRates(true)
            ->setCountryId($countryId);
        
        $shippingMethods = $this->shippingMethodManager->getList($quote->getId());
        
        if ($shippingMethods && count($shippingMethods) > 0) {
            $shippingMethod = array_shift($shippingMethods);

            $this->shippingMethodManager->set(
                $quote->getId(),
                $shippingMethod->getCarrierCode(),
                $shippingMethod->getMethodCode()
            );
            
            $quote->save();
        }

        return [];
    }
    
    /**
     * This is taken from the origin so change this if you don't want to use the origin
     * If this returns false then the auto shipping method is not set
     *
     * @return string
     */
    private function getDefaultCountryId()
    {
        return $this->scopeConfig->getValue(
            ShippingConfig::XML_PATH_ORIGIN_COUNTRY_ID
        ); 
    }
}