meanbee / magento2-infinitescroll

A Magento 2 extension for infinitely scrolling catalog pages

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add to Cart button does not redirect back to the listing page

tgerulaitis opened this issue · comments

In Magento 2.2.

Steps to reproduce:

  1. Open a category or search page
  2. Click the "View More" button at the bottom
  3. Click the "Add to Cart" button on one of the newly loaded products

Expected outcome:
Product added to basket, redirected back to the category/search page.

Actual outcome:
The raw output of the Ajax data fetch for the latest page of products is shown.

It seems that Magento uses the current URL as the redirect point when building the product add to cart URL. We need to change this to referrer or something similar, without breaking add to carts for products initially loaded with the page.

From 5c95cc32ffe70c6ebd442ad4693c67957c2ebf22 Mon Sep 17 00:00:00 2001
From: Nick Jones <nick@space48.com>
Date: Wed, 21 Feb 2018 16:16:35 +0000
Subject: [PATCH] Use a header to signal to Magento we're performing an
 ajax request

If we use ?ajax=true to signal an ajax request then we'll end up with
an add to cart link that, because the referrer contained the ?ajax=true
param, redirects the user back to a page with the category information
as a JSON object, instead of HTML.

Instead, use the X-Requested-With header to indicate that it was an
ajax request.
---
 .../view/frontend/web/js/view/product_list.js           | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/app/code/Meanbee/InfiniteScroll/view/frontend/web/js/view/product_list.js b/app/code/Meanbee/InfiniteScroll/view/frontend/web/js/view/product_list.js
index 257d697..0bcd6bd 100755
--- a/app/code/Meanbee/InfiniteScroll/view/frontend/web/js/view/product_list.js
+++ b/app/code/Meanbee/InfiniteScroll/view/frontend/web/js/view/product_list.js
@@ -13,7 +13,6 @@ define([
         },
 
         pageParam: 'p',
-        ajaxParam: 'ajax',
 
         initialize: function () {
             this._super();
@@ -33,7 +32,14 @@ define([
 
             this.state.isFetching(true);
 
-            fetch(this._getFetchUrl(true))
+            let fetchOptions = {
+                headers: {
+                    // Signals to Magento that this was an ajax request.
+                    'X-Requested-With': 'XMLHttpRequest'
+                }
+            };
+
+            fetch(this._getFetchUrl(true), fetchOptions)
                 .then(function (response) { return response.json(); })
                 .then(this._updateState.bind(this))
                 .then((function () { this._updateHistory(this._getFetchUrl(false)) }).bind(this));
@@ -42,20 +48,15 @@ define([
         /**
          * Get the URL for fetching additional products.
          *
-         * @param is_ajax
          * @return string
          * @private
          */
-        _getFetchUrl: function (is_ajax) {
+        _getFetchUrl: function () {
             const url = new URL(window.location);
             const currentPage = parseInt(url.searchParams.get(this.pageParam) || 1);
 
             url.searchParams.set(this.pageParam, currentPage + 1);
 
-            if (is_ajax) {
-                url.searchParams.set(this.ajaxParam, "true");
-            }
-
             return url.href;
         },
 
-- 
2.16.1

The problem with the above patch is that Varnish probably doesn't factor in the X-Requested-With header when running it's vcl_hash, meaning that /test.html?p=2 with and without the header will look the same. This means that returning from the add to cart will show you JSON still.

I've had to go with reading the various uencs in the cart post params and removing the parameter manually :(

From c095b329645e43c61e0fdbfa1e59d143fa49e756 Mon Sep 17 00:00:00 2001
From: Nick Jones <nick@space48.com>
Date: Fri, 23 Feb 2018 17:09:44 +0000
Subject: [PATCH] Strip any reference to ajax when generating add to cart
 parameters

---
 app/code/Meanbee/InfiniteScroll/Helper/Uenc.php    | 89 ++++++++++++++++++++++
 .../frontend/templates/product/list_json.phtml     |  5 +-
 2 files changed, 93 insertions(+), 1 deletion(-)
 create mode 100644 app/code/Meanbee/InfiniteScroll/Helper/Uenc.php

diff --git a/app/code/Meanbee/InfiniteScroll/Helper/Uenc.php b/app/code/Meanbee/InfiniteScroll/Helper/Uenc.php
new file mode 100644
index 0000000..9f2cafb
--- /dev/null
+++ b/app/code/Meanbee/InfiniteScroll/Helper/Uenc.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace Meanbee\InfiniteScroll\Helper;
+
+use Magento\Framework\App\Helper\Context;
+use Magento\Framework\Url\Helper\Data as UrlHelper;
+
+class Uenc extends \Magento\Framework\App\Helper\AbstractHelper
+{
+    /**
+     * @var UrlHelper
+     */
+    private $urlHelper;
+
+    /**
+     * @param Context $context
+     * @param UrlHelper $urlHelper
+     */
+    public function __construct(Context $context, UrlHelper $urlHelper)
+    {
+        parent::__construct($context);
+
+        $this->urlHelper = $urlHelper;
+    }
+
+    /**
+     * Remove any reference to the ajax URL parameter in the add to cart parameters.
+     *
+     * @param array $params
+     * @return array
+     */
+    public function cleanCartPostParams($params)
+    {
+        $uencKey = \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED;
+
+        if (isset($params['action'])) {
+            $actionUenc = $this->extractUencFromUrl($params['action']);
+            $cleanedActionEnc = $this->removeParamFromUenc($actionUenc, 'ajax');
+
+            $params['action'] = str_replace($actionUenc, $cleanedActionEnc, $params['action']);
+        }
+
+        if (isset($params['data'][$uencKey])) {
+            $decodedUrl = $this->urlDecoder->decode($params['data'][$uencKey]);
+
+            $dataUenc = $this->extractUencFromUrl($decodedUrl);
+            $cleanedDataUenc = $this->removeParamFromUenc($dataUenc, 'ajax');
+            $cleanedUrl = str_replace($dataUenc, $cleanedDataUenc, $decodedUrl);
+
+            $params['data'][$uencKey] = $this->urlEncoder->encode($cleanedUrl);
+        }
+
+        return $params;
+    }
+
+    /**
+     * Takes a URL and extracts the uenc parameter from it.
+     *
+     * @param string $url
+     * @return string|null
+     */
+    private function extractUencFromUrl($url)
+    {
+        $uencKey = \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED;
+
+        $matches = [];
+        $lookup = preg_match("/$uencKey\/(.*?)\//", $url, $matches);
+
+        if ($lookup && isset($matches[1])) {
+            return $matches[1];
+        }
+
+        return null;
+    }
+
+    /**
+     * Takes an encoded URL, removes a URL parameter from it and returns the new URL as an encoded URL.
+     *
+     * @param string $uenc An encoded URL
+     * @param string $param The param to remove from the encoded URL
+     * @return string
+     */
+    private function removeParamFromUenc($uenc, $param = 'ajax')
+    {
+        $decodedUrl = $this->urlDecoder->decode($uenc);
+        $cleanedUrl = $this->urlHelper->removeRequestParam($decodedUrl, $param);
+        return $this->urlEncoder->encode($cleanedUrl);
+    }
+}
diff --git a/app/code/Meanbee/InfiniteScroll/view/frontend/templates/product/list_json.phtml b/app/code/Meanbee/InfiniteScroll/view/frontend/templates/product/list_json.phtml
index ec694d8..d409dff 100755
--- a/app/code/Meanbee/InfiniteScroll/view/frontend/templates/product/list_json.phtml
+++ b/app/code/Meanbee/InfiniteScroll/view/frontend/templates/product/list_json.phtml
@@ -4,6 +4,9 @@
 $outputHelper = $this->helper(\Magento\Catalog\Helper\Output::class);
 $toolbarBlock = $block->getToolbarBlock();
 
+/** @var Meanbee\InfiniteScroll\Helper\Uenc $infiniteScrollHelper */
+$infiniteScrollHelper = $this->helper(Meanbee\InfiniteScroll\Helper\Uenc::class);
+
 if ($block->getMode() == 'grid') {
     $viewMode = 'grid';
     $image = 'category_page_grid';
@@ -50,7 +53,7 @@ foreach ($block->getLoadedProductCollection() as $product) {
             "primary"   => strpos($pos, $viewMode . "-primary") ? $position : "",
             "secondary" => strpos($pos, $viewMode . "-secondary") ? $position : "",
         ],
-        "post_params"      => $block->getAddToCartPostParams($product),
+        "post_params"      => $infiniteScrollHelper->cleanCartPostParams($block->getAddToCartPostParams($product)),
     ];
 }
 echo $this->helper(\Magento\Framework\Json\Helper\Data::class)->jsonEncode($data);
-- 
2.16.1

Closing as this repo is no longer maintained and will be marked as read-only.