7

My requirement is that if a customer visits website from country India they should be redirected to indian website www.example.com/in/ . In all other cases it should be default website only.

I'm using geoip PHP library. I've used frontend event controller_action_predispatch and here is my observer code:

namespace Amit\Geoip\Observer;
require_once 'lib/geoip.inc';
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Controller\ResultFactory;
use Magento\Store\Model\StoreManager;

class ControllerActionPredispatch implements  ObserverInterface {

    protected $resultRedirectFactory;

    public function __construct(
        ResultFactory $resultFactory,
        StoreManager $storeManager
    )  {
        $this->resultFactory = $resultFactory;
        $this->storeManager = $storeManager;
    }

    public function execute(\Magento\Framework\Event\Observer $observer) {
        $baseUrl = $this->storeManager->getStore()->getBaseUrl();
        $gi = geoip_open(getcwd()."/app/code/Amit/Geoip/Observer/lib/GeoIP.dat",GEOIP_STANDARD);
        $ip = $_SERVER['REMOTE_ADDR'];

        $country_code = geoip_country_code_by_addr($gi, $ip);

        if((strtoupper($country_code) == "IN")){
            $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
            $resultRedirect->setUrl($baseUrl . '/in/' . $_SERVER['REQUEST_URI']);
        }
    }
}

Problems:

  1. My observer function is being executed and I'm getting customers country from their IP but it is not re-directing to website www.example.com/in/*. What is the proper way to re-direct to my custom url?
  2. I think event controller_action_predispatch will call observer function on every page customer visits. Which event I should use so that it will be executed only for the first time customer visits the website?
  3. I see one of the possible options is setting cookie for it but I'm not sure where I should set cookie in my module (events? which event?) and which process I should follow to re-direct them.
1
  • This snippet of code will slow down the store. Cache country_code in PHP session. And if the store has Varnish it won't work at all. Aug 18, 2016 at 21:22

4 Answers 4

5
+100

There are multiple approaches how you can do this without editing magento code (webserver level, for example). These approaches might be more efficient.

But if you want to do it with magento, your $resultRedirect should be returned to App\Http. Your observer does not return $resultRedirect, so it is not processed by \Magento\Framework\App\Http::launch and redirect does not happen. Since you want your redirect logic to happen as early as possible, but only in storefront (is that right?) instead of observer you should put an around-plugin on \Magento\Framework\App\FrontControllerInterface::dispatch because it's the first method that gets called in \Magento\Framework\App\Http::launch after area is defined and returns ResultInterface. From that plugin you will be able to return your $resultRedirect object:

namespace My\Module\App\FrontController;

class Plugin
{
    // Constructor and dependencies here

    public function aroundDispatch(
        FrontControllerInterface $subject,
        callable $proceed,
        RequestInterface $request
    ) {
            $baseUrl = $this->storeManager->getStore()->getBaseUrl();
            $gi = geoip_open(getcwd()."/app/code/Amit/Geoip/Observer/lib/GeoIP.dat",GEOIP_STANDARD);
            $ip = $_SERVER['REMOTE_ADDR'];

            $country_code = geoip_country_code_by_addr($gi, $ip);

            if((strtoupper($country_code) == "IN")){
                $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT);
                $resultRedirect->setUrl($baseUrl . '/in/' . $_SERVER['REQUEST_URI']);
                return $resultRedirect;
            } else {
                return $proceed($request);
            }
    }
}

As for doing it only for first customer, cookie presence check looks like a viable option.

1
  • I've developed module using plugin concept. I'm having one issue there. india is being added multiple times in-between base url and requested URI. The re-direct URL is being generated something like example.com/india/india/india/.../aboutus. Why india is being added multiple times in between base-url and requested-uri ? github.com/amitshree/magento2-website-switcher/blob/master/app/…
    – amitshree
    Mar 4, 2016 at 12:18
2

These are the steps to do:

1. Redirects can be done in the following way: $observer->getControllerAction()->getResponse()>setRedirect($redirectUrl);

2. The best solution, perhaps, will be to use the controller_action_predispatch (as there are unfortunately no other, more suitable events).

3. In the same observer you can also set up some cookies ( e.g. "geoip_country_code") that will be processed by the controller_action_predispatch.

But note that in case you decide to go this way, you'll have to check customer cookies every time before the redirect.

2
  • Thanks. I was looking for the possible ways. Please let me know if there is a way better than this if you've implemented or have a reference tutorial/document. I'm ready to re-work on it if there are better ways.
    – amitshree
    Feb 5, 2016 at 6:22
  • I dont have access to a setRedirect redirect in my $observer object
    – kevando
    Mar 28, 2016 at 20:53
0

Here is what I did (remember to set the action flag):

/**
 * @var \Magento\Framework\App\Response\RedirectInterface
 */
protected $redirect;

/**
 * @var \Magento\Framework\App\ActionFlag
 */
protected $actionFlag;

public function __construct
(
    \Magento\Framework\App\Response\RedirectInterface $redirect,
    \Magento\Framework\App\ActionFlag $actionFlag
)
{
    $this->redirect = $redirect;
    $this->actionFlag = $actionFlag;
}

public function execute(\Magento\Framework\Event\Observer $observer)
{
     /** @var \Magento\Framework\App\Action\Action $controller */
    $controller = $observer->getControllerAction();

    $this->actionFlag->set('', \Magento\Framework\App\Action\Action::FLAG_NO_DISPATCH, true);
    $this->redirect->redirect($controller->getResponse(), 'my/custom/url');
}

Update:

For magento 2.1.5 do the following

/**
 * @param Observer $observer
 * @return void
 */
public function execute(\Magento\Framework\Event\Observer $observer)
{
    $event = $observer->getEvent();
    $this->redirect->redirect($event->getResponse(), 'my/custom/url');
}
0

Anton Kril wrote good example but $resultRedirect should has type \Magento\Framework\App\Response\Http . Here example from my code:

class RedirectPlugin {
protected $subDomainsPrefix = [
    'CA' => '',
    'US' => 'us',
    'UK' => 'uk',
    'EU' => 'eu',
    'AU' => 'au'
];

protected $_responseFactory;

/**
 * @var \Magento\Framework\App\Config\ScopeConfigInterface
 */
protected $_scopeConfig;

/**
 * @var \Magento\Store\Model\StoreManager
 */
protected $_storeManager;

public function __construct(
    \Magento\Store\Model\StoreManager $storeManager,
    \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
    \Magento\Framework\App\Response\HttpFactory $httpFactory
) {
    $this->_storeManager    = $storeManager;
    $this->_scopeConfig     = $scopeConfig;
    $this->_responseFactory = $httpFactory;
}

/**
 * Redirect to subdomain by country code
 *
 * @param \Magento\Framework\App\FrontControllerInterface $subject
 * @param \Closure                                        $proceed
 * @param \Magento\Framework\App\RequestInterface         $request
 *
 * @return mixed
 */
public function aroundDispatch(
    \Magento\Framework\App\FrontControllerInterface $subject,
    \Closure $proceed,
    \Magento\Framework\App\RequestInterface $request
) {
    $baseUrl = $this->_storeManager->getStore()->getBaseUrl();
    if (isset($_SERVER['GEOIP_COUNTRY_CODE']) && isset($this->subDomainsPrefix[$_SERVER['GEOIP_COUNTRY_CODE']])) {
        $prefix      = $this->subDomainsPrefix[$_SERVER['GEOIP_COUNTRY_CODE']];
        $mainBaseUrl = $this->_scopeConfig->getValue('web/unsecure/base_url');
        $parts       = explode('.', str_replace('://', '.', $baseUrl));
        $subDomain   = $parts[1];
        if ($subDomain == $prefix || ($prefix == '' && strrpos($subDomain, 'carnivore') !== false)) {
            return $proceed($request);
        } else {
            $subDomain = str_replace('://', '://' . $prefix . '.', $mainBaseUrl);
            /**
             * @var \Magento\Framework\App\Response\Http $response
             */
            $response  = $this->_responseFactory->create();
            $response->setRedirect($subDomain);

            return $response;
        }
    } else {
        return $proceed($request);
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.