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