Exit Popup Rendszer
Eszköztípus, munkaidő és kosár állapot alapján intelligensen triggerelt oldalelhagyó popup – OpenCart és Journal3 témához.
Áttekintés
Az exit popup rendszer célja, hogy az oldalról távozni készülő látogatókat visszatartsa, és vásárlásra, illetve kapcsolatfelvételre ösztönözze őket. A szkript a Journal3 téma beépített popup modulját hívja meg, saját maga nem tartalmaz popup megjelenítési logikát.
| Popup | ID | Mikor jelenik meg |
|---|---|---|
| Telefonos popup | 359 |
Munkaidőben – mobilon inaktivitás után, desktopon exit intentnél |
| Kosáras popup | 371 |
Munkaidőn túl, desktopon, tele kosár esetén exit intentnél |
Hogyan működik
A szkript a DOMContentLoaded eseményre fut le. Megvizsgálja az eszköz szélességét, és az alapján regisztrál eseményfigyelőt – inaktivitás alapút mobilon, exit intent alapút desktopon.
Munkaidő meghatározás
Az isBusinessHours() függvény a látogató böngészőjének helyi idejét vizsgálja. Munkaidőnek a hétfőtől péntekig tartó, 08:00–15:59 közötti időszak számít.
Kosár állapot olvasása
A hasItemsInCart() függvény a #cart-items ID-jú DOM elem szövegtartalmát olvassa. Ha az egész szám értéke nagyobb nullánál, a kosár teli. Ha az elem nem található, a függvény false-t ad vissza.
Ismétlés-védelem
A popupShown boolean jelző biztosítja, hogy egy oldalletöltésen belül csak egyszer jelenjen meg popup, még akkor is, ha a trigger feltétel többször is teljesülne.
Döntési logika
│
├── Mobil / Tablet (szélesség < 1024px)
│ └── 10 mp inaktivitás után
│ └── Telefonos popup (359) — munkaidőtől függetlenül
│
└── Desktop (szélesség ≥ 1024px)
└── Egér elhagyja a viewport tetejét (exit intent)
├── Munkaidőben → Telefonos popup (359)
├── Munkaidőn túl + tele kosár → Kosáras popup (371)
└── Munkaidőn túl + üres kosár → Semmi
| Eszköz | Munkaidő | Kosár | Trigger | Popup |
|---|---|---|---|---|
| Mobil/Tablet | bármikor | bármilyen | 10s inaktivitás | Telefonos 359 |
| Desktop | igen | bármilyen | exit intent | Telefonos 359 |
| Desktop | nem | tele | exit intent | Kosáras 371 |
| Desktop | nem | üres | — | Semmi |
Telepítés
-
Fájl feltöltése FTP-n
Töltsd fel azexit-popup.jsfájlt a következő helyre:
PATH/public_html/[domain]/catalog/view/theme/journal3/js/exit-popup.js -
Szkript beillesztése a témába
A Journal3 admin felületén navigálj a Theme Settings → Custom JS szekcióba, és add hozzá:HTML<script src="/catalog/view/theme/journal3/js/exit-popup.js"></script>A szkriptnek a Journal3 Popup modul JS kódja után kell betöltődnie, különben azopen_popup()függvény nem lesz elérhető. -
Popup ID-k ellenőrzése
Journal3 adminban ellenőrizd, hogy a két popup a szkriptben megadott ID-kon él. Ha eltérnek, módosítsd azexit-popup.jstetején lévő konstansokat (lásd Beállítás). -
Tesztelés
Teszteld DevToolsban Desktop nézetben munkaidőn kívül egy teli kosárral, majd mobil nézetben 10 másodperc inaktivitás után.
Beállítás
Popup ID-k módosítása
Az exit-popup.js első két sorában állíthatók be:
const phonePopupId = 359; // telefonos popup
const cartPopupId = 371; // kosáras popup
Munkaidő módosítása
function isBusinessHours() {
const now = new Date();
const day = now.getDay(); // 0 = vasárnap, 6 = szombat
const hour = now.getHours();
const isWeekday = day >= 1 && day <= 5; // H–P
const isWorkingHour = hour >= 8 && hour < 16; // 08:00–15:59
return isWeekday && isWorkingHour;
}
Példa – reggel 7-től este 18-ig, hétvégén is:
const isWeekday = day >= 0 && day <= 6;
const isWorkingHour = hour >= 7 && hour < 18;
Inaktivitási időkorlát (mobil)
inactivityTimer = setTimeout(function () {
showPopup(phonePopupId);
}, 10000); // ← ms, pl. 15000 = 15 másodperc
Desktop/mobil törési pont
Az 1024px-es határérték két helyen szerepel a kódban:
if (window.innerWidth < 1024) { /* mobil */ }
if (window.innerWidth >= 1024) { /* desktop */ }
Popup tartalmak
A popup HTML tartalmát a Journal3 admin felületén kell beállítani az adott ID-jú popuphoz.
Telefonos popup (ID: 359)
Custom URL: javascript:open_popup(359);
<div style="text-align: center; padding: 20px;">
<h2 style="margin-bottom: 15px;">Nem találtad meg, amit kerestél?</h2>
<p style="font-size: 16px; margin-bottom: 20px;">
Ne menj tovább – hívj fel most, segítünk!
</p>
<a href="tel:+36302626381"
style="display: inline-block; background-color: #007bff; color: #fff;
text-decoration: none; padding: 12px 24px; font-size: 16px;
border-radius: 6px;">
📞 Hívás most: +36 30 262 6381
</a>
</div>
Kosáras popup (ID: 371)
Custom URL: javascript:open_popup(371);
<div style="text-align: center; padding: 20px;">
<h2 style="margin-bottom: 15px;">⏰ Termékek várnak a kosaradban!</h2>
<p style="font-size: 16px; margin-bottom: 20px;">
Ne hagyd félbe – fejezd be a rendelést most!
</p>
<a href="/index.php?route=checkout/cart"
style="display: inline-block; background-color: #28a745; color: #fff;
text-decoration: none; padding: 12px 24px; font-size: 18px;
border-radius: 6px; font-weight: bold;">
🛒 Vissza a kosárhoz
</a>
</div>
Követelmények
| Követelmény | Részlet |
|---|---|
| Platform | OpenCart (bármely verzió) |
| Téma | Journal3 |
| Journal3 Popup modul | Aktív és konfigurált – ez biztosítja az open_popup() globális függvényt |
| Kosár elem | #cart-items ID-jú DOM elem, melynek szövegtartalma a kosárban lévő termékek száma (egész szám) |
| Böngésző | Minden modern böngésző (Chrome, Firefox, Safari, Edge) |
| Szerver | Nem szükséges szerverfeltétel – tisztán kliens-oldali szkript |
Ismert hibák és megoldásaik
🖥️ Desktopon nem jelenik meg a popup
Ellenőrizd ebben a sorrendben:
- Munkaidőn kívül + üres kosár? → Ez tervezett viselkedés, nem hiba.
open_popupelérhető-e? → DevTools konzolban:typeof open_popup– ha"undefined", a Journal3 Popup modul nincs aktív, vagy a szkript betöltési sorrendje helytelen.- Helyes popup ID? → Ellenőrizd a Journal3 adminban az aktuális ID-kat.
#cart-itemselem? → Konzolban:document.querySelector('#cart-items')
📱 Mobilon nem jelenik meg a popup
- Ellenőrizd, hogy a
window.innerWidthvalóban kisebb-e 1024px-nél (DevTools → Device Toolbar). - Ellenőrizd, hogy az
open_popup()függvény elérhető-e mobilon. - A 10 másodperc letelte előtt interaktáltál-e az oldallal? Bármely érintés, görgetés vagy kattintás visszaállítja a timert.
🔁 Popup többször jelenik meg ugyanazon az oldalon
A popupShown jelző csak az aktuális oldalletöltésre vonatkozik. SPA-szerű navigáció esetén (pushState) az oldal újratöltés nélkül változhat, és a jelző resetelődhet.
Megoldás: sessionStorage használata:
function showPopup(popupId) {
if (!sessionStorage.getItem('popupShown') &&
typeof open_popup === 'function') {
open_popup(popupId);
sessionStorage.setItem('popupShown', '1');
}
}
🛒 Munkaidőn túl üres kosárnál is megjelenik a popup
Valószínűleg a #cart-items DOM elem hiányzik, így a hasItemsInCart() false-t ad vissza – de ha valahol a logika megkerüli ezt, ellenőrizd az elem jelenlétét és szövegtartalmát.
DevTools konzolban:
document.querySelector('#cart-items')?.textContent
⏰ Helytelen munkaidő-meghatározás
A szkript a látogató böngészőjének helyi idejét használja – nem a szerver idejét. Ha a célközönség más időzónában van, ez eltérést okozhat.
Szerver-oldali időzóna-alapú megoldáshoz a munkaidő meghatározását az OpenCart kontroller szinten kell elvégezni, és a kapott értéket JS változóként kell átadni az oldalnak.
Forráskód
Fájl helye a szerveren:
/public_html/[domain]/catalog/view/theme/journal3/js/exit-popup.js
document.addEventListener('DOMContentLoaded', function () {
const phonePopupId = 359; // telefonos popup
const cartPopupId = 371; // kosáras popup
let popupShown = false;
function isBusinessHours() {
const now = new Date();
const day = now.getDay(); // 0 = vasárnap, 6 = szombat
const hour = now.getHours();
const isWeekday = day >= 1 && day <= 5;
const isWorkingHour = hour >= 8 && hour < 16;
return isWeekday && isWorkingHour;
}
function hasItemsInCart() {
const cartItems = document.querySelector('#cart-items');
if (cartItems) {
const count = parseInt(cartItems.textContent.trim());
return count > 0;
}
return false;
}
function showPopup(popupId) {
if (!popupShown && typeof open_popup === 'function') {
open_popup(popupId);
popupShown = true;
}
}
// Mobil/Tablet: inaktivitás után 10s-cel
if (window.innerWidth < 1024) {
let inactivityTimer;
function resetTimer() {
clearTimeout(inactivityTimer);
inactivityTimer = setTimeout(function () {
showPopup(phonePopupId);
}, 10000);
}
['touchstart', 'touchend', 'scroll', 'click'].forEach(function (e) {
document.addEventListener(e, resetTimer, { passive: true });
});
resetTimer();
}
// Desktop: kilépési szándék
if (window.innerWidth >= 1024) {
document.documentElement.addEventListener('mouseleave', function (e) {
if (e.clientY <= 0) {
if (isBusinessHours()) {
showPopup(phonePopupId);
} else if (hasItemsInCart()) {
showPopup(cartPopupId);
}
}
});
}
});