Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix swatch-renderer.js product id and isProductViewExist #8484

Merged
merged 3 commits into from
May 25, 2017

Conversation

mimarcel
Copy link
Contributor

@mimarcel mimarcel commented Feb 9, 2017

Summary

This pull requests allows you to add a list of products, with swatches, on Product Page, without conflicting with the global product's own swatches.

  • Fix getting product id
  • Fix checking if swatch is used in product view or list view

Pre-requisites

  • git clone M2 repo from develop branch; I used the latest at the time: commit 24cd0c3
  • install M2 as usual
  • Update color attribute
    • Set 'used_in_product_listing' to 1 for color attribute (in table catalog_eav_attribute)
    • Set color attribute as visual swatch and add 2-3 visual random test swatches
  • Create Products
    • Add 3 configurable products A, B and C, all three configurable by color attribute, with at least one simple product child
    • Add products A and B as related products for C
    • Attach an image to all/most simple products and configurable products created
  • In order to render swatches in products list, we will create a new module in app/code directory with the following structure:
Custom
└── AddSwatches
    ├── Plugin
    │   └── Swatches.php
    ├── etc
    │   ├── di.xml
    │   └── module.xml
    └── registration.php
  • Add Swatches.php
<?php
/**
 * Copyright © 2009-2017 Custom Group. All rights reserved.
 * See LICENSE.txt for license details.
 */

namespace Custom\AddSwatches\Plugin;

use Magento\Catalog\Block\Product\AbstractProduct;

/**
 * Swatches plugin to add color swatches to product list.
 *
 * @package Custom\AddSwatches\Plugin
 */
class Swatches
{
    /**
     * Around interceptor method for \Magento\Catalog\Block\Product\AbstractProduct::getDetailsRenderer.
     * Adds the swatches renderer to the product list for configurable products.
     *
     * @param AbstractProduct $subject
     * @param \Closure $proceed
     * @param null|string $type
     * @return bool|\Magento\Framework\View\Element\AbstractBlock
     */
    public function aroundGetDetailsRenderer(AbstractProduct $subject, \Closure $proceed, $type = null)
    {
        if ($type === 'configurable') {
            $renderer = $subject->getLayout()
                ->createBlock('Magento\Swatches\Block\Product\Renderer\Listing\Configurable')
                ->setTemplate('Magento_Swatches::product/listing/renderer.phtml');
        } else {
            $renderer = $proceed();
        }
        return $renderer;
    }
}
  • Add 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\Catalog\Block\Product\AbstractProduct">
        <plugin name="addSwatches" type="Custom\AddSwatches\Plugin\Swatches"/>
    </type>
</config>
  • Add module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Custom_AddSwatches" setup_version="1.0.0"/>
</config>
  • Add registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Custom_AddSwatches',
    __DIR__
);
  • Go to app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml
    and change this code
<div class="product details product-item-details">

to this code

<div class="product details product-item-details">
    <?php echo $block->getProductDetailsHtml($_item); ?>

Ignore that we're changing the core here.

  • Run php bin/magento setup:upgrade

Steps to Replicate

  • Go to product C in frontend
    product c
    • In the above image, swatches for products A, B and C are highlighted
  • Click on one of the swatches of related product B

Expected

Image for related product B is updated

Actual

Images for product C are updated

@vrann vrann self-requested a review February 28, 2017 13:33
@vrann vrann self-assigned this Feb 28, 2017
@vrann vrann added this to the February 2017 milestone Feb 28, 2017
@vrann vrann requested a review from zetlen February 28, 2017 17:01
@zetlen
Copy link

zetlen commented Feb 28, 2017

This is a great improvement, @mimarcel, and but it's unfortunate that you still have to work so directly with CSS class selectors to derive the relevant product ID. I think it would be a lot better if there were data attributes in the HTML so that you could always know which product was attached to a given DOM element. Using the schema.org microdata approach, for instance, you could add itemscope, itemtype, and a data attribute this in /templates/product/list/items.phtml, on line 195:

<div itemscope
    itemtype="http://schema.org/Product"
    class="product details product-item-details">
    <meta itemprop="productID" content="<?php echo $_item->getId() ?>">

Then, you could have a universal JavaScript function, perhaps in a separate module, that would always return the product ID for the current context.

define(['mage/itemscope'], function(itemscope) {
    // in some function:
    var scope = itemscope(this.element);
    if (scope && scope.itemType === itemscope.PRODUCT && scope.productID) {
        // scope contains data for the product being displayed with `this.element`.
    }
});

Might be a useful, general-purpose thing to have.

Copy link

@zetlen zetlen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from the overall structural change I'm asking about in my other comment, and the small bit of jQuery usage I recommend below, this looks good.


if (!productId) {
// Check individual product.
var product = document.getElementsByName('product')[0];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may throw an exception if there is no such element, since document.getElementsByName() can return null. Since jQuery is already present, you should perhaps replace this with var product = $('[product]')[0];.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @zetlen ,

Thank you for looking into this PR with so much care.

  • I did refactor the code to use jQuery instead of plain Javascript for an easier read: e9c42d2.
  • However, it's worth mentioning that document.getElementsByName('product')[0] doesn't return an exception because document.getElementsByName('product') returns empty array in case no elements are found and document.getElementsByName('product')[0] will return undefined.
  • The previous code document.getElementsByName('product')[0].value was indeed suspicious to throw an exception - issue which this PR fixed.

_determineProductData: function() {
// Check if product is in a list of products.
var productId = this.element.parents('.product-item-details')
.find('.price-box.price-final_price').attr('data-product-id'),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a general comment about how sad it is that it has to be done this way. This is a common need and should be separated into a general utility function/module.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @zetlen ,

This sounds like a very good idea, but I feel it's out of the scope of this PR. There are other few things I noticed that need refactoring in swatch-renderer.js, but I tried to keep the code as similar as possible with the old code and just fix the issues, so the code review will be as easy as possible. I would rather leave the refactoring on Magento team's side.

@maksek maksek modified the milestones: February 2017, March 2017 Mar 1, 2017
@okorshenko okorshenko added this to the March 2017 milestone Mar 1, 2017
@mimarcel
Copy link
Contributor Author

mimarcel commented Mar 2, 2017

@zetlen and @vrann, I updated the PR.

@okorshenko okorshenko modified the milestones: March 2017, April 2017 Apr 2, 2017
@vrann
Copy link
Contributor

vrann commented May 8, 2017

@mimarcel can you please merge with the latest develop branch

@okorshenko okorshenko modified the milestones: April 2017, May 2017 May 9, 2017
…x/swatch-renderer

# Conflicts:
#	app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js
@mimarcel
Copy link
Contributor Author

@vrann , after merging develop into current branch, I realised that this commit f349c0e is already there.

Commit e9c42d2 still remains as part of this Pull Request (from code review from @zetlen).

@magento-team magento-team merged commit 0f862c5 into magento:develop May 25, 2017
@magento-team
Copy link
Contributor

@mimarcel Thank you for the contribution

@mimarcel mimarcel deleted the fix/swatch-renderer branch June 27, 2017 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants