Home / Tutorials / PrestaShop 1.7 Tutorials / Amazing PrestaShop Project: Disable attribute out of stock with currently attribute in product prestashop 1.7

Amazing PrestaShop Project: Disable attribute out of stock with currently attribute in product prestashop 1.7

1 Star2 Stars3 Stars4 Stars5 Stars (1 votes, average: 5.00 out of 5)
Loading...

You know, Leotheme is one of the best provider marketplaces in PrestaShop for PrestaShop Themes, PrestaShop Module & Custom Work.

At present, we have a lot of power customization projects in PrestaShop. And today, we are pleased to introduce our project and we would like to share tips for all. Hope that this blog will help you well.

Firstly, the fact that Prestashop has the option to hide attribute doesn’t exist.
For example: You have size (36,37,38,39) and color (red, blue).
If you don’t input size 36 with red color. Prestashop has option PS_DISP_UNAVAILABLE_ATTR, if you turn on it, the red color will not display when you click on size 36.
That is very good, but that is not enough.

3 days ago, I got this request of my customer.

So far, all of our products have had only one variation, the shoe size. In the back office, I have activated that only existing variants are displayed on the article page. This works even if the Product has only one variant.

Now we have products with two variants (color and size) and unfortunately, the automatic filtering does not work anymore.
If the customer chooses a color, then only the available sizes should be displayed, but also unavailable sizes are displayed. If the customer then selects, he jumps to another hue. Not existing sizes are not filtered out. The customer should only see existing variationsAnother possibility is that non-existent combination are deactivated by a cross.

So I use 3 days to research it.
And I have to add my code to the Prestashop core to solver it.
If you are a developer, you can follow my code to add this function, it will help your site run perfectly.
I edit function assignAttributesGroups in controller/font/ProductController.php.


protected function assignAttributesGroups($product_for_template = null)
{
$colors = array();
$groups = array();
$this->combinations = array();
$selected_quantities = array();

// @todo (RM) should only get groups and not all declination ?
$attributes_groups = $this->product->getAttributesGroups($this->context->language->id);
if (is_array($attributes_groups) && $attributes_groups) {
$combination_images = $this->product->getCombinationImages($this->context->language->id);
$combination_prices_set = array();
foreach ($attributes_groups as $k => $row) {
// Color management
if (isset($row['is_color_group']) && $row['is_color_group'] && (isset($row['attribute_color']) && $row['attribute_color']) || (file_exists(_PS_COL_IMG_DIR_ . $row['id_attribute'] . '.jpg'))) {
$colors[$row['id_attribute']]['value'] = $row['attribute_color'];
$colors[$row['id_attribute']]['name'] = $row['attribute_name'];
if (!isset($colors[$row['id_attribute']]['attributes_quantity'])) {
$colors[$row['id_attribute']]['attributes_quantity'] = 0;
}
$colors[$row['id_attribute']]['attributes_quantity'] += (int) $row['quantity'];
}
if (!isset($groups[$row['id_attribute_group']])) {
$groups[$row['id_attribute_group']] = array(
'group_name' => $row['group_name'],
'name' => $row['public_group_name'],
'group_type' => $row['group_type'],
'default' => -1,
);
}

$groups[$row['id_attribute_group']]['attributes'][$row['id_attribute']] = array(
'name' => $row['attribute_name'],
'html_color_code' => $row['attribute_color'],
'texture' => (@filemtime(_PS_COL_IMG_DIR_ . $row['id_attribute'] . '.jpg')) ? _THEME_COL_DIR_ . $row['id_attribute'] . '.jpg' : '',
'selected' => (isset($product_for_template['attributes'][$row['id_attribute_group']]['id_attribute']) && $product_for_template['attributes'][$row['id_attribute_group']]['id_attribute'] == $row['id_attribute']) ? true : false,
);

if((isset($product_for_template['attributes'][$row['id_attribute_group']]['id_attribute']) && $product_for_template['attributes'][$row['id_attribute_group']]['id_attribute'] == $row['id_attribute'])) {
$selected_quantities[$row['id_attribute_group']][$row['id_product_attribute']] = $row['quantity'];
}

//$product.attributes.$id_attribute_group.id_attribute eq $id_attribute
if ($row['default_on'] && $groups[$row['id_attribute_group']]['default'] == -1) {
$groups[$row['id_attribute_group']]['default'] = (int) $row['id_attribute'];
}
if (!isset($groups[$row['id_attribute_group']]['attributes_quantity'][$row['id_attribute']])) {
$groups[$row['id_attribute_group']]['attributes_quantity'][$row['id_attribute']] = 0;
}
$groups[$row['id_attribute_group']]['attributes_quantity'][$row['id_attribute']] += (int) $row['quantity'];

$this->combinations[$row['id_product_attribute']]['attributes_values'][$row['id_attribute_group']] = $row['attribute_name'];
$this->combinations[$row['id_product_attribute']]['attributes'][] = (int) $row['id_attribute'];
$this->combinations[$row['id_product_attribute']]['price'] = (float) $row['price'];

// Call getPriceStatic in order to set $combination_specific_price
if (!isset($combination_prices_set[(int) $row['id_product_attribute']])) {
$combination_specific_price = null;
Product::getPriceStatic((int) $this->product->id, false, $row['id_product_attribute'], 6, null, false, true, 1, false, null, null, null, $combination_specific_price);
$combination_prices_set[(int) $row['id_product_attribute']] = true;
$this->combinations[$row['id_product_attribute']]['specific_price'] = $combination_specific_price;
}
$this->combinations[$row['id_product_attribute']]['ecotax'] = (float) $row['ecotax'];
$this->combinations[$row['id_product_attribute']]['weight'] = (float) $row['weight'];
$this->combinations[$row['id_product_attribute']]['quantity'] = (int) $row['quantity'];
$this->combinations[$row['id_product_attribute']]['reference'] = $row['reference'];
$this->combinations[$row['id_product_attribute']]['unit_impact'] = $row['unit_price_impact'];
$this->combinations[$row['id_product_attribute']]['minimal_quantity'] = $row['minimal_quantity'];
if ($row['available_date'] != '0000-00-00' && Validate::isDate($row['available_date'])) {
$this->combinations[$row['id_product_attribute']]['available_date'] = $row['available_date'];
$this->combinations[$row['id_product_attribute']]['date_formatted'] = Tools::displayDate($row['available_date']);
} else {
$this->combinations[$row['id_product_attribute']]['available_date'] = $this->combinations[$row['id_product_attribute']]['date_formatted'] = '';
}

if (!isset($combination_images[$row['id_product_attribute']][0]['id_image'])) {
$this->combinations[$row['id_product_attribute']]['id_image'] = -1;
} else {
$this->combinations[$row['id_product_attribute']]['id_image'] = $id_image = (int) $combination_images[$row['id_product_attribute']][0]['id_image'];
if ($row['default_on']) {
foreach ($this->context->smarty->tpl_vars['product']->value['images'] as $image) {
if ($image['cover'] == 1) {
$current_cover = $image;
}
}
if (!isset($current_cover)) {
$current_cover = array_values($this->context->smarty->tpl_vars['product']->value['images'])[0];
}

if (is_array($combination_images[$row['id_product_attribute']])) {
foreach ($combination_images[$row['id_product_attribute']] as $tmp) {
if ($tmp['id_image'] == $current_cover['id_image']) {
$this->combinations[$row['id_product_attribute']]['id_image'] = $id_image = (int) $tmp['id_image'];
break;
}
}
}

if ($id_image > 0) {
if (isset($this->context->smarty->tpl_vars['images']->value)) {
$product_images = $this->context->smarty->tpl_vars['images']->value;
}
if (isset($product_images) && is_array($product_images) && isset($product_images[$id_image])) {
$product_images[$id_image]['cover'] = 1;
$this->context->smarty->assign('mainImage', $product_images[$id_image]);
if (count($product_images)) {
$this->context->smarty->assign('images', $product_images);
}
}

$cover = $current_cover;

if (isset($cover) && is_array($cover) && isset($product_images) && is_array($product_images)) {
$product_images[$cover['id_image']]['cover'] = 0;
if (isset($product_images[$id_image])) {
$cover = $product_images[$id_image];
}
$cover['id_image'] = (Configuration::get('PS_LEGACY_IMAGES') ? ($this->product->id . '-' . $id_image) : (int) $id_image);
$cover['id_image_only'] = (int) $id_image;
$this->context->smarty->assign('cover', $cover);
}
}
}
}
}

foreach ($attributes_groups as $k => $row) {
foreach ($selected_quantities as $key_q => $value_q) {
if(array_key_exists($row['id_product_attribute'], $value_q)){
if(isset($groups[$row['id_attribute_group']]['attributes'][$row['id_attribute']])) {
$groups[$row['id_attribute_group']]['attributes'][$row['id_attribute']]['quantity'] = $value_q[$row['id_product_attribute']];
}
}
}
}

// wash attributes list depending on available attributes depending on selected preceding attributes
$current_selected_attributes = array();
$count = 0;
foreach ($groups as &$group) {
++$count;
if ($count > 1) {
//find attributes of current group, having a possible combination with current selected
$id_product_attributes = array(0);
$query = 'SELECT pac.`id_product_attribute`
FROM `' . _DB_PREFIX_ . 'product_attribute_combination` pac
INNER JOIN `' . _DB_PREFIX_ . 'product_attribute` pa ON pa.id_product_attribute = pac.id_product_attribute
WHERE id_product = ' . $this->product->id . ' AND id_attribute IN (' . implode(',', array_map('intval', $current_selected_attributes)) . ')
GROUP BY id_product_attribute
HAVING COUNT(id_product) = ' . count($current_selected_attributes);
if ($results = Db::getInstance()->executeS($query)) {
foreach ($results as $row) {
$id_product_attributes[] = $row['id_product_attribute'];
}
}
$id_attributes = Db::getInstance()->executeS('SELECT `id_attribute` FROM `' . _DB_PREFIX_ . 'product_attribute_combination` pac2
WHERE `id_product_attribute` IN (' . implode(',', array_map('intval', $id_product_attributes)) . ')
AND id_attribute NOT IN (' . implode(',', array_map('intval', $current_selected_attributes)) . ')');
foreach ($id_attributes as $k => $row) {
$id_attributes[$k] = (int) $row['id_attribute'];
}
foreach ($group['attributes'] as $key => $attribute) {
if (!in_array((int) $key, $id_attributes)) {
unset($group['attributes'][$key]);
unset($group['attributes_quantity'][$key]);
}
}
}
//find selected attribute or first of group
$index = 0;
$current_selected_attribute = 0;
foreach ($group['attributes'] as $key => $attribute) {
if ($index === 0) {
$current_selected_attribute = $key;
}
if ($attribute['selected']) {
$current_selected_attribute = $key;
break;
}
}
if ($current_selected_attribute > 0) {
$current_selected_attributes[] = $current_selected_attribute;
}
}
// wash attributes list (if some attributes are unavailables and if allowed to wash it)
if (!Product::isAvailableWhenOutOfStock($this->product->out_of_stock) && Configuration::get('PS_DISP_UNAVAILABLE_ATTR') == 0) {
foreach ($groups as &$group) {
foreach ($group['attributes_quantity'] as $key => &$quantity) {
if ($quantity <= 0) {
unset($group['attributes'][$key]);
}
}
}

foreach ($colors as $key => $color) {
if ($color['attributes_quantity'] <= 0) {
unset($colors[$key]);
}
}
}

foreach ($this->combinations as $id_product_attribute => $comb) {
$attribute_list = '';
foreach ($comb['attributes'] as $id_attribute) {
$attribute_list .= '\'' . (int) $id_attribute . '\',';
}
$attribute_list = rtrim($attribute_list, ',');
$this->combinations[$id_product_attribute]['list'] = $attribute_list;
}

$this->context->smarty->assign(array(
'groups' => $groups,
'colors' => (count($colors)) ? $colors : false,
'combinations' => $this->combinations,
'combinationImages' => $combination_images,
));
} else {
$this->context->smarty->assign(array(
'groups' => array(),
'colors' => false,
'combinations' => array(),
'combinationImages' => array(),
));
}
}

and in the file /themes/YOURTHEME/templates/catalog/_partials/product-variants.tpl

I added this code:

{**
* 2007-2017 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright PrestaShop SA
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
* International Registered Trademark & Property of PrestaShop SA
*}

{foreach from=$groups key=id_attribute_group item=group} {if !empty($group.attributes)}

{$group.name} {if $group.group_type == 'select'}

{elseif $group.group_type == 'color'}

    • {foreach from=$group.attributes key=id_attribute item=group_attribute}

{/foreach}

{elseif $group.group_type == 'radio'}

    • {foreach from=$group.attributes key=id_attribute item=group_attribute}

{/foreach}

{/if}

{/if} {/foreach}

you can see, I add class=”disable” for attribute have quantity =0

In theme.css file

you only need add code at the end of file

.product-variants > .product-variants-item ul li label.disable{display:none}

 

You can see demo of my customer website

leotheme custom work

DEMO

 

If you are a developer I can make sure you can do it.

If you are business man, please send all your requirements to us via: leotheme@gmail.com

SEND REQUIREMENT

Skype: trandinhnghiait

Go to top

About admin@leotheme.com

Check Also

how-to-use-image-hotspot-widget-prestashop

How to use Image Hotspot Widget Prestashop

Hotspot Image Widget presents a single image with hotspots on it. The hotspots can be …

Leave a Reply

Your email address will not be published. Required fields are marked *