HEX
Server: Microsoft-IIS/10.0
System: Windows NT ITPWINWEBSVR22 10.0 build 20348 (Windows Server 2022) AMD64
User: www.conferencesearch.co.uk (0)
PHP: 8.3.30
Disabled: NONE
Upload Files
File: D:/web/hyperflight/! bs5/gtm-lib.asp
<%

' (SS,13/10/23) Google Tag Manager module
' (SS,19/10/23) Version 1.00
' (SS,20/10/23) Version 1.01 - Added id and and google_business_vertical for Google Ads Remarketing
' (SS,24/10/23) Version 1.02 - Added dataLayer = [] to DoGoogleTagManagerScript, not actually required, just to keep James/Jimmy happy
' (SS,23/10/23) Version 1.03 - Added EventContactForm, renamed DoEcommerceEvents to DoEvents
' (SS,10/11/23) Version 1.04 - Tidied up enhanced conversion event and tested it, also event contact form code (not yet in use)
' (SS,15/01/24) Version 1.05 - Changes to add Backona version of the GTM script, new properties BackonaAnalyticsEnabled and BackonaAnalyticsDomain, new sub DoBackonaGTMScript
' (SS,Public Sub DoGoogleTagManagerScript
' (SS,27/02/24) Version 1.06 - Change to Public Sub DoGoogleTagManagerScript, removed at Backona's request the dataLayer = [] line that this was causing an issue with their settings.

Class GTMDef
 
  ' can't use a const, using a variable instead, see https://stackoverflow.com/questions/21052084/constant-inside-class
  ' Const GTM_DATA_INDENT_SPACES = 2
  Private INDENT_SPACES ' used as a constant

  Private FGTMContainerID, FAffiliation
  
  Private FBackonaAnalyticsEnabled, FBackonaAnalyticsDomain ' (SS,15/1/24)
  
  Private FDataIndentLevel, FGTMData, FItemDataCount
  
  ' Private FProductCode, FProductName, FProductVariant, FBrand, FCategory, FSubcategory, FPrice
  
  Private FEventName, FCurrency, FDiscountCode, FSearchTerm ' FDiscount
  
  Private FTransactionID, FPurchaseValue, FPurchaseTax, FShipping
  
  ' field constants
  Private F_EVENT_NAME, F_PRODUCT_CODE, F_PRODUCT_NAME, F_PRODUCT_VARIANT, F_PRICE, F_QUANTITY, F_BRAND, F_CATEGORY, F_SUBCATEGORY, F_FIELD_COUNT
  
  ' items array
  Private FItems, FFieldNo
    
  
  ' event name constants
  Private E_VIEW_ITEM, E_VIEW_CART, E_ADD_TO_CART, E_REMOVE_FROM_CART, E_BEGIN_CHECKOUT, E_ADD_SHIPPING_INFO, E_ADD_PAYMENT_INFO, E_PURCHASE, E_SEARCH, E_ENHANCED_CONVERSION
  ' Private FViewItemCount, FViewCartCount, FAddToCartCount, FRemoveFromCartCount
  
  ' (SS,23/10/23)
  Private FContactFormName
  
  ' (SS,23/10/23) enhanced conversion data
  Private FHasEnhancedConversionData, FEmail, FPhone, FFirstName, FLastName, FCity, FRegion, FPostcode, FCountryCode
    
  Private Function FieldNo
    FFieldNo = FFieldNo + 1
    F_FIELD_COUNT = FFieldNo    
    FieldNo = FFieldNo
  End Function
  
  Private Sub Class_Initialize 
    INDENT_SPACES = 2
    
    FGTMContainerID = ""
    FAffiliation = ""
    FBackonaAnalyticsEnabled = False ' (SS,15/1/24)
    FBackonaAnalyticsDomain = ""     ' (SS,15/1/24)
    
    'FGTMDataIndentLevel = 0
    'FGTMData = ""
    'FItemDataCount = 0    
    
    E_VIEW_ITEM = "view_item"
    E_VIEW_CART = "view_cart"
    E_ADD_TO_CART = "add_to_cart"
    E_REMOVE_FROM_CART = "remove_from_cart"
    E_BEGIN_CHECKOUT = "begin_checkout"
    E_ADD_SHIPPING_INFO = "add_shipping_info"
    E_ADD_PAYMENT_INFO = "add_payment_info"
    E_PURCHASE = "purchase"
    E_SEARCH = "search"
    
    E_ENHANCED_CONVERSION = "enhanced_conversion" ' custom (not built in event) to pass on enhanced conversion data
    
    FEventName = ""
    FCurrency = "GBP"    
    ' FDiscount = 0
    FDiscountCode = ""
    FSearchTerm = ""
    FHasEnhancedConversionData = False
    
    FTransactionID = ""    
    FPurchaseValue = 0 
    FPurchaseTax = 0
    FShipping = 0
    
    ' field contants    
    FFieldNo = -1 ' held in FieldNo and increments in each call
    F_EVENT_NAME = FieldNo
    F_PRODUCT_CODE = FieldNo
    F_PRODUCT_NAME = FieldNo
    F_PRODUCT_VARIANT = FieldNo
    F_PRICE = FieldNo
    F_QUANTITY = FieldNo
    F_BRAND = FieldNo
    F_CATEGORY = FieldNo
    F_SUBCATEGORY = FieldNo
    
    ' (SS,23/10/23)
    FContactFormName = ""
    
    ReDim FItems(F_FIELD_COUNT, -1)   
    
  End Sub
  
  Public Sub Class_Terminate

  End Sub  

  ' contruct with parameter see http://johna.compoutpost.com/blog/806/classic-asp-class-constructors-with-parameters/
  Public Default Function Init(AContainerID, AAffiliation)
    FGTMContainerID = AContainerID
    FAffiliation = AAffiliation
    Set Init = Me
  End Function

  ' (SS,15/1/24)
  Public Property Let BackonaAnalyticsEnabled(AValue)
    FBackonaAnalyticsEnabled = AValue
  End Property
  
  ' (SS,15/1/24)
  Public Property Let BackonaAnalyticsDomain(AValue)
    FBackonaAnalyticsDomain = AValue
  End Property    
    
 ' Public Property Let Discount(AValue)
 '   FDiscount = AValue
 ' End Property
  
  Public Property Let DiscountCode(AValue)
    FDiscountCode = AValue
  End Property

  Public Property Let TransactionID(AValue)
    FTransactionID = AValue
  End Property

  Public Property Let PurchaseValue(AValue)
    FPurchaseValue = AValue
  End Property
  
  Public Property Let PurchaseTax(AValue)
    FPurchaseTax = AValue
  End Property
  
  Public Property Let Shipping(AValue)
    FShipping = AValue
  End Property     
  
  Private Sub SetDataIndentLevel(AIndentLevel)
    FDataIndentLevel = AIndentLevel
  End Sub

  Private Sub IncDataIndentLevel
    FDataIndentLevel = FDataIndentLevel + 1
  End Sub

  Private Sub DecDataIndentLevel
    FDataIndentLevel = FDataIndentLevel - 1
  End Sub

  Private Function GetDataIndentSpaces
    GetDataIndentSpaces = Space(INDENT_SPACES * FDataIndentLevel)
  End Function

  Private Sub StartGTMData
    FGTMData = ""
  End Sub

  Private Sub EndGTMData

  End Sub

  Private Sub ShowGTMData
    Response.Write FGTMData
  End Sub
  
  Private Sub StartItem
    FItemDataCount = 0
    FGTMData = FGTMData + GetDataIndentSpaces + "{" + NL
    IncDataIndentLevel
  End Sub
    
  Private Sub NextItem
    FGTMData = FGTMData + "," + NL
  End Sub
  
  Private Sub EndItem
    DecDataIndentLevel
    FGTMData = FGTMData + NL + GetDataIndentSpaces + "}"
  End Sub

  ' *** ? to be improved with JSON object handling
  ' NB. thought number needs to be passed without quotes around it, later discovered the debug view multiplies by 1000000 causing confusion
  Private Sub AddGTMDataLine(AName, AValue)
    Dim LValue
    LValue = NB(AValue) ' converts to string including the null
    If LValue = "" Then Exit Sub
    
    ' add quote around string types only
    Dim LQuote
    If VarType(AValue) = VBString Then
      LQuote = """"
    Else
      LQuote = ""
    End If
    
    If FItemDataCount > 0 Then FGTMData = FGTMData + "," + NL 
    FItemDataCount = FItemDataCount + 1
    
    FGTMData = FGTMData + GetDataIndentSpaces + AName + ": " + LQuote + JavaScriptStrEscape(AValue) + LQuote

  End Sub
  
  
  Private Function GetNameValueStr(AName, AValue, AAppendComma)
    Dim LResult, LValue
    LValue = NB(AValue) ' converts to string including the null
    If LValue <> "" Then
      ' add quote around string types only
      Dim LQuote
      If VarType(AValue) = VBString Then
        LQuote = """"
      Else
        LQuote = ""
      End If
      LResult = GetDataIndentSpaces + AName + ": " + LQuote + JavaScriptStrEscape(AValue) + LQuote + iif(AAppendComma, ",", "") + NL      
    Else
      LResult = ""
    End If

    GetNameValueStr = LResult
  End Function
  
  
  Private Sub ShowEcommerceValue(AName, AValue, AAppendComma)
  
    Response.Write GetNameValueStr(AName, AValue, AAppendComma)
  
  End Sub


  Private Sub ShowEcommerceScriptHeader
  ' may not need first line, to check  // Clear the previous ecommerce object.  
  ' (SS,10/11/23) removed the following, don't think it's required
  ' dataLayer.push({ ecommerce: null });
%>
<script><%
  End Sub

  Private Sub ShowEcommerceEventHeader(AEventName)
    ' (SS,23/10/23) added following variable to also do user_data for enhanced_conversion as well as existing ecommerce for the events
    Dim LDataName
    If AEventName = E_ENHANCED_CONVERSION Then
      LDataName = "user_data" 
    Else
      LDataName = "ecommerce"
    End If
%>
dataLayer.push({  
  event: "<%=AEventName%>",
  <%=LDataName%>: {
<%
  End Sub
  
  Private Sub ShowEcommerceEventFooter
%>  }
});<%
  End Sub
  
  Private Sub ShowEcommerceScriptFooter
%>
</script>
<%
  End Sub
  
  ' (SS,23/10/23)
  ' (SS,10/11/23) not yet used or fully developed
  Private Sub ShowContactFormEvent(AFormName)
%>
dataLayer.push({  
  event: "contact_form",
  form_name: ""<%=AFormName%>")
  }
});
<%
  End Sub

  Private Sub ShowEcommerceEventItemsStart
    Response.Write GetDataIndentSpaces + "items: [" + NL
  End Sub
  
  Private Sub ShowEcommerceEventItemsEnd
    Response.Write NL + GetDataIndentSpaces + "]" + NL
  End Sub
  
  ' returns true if there is at least one event
  Private Function IsEvent
    IsEvent = UBound(FItems, 2) > -1
  End Function
  
  Private Function EventCount(AEventName)
    Dim i, LResult
    LResult = 0
    For i = 0 To UBound(FItems, 2)            
      If FItems(F_EVENT_NAME, i) = AEventName Then
        LResult = LResult + 1        
      End If
    Next
    EventCount = LResult
  End Function
  
  Private Function EventValue(AEventName)    
    Dim i, LResult
    LResult = 0
    For i = 0 To UBound(FItems, 2)            
      If FItems(F_EVENT_NAME, i) = AEventName Then
        LResult = Round(LResult + Round(FItems(F_PRICE, i) * FItems(F_QUANTITY, i), 2), 2)      
      End If
    Next
    EventValue = LResult    
  End Function
  
  Private Sub ShowEcommerceEventItems(AEventName)
    StartGTMData
    
    Dim i, LIndex, LProductCode
    LIndex = 0
    For i = 0 To UBound(FItems, 2)           
      If FItems(F_EVENT_NAME, i) = AEventName Then
        If LIndex > 0 Then NextItem
        StartItem
        ' only item_id and item_name are required
        'AddGTMDataLine "event_name_**_to_remove", FItems(F_EVENT_NAME, i)
        LProductCode = FItems(F_PRODUCT_CODE, i)
        AddGTMDataLine "item_id", LProductCode
        AddGTMDataLine "item_name", FItems(F_PRODUCT_NAME, i)
        AddGTMDataLine "item_variant", FItems(F_PRODUCT_VARIANT, i)
        AddGTMDataLine "affiliation", FAffiliation
        AddGTMDataLine "index", LIndex
        AddGTMDataLine "item_brand", FItems(F_BRAND, i)
        AddGTMDataLine "item_category", FItems(F_CATEGORY, i)
        AddGTMDataLine "item_category2", FItems(F_SUBCATEGORY, i)
        AddGTMDataLine "price", FItems(F_PRICE, i)
        AddGTMDataLine "quantity", FItems(F_QUANTITY, i)
        ' for Google Ads remarketing, which requires id instead of item_id and also google_business_vertical, don't include special DISCOUNT item 
        If LProductCode <> "DISCOUNT" Then
          AddGTMDataLine "id", LProductCode
          AddGTMDataLine "google_business_vertical", "retail"
        End If
        EndItem
        LIndex = LIndex + 1
      End If
    Next
    
    EndGTMData
    ShowGTMData 
  End Sub

  Public Sub EventViewItem
    FEventName = E_VIEW_ITEM
  End Sub
  
  Public Sub EventViewCart
    FEventName = E_VIEW_CART
  End Sub
  
  Public Sub EventAddToCart
    FEventName = E_ADD_TO_CART
  End Sub
  
  Public Sub EventRemoveFromCart
    FEventName = E_REMOVE_FROM_CART
  End Sub
  
  Public Sub EventBeginCheckout
    FEventName = E_BEGIN_CHECKOUT
  End Sub
  
  Public Sub EventAddShippingInfo
    FEventName = E_ADD_SHIPPING_INFO
  End Sub
  
  Public Sub EventAddPayment
    FEventName = E_ADD_PAYMENT_INFO
  End Sub
  
  Public Sub EventPurchase
    FEventName = E_PURCHASE
  End Sub
  
  ' (SS,23/10/23)
  Public Sub AddEnchancedConversionData(AEmail, APhone, AFirstName, ALastName, ACity, ARegion, APostcode, ACountryCode)
    FEventName = E_ENHANCED_CONVERSION ' doesn't really get used for anything
    FHasEnhancedConversionData = True
    FEmail = AEmail
    FPhone = APhone
    FFirstName = AFirstName
    FLastName = ALastName
    FCity = ACity
    FRegion = ARegion
    FPostcode = APostcode
    FCountryCode = ACountryCode
  End Sub
  
  ' (SS,19/10/23) *** to be completed
  Public Sub EventSearch(ASearchTerm)
    FEventName = E_SEARCH
    FSearchTerm = ASearchTerm
  End Sub
    
  ' quick single line method of adding an item, to be called after calling EventViewCart or EventAddToCart
  Public Sub AddItem(AProductCode, AProductName, AProductVariant, APrice, AQuantity, ABrand, ACategory, ASubcategory)    
    ' add to array to store new item
    Dim i
    i = UBound(FItems, 2) + 1
    Redim Preserve FItems(UBound(FItems, 1), i) ' resize the array preserving the existing data

    FItems(F_EVENT_NAME, i) = FEventName
    FItems(F_PRODUCT_CODE, i) = AProductCode
    FItems(F_PRODUCT_NAME, i) = AProductName
    FItems(F_PRODUCT_VARIANT, i) = AProductVariant
    FItems(F_PRICE, i) = APrice
    FItems(F_QUANTITY, i) = AQuantity
    FItems(F_BRAND, i) = ABrand
    FItems(F_CATEGORY, i) = ACategory
    FItems(F_SUBCATEGORY, i) = ASubcategory
  End Sub   
  
  ' (SS,23/10/23)
  ' (SS,10/11/23) not yet used/developed fully
  Public Sub EventContactForm(AFormName)
    FContactFormName = AFormName
  End Sub
  
  Public Function Enabled
    Enabled = FGTMContainerID <> ""
  End Function  
  
  ' (SS,25/10/23) calls DoEvents below, to be removed once DoEvents has been added to apputils.asp
  Public Sub DoEcommerceEvents
    DoEvents
  End Sub  
  
  ' (SS,23/10/23) renamed DoEcommerceEvents to DoEvents  
  Public Sub DoEvents
    If Not Enabled Then Exit Sub
    
    ' If IsEvent Then ' if at least one event 
    ' (SS,10/11/23) replaced above with following    
    If IsEvent Or FContactFormName <> "" Then ' if at least one event        
      ShowEcommerceScriptHeader    
      
      If IsEvent Then
        DoEcommerceEvent E_REMOVE_FROM_CART
        DoEcommerceEvent E_ADD_TO_CART
        DoEcommerceEvent E_VIEW_CART
        DoEcommerceEvent E_VIEW_ITEM
        DoEcommerceEvent E_BEGIN_CHECKOUT
        DoEcommerceEvent E_ADD_SHIPPING_INFO
        DoEcommerceEvent E_ADD_PAYMENT_INFO
        DoEcommerceEvent E_PURCHASE
      End If
      
      DoEnchancedConversionData ' will only be added for E_PURCHASE event
      
      ' (SS,23/10/23) custom contact form event
      ' *** to be continued
      If FContactFormName <> "" Then
        ShowContactFormEvent FContactFormName
      End If
    
      ShowEcommerceScriptFooter
    End If
  End Sub
  
  Private Sub DoEcommerceEvent(AEventName)
    If EventCount(AEventName) > 0 Then    
      ShowEcommerceEventHeader AEventName
      SetDataIndentLevel 2
      
      ShowEcommerceValue "currency", FCurrency, True
      'ShowEcommerceValue "value", FValue, True
      
      If AEventName = E_PURCHASE Then
        ShowEcommerceValue "transaction_id", FTransactionID, True
      End If      
      
      If AEventName = E_ADD_SHIPPING_INFO Or AEventName = E_ADD_PAYMENT_INFO Or AEventName = E_PURCHASE Then
        ShowEcommerceValue "value", FPurchaseValue, True
      Else      
        ShowEcommerceValue "value", EventValue(AEventName), True
      End If
      
      ' coupon for begin_checkout, add_shipping_info, add_payment_info, purchase
      If FDiscountCode <> "" And AEventName = E_BEGIN_CHECKOUT Or AEventName = E_ADD_SHIPPING_INFO Or AEventName = E_ADD_PAYMENT_INFO Or AEventName = E_PURCHASE Then
        ShowEcommerceValue "coupon", FDiscountCode, True
      End If
            
      '? to add payment info with payment type
      
      If AEventName = E_PURCHASE Then
        ShowEcommerceValue "shipping", FShipping, True      
        ShowEcommerceValue "tax", FPurchaseTax, True
      End If
    
      ShowEcommerceEventItemsStart    
      ShowEcommerceEventItems AEventName
      ShowEcommerceEventItemsEnd
      
      ShowEcommerceEventFooter
      
    End If
  End Sub
  
  ' (SS,23/10/23)
  ' (SS,10/11/23) finished off
  Private Sub DoEnchancedConversionData
    If FHasEnhancedConversionData Then
      ShowEcommerceEventHeader E_ENHANCED_CONVERSION
      SetDataIndentLevel 2
      ShowEcommerceValue "email", FEmail, True
      ShowEcommerceValue "first_name", FFirstName, True
      ShowEcommerceValue "last_name", FLastName, True
      ShowEcommerceValue "city", FCity, True
      ShowEcommerceValue "region", FRegion, True
      ShowEcommerceValue "postal_code", FPostcode, True
      ShowEcommerceValue "country", FCountryCode, False
      ShowEcommerceEventFooter
    End If    
  End Sub
  
  Public Sub DoGoogleTagManagerScript
    If Enabled Then
      ' (SS,15/1/24) added following to do the alternative Backona version instead of standard if enabled
      If FBackonaAnalyticsEnabled Then
        DoBackonaGTMScript
        Exit Sub
      Else
    ' (SS,24/10/23) added dataLayer = []; requested by James/Jimmy, even though it's not required because it's in the Google Tag Manager script below (not obvious), may take it out later
    ' (SS,27/02/24) removed at Backona's request that this was causing an issue with their settings.
'<script>
'dataLayer = [];
'</script>    
%>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','<%=FGTMContainerID%>');</script>
<!-- End Google Tag Manager -->
<%
      End If
    End If
  End Sub
  
  ' (SS,15/1/24) do the alternative Backona version
  Private Sub DoBackonaGTMScript
    Dim LDomain
    LDomain = FBackonaAnalyticsDomain
%>
<!-- Google Tag Manager - Backona Version -->
<script>
(function (w, d, s, l, i) {
  w[l] = w[l] || [];
  w[l].push({ "gtm.start": new Date().getTime(), event: "gtm.js" });
  var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != "dataLayer" ? "&l=" + l : "";
  j.async = true;
  if (window.alx === false) {
    fetch("https://www.googletagmanager.com/gtm.js?id=" + i, {mode: 'no-cors', credentials: 'same-origin'})
    .then(function(){
      j.src = "https://www.googletagmanager.com/gtm.js?id=" + i + dl;
    }).catch(function(){
      window.alx = true;
      j.src = "https://<%=FBackonaAnalyticsDomain%>/customer/1?id=" + i + dl;
  })
  } else {
  j.src = "https://<%=FBackonaAnalyticsDomain%>/customer/1?id=" + i + dl;
}
  f.parentNode.insertBefore(j, f);
  })(window, document, "script", "dataLayer", "<%=FGTMContainerID%>");
</script>
<!-- End Google Tag Manager - Backona Version -->
<%
  End Sub

  ' (SS,5/10/23) following called from HTMLBodyEnd adds recommended <noscript> GTM script for Javascript being disabled the Tag Assistant recommends it (otherwise I wouldn't have added it)
  Public Sub DoGoogleTagManagerNoScript
    If GTMEnabled Then
%>
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=<%=FGTMContainerID%>"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
<%
    End If
  End Sub
  
  
End Class


%>