Jump to content

modification fiche produit


Recommended Posts

Bonjour à tous,

 

Je souhaiterais faire des association de produits sur mes fiches produits mais je suis face à un mur...

 

J'explique rapidement :

 

J'ai une boutique qui vend des roues de voitures. Ces roues sont rangées dans des categories comme ceci :

 

Marque véhicule > Modèle véhicule > taille de roue

 

jusque la pas de souci... Mais maintenant je souhaite associer des pneus à ces roues et c'est là que sa ce corse !

 

Une roue peut recevoir différentes tailles de pneus en fonction du modèle de véhicule et de la taille de roue. Si j'associe un pneu à une roue, cette association ce retrouve sur tout les modèles de véhicule alors que dans mon cas les tailles de pneus varient d'un véhicule à un autre.

 

N'ayant pas trouver de moyen de gérer cette problématique j'ai donc créé dans mes catégories :

 

--> Roues

      --> Marque véhicule

            --> Modèle véhicule

                  --> Taille roue

 

--> Pneus

      --> Marque véhicule

            --> Modèle véhicule

                  --> Taille roue

 

Maintenant je me dis que je peux afficher sur ma fiche produit les produits contenu dans pneus sur ma fiche produit roues mais je sèche totalement sur ce coup la...

 

Je pense que je cherche trop compliqué peut être et qu'il y a plus simple... 

 

Quelqu'un aurait une idée ou une piste ?

 

 

Link to comment
Share on other sites

a mon avis il faut developper un module spécifique pour l'affichage des produits associés... sinon en mode bricolage, tu dupliques le module homefeatured que tu modifies pour obtenir les produits de ta catégorie, tu le hook dans la fiche produit, ca peut être une piste...

Edited by alexandre-km (see edit history)
Link to comment
Share on other sites

Oui je pense que je vais faire comme ca car je ne trouve pas d'autre solution et a vrai dire j'en vois pas pour le moment...

 

J'avais pensais filtrer l'affichage des produits en accessoires en récupérant les nom de marque modele etc sont identiques dans ma categorie jante et dans ma categorie pneus. C'est exactement la meme arborescence à l'interieure de ces deux categories, seul les id changes donc en utilisant les noms plutot que les id dans le filtre je pense que ca peut fonctionner...

Link to comment
Share on other sites

Malheureusement pour ce genre de problématique il faut déplier au max les sous-catégories quitte à avoir une redondance.

En fait je pense qu'il manque un niveau de catégorie à la base , au minimum dans les roues : 

--> Roues

      --> Marque véhicule

            --> Modèle véhicule

                  --> Taille roue

                        --> Pneus !

A ce stade il est facile de glisser dans l'arbo les pneus dispos puisqu'on est au bout de cette arbo (on a donc bien le modèle voulu et la taille de roue).

Bien sûr on aura pris soin de laisser le produit dans la catégorie Taille roue (et par défaut)

Il devient alors facile de récup l'id de la sous catégorie fille de la catégorie par défaut de la roue, de l'instancier et d'en lister les produits (voir Category->getProducts() dans la classe Category).

Link to comment
Share on other sites

j'essais de modifier la class accessory mais je ne ne trouve pour le moment, je souhaite essayer de modifier cette class en ajoutant une condition WHERE afin que les catégories correspondent

 

Categorie Jante         Catalogue Pneu

 

      Marque          =        Marque 

       Modele         =         Modele

        Taille            =         Taille

 

et ce afin d'afficher uniquement les pneus qui correspondent

 

Je pense qu'il faut modifier dans Product.php entre la ligne 3201et 3270

public static function getAccessoriesLight($id_lang, $id_product, Context $context = null)
	{
		if (!$context)
			$context = Context::getContext();

		$sql = 'SELECT p.`id_product`, p.`reference`, pl.`name`
				FROM `'._DB_PREFIX_.'accessory`
				LEFT JOIN `'._DB_PREFIX_.'product` p ON (p.`id_product`= `id_product_2`)
				'.Shop::addSqlAssociation('product', 'p').'
				LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (
					p.`id_product` = pl.`id_product`
					AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').'
				)
				WHERE `id_product_1` = '.(int)$id_product;

		return Db::getInstance()->executeS($sql);
	}

	/**
	 * Get product accessories
	 *
	 * @param integer $id_lang Language id
	 * @return array Product accessories
	 */
	public function getAccessories($id_lang, $active = true, Context $context = null)
	{
		if (!$context)
			$context = Context::getContext();

		$sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, pl.`description`, pl.`description_short`, pl.`link_rewrite`,
					pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, pl.`available_now`, pl.`available_later`,
					MAX(image_shop.`id_image`) id_image, il.`legend`, m.`name` as manufacturer_name, cl.`name` AS category_default,
					DATEDIFF(
						p.`date_add`,
						DATE_SUB(
							NOW(),
							INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY
						)
					) > 0 AS new
				FROM `'._DB_PREFIX_.'accessory`
				LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = `id_product_2`
				'.Shop::addSqlAssociation('product', 'p').'
				LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (
					p.`id_product` = pl.`id_product`
					AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').'
				)
				LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (
					product_shop.`id_category_default` = cl.`id_category`
					AND cl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('cl').'
				)
				LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`)'.
				Shop::addSqlAssociation('image', 'i', false, 'image_shop.cover=1').'
				LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (i.`id_image` = il.`id_image` AND il.`id_lang` = '.(int)$id_lang.')
				LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON (p.`id_manufacturer`= m.`id_manufacturer`)
				'.Product::sqlStock('p', 0).'
				WHERE `id_product_1` = '.(int)$this->id.
				($active ? ' AND product_shop.`active` = 1 AND product_shop.`visibility` != \'none\'' : '').'
				GROUP BY product_shop.id_product';

		if (!$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql))
			return false;
		foreach ($result as &$row)
			$row['id_product_attribute'] = Product::getDefaultAttribute((int)$row['id_product']);
		return $this->getProductsProperties($id_lang, $result);
	}

	public static function getAccessoryById($accessory_id)
	{
		return Db::getInstance()->getRow('SELECT `id_product`, `name` FROM `'._DB_PREFIX_.'product_lang` WHERE `id_product` = '.(int)$accessory_id);
	}
Edited by John77 (see edit history)
Link to comment
Share on other sites

Je fais suite au sujet. 

 

Donc après plusieurs tentatives non concluante par rapport au dernier post j'ai donc changé totalement de direction et cédé à la facilité !

 

J'ai créer un bouton en dessous du bouton ajouter au panier de la fiche produit comme ceci : 

  <div class="box-cart-bottom">
			<p id="add_to_cart" class="buttons_bottom_block no-print">
			<button type="submit" name="Submit" class="exclusive"> <span>Pack jantes + Pneus</span></button>
			</p>
               </div>

En cliquant sur ce bouton le produit s'ajoute directement au panier. Il faut maintenant que je génère un lien qui redirige vers la sous catégorie dans laquelle le visiteur ce trouve (C'est dans cette sous-catégorie que sont stocké les pneus correspondant à afficher)

 

En gros : Clique sur ajouter au panier = Ajouter au panier + redirection catégorie enfant de celle dans laquelle on se trouve.

 

Ce qui devrait donner quelque chose qui ressemble à cela :

<a href="{$link->getCategoryLink($child.id_category, $child.link_rewrite)|escape:'htmlall':'UTF-8'}" id="{$child.id_category}"> </a>

Mais bien évidement ca ne fonctionne pas... 

Link to comment
Share on other sites

Bon après un weekend à chercher, je ne parviens toujours pas à générer un lien vers la sous catégorie dans laquelle on se trouve lorsque que l'on est sur la fiche produit...  :unsure:

 

Je parviens toujours à ce résultat : 

<a href="../fr/-" id="">

Ce qui indique qu'aucune info n'est récupérer...

 

D'autre part, j'utilise un systeme de recherche rapide en ajax selon 3 criteres (marque, modele, taille) ce qui permet d'afficher la liste des produits de la catégorie choisi. 

 

Lorsque je suis sur la fiche produit dans le code source de la page ce module affiche :

<div class="block_content" style="float:left; width:50%;margin:30px 10px 21px 17px;">
<div class="categoriesnc_container" style="float:left;width:169px;margin:12px 7px;">
<div class="categoriesnc_select" >


<select id="lev1" class="lev form-control" style="float:left;width: 169px;" onchange="var lev = parseInt(this.id.substring(3)); deleteCats(lev); if (this.value.indexOf('|catID=') != -1) loadCat(parseInt(this.value.substring(this.value.indexOf('|catID=') + 7)), lev); else if (this.value != 0) window.location = this.value;">
	<option value="0">Marque</option>
	    <option value="../fr/17-marque|catID=17" selected="selected">Marque</option>
.......
.......
.......
.......
    </select>
</div></div>
	                				<div class="categoriesnc_container" style="float:left;width:169px;margin:12px 7px;">
	<div class="categoriesnc_select"">

<select id="lev2" class="lev form-control" style="float:left;width: 169px;" onchange="var lev = parseInt(this.id.substring(3)); deleteCats(lev); if (this.value.indexOf('catID=') != -1) loadCat(parseInt(this.value.substring(6)), lev); else if (this.value != 0) window.location = this.value;" onclick="deleteCats(2); loadCat(parseInt($('#lev1').val().substring($('#lev1').val().indexOf('|catID=')+7)), 1); this.onclick = null">
	<option value="0">Choisir catégorie</option>
	<option value="../fr/36-Modele|catID=36" selected="selected">Modele</option>    </select>
    </div>    </div>
    				<div class="categoriesnc_container" style="float:left;width:169px;margin:12px 7px;">
	<div class="categoriesnc_select"">

<select id="lev3" class="lev form-control" style="float:left;width: 169px;" onchange="var lev = parseInt(this.id.substring(3)); deleteCats(lev); if (this.value.indexOf('catID=') != -1) loadCat(parseInt(this.value.substring(6)), lev); else if (this.value != 0) window.location = this.value;" onclick="deleteCats(3); loadCat(parseInt($('#lev2').val().substring($('#lev2').val().indexOf('|catID=')+7)), 2); this.onclick = null">
	<option value="0">Choisir catégorie</option>
	<option value="../fr/953-Taille|catID=953" selected="selected">Taille</option>    </select>
    </div>    </div>

</div>

Dans le fichier PHP de ce module j'ai le code suivant :

<?php

if (!defined('_PS_VERSION_'))
	exit;

class CategoriesNC extends Module
{

	public function __construct()
	{
		$this->name = 'categoriesnc';
		$this->tab = 'front_office_features';
		$this->parents = array();

		$this->bootstrap = true;
		parent::__construct();

		$this->displayName = $this->l('AJAX Dropdown Categories');
		$this->description = $this->l('Dynamically loads product categories and presents them in dropdowns');

		// Check whether to enable retrocompability
		$this->retro = Tools::version_compare(_PS_VERSION_, '1.6.0.0');

		// Copy the appropriate CSS for the PrestaShop version
		$file_exists = file_exists(_PS_ROOT_DIR_.'/modules/'.$this->name.'/css/'.$this->name.'.css');

		if (!$file_exists && file_exists(_PS_ROOT_DIR_.'/modules/'.$this->name.'/css/original'.($this->retro ? '' : '16').'.css'))
			copy(_PS_ROOT_DIR_.'/modules/'.$this->name.'/css/original'.($this->retro ? '' : '16').
				'.css', _PS_ROOT_DIR_.'/modules/'.$this->name.'/css/'.$this->name.'.css');

		// Display a warning if there are no category levels
		$depth = $this->getNumberOfLevels(Tools::getValue('fromCategory', (int)Configuration::get('CATEG_NC_START_FROM_CATEG')));

		if (Configuration::get('CATEG_NC_NUM_PRODUCTS') > 0 || Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG') || $depth == 0)
			$this->warning = '';

		// Display a warning if the override is missing
		$has_override = false;

		if (Configuration::get('CATEG_NC_NUM_PRODUCTS') > 0 || Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG'))
		{
			$file_exists = file_exists(_PS_ROOT_DIR_.'/override/controllers/front/CategoryController.php');

			if ($file_exists)
			{
				$fname = _PS_ROOT_DIR_.'/override/controllers/front/CategoryController.php';
				$fhandle = fopen($fname, 'r');
				$content = (filesize($fname) > 0 ? fread($fhandle, filesize($fname)) : '');
				fclose($fhandle);

				$has_override = (strpos($content,
					'$this->context->smarty->assign(\'subcategories\', count($modifiedSubcategories) > 0 ? $modifiedSubcategories : null);'));
			}

			if (!$has_override)
				$this->warning .= $this->l('To display product numbers and hide empty categories on the category pages, you must').' '.
					(!$file_exists ? $this->l('copy') : $this->l('merge')).' modules/'.$this->name.'/override/controllers/front/CategoryController.php '.
					(!$file_exists ? $this->l('to') : $this->l('with')).' override/controllers/front/CategoryController.php';
		}
		else
			$has_override = true;

		if ($depth == 0)
			$this->warning .= (!$has_override ? '<br /><br />' : '').
				$this->l('There are no category levels - please add more levels or increase the maximum depth');

		if ($this->warning && Tools::getValue('configure') == $this->name)
			$this->adminDisplayWarning($this->warning);
	}

	public function install()
	{
		$sort = Configuration::get('BLOCK_CATEG_SORT');
		$sort_way = Configuration::get('BLOCK_CATEG_SORT_WAY');
		$footer_columns = Configuration::get('BLOCK_CATEG_NBR_COLUMN_FOOTER');

		if (!parent::install()
			|| !$this->registerHook('displayLeftColumn')
			|| !$this->registerHook('displayFooter')
			|| !$this->registerHook('displayHeader')
			// Temporary hooks. Do NOT hook any module on it. Some CRUD hook will replace them as soon as possible.
			|| !$this->registerHook('categoryAddition')
			|| !$this->registerHook('categoryUpdate')
			|| !$this->registerHook('categoryDeletion')
			|| !$this->registerHook('actionAdminMetaControllerUpdate_optionsBefore')
			|| !$this->registerHook('actionAdminLanguagesControllerStatusBefore')
			|| !$this->registerHook('addproduct')
			|| !$this->registerHook('deleteproduct')
/*			  || !$this->registerHook('updateproduct')*/
			|| !Configuration::updateValue('CATEG_NC_SECURE_KEY', Tools::strtoupper(Tools::passwdGen(16)))
			|| !Configuration::updateValue('CATEG_NC_MAX_DEPTH', 3)
			|| !Configuration::updateValue('CATEG_NC_SORT', $sort != false ? $sort : 0)
			|| !Configuration::updateValue('CATEG_NC_SORT_WAY', $sort_way != false ? $sort_way : 0)
			|| !Configuration::updateValue('CATEG_NC_NBR_COLUMN_FOOTER', $footer_columns != false ? $footer_columns : 1)
			|| !Configuration::updateValue('CATEG_NC_FOOTER_MAX_DEPTH', 2)
			|| !Configuration::updateValue('CATEG_NC_SHOW_GO_BUTTONS', 0)
			|| !Configuration::updateValue('CATEG_NC_SHOW_ALL_DROPDOWNS', 0)
			|| !Configuration::updateValue('CATEG_NC_FIX_IE_SELECT_WIDTH', 0)
			|| !Configuration::updateValue('CATEG_NC_NUM_PRODUCTS', 0)
			|| !Configuration::updateValue('CATEG_NC_HIDE_ZERO_COUNTS', 0)
			|| !Configuration::updateValue('CATEG_NC_HIDE_EMPTY_CATEG', 0)
			|| !Configuration::updateValue('CATEG_NC_SHOW_PRODUCTS', 0)
			|| !Configuration::updateValue('CATEG_NC_SAVE', 1)
			|| !Configuration::updateValue('CATEG_NC_RELOAD', 0)
			|| !Configuration::updateValue('CATEG_NC_START_FROM_CATEG', $this->context->shop->getCategory())
			|| !Configuration::updateValue('CATEG_NC_LABEL_POSITION', 0)
			|| !Configuration::updateValue('CATEG_NC_MAX_CATEGORIES', 500))
			return false;

		$depth = 0;
		$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT MAX(`level_depth`) as `max_depth` FROM `'._DB_PREFIX_.'category`');

		if (is_array($result) && count($result) > 0)
			$depth = $result[0]['max_depth'];

		$max_depth = Configuration::get('CATEG_NC_MAX_DEPTH');

		$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT `level_depth` FROM `'._DB_PREFIX_.'category` WHERE `id_category` = '.
			Configuration::get('CATEG_NC_START_FROM_CATEG'));

		if ($result != null && count($result) > 0)
			$depth -= $result[0]['level_depth'];

		if (Configuration::get('CATEG_NC_SHOW_PRODUCTS'))
			$depth++;

		if ($max_depth > 0 && $depth > $max_depth)
			$depth = $max_depth;

		$languages = Language::getLanguages(false);
		$default_language = (int)Configuration::get('PS_LANG_DEFAULT');
		$default_language_iso = 'en';

		foreach ($languages as $language)
			if ($language['id_lang'] == $default_language)
				$default_language_iso = $language['iso_code'];

		$translations = array();

		foreach ($languages as $language)
			$translations[$language['id_lang']] = array_key_exists($language['iso_code'], $this->default_labels) ?
				$this->default_labels[$language['iso_code']] :
				(array_key_exists($default_language_iso, $this->default_labels) ?
					$this->default_labels[$default_language_iso] :
					$this->default_labels['en']);

		for ($i = 1; $i <= $depth; $i++)
			if (!Configuration::updateValue('CATEG_NC_LABEL_'.$i, $translations))
					return false;

		return true;
	}

	public function uninstall()
	{
		if (!Configuration::deleteByName('CATEG_NC_SECURE_KEY')
			|| !Configuration::deleteByName('CATEG_NC_MAX_DEPTH')
			|| !Configuration::deleteByName('CATEG_NC_SORT')
			|| !Configuration::deleteByName('CATEG_NC_SORT_WAY')
			|| !Configuration::deleteByName('CATEG_NC_NBR_COLUMN_FOOTER')
			|| !Configuration::deleteByName('CATEG_NC_FOOTER_MAX_DEPTH')
			|| !Configuration::deleteByName('CATEG_NC_SHOW_GO_BUTTONS')
			|| !Configuration::deleteByName('CATEG_NC_SHOW_ALL_DROPDOWNS')
			|| !Configuration::deleteByName('CATEG_NC_FIX_IE_SELECT_WIDTH')
			|| !Configuration::deleteByName('CATEG_NC_NUM_PRODUCTS')
			|| !Configuration::deleteByName('CATEG_NC_HIDE_ZERO_COUNTS')
			|| !Configuration::deleteByName('CATEG_NC_HIDE_EMPTY_CATEG')
			|| !Configuration::deleteByName('CATEG_NC_SHOW_PRODUCTS')
			|| !Configuration::deleteByName('CATEG_NC_SAVE')
			|| !Configuration::deleteByName('CATEG_NC_RELOAD')
			|| !Configuration::deleteByName('CATEG_NC_START_FROM_CATEG')
			|| !Configuration::deleteByName('CATEG_NC_LABEL_POSITION')
			|| !Configuration::deleteByName('CATEG_NC_MAX_CATEGORIES')
			|| !parent::uninstall())
			return false;

		Db::getInstance(_PS_USE_SQL_SLAVE_)->Execute('
			DELETE FROM `'._DB_PREFIX_.'configuration_lang`
			WHERE `id_configuration` IN (
				SELECT `id_configuration`
				FROM `'._DB_PREFIX_.'configuration`
				WHERE `name` LIKE "CATEG_NC_LABEL_%")');

		Db::getInstance(_PS_USE_SQL_SLAVE_)->Execute('
			DELETE FROM `'._DB_PREFIX_.'configuration`
			WHERE `name` LIKE "CATEG_NC_LABEL_%"');

		Db::getInstance(_PS_USE_SQL_SLAVE_)->Execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'blockcategoriesnc_numproducts`');

		return true;
	}

	protected function getNumberOfLevels($from_category)
	{
		$depth = 0;
		$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
			SELECT MAX(`level_depth`) as `max_depth`
			FROM `'._DB_PREFIX_.'category`');

		if (is_array($result) && count($result) > 0)
			$depth = $result[0]['max_depth'];

		$max_depth = Configuration::get('CATEG_NC_MAX_DEPTH');

		$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
			SELECT `level_depth`
			FROM `'._DB_PREFIX_.'category`
			WHERE `id_category` = '.$from_category);

		if (Configuration::get('CATEG_NC_SHOW_PRODUCTS'))
			$depth++;

		if ($max_depth > 0 && $depth > $max_depth)
			$depth = $max_depth;

		return $depth - ($result != null && count($result) > 0 ? $result[0]['level_depth'] : 0);
	}

	public function headerHTML()
	{
		if (Tools::getValue('controller') != 'AdminModules' && Tools::getValue('configure') != $this->name)
			return;

		$this->context->controller->addJqueryUI('ui.sortable');
		/* Style & js for fieldset 'messages configuration' */
		$html = '<style type="text/css">
			@media (min-width: 768px) {
				#nc_panel {margin:40px 20px;}
				#left_panel {float: left; padding-right: 20px; margin-right: 20px; border-right: 1px solid #ccced7;}
				#right_panel {padding-left: 20px;}
			}
		</style>
		<div id="nc_panel">
			<div id="left_panel">
				<a href="http://www.nethercottconstructions.com" target="_blank"><img src="'.
				$this->_path.'img/logo.png" alt="'.$this->author.'" width="195" height="93" /></a>
			</div>
			<div id="right_panel">
				<h2>'.$this->displayName.' <span style="font-size:13px;">v'.$this->version.'</span></h2>
				<p><strong>'.$this->description.'</strong></p>
				<p>'.$this->l('For any technical questions or problems with this module, please').
				' <a href="http://www.nethercottconstructions.com/contact-us" target="_blank">'.$this->l('contact us').'</a></p>
			</div>
			<div class="clearfix"></div>
		</div>'.($this->retro ? '<br />' : '');

		return $html;
	}

	public function getContent()
	{
		$output = $this->headerHTML();

		$this->_errors = array();
		$allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
		if ($allow_employee_form_lang && !$this->context->cookie->employee_form_lang)
			$this->context->cookie->employee_form_lang = (int)Configuration::get('PS_LANG_DEFAULT');
		$use_lang_from_cookie = false;
		$this->_languages = Language::getLanguages();
		if ($allow_employee_form_lang)
			foreach ($this->_languages as $lang)
				if ($this->context->cookie->employee_form_lang == $lang['id_lang'])
					$use_lang_from_cookie = true;
		if (!$use_lang_from_cookie)
			$default_language = (int)Configuration::get('PS_LANG_DEFAULT');
		else
			$default_language = (int)$this->context->cookie->employee_form_lang;

		$languages = Language::getLanguages();
		$default_language_iso = 'en';

		foreach ($languages as $language)
			if ($language['id_lang'] == $default_language)
				$default_language_iso = $language['iso_code'];

		if (Tools::getValue('submitRestore'))
		{
			if (file_exists(_PS_MODULE_DIR_.$this->name.'/css/original'.($this->retro ? '' : '16').'.css'))
			{
				if (file_exists(_PS_MODULE_DIR_.$this->name.'/css/'.$this->name.'.css'))
					unlink(_PS_MODULE_DIR_.$this->name.'/css/'.$this->name.'.css');

				copy(_PS_MODULE_DIR_.$this->name.'/css/original'.($this->retro ? '' : '16').'.css', _PS_MODULE_DIR_.$this->name.'/css/'.$this->name.'.css');

				$output .= $this->displayConfirmation($this->l('Successfully restored CSS'));
			}
			else
				$this->_errors[] = $this->l('Could not find file').' original'.
					($this->retro ? '' : '16').'.css - '.$this->l('please restore the file from the module archive');
		}
		elseif (Tools::isSubmit('submitProductNumber'))
		{
			$num_products = (int)Tools::getValue('CATEG_NC_NUM_PRODUCTS');
			$hide_empty_categories = (int)Tools::getValue('CATEG_NC_HIDE_EMPTY_CATEG');
			$hide_zero_counts = (int)Tools::getValue('CATEG_NC_HIDE_ZERO_COUNTS');

			if ($num_products != 0 && $num_products != 1 && $num_products != 2)
				$this->_errors[] = $this->l('Product numbers: Invalid choice');
			if ($hide_zero_counts != 0 && $hide_zero_counts != 1)
				$this->_errors[] = $this->l('Hide zero counts: Invalid choice');

			if (count($this->_errors) == 0)
			{
				$current_num_products = Configuration::get('CATEG_NC_NUM_PRODUCTS');
				$current_hide_empty_categories = Configuration::get('CATEG_NC_HIDE_EMPTY_CATEGORIES');
				// Create cache for product numbers if necessary
				if ((int)$num_products == 2 && $current_num_products != 2 && $current_hide_empty_categories == 0)
				{
					Db::getInstance(_PS_USE_SQL_SLAVE_)->Execute('
						CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'blockcategoriesnc_numproducts` (
							`id_category` int(10) unsigned NOT NULL, `num_products` int(10) unsigned NOT NULL,
							PRIMARY KEY (`id_category`)
						) ENGINE=MyISAM DEFAULT CHARSET=utf8;');

					$this->createCache();
				}
				// Delete the cache if it is no longer necessary
				elseif ($current_num_products == 2 && (int)$num_products != 2 && $current_hide_empty_categories == 0)
					Db::getInstance(_PS_USE_SQL_SLAVE_)->Execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'blockcategoriesnc_numproducts`');

				Configuration::updateValue('CATEG_NC_NUM_PRODUCTS', (int)$num_products);
				Configuration::updateValue('CATEG_NC_HIDE_ZERO_COUNTS', (int)$hide_zero_counts);
				$output .= $this->displayConfirmation($this->l('Settings updated'));
			}
			else
			{
				$error_messages = '<ul>';

				foreach ($this->_errors as $error_message)
					$error_messages .= '<li>'.$error_message.'</li>';

				$error_messages .= '</ul>';

				$output .= $this->displayError($error_messages);
			}
		}
		elseif (Tools::isSubmit('submitCSS'))
		{
			$custom_css = Tools::getValue('CATEG_NC_CUSTOM_CSS');
			$previous_custom_css = '';
			$fname = _PS_MODULE_DIR_.$this->name.'/css/'.$this->name.'.css';

			if (file_exists($fname))
			{
				$fhandle = fopen($fname, 'r');
				$previous_custom_css = (filesize($fname) > 0 ? fread($fhandle, filesize($fname)) : '');
				fclose($fhandle);

				if (trim($custom_css) != trim($previous_custom_css))
				{
					unlink($fname);
					$fhandle = fopen($fname, 'w');
					fwrite($fhandle, $custom_css);
					fclose($fhandle);
				}
			}

			$output .= $this->displayConfirmation($this->l('Settings updated'));
		}
		elseif (Tools::isSubmit('submitTroubleshooting'))
		{
			$max_categories = (int)Tools::getValue('CATEG_NC_MAX_CATEGORIES');

			if (!is_numeric($max_categories) || (int)$max_categories < 0)
				$this->_errors[] = $this->l('Maximum categories per query: Must be a positive integer');

			if (count($this->_errors) == 0)
			{
				Configuration::updateValue('CATEG_NC_MAX_CATEGORIES', (int)$max_categories);
				$output .= $this->displayConfirmation($this->l('Settings updated'));
			}
			else
			{
				$error_messages = '<ul>';

				foreach ($this->_errors as $error_message)
					$error_messages .= '<li>'.$error_message.'</li>';

				$error_messages .= '</ul>';

				$output .= $this->displayError($error_messages);
			}
		}
		elseif (Tools::isSubmit('submitSettings'))
		{
			$max_depth = Tools::getValue('CATEG_NC_MAX_DEPTH');
			$num_products = (int)Tools::getValue('CATEG_NC_NUM_PRODUCTS');
			$show_go_buttons = (int)Tools::getValue('CATEG_NC_SHOW_GO_BUTTONS');
			$show_all_dropdowns = (int)Tools::getValue('CATEG_NC_SHOW_ALL_DROPDOWNS');
			$ie_fix = (int)Tools::getValue('CATEG_NC_FIX_IE_SELECT_WIDTH');
			$hide_empty_categories = (int)Tools::getValue('CATEG_NC_HIDE_EMPTY_CATEG');
			$show_products = (int)Tools::getValue('CATEG_NC_SHOW_PRODUCTS');
			$save = (int)Tools::getValue('CATEG_NC_SAVE');
			$reload = (int)Tools::getValue('CATEG_NC_RELOAD');
			$start_from_category = (int)Tools::getValue('from_category');
			$label_position = (int)Tools::getValue('CATEG_NC_LABEL_POSITION');
			$nbr_columns = (int)Tools::getValue('CATEG_NC_NBR_COLUMN_FOOTER', 4);
			$footer_max_depth = Tools::getValue('CATEG_NC_FOOTER_MAX_DEPTH');

			if (!is_numeric($max_depth) || (is_numeric($max_depth) && (int)$max_depth < 0))
				$this->_errors[] = $this->l('Maximum depth: Invalid number');
			if ($show_go_buttons != 0 && $show_go_buttons != 1)
				$this->_errors[] = $this->l('Show go buttons: Invalid choice');
			if ($show_all_dropdowns != 0 && $show_all_dropdowns != 1)
				$this->_errors[] = $this->l('Show all dropdowns: Invalid choice');
			if ($ie_fix != 0 && $ie_fix != 1)
				$this->_errors[] = $this->l('Fix IE select width: Invalid choice');
			if ($hide_empty_categories != 0 && $hide_empty_categories != 1)
				$this->_errors[] = $this->l('Hide empty categories: Invalid choice');
			if ($show_products != 0 && $show_products != 1)
				$this->_errors[] = $this->l('Show products: Invalid choice');
			if ($save != 0 && $save != 1)
				$this->_errors[] = $this->l('Save state: Invalid choice');
			if ($reload != 0 && $reload != 1)
				$this->_errors[] = $this->l('Reload categories: Invalid choice');
			if ($start_from_category <= 0)
				$this->_errors[] = $this->l('Start from: Invalid choice');
			if ($label_position != 0 && $label_position != 1)
				$this->_errors[] = $this->l('Dropdown label position: Invalid choice');
			if (!is_numeric($footer_max_depth) || (is_numeric($footer_max_depth) && (int)$footer_max_depth < 0))
				$this->_errors[] = $this->l('Footer maximum depth: Invalid number');

			if (count($this->_errors) == 0)
			{
				$current_num_products = Configuration::get('CATEG_NC_NUM_PRODUCTS');
				$current_hide_empty_categories = Configuration::get('CATEG_NC_HIDE_EMPTY_CATEGORIES');

				// Create cache for product numbers if necessary
				if ($hide_empty_categories == 1 && $current_hide_empty_categories == 0 && $current_num_products != 2)
				{
					Db::getInstance(_PS_USE_SQL_SLAVE_)->Execute('
						CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'blockcategoriesnc_numproducts` (
							`id_category` int(10) unsigned NOT NULL, `num_products` int(10) unsigned NOT NULL,
							PRIMARY KEY (`id_category`)
						) ENGINE=MyISAM DEFAULT CHARSET=utf8;');

					$this->createCache();
				}
				// Delete the cache if it is no longer necessary
				elseif ($hide_empty_categories == 0 && $current_hide_empty_categories == 1 && $current_num_products != 2)
					Db::getInstance(_PS_USE_SQL_SLAVE_)->Execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'blockcategoriesnc_numproducts`');

				Configuration::updateValue('CATEG_NC_MAX_DEPTH', (int)$max_depth);
				Configuration::updateValue('CATEG_NC_SHOW_GO_BUTTONS', (int)$show_go_buttons);
				Configuration::updateValue('CATEG_NC_SHOW_ALL_DROPDOWNS', (int)$show_all_dropdowns);
				Configuration::updateValue('CATEG_NC_FIX_IE_SELECT_WIDTH', (int)$ie_fix);
				Configuration::updateValue('CATEG_NC_HIDE_EMPTY_CATEG', (int)$hide_empty_categories);
				Configuration::updateValue('CATEG_NC_SAVE', (int)$save);
				Configuration::updateValue('CATEG_NC_RELOAD', (int)$reload);
				Configuration::updateValue('CATEG_NC_SHOW_PRODUCTS', (int)$show_products);
				Configuration::updateValue('CATEG_NC_START_FROM_CATEG', (int)$start_from_category);
				Configuration::updateValue('CATEG_NC_LABEL_POSITION', (int)$label_position);
				Configuration::updateValue('CATEG_NC_NBR_COLUMN_FOOTER', $nbr_columns);
				Configuration::updateValue('CATEG_NC_FOOTER_MAX_DEPTH', (int)$footer_max_depth);
				Configuration::updateValue('CATEG_NC_SORT_WAY', (int)Tools::getValue('CATEG_NC_SORT_WAY'));
				Configuration::updateValue('CATEG_NC_SORT', (int)Tools::getValue('CATEG_NC_SORT'));

				$depth = $this->getNumberOfLevels($start_from_category);

				for ($i = 1; $i <= $depth; $i++)
				{
					$translations = array();

					foreach ($languages as $language)
						$translations[$language['id_lang']] = (trim(Tools::getValue('CATEG_NC_LABEL_'.$i.'_'.$language['id_lang'])) == ''
							? (trim(Tools::getValue('CATEG_NC_LABEL_'.$i.'_'.$language['id_lang'])) == ''
								? (array_key_exists($language['iso_code'], $this->default_labels)
									? $this->default_labels[$language['iso_code']]
									: (array_key_exists($default_language_iso, $this->default_labels)
										? $this->default_labels[$default_language_iso]
										: $this->default_labels['en']))
								: Tools::getValue('CATEG_NC_LABEL_'.$i.'_'.$languages[$default_language]['id_lang']))
							: Tools::getValue('CATEG_NC_LABEL_'.$i.'_'.$language['id_lang']));

					Configuration::updateValue('CATEG_NC_LABEL_'.$i, $translations);
				}

				$output .= $this->displayConfirmation($this->l('Settings updated'));
			}
			else
			{
				$error_messages = '<ul>';

				foreach ($this->_errors as $error_message)
					$error_messages .= '<li>'.$error_message.'</li>';

				$error_messages .= '</ul>';

				$output .= $this->displayError($error_messages);
			}
		}
		elseif (Tools::isSubmit('submitRegenerateCache'))
		{
			if ((int)Configuration::get('CATEG_NC_NUM_PRODUCTS') == 2 || (int)Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG') == 1)
				$this->createCache();

			$output .= $this->displayConfirmation($this->l('Cache regeneration successful'));
		}
		elseif (Tools::isSubmit('submitRepairTree'))
		{
			$this->repairTree();
			$output .= $this->displayConfirmation($this->l('Tree repair successful'));
		}
		return $output.$this->renderForm();
	}

	public function renderForm()
	{
		$root_category = Category::getRootCategory();
		$root_category = array('id_category' => $root_category->id, 'name' => $root_category->name);

		$settings_form = array(
			'form' => array(
				'legend' => array(
					'title' => $this->l('Settings'),
					'icon' => 'icon-cogs',
					'image' => $this->retro ? $this->_path.'logo.gif' : null
				),
				'input' => array(
					array(
						'type' => 'text',
						'label' => $this->l('Maximum depth'),
						'name' => 'CATEG_NC_MAX_DEPTH',
						$this->retro ? 'desc' : 'hint' => $this->l('Set the maximum depth of sublevels displayed in this block (0 = infinite)'),
						'class' => 'fixed-width-xs'
					),
					array(
						'type' => 'select',
						'label' => $this->l('Sort'),
						'name' => 'CATEG_NC_SORT',
						$this->retro ? 'desc' : 'hint' => $this->l('Set whether to sort categories by name or position'),
						'default_value' => Tools::getValue('CATEG_NC_SORT', Configuration::get('CATEG_NC_SORT')),
						'options' => array(
							'query' => array(
								array(
									'id' => 1,
									'name' => $this->l('By name')
								),
								array(
									'id' => 0,
									'name' => $this->l('By position')
								),
							),
							'id' => 'id',
							'name' => 'name'
						)
					),
					array(
						'type' => 'select',
						'label' => $this->l('Sort order'),
						'name' => 'CATEG_NC_SORT_WAY',
						$this->retro ? 'desc' : 'hint' => $this->l('Set whether to sort categories ascending or descending'),
						'default_value' => Tools::getValue('CATEG_NC_SORT_WAY', Configuration::get('CATEG_NC_SORT_WAY')),
						'options' => array(
							'query' => array(
								array(
									'id' => 0,
									'name' => $this->l('Ascending')
								),
								array(
									'id' => 1,
									'name' => $this->l('Descending')
								),
							),
							'id' => 'id',
							'name' => 'name'
						)
					),
					array(
						'type' => 'text',
						'label' => $this->l('Number of footer columns'),
						'name' => 'CATEG_NC_NBR_COLUMN_FOOTER',
						'class' => 'fixed-width-xs',
						$this->retro ? 'desc' : 'hint' => $this->l('Set the number of footer columns'),
					),
					array(
						'type' => 'text',
						'label' => $this->l('Footer maximum depth'),
						'name' => 'CATEG_NC_FOOTER_MAX_DEPTH',
						$this->retro ? 'desc' : 'hint' => $this->l('Set the maximum depth of sublevels displayed in the footer (0 = infinite)'),
						'class' => 'fixed-width-xs'
					),
					array(
						'type' => $this->retro ? 'radio' : 'switch',
						'class' => $this->retro ? 'auto_width' : null,
						'is_bool' => true,
						'label' => $this->l('Show Go buttons'),
						'name' => 'CATEG_NC_SHOW_GO_BUTTONS',
						$this->retro ? 'desc' : 'hint' => $this->l('Whether to show Go buttons next to each dropdown to allow navigation to parent categories'),
						'values' => array(
									array(
										'id' => 'active_on',
										'value' => 1,
										'label' => $this->l('Enabled')
									),
									array(
										'id' => 'active_off',
										'value' => 0,
										'label' => $this->l('Disabled')
									)
								),
					),
					array(
						'type' => $this->retro ? 'radio' : 'switch',
						'is_bool' => true,
						'class' => $this->retro ? 'auto_width' : null,
						'label' => $this->l('Show all dropdowns'),
						'name' => 'CATEG_NC_SHOW_ALL_DROPDOWNS',
						$this->retro ? 'desc' : 'hint' => $this->l('Whether to start with the dropdowns displayed in a disabled state'),
						'values' => array(
									array(
										'id' => 'active_on',
										'value' => 1,
										'label' => $this->l('Enabled')
									),
									array(
										'id' => 'active_off',
										'value' => 0,
										'label' => $this->l('Disabled')
									)
								),
					),
					array(
						'type' => $this->retro ? 'radio' : 'switch',
						'is_bool' => true,
						'class' => $this->retro ? 'auto_width' : null,
						'label' => $this->l('Fix IE select width'),
						'name' => 'CATEG_NC_FIX_IE_SELECT_WIDTH',
						$this->retro ? 'desc' : 'hint' => $this->l('Adds code to fix a display bug with long category names in IE8 and below'),
						'values' => array(
									array(
										'id' => 'active_on',
										'value' => 1,
										'label' => $this->l('Enabled')
									),
									array(
										'id' => 'active_off',
										'value' => 0,
										'label' => $this->l('Disabled')
									)
								),
					),
					array(
						'type' => $this->retro ? 'radio' : 'switch',
						'is_bool' => true,
						'class' => $this->retro ? 'auto_width' : null,
						'label' => $this->l('Hide empty categories'),
						'name' => 'CATEG_NC_HIDE_EMPTY_CATEG',
						$this->retro ? 'desc' : 'hint' => $this->l('Hide categories that do not contain any products unless subcategories have products'),
						'values' => array(
									array(
										'id' => 'active_on',
										'value' => 1,
										'label' => $this->l('Enabled')
									),
									array(
										'id' => 'active_off',
										'value' => 0,
										'label' => $this->l('Disabled')
									)
								),
					),
					array(
						'type' => $this->retro ? 'radio' : 'switch',
						'is_bool' => true,
						'class' => $this->retro ? 'auto_width' : null,
						'label' => $this->l('Save state'),
						'name' => 'CATEG_NC_SAVE',
						$this->retro ? 'desc' : 'hint' => $this->l('Set whether to keep categories open when the page changes'),
						'values' => array(
									array(
										'id' => 'active_on',
										'value' => 1,
										'label' => $this->l('Enabled')
									),
									array(
										'id' => 'active_off',
										'value' => 0,
										'label' => $this->l('Disabled')
									)
								),
					),
					array(
						'type' => $this->retro ? 'radio' : 'switch',
						'is_bool' => true,
						'class' => $this->retro ? 'auto_width' : null,
						'label' => $this->l('Reload categories'),
						'name' => 'CATEG_NC_RELOAD',
						$this->retro ? 'desc' : 'hint' => $this->l('Set whether to reload categories when the page changes'),
						'values' => array(
									array(
										'id' => 'active_on',
										'value' => 1,
										'label' => $this->l('Enabled')
									),
									array(
										'id' => 'active_off',
										'value' => 0,
										'label' => $this->l('Disabled')
									)
								),
					),
					array(
						'type' => $this->retro ? 'radio' : 'switch',
						'is_bool' => true,
						'class' => $this->retro ? 'auto_width' : null,
						'label' => $this->l('Show products'),
						'name' => 'CATEG_NC_SHOW_PRODUCTS',
						$this->retro ? 'desc' : 'hint' => $this->l('Set whether to display products in the dropdowns'),
						'values' => array(
									array(
										'id' => 'active_on',
										'value' => 1,
										'label' => $this->l('Enabled')
									),
									array(
										'id' => 'active_off',
										'value' => 0,
										'label' => $this->l('Disabled')
									)
								),
					),
					array(
						'type' => 'categories',
						'is_bool' => true,
						'label' => $this->l('Start from'),
						'name'  => 'from_category',
						$this->retro ? 'desc' : 'hint' => $this->l('Set which category the dropdowns start from (select Home to display all categories)'),
						$this->retro ? 'values' : 'tree'  => array(
							'id'                  => 'categories-tree',
							'selected_categories' => array(Tools::getValue('from_category', Configuration::get('CATEG_NC_START_FROM_CATEG'))),
							'use_search' 		  => true,
							'trads' => array(
								'Root' => $root_category,
								'selected' => $this->l('selected'),
								'Collapse All' => $this->l('Collapse All'),
								'Expand All' => $this->l('Expand All'),
								'search' => $this->l('Find a category')
							),
							'selected_cat' => array(Tools::getValue('from_category', Configuration::get('CATEG_NC_START_FROM_CATEG'))),
							'disabled_categories' => array(),
							'input_name' => 'from_category',
							'use_radio' => true,
							'top_category' => Category::getTopCategory(),
							'use_context' => true,
						)
					),
					array(
						'type' => 'select',
						'label' => $this->l('Dropdown label position'),
						'name' => 'CATEG_NC_LABEL_POSITION',
						$this->retro ? 'desc' : 'hint' => $this->l('Set whether the labels appear inside the dropdowns or outside'),
						'default_value' => Tools::getValue('CATEG_NC_LABEL_POSITION', Configuration::get('CATEG_NC_LABEL_POSITION')),
						'options' => array(
							'query' => array(
								array(
									'id' => 0,
									'name' => $this->l('Inside')
								),
								array(
									'id' => 1,
									'name' => $this->l('Outside')
								)
							),
							'id' => 'id',
							'name' => 'name'
						)
					)
				),
				'submit' => array(
					'name' => 'submitSettings',
					'title' => $this->l('Save'),
					'class' => $this->retro ? 'button' : null,
				)
			)
		);

		$depth = $this->getNumberOfLevels(Tools::getValue('from_category', Configuration::get('CATEG_NC_START_FROM_CATEG')));

		for ($i = 1; $i <= $depth; $i++)
			$settings_form['form']['input'][] = array(
				'type' => 'text',
				'lang' => true,
				'label' => $this->l('Dropdown label for level').' '.$i,
				'name' => 'CATEG_NC_LABEL_'.$i,
				'hint' => $this->l('Set the label for each level that appears before a category is selected')
			);

		$product_count_cache_form = array(
			'form' => array(
				'legend' => array(
					'title' => $this->l('Product Number Settings'),
					'icon' => 'icon-sort-numeric-asc',
					'image' => $this->retro ? $this->_path.'img/sort_number.png' : null
				),
				'input' => array(
					array(
						'type' => 'select',
						'label' => $this->l('Product number'),
						'name' => 'CATEG_NC_NUM_PRODUCTS',
						'hint' => $this->retro ? null : $this->l('Display the number of products in a category (and its subcategories) in brackets after its name'),
						'desc' => ($this->retro ? $this->l('Display the number of products in a category (and its subcategories) in brackets after its name').
							'</p><p id="cache_instructions" class="preference_description">' : '').
							$this->l('Cache is automatically updated when adding or deleting products,').' '.
							$this->l('but must be regenerated if they are enabled or disabled').
							'<br /><br />'.$this->l('To automatically regenerate the cache on a regular basis, create a cron job with the following URL:').
							'<br />http://'.Tools::getHttpHost(false, true).__PS_BASE_URI__.'modules/'.$this->name.
							'/cron.php?secure_key='.Configuration::get('CATEG_NC_SECURE_KEY'),
						'onchange' => 'updateForm(\'productNumberForm\', $(this).attr(\'id\'));',
						'options' => array(
							'query' => array(
								array(
									'id' => 0,
									'name' => $this->l('None')
								),
								array(
									'id' => 1,
									'name' => $this->l('Categories')
								),
								array(
									'id' => 2,
									'name' => $this->l('Categories and subcategories')
								)
							),
							'id' => 'id',
							'name' => 'name'
						)
					),
					array(
						'type' => $this->retro ? 'radio' : 'switch',
						'is_bool' => true,
						'class' => $this->retro ? 'auto_width' : null,
						'label' => $this->l('Hide zero counts'),
						'name' => 'CATEG_NC_HIDE_ZERO_COUNTS',
						$this->retro ? 'desc' : 'hint' => $this->l('Hide the product number on empty categories'),
						'values' => array(
							array(
								'id' => 'CATEG_NC_HIDE_ZERO_COUNTS_on',
								'value' => 1,
								'label' => $this->l('Enabled')
							),
							array(
								'id' => 'CATEG_NC_HIDE_ZERO_COUNTS_off',
								'value' => 0,
								'label' => $this->l('Disabled')
							)
						)
					)
				),
				'submit' => array(
					'name' => 'submitProductNumber',
					'title' => $this->l('Save'),
					'class' => $this->retro ? 'button' : null,
				)
			)
		);

		$css_form = array(
			'form' => array(
				'legend' => array(
					'title' => $this->l('Custom CSS'),
					'icon' => 'icon-code',
					'image' => $this->retro ? $this->_path.'img/css.png' : null
				),
				'input' => array(
					array(
						'type' => 'textarea',
						'cols' => $this->retro ? '100' : null,
						'rows' => $this->retro ? '5' : null,
						'label' => $this->l('Custom CSS'),
						'name' => 'CATEG_NC_CUSTOM_CSS',
						$this->retro ? 'desc' : 'hint' => $this->l('Change the width, height and margin of dropdowns and add custom CSS'),
					)
				),
				'submit' => array(
					'name' => 'submitCSS',
					'title' => $this->l('Save'),
					'class' => $this->retro ? 'button' : null,
					)
			)
		);

		$troubleshooting_form = array(
			'form' => array(
				'legend' => array(
					'title' => $this->l('Troubleshooting'),
					'icon' => 'icon-wrench',
					'image' => $this->retro ? $this->_path.'img/wrench.png' : null
				),
				'input' => array(
					array(
						'type' => 'text',
						'label' => $this->l('Maximum categories per query'),
						'name' => 'CATEG_NC_MAX_CATEGORIES',
						$this->retro ? 'desc' : 'hint' => $this->l('If the memory limit is being exceeded, reduce this number to the reduce memory usage'),
						'class' => 'fixed-width-xs'
					)
				),
				'submit' => array(
					'name' => 'submitTroubleshooting',
					'title' => $this->l('Save'),
					'class' => $this->retro ? 'button' : null,
				)
			)
		);

		$helper = new HelperForm();
		$helper->show_toolbar = false;
		$helper->table = $this->table;
		$lang = new Language((int)Configuration::get('PS_LANG_DEFAULT'));
		$helper->default_form_language = $lang->id;
		$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
		$this->fields_form = array();

		$helper->identifier = $this->identifier;
		$helper->submit_action = 'submitCategoriesNC';
		$helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).
			'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
		$helper->token = Tools::getAdminTokenLite('AdminModules');
		$helper->tpl_vars = array(
			'fields_value' => $this->getConfigFieldsValues(),
			'languages' => $this->context->controller->getLanguages(),
			'id_language' => $this->context->language->id
		);

		$output = ($this->retro ? '<style>.margin-form > input[type="radio"] { float: left; margin-right: 6px }.auto_width { width: auto }</style>' : '').
			$helper->generateForm(array($settings_form)).($this->retro ? '<br />' : '');

		$product_count_cache_form_output = $helper->generateForm(array($product_count_cache_form));

		// Manually add Regenerate Cache button, since there's no helper to add the button to the form
		if ($this->retro)
			$product_count_cache_form_output = str_replace('name="submitProductNumber"',
				'name="submitProductNumber" class="button" /> <input type="button" name="submitRegenerateCache" value="'.$this->l('Regenerate cache').
				'" onclick="document.location = \''.AdminController::$currentIndex.'&configure='.$this->name.'&submitRegenerateCache=1&token='.
				Tools::getAdminTokenLite('AdminModules').'\';"', $product_count_cache_form_output);
		else
			$product_count_cache_form_output = str_replace('<i class="icon-sort-numeric-asc"></i>',
				'<i class="icon-sort-numeric-asc"></i><span class="panel-heading-action"><a href="'.
				AdminController::$currentIndex.'&configure='.$this->name.'&submitRegenerateCache=1&token='.
				Tools::getAdminTokenLite('AdminModules').
				'" class="list-toolbar-btn" id="desc-'.$this->name.
				'-repair"><span data-html="true" data-original-title="'.
				$this->l('Regenerate cache').
				'" class="label-tooltip" data-toggle="tooltip" title=""><i 
				class="process-icon-refresh"></i></span></a></span>', $product_count_cache_form_output);

		if ($this->retro)
		{
			$product_count_cache_form_output = $this->strReplaceFirst('<div class="clear"></div>',
			'<div class="clear"></div><div id="productNumberForm">', $product_count_cache_form_output);
			$product_count_cache_form_output = $this->strReplaceLast('<div class="margin-form">',
			'</div><div class="margin-form">', $product_count_cache_form_output);
		}
		else
		{
			$start = Tools::substr($product_count_cache_form_output,
				0, strpos($product_count_cache_form_output, '<div class="form-group') + 1);
			$end = Tools::substr($product_count_cache_form_output, strpos($product_count_cache_form_output, '<div class="form-group') + 1);
			$end = $this->strReplaceFirst('<div class="form-group', '<div id="productNumberForm"><div class="form-group', $end);
			$end = str_replace('<div class="panel-footer', '</div><div class="panel-footer', $end);
			$product_count_cache_form_output = $start.$end;
		}

		$output .= $product_count_cache_form_output.($this->retro ? '<br />' : '').$helper->generateForm(array($css_form));

		// Manually add Revert button, since there's no helper to add the button to the form
		if ($this->retro)
			$output = str_replace('name="submitCSS"', 'name="submitCSS" class="button" /> <input type="button" name="submitRestore" value="'.
				$this->l('Revert').'" onclick="if (confirm(\''.
				str_replace("'", "\'", $this->l('Are you sure? All modifications will be lost')).' '.
				str_replace("'", "\'", $this->l('after reverting to the original CSS.')).
				'\')) document.location = \''.AdminController::$currentIndex.'&configure='.
				$this->name.'&submitRestore=1&token='.
				Tools::getAdminTokenLite('AdminModules').'\';"', $output);
		else
			$output = str_replace('<i class="icon-code"></i>',
				'<i class="icon-code"></i><span class="panel-heading-action"><a href="'.
				AdminController::$currentIndex.'&configure='.$this->name.'&submitRestore=1&token='.
				Tools::getAdminTokenLite('AdminModules').'" class="list-toolbar-btn" id="desc-'.$this->name.'-revert" onclick="if (!confirm(\''.
				$this->l('Are you sure? All modifications will be lost').' '.
				$this->l('after reverting to the original CSS.').
				'\')) return false;"><span data-html="true" data-original-title="'.
				$this->l('Revert').'" class="label-tooltip" data-toggle="tooltip" title=""><i class="process-icon-mail-reply"></i></span></a></span>', $output);

		$output .= ($this->retro ? '<br />' : '').$helper->generateForm(array($troubleshooting_form));

		// Manually add Repair Tree button, since there's no helper to add the button to the form
		if ($this->retro)
			$output = str_replace('name="submitTroubleshooting"',
				'name="submitTroubleshooting" class="button" /> <input type="button" name="submitRepairTree" value="'.
				$this->l('Repair tree').'" onclick="document.location = \''.AdminController::$currentIndex.'&configure='.$this->name.
				'&submitRepairTree=1&token='.Tools::getAdminTokenLite('AdminModules').'\';"', $output);
		else
			$output = str_replace('<i class="icon-wrench"></i>',
				'<i class="icon-wrench"></i><span class="panel-heading-action"><a href="'.AdminController::$currentIndex.'&configure='.
				$this->name.'&submitRepairTree=1&token='.Tools::getAdminTokenLite('AdminModules').
				'" class="list-toolbar-btn" id="desc-'.$this->name.'-repair"><span data-html="true" data-original-title="'.
				$this->l('Repair tree').'" class="label-tooltip" data-toggle="tooltip" title=""><i class="process-icon-refresh"></i></span></a></span>', $output);

		$output .= '
		<script type="text/javascript">
			$(document).ready(function()
			{
				if (!parseInt($(\'#CATEG_NC_NUM_PRODUCTS\').val()))
					$(\'#productNumberForm\').hide();
				
				if (parseInt($(\'#CATEG_NC_NUM_PRODUCTS\').val()) != 2 && !$(\'#CATEG_NC_HIDE_EMPTY_CATEG_on\').is(\':checked\'))
					$(\''.($this->retro ? '#cache_instructions' : '#productNumberForm').'\')'.($this->retro ? '' : '.parent().find(\'.help-block\')').'.hide();
			});

			function updateForm(form, select)
			{
				if (!parseInt($(\'#\'+select).val()))
					$(\'#\'+form).slideUp();
				else if (form != \'accordionForm\')
					$(\'#\'+form).slideDown();				

				if (form == \'productNumberForm\' && (parseInt($(\'#\'+select).val()) == 2 || $(\'#CATEG_NC_HIDE_EMPTY_CATEG_on\').is(\':checked\')))
					$(\''.($this->retro ? '#cache_instructions\'' : '#\'+form').')'.($this->retro ? '' : '.parent().find(\'.help-block\')').'.slideDown();
				else if (form == \'productNumberForm\')
					$(\''.($this->retro ? '#cache_instructions\'' : '#\'+form').')'.($this->retro ? '' : '.parent().find(\'.help-block\')').'.slideUp();
			}		
		</script>';

		return $output;
	}

	public function strReplaceFirst($search, $replace, $subject)
	{
		$pos = strpos($subject, $search);

		if ($pos !== false)
			$subject = substr_replace($subject, $replace, $pos, Tools::strlen($search));

		return $subject;
	}

	public function strReplaceLast($search, $replace, $subject)
	{
		$pos = strrpos($subject, $search);

		if ($pos !== false)
			$subject = substr_replace($subject, $replace, $pos, Tools::strlen($search));

		return $subject;
	}

	public function getConfigFieldsValues()
	{
		$fields = array(
			'CATEG_NC_MAX_DEPTH' => Tools::getValue('CATEG_NC_MAX_DEPTH', Configuration::get('CATEG_NC_MAX_DEPTH')),
			'CATEG_NC_NBR_COLUMN_FOOTER' => Tools::getValue('CATEG_NC_NBR_COLUMN_FOOTER', Configuration::get('CATEG_NC_NBR_COLUMN_FOOTER')),
			'CATEG_NC_FOOTER_MAX_DEPTH' => Tools::getValue('CATEG_NC_FOOTER_MAX_DEPTH', Configuration::get('CATEG_NC_FOOTER_MAX_DEPTH')),
			'CATEG_NC_SORT_WAY' => Tools::getValue('CATEG_NC_SORT_WAY', Configuration::get('CATEG_NC_SORT_WAY')),
			'CATEG_NC_SORT' => Tools::getValue('CATEG_NC_SORT', Configuration::get('CATEG_NC_SORT')),
			'CATEG_NC_NUM_PRODUCTS' => Tools::getValue('CATEG_NC_NUM_PRODUCTS', Configuration::get('CATEG_NC_NUM_PRODUCTS')),
			'CATEG_NC_HIDE_ZERO_COUNTS' => Tools::getValue('CATEG_NC_HIDE_ZERO_COUNTS', Configuration::get('CATEG_NC_HIDE_ZERO_COUNTS')),
			'CATEG_NC_SHOW_GO_BUTTONS' => Tools::getValue('CATEG_NC_SHOW_GO_BUTTONS', Configuration::get('CATEG_NC_SHOW_GO_BUTTONS')),
			'CATEG_NC_SHOW_ALL_DROPDOWNS' => Tools::getValue('CATEG_NC_SHOW_ALL_DROPDOWNS', Configuration::get('CATEG_NC_SHOW_ALL_DROPDOWNS')),
			'CATEG_NC_FIX_IE_SELECT_WIDTH' => Tools::getValue('CATEG_NC_FIX_IE_SELECT_WIDTH', Configuration::get('CATEG_NC_FIX_IE_SELECT_WIDTH')),
			'CATEG_NC_HIDE_EMPTY_CATEG' => Tools::getValue('CATEG_NC_HIDE_EMPTY_CATEG', Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG')),
			'CATEG_NC_SAVE' => Tools::getValue('CATEG_NC_SAVE', Configuration::get('CATEG_NC_SAVE')),
			'CATEG_NC_RELOAD' => Tools::getValue('CATEG_NC_RELOAD', Configuration::get('CATEG_NC_RELOAD')),
			'CATEG_NC_SHOW_PRODUCTS' => Tools::getValue('CATEG_NC_SHOW_PRODUCTS', Configuration::get('CATEG_NC_SHOW_PRODUCTS')),
			'CATEG_NC_LABEL_POSITION' => Tools::getValue('CATEG_NC_LABEL_POSITION', Configuration::get('CATEG_NC_LABEL_POSITION')),
			'CATEG_NC_MAX_CATEGORIES' => Tools::getValue('CATEG_NC_MAX_CATEGORIES', Configuration::get('CATEG_NC_MAX_CATEGORIES')),

		);

		$languages = Language::getLanguages(false);
		$depth = $this->getNumberOfLevels(Tools::getValue('from_category', Configuration::get('CATEG_NC_START_FROM_CATEG')));

		for ($i = 1; $i <= $depth; $i++)
			foreach ($languages as $lang)
				$fields['CATEG_NC_LABEL_'.$i][$lang['id_lang']] = Tools::getValue('CATEG_NC_LABEL_'.$i.'_'.$lang['id_lang'],
					Configuration::get('CATEG_NC_LABEL_'.$i, $lang['id_lang']));

		$fname = _PS_MODULE_DIR_.$this->name.'/css/'.$this->name.'.css';

		if (file_exists($fname))
		{
			$fhandle = fopen($fname, 'r');
			$custom_css = (filesize($fname) > 0 ? fread($fhandle, filesize($fname)) : '');
			fclose($fhandle);
		}
		else
			$custom_css = '';

		$fields['CATEG_NC_CUSTOM_CSS'] = Tools::getValue('CATEG_NC_CUSTOM_CSS', $custom_css);

		return $fields;
	}

	public function getTree($result_parents, $result_ids, $max_depth, $id_category = null,
		$current_depth = 0, $num_products = null, $cache = false, $repair = false)
	{
		if (is_null($id_category))
			$id_category = $this->context->shop->getCategory();

		$children = array();
		$num_subcat_products = 0;
		if (array_key_exists($id_category, $result_parents) && count($result_parents[$id_category]) && ($max_depth == 0 || $current_depth < $max_depth))
		{
			foreach ($result_parents[$id_category] as $subcat)
				$children[] = $this->getTree($result_parents, $result_ids, $max_depth, $subcat['id_category'],
					$current_depth + 1, $num_products, $cache, $repair);

			foreach ($children as $child)
			{
				$num_subcat_products += $child['numProductsSub'];

				if (count($child['children']) && $id_category > $this->context->shop->getCategory())
					$this->parents[$id_category] = true;
			}
		}
		elseif (!array_key_exists($id_category, $result_parents) && Configuration::get('CATEG_NC_SHOW_PRODUCTS')
			&& ($max_depth == 0 || $current_depth < $max_depth))
		{
			$sql = '
				SELECT p.`id_product`, p.`id_category_default`, pl.`name`, pl.`link_rewrite`
				FROM `'._DB_PREFIX_.'category_product` cp
				LEFT JOIN `'._DB_PREFIX_.'product` p ON (cp.`id_product` = p.`id_product`)
				LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON (cp.`id_product` = pl.`id_product`)
				WHERE cp.`id_category` = '.$id_category.' && p.`active` = 1 && pl.`id_lang` = '.(int)$this->context->cookie->id_lang;

			$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);

			foreach ($result as $product)
			{
				$default_category = new Category($product['id_category_default'], (int)$this->context->cookie->id_lang);
				$children[] = array('id' => $product['id_product'],
									'link' => $this->context->link->getProductLink($product['id_product'], $product['link_rewrite'], $default_category->link_rewrite),
									'name' => $product['name'],
									'nleft' => 0,
									'nright' => 1,
									'level_depth' => $current_depth + 1,
									'numProducts' => 0,
									'numProductsSub' => 0,
									'children' => array());
			}
		}

		if (!array_key_exists($id_category, $result_ids))
			return false;

		if (Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG') == 1 && $num_subcat_products == 0)
			$children = array();

		if ($repair)
			Db::getInstance(_PS_USE_SQL_SLAVE_)->Execute('
				UPDATE `'._DB_PREFIX_.'category`
				SET `level_depth` = '.$current_depth.'
				WHERE `id_category` = '.$id_category);

		return array(
			'id' => $id_category,
			'link' => $this->context->link->getCategoryLink($id_category,
				array_key_exists('link_rewrite', $result_ids[$id_category]) ? $result_ids[$id_category]['link_rewrite'] : null),
			'nleft' => array_key_exists('nleft', $result_ids[$id_category]) ? $result_ids[$id_category]['nleft'] : 0,
			'nright' => array_key_exists('nright', $result_ids[$id_category]) ? $result_ids[$id_category]['nright'] : 0,
			'name' => array_key_exists('name', $result_ids[$id_category]) ? $result_ids[$id_category]['name'] : '',
			'level_depth' => array_key_exists('level_depth', $result_ids[$id_category]) ? $result_ids[$id_category]['level_depth'] : $current_depth,
			'desc' => array_key_exists('description', $result_ids[$id_category]) ? $result_ids[$id_category]['description'] : '',
			'numProducts' => (Configuration::get('CATEG_NC_NUM_PRODUCTS') == 2
				? ($cache
					? (($num_subcat_products + (is_array($num_products) && array_key_exists($id_category, $num_products)
						? $num_products[$id_category]
						: 0)))
					: (array_key_exists('num_products', $result_ids[$id_category])
						? $result_ids[$id_category]['num_products']
						: 0))
				: (is_array($num_products) && array_key_exists($id_category, $num_products)
					? $num_products[$id_category]
					: 0)),
			'numProductsSub' => $cache
				? (($num_subcat_products + (is_array($num_products) && array_key_exists($id_category, $num_products)
					? $num_products[$id_category]
					: 0)))
				: (array_key_exists('num_products', $result_ids[$id_category])
					? $result_ids[$id_category]['num_products']
					: 0),
			'children' => $children);
	}

	public function getTreeFooter($result_parents, $result_ids, $max_depth, $id_category = null, $current_depth = 0)
	{
		if (is_null($id_category))
			$id_category = $this->context->shop->getCategory();

		$children = array();
		if (array_key_exists($id_category, $result_parents) && count($result_parents[$id_category]) && ($max_depth == 0 || $current_depth < $max_depth))
			foreach ($result_parents[$id_category] as $subcat)
				$children[] = $this->getTree($result_parents, $result_ids, $max_depth, $subcat['id_category'], $current_depth + 1);
		if (!array_key_exists($id_category, $result_ids))
			return false;
		return array(
			'id' => $id_category,
			'link' => $this->context->link->getCategoryLink($id_category, $result_ids[$id_category]['link_rewrite']),
			'name' => $result_ids[$id_category]['name'],
			'desc'=> $result_ids[$id_category]['description'],
			'children' => $children);
	}

	protected function createCache()
	{
		Db::getInstance(_PS_USE_SQL_SLAVE_)->Execute('TRUNCATE `'._DB_PREFIX_.'blockcategoriesnc_numproducts`');

		$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT COUNT(*) as "num_categories" FROM `'._DB_PREFIX_.'category_product`');
		$total = 0;

		if (is_array($result) && count($result) > 0)
			$total = $result[0]['num_categories'];

		// Load this many subcategories at a time to keep memory usage low
		$n = Configuration::get('CATEG_NC_MAX_CATEGORIES');
		$i = 0;
		$percent = 0;

		echo '<div id="progress">'.$this->l('Counting number of products in each category').'...<span id="p'.$percent.'">'.$percent.'%</span>';

		Db::getInstance(_PS_USE_SQL_SLAVE_)->execute('
			INSERT INTO `'._DB_PREFIX_.'blockcategoriesnc_numproducts` (`id_category`, `num_products`)
			SELECT `id_category`, 0
			FROM `'._DB_PREFIX_.'category`
			WHERE `id_category` NOT IN (SELECT DISTINCT(`id_category`) FROM `'._DB_PREFIX_.'category_product`)');

		if ($total > 0)
			do
			{
				if (floor((($i * $n) / (float)$total) * 100) > $percent)
				{
					$previous_percent = $percent;
					$percent = floor((($i * $n) / (float)$total) * 100);
					echo '<span id="p'.$percent.'">'.$percent.'%</span><style type="text/css">#p'.$previous_percent.' { display: none }</style>';
				}

				$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
					SELECT DISTINCT `id_category`
					FROM `'._DB_PREFIX_.'category_product`
					LIMIT '.($i * $n).', '.$n);
				$num_results = count($result);

				foreach ($result as $row)
					Db::getInstance(_PS_USE_SQL_SLAVE_)->execute('
						INSERT INTO `'._DB_PREFIX_.'blockcategoriesnc_numproducts` (`id_category`, `num_products`)
						SELECT '.$row['id_category'].', COUNT(*)
						FROM `'._DB_PREFIX_.'category_product` cp
						LEFT JOIN `'._DB_PREFIX_.'product` p ON cp.`id_product` = p.`id_product`
						WHERE cp.`id_category` = '.$row['id_category'].' && p.`active` = 1');

				$i++;
			}
			while ($num_results == $n);

		echo '<span id="p100">100%</span><style type="text/css">#p'.$percent.' { display: none }</style>';

		$i = 0;
		$previous_percent = 0;
		$percent = 0;

		echo '<br />'.$this->l('Adding counts to parent categories').'...<span id="pc'.$percent.'">'.$percent.'%</span>';

		if ($total > 0)
			CategoriesNC::addProductCountsToParents();

		echo '</div><style type="text/css">#pc'.$percent.', #progress { display: none }</style>';
	}

	/**
	* Re-calculate the values of all branches of the nested tree
	*/
	protected static function addProductCountsToParents()
	{
		$id = Context::getContext()->shop->id;
		$id_shop = $id ? $id: Configuration::get('PS_SHOP_DEFAULT');
		$categories = Db::getInstance()->executeS('
		SELECT c.`id_category`, c.`id_parent`
		FROM `'._DB_PREFIX_.'category` c
		LEFT JOIN `'._DB_PREFIX_.'category_shop` cs
			ON (c.`id_category` = cs.`id_category` && cs.`id_shop` = '.(int)$id_shop.')
		ORDER BY c.`id_parent`, cs.`position` ASC');
		$categories_array = array();
		foreach ($categories as $category)
			$categories_array[$category['id_parent']]['subcategories'][] = $category['id_category'];
		$i = 0;
		$percent = 0;
		$total = count($categories);

		if (array_key_exists(0, $categories_array) && array_key_exists('subcategories', $categories_array[0]))
			CategoriesNC::countProducts($categories_array, 0, $categories_array[0]['subcategories'][0], $i, $percent, $total);
	}

	protected static function countProducts(&$categories, $id_parent, $id_category, &$i, &$percent, &$total)
	{
		if (array_key_exists((int)$id_category, $categories) && array_key_exists('subcategories', $categories[(int)$id_category]))
			foreach ($categories[(int)$id_category]['subcategories'] as $id_subcategory)
				CategoriesNC::countProducts($categories, $id_category, (int)$id_subcategory, $i, $percent, $total);

		$num_products = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
			SELECT `num_products`
			FROM `'._DB_PREFIX_.'blockcategoriesnc_numproducts`
			WHERE `id_category` = '.$id_category);

		if (is_array($num_products) && count($num_products) > 0 && $num_products[0]['num_products'] > 0 && $id_parent > 0)
			Db::getInstance(_PS_USE_SQL_SLAVE_)->execute('
				UPDATE `'._DB_PREFIX_.'blockcategoriesnc_numproducts`
				SET `num_products` = `num_products` + '.$num_products[0]['num_products'].'
				WHERE `id_category` = '.$id_parent);

		$i++;

		if (floor(($i / (float)$total) * 100) > $percent)
		{
			$previous_percent = $percent;
			$percent = floor(($i / (float)$total) * 100);
			echo '<span id="pc'.$percent.'">'.$percent.'%</span><style type="text/css">#pc'.$previous_percent.' { display: none }</style>';
		}
	}

	protected function recalculateLevelDepth($id_category, &$i, &$percent, $total)
	{
		if (!is_numeric($id_category))

			throw new PrestaShopException('id category is not numeric');
		/* Gets all children */
		$categories = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
			SELECT id_category, id_parent, level_depth
			FROM '._DB_PREFIX_.'category
			WHERE id_parent = '.(int)$id_category);
		/* Gets level_depth */
		$level = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow('
			SELECT level_depth
			FROM '._DB_PREFIX_.'category
			WHERE id_category = '.(int)$id_category);
		/* Updates level_depth for all children */
		foreach ($categories as $sub_category)
		{
			Db::getInstance()->execute('
				UPDATE '._DB_PREFIX_.'category
				SET level_depth = '.((int)$level['level_depth'] + 1).'
				WHERE id_category = '.(int)$sub_category['id_category']);
			/* Recursive call */
			$this->recalculateLevelDepth($sub_category['id_category'], $i, $percent, $total);
		}

		$i++;

		if (floor(($i / (float)$total) * 100) > $percent)
		{
			$previous_percent = $percent;
			$percent = floor(($i / (float)$total) * 100);
			echo '<span id="p'.$percent.'">'.$percent.'%</span><style type="text/css">#p'.$previous_percent.' { display: none }</style>';
		}
	}

	/**
	* Re-calculate the values of all branches of the nested tree
	*/
	protected static function regenerateEntireNtree()
	{
		$id = Context::getContext()->shop->id;
		$id_shop = $id ? $id: Configuration::get('PS_SHOP_DEFAULT');
		$categories = Db::getInstance()->executeS('
		SELECT c.`id_category`, c.`id_parent`
		FROM `'._DB_PREFIX_.'category` c
		LEFT JOIN `'._DB_PREFIX_.'category_shop` cs
			ON (c.`id_category` = cs.`id_category` && cs.`id_shop` = '.(int)$id_shop.')
		ORDER BY c.`id_parent`, cs.`position` ASC');
		$categories_array = array();
		foreach ($categories as $category)
			$categories_array[$category['id_parent']]['subcategories'][] = $category['id_category'];
		$n = 1;
		$i = 0;
		$percent = 0;
		$total = count($categories);

		if (array_key_exists(0, $categories_array) && array_key_exists('subcategories', $categories_array[0]))
			CategoriesNC::subTree($categories_array, $categories_array[0]['subcategories'][0], $n, $i, $percent, $total);
	}

	protected static function subTree(&$categories, $id_category, &$n, &$i, &$percent, &$total)
	{
		$left = $n++;
		if (array_key_exists((int)$id_category, $categories) && array_key_exists('subcategories', $categories[(int)$id_category]))
			foreach ($categories[(int)$id_category]['subcategories'] as $id_subcategory)
				CategoriesNC::subTree($categories, (int)$id_subcategory, $n, $i, $percent, $total);
		$right = (int)$n++;

		Db::getInstance()->execute('
			UPDATE '._DB_PREFIX_.'category
			SET nleft = '.(int)$left.', nright = '.(int)$right.'
			WHERE id_category = '.(int)$id_category.' LIMIT 1
		');

		$i++;

		if (floor(($i / (float)$total) * 100) > $percent)
		{
			$previous_percent = $percent;
			$percent = floor(($i / (float)$total) * 100);
			echo '<span id="pc'.$percent.'">'.$percent.'%</span><style type="text/css">#pc'.$previous_percent.' { display: none }</style>';
		}
	}

	protected function repairTree()
	{
		$i = 0;
		$percent = 0;
		$total = 0;

		echo '<div id="progress">'.$this->l('Recalculating level depths').'...<span id="p'.$percent.'">'.$percent.'%</span>';

		$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT COUNT(*) as "num_categories" FROM `'._DB_PREFIX_.'category`');

		if (is_array($result) && count($result) > 0)
			$total = $result[0]['num_categories'];

		$category = new Category(Configuration::get('PS_ROOT_CATEGORY'));
		$this->recalculateLevelDepth($category->id, $i, $percent, $total);

		$i = 0;
		$percent = 0;
		$total = 0;

		echo '<br />'.$this->l('Recalculating nested tree').'...<span id="pc'.$percent.'">'.$percent.'%</span>';

		$this->regenerateEntireNtree();

		echo '</div><style type="text/css">#pc'.$percent.', #progress { display: none }</style>';
	}

	public function hookAddProduct($params)
	{
		if ($params['product']->active == 1 && Configuration::get('CATEG_NC_NUM_PRODUCTS') == 2)
		{
			$categories = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('
				SELECT `id_category`
				FROM `'._DB_PREFIX_.'category_product`
				WHERE `id_product` = '.$params['product']->id);

			if (count($categories) > 0)
			{
				$sql = 'UPDATE `'._DB_PREFIX_.'blockcategoriesnc_numproducts` SET `num_products` = `num_products` + 1 WHERE ';

				foreach ($categories as $category)
					$sql .= '`id_category` = '.$category['id_category'].' OR ';

				$sql = Tools::substr($sql, 0, Tools::strlen($sql) - 4);

				Db::getInstance(_PS_USE_SQL_SLAVE_)->Execute($sql);
			}
		}
	}

	public function hookDeleteProduct($params)
	{
		if ($params['product']->active == 1 && Configuration::get('CATEG_NC_NUM_PRODUCTS') == 2)
		{
			$categories = Product::getProductCategories($params['product']->id);

			if (count($categories) > 0)
			{
				$sql = 'UPDATE `'._DB_PREFIX_.'blockcategoriesnc_numproducts` SET `num_products` = `num_products` - 1 WHERE ';

				foreach ($categories as $category)
					$sql .= '`id_category` = '.$category['id_category'].' OR ';

				$sql = Tools::substr($sql, 0, Tools::strlen($sql) - 4);

				Db::getInstance(_PS_USE_SQL_SLAVE_)->Execute($sql);
			}
		}
	}
/*
	public function hookUpdateProduct($params)
	{
		return $this->createCache();
	}
*/

	protected function getIEVersion()
	{
		$ie_version = 0;

		if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE'))
		{
			$ie_version = Tools::substr($_SERVER['HTTP_USER_AGENT'], strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') + 5);
			$ie_version = (float)Tools::substr($ie_version, 0, strpos($ie_version, ';'));
		}

		return $ie_version;
	}

	public function hookHeader()
	{
		$ie_version = $this->getIEVersion();

		$this->context->controller->addCSS(($this->_path).'css/'.$this->name.'.css');

		if (Configuration::get('CATEG_NC_FIX_IE_SELECT_WIDTH') && $ie_version > 0 && $ie_version < 9)
		{
			$this->context->controller->addCSS($this->_path.'css/ie-select-width.css');
			$this->context->controller->addJqueryPlugin('dimensions');
			$this->context->controller->addJS($this->_path.'js/jquery.ie-select-width.js');
			if ($ie_version <= 6)
				$this->context->controller->addJS($this->_path.'js/jquery.bgiframe.js');
		}
	}

	public function hookDisplayHome($params)
	{
		$max_depth = Configuration::get('CATEG_NC_MAX_DEPTH');
		$num_products = Configuration::get('CATEG_NC_NUM_PRODUCTS');
		$home_category = Configuration::get('CATEG_NC_START_FROM_CATEG');

		$id_category = (int)Tools::getValue('id_category');
		$id_product = (int)Tools::getValue('id_product');

		if (Tools::isSubmit('id_category'))
		{
			$this->context->cookie->last_visited_category = $id_category;
			$this->smarty->assign('currentCategoryId', $this->context->cookie->last_visited_category);
		}
		elseif (Tools::isSubmit('id_product'))
		{
			if (!$this->context->cookie->last_visited_category || !Product::idIsOnCategoryId($id_product,
				array('0' => array('id_category' => $this->context->cookie->last_visited_category))))
			{
				$product = new Product($id_product);
				if (Validate::isLoadedObject($product))
					$this->context->cookie->last_visited_category = (int)$product->id_category_default;
			}
			$this->smarty->assign('currentCategoryId', (int)$this->context->cookie->last_visited_category);
		}
		else
			$category = $home_category;

		if (Tools::isSubmit('id_category') || Tools::isSubmit('id_product'))
			$category = $this->context->cookie->last_visited_category;

		$category = $this->context->cookie->last_visited_category;
		$num_dropdowns = 1;
		$home_depth = 0;

		$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
			SELECT `level_depth`
			FROM `'._DB_PREFIX_.'category`
			WHERE `id_category` = '.$home_category);

		if (is_array($result) && count($result) > 0)
			$home_depth = $result[0]['level_depth'];

		if (Configuration::get('CATEG_NC_SHOW_ALL_DROPDOWNS'))
		{
			$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
				SELECT MAX(`level_depth`) as `max_depth`
				FROM `'._DB_PREFIX_.'category`'.(Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG')
				? ' c INNER JOIN `'._DB_PREFIX_.'blockcategoriesnc_numproducts` bn ON (c.`id_category` = bn.`id_category`)
				WHERE `num_products` > 0' : ''));

			if (is_array($result) && count($result) > 0)
			{
				$depth = ($max_depth > 0 && $result[0]['max_depth'] > $max_depth) ? $max_depth : $result[0]['max_depth'];
				$depth -= $home_depth;

				if (Configuration::get('CATEG_NC_SHOW_PRODUCTS'))
					$depth++;

				if ($max_depth > 0 && $depth > $max_depth)
					$depth = $max_depth;

				$num_dropdowns = $depth;
			}
		}

		$category_subquery = ' OR c.`id_category` = '.$home_category;

		$sql = 'SELECT `id_category` FROM `'._DB_PREFIX_.'category` WHERE `id_parent` = '.$home_category;
		$categories = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS($sql);

		foreach ($categories as $category)
			$category_subquery .= ' OR c.`id_category` = '.$category['id_category'];

		$subcategory_subquery = $category_subquery;

		if ($max_depth != 1 && ($id_category || Tools::isSubmit('id_product')))
		{
			$sql = 'SELECT `id_category` FROM `'._DB_PREFIX_.'category` WHERE `id_parent` = '.$id_category;

			$subcategories = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS($sql);

			foreach ($subcategories as $subcategory)
				$subcategory_subquery .= ' OR c.`id_category` = '.$subcategory['id_category'];
		}
		else
			$subcategory_subquery = $category_subquery;

		$groups = ' && (';

		if ((int)$this->context->cookie->id_customer)
		{
			$customer = new Customer((int)$this->context->cookie->id_customer);

			if (Validate::isLoadedObject($customer))
			{
				$customer_groups = $customer->getGroups();

				foreach ($customer_groups as $customer_group)
					$groups .= 'cg.`id_group` = '.(int)$customer_group.' OR ';
			}

			if (Tools::strlen($groups) > 6)
				$groups = Tools::substr($groups, 0, Tools::strlen($groups) - 4).')';
		}
		else
			$groups .= 'cg.`id_group` = 1)';

		if (Tools::isSubmit('id_category'))
		{
			$this->context->cookie->last_visited_category = $id_category;
			$this->smarty->assign('currentCategoryId', $this->context->cookie->last_visited_category);
		}
		elseif (Tools::isSubmit('id_product'))
		{
			if (!$this->context->cookie->last_visited_category || !Product::idIsOnCategoryId($id_product,
				array('0' => array('id_category' => $this->context->cookie->last_visited_category))))
			{
				$product = new Product($id_product);
				if (Validate::isLoadedObject($product))
					$this->context->cookie->last_visited_category = (int)$product->id_category_default;
			}
			$this->smarty->assign('currentCategoryId', (int)$this->context->cookie->last_visited_category);
		}
		else
			$category = $home_category;

		if (Tools::isSubmit('id_category') || Tools::isSubmit('id_product'))
			$category = $this->context->cookie->last_visited_category;

		$breadcrumbs = array();
		$breadcrumb_names = array();
		$breadcrumb_links = array();
		$last_breadcrumb_is_product = false;

		if ($category > 1)
		{
			$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
				SELECT `level_depth`
				FROM `'._DB_PREFIX_.'category`
				WHERE `id_category` = '.$category);

			if ($result != null && count($result) > 0)
				$depth = $result[0]['level_depth'];

			$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
				SELECT `level_depth`
				FROM `'._DB_PREFIX_.'category`
				WHERE `id_category` = '.$home_category);

			if ($result != null && count($result) > 0)
				$depth -= $result[0]['level_depth'];

			$depth++;

			$sql = 'SELECT ';

			for ($i = 1; $i <= $depth; $i++)
				$sql .= 't'.$i.'.`id_category` as lev'.$i.($i < $depth ? ', ' : '');

			$sql .= ' FROM `'._DB_PREFIX_.'category` as t1 ';

			for ($i = 1; $i < $depth; $i++)
				$sql .= 'LEFT JOIN `'._DB_PREFIX_.'category` as t'.($i + 1).' on t'.($i + 1).'.`id_parent` = t'.$i.'.`id_category` ';

			$sql .= 'WHERE t1.`id_category` = '.$home_category.' && t'.$depth.'.`id_category` = '.$category;

			$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);

			for ($i = 2; $i <= ($max_depth > 0 && $max_depth < $depth ? $max_depth : $depth) && array_key_exists('lev'.$i, $result[0]); $i++)
				$breadcrumbs[] = $result[0]['lev'.$i];

			if (Tools::getValue('id_product') > 0 && Configuration::get('CATEG_NC_SHOW_PRODUCTS')
				&& ($max_depth == 0 || ($max_depth > 0 && count($breadcrumbs <= $max_depth))))
				$breadcrumbs[] = (int)Tools::getValue('id_product');

			if (!Configuration::get('CATEG_NC_RELOAD'))
			{
				$num_breadcrumbs = count($breadcrumbs);

				for ($i = 0; $i < $num_breadcrumbs; $i++)
				{
					if (Tools::getValue('id_product') && Configuration::get('CATEG_NC_SHOW_PRODUCTS') && $i == $num_breadcrumbs - 1)
					{
						$product = new Product((int)Tools::getValue('id_product'), false, (int)$this->context->cookie->id_lang);
						$breadcrumb_names[] = $product->name;
						$breadcrumb_links[] = $this->context->link->getProductLink($product->id, $product->link_rewrite);
						$last_breadcrumb_is_product = true;
					}
					else
					{
						$category = new Category($breadcrumbs[$i], (int)$this->context->cookie->id_lang);
						$breadcrumb_names[] = $category->name;
						$breadcrumb_links[] = $this->context->link->getCategoryLink($category->id, $category->link_rewrite);
					}
				}
			}
		}

		if ($num_products == 2 && !Configuration::get('CATEG_NC_RELOAD'))
			foreach ($breadcrumbs as $breadcrumb)
				$subcategory_subquery .= ' OR c.`id_category` = '.$breadcrumb;

		$sql = '
		SELECT DISTINCT c.`id_category`, c.`id_parent`, c.`level_depth`, c.`nleft`, c.`nright`, cl.`id_lang`, cl.`name`, cl.`link_rewrite`'.
		((Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG') == 1 || $num_products == 2) ? ', bn.`num_products`' : '').'
		FROM `'._DB_PREFIX_.'category` c 
		LEFT JOIN `'._DB_PREFIX_.'category_shop` cs ON (c.`id_category` = cs.`id_category`)
		LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (c.`id_category` = cl.`id_category` && cl.`id_lang` = '.
		(int)$params['cookie']->id_lang.' && cl.`id_shop` = '.(int)$this->context->shop->id.')
		'.((Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG') == 1 || $num_products == 2)
		? 'LEFT JOIN `'._DB_PREFIX_.'blockcategoriesnc_numproducts` bn ON (c.`id_category` = bn.`id_category`)' : '').'
		LEFT JOIN `'._DB_PREFIX_.'category_group` cg ON (cg.`id_category` = c.`id_category`)
		WHERE c.`active` = 1'.$groups.' && (`level_depth` <= 1'.$subcategory_subquery.')
		ORDER BY `level_depth` ASC, '.(Configuration::get('CATEG_NC_SORT') ? 'cl.`name`' : 'cs.`position`').' '.
		(Configuration::get('CATEG_NC_SORT_WAY') ? 'DESC' : 'ASC');

		if (!$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS($sql))
			return;

		$result_parents = array();
		$result_ids = array();
		$result_products = array();

		foreach ($result as $row)
		{
			$result_parents[$row['id_parent']][] = $row;
			$result_ids[$row['id_category']] = $row;
		}

		if ($num_products == 1)
		{
			$sql = '
				SELECT `id_category`, COUNT(*) as "num_products"
				FROM `'._DB_PREFIX_.'category_product` cp
				LEFT JOIN `'._DB_PREFIX_.'product` p ON (cp.`id_product` = p.`id_product`)
				WHERE p.`active` = 1 AND ';

			$first = true;

			foreach ($result as $row)
			{
				if (!$first)

					$sql .= 'id_category = '.$row['id_category'].' OR ';
				else
					$first = false;
			}

			if (!Configuration::get('CATEG_NC_RELOAD'))
				foreach ($breadcrumbs as $breadcrumb)
					$sql .= 'id_category = '.$breadcrumb.' OR ';

			$sql = Tools::substr($sql, 0, Tools::strlen($sql) - 4);
			$sql .= ' GROUP BY `id_category`';

			$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS($sql);

			if ($result)
				foreach ($result as $row)
					$result_products[$row['id_category']] = $row['num_products'];
		}

		$num_breadcrumb_names = count($breadcrumb_names);

		if ($num_products > 0 && !Configuration::get('CATEG_NC_RELOAD'))
			for ($i = 0; $i < $num_breadcrumb_names; $i++)
				if ($i < $num_breadcrumb_names - 1 || ($i == count($breadcrumb_names) - 1 && !$last_breadcrumb_is_product))
				{
					$product_number = ($num_products == 1
						? (array_key_exists($breadcrumbs[$i], $result_products)
							? $result_products[$breadcrumbs[$i]]
							: 0)
						: $result_ids[$breadcrumbs[$i]]['num_products']);

					if (!Configuration::get('CATEG_NC_HIDE_ZERO_COUNTS') || (Configuration::get('CATEG_NC_HIDE_ZERO_COUNTS') && $product_number > 0))
						$breadcrumb_names[$i] .= ' ('.$product_number.')';
				}

		$last_breadcrumb_has_children = false;

		if (count($breadcrumbs) > 0 && ($max_depth == 0 || ($max_depth > 0 && $home_depth + $depth <= $max_depth)))
		{
			$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('
				SELECT COUNT(`id_category`) as num_children 
				FROM `'._DB_PREFIX_.'category`
				WHERE `id_parent` = '.$breadcrumbs[count($breadcrumbs) - 1]);

			if (is_array($result) && count($result) > 0 && $result[0]['num_children'] > 0)
				$last_breadcrumb_has_children = true;
		}

		$categ_tree = $this->getTree($result_parents, $result_ids, 0, $home_category, 0, $result_products);

		$ie_version = $this->getIEVersion();

		$this->context->smarty->assign(array(
			'retro' => $this->retro,
			'lastBreadcrumbHasChildren' => $last_breadcrumb_has_children,
			'numDropdowns' => $num_dropdowns,
			'column' => array_key_exists('column', $params) ? $params['column'] : 0,
			'friendlyURL' => (int)Configuration::get('PS_REWRITING_SETTINGS'),
			'categTree' => $categ_tree,
			'breadcrumbs' => $breadcrumbs,
			'breadcrumbNames' => $breadcrumb_names,
			'breadcrumbLinks' => $breadcrumb_links,
			'maxDepth' => (int)Configuration::get('CATEG_NC_MAX_DEPTH'),
			'showGoButtons' => (int)Configuration::get('CATEG_NC_SHOW_GO_BUTTONS'),
			'showAllDropdowns' => (int)Configuration::get('CATEG_NC_SHOW_ALL_DROPDOWNS'),
			'iefix' => (bool)Configuration::get('CATEG_NC_FIX_IE_SELECT_WIDTH') && $ie_version > 0 && $ie_version < 9,
			'showProductNum' => (int)Configuration::get('CATEG_NC_NUM_PRODUCTS'),
			'hideZeroCounts' => (int)Configuration::get('CATEG_NC_HIDE_ZERO_COUNTS'),
			'hideEmptyCategories' => (int)Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG'),
			'save' => (int)Configuration::get('CATEG_NC_SAVE'),
			'reload' => (int)Configuration::get('CATEG_NC_RELOAD'),
			'showProducts' => (int)Configuration::get('CATEG_NC_SHOW_PRODUCTS'),
			'labelPosition' => (int)Configuration::get('CATEG_NC_LABEL_POSITION')));

		$i = 1;

		$labels = array();

		do
		{
			$label = Configuration::getInt('CATEG_NC_LABEL_'.$i);

			if (is_array($label) && array_key_exists((int)$this->context->cookie->id_lang, $label) && trim($label[(int)$this->context->cookie->id_lang]) != '')
				$labels[$i] = $label[(int)$this->context->cookie->id_lang];
			else
				break;

			$i++;
		}
		while (true);

		$this->context->smarty->assign('labels', $labels);

		return $this->display(__FILE__, $this->name.'.tpl');
	}

	public function hookDisplayTop($params)
	{
		return $this->hookDisplayHome($params);
	}

	public function hookDisplayLeftColumn($params)
	{
		$params['column'] = 1;

		return $this->hookDisplayHome($params);
	}

	public function hookDisplayRightColumn($params)
	{
		$params['column'] = 1;

		return $this->hookDisplayHome($params);
	}

	public function hookDisplayFooter()
	{
		// Get all groups for this customer and concatenate them as a string: "1,2,3..."
		if (!$this->isCached('blockcategories_footer.tpl', $this->getCacheId()))
		{
			$maxdepth = Configuration::get('CATEG_NC_FOOTER_MAX_DEPTH');
			$groups = implode(', ', Customer::getGroupsStatic((int)$this->context->customer->id));
			$num_products = Configuration::get('CATEG_NC_NUM_PRODUCTS');
			if (!$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('
				SELECT DISTINCT c.id_parent, c.id_category, cl.name, cl.description, cl.link_rewrite'.
				((Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG') == 1 || $num_products == 2) ? ', bn.`num_products`' : '').'
				FROM `'._DB_PREFIX_.'category` c
				'.Shop::addSqlAssociation('category', 'c').'
				LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (c.`id_category` = cl.`id_category` && cl.`id_lang` = '.
				(int)$this->context->language->id.Shop::addSqlRestrictionOnLang('cl').')
				LEFT JOIN `'._DB_PREFIX_.'category_group` cg ON (cg.`id_category` = c.`id_category`)
				'.((Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG') == 1 || $num_products == 2)
				? 'LEFT JOIN `'._DB_PREFIX_.'blockcategoriesnc_numproducts` bn ON (c.`id_category` = bn.`id_category`)' : '').'
				WHERE (c.`active` = 1 OR c.`id_category` = '.$this->context->shop->getCategory().')
				'.((int)$maxdepth != 0 ? ' && `level_depth` <= '.(int)$maxdepth : '').'
				AND cg.`id_group` IN ('.pSQL($groups).')
				ORDER BY `level_depth` ASC, '.(Configuration::get('CATEG_NC_SORT') ? 'cl.`name`' : 'category_shop.`position`').' '.
				(Configuration::get('CATEG_NC_SORT_WAY') ? 'DESC' : 'ASC')))
				return;
			$result_parents = array();
			$result_ids = array();

			foreach ($result as &$row)
			{
				$result_parents[$row['id_parent']][] = &$row;
				$result_ids[$row['id_category']] = &$row;
			}
			$nbr_columns = Configuration::get('CATEG_NC_NBR_COLUMN_FOOTER');
			if (!$nbr_columns)
				$nbr_columns = 3;
			$number_column = abs(count($result) / $nbr_columns);
			$width_column = floor(100 / $nbr_columns);
			$this->smarty->assign('numberColumn', $number_column);
			$this->smarty->assign('widthColumn', $width_column);

			$result_products = array();

			if (Configuration::get('CATEG_NC_NUM_PRODUCTS') == 1)
			{
				$sql = '
					SELECT `id_category`, COUNT(*) as "num_products"
					FROM `'._DB_PREFIX_.'category_product` cp
					LEFT JOIN `'._DB_PREFIX_.'product` p ON (cp.`id_product` = p.`id_product`)
					WHERE p.`active` = 1 AND ';

				$first = true;

				foreach ($result as $row)
				{
					if (!$first)

						$sql .= 'id_category = '.$row['id_category'].' OR ';
					else
						$first = false;
				}

				$sql = Tools::substr($sql, 0, Tools::strlen($sql) - 4);
				$sql .= ' GROUP BY `id_category`';

				$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS($sql);

				if ($result)
					foreach ($result as $row)
						$result_products[$row['id_category']] = $row['num_products'];
			}

			$block_categ_tree = $this->getTreeFooter($result_parents, $result_ids,
				Configuration::get('CATEG_NC_FOOTER_MAX_DEPTH'), null, 0, $result_products);
			unset($result_parents, $result_ids);

			$id_category = (int)Tools::getValue('id_category');
			$id_product = (int)Tools::getValue('id_product');

			if (Tools::isSubmit('id_category'))
			{
				$this->context->cookie->last_visited_category = $id_category;
				$this->smarty->assign('currentCategoryId', $this->context->cookie->last_visited_category);
			}
			elseif (Tools::isSubmit('id_product'))
			{
				if (!$this->context->cookie->last_visited_category
					|| !Product::idIsOnCategoryId($id_product, array('0' => array('id_category' => $this->context->cookie->last_visited_category))))
				{
					$product = new Product($id_product);
					if (Validate::isLoadedObject($product))
						$this->context->cookie->last_visited_category = (int)$product->id_category_default;
				}
				$this->smarty->assign('currentCategoryId', (int)$this->context->cookie->last_visited_category);
			}
			else
				$this->smarty->assign('currentCategoryId', $this->context->shop->getCategory());
			$this->smarty->assign(array(
				'retro' => $this->retro,
				'blockCategTree' => $block_categ_tree,
				'footerMaxDepth' => (int)Configuration::get('CATEG_NC_FOOTER_MAX_DEPTH'),
				'hideEmptyCategories' => (int)Configuration::get('CATEG_NC_HIDE_EMPTY_CATEG'),
				'showProductNum' => (int)Configuration::get('CATEG_NC_NUM_PRODUCTS'),
				'hideZeroCounts' => (int)Configuration::get('CATEG_NC_HIDE_ZERO_COUNTS')
			));

			if (file_exists(_PS_THEME_DIR_.'modules/'.$this->name.'/blockcategories_footer.tpl'))
				$this->smarty->assign('branche_tpl_path', _PS_THEME_DIR_.'modules/'.$this->name.'/category-tree-branch.tpl');
			else
				$this->smarty->assign('branche_tpl_path', _PS_MODULE_DIR_.$this->name.'/views/templates/hook/category-tree-branch.tpl');
		}
		$display = $this->display(__FILE__, 'blockcategories_footer.tpl', $this->getCacheId());

		return $display;
	}
} 

Je pense qu'il est possible de se servir de ce module pour récupérer le lien de la dernière sous rubrique qui contient les pneus pour créer un lien et placer un bouton en dessous du bouton d'ajout au panier mais je sèche totalement...

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

essayez ça

{if isset($subCategories) && count($subCategories) == 1}
<a href="{$link->getCategoryLink($subCategories[0].id_category)|escape:'htmlall':'UTF-8'}" id="{$subCategories[0].id_category}">{$subCategories[0].name}</a>
{/if}

car $child n'existe pas dans product.tpl...

 

Votre lien ne s'affichera que si la catégorie de votre produit ne contient qu'une seule sous-catégorie (pneus donc)

Link to comment
Share on other sites

Je vais être grossier mais PUTAIIIINNNNNNN DE BORRDEEEEELLLLLL DE MERRRRDEEEEE !!!!!!

 

Je me casse la tête depuis vendredi sur ça et je me rend compte que j'étais partie bien trop loin.....  

 

En effet cela fonctionne correctement et affiche très bien le lien de la sous catégorie. Que dire à part MERCI !!!

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

  • 3 weeks later...

Up. Je fais remonter le post car je cherche à afficher la sous sous catégorie.

 

Actuellement j'utilise donc ceci pour afficher un lien vers la sous categorie :

 

{if isset($subCategories) && count($subCategories) == 1}
<center><a class="exclusive button"  href="{$link->getCategoryLink($subCategories[0].id_category)|escape:'htmlall':'UTF-8'}" id="{$subCategories[0].id_category}"><span>CHOISIR</span></a></center>
{/if}

Maintenant je souhaite aller plus loin et afficher le lien vers la sous sous catégorie que j'affiche avec le code ci-dessus.

 

 

J'ai créais un fichier dans /override/ avec le code suivant :

<?php
class CategoryController extends CategoryControllerCore {
    /**
	 * Surcharge du contenu pour ajouter les sous-sous Catégories
	 */
    public function initContent() {
	    parent::initContent();
	    //Rajout des information des sous-sous catégories
	    $this->assignSubSubcategories();
    }
   
    /**
	 * Informations des sous-sous catégories
	 */
    protected function assignSubSubcategories() {
	    $subCategories = $this->category->getSubCategories($this->context->language->id);
	    $subsubCategories = array();
	   
	    foreach ( $subCategories as $subCategory ) {
	 
		    //On charge les sous-catégories pour récupérer leurs sous-catégories
		    $subCat = new Category($subCategory['id_category']);
		    if ( $subCat->getSubCategories($this->context->language->id) )
		    $subsubCategories[$subCategory['id_category']] = $subCat->getSubCategories($this->context->language->id);
	    }
	   
	    $this->context->smarty->assign('subsubCategories',$subsubCategories);
    }
}
?>

et dans le fichier product tpl :

{foreach from=$subsubCategories item=subsubCategory}
{foreach from=$subsubCategory item=subsubOk}
{if $subsubOk.id_parent == $subcategory.id_category}

<a href="{$link->getCategoryLink($subsubCategories[0].id_category)|escape:'htmlall':'UTF-8'}">test</a>

{/if}
{/foreach}
{/foreach}

Mais voilà sa ne fonctionne pas.

 

Pour info sur la hiérarchie :

 

--> Categorie Produit

       --> Sous Catégorie 1

              --> Sous Catgégorie 1.1

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

John77,

Tu surcharges CategoryController et tu fais ton assign smarty sur les pages listings pour le coup.

Donc par conséquence tu ne retrouveras pas tes variables dans ProductController et donc dans product.tpl.

 

De plus , si dans les listings $products est un tableau associatif, dans la fiche produit , $product est un objet de la classe Product.

 

Pourquoi ne pas simplement créer une override de Product et y ajouter une méthode unique genre getSubCategories();

 

ça ressemblerait à ça (à la louche et de tête hein je n'approfondis pas... donc c'est du code un peu yahourt ):

public function getSubCategories(){
$subcats = array();
$category = new Category($product->id_category_default);
$subcats = $category->getSubCategories($this->context->language->id);
foreach($subcats as &$subcat){
$subcat['subcategories']=array();
$subcatobj = new Category($subcat['id_category']);
$subcat['subcategories'][] = $subcatobj->getSubCategories($this->context->language->id);
return $subcats;
}

Pas certain qu'il n'y ait pas plus simple mais bon ... 

Dans product.tpl tu récupères un tableau complet en une seule fois avec

$product->getSubCategories();  

a toi de dumper la variable pour voir comment elle ressort  pour l'exploiter ensuite.

Link to comment
Share on other sites

J'aime bien le yaourt :)

 

j'avais pensé utiliser Category::recurseLiteCategTree(), mais bon ta solution fonctionne aussi.

 

C'est exactement à ça que je pensais en disant qu'il y avait surement plus simple ;) , sauf qu'on a un peu moins de données avec celle ci et il ne faut pas oublier de spécifier la profondeur... Je voulais pas rentrer dans le compliqué et aller ouvrir la classe lol :) 

Link to comment
Share on other sites

Je pense qu'il y a plus simple et qu'encore une fois je cherche trop loin.

 

A l'heure actuelle j'affiche un lien vers la sous categorie en utilisant :

{if isset($subCategories) && count($subCategories) == 1}
<center><a class="exclusive button" href="{$link->getCategoryLink($subCategories[0].id_category)|escape:'htmlall':'UTF-8'}" id="{$subCategories[0].id_category}"><span>CHOISIR</span></a></center>
{/if}

Cela fonctionne parfaitement aucun souci.

 

Si je rajoute une sous catégorie  il faudrait quelque chose comme ceci 

{if isset($subCategories) && count($subCategories) == 2}

Il suffirait juste pouvoir distinguer les deux sous categories afin d'afficher celle que je veux sachant que le nom de cette sous categorie sera identique à tous les produits concernés.

 

Est-il possible de ce baser la dessus ?

Link to comment
Share on other sites

oui aussi, si vos catégories sont toujours les mêmes

 

$subCategories vous renvoie un tableau, donc vous récupérez les catégories comme ça:

$subCategories[0].id_category  //1ère sous-catégorie

$subCategories[1].id_category  //2ème sous-catégorie

$subCategories[2].id_category  //3ème sous-catégorie

et ainsi de suite

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