Error executing template "Designs/Swift/_parsed/Swift_Page.parsed.cshtml"
System.ArgumentException: Page ID must be greater than 0, but it was 0
   at Dynamicweb.Core.Ensure.That[TException](Boolean condition, String message)
   at Dynamicweb.Content.ParagraphService.GetParagraphsByPageId(Int32 pageId, ParagraphSort sortBy)
   at Dynamicweb.Frontend.Content.GetParagraphs(Int32 pageId)
   at Dynamicweb.Frontend.Content.CreateGridContent(Int32 contentId, Boolean ignoreVisualEdit)
   at Dynamicweb.Frontend.Content.RenderExternalGrid(Int32 pageId, String container)
   at CompiledRazorTemplates.Dynamic.RazorEngine_6adc063d0d7344a6a3df61defcfe5822.Execute() in D:\dynamicweb.net\Solutions\Mennt\mennt.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\_parsed\Swift_Page.parsed.cshtml:line 374
   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()

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