Jump to content

Change cover image based on layered navigation color selection


remyessers

Recommended Posts

Hi,

 

Is it possible to change the cover image on product-list based on the selection of the color attribute in layered navigation?

 

If I click on red, it shows my products with the red attribute available, but with the default cover image (E.g. a black image). This is very confusing for my customers, how can I change this? It looks like a feature more people should find very usefull..

 

Best regards,

 

Remy

Link to comment
Share on other sites

Probably possible, if you know some javascript.

In themes/<your theme folder>/modules/blocklayered/blocklayered.tpl

(N.B. This is the overridden file of it's original one, found in/modules/blocklayered/blocklayered.tpl. (but probably exists already there. If not, copy from original)

 

You have code like this (there are more places you need to adjust, here just a partly example):

 

<input class="color-option {if isset($value.checked) && $value.checked}on{/if} {if !$value.nbr}disable{/if}" type="button" name="layered_{$filter.type_lite}_{$id_value}" rel="{$id_value}_{$filter.id_key}" id="layered_id_attribute_group_{$id_value}" {if !$value.nbr}disabled="disabled"{/if} style="background: {if isset($value.color)}{if file_exists($smarty.const._PS_ROOT_DIR_|cat:"/img/co/$id_value.jpg")}url(img/co/{$id_value}.jpg){else}{$value.color}{/if}{else}#CCC{/if};" onclick="changeImage();"/> // add red action

 

Javascript would be basically something like this:

 

<head>

<script type="text/javascript">

 

function changeImage() {

... <code for changing image>

}

 

</script>

</head>

 

 

Probably quite some work to find exactly all places where to add this, and you need to know javascript, make the function generic to make it work for all products etc

 

Maybe it gives you some idea. Furthermore no javascript programmer, so I cannot help you with that.

 

Maybe there is a module which does this already?? Anyone?

 

My 2 cents,

Pascal

Link to comment
Share on other sites

  • 3 weeks later...
  • 2 months later...
  • 1 month later...
  • 1 year later...

Hi, all,

 

anyone solved this issue? I'm trying to use the color filter and it works on layered module but it shows the default cover images on product-list.tpl result. I would like that if i choose "red" as color filter, then the website should show me just the red products as result.

 

Thanks

Link to comment
Share on other sites

  • 11 months later...

This is in the standard application. Colors create combinations and you can assign a picture to each combination. You can see it even in Prestashop's demo shop.

 

Allocation pictures to combinations can be a bit of a fuzz but you can use the free Prestools Suite to make it easier.

 

PS layered navigation always shows the default combination image, not the corresponding image based on color selection in layered navigation filter. Anyway, good to know about Prestools Suite!.

Link to comment
Share on other sites

  • 1 year later...
  • 1 month later...

No luck I did buy advanced search 4.

 

Bye the way I think this will be my last project on prestashop.

 

Thinking to start to work with magento. because of all the stuff I found out that are missing.

 

in the that site I did I hat to get plugins for Pretsashop for stuff that are default in magento

  • Like 1
Link to comment
Share on other sites

  • 4 months later...
  • 3 months later...

Hello,

sharing a "hacky way" that works on ps 1.5  & ps 1.6.  I Hope it will lead someone to making it as a nice solution for a client.

This should not be used as a permanent solution. If the blocklayered module gets update, the code will get overwritten.  P.S. the particular code works with all of the attributes, not only the color.

Edit /modules/blocklayered/blocklayered.php

1. Put this in the function ajaxCall() after the line $this->getProducts(...)

if (isset($selected_filters['id_attribute_group']) && $selected_filters['id_attribute_group']) {
			$this->switchProductImages($selected_filters, $products);
}

}

2. Put these at the very end of the file (before closing curly brace)

       private function switchProductImages($selected_filters, &$products) {
        foreach ($products as &$product) {
            foreach($selected_filters['id_attribute_group'] as $key => $value) {
               $attributeImageId = $this->getProductImage($product['id_product'], $key);
              if((int)($attributeImageId) > 0) {

                  $product['id_image'] = $product['id_product'].'-'.$attributeImageId;
              }
            }
        }
    }

    private function getProductImage($id_product, $id_attribute) {

        $query = 'SELECT `id_image` FROM `ps_product_attribute_combination`
        INNER JOIN `ps_product_attribute` ON `ps_product_attribute`.`id_product_attribute` = `ps_product_attribute_combination`.`id_product_attribute`
        INNER JOIN `ps_product_attribute_image` ON `ps_product_attribute_image`.`id_product_attribute` = `ps_product_attribute`.`id_product_attribute`
        WHERE `id_attribute` = \''.$id_attribute.'\' AND `id_product` = \''.$id_product.'\'';

        return DB::getInstance()->getValue($query);
    }

 

 

 

 

 

Edited by Binded
Added a check for empty attribute group, because sometimes attribute group is not set (see edit history)
  • Thanks 2
Link to comment
Share on other sites

Binded! You are my HERO !!!! I can´t beleive that someone, (as you) made the time, and posted solution like this one!

I can confim, that this solution is working. I am greatly happy to thank you so much !!!

 

More posts like this one, and presta will be the best.

Link to comment
Share on other sites

@Binded I will test this today and I will edit this post later. Just posting to not forget to do this :)

EDIT:

HOOOOOLY SH*T! :) This is working :D You are the best! I tested this even with 2 selected features.


@danirub check this out.

 

I would only change this first statement to

if (isset($selected_filters['id_attribute_group']) && $selected_filters['id_attribute_group']) {
			$this->switchProductImages($selected_filters, $products);
		}

because sometimes attribute group is not set and there will notice in logs.

@Kaper it is not hidden - the post is moved to the top of the page.

 

Imho much better solution for getProductImages is this function because it is taking a photo with regarding photo position.

private function getProductImage($id_product, $id_attribute) {

		$query = 'SELECT pai`.id_image` FROM `ps_product_attribute_combination` pac
        INNER JOIN `ps_product_attribute` ON pa.`id_product_attribute` = pac.`id_product_attribute`
        INNER JOIN `ps_product_attribute_image` ON pai.`id_product_attribute` = pa.`id_product_attribute`
        INNER JOIN `ps_image` i ON pai.`id_image` = i.`id_image`
        WHERE pac.`id_attribute` = '.(int)$id_attribute.' AND pa.`id_product` = '.(int)$id_product.'
        ORDER BY i.`position`' ;

		return DB::getInstance()->getValue($query);
	}

 

Edited by hakeryk2 (see edit history)
Link to comment
Share on other sites

  • 3 months later...

Hi, I'm looking for a solution to this in PS 1.7.

I've tried changing the id_image value returned from the database query in the ps_facetedsearch module but that doesn't seem to affect the image which is displayed on the product list.

Any help or suggestions appreciated, thanks!

Link to comment
Share on other sites

  • 2 months later...
On 2/10/2018 at 4:57 AM, Binded said:

Hello,

sharing a "hacky way" that works on ps 1.5  & ps 1.6.  I Hope it will lead someone to making it as a nice solution for a client.

This should not be used as a permanent solution. If the blocklayered module gets update, the code will get overwritten.  P.S. the particular code works with all of the attributes, not only the color.

Edit /modules/blocklayered/blocklayered.php

1. Put this in the function ajaxCall() after the line $this->getProducts(...)


if (isset($selected_filters['id_attribute_group']) && $selected_filters['id_attribute_group']) {
			$this->switchProductImages($selected_filters, $products);
}

}

2. Put these at the very end of the file (before closing curly brace)


       private function switchProductImages($selected_filters, &$products) {
        foreach ($products as &$product) {
            foreach($selected_filters['id_attribute_group'] as $key => $value) {
               $attributeImageId = $this->getProductImage($product['id_product'], $key);
              if((int)($attributeImageId) > 0) {

                  $product['id_image'] = $product['id_product'].'-'.$attributeImageId;
              }
            }
        }
    }

    private function getProductImage($id_product, $id_attribute) {

        $query = 'SELECT `id_image` FROM `ps_product_attribute_combination`
        INNER JOIN `ps_product_attribute` ON `ps_product_attribute`.`id_product_attribute` = `ps_product_attribute_combination`.`id_product_attribute`
        INNER JOIN `ps_product_attribute_image` ON `ps_product_attribute_image`.`id_product_attribute` = `ps_product_attribute`.`id_product_attribute`
        WHERE `id_attribute` = \''.$id_attribute.'\' AND `id_product` = \''.$id_product.'\'';

        return DB::getInstance()->getValue($query);
    }

 

 

 

 

 

This doesnt seem to work anymore -- anyone else?

Link to comment
Share on other sites

4 hours ago, hakeryk2 said:

Any more info? For me it is working perfectly with 1.6 vr. Change some of these as well to get better performance https://www.prestashop.com/forums/topic/240139-change-cover-image-based-on-layered-navigation-color-selection/?do=findComment&comment=2682625

 

Using PS 1.6.1.4

 

I tried both the original fix and your version and when i click on a combination it still does not change image.

 

My db prefix is p_ other than ps_ , which i have changed - still no good

 

Edit: blocklayered.php for reference: https://pastebin.com/mcaZXHNA

Edited by HouseofJewellery (see edit history)
Link to comment
Share on other sites

  • 5 weeks later...
On 2018-08-03 at 6:35 PM, HouseofJewellery said:

Using PS 1.6.1.4

I tried both the original fix and your version and when i click on a combination it still does not change image.

My db prefix is p_ other than ps_ , which i have changed - still no good

Edit: blocklayered.php for reference: https://pastebin.com/mcaZXHNA

Me or other any developer in here could easily solve your problem, but I think it would be much more valuable to give you a hint: You have an error in the sql query. My original query works with 1.6.1.4, you can use it as a reference.

Link to comment
Share on other sites

  • 3 months later...
On 9/3/2018 at 9:45 AM, Binded said:

Me or other any developer in here could easily solve your problem, but I think it would be much more valuable to give you a hint: You have an error in the sql query. My original query works with 1.6.1.4, you can use it as a reference.

        $query = 'SELECT `id_image` FROM `p_product_attribute_combination`
INNER JOIN `p_product_attribute` ON p_product_attribute.id_product_attribute = p_product_attribute_combination.id_product_attribute
INNER JOIN `p_product_attribute_image` ON p_product_attribute_image.id_product_attribute = p_product_attribute.id_product_attribute
      WHERE `id_attribute` = \''.$id_attribute.'\' AND `id_product` = \''.$id_product.'\'';

        return DB::getInstance()->getValue($query);

 

Whats wrong with it

 

edit: I even tried the original statement again no luck:

 

$query = 'SELECT `id_image` FROM `p_product_attribute_combination`
INNER JOIN `p_product_attribute` ON `p_product_attribute`.`id_product_attribute` = `p_product_attribute_combination`.`id_product_attribute`
INNER JOIN `p_product_attribute_image` ON `p_product_attribute_image`.`id_product_attribute` = `p_product_attribute`.`id_product_attribute`
WHERE `id_attribute` LIKE \''.$id_attribute.'\' AND `id_product` = \''.$id_product.'\'';

return DB::getInstance()->getValue($query);
Edited by HouseofJewellery (see edit history)
Link to comment
Share on other sites

Try with this and this is the last attempt.
 

private function getProductImage($id_product, $id_attribute) {

		$query = 'SELECT pai.`id_image` FROM `ps_product_attribute_combination` pac
        LEFT JOIN `ps_product_attribute` pa ON pa.`id_product_attribute` = pac.`id_product_attribute`
        LEFT JOIN `ps_product_attribute_image` pai ON pai.`id_product_attribute` = pa.`id_product_attribute`
        LEFT JOIN `ps_image` i ON pai.`id_image` = i.`id_image`
        WHERE pac.`id_attribute` = '.(int)$id_attribute.' AND pa.`id_product` = '.(int)$id_product.'
        ORDER BY i.`position`' ;

		return DB::getInstance()->getValue($query);
}

private function getProductImage($id_product, $id_attribute) {

		$query = 'SELECT pai.`id_image` FROM `ps_product_attribute_combination` pac
        LEFT JOIN `ps_product_attribute` pa ON pa.`id_product_attribute` = pac.`id_product_attribute`
        LEFT JOIN `ps_product_attribute_image` pai ON pai.`id_product_attribute` = pa.`id_product_attribute`
        LEFT JOIN `ps_image` i ON pai.`id_image` = i.`id_image`
        WHERE pac.`id_attribute` = '.(int)$id_attribute.' AND pa.`id_product` = '.(int)$id_product.'
        ORDER BY i.`position`' ;

		return DB::getInstance()->getValue($query);
	}

If this will not work then it might be related to Your hosting configuration. I menaged to get this "NOT" working on localhost because it had some weird mysql configuration.

Link to comment
Share on other sites

  • 1 month later...
  • 1 year later...
  • 8 months later...

Just in case anyone is still looking for a solution for PS 1.7, here's a solution based on Binded's solution.

In the file modules/ps_facetedsearch/src/Filters/Products.php, right after the line

$matchingProductList = $this->searchAdapter->execute();

add the block

if (isset($selectedFilters['id_attribute_group']) && $selectedFilters['id_attribute_group']) {
	$this->setProductAttributeId($selectedFilters, $matchingProductList);
}

 

Then at the end of the class, add the two following methods :

    private function setProductAttributeId($selected_filters, &$products) {
        foreach ($products as &$product) {
            $attribute_id_sets = [];
            foreach($selected_filters['id_attribute_group'] as $attribute_group) {
                $attribute_id_sets[] = $this->getProductAttributeIds($product['id_product'], $attribute_group);
            }

            if (!empty($attribute_id_sets)) {
                $attribute_ids = array_pop($attribute_id_sets);
                while (!empty($attribute_id_sets)) {
                    $attribute_ids = array_intersect($attribute_ids, array_pop($attribute_id_sets));
                }
            }

            if (!empty($attribute_ids)) {
                $product['id_product_attribute'] = array_pop($attribute_ids);
            }
        }
    }

    private function getProductAttributeIds($id_product, $attribute_group)
    {
        $attribute_ids = [];
        foreach ($attribute_group as $key => $id_attribute) {
            $query = new DbQuery();
            $query->select('ps_product_attribute.id_product_attribute');
            $query->from('product_attribute_combination');
            $query->innerJoin('product_attribute', null, 'ps_product_attribute.id_product_attribute = ps_product_attribute_combination.id_product_attribute');
            $query->where('ps_product_attribute.id_product = \'' . $id_product . '\' AND ps_product_attribute_combination.id_attribute = \'' . $id_attribute . '\'');
            $results = Db::getInstance()->executeS($query);
            foreach ($results as $result) {
                $attribute_ids[] = $result['id_product_attribute'];
            }
        }
        return $attribute_ids;
    }

 

What this does is that whenever some filters are selected in the faceted search module, it looks for the first variation of each product that matches all filters (matches one of the conditions in each block) and displays the default image for this variation.

 

Note : My PHP skills are extremely low, so it's very likely that the code in the two added functions can be rewritten in a much more elegant way.

Link to comment
Share on other sites

  • 4 months later...
On 12/11/2020 at 2:09 AM, vpoupet said:

Just in case anyone is still looking for a solution for PS 1.7, here's a solution based on Binded's solution.

In the file modules/ps_facetedsearch/src/Filters/Products.php, right after the line



$matchingProductList = $this->searchAdapter->execute();

add the block



if (isset($selectedFilters['id_attribute_group']) && $selectedFilters['id_attribute_group']) {
	$this->setProductAttributeId($selectedFilters, $matchingProductList);
}

 

Then at the end of the class, add the two following methods :



    private function setProductAttributeId($selected_filters, &$products) {
        foreach ($products as &$product) {
            $attribute_id_sets = [];
            foreach($selected_filters['id_attribute_group'] as $attribute_group) {
                $attribute_id_sets[] = $this->getProductAttributeIds($product['id_product'], $attribute_group);
            }

            if (!empty($attribute_id_sets)) {
                $attribute_ids = array_pop($attribute_id_sets);
                while (!empty($attribute_id_sets)) {
                    $attribute_ids = array_intersect($attribute_ids, array_pop($attribute_id_sets));
                }
            }

            if (!empty($attribute_ids)) {
                $product['id_product_attribute'] = array_pop($attribute_ids);
            }
        }
    }

    private function getProductAttributeIds($id_product, $attribute_group)
    {
        $attribute_ids = [];
        foreach ($attribute_group as $key => $id_attribute) {
            $query = new DbQuery();
            $query->select('ps_product_attribute.id_product_attribute');
            $query->from('product_attribute_combination');
            $query->innerJoin('product_attribute', null, 'ps_product_attribute.id_product_attribute = ps_product_attribute_combination.id_product_attribute');
            $query->where('ps_product_attribute.id_product = \'' . $id_product . '\' AND ps_product_attribute_combination.id_attribute = \'' . $id_attribute . '\'');
            $results = Db::getInstance()->executeS($query);
            foreach ($results as $result) {
                $attribute_ids[] = $result['id_product_attribute'];
            }
        }
        return $attribute_ids;
    }

 

What this does is that whenever some filters are selected in the faceted search module, it looks for the first variation of each product that matches all filters (matches one of the conditions in each block) and displays the default image for this variation.

 

Note : My PHP skills are extremely low, so it's very likely that the code in the two added functions can be rewritten in a much more elegant way.

Perfect! Works like a charm. If anyone can't make it work then just need to modify a couple of things. Require to use DbQuery and Db class. To insert them just go to the top of the file and insert below lines after 'use Configuration;'

Find below

use Configuration;

Add below after

use DbQuery;
use Db;

The above modification should work for anyone. If it doesn't then you will have to look at the below modification.

Modify the getProductAttributeIds($id_product, $attribute_group) class if required. You will notice that 'ps_' before 'product_attribute' and some other column names. That 'ps_' is the prefix of your database table columns. If you had set something different then you will have to replace that 'ps_' with your own. If you are not sure then look at the database tables and any columns to find out your prefix. By default it's 'ps_' unless you have opted out during installation and left it blank.

The complete function will look like below (without any database prefix like 'ps_').

private function getProductAttributeIds($id_product, $attribute_group){
        $attribute_ids = [];
        foreach ($attribute_group as $key => $id_attribute) {
            $query = new DbQuery();
            $query->select('product_attribute.id_product_attribute');
            $query->from('product_attribute_combination');
            $query->innerJoin('product_attribute', null, 'product_attribute.id_product_attribute = 			 product_attribute_combination.id_product_attribute');
            $query->where('product_attribute.id_product = \'' . $id_product . '\' AND product_attribute_combination.id_attribute = \'' . $id_attribute . '\'');
            $results = Db::getInstance()->executeS($query);
            foreach ($results as $result) {
                $attribute_ids[] = $result['id_product_attribute'];
            }
        }
        return $attribute_ids;
    }

 

Edited by enamul911 (see edit history)
Link to comment
Share on other sites

  • 4 weeks later...

Thanks everyone for contribution. This is awesome, but it has on drawback.

Is it possible after changing img cover to open product also in selected color? FOr example, if i am filtering RED color SHOES, but some of the product listed have default combination BLACK, it will open this SHOES in RED color combination SELECTED ? Thanks :)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...