Jump to content

[PS 1.7][HOW TO] - Set similar product image to another product


Recommended Posts

Hi,

 

I'm developing a custom module for my shop.

 

This module will generate product packs with a unique product reference.

 

I want to take the original product images to set it to the pack freshly created with this product.

 

What I need is :

  • Find an efficient way to set multiple products to the same images
  • Something really light because it will be used for a really big amount of product packs (like 3k)

What I've got is :

  • All original product and packs informations
  • url of home_default type images

 

Waiting for you help guys 😉!!

Edited by jmauclair
SOLVED (by myself lol) (see edit history)
Link to comment
Share on other sites

 

Finally find a way to do this easily ;)

The packedproductID  is the ID of the new product and the productID is the ID of the original product, the one you want to take pictures.

function setProductImage($packedProductID, $productID)
{
    $packedProdImgs = getProductImage($packedProductID);
    foreach ($packedProdImgs as $imgs) {
        $image = new Image();
        $image->id_product = $productID;
        $image->position = $imgs['position'];
        if ($imgs['cover'] == 1) {
            $image->cover = true; // or false;
        } else {
            $image->cover = false;
        }
        if ($image->add()) {
            if (!copyImg($productID, $image->id, $imgs['url'], 'products', true)) {
                $image->delete();
            }
        }
    }
}

Aux functions :

 

function copyImg($id_entity, $id_image = null, $url, $entity = 'products', $regenerate = false)
{
    $tmpfile = tempnam(_PS_TMP_IMG_DIR_, 'ps_import');
    $watermark_types = explode(',', Configuration::get('WATERMARK_TYPES'));

    switch ($entity) {
        default:
        case 'products':
            $image_obj = new Image($id_image);
            $path = $image_obj->getPathForCreation();
            break;
    }

    $url = urldecode(trim($url));
    $parced_url = parse_url($url);

    if (isset($parced_url['path'])) {
        $uri = ltrim($parced_url['path'], '/');
        $parts = explode('/', $uri);
        foreach ($parts as &$part) {
            $part = rawurlencode($part);
        }
        unset($part);
        $parced_url['path'] = '/' . implode('/', $parts);
    }

    if (isset($parced_url['query'])) {
        $query_parts = array();
        parse_str($parced_url['query'], $query_parts);
        $parced_url['query'] = http_build_query($query_parts);
    }

    if (!function_exists('http_build_url')) {
        require_once(_PS_TOOL_DIR_ . 'http_build_url/http_build_url.php');
    }

    $url = http_build_url('', $parced_url);

    $orig_tmpfile = $tmpfile;

    if (Tools::copy($url, $tmpfile)) {
        // Evaluate the memory required to resize the image: if it's too much, you can't resize it.
        if (!ImageManager::checkImageMemoryLimit($tmpfile)) {
            @unlink($tmpfile);
            return false;
        }

        $tgt_width = $tgt_height = 0;
        $src_width = $src_height = 0;
        $error = 0;
        ImageManager::resize($tmpfile, $path . '.jpg', null, null, 'jpg', false, $error, $tgt_width, $tgt_height, 5, $src_width, $src_height);
        $images_types = ImageType::getImagesTypes($entity, true);

        if ($regenerate) {
            $previous_path = null;
            $path_infos = array();
            $path_infos[] = array($tgt_width, $tgt_height, $path . '.jpg');
            foreach ($images_types as $image_type) {
                $tmpfile = get_best_path($image_type['width'], $image_type['height'], $path_infos);

                if (ImageManager::resize($tmpfile, $path . '-' . stripslashes($image_type['name']) . '.jpg', $image_type['width'], $image_type['height'], 'jpg', false, $error, $tgt_width, $tgt_height, 5, $src_width, $src_height)) {
                    // the last image should not be added in the candidate list if it's bigger than the original image
                    if ($tgt_width <= $src_width && $tgt_height <= $src_height) {
                        $path_infos[] = array($tgt_width, $tgt_height, $path . '-' . stripslashes($image_type['name']) . '.jpg');
                    }
                    if ($entity == 'products') {
                        if (is_file(_PS_TMP_IMG_DIR_ . 'product_mini_' . (int) $id_entity . '.jpg')) {
                            unlink(_PS_TMP_IMG_DIR_ . 'product_mini_' . (int) $id_entity . '.jpg');
                        }
                        if (is_file(_PS_TMP_IMG_DIR_ . 'product_mini_' . (int) $id_entity . '_' . (int) Context::getContext()->shop->id . '.jpg')) {
                            unlink(_PS_TMP_IMG_DIR_ . 'product_mini_' . (int) $id_entity . '_' . (int) Context::getContext()->shop->id . '.jpg');
                        }
                    }
                }
                if (in_array($image_type['id_image_type'], $watermark_types)) {
                    Hook::exec('actionWatermark', array('id_image' => $id_image, 'id_product' => $id_entity));
                }
            }
        }
    } else {
        @unlink($orig_tmpfile);
        return false;
    }
    unlink($orig_tmpfile);
    return true;
}

function get_best_path($tgt_width, $tgt_height, $path_infos)
{
    $path_infos = array_reverse($path_infos);
    $path = '';
    foreach ($path_infos as $path_info) {
        list($width, $height, $path) = $path_info;
        if ($width >= $tgt_width && $height >= $tgt_height) {
            return $path;
        }
    }
    return $path;
}

These functions are normally available in AdminImportController

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

  • jmauclair changed the title to [PS 1.7][HOW TO] - Set similar product image to another product
  • 1 year later...
On 7/15/2021 at 5:19 PM, jmauclair said:

 

Finally find a way to do this easily ;)

The packedproductID  is the ID of the new product and the productID is the ID of the original product, the one you want to take pictures.

function setProductImage($packedProductID, $productID)
{
    $packedProdImgs = getProductImage($packedProductID);
    foreach ($packedProdImgs as $imgs) {
        $image = new Image();
        $image->id_product = $productID;
        $image->position = $imgs['position'];
        if ($imgs['cover'] == 1) {
            $image->cover = true; // or false;
        } else {
            $image->cover = false;
        }
        if ($image->add()) {
            if (!copyImg($productID, $image->id, $imgs['url'], 'products', true)) {
                $image->delete();
            }
        }
    }
}

Aux functions :

 

function copyImg($id_entity, $id_image = null, $url, $entity = 'products', $regenerate = false)
{
    $tmpfile = tempnam(_PS_TMP_IMG_DIR_, 'ps_import');
    $watermark_types = explode(',', Configuration::get('WATERMARK_TYPES'));

    switch ($entity) {
        default:
        case 'products':
            $image_obj = new Image($id_image);
            $path = $image_obj->getPathForCreation();
            break;
    }

    $url = urldecode(trim($url));
    $parced_url = parse_url($url);

    if (isset($parced_url['path'])) {
        $uri = ltrim($parced_url['path'], '/');
        $parts = explode('/', $uri);
        foreach ($parts as &$part) {
            $part = rawurlencode($part);
        }
        unset($part);
        $parced_url['path'] = '/' . implode('/', $parts);
    }

    if (isset($parced_url['query'])) {
        $query_parts = array();
        parse_str($parced_url['query'], $query_parts);
        $parced_url['query'] = http_build_query($query_parts);
    }

    if (!function_exists('http_build_url')) {
        require_once(_PS_TOOL_DIR_ . 'http_build_url/http_build_url.php');
    }

    $url = http_build_url('', $parced_url);

    $orig_tmpfile = $tmpfile;

    if (Tools::copy($url, $tmpfile)) {
        // Evaluate the memory required to resize the image: if it's too much, you can't resize it.
        if (!ImageManager::checkImageMemoryLimit($tmpfile)) {
            @unlink($tmpfile);
            return false;
        }

        $tgt_width = $tgt_height = 0;
        $src_width = $src_height = 0;
        $error = 0;
        ImageManager::resize($tmpfile, $path . '.jpg', null, null, 'jpg', false, $error, $tgt_width, $tgt_height, 5, $src_width, $src_height);
        $images_types = ImageType::getImagesTypes($entity, true);

        if ($regenerate) {
            $previous_path = null;
            $path_infos = array();
            $path_infos[] = array($tgt_width, $tgt_height, $path . '.jpg');
            foreach ($images_types as $image_type) {
                $tmpfile = get_best_path($image_type['width'], $image_type['height'], $path_infos);

                if (ImageManager::resize($tmpfile, $path . '-' . stripslashes($image_type['name']) . '.jpg', $image_type['width'], $image_type['height'], 'jpg', false, $error, $tgt_width, $tgt_height, 5, $src_width, $src_height)) {
                    // the last image should not be added in the candidate list if it's bigger than the original image
                    if ($tgt_width <= $src_width && $tgt_height <= $src_height) {
                        $path_infos[] = array($tgt_width, $tgt_height, $path . '-' . stripslashes($image_type['name']) . '.jpg');
                    }
                    if ($entity == 'products') {
                        if (is_file(_PS_TMP_IMG_DIR_ . 'product_mini_' . (int) $id_entity . '.jpg')) {
                            unlink(_PS_TMP_IMG_DIR_ . 'product_mini_' . (int) $id_entity . '.jpg');
                        }
                        if (is_file(_PS_TMP_IMG_DIR_ . 'product_mini_' . (int) $id_entity . '_' . (int) Context::getContext()->shop->id . '.jpg')) {
                            unlink(_PS_TMP_IMG_DIR_ . 'product_mini_' . (int) $id_entity . '_' . (int) Context::getContext()->shop->id . '.jpg');
                        }
                    }
                }
                if (in_array($image_type['id_image_type'], $watermark_types)) {
                    Hook::exec('actionWatermark', array('id_image' => $id_image, 'id_product' => $id_entity));
                }
            }
        }
    } else {
        @unlink($orig_tmpfile);
        return false;
    }
    unlink($orig_tmpfile);
    return true;
}

function get_best_path($tgt_width, $tgt_height, $path_infos)
{
    $path_infos = array_reverse($path_infos);
    $path = '';
    foreach ($path_infos as $path_info) {
        list($width, $height, $path) = $path_info;
        if ($width >= $tgt_width && $height >= $tgt_height) {
            return $path;
        }
    }
    return $path;
}

These functions are normally available in AdminImportController

Hi @jmauclair i want to use same images several products. Is this code is work for that? Can u help me please?

Link to comment
Share on other sites

53 minutes ago, GUNEZ said:

Hi @jmauclair i want to use same images several products. Is this code is work for that? Can u help me please?

Hi @GUNEZ, yes this code might still work as it was working one year ago, have you tried it ?

By the way, before sending a direct message to me, please let me the time to answer on the post, that’s not polite

 

Link to comment
Share on other sites

1 minute ago, jmauclair said:

Hi @GUNEZ, yes this code might still work as it was working one year ago, have you tried it ?

By the way, before sending a direct message to me, please let me the time to answer on the post, that’s not polite

 

I'm so sorry for direct message. I'm searching 2 weeks. I'm not try. 

 

I will add the code below AdminImportController.php . Is this correct? 

function setProductImage($packedProductID, $productID)
{
    $packedProdImgs = getProductImage($packedProductID);
    foreach ($packedProdImgs as $imgs) {
        $image = new Image();
        $image->id_product = $productID;
        $image->position = $imgs['position'];
        if ($imgs['cover'] == 1) {
            $image->cover = true; // or false;
        } else {
            $image->cover = false;
        }
        if ($image->add()) {
            if (!copyImg($productID, $image->id, $imgs['url'], 'products', true)) {
                $image->delete();
            }
        }
    }
}

 

Link to comment
Share on other sites

Before asking for help you should try.

No, you should use this code in a php file, you don’t have to put it in AdminImportController.php.

I recommend you to make some research about how is working PHP and how to make simple scripts for Prestashop.

  • Like 1
Link to comment
Share on other sites

  • 5 weeks later...

Hi.
When I read it like that, I can't help but wonder.
Making copies of images for such a large number of products is nonsense.
Let's count.
You have 3,000 products and each product has 5 thumbnails for one image.
There are 3 products in the package.
So by copying images you create 3000 x 5 x 3 = 450,000 images, which is approx. 17GB. If the product has multiple images, the result needs to be multiplied by the number of images.

The solution is to create your own table in the database and write the product id, the image id of the original product into it. And then create an override Product.php and function getImages().

 

The solution is always simple 😉
I'll write the override code when I get to the computer.

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

./override/classes/Product.php

This code does not copy any images.
It finds out the ID of the products in the package and creates a simple SQL query to the database and returns the ID of the images of the individual products !!!

You can also edit the code so that it only shows images of the variant in the package.

Just load the id_product_attribute item and find out the image of the attribute / combination.

class Product extends ProductCore
{


    public function getImages($id_lang, Context $context = null)
    {

        $productsInPack = array();

        if (Pack::isPack((int) $this->id)) {

            $getProductInPack = Db::getInstance()->executeS('SELECT id_product_item FROM '._DB_PREFIX_.'pack WHERE id_product_pack = '.$this->id.' GROUP BY id_product_item');

            if ($getProductInPack){
                foreach ($getProductInPack as $productPack){
                    $productsInPack[] = $productPack['id_product_item'];
                }
            }
        }


        if ($productsInPack){
            $getProducts = implode(', ', $productsInPack);
        } else {
            $getProducts = $this->id;
        }

        $query = '
        SELECT image_shop.`cover`, i.`id_image`, il.`legend`, i.`position`
        FROM `' . _DB_PREFIX_ . 'image` i
        ' . Shop::addSqlAssociation('image', 'i') . '
        LEFT JOIN `' . _DB_PREFIX_ . 'image_lang` il ON (i.`id_image` = il.`id_image` AND il.`id_lang` = ' . (int) $id_lang . ')
        WHERE i.`id_product` IN (' . $getProducts . ')
        ORDER BY `position`';

        return Db::getInstance()->executeS($query);

    }

    

    public function __construct($id_product = null, $full = false, $id_lang = null, $id_shop = null, \Context $context = null) 
    {
        parent::__construct($id_product, $full, $id_lang, $id_shop, $context);
    }
}

 

BO:

obrazek.thumb.png.20b63d62aba1ff31cab5a87fcfd2d585.png

 

FO:

obrazek.png.6f571fed1f0f98f4b9229987e055e8b1.png

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

Sample for loading attribute/combination images.
When there is no combination, it loads the default product image from the package.

class Product extends ProductCore
{


    public function getImages($id_lang, Context $context = null)
    {

        $productsInPack = array();
        $productsAttributeItem = array();

        if (Pack::isPack((int) $this->id)) {

            $getProductInPack = Db::getInstance()->executeS('SELECT id_product_item, id_product_attribute_item FROM '._DB_PREFIX_.'pack WHERE id_product_pack = '.$this->id.' GROUP BY id_product_item');

            if ($getProductInPack > 0){
                foreach ($getProductInPack as $productPack){
                    if ($productPack['id_product_attribute_item']){
                        $getAttributeImage = Db::getInstance()->executeS('SELECT id_image FROM '._DB_PREFIX_.'product_attribute_image WHERE id_product_attribute = '.$productPack['id_product_attribute_item'].' GROUP BY id_image');
                        foreach ($getAttributeImage as $attributeImages){
                            $productsAttributeItem[] = $attributeImages['id_image'];
                        }
                    } 
                    
                    if ($productPack['id_product_attribute_item'] == '0'){
                        $getImage = Db::getInstance()->executeS('SELECT id_image FROM '._DB_PREFIX_.'image WHERE id_product = '.$productPack['id_product_item']);
                        foreach ($getImage as $image){
                            $productsAttributeItem[] = $image['id_image'];
                        }
                    }

                    $productsInPack[] = $productPack['id_product_item'];
                }
            }
        }


        if ($productsInPack){
            $getProducts = implode(', ', $productsInPack);
        } else {
            $getProducts = $this->id;
        }

        if ($productsAttributeItem){
            $whereAttributeImages = ' AND i.id_image IN ('.implode(', ', $productsAttributeItem).')';
        } else {
            $whereAttributeImages = '';
        }

        $query = '
        SELECT image_shop.`cover`, i.`id_image`, il.`legend`, i.`position`
        FROM `' . _DB_PREFIX_ . 'image` i
        ' . Shop::addSqlAssociation('image', 'i') . '
        LEFT JOIN `' . _DB_PREFIX_ . 'image_lang` il ON (i.`id_image` = il.`id_image` AND il.`id_lang` = ' . (int) $id_lang . ')
        WHERE i.`id_product` IN (' . $getProducts . ')'.$whereAttributeImages.'
        ORDER BY `position`';

        return Db::getInstance()->executeS($query);

    }

    

    public function __construct($id_product = null, $full = false, $id_lang = null, $id_shop = null, \Context $context = null) 
    {
        parent::__construct($id_product, $full, $id_lang, $id_shop, $context);
    }
}

 

FO:

obrazek.png.eba29818874e011905c633ad54d62c31.png

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

  • 1 month later...
On 8/25/2022 at 7:16 AM, knacky said:

Sample for loading attribute/combination images.
When there is no combination, it loads the default product image from the package.

class Product extends ProductCore
{


    public function getImages($id_lang, Context $context = null)
    {

        $productsInPack = array();
        $productsAttributeItem = array();

        if (Pack::isPack((int) $this->id)) {

            $getProductInPack = Db::getInstance()->executeS('SELECT id_product_item, id_product_attribute_item FROM '._DB_PREFIX_.'pack WHERE id_product_pack = '.$this->id.' GROUP BY id_product_item');

            if ($getProductInPack > 0){
                foreach ($getProductInPack as $productPack){
                    if ($productPack['id_product_attribute_item']){
                        $getAttributeImage = Db::getInstance()->executeS('SELECT id_image FROM '._DB_PREFIX_.'product_attribute_image WHERE id_product_attribute = '.$productPack['id_product_attribute_item'].' GROUP BY id_image');
                        foreach ($getAttributeImage as $attributeImages){
                            $productsAttributeItem[] = $attributeImages['id_image'];
                        }
                    } 
                    
                    if ($productPack['id_product_attribute_item'] == '0'){
                        $getImage = Db::getInstance()->executeS('SELECT id_image FROM '._DB_PREFIX_.'image WHERE id_product = '.$productPack['id_product_item']);
                        foreach ($getImage as $image){
                            $productsAttributeItem[] = $image['id_image'];
                        }
                    }

                    $productsInPack[] = $productPack['id_product_item'];
                }
            }
        }


        if ($productsInPack){
            $getProducts = implode(', ', $productsInPack);
        } else {
            $getProducts = $this->id;
        }

        if ($productsAttributeItem){
            $whereAttributeImages = ' AND i.id_image IN ('.implode(', ', $productsAttributeItem).')';
        } else {
            $whereAttributeImages = '';
        }

        $query = '
        SELECT image_shop.`cover`, i.`id_image`, il.`legend`, i.`position`
        FROM `' . _DB_PREFIX_ . 'image` i
        ' . Shop::addSqlAssociation('image', 'i') . '
        LEFT JOIN `' . _DB_PREFIX_ . 'image_lang` il ON (i.`id_image` = il.`id_image` AND il.`id_lang` = ' . (int) $id_lang . ')
        WHERE i.`id_product` IN (' . $getProducts . ')'.$whereAttributeImages.'
        ORDER BY `position`';

        return Db::getInstance()->executeS($query);

    }

    

    public function __construct($id_product = null, $full = false, $id_lang = null, $id_shop = null, \Context $context = null) 
    {
        parent::__construct($id_product, $full, $id_lang, $id_shop, $context);
    }
}

 

FO:

obrazek.png.eba29818874e011905c633ad54d62c31.png

That's way bettter but it seems that Prestashop 1.7 will not use override anymore

Source :

 

 

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...