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