PageSourceSearch

https://www.freee.co.jp/script/utm/utm-parameter.js?update=20260522

js freee.co.jp collected 2026-09-24 08:39:00 UTC 8,954 bytes, 241 lines download raw bytes

1const mrktInputValueUpdate = (paramObject) => {
2  const utmFiltered = Object.fromEntries(
3    Object.entries(paramObject).filter(([key]) => key.toLowerCase().startsWith('utm_') || key.toLowerCase() === 'gclid')
4  );
5
6  // MktoForms2の読み込みを待つポーリング処理関数
7  const pollMktoForms2 = (callback, interval = 200, maxAttempts = 50) => {
8    let attempts = 0;
9    const timer = setInterval(() => {
10      // ライブラリ本体が存在するかチェック
11      if (window.MktoForms2) {
12        clearInterval(timer);
13        callback();
14      } else if (++attempts >= maxAttempts) {
15        clearInterval(timer);
16        console.warn('MktoForms2 is undifined');
17      }
18    }, interval);
19  };
20
21  pollMktoForms2(() => {
22    // 既存のフォームがあれば即座に、これから生成されるものには準備ができ次第実行
23    window.MktoForms2.whenReady((form) => {
24      // utmFilteredのkeyの先頭に「PMCF_」か,末尾に「__c」をつけてセット
25      const utmValuesToSet = {};
26      Object.entries(utmFiltered).forEach(([key, value]) => {
27        utmValuesToSet[`PMCF_${key}`] = value;
28        utmValuesToSet[`${key}__c`] = value;
29      });
30      form.setValues(utmValuesToSet);
31    });
32  });
33};
34const UtmParameterControl = () => {
35  // すでに完了しているなら何もしない(グローバル変数は適宜定義してください)
36  if (window.__fr__utmTaskCompleted === true) return;
37
38  // eslint-disable-next-line compat/compat
39  const params = new URLSearchParams(window.location.search);
40  const currentTime = Date.now();
41  const hasUtmParamOriginal = [...params.keys()].some((key) => key.startsWith('utm_'));
42  let hasUtmParam = hasUtmParamOriginal;
43  const hasRequiredUtm = params.has('utm_source') && params.has('utm_medium');
44
45  // オーガニック検索流入の判定とパラメータ追加処理
46  if (!hasRequiredUtm && document.referrer) {
47    try {
48      const referrerUrl = new URL(document.referrer);
49      const host = referrerUrl.hostname.toLowerCase();
50
51      const organicList = [
52        'google.com',
53        'google.co.jp',
54        'yahoo.co.jp',
55        'yahoo.com',
56        'bing.com',
57        'biglobe.ne.jp',
58        'goo.ne.jp',
59        'duckduckgo.com',
60        'ecosia.org',
61        'yandex.ru',
62        'naver.com',
63        'baidu.com',
64        'so.com',
65        'ask.com'
66      ];
67
68      // リファラーが指定のオーガニック検索エンジンに該当するかチェック
69      const matchedDomain = organicList.find((domain) => host.includes(domain));
70
71      if (matchedDomain) {
72        // ドメインの最初のドットより前を抽出してGA4準拠のsource名とする(例: 'google', 'yahoo')
73        const detectedSource = matchedDomain.split('.')[0];
74
75        params.set('utm_source', detectedSource);
76        params.set('utm_medium', 'organic');
77        hasUtmParam = true; // 新たにパラメータを付与したため保存対象とする
78
79        let queryString = params.toString();
80        queryString = queryString.replace(/=(?=&|$)/g, ''); // 値が空のパラメータを「key=」から「key」に変換
81        const newUrl = `${window.location.pathname}${queryString ? '?' + queryString : ''}${window.location.hash}`;
82        history.replaceState(null, '', newUrl);
83      }
84    } catch (e) {
85      console.error('Referrer parse error:', e);
86    }
87  }
88
89  // 1. UTMがある場合は保存
90  if (hasUtmParam) {
91    try {
92      localStorage.setItem(
93        'last_utm_query',
94        JSON.stringify({
95          time: currentTime,
96          query: Object.fromEntries(params)
97        })
98      );
99    } catch (e) {
100      console.warn('localStorage is not available:', e);
101    }
102  }
103
104  // 2. 復元が必要かチェック
105  let rawData = null;
106  try {
107    rawData = localStorage.getItem('last_utm_query');
108  } catch (e) {
109    console.warn('localStorage read blocked:', e);
110  }
111
112  let savedQuery = null;
113  let isExpired = true;
114
115  if (rawData) {
116    const parsed = JSON.parse(rawData);
117    savedQuery = parsed.query;
118    isExpired = currentTime - parsed.time >= 1 * 864e5; // 1日
119  }
120
121  // localStorageが使えない環境向けにdocument.referrerからパラメータを救済する処理
122  if (!savedQuery && document.referrer) {
123    try {
124      const referrerUrl = new URL(document.referrer);
125      // 同一ホスト間での遷移であり、遷移元URLにUTMパラメータがある場合はデータを救済
126      if (referrerUrl.hostname === window.location.hostname) {
127        const referrerParams = Object.fromEntries(referrerUrl.searchParams);
128        const hasReferrerUtm = Object.keys(referrerParams).some((key) => key.startsWith('utm_'));
129        if (hasReferrerUtm) {
130          savedQuery = referrerParams;
131          isExpired = false; // 同一セッション内のため期限切れとしない
132        }
133      }
134    } catch (e) {
135      console.error('Referrer rescue process error:', e);
136    }
137  }
138
139  const hasMrktoFormDom = document.querySelector("form[id*='mktoForm_']");
140
141  // 復元条件に合致しない場合は終了
142  if (!hasMrktoFormDom || isExpired || (!savedQuery && !hasUtmParamOriginal)) return;
143
144  // 3. 実際の復元処理
145  if (!hasUtmParamOriginal && savedQuery) {
146    const utmEntries = Object.entries(savedQuery).filter(
147      ([key]) => key.toLowerCase().startsWith('utm_') || key.toLowerCase() === 'gclid'
148    ); // utm_から始まるパラメータとgclidを復元対象に追加
149
150    if (utmEntries.length > 0) {
151      utmEntries.forEach(([key, value]) => params.set(key, value));
152      params.set('restored', currentTime);
153
154      let queryString = params.toString();
155      queryString = queryString.replace(/=(?=&|$)/g, ''); // 値が空のパラメータを「key=」から「key」に変換
156      const newUrl = `${window.location.pathname}${queryString ? '?' + queryString : ''}${window.location.hash}`;
157
158      history.replaceState(null, '', newUrl);
159      window.__fr__utmTaskCompleted = true; // 完了フラグを立てる
160
161      try {
162        localStorage.setItem(
163          'last_utm_query',
164          JSON.stringify({
165            time: currentTime,
166            query: Object.fromEntries(params)
167          })
168        );
169      } catch (e) {
170        console.warn('localStorage is not available:', e);
171      }
172    }
173  }
174
175  // フォームへの値セットを実行
176  mrktInputValueUpdate(Object.fromEntries(params));
177};
178
179const setURLParameter = (url, paramName, paramValue) => {
180  let anchor = '';
181  if (url.indexOf('#') >= 0) {
182    anchor = url.substring(url.indexOf('#'));
183    url = url.substring(0, url.indexOf('#'));
184  }
185  if (url.indexOf('?') == -1) {
186    return paramValue !== null ? url + '?' + paramName + '=' + paramValue + anchor : url + '?' + paramName + anchor;
187  } else {
188    return paramValue !== null ? url + '&' + paramName + '=' + paramValue + anchor : url + '&' + paramName + anchor;
189  }
190};
191const catchLastLp = () => {
192  // eslint-disable-next-line compat/compat
193  const currentLocation = new URL(window.location.href);
194  const getParamsValue = currentLocation.searchParams;
195  const getParamsString = currentLocation.search;
196
197  const pageDirectory = location.pathname;
198
199  const formatPageDirectory = pageDirectory.replace(/\//g, '_').replace(/#/g, '').replace(/:/g, '').slice(0, -1);
200  const lastLpId = '__' + formatPageDirectory;
201
202  const isReferral = getParamsString.includes('referral');
203  const isAdvisorReferral3 = getParamsString.includes('advisorReferral3');
204  const isAfSub = getParamsString.includes('af_sub1');
205
206  const aTag = document.querySelectorAll('a');
207  aTag.forEach((element) => {
208    let hrefInPage = element.getAttribute('href');
209    const loginURLRegex = /accounts\.secure\.freee\.co\.jp\/sessions\/new/;
210
211    if (hrefInPage) {
212      if (/last_lp/.test(hrefInPage)) return; // すでにlast_lpが付与されているなら抜ける
213      if (loginURLRegex.test(hrefInPage)) return; // loginURLなら抜ける
214      if (/secure\.freee\.co\.jp/.test(hrefInPage)) {
215        hrefInPage = setURLParameter(hrefInPage, 'last_lp', lastLpId);
216      }
217      if (
218        !((hrefInPage.startsWith('http') || hrefInPage.startsWith('//')) && !hrefInPage.includes('www.freee.co.jp')) ||
219        /secure\.freee\.co\.jp/.test(hrefInPage)
220      ) {
221        if (isReferral) {
222          const referralValue = getParamsValue.get('referral');
223          hrefInPage = setURLParameter(hrefInPage, 'referral', referralValue);
224        }
225        if (isAdvisorReferral3) {
226          const advisorReferral3Value = getParamsValue.get('advisorReferral3');
227          hrefInPage = setURLParameter(hrefInPage, 'advisorReferral3', advisorReferral3Value);
228        }
229        if (isAfSub) {
230          const AfSubValue = getParamsValue.get('af_sub1');
231          hrefInPage = setURLParameter(hrefInPage, 'af_sub1', AfSubValue);
232        }
233      }
234      element.setAttribute('href', hrefInPage);
235    }
236  });
237};
238
239UtmParameterControl();
240
241catchLastLp();

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.