טוב, אז קודם כל אני רוצה שתקחו נשימה עמוקה. זה הולך להיות מדריך מקיף, מפורט, חופר ומעמיק ביותר על הדבר הכי מגניב שקיים בגוגל תג מנג׳ר (להלן GTM), ואני רוצה שתבינו את הנושא לעומק ולכן לא אסתפק בהסברים מעל פני השטח.
הדבר המגניב הזה נקרא dataLayer (להלן dL), ולמרות שעל פניו הוא נראה פשוט אני באופן אישי מתלהב ממנו כל פעם מחדש כשאני מגלה עד כמה אפשרויות המשחק איתו הם בלתי מוגבלות.
אז כמו שאמרתי, הפוסט הולך להיות דיי טכני, ואני יודע שברגע זה 80% יפסיקו לקרוא אבל זה לא ממש אכפת לי כי אני נהנה מזה 🙂
מה שכן חשוב לי להקדים שהמטרה של הפוסט הזה היא לעזור לכם להבין איך בדיוק פועל הדטאלייר ומה ההגיון שעומד מאחוריו, כדי שתדעו איך להשתמש בו לפעילויות יותר מתוחכמות מהדברים הרגילים שקיימים מעל פני השטח.
מוכנים? נתחיל:
ובכן – מה זה dataLayer?
אז דטאלייר, dL, הוא בעצם מערך JavaScript (להלן JS) שקולט לתוכו נתונים כדי שאחר כך GTM יוכל להשתמש בהם לצרכים שונים.
אם יש לכם קצת ידע בג׳אווה סקריפט אתם יכולים לדלג לקטע הבא. אם לא תמשיכו לקרוא:
באופן כללי מערך JS מוגדר באמצעות שורת קוד פשוטה שנראית כך: [syntax type=”js”]dataLayer = [][/syntax] או כך: [syntax type=”js”]var dataLayer = [][/syntax] או כך: [syntax type=”js”]var dataLayer = new Array()[/syntax]
לאחר שהגדרנו מערך JS, ניתן לדחוף לתוכו איברים ולאחר מכן להתייחס אליהם באמצעות מספרים (ש-0 מתייחס לראשון, 1 לשני וכן הלאה). כך למשל האובייקט הראשון יהיה [syntax type=”js”]dataLayer[0][/syntax] השני יהיה [syntax type=”js”]dataLayer[1][/syntax] וכן הלאה.
בואו ננסה את זה – פתחו את הקונסולה בדפדפן שלכם (F12 או CMD+option+J במקינטוש) ורשמו [syntax type=”js”]dataLayer = [][/syntax]
בואו נכניס ערך מסוים לאיבר הראשון (0) במערך (ואחרי זה לעוד איברים) – [syntax type=”js”]dataLayer[0] = “aaa”[/syntax],
עכשיו אם תכתבו סתם dataLayer בקונסול אתם תראו את כל המערכים שהכנסתם לdL אחד אחרי השני.
כמובן שאפשר לעשות את זה יותר קצר, כלומר ליצור את הdL ובאותה שורה להכניס אליו מיד כמה איברים כאשר הם מופרדים עם פסיק. נסו את זה ותראו איך האיבר הראשון/שני/שלישי מוחזר אליכם כאשר אתם קוראים לו בצורה ישירה (סוגריים מרובעות+מספר האיבר). כמובן שכאשר אתם כותבים רק dataLayer הוא מחזיר את כל הערכים:
הדברים האלו נקראים ״מערכים של מחרוזות (strings)״, וכמובן שיכול להיות מערכים של מספרים (ללא הגרשיים) או מערכים בוליאנים שלא נכנס אליהם כרגע.
כמו שאמרנו, לאיברים בתוך המערכים ניגשים על ידי שכותבים את שם המערך, ולאחר מכן את מספר האיבר בתוך סוגריים מרובעות, כמו זה למשל [syntax type=”js”]dataLayer[0][/syntax]
סוג נוסף של מערכים שיכולים להיות זה מערך של אובייקטים, וזה בעצם מה שמרכיב את ה-dL שלנו.
אובייקטים ב-JS
כשאומרים ״אובייקט״ ב-JS הכוונה למשתנה (variable), אבל במקום להכיל ערך בודד הוא מכיל צמדי ערכים המורכבים מ-property-value, המופרדים ביניהם עם פסיק.
כדי לראות את זה בפעולה פתחו את הקונסולה וכתבו את השורה הבאה:
[syntax type=”js”]object = {‘property1′:’value1′,’property2′:’value2′,’property3′:’value3’}[/syntax]
השורה הזו בעצם יוצרת משתנה בשם object שמכיל 3 צמדי ערכים. אחרי שיצרתם אותו אתם יכולים לרשום פשוט object ולקבל את כל הצמדים שהכנסתם, או לציין property ספציפי ואז לקבל את הערך הספציפי שלו. ככה:
כדי להוסיף צמדים לאובייקט הזה, אתם יכולים לכתוב [syntax type=”js”]object.newProp = “value”[/syntax] או [syntax type=”js”]object[“newProp”] = “value”[/syntax].
עד כאן דיברנו על אובייקט JS עם כמה ערכים, אבל זה עדיין לא dL כי הדטאלייר הוא מערך (זוכרים את החלק הראשון של הפוסט?) שנראה ככה:
[syntax type=”js”]dataLayer = [{‘property1′:’value1′,’propery1′:’value2′,’property3′:’value3’}][/syntax]
באופן עקרוני אפשר להגיד שמערך JS נמצא “מעל” האובייקט של ה-JS, ויכול להכיל מספר אובייקטים של JS, שבתוך כל אחד מהם מספר צמדים של key:value. ההבדל שחשוב לזכור ביצירה של המערך (בניגוד לאובייקט) הוא בסוגריים המרובעות שעוטפות את האובייקטים.
בדוגמא הבא תוכלו לראות שיצרתי מערך בשם dataLayer, שבתוכו יש 2 אובייקטים שכל אחד מהם מכיל 3 צמדים. אני יכול לגשת לאיבר הראשון במערך בעזרת ציון המספר שלו (0 עבור האיבר הראשון) ואז אקבל את כל הצמדים שבאותו איבר (שהוא בעצם אובייקט), או לקבל ערך ספציפי של צמד מסוים, אליו אני ניגש על ידי [syntax type=”js”]dataLayer = [0][“key1”][/syntax]
באופן עקרוני אין סיבה להכניס לdL יותר מאיבר אחד, מכיוון שתחת האובייקט עצמו אפשר להכניס עוד אובייקטים, וכך ליצור את המערך עם מספר אובייקטים, שבכל אחד מהם יש עוד תתי אובייקטים. נסו לכתוב את הקוד הבא בקונסולה:
[syntax type=”js”]dataLayer=[{ “totalPrice”:164900.00, “products”:{“clothing”:”shirt”,”clothing”:”pants”,”footwear”:”shoes”}}][/syntax]
זה יצר לנו מערך עם איבר אחד שהוא אובייקט שמכיל 2 צמדים. ניתן לכתוב dataLayer ולקבל את כל המערך, ניתן לכתוב [syntax type=”js”]dataLayer[0][/syntax] ולקבל את האיבר הראשון (שהוא היחיד במקרה שלנו), וניתן לקבל ערך מסוים בעזרת פניה ל-property הספציפי שמכיל את הערך הזה. נסו לכתוב dataLayer[0][“totalPrice”] ותראו שאתם מקבלים את הערך הספציפי שמצא ב-property של totalPrice.
כדי לדחוף עוד נתונים למערך צריך פשוט לכתוב [syntax type=”js”]dataLayer.push({‘key’:’value’})[/syntax] ושימו לב לpush שבעצם מוסיף ערכים במקום להחליף את כל המערך.
כדי לשנות ערכים באחד הproperties צריך פשוט לדחוף ערך אחר לאותו פרופרטי.
[mc4wp_form id=”2160″]
ועכשיו אנחנו מגיעים ל-GTM
כשאתם מתקינים את הסניפט של GTM אתם בעצם מריצים פונקציה עם 5 ארגומנטים, שהרביעי מביניהם נקרא dataLayer (או כל שם אחר שתחליטו לקרוא לו, אם כי לא כדאי לשנות את זה בלי לדעת מה אתם עושים).
שימו לב שמיד בתחילת הפונקציה כתוב לכם: [syntax type=”js”]w[l]=w[l]||[][/syntax] וזאת בדיוק השורה שיוצרת את מערך הdataLayer שלנו.
אם נפשט את הקיצורים ונכתוב את זה בצורה יותר ברורה, יצא לנו: [syntax type=”js”]window[‘dataLayer’] = window[‘dataLayer’] || [][/syntax] שזה בעצם יוצר מערך בשם dataLayer, ואז מכניס אליו את הערכים של מערך dataLayer אם הוא קיים כבר (במידה והכנסתם ערכים למערך לפני הקריאה לסניפט), ואם הוא לא קיים – הוא יוצר מערך חדש.
ה-w זה בעצם window ו-l זה dataLayer, והם מוגדרים בשורה האחרונה.
הסיבה שהקוד בודק אם יש כבר מערך בשם dataLayer היא מכיוון שהרבה פעמים אנחנו רוצים להכניס ערכים לתוך ה-dL לפני הקריאה לסניפט של GTM, כדי שהוא יוכל להשתמש בערכים הללו לפני ששאר התוכן של העמוד נטען.
אם למשל אתם רוצים לשלוח ערכים מסויימים ביחד עם הקוד של גוגל אנליטיקס (למשל Custom Dimensions או Custom Metrics), ובהנחה שקוד הGTM שלכם מותקן מיד בתחילת ה<body>, אתם חייבים ש-GTM יוכל לקחת את הערכים האלו מיד בהתחלה ואתם לא יכולים לחכות לטעינה של שאר העמוד, ולכן חובה להכניס את הערכים לdL לפני הסניפט. במצב כזה, אם הסניפט היה יוצר מחדש את מערך ה-dataLayer זה היה דורס את כל הערכים שכבר הכנסנו אליו, ולכן הקוד קודם כל בודק אם המערך קיים – אם כן הוא משאיר אותו כמו שהוא ואם לא הוא יוצר חדש.
אז מה השוס של ה-dataLayer?
הבעיה עם אובייקטים ומערכים של JS היא שכדי לקבל את הערך שנמצא בפרופרטי אני חייב לדעת את המיקום של האובייקט בתוך המערך, מה שאפשרי אבל לא ממש ידידותי למשתמש.
ופה בדיוק נכנס המאקרו dataLayer Variable שאתם יכולים ליצור ב-GTM, ולחסוך לעצמכם שעות רבות של עבודה והתעסקות עם משתנים ומערכים.
[blockquote]
הערה חשובה שצריך לדעת:
כאשר אתם מגדירים Event Listener ב-GTM, הוא דוחף איבר נוסף (אובייקט) לתוך ה-dL שמכיל שישה properties. אחד מהם הוא event, השני זה הקלאס של האלמנט, השלישי זה ה-Id וכו׳ כאשר החשוב ביותר (לדעתי) נקרא gtm.element והוא מכיל את כל המאפיינים של האלמנט הזה ושל כל האלמנטים שקשורים אליו בהיררכיה של ה-DOM. כשגיליתי את זה הרגשתי שעליתי על מכרה זהב! ממש ככה. בהמשך אראה לכם איך אפשר להשתמש בזה.
שימו לב שכל הנתונים מתייחסים לאותו אלמנט שיצר את הauto event. למשל אם הגדרתם Click Listener והקלקתם על אלמנט מסוים בעמוד (נגיד כותרת H1), אז האיבר (וגם ה-gtm.element כמובן) יכיל את כל הנתונים על ה-H1, וכן הלאה.
[/blockquote]
הרעיון פה הוא, שכאשר אנחנו יוצרים dataLayer Variable ומכניסים לו ערך מסוים, אנחנו יכולים לגשת בצורה פשוטה מאוד לכל המאפיינים של האלמנטים השונים בהיררכיה של הDOM שיש להם קשר לאותו אלמנט.
כדי להמחיש לכם את זה אתן דוגמא שהיתה לי עם אחד הלקוחות שלי – באתר שלו היה את הdiv הבא:
[syntax type=”html”]
<div id=”video_box”>
<div>
<a href=”#video”>
<img src=”….”>
</a>
</div>
</div>
[/syntax]
אני רציתי פשוט לשים איוונט של גוגל אנליטיקס כדי שאוכל לעקוב אחרי כל אלו שלחצו על התמונה כדי לראות את הוידאו, והתכנון היה לשים link click listener, שכאשר הגולש לוחץ על לינק (event equals gtm.linkClick) עם קלאס או Id מסוים (element id equals something) – האיוונט ישלח.
הבעיה היתה שהאלמנט ש-GTM זיהה בזמן הקליק היה התמונה (כלומר – זה האלמנט שיצר את הauto event ולכן כל הgtm.element התיחס אליו), והאלמנט היחיד שהכיל קלאס או id היה 3 רמות מעליה.
הפתרון היה ״פשוט״ למדי
יצרתי משתנה מסוג dataLayer Variable והכנסתי בו את הערך הבא: gtm.element.parentElement.parentElement.parentElement.className.
המשתנה הזה ניגש ישירות לתוך הdL, ומתחיל לחפש באיבר האחרון את הקלאס של האלמנט-האב השלישי. אם הוא מוצא – הוא מחזיר את הערך שלו (video_box במקרה שלנו) ועוצר את התהליך. אם לא הוא עובר לבדוק באיבר הקודם, וכן הלאה.
עוד דוגמא שאולי תעשה לכם יותר שכל:
נגיד שיש לי את הקוד הבא:
ואני רוצה שבכל פעם שמישהו מקליק על div#6 – אני אקבל את הערך שנמצא ב-div#4-1 (אל תשאלו אותי למה שארצה לעשות דבר כזה, אבל זה רק בשביל הדוגמא). כלומר אני צריך לטפס 2 רמות למעלה ועוד אחד ימינה. אם נצייר את ה-DOM Tree זה יראה ככה:
כדי להגיע לזה אני קודם כל מוסיף click listener כמובן, ואז מוסיף מאקרו מסוג dL Variable ונותן לו את הערך gtm.element.parentElement.parentElement.nextElementSibling.innerText.
כמו שאמרנו, בכל פעם שיתבצע אירוע onclick ה-GTM יוסיף את הgtm.element לתוך הdL והוא כמובן יכיל את כל המידע על האלמנט שעליו הקליקו. בכל פעם המאקרו יטפס 2 רמות למעלה ואחד הצידה וינסה להחזיר את הטקסט של האלמנט הזה (אם הוא קיים), וכאשר יקליקו על הdiv#6 – הוא יחזיר את הטקסט 4-1.
דוגמא שימושית יותר
הפוסט כבר מתחיל להיות ארוך אז אתן דוגמא אחת שימושית ואחרי זה אשחרר אתכם:
נגיד שיש לכם טופס בעמוד עם 3 שדות – שם, מייל, וטלפון, ובכל פעם שהטופס נשלח אתם רוצים לבדוק איזה שדות לא מולאו ואז לשלוח לגוגל אנליטיקס event עם השם של השדה שלא מולא.
מה שאתם צריכים לעשות זה דבר פשוט מאוד – צרו מאקרו מסוג dL Var ובvalue שלו תכתבו gtm.element.children.
זה יחזיר מערך עם כל תתי-האלמנטים של gtm.element (שכמו שאמרנו זה האלמנט שיפעיל את הauto event listener).
לאחר מכן צרו תג מסוג Custom HTML ורשמו בו:
[syntax type=”js”]
<script>
for (i=0;i<{{element}}.length;i++){
if ({{children}}[i].value == ”) {
ga(‘send’,’event’,{{children}}[i].name);}
}
</script>
[/syntax]
וכמובן תנו לו rule שיפעל כשהטופס נשלח (event equals gtm.formSubmit).
בכל פעם שהטופס נשלח – GTM דוחף למאקרו {{element}} את האובייקט gtm.element שבמקרה שלנו זה הטופס.
קוד הHTML שלנו יוצר בעצם לולאה באורך מספר השדות (האינפוטים) שיש בטופס (פחות 1, בגלל שזה ״קטן מ-״) ואז בודק לגבי כל כל אחד מהשדות אם הוא ריק, ואם כן הוא שולח איוונט עם השם של השדה הנוכחי בתור ה-label של האיוונט: [syntax type=”js”]{{children}}[i].name[/syntax]
איך נדע בדיוק איך לפנות לאלמנט הנכון ב-dataLayer Variable?
נורא פשוט – אחרי שהוספת Event Listener, תלחצו על האלמנט שאליו אתם רוצים לפנות (או על אחד האלמנטים שבסביבה שלו) וזה יכניס את הgtm.element לתוך מערך ב-dL. עכשיו לכו לקונסולה, כתבו dataLayer ולחצו על האובייקט האחרון במערך (זה בעצם האובייקט שנוצר כתוצאה מהאירוע שלכם).
עכשיו אתם תראו ב-gtm.element את האלמנט שהפעיל את הauto event ואם תפתחו אותו אתם תראו את כל הproperties של האלמנט הזה, כולל מה שמעליו, מצדדיו ומתחתיו בהיררכיה של הDOM. עכשיו אתם פשוט צריכים לקחת את זה ולכתוב בתור הערך של ה dataLayer Variable וכאשר תקראו למאקרו הזה הוא יחזיר את הערך שלו:
סיכום
דיי, חפרתי מספיק. מקווה שהבנתם והתלהבתם כמוני ואם לא אז תשאירו תגובה (פשוט נראה לי שככה יהיו יותר תגובות 🙂 )
מה שבאתי להראות פה זה את היופי של ה-dataLayer Variable שבעצם מאפשר לגשת לכל אלמנט בדטאלייר ולהתייחס אליו עם כל האפשרויות שקיימות בג׳אווה סקריפט רגיל – רק ישירות מהממשק של GTM ועם קיצורים שחוסכים המון זמן.
כמובן שהאפשרויות פה הם באמת בלתי מוגבלות והמדריך הזה נועד לתת לכם רק טעימה קטנה ולהסביר לכם את ההגיון מאחורי הדברים.
אז צ׳או לבינתיים,
שלכם תמיד (טוב, כמעט…)
שוקי
פשוט מאוד ההסבר הכי טוב שאי פעם תוכלו לקרוא על ה DATALAYER.
כל הכבוד שוקי, כרגיל אתה מפציץ!
תודה אייל. מזל שיש מישהו שאני יודע שבטוח יקרא פוסטים כאלו 😉
אחלה פוסט, מרגישים שאתה אוהב את מה שאתה עושה:) רק תיקון דפוס קטנטן תחת ‘אובייקטים JS’ אני מניחה שהתכוונת לכתוב property2:value2.
תודה אלה 🙂
תוקן