Error executing template "Designs/Swift/Swift_Page.cshtml"
System.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)
---> System.ComponentModel.Win32Exception (2): The system cannot find the file specified.
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.Open()
at Dynamicweb.Data.DatabaseConnectionProvider.CreateConnection(Boolean open)
at Dynamicweb.Data.Database.CreateConnection()
at Dynamicweb.Data.Database.CreateDataReader(CommandBuilder commandBuilder, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout)
at Dynamicweb.Ecommerce.Products.ProductRepository.GetProductById(String productId, String productVariantId, String productLanguageId)
at Dynamicweb.Ecommerce.Products.ProductService.FetchMissingProductsInternal(IProductRepository repo, IEnumerable`1 keys)
at Dynamicweb.Caching.ServiceCache`2.GetCache(IEnumerable`1 keys)
at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId, User user, Boolean showUntranslated)
at Dynamicweb.Ecommerce.Frontend.UrlHandling.ProductUrlQueryStringProvider.TryResolveQueryString(NameValueCollection queryString, UrlNode& resolvedPath)
at Dynamicweb.Frontend.UrlHandling.UrlIndex.GetPathFromQueryString(String queryString)
at Dynamicweb.Frontend.SearchEngineFriendlyURLs.ResolveQueryString(String fullQueryString, Int32 pageid, String alternatekey)
at Dynamicweb.Frontend.PageView.ResolveSearchFriendlyUrl()
at Dynamicweb.Frontend.PageView.get_SearchFriendlyUrl()
at CompiledRazorTemplates.Dynamic.RazorEngine_75cde2c75af44648826b63b890029277.SetMetaTags()
at CompiledRazorTemplates.Dynamic.RazorEngine_75cde2c75af44648826b63b890029277.ExecuteAsync()
at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer)
at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
at Dynamicweb.Rendering.Template.RenderRazorTemplate()
ClientConnectionId:00000000-0000-0000-0000-000000000000
Error Number:2,State:0,Class:20
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel>
2 @using System
3 @using Dynamicweb
4 @using Dynamicweb.Environment
5 @using Dynamicweb.Frontend
6
7 @functions {
8 string GetCookieOptInPermission(string category)
9 {
10 bool categoryOrAllGranted = false;
11
12 if (CookieManager.IsCookieManagementActive)
13 {
14 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
15 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
16 categoryOrAllGranted = cookieOptInCategories.Contains(category) || cookieOptInLevel == CookieOptInLevel.All;
17 }
18
19 return categoryOrAllGranted ? "granted" : "denied";
20 }
21
22 bool AllowTracking()
23 {
24 bool allowTracking = true;
25 if (CookieManager.IsCookieManagementActive)
26 {
27 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
28 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
29
30 bool consentEither = (cookieOptInCategories.Contains("Statistical") || cookieOptInCategories.Contains("Marketing"));
31 bool consentFunctional = cookieOptInLevel == CookieOptInLevel.Functional;
32 bool consentAtLeastOne = cookieOptInLevel == CookieOptInLevel.All || (consentFunctional && consentEither);
33
34 allowTracking = consentAtLeastOne;
35 }
36 return allowTracking;
37 }
38 }
39
40 @{
41 var cartSummaryPageId = Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Model.Area.ID, "CartSummary")?.ID;
42 bool enableMiniCart = Model.Area.Item?.GetBoolean("EnableOffcanvasMiniCart") ?? false;
43 var offcanvasMiniCartBehaviour = Model.Area.Item?.GetRawValueString("OffcanvasMinicartBehaviour", "3") ?? "3";
44 bool miniCartEnabled = cartSummaryPageId != null && enableMiniCart;
45 var brandingPageId = Model.Area.Item?.GetInt32("BrandingPage") ?? 0;
46 var themePageId = Model.Area.Item?.GetInt32("ThemesPage") ?? 0;
47 var cssPageId = Model.Area.Item?.GetInt32("CssPage") ?? 0;
48 var brandingPage = brandingPageId != 0 ? Dynamicweb.Content.Services.Pages?.GetPage(brandingPageId) ?? null : null;
49 var themesParagraphs = themePageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(themePageId) ?? null : null;
50 var cssParagraphs = cssPageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(cssPageId) ?? null : null;
51 }
52
53 @if (themesParagraphs != null || brandingPage != null)
54 {
55 string swiftVersion = ReadFile("/Files/Templates/Designs/Swift/swift_version.txt");
56 bool renderAsResponsive = Model.Area.Item.GetString("DeviceRendering", "responsive").Equals("responsive", StringComparison.OrdinalIgnoreCase);
57 bool renderMobile = Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Mobile || Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Tablet;
58 string responsiveClassDesktop = string.Empty;
59 string responsiveClassMobile = string.Empty;
60 if (renderAsResponsive)
61 {
62 responsiveClassDesktop = " d-none d-xl-block";
63 responsiveClassMobile = " d-block d-xl-none";
64 }
65
66 var headerDesktopLink = Model.Area.Item?.GetLink("HeaderDesktop") ?? null;
67 var headerMobileLink = Model.Area.Item?.GetLink("HeaderMobile") ?? null;
68
69 var footerDesktopLink = Model.Area.Item?.GetLink("FooterDesktop") ?? null;
70 var footerMobileLink = Model.Area.Item?.GetLink("FooterMobile") ?? null;
71
72 var disableWideBreakpoints = Model.Area?.Item?.GetRawValueString("DisableWideBreakpoints", "default");
73
74 //string customHeaderInclude = !string.IsNullOrEmpty(Model.Area.Item.GetRawValueString("CustomHeaderInclude")) ? Model.Area.Item.GetFile("CustomHeaderInclude").Name : string.Empty;
75 string customHeaderInclude = !string.IsNullOrEmpty(Model.Area.Item.GetRawValueString("CustomHeaderInclude")) ? Model.Area.Item.GetRawValueString("CustomHeaderInclude").Split('/').Last() : string.Empty;
76
77
78 var themesParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(themePageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
79 var cssLastModified = brandingPage.Audit.LastModifiedAt > themesParagraphLastChanged.Audit.LastModifiedAt ? brandingPage.Audit.LastModifiedAt : themesParagraphLastChanged.Audit.LastModifiedAt;
80
81 var cssThemeAndBrandingStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css"));
82
83
84 if (cssPageId != 0)
85 {
86 var cssFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_css_styles_{Model.Area.ID}.css"));
87 var cssParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(cssPageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
88 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < cssParagraphLastChanged.Audit.LastModifiedAt)
89 {
90 var cssPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(cssPageId);
91 cssPageview.Redirect = false;
92 cssPageview.Output();
93 }
94 }
95
96 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < brandingPage.Audit.LastModifiedAt)
97 {
98 //Branding page has been saved or the file is missing. Rewrite the file to disc.
99 if (brandingPageId > 0)
100 {
101 var brandingPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(brandingPageId);
102 brandingPageview.Redirect = false;
103 brandingPageview.Output();
104 }
105 }
106
107 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < themesParagraphLastChanged.Audit.LastModifiedAt)
108 {
109 //Branding page has been saved or the file is missing. Rewrite the file to disc.
110 if (themePageId > 0)
111 {
112 var themePageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(themePageId);
113 themePageview.Redirect = false;
114 themePageview.Output();
115 }
116 }
117
118 // Schema.org details for PDP
119 bool isProductDetailsPage = Dynamicweb.Context.Current.Request.QueryString.AllKeys.Contains("ProductID");
120 bool isArticlePage = Model.ItemType == "Swift_Article";
121 string schemaOrgType = string.Empty;
122
123 if (isProductDetailsPage)
124 {
125 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Product\"";
126 }
127
128 if (isArticlePage)
129 {
130 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Article\"";
131 }
132
133
134 var cssStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/styles.css"));
135 var cssStyleFileInfoCustom = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/custom.css"));
136 var jsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/scripts.js"));
137 var jsFileInfoCustom = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/custom.js"));
138
139 string masterTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("Theme")) ? " theme " + Model.Area.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
140
141 string favicon = Model.Area.Item.GetRawValueString("Favicon", "/Files/Templates/Designs/Swift/Assets/Images/favicon.png");
142 string appleTouchIcon = Model.Area.Item.GetRawValueString("AppleTouchIcon", "/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon.png");
143
144 string headerCssClass = "sticky-top";
145 bool movePageBehind = false;
146
147 string customScript = "";
148
149
150 if (Model.PropertyItem != null)
151 {
152 customScript = Model.PropertyItem.GetRawValueString("CustomScript", "");
153
154 headerCssClass = Model.PropertyItem.GetRawValueString("MoveThisPageBehindTheHeader", "sticky-top");
155 movePageBehind = headerCssClass == "fixed-top" && !Pageview.IsVisualEditorMode ? true : false;
156 }
157
158 headerCssClass = headerCssClass == "" ? "sticky-top" : headerCssClass;
159 headerCssClass = Pageview.IsVisualEditorMode ? "" : headerCssClass;
160
161 string googleTagManagerID = Model.Area.Item.GetString("GoogleTagManagerID").Trim();
162 string googleAnalyticsMeasurementID = Model.Area.Item.GetString("GoogleAnalyticsMeasurementID").Trim();
163
164 bool allowTracking = AllowTracking();
165
166 string klaviyoID = Model.Area.Item.GetString("KlaviyoPublicKey");
167
168 string facebookPixel = Model.Area.Item.GetString("FacebookPixel");
169
170 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/styles.css?{cssStyleFileInfo.LastWriteTime.Ticks}>; rel=preload; as=style;");
171 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/custom.css?{cssStyleFileInfoCustom.LastWriteTime.Ticks}>; rel=preload; as=style;");
172 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css?{cssLastModified.Ticks}>; rel=preload; as=style;");
173 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/scripts.js?{jsFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;");
174 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/custom.js?{jsFileInfoCustom.LastWriteTime.Ticks}>; rel=preload; as=script;");
175
176
177 SetMetaTags();
178
179 List<Dynamicweb.Content.Page> languages = new List<Dynamicweb.Content.Page>();
180
181 var masterPage = Pageview.Area.IsMaster ? Pageview.Page : Pageview.Page.MasterPage;
182 languages.Add(masterPage);
183 if (masterPage?.Languages != null)
184 {
185 foreach (var language in masterPage.Languages)
186 {
187 languages.Add(language);
188 }
189 }
190
191 Uri url = Dynamicweb.Context.Current.Request.Url;
192 string hostName = url.Host;
193
194 <!doctype html>
195 <html lang="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName">
196 <head>
197 <!-- @swiftVersion -->
198 @* Required meta tags *@
199 <meta charset="utf-8">
200 <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0">
201 <link rel="shortcut icon" href="@favicon">
202 <link rel="apple-touch-icon" href="@appleTouchIcon">
203
204 @Model.MetaTags
205
206 @{
207 var alreadyWrittenTwoletterIsos = new List<string>();
208 @* Languages meta data *@
209 foreach (var language in languages)
210 {
211 hostName = url.Host;
212 if (language?.Area != null)
213 {
214 if (language.Area?.MasterArea != null && !string.IsNullOrEmpty(language.Area.MasterArea.DomainLock))
215 {
216 hostName = language.Area.MasterArea.DomainLock; //dk.domain.com or dk-domain.dk
217 }
218 if (language != null && language.Area != null && language.Published && language.Area.Active && language.Area.Published)
219 {
220 if (!string.IsNullOrEmpty(language.Area.DomainLock))
221 {
222 hostName = language.Area.DomainLock; //dk.domain.com or dk-domain.dk
223 }
224 string querystring = $"Default.aspx?ID={language.ID}";
225 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["GroupID"]))
226 {
227 querystring += $"&GroupID={Dynamicweb.Context.Current.Request.QueryString["GroupID"]}";
228 }
229 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"]))
230 {
231 querystring += $"&ProductID={Dynamicweb.Context.Current.Request.QueryString["ProductID"]}";
232 }
233 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["VariantID"]))
234 {
235 querystring += $"&VariantID={Dynamicweb.Context.Current.Request.QueryString["VariantID"]}";
236 }
237
238 string friendlyUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(querystring);
239 if (language.Area.RedirectFirstPage && language.ParentPageId == 0 && language.Sort == 1)
240 {
241 friendlyUrl = "/";
242 }
243 string href = $"{url.Scheme}://{hostName}{friendlyUrl}";
244
245
246 <link rel="alternate" hreflang="@language.Area.CultureInfo.Name.ToLower()" href="@href">
247 if (!alreadyWrittenTwoletterIsos.Contains(language.Area.CultureInfo.TwoLetterISOLanguageName))
248 {
249 alreadyWrittenTwoletterIsos.Add(language.Area.CultureInfo.TwoLetterISOLanguageName);
250 <link rel="alternate" hreflang="@language.Area.CultureInfo.TwoLetterISOLanguageName.ToLower()" href="@href">
251 }
252 }
253 }
254 }
255 }
256
257 <title>@Model.Title</title>
258 @* Bootstrap + Swift stylesheet *@
259 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css">
260 <link href="/Files/Templates/Designs/Swift/Assets/css/custom.css?@cssStyleFileInfoCustom.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css">
261
262 @if (disableWideBreakpoints != "disableBoth")
263 {
264 <style>
265 @@media ( min-width: 1600px ) {
266 .container-xxl,
267 .container-xl,
268 .container-lg,
269 .container-md,
270 .container-sm,
271 .container {
272 max-width: 1520px;
273 }
274 }
275 </style>
276
277
278
279 if (disableWideBreakpoints != "disableUltraWideOnly")
280 {
281 <style>
282 @@media ( min-width: 1920px ) {
283 .container-xxl,
284 .container-xl,
285 .container-lg,
286 .container-md,
287 .container-sm,
288 .container {
289 max-width: 1820px;
290 }
291 }
292 </style>
293 }
294 }
295
296 @* Branding and Themes min stylesheet *@
297 <link href="/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_@(Model.Area.ID).min.css?@cssLastModified.Ticks" rel="stylesheet" media="all" type="text/css" data-last-modified-content="@cssLastModified">
298 <script src="/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks"></script>
299 <script src="/Files/Templates/Designs/Swift/Assets/js/custom.js?@jsFileInfoCustom.LastWriteTime.Ticks"></script>
300 <script type="module">
301 swift.Scroll.hideHeadersOnScroll();
302 swift.Scroll.handleAlternativeTheme();
303
304 //Only load if AOS
305 const aosColumns = document.querySelectorAll('[data-aos]');
306 if (aosColumns.length > 0) {
307 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/js/aos.js?@jsFileInfo.LastWriteTime.Ticks', 'js');
308 document.addEventListener('load.swift.assetloader', function () {
309 AOS.init({ duration: 400, delay: 100, easing: 'ease-in-out', mirror: false, disable: window.matchMedia('(prefers-reduced-motion: reduce)') });
310 });
311 }
312 </script>
313
314 @* Google gtag method - always include even if it is not used for anything *@
315 <script>
316 window.dataLayer = window.dataLayer || [];
317 function gtag() { dataLayer.push(arguments); }
318 </script>
319 @* Google tag manager *@
320 @if (!string.IsNullOrWhiteSpace(googleTagManagerID))
321 {
322 @*<script>
323 gtag('consent', 'default', {
324 'ad_storage': 'denied',
325 'ad_user_data': 'denied',
326 'ad_personalization': 'denied',
327 'analytics_storage': 'denied'
328 });
329 </script>*@
330 <script>
331 (function (w, d, s, l, i) {
332 w[l] = w[l] || []; w[l].push({
333 'gtm.start':
334 new Date().getTime(), event: 'gtm.js'
335 }); var f = d.getElementsByTagName(s)[0],
336 j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src =
337 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f);
338 })(window, document, 'script', 'dataLayer', '@(googleTagManagerID)');
339 </script>
340 if (allowTracking)
341 {
342 string adConsent = GetCookieOptInPermission("Marketing");
343 string analyticsConsent = GetCookieOptInPermission("Statistical");
344 @*<script>
345 gtag('consent', 'update', {
346 'ad_storage': '@adConsent',
347 'ad_user_data': '@adConsent',
348 'ad_personalization': '@adConsent',
349 'analytics_storage': '@analyticsConsent'
350 });
351 </script>*@
352
353
354 }
355 }
356
357 @if (!string.IsNullOrWhiteSpace(facebookPixel) && allowTracking && GetCookieOptInPermission("Marketing") == "granted")
358 {
359 <!-- Facebook Pixel Code -->
360 <script>
361 !function(f,b,e,v,n,t,s)
362 {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
363 n.callMethod.apply(n,arguments):n.queue.push(arguments)};
364 if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
365 n.queue=[];t=b.createElement(e);t.async=!0;
366 t.src=v;s=b.getElementsByTagName(e)[0];
367 s.parentNode.insertBefore(t,s)}(window, document,'script',
368 'https://connect.facebook.net/en_US/fbevents.js');
369 fbq('init', '@(facebookPixel)');
370 fbq('track', 'PageView');
371 </script>
372 <noscript>
373 <img height="1" width="1" style="display:none"
374 src="https://www.facebook.com/tr?id=@(facebookPixel)&ev=PageView&noscript=1"/>
375 </noscript>
376 <!-- End Facebook Pixel Code -->
377
378 }
379
380
381
382 @if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking)
383 {
384 var GoogleAnalyticsDebugMode = "";
385
386 if (Model.Area.Item.GetBoolean("EnableGoogleAnalyticsDebugMode"))
387 {
388 GoogleAnalyticsDebugMode = ", {'debug_mode': true}";
389 }
390
391 <script async src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsMeasurementID"></script>
392 <script>
393 gtag('js', new Date());
394 gtag('config', '@googleAnalyticsMeasurementID'@GoogleAnalyticsDebugMode);
395 </script>
396 }
397
398 @if (!string.IsNullOrWhiteSpace(klaviyoID)){
399 <script type="text/javascript" async="" src="https://static.klaviyo.com/onsite/js/klaviyo.js?company_id=@(klaviyoID)"></script>
400
401 <script>
402 !function(){if(!window.klaviyo){window._klOnsite=window._klOnsite||[];try{window.klaviyo=new Proxy({},{get:function(n,i){return"push"===i?function(){var n;(n=window._klOnsite).push.apply(n,arguments)}:function(){for(var n=arguments.length,o=new Array(n),w=0;w<n;w++)o[w]=arguments[w];var t="function"==typeof o[o.length-1]?o.pop():void 0,e=new Promise((function(n){window._klOnsite.push([i].concat(o,[function(i){t&&t(i),n(i)}]))}));return e}}})}catch(n){window.klaviyo=window.klaviyo||[],window.klaviyo.push=function(){var n;(n=window._klOnsite).push.apply(n,arguments)}}}}();
403 </script>
404
405 if (Pageview?.User?.ID != null){
406
407 string userEmail = Dynamicweb.Core.Converter.ToString(Pageview.User?.Email);
408 string userName = Dynamicweb.Core.Converter.ToString(Pageview.User?.Name);
409
410 <script>
411 klaviyo.identify({
412 '$email' : '@(userEmail)',
413 '$first_name' : '@(userName)'
414 });
415 </script>
416
417 }
418 }
419
420 @if (!string.IsNullOrWhiteSpace(customScript)){
421 @(customScript)
422 }
423
424 @if (!string.IsNullOrWhiteSpace(customHeaderInclude))
425 {
426 @RenderPartial($"Components/Custom/{customHeaderInclude}")
427 }
428 </head>
429 <body class="brand @(masterTheme)" id="page@(Model.ID)">
430
431 @* Google tag manager *@
432 @if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking)
433 {
434 <noscript>
435 <iframe src="https://www.googletagmanager.com/ns.html?id=@(googleTagManagerID)"
436 height="0" width="0" style="display:none;visibility:hidden"></iframe>
437 </noscript>
438 }
439
440 @if (renderAsResponsive || !renderMobile)
441 {
442 <header class="page-header @headerCssClass top-0@(responsiveClassDesktop)" id="page-header-desktop">
443 @if (headerDesktopLink != null)
444 {
445 @RenderGrid(headerDesktopLink.PageId)
446 }
447 </header>
448 }
449
450 @if ((renderAsResponsive || renderMobile))
451 {
452 <header class="page-header @headerCssClass top-0@(responsiveClassMobile)" id="page-header-mobile">
453 @if (headerMobileLink != null)
454 {
455 @RenderGrid(headerMobileLink.PageId)
456 }
457 </header>
458 }
459
460 <div data-intersect></div>
461
462 <main id="content" @(schemaOrgType)>
463 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel>
464 @using System
465 @using Dynamicweb.Ecommerce.ProductCatalog
466
467
468 @{
469 string productIdFromUrl = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : string.Empty;
470 bool isProductDetail = !string.IsNullOrEmpty(productIdFromUrl) && Pageview.Page.NavigationTag.ToLower() == "shop";
471
472 bool isArticlePagePage = Model.ItemType == "Swift_Article";
473 bool isArticleListPage = Model.ItemType == "Swift_ArticleListPage";
474 string schemaOrgProp = string.Empty;
475 if(isArticlePagePage)
476 {
477 schemaOrgProp = "itemprop=\"articleBody\"";
478 }
479
480 string theme = "";
481 string gridContent = "";
482
483 if (Model.PropertyItem != null)
484 {
485 theme = !string.IsNullOrWhiteSpace(Model.PropertyItem.GetRawValueString("Theme")) ? "theme " + Model.PropertyItem.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
486 }
487
488 if (Model.Item != null || Pageview.IsVisualEditorMode)
489 {
490 if (!isProductDetail)
491 {
492 gridContent = Model.Grid("Grid", "Grid", "default:true;sort:1", "Page");
493 }
494 else
495 {
496 var productObject = Dynamicweb.Ecommerce.Services.Products.GetProductById(productIdFromUrl, "", Pageview.Area.EcomLanguageId);
497 var detailPage = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(productObject.PrimaryGroupId)?.Meta.PrimaryPage ?? string.Empty;
498 var detailPageId = detailPage != string.Empty ? Convert.ToInt16(detailPage.Substring(detailPage.LastIndexOf('=') + 1)) : GetPageIdByNavigationTag("ProductDetailPage");
499
500 @RenderGrid(detailPageId)
501 }
502 }
503
504 bool doNotRenderPage = false;
505
506 //Check if we are on the poduct detail page, and if there is data to render
507 ProductViewModel product = new ProductViewModel();
508 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
509 {
510 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
511 if (string.IsNullOrEmpty(product.Id)) {
512 doNotRenderPage = true;
513 }
514 }
515
516 //Render the page
517 if (!doNotRenderPage) {
518 string itemIdentifier = Model?.Item?.SystemName != null ? "item_" + Model.Item.SystemName.ToLower() : "item_Swift_Page";
519
520 if (Pageview.IsVisualEditorMode) {
521 @Model.Placeholder("dwcontent", "content", "default:true;sort:1")
522 }
523
524 <div class="@theme @itemIdentifier" @schemaOrgProp>
525 @if (isArticleListPage)
526 {
527 var hx = $"hx-get=\"{Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(Model.ID)}\" hx-select=\"#content\" hx-target=\"#content\" hx-swap=\"outerHTML\" hx-trigger=\"change\" hx-headers='{{\"feed\": \"true\"}}' hx-push-url=\"true\" hx-indicator=\"#ArticleFacetForm\"";
528
529 <form @hx id="ArticleFacetForm">
530 @gridContent
531 </form>
532 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/htmx.js"></script>
533 <script type="module">
534 document.addEventListener('htmx:confirm', (event) => {
535 let filters = event.detail.elt.querySelectorAll('select');
536 for (var i = 0; i < filters.length; i++) {
537 let input = filters[i];
538 if (input.name && !input.value) {
539 input.name = '';
540 }
541 }
542 });
543
544 document.addEventListener('htmx:beforeOnLoad', (event) => {
545 swift.Scroll.stopIntersectionObserver();
546 });
547
548 document.addEventListener('htmx:afterOnLoad', () => {
549 swift.Scroll.hideHeadersOnScroll();
550 swift.Scroll.handleAlternativeTheme();
551 });
552 </script>
553 }
554 else
555 {
556 @gridContent
557 }
558 </div>
559
560 } else {
561 <div class="container">
562 <div class="alert alert-info" role="alert">@Translate("Sorry. There is nothing to view here")</div>
563 </div>
564 }
565
566 if (!Model.IsCurrentUserAllowed)
567 {
568 int signInPage = GetPageIdByNavigationTag("SignInPage");
569 int dashboardPage = GetPageIdByNavigationTag("MyAccountDashboardPage");
570
571 if (!Pageview.IsVisualEditorMode)
572 {
573 if (signInPage != 0)
574 {
575 if (signInPage != Model.ID) {
576 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + signInPage);
577 } else {
578 if (dashboardPage != 0) {
579 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + dashboardPage);
580 } else {
581 Dynamicweb.Context.Current.Response.Redirect("/");
582 }
583 }
584 }
585 else
586 {
587 <div class="alert alert-dark m-0" role="alert">
588 <span>@Translate("You do not have access to this page")</span>
589 </div>
590 }
591 }
592 else
593 {
594 <div class="alert alert-dark m-0" role="alert">
595 <span>@Translate("To work on this page, you must be signed in, in the frontend")</span>
596 </div>
597 }
598 }
599 }
600
601 <script>
602 // Listen for the event.
603
604 function delay(time) {
605 return new Promise(resolve => setTimeout(resolve, time));
606 }
607
608 function runKlaviyo(){
609 let scr = document.createElement('script');
610 let el = document.getElementById("AddedToCart");
611 scr.setAttribute("id", "tempAddedToCart");
612 scr.innerHTML = el.innerHTML;
613 document.body.appendChild(scr);
614 document.getElementById("tempAddedToCart").outerHTML = "";
615 }
616
617 document.addEventListener(
618 "updated.swift.cart",
619 (e) => {
620 delay(200).then(() => runKlaviyo());
621 },
622 false,
623 );
624
625 </script>
626 </main>
627
628 @if (renderAsResponsive || !renderMobile)
629 {
630 <footer class="page-footer@(responsiveClassDesktop)" id="page-footer-desktop">
631 @if (footerDesktopLink != null)
632 {
633 @RenderGrid(footerDesktopLink.PageId)
634 }
635 </footer>
636 }
637
638 @if (renderAsResponsive || renderMobile)
639 {
640 <footer class="page-footer@(responsiveClassMobile)" id="page-footer-mobile">
641 @if (footerMobileLink != null)
642 {
643 @RenderGrid(footerMobileLink.PageId)
644 }
645 </footer>
646 }
647
648 @* Render any offcanvas menu here *@
649 @RenderSnippet("offcanvas")
650
651 @{
652 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]);
653 }
654
655 @* Language selector modal *@
656 <div class="modal fade" id="PreferencesModal" tabindex="-1" aria-hidden="true">
657 <div class="modal-dialog modal-dialog-centered modal-sm" id="PreferencesModalContent">
658 @* The content here comes from an external request *@
659 </div>
660 </div>
661
662 @* Favorite toast *@
663 <div aria-live="polite" aria-atomic="true">
664 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11">
665 <div id="favoriteNotificationToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
666 <div class="toast-header">
667 <strong class="me-auto">@Translate("Favorite list updated")</strong>
668 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
669 </div>
670 <div class="toast-body d-flex gap-3">
671 <div id="favoriteNotificationToast_Image"></div>
672 <div id="favoriteNotificationToast_Text"></div>
673 </div>
674 </div>
675 </div>
676 </div>
677
678 @* Modal for dynamic content *@
679 <div class="modal fade js-product" id="DynamicModal" tabindex="-1" aria-hidden="true">
680 <div class="modal-dialog modal-dialog-centered modal-md">
681 <div class="modal-content theme light" id="DynamicModalContent">
682 @* The content here comes from an external request *@
683 </div>
684 </div>
685 </div>
686
687 @* Offcanvas for dynamic content *@
688 <div class="offcanvas offcanvas-end theme light" tabindex="-1" id="DynamicOffcanvas">
689 @* The content here comes from an external request *@
690 </div>
691
692 @if (Model.Area.Item.GetBoolean("ShowErpDownMessage") && !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]))
693 {
694 string erpDownMessageTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("ErpDownMessageTheme")) ? " theme " + Model.Area.Item.GetRawValueString("ErpDownMessageTheme").Replace(" ", "").Trim().ToLower() : "theme light";
695
696 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1040">
697 <div class="toast fade show border-0 @erpDownMessageTheme" role="alert" aria-live="assertive" aria-atomic="true">
698 <div class="toast-header">
699 <strong class="me-auto">@Translate("Connection down")</strong>
700 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
701 </div>
702 <div class="toast-body">
703 @Translate("We are experiencing some connectivity issues. Not all features may be available to you.")
704 </div>
705 </div>
706 </div>
707 }
708
709 @if (miniCartEnabled)
710 {
711 @* Open MiniCart when the cart is updated *@
712 <script type="module">
713 document.addEventListener('updated.swift.cart', (event) => {
714 let orderContext = event?.detail?.formData?.get("OrderContext");
715 updateCartSummary(orderContext);
716
717 @if (offcanvasMiniCartBehaviour == "2" || offcanvasMiniCartBehaviour == "3") {
718 <text>openMiniCartOffcanvas();</text>
719 }
720 });
721 </script>
722
723 if (offcanvasMiniCartBehaviour == "1" || offcanvasMiniCartBehaviour == "3")
724 {
725 @* Open MiniCart when toggle is clicked *@
726 <script type="module">
727 let miniCartToggles = document.querySelectorAll('.mini-cart-quantity');
728 miniCartToggles?.forEach((toggle) => {
729 toggle.parentElement.addEventListener('click', (event) => {
730 event.preventDefault();
731 let orderContext = toggle.dataset?.orderContext;
732 updateCartSummary(orderContext);
733
734 openMiniCartOffcanvas();
735 });
736 });
737 </script>
738 }
739
740 <script>
741
742 const updateCartSummary = (orderContext) => {
743 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas');
744 swift.PageUpdater.UpdateFromUrlInline(event, '/Default.aspx?ID=@(cartSummaryPageId)&CartType=minicart&RequestPageID=@(Pageview.Page.ID)&OrderContext=' + orderContext +'', 'Swift_CartSummary.cshtml', dynamicOffcanvas);
745 };
746
747 const openMiniCartOffcanvas = () => {
748 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas');
749 const miniCartOffcanvas = bootstrap.Offcanvas.getOrCreateInstance(dynamicOffcanvas);
750 dynamicOffcanvas.classList.add('overflow-y-auto');
751
752 if (!miniCartOffcanvas._isShown) {
753 miniCartOffcanvas.show();
754 hideActiveOffcanvases(miniCartOffcanvas);
755 }
756 };
757
758 const hideActiveOffcanvases = (miniCartOffcanvas) => {
759 let activeOffcanvases = document.querySelectorAll('.offcanvas.show');
760 activeOffcanvases?.forEach((offCanvas) => {
761 offCanvas = bootstrap.Offcanvas.getInstance(offCanvas);
762 if (offCanvas !== miniCartOffcanvas) {
763 offCanvas.hide();
764 }
765 });
766 };
767
768 </script>
769 }
770
771 </body>
772
773 </html>
774
775 }
776 else if (Pageview.IsVisualEditorMode)
777 {
778 <head>
779 <title>@Model.Title</title>
780 @* Bootstrap + Swift stylesheet *@
781 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css" rel="stylesheet" media="all" type="text/css">
782 </head>
783 <body class="p-3">
784 <div class="alert alert-danger" role="alert">
785 @Translate("Basic Swift setup is needed!")
786 </div>
787
788 @if (brandingPage == null)
789 {
790 <div class="alert alert-warning" role="alert">
791 @Translate("Please add a Branding page and reference it in website settings")
792 </div>
793 }
794
795 @if (themesParagraphs == null)
796 {
797 <div class="alert alert-warning" role="alert">
798 @Translate("Please add a Themes collection page and reference it in website settings")
799 </div>
800 }
801 </body>
802 }
803
804
805 @functions {
806 void SetMetaTags()
807 {
808 //Verification Tokens
809 string siteVerificationGoogle = Model.Area.Item.GetString("Google_Site_Verification") != null ? Model.Area.Item.GetString("Google_Site_Verification") : "";
810
811 //Generic Site Values
812 string openGraphFacebookAppID = Model.Area.Item.GetString("Fb_app_id") != null ? Model.Area.Item.GetString("Fb_app_id") : "";
813 string openGraphType = Model.Area.Item.GetString("Open_Graph_Type") != null ? Model.Area.Item.GetString("Open_Graph_Type") : "";
814 string openGraphSiteName = Model.Area.Item.GetString("Open_Graph_Site_Name") != null ? Model.Area.Item.GetString("Open_Graph_Site_Name") : "";
815
816 string twitterCardSite = Model.Area.Item.GetString("Twitter_Site") != null ? Model.Area.Item.GetString("Twitter_Site") : "";
817
818 //Page specific values
819 string openGraphSiteTitle = Model.Area.Item.GetString("Open_Graph_Title") != null ? Model.Area.Item.GetString("Open_Graph_Title") : "";
820 FileViewModel openGraphImage = Model.Area.Item.GetFile("Open_Graph_Image");
821 string openGraphImageALT = Model.Area.Item.GetString("Open_Graph_Image_ALT") != null ? Model.Area.Item.GetString("Open_Graph_Image_ALT") : "";
822 string openGraphDescription = Model.Area.Item.GetString("Open_Graph_Description") != null ? Model.Area.Item.GetString("Open_Graph_Description") : "";
823
824 string twitterCardURL = Model.Area.Item.GetString("Twitter_URL") != null ? Model.Area.Item.GetString("Twitter_URL") : "";
825 string twitterCardTitle = Model.Area.Item.GetString("Twitter_Title") != null ? Model.Area.Item.GetString("Twitter_Title") : "";
826 string twitterCardDescription = Model.Area.Item.GetString("Twitter_Description") != null ? Model.Area.Item.GetString("Twitter_Description") : "";
827 FileViewModel twitterCardImage = Model.Area.Item.GetFile("Twitter_Image");
828 string twitterCardImageALT = Model.Area.Item.GetString("Twitter_Image_ALT") != null ? Model.Area.Item.GetString("Twitter_Image_ALT") : "";
829 string topImage = Pageview.Page.TopImage.StartsWith("/Files", StringComparison.OrdinalIgnoreCase) ? Pageview.Page.TopImage : $"/Files{Pageview.Page.TopImage}";
830
831
832
833 if (string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"]))
834 {
835 if (!string.IsNullOrEmpty(Model.Description))
836 {
837 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{Model.Description}\">");
838 }
839 else
840 {
841 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{openGraphDescription}\">");
842 }
843
844 if (!string.IsNullOrEmpty(Pageview.Page.TopImage))
845 {
846 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">");
847 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">");
848 }
849 else if (openGraphImage != null)
850 {
851 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">");
852 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">");
853 }
854
855 if (!string.IsNullOrEmpty(openGraphImageALT))
856 {
857 Pageview.Meta.AddTag($"<meta property=\"og:image:alt\" content=\"{openGraphImageALT}\">");
858 }
859 if (!string.IsNullOrEmpty(twitterCardDescription))
860 {
861 Pageview.Meta.AddTag("twitter:description", twitterCardDescription);
862 }
863
864 if (!string.IsNullOrEmpty(Pageview.Page.TopImage))
865 {
866 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}");
867 }
868 else if (twitterCardImage != null)
869 {
870 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}");
871 }
872
873 if (!string.IsNullOrEmpty(twitterCardImageALT))
874 {
875 Pageview.Meta.AddTag("twitter:image:alt", twitterCardImageALT);
876 }
877 }
878
879 if (!string.IsNullOrEmpty(siteVerificationGoogle))
880 {
881 Pageview.Meta.AddTag("google-site-verification", siteVerificationGoogle);
882 }
883
884 if (!string.IsNullOrEmpty(openGraphFacebookAppID))
885 {
886 Pageview.Meta.AddTag($"<meta property=\"fb:app_id\" content=\"{openGraphFacebookAppID}\">");
887 }
888
889 if (!string.IsNullOrEmpty(openGraphType))
890 {
891 Pageview.Meta.AddTag($"<meta property=\"og:type\" content=\"{openGraphType}\">");
892 }
893
894 <!-- test System.Web.HttpContext.Current.Request.QueryString["ProductID"] Dynamicweb.Environment.IRequest.QueryString("ProductID") -->
895
896
897 if (!string.IsNullOrEmpty(openGraphSiteName))
898 {
899 Pageview.Meta.AddTag($"<meta property=\"og:url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{Pageview.SearchFriendlyUrl}\">");
900 }
901
902 if (!string.IsNullOrEmpty(openGraphSiteName))
903 {
904 Pageview.Meta.AddTag($"<meta property=\"og:site_name\" content=\"{openGraphSiteName}\">");
905 }
906
907 if (!string.IsNullOrEmpty(Model.Title))
908 {
909 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{Model.Title}\">");
910 }
911 else
912 {
913 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{openGraphSiteTitle}\">");
914 }
915
916 if (!string.IsNullOrEmpty(twitterCardSite))
917 {
918 Pageview.Meta.AddTag("twitter:site", twitterCardSite);
919 }
920
921 if (!string.IsNullOrEmpty(twitterCardURL))
922 {
923 Pageview.Meta.AddTag("twitter:url", twitterCardURL);
924 }
925
926 if (!string.IsNullOrEmpty(twitterCardTitle))
927 {
928 Pageview.Meta.AddTag("twitter:title", twitterCardTitle);
929 }
930 }
931 }
932