How to get customer id from block when full page cache enable in magento 2

Today I discuss about getting customer_id from block when full page cache(FPC) is enable. If FPC is enable then you can’t get customer id from block just because magento2 reset all customer session. You can get customer session data if your layout set cacheable=”false” in that case magento2 just ignore cache whole page. How? lets dive.

If you open vendor/magento/module-customer/Model/Layout/DepersonalizePlugin.php


/**
 * After generate Xml
 *
 * @param \Magento\Framework\View\LayoutInterface $subject
 * @param \Magento\Framework\View\LayoutInterface $result
 * @return \Magento\Framework\View\LayoutInterface
 */
public function afterGenerateXml(\Magento\Framework\View\LayoutInterface $subject, $result)
{
    if ($this->depersonalizeChecker->checkIfDepersonalize($subject)) {
        $this->visitor->setSkipRequestLogging(true);
        $this->visitor->unsetData();
        $this->session->clearStorage();
        $this->customerSession->clearStorage();
        $this->session->setData(\Magento\Framework\Data\Form\FormKey::FORM_KEY, $this->formKey);
        $this->customerSession->setCustomerGroupId($this->customerGroupId);
        $this->customerSession->setCustomer($this->customerFactory->create()->setGroupId($this->customerGroupId));
    }
    return $result;
}

Now check the if condition, basically this return true/false from following function
vendor/magento/module-page-cache/Model/DepersonalizeChecker.php


/**
 * Check if depersonalize or not
 *
 * @param \Magento\Framework\View\LayoutInterface $subject
 * @return bool
 * @api
 */
public function checkIfDepersonalize(\Magento\Framework\View\LayoutInterface $subject)
{
    return ($this->moduleManager->isEnabled('Magento_PageCache')
        && $this->cacheConfig->isEnabled()
        && !$this->request->isAjax()
        && ($this->request->isGet() || $this->request->isHead())
        && $subject->isCacheable());
}

Here $subject->isCacheable() return false if your layout has ‘cacheable=”false”‘ attribute, lets check
vendor/magento/framework/View/Layout.php


/**
 * Check is exists non-cacheable layout elements
 *
 * @return bool
 */
public function isCacheable()
{
    $this->build();
    $cacheableXml = !(bool)count($this->getXml()->xpath('//' . Element::TYPE_BLOCK . '[@cacheable="false"]'));
    return $this->cacheable && $cacheableXml;
}

So if full page cahce enable and cacheable=”false” is not exist then magento 2 reset customer session by


$this->session->clearStorage();
$this->customerSession->clearStorage();

That’s why if you try to get customer session data from block, it’s return always empty basically only group_id is present in customer session data.

So how to get customer information then.

You can follow Magento2 official tutorial.

Now Today I discuss how you can get customer_id if cache enable. Lets dive.

Suppose vendor name ‘SR‘ and module name ‘CustomerSession

Create a contex class [SR/CustomerSession/Model/Customer/Context.php]


namespace SR\CustomerSession\Model\Customer;

class Context
{
    /**
     * Customer authorization cache context
     */
    const CONTEXT_CUSTOMER_ID = 'logged_in_customer_id';
}

Now pluginize Magento\Framework\App\Action\AbstractAction dispatch method.
So create a di.xml [SR/CustomerSession/etc/frontend/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\Framework\App\Action\AbstractAction">
        <plugin name="sr-customer-app-action-dispatchController-context-plugin" type="SR\CustomerSession\Plugin\App\Action\Context" sortOrder="15"/>
    </type>
</config>

Now create SR/CustomerSession/Plugin/App/Action/Context.php


namespace SR\CustomerSession\Plugin\App\Action;

use SR\CustomerSession\Model\Customer\Context as CustomerSessionContext;

class Context
{
    /**
     * @var \Magento\Customer\Model\Session
     */
    protected $customerSession;

    /**
     * @var \Magento\Framework\App\Http\Context
     */
    protected $httpContext;

    /**
     * @param \Magento\Customer\Model\Session $customerSession
     * @param \Magento\Framework\App\Http\Context $httpContext
     */
    public function __construct(
        \Magento\Customer\Model\Session $customerSession,
        \Magento\Framework\App\Http\Context $httpContext
    ) {
        $this->customerSession = $customerSession;
        $this->httpContext = $httpContext;
    }

    /**
     * @param \Magento\Framework\App\ActionInterface $subject
     * @param callable $proceed
     * @param \Magento\Framework\App\RequestInterface $request
     * @return mixed
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function aroundDispatch(
        \Magento\Framework\App\ActionInterface $subject,
        \Closure $proceed,
        \Magento\Framework\App\RequestInterface $request
    ) {
        $customerId = $this->customerSession->getCustomerId();
        if(!$customerId) {
            $customerId = 0;
        }

        $this->httpContext->setValue(
            CustomerSessionContext::CONTEXT_CUSTOMER_ID,
            $customerId,
            false
        );

        return $proceed($request);
    }
}

That’s it. Now you can able to get customer id following way even cache enable:


/**
* @var \Magento\Framework\App\Http\Context
*/
$this->httpContext->getValue(SR\CustomerSession\Model\Customer\Context::CONTEXT_CUSTOMER_ID);

Download full module from here

6 thoughts on “How to get customer id from block when full page cache enable in magento 2

  1. Hi Sohel,

    Thanks! This works great we have implemented this in our pricing module. Can you think of any disadvantage by implementing this method to get customer session data?

    Kind regards

    Erica

    1. Hi Erica,

      You can use it in your module without any doubt. It’s great solution over FPC and Varnish cache.

      Thanks!
      Sohel Rana

  2. Hi Sohel,
    I was thinking about the same solution, however it’s causing interesting and unexpected effect – as result you are getting personalized page cache, here is why – when FPC module is deciding to generate cache or to take existing one, it’s taking a key for cache (vendor/magento/framework/App/PageCache/Identifier.php:46 in getValue() ), that is basing on Vary String, and the Vary String contains all data from httpContext in its turn.
    With this customization you’ll get different Vary String for each customer, and cache for each customer is generated separately

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.