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_c2baace2fe09498488ce3650a8687030.Execute() in D:\dynamicweb.net\Solutions\Dynamicweb\hctswift.cloud.dynamicweb-cms.com\files\Templates\Designs\Swift\_parsed\Swift_Page.parsed.cshtml:line 454
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 7 8 @functions {
9 string GetCookieOptInPermission(string category)
10 {
11 bool categoryOrAllGranted = false;
12 13 if (CookieManager.IsCookieManagementActive)
14 {
15 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
16 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
17 categoryOrAllGranted = cookieOptInCategories.Contains(category) || cookieOptInLevel == CookieOptInLevel.All;
18 }
19 20 return categoryOrAllGranted ? "granted" : "denied";
21 }
22 23 bool AllowTracking()
24 {
25 bool allowTracking = true;
26 if (CookieManager.IsCookieManagementActive)
27 {
28 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
29 var cookieOptInCategories = CookieManager.GetCookieOptInCategories();
30 31 bool consentEither = (cookieOptInCategories.Contains("Statistical") || cookieOptInCategories.Contains("Marketing"));
32 bool consentFunctional = cookieOptInLevel == CookieOptInLevel.Functional;
33 bool consentAtLeastOne = cookieOptInLevel == CookieOptInLevel.All || (consentFunctional && consentEither);
34 35 allowTracking = consentAtLeastOne;
36 }
37 return allowTracking;
38 }
39 }
40 41 @{
42 var cartSummaryPageId = Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Model.Area.ID, "CartSummary")?.ID;
43 bool enableMiniCart = Model.Area.Item?.GetBoolean("EnableOffcanvasMiniCart") ?? false;
44 var offcanvasMiniCartBehaviour = Model.Area.Item?.GetRawValueString("OffcanvasMinicartBehaviour", "3") ?? "3";
45 bool miniCartEnabled = cartSummaryPageId != null && enableMiniCart;
46 var brandingPageId = Model.Area.Item?.GetInt32("BrandingPage") ?? 0;
47 var themePageId = Model.Area.Item?.GetInt32("ThemesPage") ?? 0;
48 var cssPageId = Model.Area.Item?.GetInt32("CssPage") ?? 0;
49 var brandingPage = brandingPageId != 0 ? Dynamicweb.Content.Services.Pages?.GetPage(brandingPageId) ?? null : null;
50 var themesParagraphs = themePageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(themePageId) ?? null : null;
51 var cssParagraphs = cssPageId != 0 ? Dynamicweb.Content.Services.Paragraphs?.GetParagraphsByPageId(cssPageId) ?? null : null;
52 var customFooterScripts = Model.Area.Item?.GetRawValueString("FooterScripts", "") ?? "";
53 var scriptsHeader = Model.Area.Item?.GetRawValueString("ScriptsHeader", "") ?? "";
54 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 var themesParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(themePageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
81 var cssLastModified = brandingPage.Audit.LastModifiedAt > themesParagraphLastChanged.Audit.LastModifiedAt ? brandingPage.Audit.LastModifiedAt : themesParagraphLastChanged.Audit.LastModifiedAt;
82 83 var cssThemeAndBrandingStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_styles_{Model.Area.ID}.min.css"));
84 85 86 if (cssPageId != 0)
87 {
88 var cssFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath($"/Files/Templates/Designs/Swift/_parsed/Swift_css/Swift_css_styles_{Model.Area.ID}.css"));
89 var cssParagraphLastChanged = Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(cssPageId).OrderByDescending(p => p.Audit.LastModifiedAt).FirstOrDefault();
90 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < cssParagraphLastChanged.Audit.LastModifiedAt)
91 {
92 var cssPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(cssPageId);
93 cssPageview.Redirect = false;
94 cssPageview.Output();
95 }
96 }
97 98 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < brandingPage.Audit.LastModifiedAt)
99 {
100 //Branding page has been saved or the file is missing. Rewrite the file to disc.
101 if (brandingPageId > 0)
102 {
103 var brandingPageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(brandingPageId);
104 brandingPageview.Redirect = false;
105 brandingPageview.Output();
106 }
107 }
108109 if (!cssThemeAndBrandingStyleFileInfo.Exists || cssThemeAndBrandingStyleFileInfo.LastWriteTime < themesParagraphLastChanged.Audit.LastModifiedAt)
110 {
111 //Branding page has been saved or the file is missing. Rewrite the file to disc.
112 if (themePageId > 0)
113 {
114 var themePageview = Dynamicweb.Frontend.PageView.GetPageviewByPageID(themePageId);
115 themePageview.Redirect = false;
116 themePageview.Output();
117 }
118 }
119120 // Schema.org details for PDP
121 bool isProductDetailsPage = Dynamicweb.Context.Current.Request.QueryString.AllKeys.Contains("ProductID");
122 bool isArticlePage = Model.ItemType == "Swift_Article";
123 string schemaOrgType = string.Empty;
124125 if (isProductDetailsPage)
126 {
127 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Product\"";
128 }
129130 if (isArticlePage)
131 {
132 schemaOrgType = "itemscope=\"\" itemtype=\"https://schema.org/Article\"";
133 }
134135136 var cssStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/styles.css"));
137 var cssStyleFileInfoCustom = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/custom.css"));
138 var jsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/scripts.js"));
139140 string masterTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("Theme")) ? " theme " + Model.Area.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
141142 string favicon = Model.Area.Item.GetRawValueString("Favicon", "/Files/Templates/Designs/Swift/Assets/Images/favicon.png");
143 string appleTouchIcon = Model.Area.Item.GetRawValueString("AppleTouchIcon", "/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon.png");
144145 string headerCssClass = "sticky-top";
146 bool movePageBehind = false;
147148 if (Model.PropertyItem != null)
149 {
150 headerCssClass = Model.PropertyItem.GetRawValueString("MoveThisPageBehindTheHeader", "sticky-top");
151 movePageBehind = headerCssClass == "fixed-top" && !Pageview.IsVisualEditorMode ? true : false;
152 }
153154 headerCssClass = headerCssClass == "" ? "sticky-top" : headerCssClass;
155 headerCssClass = Pageview.IsVisualEditorMode ? "" : headerCssClass;
156157 string googleTagManagerID = Model.Area.Item.GetString("GoogleTagManagerID").Trim();
158 string googleAnalyticsMeasurementID = Model.Area.Item.GetString("GoogleAnalyticsMeasurementID").Trim();
159 string userCentrics = Model.Area.Item.GetString("UsercentricsScript");
160 bool allowTracking = true;
161162 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/styles.css?{cssStyleFileInfo.LastWriteTime.Ticks}>; rel=preload; as=style;");
163 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/custom.css?{cssStyleFileInfoCustom.LastWriteTime.Ticks}>; rel=preload; as=style;");
164 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;");
165 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/scripts.js?{jsFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;");
166167168 SetMetaTags();
169170 List<Dynamicweb.Content.Page> languages = new List<Dynamicweb.Content.Page>();
171172 var masterPage = Pageview.Area.IsMaster ? Pageview.Page : Pageview.Page.MasterPage;
173 languages.Add(masterPage);
174 if (masterPage?.Languages != null)
175 {
176 foreach (var language in masterPage.Languages)
177 {
178 languages.Add(language);
179 }
180 }
181182 Uri url = Dynamicweb.Context.Current.Request.Url;
183 string hostName = url.Host;
184185 <!doctype html>
186 <html lang="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName">
187 <head>
188 <!-- @swiftVersion -->
189 @* Required meta tags *@
190 <meta charset="utf-8">
191 <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0">
192 <link rel="shortcut icon" href="@favicon">
193 <link rel="apple-touch-icon" href="@appleTouchIcon">
194195 @Model.MetaTags
196197 @{
198 var alreadyWrittenTwoletterIsos = new List<string>();
199 @* Languages meta data *@
200 foreach (var language in languages)
201 {
202 hostName = url.Host;
203 if (language?.Area != null)
204 {
205 if (language.Area?.MasterArea != null && !string.IsNullOrEmpty(language.Area.MasterArea.DomainLock))
206 {
207 hostName = language.Area.MasterArea.DomainLock; //dk.domain.com or dk-domain.dk
208 }
209 if (language != null && language.Area != null && language.Published && language.Area.Active && language.Area.Published)
210 {
211 if (!string.IsNullOrEmpty(language.Area.DomainLock))
212 {
213 hostName = language.Area.DomainLock; //dk.domain.com or dk-domain.dk
214 }
215 string querystring = $"Default.aspx?ID={language.ID}";
216 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["GroupID"]))
217 {
218 querystring += $"&GroupID={Dynamicweb.Context.Current.Request.QueryString["GroupID"]}";
219 }
220 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"]))
221 {
222 querystring += $"&ProductID={Dynamicweb.Context.Current.Request.QueryString["ProductID"]}";
223 }
224 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["VariantID"]))
225 {
226 querystring += $"&VariantID={Dynamicweb.Context.Current.Request.QueryString["VariantID"]}";
227 }
228229 string friendlyUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(querystring);
230 if (language.Area.RedirectFirstPage && language.ParentPageId == 0 && language.Sort == 1)
231 {
232 friendlyUrl = "/";
233 }
234 string href = $"{url.Scheme}://{hostName}{friendlyUrl}";
235236237 <link rel="alternate" hreflang="@language.Area.CultureInfo.Name.ToLower()" href="@href">
238 if (!alreadyWrittenTwoletterIsos.Contains(language.Area.CultureInfo.TwoLetterISOLanguageName))
239 {
240 alreadyWrittenTwoletterIsos.Add(language.Area.CultureInfo.TwoLetterISOLanguageName);
241 <link rel="alternate" hreflang="@language.Area.CultureInfo.TwoLetterISOLanguageName.ToLower()" href="@href">
242 }
243 }
244 }
245 }
246 }
247248 <title>@Model.Title</title>
249 @* Bootstrap + Swift stylesheet *@
250 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css">
251 <link href="/Files/Templates/Designs/Swift/Assets/css/custom.css?@cssStyleFileInfoCustom.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css">
252253 @if (disableWideBreakpoints != "disableBoth")
254 {
255 <style>
256 @@media ( min-width: 1600px ) {
257 .container-xxl,
258 .container-xl,
259 .container-lg,
260 .container-md,
261 .container-sm,
262 .container {
263 max-width: 1520px;
264 }
265 }
266 </style>
267268269270 if (disableWideBreakpoints != "disableUltraWideOnly")
271 {
272 <style>
273 @@media ( min-width: 1920px ) {
274 .container-xxl,
275 .container-xl,
276 .container-lg,
277 .container-md,
278 .container-sm,
279 .container {
280 max-width: 1820px;
281 }
282 }
283 </style>
284 }
285 }
286287 @* Branding and Themes min stylesheet *@
288 <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">
289 <script src="/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks"></script>
290 <script type="module">
291 swift.Scroll.hideHeadersOnScroll();
292 swift.Scroll.handleAlternativeTheme();
293294 //Only load if AOS
295 const aosColumns = document.querySelectorAll('[data-aos]');
296 if (aosColumns.length > 0) {
297 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/js/aos.js?@jsFileInfo.LastWriteTime.Ticks', 'js');
298 document.addEventListener('load.swift.assetloader', function () {
299 AOS.init({ duration: 400, delay: 100, easing: 'ease-in-out', mirror: false, disable: window.matchMedia('(prefers-reduced-motion: reduce)') });
300 });
301 }
302 </script>
303304 @if (!string.IsNullOrWhiteSpace(userCentrics))
305 {
306307 <link rel="preconnect" href="//app.usercentrics.eu">
308 <link rel="preconnect" href="//api.usercentrics.eu">
309 <link rel="preload" href="//app.usercentrics.eu/browser-ui/latest/loader.js" as="script">
310311 }
312313 @if (!string.IsNullOrWhiteSpace(userCentrics))
314 {
315 <text>@userCentrics</text>
316 }
317318 @* Google tag manager *@
319 @if (!string.IsNullOrWhiteSpace(userCentrics) && !string.IsNullOrWhiteSpace(googleTagManagerID))
320 {
321 <script type="text/plain" data-usercentrics="Google Tag Manager">
322 (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
323 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
324 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
325 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
326 })(window, document, 'script', 'dataLayer', '@(googleTagManagerID)');
327328 function gtag() { dataLayer.push(arguments); }
329 </script>
330 } else if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking)
331 {
332 <script>
333 (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
334 new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
335 j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
336 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
337 })(window, document, 'script', 'dataLayer', '@(googleTagManagerID)');
338339 function gtag() { dataLayer.push(arguments); }
340 </script>
341 }
342343 @if (!string.IsNullOrWhiteSpace(userCentrics) && !string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID))
344 {
345 var GoogleAnalyticsDebugMode = "";
346347 if (Model.Area.Item.GetBoolean("EnableGoogleAnalyticsDebugMode"))
348 {
349 GoogleAnalyticsDebugMode = ", {'debug_mode': true}";
350 }
351352 <script type="text/plain" data-usercentrics="Google Analytics" async src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsMeasurementID"></script>
353 <script type="text/plain" data-usercentrics="Google Analytics">
354 window.dataLayer = window.dataLayer || [];
355 function gtag() { dataLayer.push(arguments); }
356 gtag('js', new Date());
357 gtag('config', '@googleAnalyticsMeasurementID'@GoogleAnalyticsDebugMode);
358 </script>
359 } else if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking)
360 {
361 var GoogleAnalyticsDebugMode = "";
362363 if (Model.Area.Item.GetBoolean("EnableGoogleAnalyticsDebugMode"))
364 {
365 GoogleAnalyticsDebugMode = ", {'debug_mode': true}";
366 }
367368 <script async src="https://www.googletagmanager.com/gtag/js?id=@googleAnalyticsMeasurementID"></script>
369 <script>
370 window.dataLayer = window.dataLayer || [];
371 function gtag() { dataLayer.push(arguments); }
372 gtag('js', new Date());
373 gtag('config', '@googleAnalyticsMeasurementID'@GoogleAnalyticsDebugMode);
374 </script>
375 }
376377 @if (!string.IsNullOrWhiteSpace(customHeaderInclude))
378 {
379 @RenderPartial($"Components/Custom/{customHeaderInclude}")
380 }
381382 @if (allowTracking && !string.IsNullOrWhiteSpace(scriptsHeader)){
383 @scriptsHeader
384 }
385386 </head>
387 <body class="brand @(masterTheme)" id="page@(Model.ID)">
388389 @* Google tag manager *@
390 @if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking)
391 {
392 <noscript>
393 <iframe src="https://www.googletagmanager.com/ns.html?id=@(googleTagManagerID)"
394 height="0" width="0" style="display:none;visibility:hidden"></iframe>
395 </noscript>
396 }
397398 @if (renderAsResponsive || !renderMobile)
399 {
400 <header class="page-header @headerCssClass top-0@(responsiveClassDesktop)" id="page-header-desktop">
401 @if (headerDesktopLink != null)
402 {
403 @RenderGrid(headerDesktopLink.PageId)
404 }
405 </header>
406 }
407408 @if ((renderAsResponsive || renderMobile))
409 {
410 <header class="page-header @headerCssClass top-0@(responsiveClassMobile)" id="page-header-mobile">
411 @if (headerMobileLink != null)
412 {
413 @RenderGrid(headerMobileLink.PageId)
414 }
415 </header>
416 }
417418 <div data-intersect></div>
419420 <main id="content" @(schemaOrgType)>
421 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel>
422 @using System
423 @using Dynamicweb.Ecommerce.ProductCatalog
424425426 @{
427 string productIdFromUrl = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : string.Empty;
428 bool isProductDetail = !string.IsNullOrEmpty(productIdFromUrl) && Pageview.Page.NavigationTag.ToLower() == "shop";
429430 bool isArticlePagePage = Model.ItemType == "Swift_Article";
431 bool isArticleListPage = Model.ItemType == "Swift_ArticleListPage";
432 string schemaOrgProp = string.Empty;
433 if (isArticlePagePage)
434 {
435 schemaOrgProp = "itemprop=\"articleBody\"";
436 }
437438 string theme = "";
439 string gridContent = "";
440441 if (Model.PropertyItem != null)
442 {
443 theme = !string.IsNullOrWhiteSpace(Model.PropertyItem.GetRawValueString("Theme")) ? "theme " + Model.PropertyItem.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
444 }
445446 if (Model.Item != null || Pageview.IsVisualEditorMode)
447 {
448 if (!isProductDetail)
449 {
450 gridContent = Model.Grid("Grid", "Grid", "default:true;sort:1", "Page");
451 }
452 else
453 {
454 var productObject = Dynamicweb.Ecommerce.Services.Products.GetProductById(productIdFromUrl, "", Pageview.Area.EcomLanguageId);
455 if (productObject != null)
456 {
457 var detailPage = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(productObject?.PrimaryGroupId)?.Meta.PrimaryPage ?? string.Empty;
458 var detailPageId = detailPage != string.Empty ? Convert.ToInt16(detailPage.Substring(detailPage.LastIndexOf('=') + 1)) : GetPageIdByNavigationTag("ProductDetailPage");
459460 @RenderGrid(detailPageId)
461 }
462 }
463 }
464465 bool doNotRenderPage = false;
466467 //Check if we are on the poduct detail page, and if there is data to render
468 ProductViewModel product = new ProductViewModel();
469 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
470 {
471 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"];
472 if (string.IsNullOrEmpty(product.Id))
473 {
474 doNotRenderPage = true;
475 }
476 }
477478 //Render the page
479 if (!doNotRenderPage)
480 {
481 string itemIdentifier = Model?.Item?.SystemName != null ? "item_" + Model.Item.SystemName.ToLower() : "item_Swift_Page";
482483 if (Pageview.IsVisualEditorMode)
484 {
485 @Model.Placeholder("dwcontent", "content", "default:true;sort:1")
486 }
487488 <div class="@theme @itemIdentifier" @schemaOrgProp>
489 @if (isArticleListPage)
490 {
491 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\"";
492493 <form @hx id="ArticleFacetForm">
494 @gridContent
495 </form>
496 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/htmx.js"></script>
497 <script type="module">
498 document.addEventListener('htmx:confirm', (event) => {
499 let filters = event.detail.elt.querySelectorAll('select');
500 for (var i = 0; i < filters.length; i++) {
501 let input = filters[i];
502 if (input.name && !input.value) {
503 input.name = '';
504 }
505 }
506 });
507508 document.addEventListener('htmx:beforeOnLoad', (event) => {
509 swift.Scroll.stopIntersectionObserver();
510 });
511512 document.addEventListener('htmx:afterOnLoad', () => {
513 swift.Scroll.hideHeadersOnScroll();
514 swift.Scroll.handleAlternativeTheme();
515 });
516 </script>
517 }
518 else
519 {
520 @gridContent
521 }
522 </div>
523524 }
525 else
526 {
527 <div class="container">
528 <div class="alert alert-info" role="alert">@Translate("Sorry. There is nothing to view here")</div>
529 </div>
530 }
531532 if (!Model.IsCurrentUserAllowed)
533 {
534 int signInPage = GetPageIdByNavigationTag("SignInPage");
535 int dashboardPage = GetPageIdByNavigationTag("MyAccountDashboardPage");
536537 if (!Pageview.IsVisualEditorMode)
538 {
539 if (signInPage != 0)
540 {
541 if (signInPage != Model.ID)
542 {
543 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + signInPage);
544 }
545 else
546 {
547 if (dashboardPage != 0)
548 {
549 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + dashboardPage);
550 }
551 else
552 {
553 Dynamicweb.Context.Current.Response.Redirect("/");
554 }
555 }
556 }
557 else
558 {
559 <div class="alert alert-dark m-0" role="alert">
560 <span>@Translate("You do not have access to this page")</span>
561 </div>
562 }
563 }
564 else
565 {
566 <div class="alert alert-dark m-0" role="alert">
567 <span>@Translate("To work on this page, you must be signed in, in the frontend")</span>
568 </div>
569 }
570 }
571 }
572573 </main>
574575 @if (renderAsResponsive || !renderMobile)
576 {
577 <footer class="page-footer@(responsiveClassDesktop)" id="page-footer-desktop">
578 @if (footerDesktopLink != null)
579 {
580 @RenderGrid(footerDesktopLink.PageId)
581 }
582583 @if (allowTracking && !string.IsNullOrWhiteSpace(customFooterScripts)){
584 @customFooterScripts
585 }
586 </footer>
587 }
588589 @if (renderAsResponsive || renderMobile)
590 {
591 <footer class="page-footer@(responsiveClassMobile)" id="page-footer-mobile">
592 @if (footerMobileLink != null)
593 {
594 @RenderGrid(footerMobileLink.PageId)
595 }
596 </footer>
597 }
598599 @* Render any offcanvas menu here *@
600 @RenderSnippet("offcanvas")
601602 @{
603 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]);
604 }
605606 @* Language selector modal *@
607 <div class="modal fade" id="PreferencesModal" tabindex="-1" aria-hidden="true">
608 <div class="modal-dialog modal-dialog-centered modal-sm" id="PreferencesModalContent">
609 @* The content here comes from an external request *@
610 </div>
611 </div>
612613 @* Favorite toast *@
614 <div aria-live="polite" aria-atomic="true">
615 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11">
616 <div id="favoriteNotificationToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
617 <div class="toast-header">
618 <strong class="me-auto">@Translate("Favorite list updated")</strong>
619 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
620 </div>
621 <div class="toast-body d-flex gap-3">
622 <div id="favoriteNotificationToast_Image"></div>
623 <div id="favoriteNotificationToast_Text"></div>
624 </div>
625 </div>
626 </div>
627 </div>
628629 @* Modal for dynamic content *@
630 <div class="modal fade js-product" id="DynamicModal" tabindex="-1" aria-hidden="true">
631 <div class="modal-dialog modal-dialog-centered modal-md">
632 <div class="modal-content theme light" id="DynamicModalContent">
633 @* The content here comes from an external request *@
634 </div>
635 </div>
636 </div>
637638 @* Offcanvas for dynamic content *@
639 <div class="offcanvas offcanvas-end theme light" tabindex="-1" id="DynamicOffcanvas">
640 @* The content here comes from an external request *@
641 </div>
642643 @if (Model.Area.Item.GetBoolean("ShowErpDownMessage") && !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]))
644 {
645 string erpDownMessageTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("ErpDownMessageTheme")) ? " theme " + Model.Area.Item.GetRawValueString("ErpDownMessageTheme").Replace(" ", "").Trim().ToLower() : "theme light";
646647 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1040">
648 <div class="toast fade show border-0 @erpDownMessageTheme" role="alert" aria-live="assertive" aria-atomic="true">
649 <div class="toast-header">
650 <strong class="me-auto">@Translate("Connection down")</strong>
651 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
652 </div>
653 <div class="toast-body">
654 @Translate("We are experiencing some connectivity issues. Not all features may be available to you.")
655 </div>
656 </div>
657 </div>
658 }
659660 @if (miniCartEnabled)
661 {
662 @* Open MiniCart when the cart is updated *@
663 <script type="module">
664 document.addEventListener('updated.swift.cart', (event) => {
665 let orderContext = event?.detail?.formData?.get("OrderContext");
666 updateCartSummary(orderContext);
667668 @if (offcanvasMiniCartBehaviour == "2" || offcanvasMiniCartBehaviour == "3") {
669 <text>openMiniCartOffcanvas();</text>
670 }
671 });
672 </script>
673674 if (offcanvasMiniCartBehaviour == "1" || offcanvasMiniCartBehaviour == "3")
675 {
676 @* Open MiniCart when toggle is clicked *@
677 <script type="module">
678 let miniCartToggles = document.querySelectorAll('.mini-cart-quantity');
679 miniCartToggles?.forEach((toggle) => {
680 toggle.parentElement.addEventListener('click', (event) => {
681 event.preventDefault();
682 let orderContext = toggle.dataset?.orderContext;
683 updateCartSummary(orderContext);
684685 openMiniCartOffcanvas();
686 });
687 });
688 </script>
689 }
690691 <script>
692693 const updateCartSummary = (orderContext) => {
694 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas');
695 swift.PageUpdater.UpdateFromUrlInline(event, '/Default.aspx?ID=@(cartSummaryPageId)&CartType=minicart&RequestPageID=@(Pageview.Page.ID)&OrderContext=' + orderContext +'', 'Swift_CartSummary.cshtml', dynamicOffcanvas);
696 };
697698 const openMiniCartOffcanvas = () => {
699 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas');
700 const miniCartOffcanvas = bootstrap.Offcanvas.getOrCreateInstance(dynamicOffcanvas);
701 dynamicOffcanvas.classList.add('overflow-y-auto');
702703 if (!miniCartOffcanvas._isShown) {
704 miniCartOffcanvas.show();
705 hideActiveOffcanvases(miniCartOffcanvas);
706 }
707 };
708709 const hideActiveOffcanvases = (miniCartOffcanvas) => {
710 let activeOffcanvases = document.querySelectorAll('.offcanvas.show');
711 activeOffcanvases?.forEach((offCanvas) => {
712 offCanvas = bootstrap.Offcanvas.getInstance(offCanvas);
713 if (offCanvas !== miniCartOffcanvas) {
714 offCanvas.hide();
715 }
716 });
717 };
718719 </script>
720 }
721722 </body>
723724 </html>
725726 }
727 else if (Pageview.IsVisualEditorMode)
728 {
729 <head>
730 <title>@Model.Title</title>
731 @* Bootstrap + Swift stylesheet *@
732 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css" rel="stylesheet" media="all" type="text/css">
733 </head>
734 <body class="p-3">
735 <div class="alert alert-danger" role="alert">
736 @Translate("Basic Swift setup is needed!")
737 </div>
738739 @if (brandingPage == null)
740 {
741 <div class="alert alert-warning" role="alert">
742 @Translate("Please add a Branding page and reference it in website settings")
743 </div>
744 }
745746 @if (themesParagraphs == null)
747 {
748 <div class="alert alert-warning" role="alert">
749 @Translate("Please add a Themes collection page and reference it in website settings")
750 </div>
751 }
752 </body>
753 }
754755756 @functions {
757 void SetMetaTags()
758 {
759 //Verification Tokens
760 string siteVerificationGoogle = Model.Area.Item.GetString("Google_Site_Verification") != null ? Model.Area.Item.GetString("Google_Site_Verification") : "";
761762 //Generic Site Values
763 string openGraphFacebookAppID = Model.Area.Item.GetString("Fb_app_id") != null ? Model.Area.Item.GetString("Fb_app_id") : "";
764 string openGraphType = Model.Area.Item.GetString("Open_Graph_Type") != null ? Model.Area.Item.GetString("Open_Graph_Type") : "";
765 string openGraphSiteName = Model.Area.Item.GetString("Open_Graph_Site_Name") != null ? Model.Area.Item.GetString("Open_Graph_Site_Name") : "";
766767 string twitterCardSite = Model.Area.Item.GetString("Twitter_Site") != null ? Model.Area.Item.GetString("Twitter_Site") : "";
768769 //Page specific values
770 string openGraphSiteTitle = Model.Area.Item.GetString("Open_Graph_Title") != null ? Model.Area.Item.GetString("Open_Graph_Title") : "";
771 FileViewModel openGraphImage = Model.Area.Item.GetFile("Open_Graph_Image");
772 string openGraphImageALT = Model.Area.Item.GetString("Open_Graph_Image_ALT") != null ? Model.Area.Item.GetString("Open_Graph_Image_ALT") : "";
773 string openGraphDescription = Model.Area.Item.GetString("Open_Graph_Description") != null ? Model.Area.Item.GetString("Open_Graph_Description") : "";
774775 string twitterCardURL = Model.Area.Item.GetString("Twitter_URL") != null ? Model.Area.Item.GetString("Twitter_URL") : "";
776 string twitterCardTitle = Model.Area.Item.GetString("Twitter_Title") != null ? Model.Area.Item.GetString("Twitter_Title") : "";
777 string twitterCardDescription = Model.Area.Item.GetString("Twitter_Description") != null ? Model.Area.Item.GetString("Twitter_Description") : "";
778 FileViewModel twitterCardImage = Model.Area.Item.GetFile("Twitter_Image");
779 string twitterCardImageALT = Model.Area.Item.GetString("Twitter_Image_ALT") != null ? Model.Area.Item.GetString("Twitter_Image_ALT") : "";
780 string topImage = Pageview.Page.TopImage.StartsWith("/Files", StringComparison.OrdinalIgnoreCase) ? Pageview.Page.TopImage : $"/Files{Pageview.Page.TopImage}";
781782 if (string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"]))
783 {
784 if (!string.IsNullOrEmpty(Model.Description))
785 {
786 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{Model.Description}\">");
787 }
788 else
789 {
790 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{openGraphDescription}\">");
791 }
792793 if (!string.IsNullOrEmpty(Pageview.Page.TopImage))
794 {
795 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">");
796 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">");
797 }
798 else if (openGraphImage != null)
799 {
800 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">");
801 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">");
802 }
803804 if (!string.IsNullOrEmpty(openGraphImageALT))
805 {
806 Pageview.Meta.AddTag($"<meta property=\"og:image:alt\" content=\"{openGraphImageALT}\">");
807 }
808 if (!string.IsNullOrEmpty(twitterCardDescription))
809 {
810 Pageview.Meta.AddTag("twitter:description", twitterCardDescription);
811 }
812813 if (!string.IsNullOrEmpty(Pageview.Page.TopImage))
814 {
815 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}");
816 }
817 else if (twitterCardImage != null)
818 {
819 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}");
820 }
821822 if (!string.IsNullOrEmpty(twitterCardImageALT))
823 {
824 Pageview.Meta.AddTag("twitter:image:alt", twitterCardImageALT);
825 }
826 }
827828 if (!string.IsNullOrEmpty(siteVerificationGoogle))
829 {
830 Pageview.Meta.AddTag("google-site-verification", siteVerificationGoogle);
831 }
832833 if (!string.IsNullOrEmpty(openGraphFacebookAppID))
834 {
835 Pageview.Meta.AddTag($"<meta property=\"fb:app_id\" content=\"{openGraphFacebookAppID}\">");
836 }
837838 if (!string.IsNullOrEmpty(openGraphType))
839 {
840 Pageview.Meta.AddTag($"<meta property=\"og:type\" content=\"{openGraphType}\">");
841 }
842843 if (!string.IsNullOrEmpty(openGraphSiteName))
844 {
845 Pageview.Meta.AddTag($"<meta property=\"og:url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{Pageview.SearchFriendlyUrl}\">");
846 }
847848 if (!string.IsNullOrEmpty(openGraphSiteName))
849 {
850 Pageview.Meta.AddTag($"<meta property=\"og:site_name\" content=\"{openGraphSiteName}\">");
851 }
852853 if (!string.IsNullOrEmpty(Model.Title))
854 {
855 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{Model.Title}\">");
856 }
857 else
858 {
859 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{openGraphSiteTitle}\">");
860 }
861862 if (!string.IsNullOrEmpty(twitterCardSite))
863 {
864 Pageview.Meta.AddTag("twitter:site", twitterCardSite);
865 }
866867 if (!string.IsNullOrEmpty(twitterCardURL))
868 {
869 Pageview.Meta.AddTag("twitter:url", twitterCardURL);
870 }
871872 if (!string.IsNullOrEmpty(twitterCardTitle))
873 {
874 Pageview.Meta.AddTag("twitter:title", twitterCardTitle);
875 }
876 }
877 }
878