1

I thought this would be better in Magento 2, but currently (Magento 2.1.4) Magento still has a quote complex way of rendering a product list. I'm talking about vendor/magento/module-catalog/view/frontend/templates/product/list.phtml. This is the template that is responsible for rendering the catalog- and the search results list.

The task

We all had the task at some point where the client requests a small addition to this template. Perhaps a product label, or an additional image, etc. But this template has very few points to hook into. The way I currently see it, when you want to make a modification to this list there are the following options:

The posible options

  • Copy/paste the phtml-file to your design folder and make the adjustments there. This - of course - is no option if you want to modify this template from within your module.
  • Add a modified template to your own module and point Magento to it from within your own custom catalog_category_view.xml. However, this could give unexpected results when using 3rd party templates. And I generally don't like the idea to overrule such a big template purely for a minor edit.
  • Rewrite the default product details renderer. This however gives the problem that as soon as you have a configurable product the default renderer is no longer rendered.
  • Hook into the addto-block (since this is the only place in the template where getChildHtml() is called for dynamicly added child templates.
  • Use JavaScript to enrich the html later on. This might seem a bit like the wrong solution for the problem, especially when what you're trying to render can already be done server-side.
  • There are some other hacky options (like using plugins to modify the output with regexp), but those are so not-done that I won't even discuss them here.

The question

So with the above options that I currently can think of, what would be the best approach to add custom html the the product block (in the product list). I'm currently tending toward the 'addto'-method, although it also seems like it's not the exact right place for the job. But at least it allows me to:

  • Minimize the changes I have to do about core templates.
  • Maximize the compatibility with external templates.
  • Keeps my own logic separated.

Of course it would be nicer if the rendering of a single product provided more hooks to manipulate the output (or at least, don't wrap the whole thing inside one massive foreach-loop inside list.phtml). Perhaps there are plans for this in the future?

What are your suggestions on this task?

2 Answers 2

1

It really depends on what exactly are you trying to accomplish, but using a preference should be the last resort. In the advice above, plugin is way better choice.

I would personally took following approach to the problem:

1, addto method. If you can accomplish whatever you are trying to do in a separate block, go for it. That is the best option.

2, If the change is client/project specific, there is nothing wrong in overriding phtml templates. It has it's downsides, but depending on the project it can be the most time effective way (even if you will have to resolve conflicts).

3, Rewrite is a strong word. Always look for a way to 'plugin' a functionality. You can either plugin the renderer, or you can plugin the getProductDetailsHtml() method mentioned above and write your own renderer.

3, catalog_category_view.xml layout edit. This has same problems as point 2, it is a bit more work, but at the same time it is transferable with a module.

4, If nothing works there are preferences.

5, JavaScript hack

6, Other hacks

1
  • Yeah, kind of the same solutions in the same order I would do. Guess I'm on the right track after all :-) Commented Feb 21, 2017 at 7:03
0

For this, you can rewrite getProductDetailsHtml from \Magento\Catalog\Block\Product\ListProduct so you can append your custom html.

In 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">
    <preference for="Magento\Catalog\Block\Product\ListProduct" type="Vendor\Module_Name\Block\Product\ListProduct" />
</config>

In ListProduct.php from Vendor\Module_Name\Block\Product\ListProduct

namespace Vendor\Module_Name\Block\Product;
class ListProduct extends \Magento\Catalog\Block\Product\ListProduct
{
    public function getProductDetailsHtml(\Magento\Catalog\Model\Product $product)
    {
        $html = $this->getLayout()->createBlock('Magento\Framework\View\Element\Template')->setProduct($product)->setTemplate('Vendor_ModuleName::test.phtml')->toHtml();
        $renderer = $this->getDetailsRenderer($product->getTypeId());
        if ($renderer) {
            $renderer->setProduct($product);
            return $html.$renderer->toHtml();
        }
        return '';
    }
}

here you can set your custom block with with the Magento\Framework\View\Element\Template as well as your custom.phtml

might be there are another good options available but right now I am using this.

Credit @Magev2

1
  • I know, but having to rewrite a method to do this (especially a public one, that can be rewritten with a plugin) and appending a HTML string seems like a hacky solution to me. Commented Feb 21, 2017 at 7:02

Your Answer

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

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