Jump to content

Sort Product «Attributes»


Recommended Posts

Hello all!

I've realized that the current SVN version of PrestaShop is not sorting correctly product attributes. To correct this you can do the following changes on your source code:

(obviously, you don't have to include «[iNI] Infordesign» and «[END] Infordesign» comments, they're on the code I posted just to indicate were the changes have been done.)

NOTE: The idea of hiding "01.", "02.", ... from the Attribute name was from «vinoalvino» user, from this forum, as posted here: http://www.prestashop.com/forums/viewthread/3139/

FILE: /classes/Product.php
TODO: Change «getAttributesGroups» to this:

   public function getAttributesGroups($id_lang)
   {
       $result = Db::getInstance()->ExecuteS('
       SELECT ag.`id_attribute_group`, agl.`name` AS group_name, agl.`public_name` AS public_group_name, a.`id_attribute`, al.`name` AS attribute_name,
       a.`color` AS attribute_color, pa.`id_product_attribute`, pa.`quantity`, pa.`price`, pa.`ecotax`, pa.`weight`, pa.`default_on`, pa.`reference`
       FROM `'._DB_PREFIX_.'product_attribute` pa
       LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON pac.`id_product_attribute` = pa.`id_product_attribute`
       LEFT JOIN `'._DB_PREFIX_.'attribute` a ON a.`id_attribute` = pac.`id_attribute`
       LEFT JOIN `'._DB_PREFIX_.'attribute_group` ag ON ag.`id_attribute_group` = a.`id_attribute_group`
       LEFT JOIN `'._DB_PREFIX_.'attribute_lang` al ON a.`id_attribute` = al.`id_attribute`
       LEFT JOIN `'._DB_PREFIX_.'attribute_group_lang` agl ON ag.`id_attribute_group` = agl.`id_attribute_group`
       WHERE pa.`id_product` = '.intval($this->id).'
       AND al.`id_lang` = '.intval($id_lang).'
       AND agl.`id_lang` = '.intval($id_lang).

       // [iNI] Infordesign
       'ORDER BY agl.`name`, al.`name`, pa.`id_product_attribute`');

       $resultsArray = array();
       foreach ($result AS $row)
       {
           $row['attribute_name'] = preg_replace('/^[0-9]+\./', '', $row['attribute_name']);
           $resultsArray[] = $row;
       }
       return $resultsArray;
       // [END] Infordesign
   }

Link to comment
Share on other sites

FILE: /classes/Cart.php
TODO: Change «getProducts» to this:

public function getProducts($refresh = false, $id_product = false)
   {

          ( . . . )

           /* Add attributes to the SQL result if needed */
           if (isset($row['id_product_attribute']) AND Validate::isUnsignedInt($row['id_product_attribute']))
           {
               $result2 = Db::getInstance()->ExecuteS('
               SELECT agl.`public_name` AS public_group_name, al.`name` AS attribute_name
               FROM `'._DB_PREFIX_.'product_attribute_combination` pac
               LEFT JOIN `'._DB_PREFIX_.'attribute` a ON a.`id_attribute` = pac.`id_attribute`
               LEFT JOIN `'._DB_PREFIX_.'attribute_group` ag ON ag.`id_attribute_group` = a.`id_attribute_group`
               LEFT JOIN `'._DB_PREFIX_.'attribute_lang` al ON (a.`id_attribute` = al.`id_attribute` AND al.`id_lang` = '.intval($this->id_lang).')
               LEFT JOIN `'._DB_PREFIX_.'attribute_group_lang` agl ON (ag.`id_attribute_group` = agl.`id_attribute_group` AND agl.`id_lang` = '.intval($this->id_lang).')
               WHERE pac.`id_product_attribute` = '.intval($row['id_product_attribute'].' ORDER BY al.`name`'));

               $attributesList = '';
               $attributesListSmall = '';
               if ($result2)
                   foreach ($result2 AS $k2 => $row2)
                   {
                       // [iNI] Infordesign
                       $attributesList .= $row2['public_group_name'].': '.preg_replace('/^[0-9]+\./', '', $row2['attribute_name']).', ';
                       $attributesListSmall .= preg_replace('/^[0-9]+\./', '', $row2['attribute_name']).', ';
                       // [END] Infordesign
                   }
               $attributesList = rtrim($attributesList, ', ');
               $attributesListSmall = rtrim($attributesListSmall, ', ');
               $row['attributes'] = $attributesList;
               $row['attributes_small'] = $attributesListSmall;
               $row['stock_quantity'] = $row['quantity_attribute'];
           }
           $products[] = $row;
       }
       $this->_products = $products;
       return $this->_products;
   }

Link to comment
Share on other sites

FILE: /classes/Attribute.php
TODO: Change «getAttributes» to this:

   static public function getAttributes($id_lang, $notNull = false)
   {
      $result = Db::getInstance()->ExecuteS('
       SELECT ag.*, agl.*, a.`id_attribute`, al.`name`, agl.`name` AS `attribute_group`
       FROM `'._DB_PREFIX_.'attribute_group` ag
       LEFT JOIN `'._DB_PREFIX_.'attribute_group_lang` agl ON (ag.`id_attribute_group` = agl.`id_attribute_group` AND agl.`id_lang` = '.intval($id_lang).')
       LEFT JOIN `'._DB_PREFIX_.'attribute` a ON a.`id_attribute_group` = ag.`id_attribute_group`
       LEFT JOIN `'._DB_PREFIX_.'attribute_lang` al ON (a.`id_attribute` = al.`id_attribute` AND al.`id_lang` = '.intval($id_lang).')
       '.($notNull ? 'WHERE a.`id_attribute` IS NOT NULL AND al.`name` IS NOT NULL' : '').

       // [iNI] Infordesign
       'ORDER BY agl.`name` ASC, al.`name` ASC');

       $resultsArray = array();
       foreach ($result AS $row)
       {
           $row['name'] = preg_replace('/^[0-9]+\./', '', $row['name']);
           $resultsArray[] = $row;
       }
       return $resultsArray;
       // [END] Infordesign
   }

Link to comment
Share on other sites

FILE: /classes/AttributeGroup.php
TODO: Change «getAttributes» to this:

   static public function getAttributes($id_lang, $id_attribute_group)
   {
       $result = Db::getInstance()->ExecuteS('
       SELECT *
       FROM `'._DB_PREFIX_.'attribute` a
       LEFT JOIN `'._DB_PREFIX_.'attribute_lang` al ON (a.`id_attribute` = al.`id_attribute` AND al.`id_lang` = '.intval($id_lang).')
       WHERE a.`id_attribute_group` = '.intval($id_attribute_group).

       // [iNI] Infordesign
       'ORDER BY `name`');

           $resultsArray = array();
           foreach ($result AS $row)
           {
           $row['name'] = preg_replace('/^[0-9]+\./', '', $row['name']);
           $resultsArray[] = $row;
       }
       return $resultsArray;
       // [END] Infordesign
   }

Link to comment
Share on other sites

  • 2 weeks later...
  • 4 weeks later...
Hi,

I copied the code as per the above, but i just get a blank screen?

Any ideas

Thanks

Jarno


Well, that could be a result of a php error somewhere (could be a missing ";", a non-closed "{", or any syntax error). Please, check your code and see your php error log to find out what is causing that error.
Link to comment
Share on other sites

Hi there,
I got this error after changing the above:
Warning: Invalid argument supplied for foreach() in /sites/prestabuild/classes/Product.php on line 1404
I'm running on Apache 2.2.3, PHP 5.2.1 and MySQL 5.0.38

// Fredrik

Link to comment
Share on other sites

  • 1 month later...
  • 4 weeks later...

Hi,

I have been pulling my hair out over this for the last couple of days.

I have implemented the code and order the attributes 01.S , 02.M , 03.L

When I make the changes I actually lose the attributes in the cart box - and the only error I come up with in the error log is related to the LoyaltyModule.php on line 111 - it is:

foreach ($attributesGroups AS $attributesGroup)

so obviously (dangerous word) is has to with the variable $attributesGroups which I guess are defined in getAttributesGroups in product.php

Could someone please post the four files to see if they work on my site (Version 1.1.0.5)?

Thanks

Link to comment
Share on other sites

OK I sorted it!

The code I used was the following (from the Spanish forum - you have to be multilingual round here!)

    public function getAttributesGroups($id_lang)
       {
           $result = Db::getInstance()->ExecuteS('
           SELECT ag.`id_attribute_group`, agl.`name` AS group_name, agl.`public_name` AS public_group_name, a.`id_attribute`, al.`name` AS attribute_name,
           a.`color` AS attribute_color, pa.`id_product_attribute`, pa.`quantity`, pa.`price`, pa.`ecotax`, pa.`weight`, pa.`id_image`,pa.`default_on`, pa.`reference`
           FROM `'._DB_PREFIX_.'product_attribute` pa
           LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON pac.`id_product_attribute` = pa.`id_product_attribute`
           LEFT JOIN `'._DB_PREFIX_.'attribute` a ON a.`id_attribute` = pac.`id_attribute`
           LEFT JOIN `'._DB_PREFIX_.'attribute_group` ag ON ag.`id_attribute_group` = a.`id_attribute_group`
           LEFT JOIN `'._DB_PREFIX_.'attribute_lang` al ON a.`id_attribute` = al.`id_attribute`
           LEFT JOIN `'._DB_PREFIX_.'attribute_group_lang` agl ON ag.`id_attribute_group` = agl.`id_attribute_group`
           WHERE pa.`id_product` = '.intval($this->id).'
           AND al.`id_lang` = '.intval($id_lang).'
           AND agl.`id_lang` = '.intval($id_lang).'
           ORDER BY agl.`name`, al.`name`, pa.`id_product_attribute`');

              /* Modify SQL result - hide 01. 02. */
           $resultsArray = array();
           foreach ($result AS $row)
           {
               $row['attribute_name'] = preg_replace('/^[0-9]+\./', '', $row['attribute_name']);
               $resultsArray[] = $row;
           }
           return $resultsArray;
       }



Note that this is slightly different to the code in http://www.prestashop.com/forums/viewthread/3139/ by
Infordesign

Thanks to everyone

What I would like to do now is to write it so that if an attribute has a number (begining with 0) then this reordering is done but if not then the order by name is used.

That way I can get 01.S, 02.M and 03.L working and 60 x 200, 100 x 200 in the right order without having to put the 01. etc. I have about 300 sizes to edit otherwise!

Up to now I can identify those attributes with zero in front and those without:

$resultsArray = array();
           foreach ($result AS $row)
           {   
               $zero = substr($row['attribute_name'],0,1);
               if ( $zero =="0")
               {

               $row['attribute_name'] = preg_replace('/^[0-9]+\./', '', $row['attribute_name']);
               $resultsArray[] = $row;
               }
               else {
               $row['attribute_name'] = $row['attribute_name'];
               $resultsArray[] = $row;
               }

           }
           return $resultsArray;



but I can't see how to re-order the sort to show those that don't have zero in teh standard way?

Link to comment
Share on other sites

Solved - this was easier than I thought.

$resultsArray = array();
           foreach ($result AS $row)
           {   
               $zero = substr($row['attribute_name'],0,1);
               if ( $zero =="0")
               { echo "0 case";

               $row['attribute_name'] = preg_replace('/^[0-9]+\./', '', $row['attribute_name']);
               $resultsArray[] = $row;
               }
               else {

               $row['attribute_name'] = $row['attribute_name'];

               $resultsArray[] = $row;

               sort($resultsArray);
               }

           }
           return $resultsArray;



This displays 01.S, 02.M, 03.L in the correct order and it shows attributes for size as 80x120, 105x120 in the right order without the need to place the 01. etc in front of all the measurements.

Hope this helps someone.

Link to comment
Share on other sites

  • 1 month later...

I used this but now have problems. The problem is that nothing is shown under "products in this catagory" in the admin part. The products are still on my shop, but i just can't see them in the admin part. Any inputs on where I went wrong?

Link to comment
Share on other sites

  • 2 months later...

This is a great post and really help me to organise the order of my attributes.

Is there a similar way of ordering the data within the attributes drop down menus as well? It defaults to alphabetical, which is a disaster if you want to do sizes or something similar. How about changing it to sort by the id? At least this way you can order them in the same order as you enter the attributes.

Any help would be very much appreciated.

Link to comment
Share on other sites

  • 4 weeks later...
  • 2 months later...
  • 2 months later...

I just wonder if these changes can still be used to solve sorting problem.Running Prestashop 1.2.5

I try to use it, but get an

Warning: Invalid argument supplied for foreach() in /var/www/vhosts/myshop.com/httpdocs/classes/Attribute.php on line 94

In getAttributes function I have changed $result variable to not get in any name conflict.

Any help will be appreciated

Kind Regards
Tom

Link to comment
Share on other sites

  • 5 months later...

Hello all,

got the same problem, tried out this hack but unfortunatley it doesnt work with my Version (1.3.1.1)

Have tried out only the /* Modify SQL result - hide 01. 02. */ in classes/product.php but as soon as it filters out the prefix the list gets sorted by the fitered-name and NOT by the real name - D'Oh!! ;-)

can anyone help?

Link to comment
Share on other sites

SOLVED! :-)

The hack worked in previous versions, it seems that in 1.3.1.1 the list gets sorted again before output, rendering the hack useless.

The solution i just found: Find the piece of code where it get sorted again and disable it. Well, i just found it:

In File product.php in the root directory, on line 279 find the site "wash attributes list", and a few lines below the command "natcasesort", disable it by adding // or /* - thats it.

Before:

           // wash attributes list (if some attributes are unavailables and if allowed to wash it)
           if (Configuration::get('PS_DISP_UNAVAILABLE_ATTR') == 0)
               foreach ($groups AS &$group)
                   foreach ($group['attributes_quantity'] AS $key => &$quantity)
                       if (!$quantity)
                           unset($group['attributes'][$key]);
           foreach($groups AS &$group)
           natcasesort($group['attributes']);
           foreach ($combinations AS $id_product_attribute => $comb)
           {



After:

           // wash attributes list (if some attributes are unavailables and if allowed to wash it)
           if (Configuration::get('PS_DISP_UNAVAILABLE_ATTR') == 0)
               foreach ($groups AS &$group)
                   foreach ($group['attributes_quantity'] AS $key => &$quantity)
                       if (!$quantity)
                           unset($group['attributes'][$key]);
           foreach($groups AS &$group)
           // natcasesort($group['attributes']);
           foreach ($combinations AS $id_product_attribute => $comb)
           {

  • Like 1
Link to comment
Share on other sites

  • 1 month later...

hi,

you can add this code

foreach ($group['attributes'] AS $key=>$value)
               {
                   $group['attributes'][$key] = preg_replace('/^[0-9]+\./', '', $value);
               }



just after

natcasesort($group['attributes']);

on product.php on presta 1.3.1.

With this code product attribute are sorted, but you can modify this sort like category with 00. for example before your attribute name.

Link to comment
Share on other sites

  • 2 months later...
  • 2 months later...
  • 2 weeks later...
  • 2 months later...

hi guys
my way to fix this bug to select attributes (and all other stuff you need) already in the right order. The problem is,that the attributes are in DB stored in text format. So you can just add "+0" to all *.php files into the order by....basicly,it changes the format from text to numeric,without affecting the colums- it is changed just for the Select statement

public function getAttributesGroups($id_lang)
   {
       return Db::getInstance()->ExecuteS('
       SELECT ag.`id_attribute_group`, ag.`is_color_group`, agl.`name` AS group_name, agl.`public_name` AS public_group_name, a.`id_attribute`, al.`name` AS attribute_name,
       a.`color` AS attribute_color, pa.`id_product_attribute`, pa.`quantity`, pa.`price`, pa.`ecotax`, pa.`weight`, pa.`default_on`, pa.`reference`
       FROM `'._DB_PREFIX_.'product_attribute` pa
       LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON pac.`id_product_attribute` = pa.`id_product_attribute`
       LEFT JOIN `'._DB_PREFIX_.'attribute` a ON a.`id_attribute` = pac.`id_attribute`
       LEFT JOIN `'._DB_PREFIX_.'attribute_group` ag ON ag.`id_attribute_group` = a.`id_attribute_group`
       LEFT JOIN `'._DB_PREFIX_.'attribute_lang` al ON a.`id_attribute` = al.`id_attribute`
       LEFT JOIN `'._DB_PREFIX_.'attribute_group_lang` agl ON ag.`id_attribute_group` = agl.`id_attribute_group`
       WHERE pa.`id_product` = '.intval($this->id).'
       AND al.`id_lang` = '.intval($id_lang).'
       AND agl.`id_lang` = '.intval($id_lang).'
       ORDER BY al.`name` + 0');
   }

Link to comment
Share on other sites

  • 5 months later...

FILE: /classes/Cart.php

TODO: Change «getProducts» to this:

public function getProducts($refresh = false, $id_product = false)
{
	   ( . . . )
		/* Add attributes to the SQL result if needed */
		if (isset($row['id_product_attribute']) AND Validate::isUnsignedInt($row['id_product_attribute']))
		{
			$result2 = Db::getInstance()->ExecuteS('
			SELECT agl.`public_name` AS public_group_name, al.`name` AS attribute_name
			FROM `'._DB_PREFIX_.'product_attribute_combination` pac
			LEFT JOIN `'._DB_PREFIX_.'attribute` a ON a.`id_attribute` = pac.`id_attribute`
			LEFT JOIN `'._DB_PREFIX_.'attribute_group` ag ON ag.`id_attribute_group` = a.`id_attribute_group`
			LEFT JOIN `'._DB_PREFIX_.'attribute_lang` al ON (a.`id_attribute` = al.`id_attribute` AND al.`id_lang` = '.intval($this->id_lang).')
			LEFT JOIN `'._DB_PREFIX_.'attribute_group_lang` agl ON (ag.`id_attribute_group` = agl.`id_attribute_group` AND agl.`id_lang` = '.intval($this->id_lang).')
			WHERE pac.`id_product_attribute` = '.intval($row['id_product_attribute'].' ORDER BY al.`name`'));
			$attributesList = '';
			$attributesListSmall = '';
			if ($result2)
				foreach ($result2 AS $k2 => $row2)
				{
					// [iNI] Infordesign
					$attributesList .= $row2['public_group_name'].': '.preg_replace('/^[0-9]+\./', '', $row2['attribute_name']).', ';
					$attributesListSmall .= preg_replace('/^[0-9]+\./', '', $row2['attribute_name']).', ';
					// [END] Infordesign
				}
			$attributesList = rtrim($attributesList, ', ');
			$attributesListSmall = rtrim($attributesListSmall, ', ');
			$row['attributes'] = $attributesList;
			$row['attributes_small'] = $attributesListSmall;
			$row['stock_quantity'] = $row['quantity_attribute'];
		}
		$products[] = $row;
	}
	$this->_products = $products;
	return $this->_products;
}

 

Changing cart.php with above coding doesn't work for me. Or am I missing something here? Btw, I just add it on the bottom of «getProducts».

 

Currently, I'm running on PS1.4.4.1.

 

Thanks!

Link to comment
Share on other sites

Changing cart.php with above coding doesn't work for me. Or am I missing something here? Btw, I just add it on the bottom of «getProducts».

 

Currently, I'm running on PS1.4.4.1.

 

That code fixes the sorting problem of earlier versions (only), it does not work in the latest version of PrestaShop.

Link to comment
Share on other sites

Finally problem solved by my own hand for PS 1.4.4.1. Change cart.php <<cacheSomeAttributesLists>>

 

Sorting and hide 01, 02, 03 number on both Cart Block & Shopping Cart Summary.

 

FROM:

foreach ($result as $row)
{
  self::$_attributesLists[$row['id_product_attribute'].'-'.$id_lang]['attributes'] .= $row['public_group_name'].' : '.$row['attribute_name'].', ';
  self::$_attributesLists[$row['id_product_attribute'].'-'.$id_lang]['attributes_small'] .= $row['attribute_name'].', ';
}

 

CHANGE TO:

foreach ($result as $row)
{
 self::$_attributesLists[$row['id_product_attribute'].'-'.$id_lang]['attributes'] .= preg_replace('/^[0-9]+./', '', $row['public_group_name']).' : '.$row['attribute_name'].', ';
 self::$_attributesLists[$row['id_product_attribute'].'-'.$id_lang]['attributes_small'] .= $row['attribute_name'].', ';
}

 

Cheers!

Link to comment
Share on other sites

  • 5 months later...

Solved - this was easier than I thought.

 

$resultsArray = array();
		foreach ($result AS $row)
		{  
			$zero = substr($row['attribute_name'],0,1);
			if ( $zero =="0")
			{ echo "0 case";

			$row['attribute_name'] = preg_replace('/^[0-9]+\./', '', $row['attribute_name']);
			$resultsArray[] = $row;
			}
			else {

			$row['attribute_name'] = $row['attribute_name'];

			$resultsArray[] = $row;

			sort($resultsArray);
			}

		}
		return $resultsArray;

 

This displays 01.S, 02.M, 03.L in the correct order and it shows attributes for size as 80x120, 105x120 in the right order without the need to place the 01. etc in front of all the measurements.

 

Hope this helps someone.

What page is this code from? I need to do this as well many thanks!!
Link to comment
Share on other sites

Finally problem solved by my own hand for PS 1.4.4.1. Change cart.php <<cacheSomeAttributesLists>>

 

Sorting and hide 01, 02, 03 number on both Cart Block & Shopping Cart Summary.

 

FROM:

foreach ($result as $row)
{
  self::$_attributesLists[$row['id_product_attribute'].'-'.$id_lang]['attributes'] .= $row['public_group_name'].' : '.$row['attribute_name'].', ';
  self::$_attributesLists[$row['id_product_attribute'].'-'.$id_lang]['attributes_small'] .= $row['attribute_name'].', ';
}

 

CHANGE TO:

foreach ($result as $row)
{
 self::$_attributesLists[$row['id_product_attribute'].'-'.$id_lang]['attributes'] .= preg_replace('/^[0-9]+./', '', $row['public_group_name']).' : '.$row['attribute_name'].', ';
 self::$_attributesLists[$row['id_product_attribute'].'-'.$id_lang]['attributes_small'] .= $row['attribute_name'].', ';
}

 

Cheers!

HolyGuyZ... Are you sure the page to change is "Cart.php"??? That page doesn't have the code you listed above?

 

 

Classes/Attribute.php

Classes/AttributeGroup.php

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

×
×
  • Create New...