Desirable tool : --------- client FileZilla - ftp-client for possible move images on hosting Notepad++ - program for possible edit php-pages Desirable parameters to hosting : --------- VDS - hosting for MySql - set all privileges to the user ======== - necessary do changes for Mysql server. Need set some changes for work with big database and with import big files (all values are approximate and depend on the parameters of your hosting) : sort_buffer_size=4M # for work with memory key_buffer_size = 256M # for work with memory key_buffer = 32M # for work with memory max_allowed_packet = 256M # for work with big files table_open_cache = 256 # for work with memory read_buffer_size = 2M # for work with memory read_rnd_buffer_size = 4M # for work with memory myisam_sort_buffer_size = 64M # for work with memory thread_cache_size = 8 # for work with memory query_cache_size= 16M # for work with memory connect_timeout = 2400 # longer delay due to work with large amounts of data max_heap_table_size = 256M # for work with temp files tmp_table_size = 256M # for work with temp files group_concat_max_len = 400000 # to be able to grouping data on base engine Mysql-server wait_timeout = 2400 # longer delay due to work with large amounts of data innodb_buffer_pool_size = 256M # for work with memory innodb_additional_mem_pool_size = 20M # for work with memory *********************************************************************************************** Changes that need to be undertaken to accelerate the operation of the site - you must disable unused or little used modules for [Modules]->[Front Office Features] - disable module "Categories block" or setting value to Maximum depth (set = 1) - setting or disable module "Top horizontal menu" - and etc ... ======== - specify settings for increased performance : - setting to search weight [PREFERENCES]->[SEARCH]->[WEIGHT] (for example, specify a value of zero for all values ​​except "Tags weight", that enables to search by code of analog parts) - setting to [ADVANCED PARAMETERS]->[PERFORMANCE]->[OPTIONAL FEATURES] (for example, disable values "Combinations" and "Customer Groups") - setting to [ADVANCED PARAMETERS]->[PERFORMANCE]->[CACHING] : disable caching. ======== - add new index(s) - add INDEX to field "link_rewrite" to table "_product_lang" - change PRIMARY KEY to table "_feature_product", where need set new PRIMARY KEY as [id_feature]&[id_product]$[id_feature_value] - to table "_tag" add new field "`id_manufacturer` int(10) default null" - change PRIMARY KEY to table "_tag", where need set new PRIMARY KEY as [id_tag]&[id_lang] ... All these changes make the program automatically on the page[UPLOAD DATA INTO THE STORE]=>button[CLEAN INSTALLATION] ... but automatic change of necessary data depends on the privileges of your user Mysql ======== - Changes for Prestashop version from 1.6.1.x - change for table "image" : need delete UNIQUE INDEX "id_product_cover" - change for table "image_shop" : need delete all UNIQUE INDEX | add new INDEX for column "id_product" ... All these changes make the program automatically on the page[UPLOAD DATA INTO THE STORE]=>button[CLEAN INSTALLATION] ... but automatic change of necessary data depends on the privileges of your user Mysql ======== Solution of problem connection to TecDoc in version 04/2015 Need install service pack for TecDoc 04/2015 ... - file http://www.tecdoc.de/fileadmin/downloads/tecdoc/Alles/TecDoc-Analyzer.exe - page description this and other problems http://www.tecdoc.de/en/home/products/faq/tecdoc-catalog.html ======== - for search capabilities by cross-reference code you need to change the fileS -------- ... /controllers/front/SearchController.php instead of ... elseif (($query = Tools::getValue('search_query', Tools::getValue('ref'))) && !is_array($query)) { $this->productSort(); $this->n = abs((int)(Tools::getValue('n', Configuration::get('PS_PRODUCTS_PER_PAGE')))); $this->p = abs((int)(Tools::getValue('p', 1))); $original_query = $query; $query = Tools::replaceAccentedChars(urldecode($query)); $search = Search::find($this->context->language->id, $query, $this->p, $this->n, $this->orderBy, $this->orderWay); foreach ($search['result'] as &$product) $product['link'] .= (strpos($product['link'], '?') === false ? '?' : '&').'search_query='.urlencode($query).'&results='.(int)$search['total']; Hook::exec('actionSearch', array('expr' => $query, 'total' => $search['total'])); $nbProducts = $search['total']; $this->pagination($nbProducts); $this->addColorsToProductList($search['result']); $this->context->smarty->assign(array( 'products' => $search['result'], // DEPRECATED (since to 1.4), not use this: conflict with block_cart module 'search_products' => $search['result'], 'nbProducts' => $search['total'], 'search_query' => $original_query, 'homeSize' => Image::getSize(ImageType::getFormatedName('home')))); } replaced by : elseif (($query = Tools::getValue('search_query', Tools::getValue('ref'))) && !is_array($query)) { $tag=$query; $tag=trim(str_replace(array('_', '-', '*', '.', ',', ' ', '+', '/', '|'), '', $tag)); $nbProducts = (int)(Search::searchTag($this->context->language->id, $tag, true)); $this->pagination($nbProducts); $result = Search::searchTag($this->context->language->id, $tag, false, $this->p, $this->n, $this->orderBy, $this->orderWay); Hook::exec('actionSearch', array('expr' => $tag, 'total' => count($result))); $this->context->smarty->assign(array( 'search_tag' => $tag, 'products' => $result, // DEPRECATED (since to 1.4), not use this: conflict with block_cart module 'search_products' => $result, 'nbProducts' => $nbProducts, 'homeSize' => Image::getSize(ImageType::getFormatedName('home')))); } -------- .../classes/Tag.php instead of ... WHERE `name` LIKE \'%'.pSQL($name).'%\' AND `id_lang` = '.(int)$id_lang); replaced by : WHERE `name` = \''.pSQL($name).'\' AND `id_lang` = '.(int)$id_lang); -------- .../classes/Search.php edit public static function "searchTag" for querys where are string t.`name` LIKE \'%'.pSQL($tag).'%\' replaced by : t.`name` = \''.pSQL($tag).'\' -------- .../classes/Search.php editing public static function "searchTag", comment out the call "if (Group::isFeatureActive())" public static function searchTag($id_lang, $tag, $count = false, $pageNumber = 0, $pageSize = 10, $orderBy = false, $orderWay = false, $useCookie = true, Context $context = null) { ... /*if (Group::isFeatureActive()) { $groups = FrontController::getCurrentCustomerGroups(); $sql_groups = 'AND cg.`id_group` '.(count($groups) ? 'IN ('.implode(',', $groups).')' : '= 1'); }*/ ... } editing public static function "searchTag", editing for queries ... comment out './*(Group::isFeatureActive() ? 'LEFT JOIN `'._DB_PREFIX_.'category_group` cg ON (cg.`id_category` = cp.`id_category`)' : '').*/' -------- ======== - improved search by cross-ref numbers, with sending ID Manufacturer ... -------- /controllers/front/SearchController.php ... elseif (($query = Tools::getValue('search_query', Tools::getValue('ref'))) && !is_array($query)) { ... $tag=$query; $tag=trim(str_replace(array('_', '-', '*', '.', ',', ' ', '+', '/', '|'), '', $tag)); // add checking value "braid" $braid=Tools::getValue('braid'); $nbProducts = (int)(Search::searchTag($braid, $this->context->language->id, $tag, true)); // <--- edit here, add $braid ... $result = Search::searchTag($braid, $this->context->language->id, $tag, false, $this->p, $this->n, $this->orderBy, $this->orderWay); // <--- edit here, add $braid ... } ... -------- .../classes/Search.php editing head for function "searchTag" public static function searchTag($id_lang, $tag, $count = false, $pageNumber = 0, $pageSize = 10, $orderBy = false, $orderWay = false, $useCookie = true, Context $context = null) change in, add "$braid = null" public static function searchTag($braid = null, $id_lang, $tag, $count = false, $pageNumber = 0, $pageSize = 10, $orderBy = false, $orderWay = false, $useCookie = true, Context $context = null) -------- .../classes/Search.php editing function "searchTag" public static function searchTag($braid = null, $id_lang, $tag, $count = false, $pageNumber = 0, $pageSize = 10, $orderBy = false, $orderWay = false, $useCookie = true, Context $context = null) { // add $tag_bra_id = ''; IF ($braid != null && $braid != '') {$tag_bra_id = ' AND t.`id_manufacturer` = '.(int)$braid.' ';}; ... } -------- .../classes/Search.php editing queries for function "searchTag", where are "AND t.`name` = \''.pSQL($tag).'\'" need change on "AND t.`name` = \''.pSQL($tag).'\' '.$tag_bra_id.'" instead of ... AND t.`name` = \''.pSQL($tag).'\' replaced by : AND t.`name` = \''.pSQL($tag).'\' '.$tag_bra_id.' -------- .../classes/Tag.php editing function "getProductTags", for SELECT add t.`id_manufacturer` and "$result[$tag['id_lang']][]" change on "$result[$tag['id_lang']][] = $tag['brand'].'|'.$tag['name'].'|'.$tag['id_manufacturer'];" instead of ... public static function getProductTags($id_product) { if (!$tmp = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT t.`id_lang`, t.`name`, (select m.`name` from '._DB_PREFIX_.'manufacturer as m where m.`id_manufacturer` = t.`id_manufacturer`) as brand FROM '._DB_PREFIX_.'tag t LEFT JOIN '._DB_PREFIX_.'product_tag pt ON (pt.id_tag = t.id_tag) WHERE pt.`id_product`='.(int)$id_product.' ORDER BY brand, name')) return false; $result = array(); foreach ($tmp as $tag) $result[$tag['id_lang']][] = $tag['brand'].'|'.$tag['name']; return $result; } replaced by : public static function getProductTags($id_product) { if (!$tmp = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT t.`id_lang`, t.`name`, t.`id_manufacturer`, (select m.`name` from '._DB_PREFIX_.'manufacturer as m where m.`id_manufacturer` = t.`id_manufacturer`) as brand FROM '._DB_PREFIX_.'tag t LEFT JOIN '._DB_PREFIX_.'product_tag pt ON (pt.id_tag = t.id_tag) WHERE pt.`id_product`='.(int)$id_product.' ORDER BY brand, name')) return false; $result = array(); foreach ($tmp as $tag) $result[$tag['id_lang']][] = $tag['brand'].'|'.$tag['name'].'|'.$tag['id_manufacturer']; return $result; } ======== - the ability to check the brand for search number, as like http://demoprestashop.ttc.bovsoft.com/search?controller=search&orderby=position&orderway=desc&search_query=C422&submit_search= first need do change which is in description for "improved search by cross-ref numbers, with sending ID Manufacturer ..." -------- ... /classes/Search.php add new function for view panel (new class="list-of-brands-for-search" for css) list of brands public static function searchListBrandsForTag($id_lang, $tagg) { if (!$tmp = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT /* DISTINCT */ t.`name`, t.`id_manufacturer`, (select m.`name` from '._DB_PREFIX_.'manufacturer as m where m.`id_manufacturer` = t.`id_manufacturer`) as brand ,(SELECT MIN(cl.name) FROM '._DB_PREFIX_.'category_lang as cl JOIN '._DB_PREFIX_.'product as p on (cl.id_category = p.id_category_default) JOIN '._DB_PREFIX_.'product_tag as pt on (p.id_product = pt.id_product) WHERE pt.id_tag = t.id_tag and cl.id_lang = '.(int)$id_lang.' ) as nameparts FROM '._DB_PREFIX_.'tag t WHERE t.`name`= \''.$tagg.'\' AND t.`id_lang` = '.(int)$id_lang.' GROUP BY brand, name ')) return null; $result = ''; return $result; } -------- ... /controllers/front/SearchController.php ... elseif (($query = Tools::getValue('search_query', Tools::getValue('ref'))) && !is_array($query)) { ... // add $listbrands = Search::searchListBrandsForTag($this->context->language->id, $tag); $this->context->smarty->assign(array( ... 'listbrands' => $listbrands, // add 'braid' => $braid, // add ... 'homeSize' => Image::getSize(ImageType::getFormatedName('home')))); } ... -------- ... yourtemes/search.tpl {if !$nbProducts} ... {else} {if isset($instant_search) && $instant_search}

{if $nbProducts == 1}{l s='%d result has been found.' sprintf=$nbProducts|intval}{else}{l s='%d results have been found.' sprintf=$nbProducts|intval}{/if}

{/if}
{include file="$tpl_dir./product-sort.tpl"} {if !isset($instant_search) || (isset($instant_search) && !$instant_search)} {include file="./nbr-product-page.tpl"} {/if}
{include file="./product-compare.tpl"} {if !isset($instant_search) || (isset($instant_search) && !$instant_search)} {include file="$tpl_dir./pagination.tpl"} {/if}
{include file="$tpl_dir./product-list.tpl" products=$search_products}
{include file="./product-compare.tpl"} {if !isset($instant_search) || (isset($instant_search) && !$instant_search)} {include file="$tpl_dir./pagination.tpl" paginationId='bottom'} {/if}
{/if} replaced by : {if !$nbProducts} ... {else} {if $braid == ''} {$listbrands} {else} {if isset($instant_search) && $instant_search}

{if $nbProducts == 1}{l s='%d result has been found.' sprintf=$nbProducts|intval}{else}{l s='%d results have been found.' sprintf=$nbProducts|intval}{/if}

{/if}
{include file="$tpl_dir./product-sort.tpl"} {if !isset($instant_search) || (isset($instant_search) && !$instant_search)} {include file="./nbr-product-page.tpl"} {/if}
{include file="./product-compare.tpl"} {if !isset($instant_search) || (isset($instant_search) && !$instant_search)} {include file="$tpl_dir./pagination.tpl"} {/if}
{include file="$tpl_dir./product-list.tpl" products=$search_products}
{include file="./product-compare.tpl"} {if !isset($instant_search) || (isset($instant_search) && !$instant_search)} {include file="$tpl_dir./pagination.tpl" paginationId='bottom'} {/if}
{/if} {/if} -------- ======== - for the possibility of displaying a list of cross-references codes on the product page -------- ... /classes/Tag.php instead of ... public static function getProductTags($id_product) { if (!$tmp = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT t.`id_lang`, t.`name` FROM '._DB_PREFIX_.'tag t LEFT JOIN '._DB_PREFIX_.'product_tag pt ON (pt.id_tag = t.id_tag) WHERE pt.`id_product`='.(int)$id_product)) return false; $result = array(); foreach ($tmp as $tag) $result[$tag['id_lang']][] = $tag['brand'].'|'.$tag['name']; return $result; } replaced by : public static function getProductTags($id_product) { if (!$tmp = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT t.`id_lang`, t.`name`, (select m.`name` from '._DB_PREFIX_.'manufacturer as m where m.`id_manufacturer` = t.`id_manufacturer`) as brand FROM '._DB_PREFIX_.'tag t LEFT JOIN '._DB_PREFIX_.'product_tag pt ON (pt.id_tag = t.id_tag) WHERE pt.`id_product`='.(int)$id_product.' ORDER BY brand, name')) return false; $result = array(); foreach ($tmp as $tag) $result[$tag['id_lang']][] = $tag['brand'].'|'.$tag['name']; return $result; } -------- ... /themes/yourthemes/product.tpl add new panel (for example insert after panel "Data sheet") {if $product->tags}

CROSS REFERENCES NUMBERS

{foreach from=$product->tags item=tag1} {foreach from=$tag1 item=tag} {if isset($tag)} {$tag_1=strtok($tag, '|')} {$tag_2=strtok('|')} {$tag_3=strtok('|')} {if $tag_2 == ''} {$tag_2 = $tag_1} {$tag_1 = '---'} {/if} {/if} {/foreach} {/foreach}
{$tag_1|escape:'html':'UTF-8'} {$tag_2}
{/if} -------- ======== - for the possibility of displaying a list of vehicles for which are used a specified spare part -------- /classes/Product.php add new public value to class "ProductCore" class ProductCore extends ObjectModel { ... /*** @var array aplicability */ public $aplicability; ... } -------- /classes/Product.php add new function "getProductAplicability" for create list vehicle for which are used the spare part public static function getProductAplicability($id_product) { $id_lang = (int)Context::getContext()->language->id; $id_shop = (int)Context::getContext()->shop->id; $result = array(); $tmp = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT DISTINCT T2.id_category AS ID, (select min(M4.NAME) from '._DB_PREFIX_.'category_lang as M4 where (M4.id_shop = '.(int)$id_shop.') AND (M4.id_lang = '.(int)$id_lang.') and (M4.id_category = T4.id_category)) AS nameCAT_1, (select min(M3.NAME) from '._DB_PREFIX_.'category_lang as M3 where (M3.id_shop = '.(int)$id_shop.') AND (M3.id_lang = '.(int)$id_lang.') and (M3.id_category = T3.id_category)) AS nameCAT_2, (select min(M2.NAME) from '._DB_PREFIX_.'category_lang as M2 where (M2.id_shop = '.(int)$id_shop.') AND (M2.id_lang = '.(int)$id_lang.') and (M2.id_category = T2.id_category)) AS nameCAT_3 FROM '._DB_PREFIX_.'category_lang AS M join '._DB_PREFIX_.'category_product as CatProd on (M.id_category = CatProd.id_category) JOIN '._DB_PREFIX_.'category AS T ON (T.id_category = M.id_category) JOIN '._DB_PREFIX_.'category AS T1 ON (T1.id_category = T.id_parent) JOIN '._DB_PREFIX_.'category AS T2 ON (T2.id_category = T1.id_parent) JOIN '._DB_PREFIX_.'category AS T3 ON (T3.id_category = T2.id_parent) JOIN '._DB_PREFIX_.'category AS T4 ON (T4.id_category = T3.id_parent) WHERE CatProd.id_product = '.(int)$id_product.' and (M.id_shop = '.(int)$id_shop.') AND (M.id_lang = '.(int)$id_lang.') ORDER BY nameCAT_1, nameCAT_2, nameCAT_3 LIMIT 30'); if ($tmp) foreach ($tmp as $aplic) $result[] = $aplic['nameCAT_1'].'^'.$aplic['nameCAT_2'].'^'.$aplic['nameCAT_3'].'^'.$aplic['ID']; return $result; } -------- /classes/Product.php edit of function "__construct" for add a call new function "getProductAplicability" public function __construct($id_product = null, $full = false, $id_lang = null, $id_shop = null, Context $context = null) { ... ... if ($full && $this->id) { ... // ADD if ($this->id) $this->aplicability = Product::getProductAplicability((int)$this->id); // ***************************************************************************** ... } ... } -------- ... /themes/yourthemes/product.tpl add new panel (for example insert after panel "Data sheet")

APLICABILITY

{foreach from=$product->aplicability item=tag1} {foreach from=$tag1 item=tag} {if isset($tag)} {$tag_1=strtok($tag, '^')} {$tag_2=strtok('^')} {$tag_3=strtok('^')} {$tag_4=strtok('^')} {if ($tag_4 != '' && $tag_1 != 'Root') } {/if} {/if} {/foreach} {/foreach}
{$tag_1|escape:'html':'UTF-8'} {$tag_2|escape:'html':'UTF-8'} {$tag_3|escape:'html':'UTF-8'}
-------- ======== - error correction (long download time to pages) PrestaShop in time creating a list of categories, because that PrestaShop doing checks all categories for links with user groups (this error occurs on pages that work with controller "category") -------- /classes/category.php correction of query for obtain of list of categories change for function ... public static function getNestedCategories($root_category = null, $id_lang = false, $active = true, $groups = null, $use_shop_restriction = true, $sql_filter = '', $sql_sort = '', $sql_limit = '') { ... if (!Cache::isStored($cache_id)) { $result = Db::getInstance()->executeS(' SELECT c.*, cl.* FROM `'._DB_PREFIX_.'category` c '.($use_shop_restriction ? Shop::addSqlAssociation('category', 'c') : '').' LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON c.`id_category` = cl.`id_category`'.Shop::addSqlRestrictionOnLang('cl').' '.(isset($groups) && Group::isFeatureActive() ? 'LEFT JOIN `'._DB_PREFIX_.'category_group` cg ON c.`id_category` = cg.`id_category`' : '').' '.(isset($root_category) ? 'RIGHT JOIN `'._DB_PREFIX_.'category` c2 ON c2.`id_category` = '.(int)$root_category.' AND c.`nleft` >= c2.`nleft` AND c.`nright` <= c2.`nright`' : '').' WHERE 1 '.$sql_filter.' '.($id_lang ? 'AND `id_lang` = '.(int)$id_lang : '').' '.($active ? ' AND c.`active` = 1' : '').' '.(isset($groups) && Group::isFeatureActive() ? ' AND cg.`id_group` IN ('.implode(',', $groups).')' : '').' '.(!$id_lang || (isset($groups) && Group::isFeatureActive()) ? ' GROUP BY c.`id_category`' : '').' '.($sql_sort != '' ? $sql_sort : ' ORDER BY c.`level_depth` ASC').' '.($sql_sort == '' && $use_shop_restriction ? ', category_shop.`position` ASC' : '').' '.($sql_limit != '' ? $sql_limit : '') ); ... } ... } replaced by : public static function getNestedCategories($root_category = null, $id_lang = false, $active = true, $groups = null, $use_shop_restriction = true, $sql_filter = '', $sql_sort = '', $sql_limit = '') { ... if (!Cache::isStored($cache_id)) { $result = Db::getInstance()->executeS(' SELECT c.*, cl.* FROM `'._DB_PREFIX_.'category` c '.($use_shop_restriction ? Shop::addSqlAssociation('category', 'c') : '').' LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON c.`id_category` = cl.`id_category`'.Shop::addSqlRestrictionOnLang('cl').' '.(isset($root_category) ? 'RIGHT JOIN `'._DB_PREFIX_.'category` c2 ON c2.`id_category` = '.(int)$root_category.' AND c.`nleft` >= c2.`nleft` AND c.`nright` <= c2.`nright`' : '').' WHERE (c.`id_parent` <= 4) '.$sql_filter.' '.($id_lang ? 'AND `id_lang` = '.(int)$id_lang : '').' '.($active ? ' AND c.`active` = 1' : '').' '.($sql_sort != '' ? $sql_sort : ' ORDER BY c.`level_depth` ASC').' '.($sql_sort == '' && $use_shop_restriction ? ', category_shop.`position` ASC' : '').' '.($sql_limit != '' ? $sql_limit : '') ); ... } ... } -------- /classes/category.php correction of query for obtain of list of categories change for function (comment out the function call) ... public function getSubCategories($id_lang, $active = true) { ... if (Group::isFeatureActive()) { $sql_groups_join = 'LEFT JOIN `'._DB_PREFIX_.'category_group` cg ON (cg.`id_category` = c.`id_category`)'; $groups = FrontController::getCurrentCustomerGroups(); $sql_groups_where = 'AND cg.`id_group` '.(count($groups) ? 'IN ('.implode(',', $groups).')' : '='.(int)Group::getCurrent()->id); } ... } replaced by : public function getSubCategories($id_lang, $active = true) { ... /*if (Group::isFeatureActive()) { $sql_groups_join = 'LEFT JOIN `'._DB_PREFIX_.'category_group` cg ON (cg.`id_category` = c.`id_category`)'; $groups = FrontController::getCurrentCustomerGroups(); $sql_groups_where = 'AND cg.`id_group` '.(count($groups) ? 'IN ('.implode(',', $groups).')' : '='.(int)Group::getCurrent()->id); }*/ ... } -------- /classes/category.php correction of query change for function ... public function checkAccess($id_customer) { $cache_id = 'Category::checkAccess_'.(int)$this->id.'-'.$id_customer.(!$id_customer ? '-'.(int)Group::getCurrent()->id : ''); if (!Cache::isStored($cache_id)) { if (!$id_customer) $result = (bool)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue(' SELECT ctg.`id_group` FROM '._DB_PREFIX_.'category_group ctg WHERE ctg.`id_category` = '.(int)$this->id.' AND ctg.`id_group` = '.(int)Group::getCurrent()->id); else $result = (bool)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue(' SELECT ctg.`id_group` FROM '._DB_PREFIX_.'category_group ctg INNER JOIN '._DB_PREFIX_.'customer_group cg on (cg.`id_group` = ctg.`id_group` AND cg.`id_customer` = '.(int)$id_customer.') WHERE ctg.`id_category` = '.(int)$this->id); Cache::store($cache_id, $result); } return Cache::retrieve($cache_id); } replaced by : public function checkAccess($id_customer) { return true; } -------- ======== - Sort subcategories by name -------- /classes/category.php edit query for function[getSubCategories]->value[$result]->edit row with "ORDER BY" instead of ... ORDER BY `level_depth` ASC, category_shop.`position` ASC'); replaced by : ORDER BY cl.`name`, `level_depth` ASC, category_shop.`position` ASC'); -------- ======== - Ability to display the "top menu" bar -------- /modules/blocktopmenu/blocktopmenu.php edit private function "generateCategoriesMenu" private function generateCategoriesMenu($categories, $is_children = 0) { $html = ''; foreach ($categories as $key => $category) { ... // add link for category $link = $this->context->link->getCategoryLink((int)$category['id_category']); ... if (isset($category['children']) && !empty($category['children'])) { ... instead of ... $html .= $this->generateCategoriesMenu($category['children'], 1); replaced by : if ($is_children == 0) // bovsoft $html .= $this->generateCategoriesMenu($category['children'], 1); ... } ... } ... } -------- /modules/blocktopmenu/blocktopmenu.php edit private function "customGetNestedCategories" instead of ... public function customGetNestedCategories($shop_id, $root_category = null, $id_lang = false, $active = true, $groups = null, $use_shop_restriction = true, $sql_filter = '', $sql_sort = '', $sql_limit = '') { ... if (!Cache::isStored($cache_id)) { ... $result = Db::getInstance()->executeS(' SELECT c.*, cl.* FROM `'._DB_PREFIX_.'category` c INNER JOIN `'._DB_PREFIX_.'category_shop` category_shop ON (category_shop.`id_category` = c.`id_category` AND category_shop.`id_shop` = "'.(int)$shop_id.'") LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (c.`id_category` = cl.`id_category` AND cl.`id_shop` = "'.(int)$shop_id.'") WHERE 1 '.$sql_filter.' '.($id_lang ? 'AND cl.`id_lang` = '.(int)$id_lang : '').' '.($active ? ' AND (c.`active` = 1 OR c.`is_root_category` = 1)' : '').' '.(isset($groups) && Group::isFeatureActive() ? ' AND cg.`id_group` IN ('.implode(',', $groups).')' : '').' '.(!$id_lang || (isset($groups) && Group::isFeatureActive()) ? ' GROUP BY c.`id_category`' : '').' '.($sql_sort != '' ? $sql_sort : ' ORDER BY c.`level_depth` ASC').' '.($sql_sort == '' && $use_shop_restriction ? ', category_shop.`position` ASC' : '').' '.($sql_limit != '' ? $sql_limit : '') ); ... } ... } replaced by : public function customGetNestedCategories($shop_id, $root_category = null, $id_lang = false, $active = true, $groups = null, $use_shop_restriction = true, $sql_filter = '', $sql_sort = '', $sql_limit = '') { ... if (!Cache::isStored($cache_id)) { ... $result = Db::getInstance()->executeS(' SELECT c.*, cl.* FROM `'._DB_PREFIX_.'category` c INNER JOIN `'._DB_PREFIX_.'category_shop` category_shop ON (category_shop.`id_category` = c.`id_category` AND category_shop.`id_shop` = "'.(int)$shop_id.'") LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (c.`id_category` = cl.`id_category` AND cl.`id_shop` = "'.(int)$shop_id.'") WHERE (c.`id_parent` <= 4) '.$sql_filter.' '.($id_lang ? 'AND cl.`id_lang` = '.(int)$id_lang : '').' '.($active ? ' AND (c.`active` = 1 OR c.`is_root_category` = 1)' : '').' order by c.`id_parent`, cl.`name` '.($sql_limit != '' ? $sql_limit : '') ); ... } ... } -------- /yourthemes/category.tpl Ability to display subcategories (need disable module "Categories block", as there is error with display categories in query for load list categories) edit block "" ... disable scanning to display subcategories {if (isset($display_subcategories) && $display_subcategories eq 1) || !isset($display_subcategories) } -------- ======== - editing class "Product", allowing enable some modules for works with products, for example module "New Products" -------- /classes/Product.php editing public static function "getNewProducts",comment out the call "if (Group::isFeatureActive())" public static function getNewProducts($id_lang, $page_number = 0, $nb_products = 10, $count = false, $order_by = null, $order_way = null, Context $context = null) { ... /*if (Group::isFeatureActive()) { $groups = FrontController::getCurrentCustomerGroups(); $sql_groups = 'AND p.`id_product` IN ( SELECT cp.`id_product` FROM `'._DB_PREFIX_.'category_group` cg LEFT JOIN `'._DB_PREFIX_.'category_product` cp ON (cp.`id_category` = cg.`id_category`) WHERE cg.`id_group` '.(count($groups) ? 'IN ('.implode(',', $groups).')' : '= 1').' )'; }*/ ... /*if (Group::isFeatureActive()) $sql->where('p.`id_product` IN ( SELECT cp.`id_product` FROM `'._DB_PREFIX_.'category_group` cg LEFT JOIN `'._DB_PREFIX_.'category_product` cp ON (cp.`id_category` = cg.`id_category`) WHERE cg.`id_group` '.$sql_groups.' )');*/ ... } -------- /classes/Product.php editing public static function "getRandomSpecial" public static function getRandomSpecial($id_lang, $beginning = false, $ending = false, Context $context = null) { ... if ($product_reductions) { ... $sql = 'SELECT product_shop.id_product, MAX(product_attribute_shop.id_product_attribute) id_product_attribute FROM `'._DB_PREFIX_.'product` p '.Shop::addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (product_shop.id_product = pa.id_product) '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.default_on = 1').' WHERE product_shop.`active` = 1 '.(($ids_product) ? $ids_product : '').' AND p.`id_product` IN ( SELECT cp.`id_product` FROM `'._DB_PREFIX_.'category_group` cg LEFT JOIN `'._DB_PREFIX_.'category_product` cp ON (cp.`id_category` = cg.`id_category`) WHERE cg.`id_group` '.$sql_groups.' ) '.($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '').' GROUP BY product_shop.id_product ORDER BY RAND()'; ... } } replaced by : public static function getRandomSpecial($id_lang, $beginning = false, $ending = false, Context $context = null) { ... if ($product_reductions) { ... $sql = 'SELECT product_shop.id_product, MAX(product_attribute_shop.id_product_attribute) id_product_attribute FROM `'._DB_PREFIX_.'product` p '.Shop::addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (product_shop.id_product = pa.id_product) '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.default_on = 1').' WHERE product_shop.`active` = 1 '.(($ids_product) ? $ids_product : '').' '.($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '').' GROUP BY product_shop.id_product ORDER BY RAND()'; ... } } -------- /classes/Product.php editing public static function "getPricesDrop", comment out the call "if (Group::isFeatureActive())" public static function getPricesDrop($id_lang, $page_number = 0, $nb_products = 10, $count = false, $order_by = null, $order_way = null, $beginning = false, $ending = false, Context $context = null) { ... /*if (Group::isFeatureActive()) { $groups = FrontController::getCurrentCustomerGroups(); $sql_groups = 'AND p.`id_product` IN ( SELECT cp.`id_product` FROM `'._DB_PREFIX_.'category_group` cg LEFT JOIN `'._DB_PREFIX_.'category_product` cp ON (cp.`id_category` = cg.`id_category`) WHERE cg.`id_group` '.(count($groups) ? 'IN ('.implode(',', $groups).')' : '= 1').' )'; }*/ ... } -------- /classes/Product.php editing public function "checkAccess" public function checkAccess($id_customer) { if (!Group::isFeatureActive()) return true; $cache_id = 'Product::checkAccess_'.(int)$this->id.'-'.(int)$id_customer.(!$id_customer ? '-'.(int)Group::getCurrent()->id : ''); if (!Cache::isStored($cache_id)) { if (!$id_customer) $result = (bool)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue(' SELECT ctg.`id_group` FROM `'._DB_PREFIX_.'category_product` cp INNER JOIN `'._DB_PREFIX_.'category_group` ctg ON (ctg.`id_category` = cp.`id_category`) WHERE cp.`id_product` = '.(int)$this->id.' AND ctg.`id_group` = '.(int)Group::getCurrent()->id); else $result = (bool)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue(' SELECT cg.`id_group` FROM `'._DB_PREFIX_.'category_product` cp INNER JOIN `'._DB_PREFIX_.'category_group` ctg ON (ctg.`id_category` = cp.`id_category`) INNER JOIN `'._DB_PREFIX_.'customer_group` cg ON (cg.`id_group` = ctg.`id_group`) WHERE cp.`id_product` = '.(int)$this->id.' AND cg.`id_customer` = '.(int)$id_customer); Cache::store($cache_id, $result); } return Cache::retrieve($cache_id); } replaced by : public function checkAccess($id_customer) { return true; } -------- ======== - ABILITY TO DISPLAY FOR DESCRIPTION OF THE CONDITIONS OF APPLICATION OF SPARE PARTS FOR THE SELECTED CATEGORY 1. first need fill database sql-data which was creating on page "Export data" 2. create empty table with your prefix CREATE TABLE IF NOT EXISTS `ps_TermOfUseFromTecDoc` (`id_category` int(10) NOT NULL, `id_product` int(10) NOT NULL, `id_lang` int(10) NOT NULL, `id_feature` int(10) DEFAULT '0', `value` varchar(255) DEFAULT NULL, KEY `idcat_idprod` (`id_category`, `id_product`), KEY `id_product` (`id_product`)); ... create table "TermsOfUse" http://ttc.bovsoft.com/download/creatorforprestashop_ver_1.2.5.jpg -------- /classes/Category.php change query for function "getProducts" $sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, MAX(product_attribute_shop.id_product_attribute) id_product_attribute, product_attribute_shop.minimal_quantity AS product_attribute_minimal_quantity, pl.`description`, pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, MAX(image_shop.`id_image`) id_image, il.`legend`, m.`name` AS manufacturer_name, cl.`name` AS category_default, DATEDIFF(product_shop.`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, product_shop.price AS orderprice FROM `'._DB_PREFIX_.'category_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product` '.Shop::addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (p.`id_product` = pa.`id_product`) '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.`default_on` = 1').' '.Product::sqlStock('p', 'product_attribute_shop', false, $context->shop).' 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_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').') 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 (image_shop.`id_image` = il.`id_image` AND il.`id_lang` = '.(int)$id_lang.') LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer` WHERE product_shop.`id_shop` = '.(int)$context->shop->id.' AND cp.`id_category` = '.(int)$this->id .($active ? ' AND product_shop.`active` = 1' : '') .($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '') .($id_supplier ? ' AND p.id_supplier = '.(int)$id_supplier : '') .' GROUP BY product_shop.id_product'; replaced by : $sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, MAX(product_attribute_shop.id_product_attribute) id_product_attribute, product_attribute_shop.minimal_quantity AS product_attribute_minimal_quantity, pl.`description`, pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`meta_description`, pl.`meta_keywords`, pl.`meta_title`, pl.`name`, MAX(image_shop.`id_image`) id_image, il.`legend`, m.`name` AS manufacturer_name, cl.`name` AS category_default, DATEDIFF(product_shop.`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, product_shop.price AS orderprice ,(SELECT DISTINCT GROUP_CONCAT(CONCAT(fln.`name`," :: ",fval.`value`) SEPARATOR "
") FROM '._DB_PREFIX_.'feature_product as fpr JOIN '._DB_PREFIX_.'feature_lang as fln ON (fln.`id_feature` = fpr.`id_feature`) JOIN '._DB_PREFIX_.'feature_value_lang fval ON (fval.`id_feature_value` = fpr.`id_feature_value`) where (id_product = p.`id_product`) AND (fln.`id_lang` = '.(int)$id_lang.') AND (fval.`id_lang` = '.(int)$id_lang.') ) AS feature ,(SELECT DISTINCT GROUP_CONCAT(CONCAT(fln2.`name`," :: ",tuse.`value`) SEPARATOR "
") FROM '._DB_PREFIX_.'TermOfUseFromTecDoc as tuse LEFT JOIN '._DB_PREFIX_.'feature_lang as fln2 ON (fln2.`id_feature` = tuse.`id_feature` AND fln2.`id_lang` = '.(int)$id_lang.') JOIN '._DB_PREFIX_.'category AS T1 ON (tuse.id_category = T1.id_category) JOIN '._DB_PREFIX_.'category AS T2 ON (T1.id_category = T2.id_parent) JOIN '._DB_PREFIX_.'category AS T3 ON (T2.id_category = T3.id_parent) where (tuse.`id_product` = p.`id_product`) AND (T3.`id_category` = '.(int)$this->id.') AND (tuse.`id_lang` = '.(int)$id_lang.') ) AS termsofuse FROM `'._DB_PREFIX_.'category_product` cp LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product` '.Shop::addSqlAssociation('product', 'p').' LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (p.`id_product` = pa.`id_product`) '.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.`default_on` = 1').' '.Product::sqlStock('p', 'product_attribute_shop', false, $context->shop).' 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_.'product_lang` pl ON (p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').') 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 (image_shop.`id_image` = il.`id_image` AND il.`id_lang` = '.(int)$id_lang.') LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer` WHERE product_shop.`id_shop` = '.(int)$context->shop->id.' AND cp.`id_category` = '.(int)$this->id .($active ? ' AND product_shop.`active` = 1' : '') .($front ? ' AND product_shop.`visibility` IN ("both", "catalog")' : '') .($id_supplier ? ' AND p.id_supplier = '.(int)$id_supplier : '') .' GROUP BY product_shop.id_product'; -------- /classes/Search.php change query for function "searchTag" $sql = 'SELECT DISTINCT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, pl.`description_short`, pl.`link_rewrite`, pl.`name`, MAX(image_shop.`id_image`) id_image, il.`legend`, m.`name` manufacturer_name, 1 position, 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 new FROM `'._DB_PREFIX_.'product` p INNER JOIN `'._DB_PREFIX_.'product_lang` pl ON ( p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').' ) '.Shop::addSqlAssociation('product', 'p', false).' 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 (m.`id_manufacturer` = p.`id_manufacturer`) LEFT JOIN `'._DB_PREFIX_.'product_tag` pt ON (p.`id_product` = pt.`id_product`) LEFT JOIN `'._DB_PREFIX_.'tag` t ON (pt.`id_tag` = t.`id_tag` AND t.`id_lang` = '.(int)$id_lang.') LEFT JOIN `'._DB_PREFIX_.'category_product` cp ON (cp.`id_product` = p.`id_product`) '.(Group::isFeatureActive() ? 'LEFT JOIN `'._DB_PREFIX_.'category_group` cg ON (cg.`id_category` = cp.`id_category`)' : '').' LEFT JOIN `'._DB_PREFIX_.'category_shop` cs ON (cp.`id_category` = cs.`id_category` AND cs.`id_shop` = '.(int)$id_shop.') '.Product::sqlStock('p', 0).' WHERE product_shop.`active` = 1 AND cs.`id_shop` = '.(int)Context::getContext()->shop->id.' '.$sql_groups.' AND t.`name` = \''.pSQL($tag).'\' GROUP BY product_shop.id_product ORDER BY position DESC'.($orderBy ? ', '.$orderBy : '').($orderWay ? ' '.$orderWay : '').' LIMIT '.(int)(($pageNumber - 1) * $pageSize).','.(int)$pageSize; replaced by : $sql = 'SELECT DISTINCT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity, pl.`description_short`, pl.`link_rewrite`, pl.`name`, MAX(image_shop.`id_image`) id_image, il.`legend`, m.`name` manufacturer_name, 1 position, 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 new ,(SELECT DISTINCT GROUP_CONCAT(CONCAT(fln.`name`," :: ",fval.`value`) SEPARATOR "
") FROM '._DB_PREFIX_.'feature_product as fpr JOIN '._DB_PREFIX_.'feature_lang as fln ON (fln.`id_feature` = fpr.`id_feature`) JOIN '._DB_PREFIX_.'feature_value_lang fval ON (fval.`id_feature_value` = fpr.`id_feature_value`) where (id_product = p.`id_product`) AND (fln.`id_lang` = '.(int)$id_lang.') AND (fval.`id_lang` = '.(int)$id_lang.') ) AS feature FROM `'._DB_PREFIX_.'product` p INNER JOIN `'._DB_PREFIX_.'product_lang` pl ON ( p.`id_product` = pl.`id_product` AND pl.`id_lang` = '.(int)$id_lang.Shop::addSqlRestrictionOnLang('pl').' ) '.Shop::addSqlAssociation('product', 'p', false).' 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 (m.`id_manufacturer` = p.`id_manufacturer`) LEFT JOIN `'._DB_PREFIX_.'product_tag` pt ON (p.`id_product` = pt.`id_product`) LEFT JOIN `'._DB_PREFIX_.'tag` t ON (pt.`id_tag` = t.`id_tag` AND t.`id_lang` = '.(int)$id_lang.') LEFT JOIN `'._DB_PREFIX_.'category_product` cp ON (cp.`id_product` = p.`id_product`) '.(Group::isFeatureActive() ? 'LEFT JOIN `'._DB_PREFIX_.'category_group` cg ON (cg.`id_category` = cp.`id_category`)' : '').' LEFT JOIN `'._DB_PREFIX_.'category_shop` cs ON (cp.`id_category` = cs.`id_category` AND cs.`id_shop` = '.(int)$id_shop.') '.Product::sqlStock('p', 0).' WHERE product_shop.`active` = 1 AND cs.`id_shop` = '.(int)Context::getContext()->shop->id.' '.$sql_groups.' AND t.`name` = \''.pSQL($tag).'\' GROUP BY product_shop.id_product ORDER BY position DESC'.($orderBy ? ', '.$orderBy : '').($orderWay ? ' '.$orderWay : '').' LIMIT '.(int)(($pageNumber - 1) * $pageSize).','.(int)$pageSize; -------- \themes\yourtemes\product-list.tpl change class "product-desc", add 2 rows

... {if isset($product.termsofuse)}{$product.termsofuse}
{/if} {$product.feature} ...

-------- ======== - for opportunity to correct display "breadcrumb"-string -------- /classes/Product.php add new public value to class "breadcrumb_path" class ProductCore extends ObjectModel { ... // add public $breadcrumb_path; ... } -------- /classes/Product.php add new procedure getBreadcrumbPath public static function getBreadcrumbPath($id_product) { $id_lang = (int)Context::getContext()->language->id; $id_shop = (int)Context::getContext()->shop->id; $tmp = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT DISTINCT T1.id_category AS ID1, T2.id_category AS ID2, T.id_category AS ID3, (select min(M4.NAME) from '._DB_PREFIX_.'category_lang as M4 where (M4.id_shop = '.(int)$id_shop.') AND (M4.id_lang = '.(int)$id_lang.') and (M4.id_category = T4.id_category)) AS nameCAT_1, (select min(M3.NAME) from '._DB_PREFIX_.'category_lang as M3 where (M3.id_shop = '.(int)$id_shop.') AND (M3.id_lang = '.(int)$id_lang.') and (M3.id_category = T3.id_category)) AS nameCAT_2, (select min(M2.NAME) from '._DB_PREFIX_.'category_lang as M2 where (M2.id_shop = '.(int)$id_shop.') AND (M2.id_lang = '.(int)$id_lang.') and (M2.id_category = T2.id_category)) AS nameCAT_3, (select min(M1.NAME) from '._DB_PREFIX_.'category_lang as M1 where (M1.id_shop = '.(int)$id_shop.') AND (M1.id_lang = '.(int)$id_lang.') and (M1.id_category = T1.id_category)) AS nameCAT_4, M.name AS nameCAT_5 FROM '._DB_PREFIX_.'category_lang AS M JOIN '._DB_PREFIX_.'product as CatProd on (M.id_category = CatProd.id_category_default) JOIN '._DB_PREFIX_.'category AS T ON (T.id_category = M.id_category) JOIN '._DB_PREFIX_.'category AS T1 ON (T1.id_category = T.id_parent) JOIN '._DB_PREFIX_.'category AS T2 ON (T2.id_category = T1.id_parent) JOIN '._DB_PREFIX_.'category AS T3 ON (T3.id_category = T2.id_parent) JOIN '._DB_PREFIX_.'category AS T4 ON (T4.id_category = T3.id_parent) WHERE CatProd.id_product = '.(int)$id_product.' AND CatProd.id_category_default IS NOT NULL AND (M.id_shop = '.(int)$id_shop.') AND (M.id_lang = '.(int)$id_lang.') LIMIT 1'); if ($tmp) foreach ($tmp as $aplic) $result = $aplic['nameCAT_3'].'^'.$aplic['ID2'].'^'.$aplic['nameCAT_4'].'^'.$aplic['ID1'].'^'.$aplic['nameCAT_5'].'^'.$aplic['ID3']; return $result; } -------- /classes/Product.php initialization data ... public function __construct($id_product = null, $full = false, $id_lang = null, $id_shop = null, Context $context = null) { ... if ($full && $this->id) { ... // add if ($this->id) $this->breadcrumb_path = Product::getBreadcrumbPath((int)$this->id); ... } ... } -------- /classes/Category.php add new public value to class "breadcrumb_path" class CategoryCore extends ObjectModel { ... // add public $breadcrumb_path; ... } -------- /classes/Category.php add new procedure getBreadcrumbPath public static function getBreadcrumbPath($id_category) { $id_lang = (int)Context::getContext()->language->id; $id_shop = (int)Context::getContext()->shop->id; $tmp = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT DISTINCT T6.id_category AS ID0, T5.id_category AS ID1, T4.id_category AS ID2, T3.id_category AS ID3, T2.id_category AS ID4, T1.id_category AS ID5, (select min(M6.NAME) from '._DB_PREFIX_.'category_lang as M6 where (M6.id_shop = '.(int)$id_shop.') AND (M6.id_lang = '.(int)$id_lang.') and (M6.id_category = T6.id_category)) AS nameCAT_0, (select min(M5.NAME) from '._DB_PREFIX_.'category_lang as M5 where (M5.id_shop = '.(int)$id_shop.') AND (M5.id_lang = '.(int)$id_lang.') and (M5.id_category = T5.id_category)) AS nameCAT_1, (select min(M4.NAME) from '._DB_PREFIX_.'category_lang as M4 where (M4.id_shop = '.(int)$id_shop.') AND (M4.id_lang = '.(int)$id_lang.') and (M4.id_category = T4.id_category)) AS nameCAT_2, (select min(M3.NAME) from '._DB_PREFIX_.'category_lang as M3 where (M3.id_shop = '.(int)$id_shop.') AND (M3.id_lang = '.(int)$id_lang.') and (M3.id_category = T3.id_category)) AS nameCAT_3, (select min(M2.NAME) from '._DB_PREFIX_.'category_lang as M2 where (M2.id_shop = '.(int)$id_shop.') AND (M2.id_lang = '.(int)$id_lang.') and (M2.id_category = T2.id_category)) AS nameCAT_4, (select min(M1.NAME) from '._DB_PREFIX_.'category_lang as M1 where (M1.id_shop = '.(int)$id_shop.') AND (M1.id_lang = '.(int)$id_lang.') and (M1.id_category = T1.id_category)) AS nameCAT_5 FROM '._DB_PREFIX_.'category AS T1 left JOIN '._DB_PREFIX_.'category AS T2 ON (T2.id_category = T1.id_parent) left JOIN '._DB_PREFIX_.'category AS T3 ON (T3.id_category = T2.id_parent) left JOIN '._DB_PREFIX_.'category AS T4 ON (T4.id_category = T3.id_parent) left JOIN '._DB_PREFIX_.'category AS T5 ON (T5.id_category = T4.id_parent) left JOIN '._DB_PREFIX_.'category AS T6 ON (T6.id_category = T5.id_parent) WHERE T1.id_category = '.(int)$id_category.' LIMIT 1'); if ($tmp) foreach ($tmp as $aplic) $result = $aplic['nameCAT_0'].'^'.$aplic['ID0'].'^'.$aplic['nameCAT_1'].'^'.$aplic['ID1'].'^'.$aplic['nameCAT_2'].'^'.$aplic['ID2'].'^'.$aplic['nameCAT_3'].'^'.$aplic['ID3'].'^'.$aplic['nameCAT_4'].'^'.$aplic['ID4'].'^'.$aplic['nameCAT_5'].'^'.$aplic['ID5']; return $result; } -------- /classes/Category.php initialization data ... public function __construct($id_category = null, $id_lang = null, $id_shop = null) { ... // add $this->breadcrumb_path = Category::getBreadcrumbPath((int)$id_category); } -------- yourthemes/breadcrumb.tpl change pattern to display data ... change for "