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 (64): The specified network name is no longer available.
   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.FetchMissingProductsInternal(IProductRepository repo, 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_e0e42a14a9b848719239fe1fa630c49c.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:64,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 // Has ContactID? - used with ActiveCampaign 132 var ContactId = Dynamicweb.Context.Current.Request.QueryString["ContactId"]; 133 if (!string.IsNullOrWhiteSpace(ContactId)) 134 { 135 Dynamicweb.Environment.CookieManager.SetCookie("ContactId", ContactId, DateTime.Now.AddYears(1)); 136 } 137 138 var cssStyleFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/css/styles.css")); 139 var jsFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/scripts.js")); 140 var jsMainFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/Swift/Assets/js/main.js")); 141 142 string masterTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("Theme")) ? " theme " + Model.Area.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 143 144 string favicon = Model.Area.Item.GetRawValueString("Favicon", "/Files/Templates/Designs/Swift/Assets/Images/favicon.png"); 145 string appleTouchIcon = Model.Area.Item.GetRawValueString("AppleTouchIcon", "/Files/Templates/Designs/Swift/Assets/Images/apple-touch-icon.png"); 146 147 string headerCssClass = "sticky-top"; 148 bool movePageBehind = false; 149 150 if (Model.PropertyItem != null) 151 { 152 headerCssClass = Model.PropertyItem.GetRawValueString("MoveThisPageBehindTheHeader", "sticky-top"); 153 movePageBehind = headerCssClass == "fixed-top" && !Pageview.IsVisualEditorMode ? true : false; 154 } 155 156 headerCssClass = headerCssClass == "" ? "sticky-top" : headerCssClass; 157 headerCssClass = Pageview.IsVisualEditorMode ? "" : headerCssClass; 158 159 string googleTagManagerID = Model.Area.Item.GetString("GoogleTagManagerID").Trim(); 160 string googleAnalyticsMeasurementID = Model.Area.Item.GetString("GoogleAnalyticsMeasurementID").Trim(); 161 162 bool allowTracking = AllowTracking(); 163 164 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/css/styles.css?{cssStyleFileInfo.LastWriteTime.Ticks}>; rel=preload; as=style;"); 165 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;"); 166 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/scripts.js?{jsFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;"); 167 Dynamicweb.Context.Current.Response.AddHeader("link", $"</Files/Templates/Designs/Swift/Assets/js/main.js?{jsMainFileInfo.LastWriteTime.Ticks}>; rel=preload; as=script;"); 168 169 170 SetMetaTags(); 171 172 List<Dynamicweb.Content.Page> languages = new List<Dynamicweb.Content.Page>(); 173 174 var masterPage = Pageview.Area.IsMaster ? Pageview.Page : Pageview.Page.MasterPage; 175 languages.Add(masterPage); 176 if (masterPage?.Languages != null) 177 { 178 foreach (var language in masterPage.Languages) 179 { 180 languages.Add(language); 181 } 182 } 183 184 Uri url = Dynamicweb.Context.Current.Request.Url; 185 string hostName = url.Host; 186 187 <!doctype html> 188 <html lang="@Pageview.Area.CultureInfo.TwoLetterISOLanguageName"> 189 <head> 190 <!-- @swiftVersion --> 191 @* Required meta tags *@ 192 <meta charset="utf-8"> 193 <meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0"> 194 <link rel="shortcut icon" href="@favicon"> 195 <link rel="apple-touch-icon" href="@appleTouchIcon"> 196 197 @Model.MetaTags 198 199 @{ 200 var alreadyWrittenTwoletterIsos = new List<string>(); 201 @* Languages meta data *@ 202 foreach (var language in languages) 203 { 204 hostName = url.Host; 205 if (language?.Area != null) 206 { 207 if (language.Area?.MasterArea != null && !string.IsNullOrEmpty(language.Area.MasterArea.DomainLock)) 208 { 209 hostName = language.Area.MasterArea.DomainLock; //dk.domain.com or dk-domain.dk 210 } 211 if (language != null && language.Area != null && language.Published && language.Area.Active && language.Area.Published) 212 { 213 if (!string.IsNullOrEmpty(language.Area.DomainLock)) 214 { 215 hostName = language.Area.DomainLock; //dk.domain.com or dk-domain.dk 216 } 217 string querystring = $"Default.aspx?ID={language.ID}"; 218 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["GroupID"])) 219 { 220 querystring += $"&GroupID={Dynamicweb.Context.Current.Request.QueryString["GroupID"]}"; 221 } 222 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"])) 223 { 224 querystring += $"&ProductID={Dynamicweb.Context.Current.Request.QueryString["ProductID"]}"; 225 } 226 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["VariantID"])) 227 { 228 querystring += $"&VariantID={Dynamicweb.Context.Current.Request.QueryString["VariantID"]}"; 229 } 230 231 string friendlyUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(querystring); 232 if (language.Area.RedirectFirstPage && language.ParentPageId == 0 && language.Sort == 1) 233 { 234 friendlyUrl = "/"; 235 } 236 string href = $"{url.Scheme}://{hostName}{friendlyUrl}"; 237 238 var hreflang = language.Area.CultureInfo.Name.ToLower(); 239 if(language.Area.EcomLanguageId == "LANG7") 240 { 241 hreflang = "en-150"; 242 } 243 244 if (!alreadyWrittenTwoletterIsos.Contains(hreflang)) 245 { 246 alreadyWrittenTwoletterIsos.Add(hreflang); 247 <link rel="alternate" hreflang="@hreflang" href="@href.TrimEnd('/')"> 248 } 249 } 250 } 251 } 252 } 253 254 <title>@Model.Title</title> 255 @* Bootstrap + Swift stylesheet *@ 256 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css?@cssStyleFileInfo.LastWriteTime.Ticks" rel="stylesheet" media="all" type="text/css"> 257 @* <style>pre.dw-error { display:none; }</style> *@ 258 @if (disableWideBreakpoints != "disableBoth") 259 { 260 <style> 261 @@media ( min-width: 1600px ) { 262 .container-xxl, 263 .container-xl, 264 .container-lg, 265 .container-md, 266 .container-sm, 267 .container { 268 max-width: 1520px; 269 } 270 } 271 </style> 272 273 274 275 if (disableWideBreakpoints != "disableUltraWideOnly") 276 { 277 <style> 278 @@media ( min-width: 1920px ) { 279 .container-xxl, 280 .container-xl, 281 .container-lg, 282 .container-md, 283 .container-sm, 284 .container { 285 max-width: 1820px; 286 } 287 } 288 </style> 289 } 290 } 291 292 @* Branding and Themes min stylesheet *@ 293 <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"> 294 <script src="/Files/Templates/Designs/Swift/Assets/js/scripts.js?@jsFileInfo.LastWriteTime.Ticks"></script> 295 <script src="/Files/Templates/Designs/Swift/Assets/js/main.js?@jsMainFileInfo.LastWriteTime.Ticks"></script> 296 <script type="module"> 297 swift.Scroll.hideHeadersOnScroll(); 298 swift.Scroll.handleAlternativeTheme(); 299 300 //Only load if AOS 301 const aosColumns = document.querySelectorAll('[data-aos]'); 302 if (aosColumns.length > 0) { 303 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/js/aos.js?@jsFileInfo.LastWriteTime.Ticks', 'js'); 304 document.addEventListener('load.swift.assetloader', function () { 305 AOS.init({ duration: 400, delay: 100, easing: 'ease-in-out', mirror: false, disable: window.matchMedia('(prefers-reduced-motion: reduce)') }); 306 }); 307 } 308 </script> 309 310 @* Google gtag method - always include even if it is not used for anything *@ 311 <script> 312 window.dataLayer = window.dataLayer || []; 313 function gtag() { 314 //dataLayer.push(arguments); 315 if(arguments[2] && arguments[2]?.items) { 316 // try update items 317 // arguments[2]?.items?.forEach(itm => { 318 // const itm_brand = document.querySelector('[data-gtagbrand="'+itm.item_id+'"]')?.innerText; 319 // if(itm_brand) { 320 // itm['item_brand'] = itm_brand; 321 // } 322 // }); 323 324 dataLayer.push({ ecommerce: null }); 325 dataLayer.push({ 326 event: arguments[1], 327 ecommerce: arguments[2] 328 }); 329 } else { 330 dataLayer.push(arguments); 331 } 332 } 333 </script> 334 335 @if (!string.IsNullOrWhiteSpace(customHeaderInclude)) 336 { 337 @RenderPartial($"Components/Custom/{customHeaderInclude}") 338 } 339 <style> 340 .item_swift_productlistitemrepeater { 341 font-size: 0.85rem; 342 } 343 .grid > * { 344 min-width: 0 !important; 345 } 346 article.product:hover .border-hover-primary { 347 border: 1px solid var(--swift-button-primary-background-color)!important; 348 } 349 @@media (min-width: 992px) { 350 .component-sticky { 351 position: sticky; 352 top: var(--header-height); 353 height: auto !important; 354 } 355 356 .modal-open .component-sticky { 357 position: static; 358 } 359 } 360 </style> 361 </head> 362 <body class="brand @(masterTheme)" id="page@(Model.ID)"> 363 364 @* Google tag manager *@ 365 @if (!string.IsNullOrWhiteSpace(googleTagManagerID) && allowTracking) 366 { 367 <noscript> 368 <iframe src="@googleTagManagerID" height="0" width="0" style="display:none;visibility:hidden"></iframe> 369 </noscript> 370 } 371 372 @if (renderAsResponsive || !renderMobile) 373 { 374 var IsCatalogPage = Pageview.Page.ItemType == "Swift_CatalogPage"; 375 376 <header class="page-header @headerCssClass top-0@(responsiveClassDesktop)" id="page-header-desktop"> 377 @if (IsCatalogPage) 378 { 379 // Current page path. Page Id and title 380 var PagePath = Pageview.Page.GetPath() 381 .Select(a => new KeyValuePair<int, string>(a.ID, a.MenuText)) 382 .ToDictionary(x => x.Key, x => x.Value); 383 384 var CatalogHeader = Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Pageview.Area.ID, "CatalogHeader"); 385 var RootpathBrandname = PagePath.Skip(3).FirstOrDefault().Value; 386 var BrandName = RootpathBrandname?.ToLower() switch 387 { 388 "outwell" => "Swift_styles_3", 389 "robens" => "Swift_styles_4", 390 "easy camp" => "Swift_styles_2", 391 _ => "" 392 }; 393 <link href="/Files/Templates/Designs/Swift/_parsed/Swift_css/@(BrandName).min.css?@cssLastModified.Ticks" rel="stylesheet" media="all" type="text/css" data-last-modified-content="@cssLastModified"> 394 @RenderGrid(CatalogHeader.ID) 395 } else 396 { 397 if (headerDesktopLink != null) 398 { 399 @RenderGrid(headerDesktopLink.PageId) 400 } 401 } 402 </header> 403 } 404 405 @if ((renderAsResponsive || renderMobile)) 406 { 407 <header class="page-header @headerCssClass top-0@(responsiveClassMobile)" id="page-header-mobile"> 408 @if (headerMobileLink != null) 409 { 410 @RenderGrid(headerMobileLink.PageId) 411 } 412 </header> 413 } 414 415 <div data-intersect></div> 416 417 <main id="content" style="user-select:none;" @(schemaOrgType)> 418 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.PageViewModel> 419 @using System 420 @using Dynamicweb.Ecommerce.ProductCatalog 421 @using Oase.Backend.Extensions 422 423 424 @{ 425 string productIdFromUrl = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("ProductID") : string.Empty; 426 bool isProductDetail = !string.IsNullOrEmpty(productIdFromUrl) && Pageview.Page.NavigationTag.ToLower() == "shop"; 427 428 bool isArticlePagePage = Model.ItemType == "Swift_Article"; 429 bool isArticleListPage = Model.ItemType == "Swift_ArticleListPage"; 430 string schemaOrgProp = string.Empty; 431 if(isArticlePagePage) 432 { 433 schemaOrgProp = "itemprop=\"articleBody\""; 434 } 435 436 string theme = ""; 437 string gridContent = ""; 438 439 if (Model.PropertyItem != null) 440 { 441 theme = !string.IsNullOrWhiteSpace(Model.PropertyItem.GetRawValueString("Theme")) ? "theme " + Model.PropertyItem.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 442 } 443 444 if (Model.Item != null || Pageview.IsVisualEditorMode) 445 { 446 if (!isProductDetail) 447 { 448 gridContent = Model.Grid("Grid", "Grid", "default:true;sort:1", "Page"); 449 } 450 else 451 { 452 var productObject = Dynamicweb.Ecommerce.Services.Products.GetProductById(productIdFromUrl, "", Pageview.Area.EcomLanguageId); 453 var detailPage = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(productObject.PrimaryGroupId)?.Meta.PrimaryPage ?? string.Empty; 454 var detailPageId = detailPage != string.Empty ? Convert.ToInt16(detailPage.Substring(detailPage.LastIndexOf('=') + 1)) : GetPageIdByNavigationTag("ProductDetailPage"); 455 456 @RenderGrid(detailPageId) 457 } 458 } 459 460 bool doNotRenderPage = false; 461 462 //Check if we are on the poduct detail page, and if there is data to render 463 ProductViewModel product = new ProductViewModel(); 464 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 465 { 466 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 467 if (string.IsNullOrEmpty(product.Id)) { 468 doNotRenderPage = true; 469 } 470 } 471 if(!string.IsNullOrWhiteSpace(productIdFromUrl)) 472 { 473 <script> 474 475 gtag("event", "view_item", { 476 currency: "@product.Price.CurrencyCode", 477 value: @PriceViewModelExtensions.ToStringInvariant(product.Price), 478 items: [ 479 { 480 item_id: "@product.Id", 481 item_name: "@Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(product.Name)", 482 item_brand: "@product.ProductFields.GetValueOrDefault("Collection")?.Value", 483 currency: "@product.Price.CurrencyCode", 484 price: @PriceViewModelExtensions.ToStringInvariant(product.Price) 485 } 486 ] 487 }); 488 </script> 489 } 490 491 // Custom authorization 492 var AllowUserWith = Model?.PropertyItem?.GetString("AllowUserWith", ""); 493 if (!string.IsNullOrWhiteSpace(AllowUserWith)) 494 { 495 var currentUserValue = Dynamicweb.Security.UserManagement.UserContext.Current.User?.GetCustomFieldValue($"{AllowUserWith}"); 496 if (currentUserValue == false) 497 { 498 doNotRenderPage = true; 499 } 500 } 501 502 //Render the page 503 if (!doNotRenderPage) 504 { 505 string itemIdentifier = Model?.Item?.SystemName != null ? "item_" + Model.Item.SystemName.ToLower() : "item_Swift_Page"; 506 507 if (Pageview.IsVisualEditorMode) { 508 @Model.Placeholder("dwcontent", "content", "default:true;sort:1") 509 } 510 <div class="@theme @itemIdentifier" @schemaOrgProp> 511 @if (isArticleListPage) 512 { 513 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\""; 514 515 <form @hx id="ArticleFacetForm"> 516 @gridContent 517 </form> 518 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/htmx.js"></script> 519 <script type="module"> 520 document.addEventListener('htmx:confirm', (event) => { 521 let filters = event.detail.elt.querySelectorAll('select'); 522 for (var i = 0; i < filters.length; i++) { 523 let input = filters[i]; 524 if (input.name && !input.value) { 525 input.name = ''; 526 } 527 } 528 }); 529 530 document.addEventListener('htmx:beforeOnLoad', (event) => { 531 swift.Scroll.stopIntersectionObserver(); 532 }); 533 534 document.addEventListener('htmx:afterOnLoad', () => { 535 swift.Scroll.hideHeadersOnScroll(); 536 swift.Scroll.handleAlternativeTheme(); 537 }); 538 </script> 539 } 540 else 541 { 542 @gridContent 543 } 544 </div> 545 <style> 546 @@media (max-width: 991.98px) { 547 .item_custom_swift_productaddtocart.is-sticky { 548 position: fixed; 549 top: var(--header-height); 550 left: 0; 551 right: 0; 552 max-width: 100vw!important; 553 z-index: 1060; 554 padding: 0.5rem 1rem; 555 background: #fff; 556 box-shadow: 0 2px 10px rgba(0,0,0,0.1); 557 } 558 559 .item_custom_swift_productaddtocart-placeholder { 560 display: none; 561 } 562 563 .item_custom_swift_productaddtocart-placeholder.active { 564 display: block; 565 } 566 567 .offcanvas { 568 z-index: 1070!important; 569 } 570 } 571 </style> 572 } else { 573 <div class="container py-5"> 574 <div class="alert alert-info" role="alert">@Translate("Sorry. There is nothing to view here")</div> 575 </div> 576 } 577 578 if (!Model.IsCurrentUserAllowed) 579 { 580 int signInPage = GetPageIdByNavigationTag("SignInPage"); 581 int dashboardPage = GetPageIdByNavigationTag("MyAccountDashboardPage"); 582 583 if (!Pageview.IsVisualEditorMode) 584 { 585 if (signInPage != 0) 586 { 587 if (signInPage != Model.ID) { 588 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + signInPage); 589 } else { 590 if (dashboardPage != 0) { 591 Dynamicweb.Context.Current.Response.Redirect("/Default.aspx?ID=" + dashboardPage); 592 } else { 593 Dynamicweb.Context.Current.Response.Redirect("/"); 594 } 595 } 596 } 597 else 598 { 599 <div class="alert alert-dark m-0" role="alert"> 600 <span>@Translate("You do not have access to this page")</span> 601 </div> 602 } 603 } 604 else 605 { 606 <div class="alert alert-dark m-0" role="alert"> 607 <span>@Translate("To work on this page, you must be signed in, in the frontend")</span> 608 </div> 609 } 610 } 611 } 612 613 </main> 614 615 <link rel="stylesheet" href="/Files/Templates/Designs/Swift/Assets/css/glightbox.min.css" /> 616 <script src="/Files/Templates/Designs/Swift/Assets/js/glightbox.min.js"></script> 617 <script> 618 var lightbox = GLightbox({ 619 touchNavigation: true, 620 loop: false, 621 autoplayVideos: true, 622 videosWidth: '80vw', 623 dragAutoSnap: true, 624 plyr: { 625 config: { 626 quality: 720, 627 muted: false, 628 volume: 100, 629 youtube: { noCookie: true, rel: 0, showinfo: 0, iv_load_policy: 3, modestbranding: 1 } 630 } 631 } 632 }); 633 </script> 634 <script> 635 document.addEventListener('DOMContentLoaded', () => { 636 document.querySelectorAll('a').forEach(link => { 637 const href = link.getAttribute('href'); 638 if (href && href.startsWith('https')) { 639 link.setAttribute('target', '_blank'); 640 } else { 641 link.setAttribute('target', '_self'); 642 } 643 }); 644 }); 645 </script> 646 647 @if (renderAsResponsive || !renderMobile) 648 { 649 <footer class="page-footer@(responsiveClassDesktop)" id="page-footer-desktop"> 650 @if (footerDesktopLink != null) 651 { 652 @RenderGrid(footerDesktopLink.PageId) 653 } 654 </footer> 655 } 656 657 @if (renderAsResponsive || renderMobile) 658 { 659 <footer class="page-footer@(responsiveClassMobile)" id="page-footer-mobile"> 660 @if (footerMobileLink != null) 661 { 662 @RenderGrid(footerMobileLink.PageId) 663 } 664 </footer> 665 } 666 667 @* Render any offcanvas menu here *@ 668 @RenderSnippet("offcanvas") 669 670 @{ 671 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"]); 672 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 673 } 674 675 @* Language selector modal *@ 676 <div class="modal fade" id="PreferencesModal" tabindex="-1" aria-hidden="true"> 677 <div class="modal-dialog modal-dialog-centered modal-sm" id="PreferencesModalContent"> 678 @* The content here comes from an external request *@ 679 </div> 680 </div> 681 682 @* Toast *@ 683 <div aria-live="polite" aria-atomic="true"> 684 <div class="toast-container position-fixed end-0 p-3" style="top:50px;z-index:1500;"> 685 <div id="notificationToast" class="toast rounded-6 overflow-hidden" role="alert" aria-live="assertive" aria-atomic="true" data-bs-delay="1000"> 686 <div class="toast-body d-flex align-items-end gap-3 theme theme-gray bg-dark text-light"> 687 @ReadFile(iconPath + "check.svg") 688 <div id="notificationToast_Text" class=""></div> 689 </div> 690 </div> 691 </div> 692 </div> 693 694 @* Modal for dynamic content *@ 695 <div class="modal fade js-product" id="DynamicModal" tabindex="-1" aria-hidden="true"> 696 <div class="modal-dialog modal-dialog-centered modal-md"> 697 <div class="modal-content theme light" id="DynamicModalContent"> 698 @* The content here comes from an external request *@ 699 </div> 700 </div> 701 </div> 702 703 @* Offcanvas for dynamic content *@ 704 <div class="offcanvas offcanvas-end theme light" tabindex="-1" id="DynamicOffcanvas"> 705 @* The content here comes from an external request *@ 706 </div> 707 708 @if (Model.Area.Item.GetBoolean("ShowErpDownMessage") && !Dynamicweb.Core.Converter.ToBoolean(Context.Current.Items["IsWebServiceConnectionAvailable"])) 709 { 710 string erpDownMessageTheme = !string.IsNullOrWhiteSpace(Model.Area.Item.GetRawValueString("ErpDownMessageTheme")) ? " theme " + Model.Area.Item.GetRawValueString("ErpDownMessageTheme").Replace(" ", "").Trim().ToLower() : "theme light"; 711 712 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1040"> 713 <div class="toast fade show border-0 @erpDownMessageTheme" role="alert" aria-live="assertive" aria-atomic="true"> 714 <div class="toast-header"> 715 <strong class="me-auto">@Translate("Connection down")</strong> 716 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> 717 </div> 718 <div class="toast-body"> 719 @Translate("We are experiencing some connectivity issues. Not all features may be available to you.") 720 </div> 721 </div> 722 </div> 723 } 724 725 @if (miniCartEnabled) 726 { 727 @* Open MiniCart when the cart is updated *@ 728 <script type="module"> 729 document.addEventListener('updated.swift.cart', (event) => { 730 let orderContext = event?.detail?.formData?.get("OrderContext"); 731 updateCartSummary(orderContext); 732 733 @if (offcanvasMiniCartBehaviour == "2" || offcanvasMiniCartBehaviour == "3") { 734 <text>openMiniCartOffcanvas();</text> 735 } 736 }); 737 </script> 738 739 if (offcanvasMiniCartBehaviour == "1" || offcanvasMiniCartBehaviour == "3") 740 { 741 @* Open MiniCart when toggle is clicked *@ 742 <script type="module"> 743 let miniCartToggles = document.querySelectorAll('.mini-cart-quantity'); 744 miniCartToggles?.forEach((toggle) => { 745 toggle.parentElement.addEventListener('click', (event) => { 746 event.preventDefault(); 747 let orderContext = toggle.dataset?.orderContext; 748 updateCartSummary(orderContext); 749 750 openMiniCartOffcanvas(); 751 }); 752 }); 753 </script> 754 } 755 756 <script> 757 758 const updateCartSummary = (orderContext) => { 759 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas'); 760 swift.PageUpdater.UpdateFromUrlInline(event, '/Default.aspx?ID=@(cartSummaryPageId)&CartType=minicart&RequestPageID=@(Pageview.Page.ID)&OrderContext=' + orderContext +'', 'Swift_CartSummary.cshtml', dynamicOffcanvas); 761 }; 762 763 const openMiniCartOffcanvas = () => { 764 const dynamicOffcanvas = document.getElementById('DynamicOffcanvas'); 765 const miniCartOffcanvas = bootstrap.Offcanvas.getOrCreateInstance(dynamicOffcanvas); 766 dynamicOffcanvas.classList.add('overflow-y-auto'); 767 768 if (!miniCartOffcanvas._isShown) { 769 miniCartOffcanvas.show(); 770 hideActiveOffcanvases(miniCartOffcanvas); 771 } 772 }; 773 774 const hideActiveOffcanvases = (miniCartOffcanvas) => { 775 let activeOffcanvases = document.querySelectorAll('.offcanvas.show'); 776 activeOffcanvases?.forEach((offCanvas) => { 777 offCanvas = bootstrap.Offcanvas.getInstance(offCanvas); 778 if (offCanvas !== miniCartOffcanvas) { 779 offCanvas.hide(); 780 } 781 }); 782 }; 783 784 </script> 785 } 786 @if (Pageview.Area.Name?.StartsWith("Xhelter") == false && Pageview.Area.Name?.StartsWith("Oase") == false) 787 { 788 <p class="d-none">@Pageview.Area.Name</p> 789 @RenderPartial("Components/Custom/CustomLanguageModal.cshtml") 790 } 791 </body> 792 793 </html> 794 795 } 796 else if (Pageview.IsVisualEditorMode) 797 { 798 <head> 799 <title>@Model.Title</title> 800 @* Bootstrap + Swift stylesheet *@ 801 <link href="/Files/Templates/Designs/Swift/Assets/css/styles.css" rel="stylesheet" media="all" type="text/css"> 802 </head> 803 <body class="p-3"> 804 <div class="alert alert-danger" role="alert"> 805 @Translate("Basic Swift setup is needed!") 806 </div> 807 808 @if (brandingPage == null) 809 { 810 <div class="alert alert-warning" role="alert"> 811 @Translate("Please add a Branding page and reference it in website settings") 812 </div> 813 } 814 815 @if (themesParagraphs == null) 816 { 817 <div class="alert alert-warning" role="alert"> 818 @Translate("Please add a Themes collection page and reference it in website settings") 819 </div> 820 } 821 </body> 822 } 823 824 825 @functions { 826 void SetMetaTags() 827 { 828 //Verification Tokens 829 string siteVerificationGoogle = Model.Area.Item.GetString("Google_Site_Verification") != null ? Model.Area.Item.GetString("Google_Site_Verification") : ""; 830 string siteVerificationFacebook = Model.Area.Item.GetString("Facebook_Site_Verification") != null ? Model.Area.Item.GetString("Facebook_Site_Verification") : ""; 831 832 //Generic Site Values 833 string openGraphFacebookAppID = Model.Area.Item.GetString("Fb_app_id") != null ? Model.Area.Item.GetString("Fb_app_id") : ""; 834 string openGraphType = Model.Area.Item.GetString("Open_Graph_Type") != null ? Model.Area.Item.GetString("Open_Graph_Type") : ""; 835 string openGraphSiteName = Model.Area.Item.GetString("Open_Graph_Site_Name") != null ? Model.Area.Item.GetString("Open_Graph_Site_Name") : ""; 836 837 string twitterCardSite = Model.Area.Item.GetString("Twitter_Site") != null ? Model.Area.Item.GetString("Twitter_Site") : ""; 838 839 //Page specific values 840 string openGraphSiteTitle = Model.Area.Item.GetString("Open_Graph_Title") != null ? Model.Area.Item.GetString("Open_Graph_Title") : ""; 841 FileViewModel openGraphImage = Model.Area.Item.GetFile("Open_Graph_Image"); 842 string openGraphImageALT = Model.Area.Item.GetString("Open_Graph_Image_ALT") != null ? Model.Area.Item.GetString("Open_Graph_Image_ALT") : ""; 843 string openGraphDescription = Model.Area.Item.GetString("Open_Graph_Description") != null ? Model.Area.Item.GetString("Open_Graph_Description") : ""; 844 845 string twitterCardURL = Model.Area.Item.GetString("Twitter_URL") != null ? Model.Area.Item.GetString("Twitter_URL") : ""; 846 string twitterCardTitle = Model.Area.Item.GetString("Twitter_Title") != null ? Model.Area.Item.GetString("Twitter_Title") : ""; 847 string twitterCardDescription = Model.Area.Item.GetString("Twitter_Description") != null ? Model.Area.Item.GetString("Twitter_Description") : ""; 848 FileViewModel twitterCardImage = Model.Area.Item.GetFile("Twitter_Image"); 849 string twitterCardImageALT = Model.Area.Item.GetString("Twitter_Image_ALT") != null ? Model.Area.Item.GetString("Twitter_Image_ALT") : ""; 850 string topImage = Pageview.Page.TopImage.StartsWith("/Files", StringComparison.OrdinalIgnoreCase) ? Pageview.Page.TopImage : $"/Files{Pageview.Page.TopImage}"; 851 852 if (string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["ProductID"])) 853 { 854 if (!string.IsNullOrEmpty(Model.Description)) 855 { 856 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{Model.Description}\">"); 857 } 858 else 859 { 860 Pageview.Meta.AddTag($"<meta property=\"og:description\" content=\"{openGraphDescription}\">"); 861 } 862 863 if (!string.IsNullOrEmpty(Pageview.Page.TopImage)) 864 { 865 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">"); 866 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}\">"); 867 } 868 else if (openGraphImage != null) 869 { 870 Pageview.Meta.AddTag($"<meta property=\"og:image\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">"); 871 Pageview.Meta.AddTag($"<meta property=\"og:image:secure_url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}\">"); 872 } 873 874 if (!string.IsNullOrEmpty(openGraphImageALT)) 875 { 876 Pageview.Meta.AddTag($"<meta property=\"og:image:alt\" content=\"{openGraphImageALT}\">"); 877 } 878 if (!string.IsNullOrEmpty(twitterCardDescription)) 879 { 880 Pageview.Meta.AddTag("twitter:description", twitterCardDescription); 881 } 882 883 if (!string.IsNullOrEmpty(Pageview.Page.TopImage)) 884 { 885 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{topImage}"); 886 } 887 else if (twitterCardImage != null) 888 { 889 Pageview.Meta.AddTag("twitter:image", $"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{openGraphImage.Path}"); 890 } 891 892 if (!string.IsNullOrEmpty(twitterCardImageALT)) 893 { 894 Pageview.Meta.AddTag("twitter:image:alt", twitterCardImageALT); 895 } 896 } 897 898 if (!string.IsNullOrEmpty(siteVerificationGoogle)) 899 { 900 Pageview.Meta.AddTag("google-site-verification", siteVerificationGoogle); 901 } 902 903 if (!string.IsNullOrEmpty(siteVerificationFacebook)) 904 { 905 Pageview.Meta.AddTag("facebook-domain-verification", siteVerificationFacebook); 906 } 907 908 if (!string.IsNullOrEmpty(openGraphFacebookAppID)) 909 { 910 Pageview.Meta.AddTag($"<meta property=\"fb:app_id\" content=\"{openGraphFacebookAppID}\">"); 911 } 912 913 if (!string.IsNullOrEmpty(openGraphType)) 914 { 915 Pageview.Meta.AddTag($"<meta property=\"og:type\" content=\"{openGraphType}\">"); 916 } 917 918 if (!string.IsNullOrEmpty(openGraphSiteName)) 919 { 920 Pageview.Meta.AddTag($"<meta property=\"og:url\" content=\"{Dynamicweb.Context.Current.Request.Url.Scheme}://{Dynamicweb.Context.Current.Request.Url.Host}{Pageview.SearchFriendlyUrl}\">"); 921 } 922 923 if (!string.IsNullOrEmpty(openGraphSiteName)) 924 { 925 Pageview.Meta.AddTag($"<meta property=\"og:site_name\" content=\"{openGraphSiteName}\">"); 926 } 927 928 if (!string.IsNullOrEmpty(Model.Title)) 929 { 930 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{Model.Title}\">"); 931 } 932 else 933 { 934 Pageview.Meta.AddTag($"<meta property=\"og:title\" content=\"{openGraphSiteTitle}\">"); 935 } 936 937 if (!string.IsNullOrEmpty(twitterCardSite)) 938 { 939 Pageview.Meta.AddTag("twitter:site", twitterCardSite); 940 } 941 942 if (!string.IsNullOrEmpty(twitterCardURL)) 943 { 944 Pageview.Meta.AddTag("twitter:url", twitterCardURL); 945 } 946 947 if (!string.IsNullOrEmpty(twitterCardTitle)) 948 { 949 Pageview.Meta.AddTag("twitter:title", twitterCardTitle); 950 } 951 } 952 } 953