Kapcsolódó Termékek
Egyirányú Kapcsolat Fix

OpenCart alapból kétirányúan menti a kapcsolódó termékeket: ha A-hoz hozzárendeled B-t, B is automatikusan megkapja A-t kapcsolódóként. Ez a javítás megszünteti ezt a viselkedést.

OpenCart 3.0.x Journal 3.x Admin PHP módosítás

🔍 A probléma

Ha az admin felületen egy terméknél kapcsolódó terméket adsz hozzá, az OpenCart automatikusan visszafelé is bejegyzi a kapcsolatot – mindkét irányban. Ez sok esetben nem kívánatos.

📦

Kívánatos viselkedés

A-nál megjelenik B mint kapcsolódó termék. B-nél nem jelenik meg A.

🔄

Jelenlegi (OC alap) viselkedés

A-nál B kapcsolódó → automatikusan B-nél is A kapcsolódó lesz. Mindkét irányban.

🗄️

Adatbázisban

Két sor keletkezik a product_related táblában termékpáronként a mentés során.

⚙️ Miért történik – a kód logikája

A kapcsolódó termékek mentése az admin/model/catalog/product.php fájlban, az editProduct() és addProduct() metódusokban történik. Az OpenCart két SQL műveletet végez minden egyes kapcsolódó termékhez: egyet az eredeti irányba, egyet visszafelé.

Az érintett kódrészlet (eredeti)

admin/model/catalog/product.php editProduct() – kapcsolódó termékek blokk
// Előbb törli a meglévő kapcsolatokat – MINDKÉT irányból:
$this->db->query("DELETE FROM " . DB_PREFIX . "product_related
	WHERE product_id = '" . (int)$product_id . "'");

$this->db->query("DELETE FROM " . DB_PREFIX . "product_related
	WHERE related_id = '" . (int)$product_id . "'");

foreach ($data['product_related'] as $related_id) {

	// Előre irány – ez kell:
	$this->db->query("INSERT INTO " . DB_PREFIX . "product_related
		SET product_id = '" . (int)$product_id . "',
			related_id = '" . (int)$related_id . "'");

	// Visszafelé irány – ezt kell törölni:
	$this->db->query("INSERT INTO " . DB_PREFIX . "product_related
		SET product_id = '" . (int)$related_id . "',
			related_id = '" . (int)$product_id . "'");
}
ℹ️
A piros sorok felelnek a kétirányú viselkedésért. Az egyirányi fix pontosan ezeket a sorokat távolítja el – semmi mást nem érint.

🔧 A megoldás

Az admin/model/catalog/product.php fájlban két metódus érintett. Az alábbiakban a helyes, végleges kód látható mindkét helyen.

⚠️
Mentsd el az eredeti fájlt (product.php.bak) mielőtt felülírod.

addProduct() – helyes product_related blokk

admin/model/catalog/product.php → addProduct() ✅ végleges kód
if (isset($data['product_related'])) {
	foreach ($data['product_related'] as $related_id) {
		$this->db->query("DELETE FROM " . DB_PREFIX . "product_related WHERE product_id = '" . (int)$product_id . "' AND related_id = '" . (int)$related_id . "'");
		$this->db->query("INSERT INTO " . DB_PREFIX . "product_related SET product_id = '" . (int)$product_id . "', related_id = '" . (int)$related_id . "'");
	}
}

editProduct() – helyes product_related blokk

admin/model/catalog/product.php → editProduct() ✅ végleges kód
$this->db->query("DELETE FROM " . DB_PREFIX . "product_related WHERE product_id = '" . (int)$product_id . "'");

if (isset($data['product_related'])) {
	foreach ($data['product_related'] as $related_id) {
		$this->db->query("DELETE FROM " . DB_PREFIX . "product_related WHERE product_id = '" . (int)$product_id . "' AND related_id = '" . (int)$related_id . "'");
		$this->db->query("INSERT INTO " . DB_PREFIX . "product_related SET product_id = '" . (int)$product_id . "', related_id = '" . (int)$related_id . "'");
	}
}

🗄️ Adatbázis cleanup – meglévő duplikációk

A kódfájl módosítása csak az ezután mentett termékekre hat. A korábban felvitt kétirányú bejegyzések az adatbázisban maradnak. Ezeket kézzel kell kitakarítani.

A visszafelé irányú sorok azonosítása

Azok a sorok "feleslegesek", amelyeknél az ellentétes párjuk is megvan (product_id és related_id felcserélve):

SQL – duplikált (visszafelé irányú) párok listázása
SELECT a.product_id, a.related_id
FROM   oc_product_related a
JOIN   oc_product_related b
		 ON  b.product_id = a.related_id
		 AND b.related_id = a.product_id
WHERE  a.product_id > a.related_id;
-- A WHERE feltétel biztosítja, hogy minden pár csak egyszer szerepeljen
⚠️
Mielőtt törölsz: futtasd le csak a SELECT-et, és ellenőrizd az eredményt. Győződj meg róla, hogy valóban csak a visszafelé irányú duplikátumokat tartalmazza.

A felesleges sorok törlése

SQL – visszafelé irányú duplikátumok törlése törlés – előbb tesztelj
DELETE a
FROM   oc_product_related a
JOIN   oc_product_related b
		 ON  b.product_id = a.related_id
		 AND b.related_id = a.product_id
WHERE  a.product_id > a.related_id;

Alternatíva: újramentés

Ha kevés az érintett termék, a legegyszerűbb megoldás: a kódfájl módosítása után az admin felületen nyisd meg és mentsd újra az érintett termékeket. A mentéskor a régi kapcsolatok törlődnek, és az újak már csak egyirányban kerülnek be.

Az újramentéses megoldás biztonságosabb – nem igényel közvetlen adatbázis-műveletet, és az OC saját logikáján megy keresztül.

Ellenőrzés

A javítás után ellenőrizd, hogy minden rendben működik:

1

Admin: kapcsolódó termék hozzáadása

Nyisd meg az A terméket, adj hozzá B-t kapcsolódóként, mentsd el.

2

Admin: B termék ellenőrzése

Nyisd meg a B terméket – az A nem kell, hogy megjelenjen ott kapcsolódóként.

3

Adatbázis ellenőrzés (opcionális)

Ellenőrizd, hogy csak egy sor keletkezett-e a mentés után:

SQL – ellenőrző lekérdezés (cseréld ki az ID-kat)
SELECT * FROM oc_product_related
WHERE product_id IN (A_ID, B_ID)
   OR related_id IN (A_ID, B_ID);

Ha a fix működött, az eredménynek egy sort kell mutatnia: product_id = A, related_id = B.

📋 Tudnivalók

Szempont Részlet
Érintett fájl admin/model/catalog/product.php
Érintett metódusok editProduct() és addProduct()
Adatbázis tábla oc_product_related
Frontend hatás Nincs – csak az admin mentési logika változik
Journal 3 konfliktus Nincs – a Journal theme nem módosítja ezt a modell fájlt
OC frissítésnél A product.php felülíródhat – frissítés után újra el kell végezni a módosítást
Visszaállítás A .bak fájl visszamásolásával azonnal visszaállítható az eredeti viselkedés
OC core fájl módosítása! Ez nem OCMod – közvetlenül egy core fájlt érint. Minden OC frissítés után ellenőrizd, hogy a változtatás megmaradt-e. Ajánlott a módosítást egy szöveges fájlban rögzíteni, hogy frissítés után gyorsan vissza lehessen alkalmazni.