Ha rákeresünk a “Prestashop search issue” vagy “Prestashop front search not working” esetleg a “Prestashop search module doesn’t work” kulcskifejezésekre, bizony tengernyi találatot kapunk.
Mi ennek az oka?
Pontosan elég nehéz megmondani, mivel majdnem minden eset más és más.
Rosszul lenne megírva a keresőmotor? Bizonyos esetekben igen, de ez elég ritka, plusz jön a stabil kiadás ami segít.
Akkor mi a gond?
Amikor elővesszük a Prestashop front oldali keresőrészét akkor egy olyan szekcióval foglalkozunk ami rengeteg kisebb, apróbb, különálló részből épül fel. Ezek bizony egyes helyzetekben meghasalhatnak. Amikor azt tapasztaljuk, hogy a front oldali kereső egyáltalán nem működik, az alábbi pontokat érdemes végignézni, figyelembe venni:
1. Admin felület => Beállítások => Keresés: indexelés:
Ha a számok nem ugyanazok mindkét oldalon, akkor értelemszerűen a hiányzókat tegyük hozzá a keresőmotorhoz, vagy építsük újjá az egészet “Re-build the entire index” segítségével.
2. Kapcsoljuk be a developer módot, és a fennálló hibaüzenet birtokában járjunk el, keressük tovább a hibát.
3. Érdemes az ajax keresést illetőleg az ez alatt lévő egyéb kapcsolókat kikapcsolni a hibakeresés idejére.
4. Utána kell járnunk, volt-e a közelmúltban (vagy mióta a hiba fennáll) php és/vagy mysql verziószám váltás. Ezt a szolgáltatótól tudhatjuk meg, vagy ha esetleg VPS szolgáltatásunk van, akkor a rendszergazdánktól.
5. Ha a verziónk nem stabil kiadás, backup/mentés készítése után frissítsünk fel stabil verzióra.
A probléma akkor szokott elhatalmasodni felettünk, mikor bizonyos körülmények miatt nem tudunk frissíteni. Ennek számos oka lehet, úgy mint a téma – és modulkompatibilitás, egyedi számlázóprogram-összeköttetés vagy egyszerűen csak “szezon” van és nem engedhetjük meg magunknak a frissítéssel járó kiesést.
Ha nincs más megoldás akkor debug-olnunk, vagyis hiba-javítanunk kell. Ha a keresőindex rendben van, és számos olyan kereső-anomália üti fel a fejét melyet nem értünk és látszólag semmi értelem/szabály nincs bennük, akkor kell higgadt fejjel leülni és elgondolkodni a keresési metóduson.
A minap az alábbi rendkívül furcsa dologba botlottam bele: a front oldali kereső néhány terméket megtalált, néhányat pedig nem, annak ellenére, hogy az indexelés az adminban rendben volt. Ami még ennél is furcsább, hogy az admin kereső tökéletesen hozta az eredményeket.
Látszólag semmi értelmes oka nem volt ennek. Adminban kutakodva semmi kiváltóját nem láttam az efféle viselkedésnek, nem értettem miért működik így a motor. A verziószám a híres 1.6.0.14 volt.
Egy alapos backup elvégezte után nekiláttam. A keresendő szó az alábbi volt: “olive”. A hibajelenség alapján az admin hozta a 8 darab “olive” terméket, míg a front rész kettő darabot jelenített csak meg kereséskor.
Megnyitottam a /classes/Search.php
-t, hogy jobban szemügyre vegyem a keresőalgoritmust:
$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 = '.$context->shop->id.'
AND sw.word LIKE
'.($word[0] == '-'
? ' \''.$start_search.pSQL(Tools::substr($word, 1, PS_SEARCH_MAX_WORD_LENGTH)).$end_search.'\''
: ' \''.$start_search.pSQL(Tools::substr($word, 0, PS_SEARCH_MAX_WORD_LENGTH)).$end_search.'\''
);
Itt kicsit kísérletezve, majd átírva az “sw.id_shop” változót direkt “1”-re (angol nyelv), megjavult a kereső. Ezek szerint a keresési hiba nyelvi eredetű. Természetesen ezek után adminban ellenőrizve lett mind a 8 termék neve a különböző nyelvekben, és mindegyikben pontosan elkülönítve ott virított az “olive”. Így tehát az emberi mulasztás ki lett zárva.
PhpMyAdmin-ban, tehát az adatbázisban két táblát kell tüzetesebben szemügyre vennünk: az egyik a “ps_search_index
“, a másik pedig a “ps_search_word
“. Mindkettő szükséges a front oldali kereső megfelelő működéséhez. Adminban indexelés során ezt a két táblát “töltjük fel” adattal, amit aztán a keresőmotor felhasznál kereséskor. Az alábbi lekérdezéssel folytattam:
SELECT si.id_product
FROM ps_search_word sw
LEFT JOIN ps_search_index si ON sw.id_word = si.id_word
WHERE sw.id_lang =1
AND sw.id_shop =1
AND sw.word LIKE 'olive'
ORDER BY `si`.`id_product` ASC
A két tábla összekötésre került, és megkérdeztem, hogy az “olive” keresőszó hol található meg. Az eredmény ez volt:
Ebből a következő volt leszűrhető: összeszámolva 8 darab termék nevében találta meg a keresőszót, ami tökéletes volt admin szerint, ugyanis az eddig is jól mutatta a 8 darab “olive” terméket, ellentétben a front résszel ahol csak kettőt hozott, bármilyen beállítást is alkalmaztam.
Ezek után lekérdeztem, hogy a 8 darab termék az adott kulcsszóra milyen eloszlásban jelenik meg a nyelveket illetően, és itt már megmutatta magát a hiba:
Azt lehet látni, hogy az indexelőmotor bizony nem töltötte fel a magyar nyelvet (ami a hatos ID-t képviseli) az összes termékkel amiben az “olive” megtalálható volt, ellentétben például az angollal melyet az 1-es ID azonosít. Jól látható, hogy angolul 8-szor szerepel az “olive”, míg magyarul csak kettőször. Valamilyen rejtett oknál fogva a maradék hatot nem képes felvenni a magyar indexbe. Sokáig kutattam ennek az okát, rengeteget fórumoztam, de értelemszerű okot nem találtam rá. Egyesek a szerverbeállításokkal magyarázták, mások a táblák rossz karakterkódolási beállításával.
Három topicban találtam hasonló problémát ehhez, EZ az egyik, EZ a másik és ITT található a harmadik. Nem találtam ezekben számomra működő megoldást sajnos.
Végső megoldást a fent már említett /classes/Search.php fájlban találtam meg. Nyissuk meg, majd keressük ki a 400. sor körül íródott “getProductsToIndex
” function-t:
…
protected static function getProductsToIndex($total_languages, $id_product = false, $limit = 50, $weight_array = array())
…
Az ebben lévő function-ben írjuk át az sql lekérdezést erről:
$sql .= ' FROM '._DB_PREFIX_.'product p
LEFT JOIN '._DB_PREFIX_.'product_attribute pa
ON pa.id_product = p.id_product
LEFT JOIN '._DB_PREFIX_.'product_lang pl
ON p.id_product = pl.id_product
'.Shop::addSqlAssociation('product', 'p', true, null, true).'
LEFT JOIN '._DB_PREFIX_.'category_lang cl
ON (cl.id_category = product_shop.id_category_default AND pl.id_lang = cl.id_lang AND cl.id_shop = product_shop.id_shop)
LEFT JOIN '._DB_PREFIX_.'manufacturer m
ON m.id_manufacturer = p.id_manufacturer
LEFT JOIN '._DB_PREFIX_.'lang l
ON l.id_lang = pl.id_lang
WHERE product_shop.indexed = 0
AND product_shop.visibility IN ("both", "search")
'.($id_product ? 'AND p.id_product = '.(int)$id_product : '').'
AND product_shop.`active` = 1
AND pl.`id_shop` = product_shop.`id_shop`
LIMIT '.(int)$limit;
return Db::getInstance()->executeS($sql);
erre:
return Db::getInstance()->executeS('
SELECT p.id_product, pl.id_lang, pl.id_shop, pl.name pname, p.reference, p.ean13, p.upc,
pl.description_short, pl.description, cl.name cname, m.name mname, l.iso_code
FROM '._DB_PREFIX_.'product p
LEFT JOIN '._DB_PREFIX_.'product_lang pl
ON p.id_product = pl.id_product
'.Shop::addSqlAssociation('product', 'p').'
LEFT JOIN '._DB_PREFIX_.'category_lang cl
ON (cl.id_category = product_shop.id_category_default AND pl.id_lang = cl.id_lang AND cl.id_shop = product_shop.id_shop)
LEFT JOIN '._DB_PREFIX_.'manufacturer m
ON m.id_manufacturer = p.id_manufacturer
LEFT JOIN '._DB_PREFIX_.'lang l
ON l.id_lang = pl.id_lang
WHERE product_shop.indexed = 0
AND product_shop.visibility IN ("both", "search")
'.($id_product ? 'AND p.id_product = '.(int)$id_product : '').'
LIMIT '.(int)$limit
);
A módosítás után építsük újra az indexelést és máris fel fogja tölteni a magyar nyelvet is teljes egészében, helyesen.