Error executing template "Designs/Swift/Swift_Page.cshtml"
System.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)
 ---> System.ComponentModel.Win32Exception (2): The system cannot find the file specified.
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.SqlClient.SqlConnection.Open()
   at Dynamicweb.Data.DatabaseConnectionProvider.CreateConnection(Boolean open)
   at Dynamicweb.Data.Database.CreateConnection()
   at Dynamicweb.Data.Database.CreateDataReader(CommandBuilder commandBuilder, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout)
   at Dynamicweb.Ecommerce.Products.ProductRepository.GetProductById(String productId, String productVariantId, String productLanguageId)
   at Dynamicweb.Ecommerce.Products.ProductService.FetchMissingProducts(IEnumerable`1 keys)
   at Dynamicweb.Caching.ServiceCache`2.GetCache(IEnumerable`1 keys)
   at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId, User user, Boolean showUntranslated)
   at Dynamicweb.Ecommerce.Products.ProductService.GetProductById(String productId, String productVariantId, String productLanguageId)
   at CompiledRazorTemplates.Dynamic.RazorEngine_aea9c5ae9d4742dab212ded8deb007eb.ExecuteAsync()
   at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
   at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()
ClientConnectionId:00000000-0000-0000-0000-000000000000
Error Number:2,State:0,Class:20

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