Jump to content

[solved]Is there a quick search module to search in all my stores ?


iceweird

Recommended Posts

Hi,

i'm on prestashop 1.6.1.2 with multi stores enabled. They are all in the same domain, the main reason is that i have groups of clients that have permissions over showing prices and others don't, but everyone can see the products in all stores.

 

Is it possible to change the module or is there a module to quick search in more than 1 shop in multi stores mode ?

 

Thanks in advance.

 

 

 

edit: [sOLVED]

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

Everything is possible, but it is very complicated.

Do you have the same products in all shops?

If yes, does the products have different prices?

If yes, what would search have to display? Product from every shop with different prices? What happens if one shop is out of stock and others are not?

 

If no. If you have different products in different shops, how cart should work? 

Link to comment
Share on other sites

Hi,

 

3 stores, Electric & Electronic Devices , Energy , Engineering

There's no overlap of products, all the stores have different products.

 

The cart is shared, the clients are shared also.

 

All clients and guests have permissions to see all the products.

Some groups have permissions to see prices on some stores and other clients on another stores.

 

I hope that clarifies a bit more. Thank you for your input.

Link to comment
Share on other sites

  • 2 weeks later...

The solution is probably more complicated than this, but you could try overriding classes/Search.php, copy the entire find function and then remove the following code on lines 206 and 232:

					AND sw.id_shop = '.$context->shop->id.'

and lines 250-254 from:

		'.Shop::addSqlAssociation('product', 'p', false).'
		WHERE c.`active` = 1
		AND product_shop.`active` = 1
		AND product_shop.`visibility` IN ("both", "search")
		AND product_shop.indexed = 1

to:

		WHERE c.`active` = 1

Hopefully, by removing all references to the current shop, all shops will be searched. Anyway, I hope it gives you an idea.

Link to comment
Share on other sites

The solution is probably more complicated than this, but you could try overriding classes/Search.php, copy the entire find function and then remove the following code on lines 206 and 232:

					AND sw.id_shop = '.$context->shop->id.'

and lines 250-254 from:

		'.Shop::addSqlAssociation('product', 'p', false).'
		WHERE c.`active` = 1
		AND product_shop.`active` = 1
		AND product_shop.`visibility` IN ("both", "search")
		AND product_shop.indexed = 1

to:

		WHERE c.`active` = 1

Hopefully, by removing all references to the current shop, all shops will be searched. Anyway, I hope it gives you an idea.

 

Thanks for the tip rocky. Going to see where it takes me and i'll give a feedback soon.

Link to comment
Share on other sites

Hi,

so i managed to get it parcialy working, i'm getting the right products on both the ajax quick search and search results.
Deleting the lines didn't affect the end result :(

Instead of deleting those lines i added 2 querys to get the stores inside the shop group (i have 2 groups).
so i did a bit more digging into the code, and the other bottlenecks were the Shop::addSqlAssociation , Shop::addSqlRestrictionOnLang , that were forcing the shop id .
I printed out those parts of the querys and swaped them to force all the stores in the current shop group.
Here's the code i ended up with.
 

    public static function find($id_lang, $expr, $page_number = 1, $page_size = 1, $order_by = 'position',
		                            $order_way = 'desc', $ajax = false, $use_cookie = true, Context $context = null,$id_category=null)
		{
			if (!$context)
				$context = Context::getContext();
			$db = Db::getInstance(_PS_USE_SQL_SLAVE_);
			if ($page_number < 1) $page_number = 1;
			if ($page_size < 1) $page_size = 1;
			if (!Validate::isOrderBy($order_by) || !Validate::isOrderWay($order_way))
				return false;
			$intersect_array = array();
			$score_array = array();
			$words = explode(' ', Search::sanitize($expr, $id_lang, false, $context->language->iso_code));
// 2 querys to find the id_shop_group and the stores that are in it, and stringify the stores into a variable
			$id_grupo = $db->executeS('SELECT id_shop_group FROM '._DB_PREFIX_.'shop WHERE id_shop='.$context->shop->id);
			$lojas_arr = $db->executeS('SELECT id_shop FROM '._DB_PREFIX_.'shop WHERE id_shop_group='.$id_grupo[0]['id_shop_group']);
			$lojas='';
			foreach($lojas_arr as $loja){
				if($lojas!=''){
					$lojas.=',';
				}
				$lojas.=$loja['id_shop'];
			}
			foreach ($words as $key => $word)
				if (!empty($word) && strlen($word) >= (int)Configuration::get('PS_SEARCH_MINWORDLEN'))
				{
					$word = str_replace('%', '\\%', $word);
					$word = str_replace('_', '\\_', $word);
					$intersect_array[] = 'SELECT si.id_product
					FROM '._DB_PREFIX_.'search_word sw
					LEFT JOIN '._DB_PREFIX_.'search_index si ON sw.id_word = si.id_word
					WHERE sw.id_lang = '.(int)$id_lang.'
						AND sw.id_shop IN('.$lojas.')
						AND sw.word LIKE
					'.($word[0] == '-'
							? ' \''.pSQL(Tools::substr($word, 1, PS_SEARCH_MAX_WORD_LENGTH)).'%\''
							: '\''.pSQL(Tools::substr($word, 0, PS_SEARCH_MAX_WORD_LENGTH)).'%\''
						);
					if ($word[0] != '-')
						$score_array[] = 'sw.word LIKE \''.pSQL(Tools::substr($word, 0, PS_SEARCH_MAX_WORD_LENGTH)).'%\'';
				}
				else
					unset($words[$key]);
			if (!count($words))
				return ($ajax ? array() : array('total' => 0, 'result' => array()));
			$score = '';
			if (count($score_array))
				$score = ',(
				SELECT SUM(weight)
				FROM '._DB_PREFIX_.'search_word sw
				LEFT JOIN '._DB_PREFIX_.'search_index si ON sw.id_word = si.id_word
				WHERE sw.id_lang = '.(int)$id_lang.'
					AND sw.id_shop IN('.$lojas.')
					AND si.id_product = p.id_product
					AND ('.implode(' OR ', $score_array).')
			) position';
			$sql_groups = '';
			if (Group::isFeatureActive())
			{
				$groups = FrontController::getCurrentCustomerGroups();
				$sql_groups = 'AND cg.`id_group` '.(count($groups) ? 'IN ('.implode(',', $groups).')' : '= 1');
			}
			$results = $db->executeS('
				SELECT cp.`id_product`, pl.name
				FROM `'._DB_PREFIX_.'category_product` cp
				'.(Group::isFeatureActive() ? 'INNER JOIN `'._DB_PREFIX_.'category_group` cg ON cp.`id_category` = cg.`id_category`' : '').'
				INNER JOIN `'._DB_PREFIX_.'category` c ON cp.`id_category` = c.`id_category`
				INNER JOIN `'._DB_PREFIX_.'product` p ON cp.`id_product` = p.`id_product`
				INNER JOIN `'._DB_PREFIX_.'product_lang` pl ON cp.`id_product` = pl.`id_product`
				LEFT JOIN ps_product_shop product_shop ON (product_shop.id_product = p.id_product AND product_shop.id_shop IN('.$lojas.')) 
				WHERE c.`active` = 1
				'.($id_category !=  null? 'AND c.`id_category` = '.$id_category.'':'').'
				AND product_shop.`active` = 1
				AND product_shop.`visibility` IN ("both", "search")
				AND product_shop.indexed = 1
				'.$sql_groups.' 
				GROUP BY cp.id_product');
			$eligible_products = array();
			foreach ($results as $row)
				$eligible_products[] = $row['id_product'];
			foreach ($intersect_array as $query)
			{
				$eligible_products2 = array();
				foreach ($db->executeS($query) as $row)
					$eligible_products2[] = $row['id_product'];
				$eligible_products = array_intersect($eligible_products, $eligible_products2);
				if (!count($eligible_products))
					return ($ajax ? array() : array('total' => 0, 'result' => array()));
			}
			$eligible_products = array_unique($eligible_products);
			$product_pool = '';
			foreach ($eligible_products as $id_product)
				if ($id_product)
					$product_pool .= (int)$id_product.',';
			if (empty($product_pool))
				return ($ajax ? array() : array('total' => 0, 'result' => array()));
			$product_pool = ((strpos($product_pool, ',') === false) ? (' = '.(int)$product_pool.' ') : (' IN ('.rtrim($product_pool, ',').') '));
			if ($ajax)
			{
				$sql = 'SELECT DISTINCT p.id_product, pl.name pname, cl.name cname,
						cl.link_rewrite crewrite, pl.link_rewrite prewrite '.$score.'
					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.'
					)
					LEFT JOIN ps_product_shop product_shop ON (product_shop.id_product = p.id_product AND product_shop.id_shop IN('.$lojas.')) 
					INNER JOIN `'._DB_PREFIX_.'category_lang` cl ON (
						product_shop.`id_category_default` = cl.`id_category`
						AND cl.`id_lang` = '.(int)$id_lang.'
					)
					WHERE p.`id_product` '.$product_pool.'
					ORDER BY position DESC LIMIT 10';
				return $db->executeS($sql);
			}
			if (strpos($order_by, '.') > 0)
			{
				$order_by = explode('.', $order_by);
				$order_by = pSQL($order_by[0]).'.`'.pSQL($order_by[1]).'`';
			}
			$alias = '';
			if ($order_by == 'price')
				$alias = 'product_shop.';
			else if ($order_by == 'date_upd')
				$alias = 'p.';
			$sql = 'SELECT p.*, product_shop.*, stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity,
				pl.`description_short`, pl.`available_now`, pl.`available_later`, pl.`link_rewrite`, pl.`name`,
			 MAX(image_shop.`id_image`) id_image, il.`legend`, m.`name` manufacturer_name '.$score.', MAX(product_attribute_shop.`id_product_attribute`) id_product_attribute,
				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
				LEFT JOIN ps_product_shop product_shop ON (product_shop.id_product = p.id_product AND product_shop.id_shop IN('.$lojas.')) 
				INNER JOIN `'._DB_PREFIX_.'product_lang` pl ON (
					p.`id_product` = pl.`id_product`
					AND pl.`id_lang` = '.(int)$id_lang.'
				)
				LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa	ON (p.`id_product` = pa.`id_product`)
				LEFT JOIN ps_product_attribute_shop product_attribute_shop 
				ON (product_attribute_shop.id_product_attribute = pa.id_product_attribute AND product_attribute_shop.id_shop IN('.$lojas.'))
				'.Product::sqlStock('p', 'product_attribute_shop', false, $context->shop).'
				LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer`
				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.')
				WHERE p.`id_product` '.$product_pool.'
				GROUP BY product_shop.id_product
				'.($order_by ? 'ORDER BY  '.$alias.$order_by : '').($order_way ? ' '.$order_way : '').'
				LIMIT '.(int)(($page_number - 1) * $page_size).','.(int)$page_size;
			$result = $db->executeS($sql);
// Add DISTINCT(p.id_product) so we don't get duplicates
			$sql = 'SELECT COUNT(DISTINCT(p.id_product))
				FROM '._DB_PREFIX_.'product p
				LEFT JOIN ps_product_shop product_shop ON (product_shop.id_product = p.id_product AND product_shop.id_shop IN('.$lojas.')) 
				INNER JOIN `'._DB_PREFIX_.'product_lang` pl ON (
					p.`id_product` = pl.`id_product`
					AND pl.`id_lang` = '.(int)$id_lang.'
				)
				LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON m.`id_manufacturer` = p.`id_manufacturer`
				WHERE p.`id_product` '.$product_pool;
			$total = $db->getValue($sql);
			if (!$result)
				$result_properties = false;
			else
				$result_properties = Product::getProductsProperties((int)$id_lang, $result);
			return array('total' => $total,'result' => $result_properties);
		}

Now i'm faced with another problem, when you click the product it doesn't redirects to the right store, and displays a 404 error page instead.

Any ideas ? :)

Link to comment
Share on other sites

My guess is that PrestaShop is checking whether the product is in the current store and is generating a 404 error if it isn't. If that is the case, you could either disable that check or change the domain of the product URLs to the shop they belong to.

Link to comment
Share on other sites

My guess is that PrestaShop is checking whether the product is in the current store and is generating a 404 error if it isn't. If that is the case, you could either disable that check or change the domain of the product URLs to the shop they belong to.

 

Hi rocky, do you know where's the product url , so i can see if i can change it ?

Link to comment
Share on other sites

I've traced the code in PrestaShop v1.6.1.5 and I think it is the following on line 4279 of classes/Product.php that generates the link:

        $row['link'] = $context->link->getProductLink((int)$row['id_product'], $row['link_rewrite'], $row['category'], $row['ean13']);

I think if you override the getProductProperties function and change the line to the following, it may help:

        $row['link'] = $context->link->getProductLink((int)$row['id_product'], $row['link_rewrite'], $row['category'], $row['ean13'], null, $row['id_shop_default']);

I haven't tested this code, but I hope passing the product's default shop ID into the function that generates the product link will cause the domain of that shop to be used instead of the current shop. Good luck. :)

Link to comment
Share on other sites

Yup, you're right. I managed to figure it out and was precisely doing that, and it works, the link changes to the correct store.

But as soon as it redirects, it shows up a blank page... i'll have to debug that now :(

i'll give some feedback soon.

 

Thank you rocky for the tips.

Link to comment
Share on other sites

  • 2 weeks later...

Problem solved!

 

I've created an override for the getProductLink function in the Link class.

		public function getProductLink($product, $alias = null, $category = null, $ean13 = null, $id_lang = null, $id_shop = null, $ipa = 0, $force_routes = false, $relative_protocol = false, $add_anchor = false)
		{
			$dispatcher = Dispatcher::getInstance();
	
			if (!$id_lang) {
				$id_lang = Context::getContext()->language->id;
			}

			if (is_object($product)){
				$id_produto=$product->id;
			}else{
				$id_produto=$product;
			}
			$db = Db::getInstance(_PS_USE_SQL_SLAVE_);
			$prod = $db->executeS('SELECT id_shop_default FROM '._DB_PREFIX_.'product WHERE id_product='.$id_produto);
			$id_shop = $prod[0]['id_shop_default'];
			
			$url = $this->getBaseLink($id_shop, null, $relative_protocol).$this->getLangLink($id_lang, null, $id_shop);
	
			if (!is_object($product)) {
				if (is_array($product) && isset($product['id_product'])){
					$product = new Product($product['id_product'], false, $id_lang, $id_shop);
				} elseif ((int)$product) {
					$product = new Product((int)$product, false, $id_lang, $id_shop);
				} else {
					throw new PrestaShopException('Invalid product vars');
				}
			}
	
			// Set available keywords
			$params = array();
			$params['id'] = $product->id;
			$params['rewrite'] = (!$alias) ? $product->getFieldByLang('link_rewrite') : $alias;
	
			$params['ean13'] = (!$ean13) ? $product->ean13 : $ean13;
			$params['meta_keywords'] =    Tools::str2url($product->getFieldByLang('meta_keywords'));
			$params['meta_title'] = Tools::str2url($product->getFieldByLang('meta_title'));
	
			if ($dispatcher->hasKeyword('product_rule', $id_lang, 'manufacturer', $id_shop)) {
				$params['manufacturer'] = Tools::str2url($product->isFullyLoaded ? $product->manufacturer_name : Manufacturer::getNameById($product->id_manufacturer));
			}
	
			if ($dispatcher->hasKeyword('product_rule', $id_lang, 'supplier', $id_shop)) {
				$params['supplier'] = Tools::str2url($product->isFullyLoaded ? $product->supplier_name : Supplier::getNameById($product->id_supplier));
			}
	
			if ($dispatcher->hasKeyword('product_rule', $id_lang, 'price', $id_shop)) {
				$params['price'] = $product->isFullyLoaded ? $product->price : Product::getPriceStatic($product->id, false, null, 6, null, false, true, 1, false, null, null, null, $product->specificPrice);
			}
	
			if ($dispatcher->hasKeyword('product_rule', $id_lang, 'tags', $id_shop)) {
				$params['tags'] = Tools::str2url($product->getTags($id_lang));
			}
	
			if ($dispatcher->hasKeyword('product_rule', $id_lang, 'category', $id_shop)) {
				$params['category'] = (!is_null($product->category) && !empty($product->category)) ? Tools::str2url($product->category) : Tools::str2url($category);
			}
	
			if ($dispatcher->hasKeyword('product_rule', $id_lang, 'reference', $id_shop)) {
				$params['reference'] = Tools::str2url($product->reference);
			}
	
			if ($dispatcher->hasKeyword('product_rule', $id_lang, 'categories', $id_shop)) {
				$params['category'] = (!$category) ? $product->category : $category;
				$cats = array();
				foreach ($product->getParentCategories($id_lang) as $cat) {
					if (!in_array($cat['id_category'], Link::$category_disable_rewrite)) {
						//remove root and home category from the URL
						$cats[] = $cat['link_rewrite'];
					}
				}
				$params['categories'] = implode('/', $cats);
			}
			$anchor = $ipa ? $product->getAnchor((int)$ipa, (bool)$add_anchor) : '';
	
			return $url.$dispatcher->createUrl('product_rule', $id_lang, $params, $force_routes, $anchor, $id_shop);
		}

Quick search , regular search and Layered navigation works well with this changes.

 

I'll change this thread to solved, thank you .

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