PageSourceSearch

https://hotel-riga.com/wp-content/plugins/hotelbox-connect/public/js/hb-booking-bridge.js?ver=2.9.1

js hotel-riga.com collected 2026-10-08 10:32:49 UTC 8,187 bytes, 158 lines download raw bytes

1/**
2 * HotelBox Booking Bridge — URL enrichment for booking engine links.
3 *
4 * Attribution (utm params, gclid, fbclid) is captured on landing and persisted in a
5 * first-party cookie (first-touch wins). When the visitor later clicks a link to
6 * the booking engine, the params are forwarded from the cookie — not only from the
7 * current URL — so campaign data survives internal navigation between landing and
8 * the "Book" click, and crosses over to the booking-engine domain via the URL.
9 */
10(function() {
11    'use strict';
12
13    var config = window.hbBridge || {};
14
15    // Настроеният домейн на резервационната система, ако администраторът го е попълнил.
16    // Празно = не е попълнен; НЕ пада на 'booking.hotelbox.bg' както преди.
17    //
18    // Защо: старата резервна стойност не съвпадаше с нито един реален хотелски домейн, а
19    // проверката по-долу излиза при несъвпадение — тоест на всеки сайт без ръчно попълнена
20    // настройка мостът мълчаливо не правеше нищо. Измерено на прода: utm достигаше до 13 от
21    // 2743 beacon-а, а hb_sid до нито един. Затова при липсваща настройка сега разпознаваме
22    // резервационния поддомейн на самия сайт.
23    var beDomain = (config.beDomain || '').trim();
24
25    // Домейнът на текущия сайт без водещото www — основата, спрямо която се познава
26    // резервационният поддомейн.
27    var siteHost = window.location.hostname.replace(/^www\./, '').toLowerCase();
28
29    /**
30     * Домейните на резервационните системи, които обслужват хотелите.
31     *
32     * Мерено на прода на 26.08.2026: от 18-те достъпни сайта с booking engine
33     * ВСИЧКИТЕ 18 водят към booking.quendoo.com, а нито един — към book.<домейн>.
34     * Дотук мостът търсеше точно обратното и затова не обогатяваше нищо: за
35     * седмица до резервационната система стигнаха 6 utm етикета от 223 резервации,
36     * а fbclid — нула, при 38 000 сесии с utm от Meta на самите сайтове.
37     *
38     * Чуждият домейн значи и че бисквитката не помага: тя живее на домейна на
39     * хотела и booking.quendoo.com не я вижда. Адресът на връзката е единственият
40     * начин етикетът да премине.
41     */
42    var BE_PROVIDERS = ['quendoo.com', 'bookonlinenow.com', 'booking.hotelbox.bg'];
43
44    function isProviderHost(host) {
45        for (var i = 0; i < BE_PROVIDERS.length; i++) {
46            var p = BE_PROVIDERS[i];
47            if (host === p || host.slice(-(p.length + 1)) === '.' + p) return true;
48        }
49        return false;
50    }
51
52    /**
53     * Води ли връзката към резервационната система.
54     *
55     * Трите правила са РАВНОСТОЙНИ, не подредени с излизане при първото: доскоро
56     * попълнената настройка прекратяваше проверката и сайт с въведен
57     * „book.<домейн>“ отхвърляше истинската си връзка към Quendoo. Точно това
58     * обезсили моста навсякъде, където домейнът беше попълнен.
59     *
60     * Правилото за поддомейн сравнява ЦЯЛАТА първа етикетна част, не подниз:
61     * `facebook.com` съдържа „book.“ и при сравнение по подниз би минал за
62     * резервационна връзка.
63     */
64    function isBookingHost(hostname) {
65        var host = (hostname || '').toLowerCase().replace(/^www\./, '');
66
67        if (isProviderHost(host)) return true;
68
69        if (beDomain && host.indexOf(beDomain.toLowerCase().replace(/^www\./, '')) !== -1) return true;
70
71        var dot = host.indexOf('.');
72        if (dot === -1) return false;
73
74        var label = host.slice(0, dot);
75        var rest  = host.slice(dot + 1);
76
77        return (label === 'book' || label === 'booking') && rest === siteHost;
78    }
79
80    // utm_* + click IDs (gclid = Google Ads, fbclid = Meta).
81    var ATTR_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'gclid', 'fbclid'];
82    var COOKIE = 'hb_attr';
83    var MAX_AGE = 2592000; // 30 дни
84
85    function readStore() {
86        try {
87            var m = document.cookie.match(/(^| )hb_attr=([^;]+)/);
88            if (m) return JSON.parse(decodeURIComponent(m[2])) || {};
89        } catch(e) {}
90        return {};
91    }
92
93    // Host-only cookie (както hb_sid) — оцелява вътрешната навигация на сайта.
94    function writeStore(obj) {
95        try {
96            document.cookie = COOKIE + '=' + encodeURIComponent(JSON.stringify(obj)) +
97                ';path=/;max-age=' + MAX_AGE + ';SameSite=Lax';
98        } catch(e) {}
99    }
100
101    // First-touch: запиши attribution при кацане, без да презаписваш вече уловена стойност.
102    function captureAttribution() {
103        var params = new URLSearchParams(window.location.search);
104        var store = readStore();
105        var changed = false;
106
107        ATTR_KEYS.forEach(function(key) {
108            var value = params.get(key);
109            if (value && !store[key]) {
110                store[key] = value;
111                changed = true;
112            }
113        });
114
115        if (changed) writeStore(store);
116        return store;
117    }
118
119    var attribution = captureAttribution();
120
121    document.addEventListener('click', function(e) {
122        var link = e.target.closest('a[href]');
123        if (!link) return;
124
125        var href = link.getAttribute('href') || '';
126
127        // Check if link points to booking engine.
128        try {
129            var url = new URL(href, window.location.origin);
130            if (!isBookingHost(url.hostname)) return;
131            // Връзка към самия сайт не се обогатява — иначе вътрешната навигация на сайт,
132            // който сам живее на book.<домейн>, би трупала проследяващи параметри.
133            if (url.hostname.toLowerCase() === window.location.hostname.toLowerCase()) return;
134
135            // Enrich URL with tracking parameters.
136            url.searchParams.set('hb_sid', window.hb_sid || '');
137            url.searchParams.set('hb_cid', window.hb_cid || '');
138            url.searchParams.set('hb_vid', window.hb_vid || '');
139            url.searchParams.set('hb_ref', window.location.pathname);
140            url.searchParams.set('hb_hotel', config.hotelId || '');
141
142            // Forward attribution от cookie-то (first-touch), с fallback към текущия URL.
143            // Покрива случая, в който потребителят каца с ?utm на една страница и цъка
144            // „Резервирай" няколко страници по-късно (UTM вече го няма в URL-а).
145            var current = new URLSearchParams(window.location.search);
146            ATTR_KEYS.forEach(function(key) {
147                var value = attribution[key] || current.get(key) || '';
148                if (value) {
149                    url.searchParams.set(key, value);
150                }
151            });
152
153            link.setAttribute('href', url.toString());
154        } catch(ex) {
155            // Invalid URL, ignore.
156        }
157    }, true);
158})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.