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