Public Access
feat(bf): lead /odoo-black-friday/ with the homepage hero, move the Bootcamp box to the foot
- Hero is the homepage's (same markup/assets): slide-in city image + the server location selector below it that slides a chosen city in; headline adapted to the offer. - Order now: hero > location selector > deal (HOST27, $295 first year / $395 after, one-click product-4 buy with redirect=/coupon/HOST27?r=/shop/checkout) > trust bar > Black Friday FAQ > features + trial card > FAQ > pricing (buy section) > Bootcamp > footer. - Bootcamp box restored from webmaster/out/2026-11-02-bootcamp-box-removed-archive.md: heading, USD 595.00, mechanism line, deadline, CTA, its meta/og contribution, its JSON-LD Product entry and the FAQ answer are all back and consistent. - Excluded (no blog, no OCA modules, no Project Plan); no dangling refs. - New /static/black-friday.js = the homepage behaviours this page needs (root-relative image paths), with the blog/OCA/project-plan blocks removed. - Canonical URL unchanged; competitor QC 0 on the page.
This commit is contained in:
1 parent
e6f0b6a395
commit
0a493d4e10
2 files changed
+766
-98
No files matched your search
+340
-98
@@ -6,13 +6,13 @@
|
|||||||
<title>Odoo Black Friday 2026: $100 Off Your First Year</title>
|
<title>Odoo Black Friday 2026: $100 Off Your First Year</title>
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Black Friday 2026: $100 off your first year of managed Odoo Community hosting — $295 for year one, then $395 a year. The offer runs 16–30 November 2026."
|
content="Our Black Friday and Cyber Monday offers: $100 off your first year of hosting, and a Bootcamp place with a second hosted year. 16–30 Nov 2026."
|
||||||
/>
|
/>
|
||||||
<link rel="canonical" href="https://odoo4projects.com/odoo-black-friday/" />
|
<link rel="canonical" href="https://odoo4projects.com/odoo-black-friday/" />
|
||||||
<meta property="og:title" content="Odoo Black Friday 2026: $100 Off Your First Year" />
|
<meta property="og:title" content="Odoo Black Friday 2026: $100 Off Your First Year" />
|
||||||
<meta
|
<meta
|
||||||
property="og:description"
|
property="og:description"
|
||||||
content="Black Friday 2026: $100 off your first year of managed Odoo Community hosting — $295 for year one, then $395 a year. The offer runs 16–30 November 2026."
|
content="Our Black Friday and Cyber Monday offers: $100 off your first year of hosting, and a Bootcamp place with a second hosted year. 16–30 Nov 2026."
|
||||||
/>
|
/>
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:url" content="https://odoo4projects.com/odoo-black-friday/" />
|
<meta property="og:url" content="https://odoo4projects.com/odoo-black-friday/" />
|
||||||
@@ -21,13 +21,14 @@
|
|||||||
<meta property="og:image:height" content="630" />
|
<meta property="og:image:height" content="630" />
|
||||||
<meta
|
<meta
|
||||||
property="og:image:alt"
|
property="og:image:alt"
|
||||||
content="Black Friday 2026 poster: 'Black Friday — 16–30 November', 'Save $100 on Odoo hosting', with the Black Friday code HOST27."
|
content="Black Friday 2026 poster: 'Black Friday — 16–30 November', 'Save $100 on Odoo hosting' with a secret deal on the Bootcamp."
|
||||||
/>
|
/>
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
<meta name="twitter:image" content="https://odoo4projects.com/images/black-friday/bf2026-hosting-og.png" />
|
<meta name="twitter:image" content="https://odoo4projects.com/images/black-friday/bf2026-hosting-og.png" />
|
||||||
<link rel="icon" href="/images/favicon.ico" />
|
<link rel="icon" href="/images/favicon.ico" />
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
<link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin />
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap"
|
||||||
@@ -35,6 +36,13 @@
|
|||||||
onload="this.media='all'"
|
onload="this.media='all'"
|
||||||
/>
|
/>
|
||||||
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Marcellus&display=swap" /></noscript>
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||||
|
media="print"
|
||||||
|
onload="this.media='all'"
|
||||||
|
/>
|
||||||
|
<noscript><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" /></noscript>
|
||||||
<link rel="stylesheet" href="/style.css" media="print" onload="this.media='all'" />
|
<link rel="stylesheet" href="/style.css" media="print" onload="this.media='all'" />
|
||||||
<noscript><link rel="stylesheet" href="/style.css" /></noscript>
|
<noscript><link rel="stylesheet" href="/style.css" /></noscript>
|
||||||
<style>
|
<style>
|
||||||
@@ -51,84 +59,27 @@
|
|||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Top bar (page-scoped: the site has no global header) */
|
/* Language selector in the hero — copied from the homepage's inline critical CSS, because
|
||||||
.bf-topbar {
|
style.css does not carry the hero variant of the switcher slot. */
|
||||||
background: var(--midnight-2);
|
.hero .lang-switch-slot {
|
||||||
border-bottom: 1px solid var(--line-brass);
|
|
||||||
padding: 0.85rem 0;
|
|
||||||
}
|
|
||||||
.bf-topbar .container {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
justify-content: flex-end;
|
||||||
justify-content: space-between;
|
margin-bottom: 1rem;
|
||||||
gap: 1rem;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
}
|
||||||
.bf-brand {
|
.hero .lang-switch {
|
||||||
font-family: Marcellus, Georgia, serif;
|
color: rgba(255, 255, 255, 0.65);
|
||||||
font-size: 1.15rem;
|
|
||||||
letter-spacing: 0.04em;
|
|
||||||
color: #fff;
|
|
||||||
}
|
}
|
||||||
.bf-brand span {
|
.hero .lang-switch a:hover,
|
||||||
color: var(--brass);
|
.hero .lang-switch a:focus-visible {
|
||||||
}
|
|
||||||
.bf-topbar-links {
|
|
||||||
display: flex;
|
|
||||||
gap: 1.25rem;
|
|
||||||
font-size: 0.82rem;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
.bf-topbar-links a {
|
|
||||||
color: rgba(255, 255, 255, 0.7);
|
|
||||||
}
|
|
||||||
.bf-topbar-links a:hover {
|
|
||||||
color: var(--brass);
|
|
||||||
}
|
|
||||||
/* Language selector — slides into the top-bar row, right of the links, behind a hairline brass
|
|
||||||
divider. CI §1/§2: brass marks the active language; lang.js owns the markup. */
|
|
||||||
.bf-topbar .lang-switch-slot {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding-left: 1rem;
|
|
||||||
border-left: 1px solid rgba(201, 162, 39, 0.45);
|
|
||||||
}
|
|
||||||
.bf-topbar .lang-switch {
|
|
||||||
color: rgba(255, 255, 255, 0.7);
|
|
||||||
}
|
|
||||||
.bf-topbar .lang-switch a:hover,
|
|
||||||
.bf-topbar .lang-switch a:focus-visible {
|
|
||||||
color: var(--brass-bright);
|
color: var(--brass-bright);
|
||||||
}
|
}
|
||||||
.bf-topbar .lang-switch a[aria-current="true"] {
|
.hero .lang-switch a[aria-current="true"] {
|
||||||
color: var(--brass);
|
color: var(--brass);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
text-underline-offset: 3px;
|
text-underline-offset: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hero */
|
/* The offer boxes (Hosting, then Bootcamp at the foot of the page): one centred column. */
|
||||||
.bf-hero {
|
|
||||||
min-height: 0;
|
|
||||||
padding: 3.5rem 0 3rem;
|
|
||||||
}
|
|
||||||
.bf-hero .hero-sub {
|
|
||||||
max-width: 640px;
|
|
||||||
}
|
|
||||||
.bf-hero .hero-window {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
color: rgba(255, 255, 255, 0.78);
|
|
||||||
line-height: 1.6;
|
|
||||||
margin: 0 0 0.25rem;
|
|
||||||
}
|
|
||||||
.bf-hero .hero-deadline {
|
|
||||||
font-size: 0.95rem;
|
|
||||||
color: rgba(255, 255, 255, 0.6);
|
|
||||||
line-height: 1.6;
|
|
||||||
margin: 0 0 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* One offer box now: a single centred column, so removing the Bootcamp box leaves no empty
|
|
||||||
cell beside the Hosting card. Narrower than the old half-width card, centred on the page. */
|
|
||||||
.bf-box .container {
|
.bf-box .container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(0, 620px);
|
grid-template-columns: minmax(0, 620px);
|
||||||
@@ -405,7 +356,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn:focus-visible,
|
.btn:focus-visible,
|
||||||
.bf-topbar-links a:focus-visible,
|
|
||||||
.bf-links a:focus-visible {
|
.bf-links a:focus-visible {
|
||||||
outline: 3px solid var(--brass-bright);
|
outline: 3px solid var(--brass-bright);
|
||||||
outline-offset: 2px;
|
outline-offset: 2px;
|
||||||
@@ -434,11 +384,12 @@
|
|||||||
"@id": "https://odoo4projects.com/odoo-black-friday/",
|
"@id": "https://odoo4projects.com/odoo-black-friday/",
|
||||||
"url": "https://odoo4projects.com/odoo-black-friday/",
|
"url": "https://odoo4projects.com/odoo-black-friday/",
|
||||||
"name": "Odoo Black Friday 2026: $100 Off Your First Year",
|
"name": "Odoo Black Friday 2026: $100 Off Your First Year",
|
||||||
"description": "Black Friday 2026: $100 off your first year of managed Odoo Community hosting — $295 for year one, then $395 a year. The offer runs 16–30 November 2026.",
|
"description": "Our Black Friday and Cyber Monday offers: $100 off your first year of hosting, and a Bootcamp place with a second hosted year. 16–30 Nov 2026.",
|
||||||
"isPartOf": { "@id": "https://odoo4projects.com/#organization" },
|
"isPartOf": { "@id": "https://odoo4projects.com/#organization" },
|
||||||
"about": [
|
"about": [
|
||||||
{ "@type": "Thing", "name": "Odoo Black Friday" },
|
{ "@type": "Thing", "name": "Odoo Black Friday" },
|
||||||
{ "@type": "Thing", "name": "managed Odoo Community hosting" }
|
{ "@type": "Thing", "name": "managed Odoo Community hosting" },
|
||||||
|
{ "@type": "Thing", "name": "Odoo ERP automation Bootcamp" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -463,6 +414,21 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"@type": "Product",
|
||||||
|
"name": "Odoo ERP automation Bootcamp",
|
||||||
|
"description": "A ten-session live Bootcamp that ends with your business running on a working Odoo system: ten live Thursday sessions, 18:00–19:00 Central Time, starting Thursday 21 January 2027, with a year of hosted Odoo Community Edition included.",
|
||||||
|
"brand": { "@id": "https://odoo4projects.com/#organization" },
|
||||||
|
"offers": [
|
||||||
|
{
|
||||||
|
"@type": "Offer",
|
||||||
|
"name": "Odoo ERP automation Bootcamp — January 2027 cohort",
|
||||||
|
"price": "595.00",
|
||||||
|
"priceCurrency": "USD",
|
||||||
|
"url": "https://odoo4projects.com/odoo-erp-automation-bootcamp/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"@type": "FAQPage",
|
"@type": "FAQPage",
|
||||||
"mainEntity": [
|
"mainEntity": [
|
||||||
@@ -487,7 +453,7 @@
|
|||||||
"name": "Is the Bootcamp part of the Black Friday offer?",
|
"name": "Is the Bootcamp part of the Black Friday offer?",
|
||||||
"acceptedAnswer": {
|
"acceptedAnswer": {
|
||||||
"@type": "Answer",
|
"@type": "Answer",
|
||||||
"text": "No. This page covers the hosting offer only. The Bootcamp is a separate programme with its own page and its own campaign."
|
"text": "Yes. The Bootcamp's Black Friday offer is a second year of hosted Odoo Community Edition, on top of the one that is already included. It runs 16–30 November 2026, and the cohort is six seats."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -528,33 +494,49 @@
|
|||||||
<script defer src="/static/lang.js"></script>
|
<script defer src="/static/lang.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
|
<!-- Hero — copied from the homepage (index.html): same component, same behaviour. On load the
|
||||||
<div class="bf-topbar">
|
fastest server's city photo slides in with a "fits your location" label; the Location
|
||||||
|
Selector below slides any city into it on click. The headline and copy are adapted to the
|
||||||
|
Black Friday offer so the page leads with the deal; the stats row is the homepage's. -->
|
||||||
|
<section class="hero" id="hero">
|
||||||
|
<div class="hero-bg"></div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="bf-brand" href="/">ODOO4<span>projects</span></a>
|
|
||||||
<nav class="bf-topbar-links" aria-label="Page links">
|
|
||||||
<a href="/index.html#pricing">Plans & pricing</a>
|
|
||||||
<a href="/support.html">Support</a>
|
|
||||||
</nav>
|
|
||||||
<div data-lang-switcher class="lang-switch-slot"></div>
|
<div data-lang-switcher class="lang-switch-slot"></div>
|
||||||
|
<div class="hero-kicker">Black Friday 2026 · Fully Managed Odoo Community Hosting</div>
|
||||||
|
<h1>Odoo Hosting: <span>$100 Off</span> Your First Year</h1>
|
||||||
|
<p class="hero-sub">Black Friday 2026: $100 off your first year of managed Odoo Community hosting — $295 for year one, then $395 a year. Code HOST27, 16–30 November 2026.</p>
|
||||||
|
<div class="hero-stats">
|
||||||
|
<span class="hero-stat"><i class="fas fa-check-circle"></i> 6 global locations</span>
|
||||||
|
<span class="hero-stat"><i class="fas fa-check-circle"></i> Deploy in 5 min</span>
|
||||||
|
<span class="hero-stat"><i class="fas fa-check-circle"></i> AI support included</span>
|
||||||
|
<span class="hero-stat"><i class="fas fa-check-circle"></i> Instant backups</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Hero -->
|
|
||||||
<section class="hero bf-hero">
|
|
||||||
<div class="container">
|
|
||||||
<p class="hero-kicker">16–30 NOVEMBER 2026 · ONCE A YEAR</p>
|
|
||||||
<h1>Odoo Black Friday 2026</h1>
|
|
||||||
<p class="hero-sub">One Black Friday offer: $100 off your first year of hosting — $295 for year one, then $395 a year after that.</p>
|
|
||||||
<p class="hero-window">The window is 16–30 November 2026.</p>
|
|
||||||
<p class="hero-deadline">Last day to use it: Monday 30 November 2026.</p>
|
|
||||||
<div class="hero-actions">
|
<div class="hero-actions">
|
||||||
<a href="/index.html#trialCard" class="btn btn-brass btn-lg">Start the 30-day free trial</a>
|
<a href="#offer" class="btn btn-brass">See the Black Friday deal →</a>
|
||||||
|
<a href="#trialCard" class="btn btn-outline">Start the 30-day free trial</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- The Black Friday offer — one section, one box. The card is always open: the price and the
|
<!-- Location selector — the homepage's server banner. Picking a location slides that city's
|
||||||
|
photo into the hero above; the fastest server is chosen automatically on load. -->
|
||||||
|
<section class="server-banner" id="serverBanner">
|
||||||
|
<div class="container">
|
||||||
|
<div class="server-banner-header">
|
||||||
|
<span class="server-banner-kicker">Our Server Locations</span>
|
||||||
|
</div>
|
||||||
|
<div class="server-grid">
|
||||||
|
<div class="server-card"><div class="server-city">Amsterdam</div><div class="server-region">Netherlands</div></div>
|
||||||
|
<div class="server-card"><div class="server-city">Boston</div><div class="server-region">United States</div></div>
|
||||||
|
<div class="server-card"><div class="server-city">Manchester</div><div class="server-region">United Kingdom</div></div>
|
||||||
|
<div class="server-card"><div class="server-city">Mumbai</div><div class="server-region">India</div></div>
|
||||||
|
<div class="server-card"><div class="server-city">São Paulo</div><div class="server-region">Brazil</div></div>
|
||||||
|
<div class="server-card"><a class="server-city" href="/australia.html" title="Managed Odoo hosting in Australia — Sydney">Sydney</a><div class="server-region">Australia</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- The Black Friday offer — Hosting, On the Rise. The card is always open: the price and the
|
||||||
code are readable on arrival, with no reveal and no click. -->
|
code are readable on arrival, with no reveal and no click. -->
|
||||||
<section class="section-light bf-box" id="offer">
|
<section class="section-light bf-box" id="offer">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -585,7 +567,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- FAQ -->
|
<!-- Trust bar — the homepage's section#trust-bar -->
|
||||||
|
<section class="trust-bar" id="trust-bar">
|
||||||
|
<div class="container">
|
||||||
|
<p class="trust-label">Trusted by businesses worldwide</p>
|
||||||
|
<div class="partner-carousel-wrap">
|
||||||
|
<div class="partner-grid">
|
||||||
|
<!-- Trust Bar Partners (no duplicates - CSS animation handles seamless loop) -->
|
||||||
|
<a href="https://paraguayservice.com/" target="_blank" rel="noopener noreferrer" class="partner-item"><img src="/images/paraguayservice-favicon.png" alt="Paraguay Service" /><span>Paraguay Service</span></a>
|
||||||
|
<a href="https://estancia-agape.com/" target="_blank" rel="noopener noreferrer" class="partner-item"><img src="/images/estancia-agape-logo.png" alt="Estancia Agape" /><span>Estancia Agape</span></a>
|
||||||
|
<a href="https://kate-group.de/" target="_blank" rel="noopener noreferrer" class="partner-item"><img src="/images/kate-group-favicon.png" alt="KATE Group" /><span>KATE Group</span></a>
|
||||||
|
<a href="https://agilnova.de/" target="_blank" rel="noopener noreferrer" class="partner-item"><img src="/images/agilnova-favicon.png" alt="agilnova" /><span>agilnova</span></a>
|
||||||
|
<a href="https://006-002-bc5bb1cb-984d-42c3-8580-63439f4924c5.odoo4projects.com/" target="_blank" rel="noopener noreferrer" class="partner-item"><img src="/images/ramani-kenya-logo.png" alt="Ramani Kenya" /><span>Ramani Kenya</span></a>
|
||||||
|
<a href="https://startparaguay.net/" target="_blank" rel="noopener noreferrer" class="partner-item"><img src="/images/startparaguay-favicon.png" alt="Start Paraguay" /><span>Start Paraguay</span></a>
|
||||||
|
<a href="https://accelersales.com/" target="_blank" rel="noopener noreferrer" class="partner-item"><img src="/images/accelersales-logo.png" alt="AccellerSales" /><span>AccellerSales</span></a>
|
||||||
|
<a href="#pricing" class="partner-item" style="opacity:0.55"><img src="/images/your-company-logo.svg" alt="Your Company" /><span>Your Company</span></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Black Friday questions — the page's own deal FAQ (native details/summary, no JS). The
|
||||||
|
Bootcamp answer matches what the page now shows: the Bootcamp box is back, at the foot. -->
|
||||||
<section class="section-light" id="faq">
|
<section class="section-light" id="faq">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2 class="section-title">Black Friday questions</h2>
|
<h2 class="section-title">Black Friday questions</h2>
|
||||||
@@ -600,7 +603,7 @@
|
|||||||
</details>
|
</details>
|
||||||
<details class="cmp-faq">
|
<details class="cmp-faq">
|
||||||
<summary class="plausible-event-name=FAQ">Is the Bootcamp part of the Black Friday offer?</summary>
|
<summary class="plausible-event-name=FAQ">Is the Bootcamp part of the Black Friday offer?</summary>
|
||||||
<div class="faq-a"><p>No. This page covers the hosting offer only. The Bootcamp is a separate programme with its own page and its own campaign.</p></div>
|
<div class="faq-a"><p>Yes. The Bootcamp's Black Friday offer is a second year of hosted Odoo Community Edition, on top of the one that is already included. It runs 16–30 November 2026, and the cohort is six seats.</p></div>
|
||||||
</details>
|
</details>
|
||||||
<details class="cmp-faq">
|
<details class="cmp-faq">
|
||||||
<summary class="plausible-event-name=FAQ">What does On the Rise cost in the offer?</summary>
|
<summary class="plausible-event-name=FAQ">What does On the Rise cost in the offer?</summary>
|
||||||
@@ -617,13 +620,249 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="bf-links" aria-label="Related pages">
|
<nav class="bf-links" aria-label="Related pages">
|
||||||
|
<a href="/odoo-hosting-offers/">Everything a year of hosting includes</a>
|
||||||
<a href="/odoo-hosting-2027.html">Odoo hosting in 2027, compared</a>
|
<a href="/odoo-hosting-2027.html">Odoo hosting in 2027, compared</a>
|
||||||
<a href="/blog/posts/community-vs-enterprise-cost.html">What Community costs compared with Enterprise</a>
|
<a href="#trialCard">Start the 30-day free trial</a>
|
||||||
<a href="/index.html#trialCard">Start the 30-day free trial</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Features + free-trial card — the homepage's section -->
|
||||||
|
<section class="section-light">
|
||||||
|
<div class="container">
|
||||||
|
<h2 class="section-title">Everything you need, nothing you don't</h2>
|
||||||
|
<div class="features-grid">
|
||||||
|
<div class="feature-card">
|
||||||
|
<i class="fas fa-rocket"></i>
|
||||||
|
<h3>5-Minute Deployment</h3>
|
||||||
|
<p>No DevOps team needed. Pick a plan, choose your region, and your Odoo instance is live in minutes.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<i class="fas fa-shield-alt"></i>
|
||||||
|
<h3>Automatic Backups & SSL</h3>
|
||||||
|
<p>Backups run on a schedule and are kept in rotating slots — one on Side Hustle, four on On the Rise and Powerhouse. Free SSL certificates on every domain — always secure.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<i class="fas fa-cubes"></i>
|
||||||
|
<h3>Management Within Odoo</h3>
|
||||||
|
<p>The one-stop shop for your entire business. No need for several accounts — manage your applications, users, and modules from one control panel.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<i class="fas fa-code-branch"></i>
|
||||||
|
<h3>Git-Based Module Deployment</h3>
|
||||||
|
<p>Push custom modules via Git or use one-click Quick Git. No FTP, no hassle.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card">
|
||||||
|
<i class="fas fa-headset"></i>
|
||||||
|
<h3>Support Bot & Human Support</h3>
|
||||||
|
<p>AI support bot for instant fixes. Human team for everything else. Your UUID is your key.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature-card-trial" id="trialCard">
|
||||||
|
<h3>Free Trial</h3>
|
||||||
|
<p>Start your 30-day free trial. No credit card required.</p>
|
||||||
|
<form class="trial-form" id="trialForm">
|
||||||
|
<input type="email" id="trialEmail" placeholder="Your email address" required />
|
||||||
|
<select id="trialLocation"></select>
|
||||||
|
<button type="submit" class="btn btn-brass">Send</button>
|
||||||
|
</form>
|
||||||
|
<div class="trial-success" id="trialSuccess">✓ Check your inbox to confirm your email address.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- FAQ — the homepage's section -->
|
||||||
|
<section class="section-dark" id="faq-general">
|
||||||
|
<div class="container">
|
||||||
|
<h2 class="section-title">Frequently asked questions</h2>
|
||||||
|
<div class="faq-grid">
|
||||||
|
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||||
|
<div class="faq-q"><span>What if I outgrow my plan?</span> <i class="fas fa-chevron-down"></i></div>
|
||||||
|
<div class="faq-a"><p>Grow from Side Hustle to Empire without data migration or downtime. Upgrade in your Odoo Settings panel — your instance stays live, your data moves with you.</p></div>
|
||||||
|
</div>
|
||||||
|
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||||
|
<div class="faq-q"><span>Can I customize it?</span> <i class="fas fa-chevron-down"></i></div>
|
||||||
|
<div class="faq-a"><p>Yes. On the Rise and above support Git-based modules. Install custom apps, build your own, or use Quick GIT for one-click installs.</p></div>
|
||||||
|
</div>
|
||||||
|
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||||
|
<div class="faq-q"><span>How fast can I get started?</span> <i class="fas fa-chevron-down"></i></div>
|
||||||
|
<div class="faq-a"><p>Five minutes. Pick a plan, choose your region — your Odoo instance is live. No setup fee. Stripe payment. Cancel anytime.</p></div>
|
||||||
|
</div>
|
||||||
|
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||||
|
<div class="faq-q"><span>Can I run Odoo Enterprise?</span> <i class="fas fa-chevron-down"></i></div>
|
||||||
|
<div class="faq-a"><p>Powerhouse and Empire are Enterprise-ready. Bring your license; we provide the infrastructure.</p></div>
|
||||||
|
</div>
|
||||||
|
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||||
|
<div class="faq-q"><span>ODOO Community? What can it do?</span> <i class="fas fa-chevron-down"></i></div>
|
||||||
|
<div class="faq-a"><p>Inventory, accounting, CRM, sales, manufacturing, HR — all in one system. Free and fully open-source. <a href="/what-can-i-use-odoo-for/">What you can use Odoo for, in plain English</a>.</p></div>
|
||||||
|
</div>
|
||||||
|
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||||
|
<div class="faq-q"><span>Do you need an Odoo staging environment?</span> <i class="fas fa-chevron-down"></i></div>
|
||||||
|
<div class="faq-a"><p>Most small businesses do not. If you change Odoo's code you do; if you install a finished module, a backup and a careful test is enough. <a href="/odoo-staging-environment/">Do you need an Odoo staging environment?</a></p></div>
|
||||||
|
</div>
|
||||||
|
<div class="faq-card plausible-event-name=FAQ" onclick="this.classList.toggle('open')">
|
||||||
|
<div class="faq-q"><span>Do you have an affiliate program?</span> <i class="fas fa-chevron-down"></i></div>
|
||||||
|
<div class="faq-a"><p>No. We believe it is in our best interest to have competitive prices for our shared clients.</p></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a href="/support.html" class="faq-link">Full FAQ →</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Pricing / buy section — the homepage's section -->
|
||||||
|
<section class="section-dark" id="pricing">
|
||||||
|
<div class="container">
|
||||||
|
<p class="section-kicker">Order & Pricing</p>
|
||||||
|
<h2 class="section-title">Your Plan, Your Timing: Upgrade Anytime</h2>
|
||||||
|
<div class="pricing-server-row">
|
||||||
|
<label for="pricingServerLocation">Server Location</label>
|
||||||
|
<select id="pricingServerLocation" class="pricing-server-select"></select>
|
||||||
|
<label for="pricingOdooVersion">Odoo Version</label>
|
||||||
|
<select id="pricingOdooVersion" class="pricing-server-select">
|
||||||
|
<option value="19.0">19.0 — Tons of OCA supported modules</option>
|
||||||
|
<option value="20.0" selected>20.0 — Latest Greatest</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="pricing-grid">
|
||||||
|
<!-- Side Hustle -->
|
||||||
|
<div class="pcard">
|
||||||
|
<div class="pcard-body">
|
||||||
|
<h3>Side Hustle</h3>
|
||||||
|
<div class="price">
|
||||||
|
<strong>$ 214.00</strong>
|
||||||
|
<small class="price-period">/ year</small>
|
||||||
|
</div>
|
||||||
|
<p class="desc">"ODOO Standard .. that is all my business needs"</p>
|
||||||
|
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="6">Buy Now</a>
|
||||||
|
<ul>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> Launch Odoo CE in 5 minutes</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> Automatic backups — no remembering</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> 1 domain & SSL cert</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="pcard-foot">No setup fee. Stripe Payment<br />Cancel at any time</div>
|
||||||
|
</div>
|
||||||
|
<!-- On the Rise -->
|
||||||
|
<div class="pcard featured">
|
||||||
|
<div class="pcard-body">
|
||||||
|
<h3>On the Rise</h3>
|
||||||
|
<div class="price">
|
||||||
|
<strong>$ 395.00</strong>
|
||||||
|
<small class="price-period">/ year</small>
|
||||||
|
</div>
|
||||||
|
<p class="desc">"I need some modules and professional reports"</p>
|
||||||
|
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="4">Buy Now</a>
|
||||||
|
<ul>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> Launch Odoo CE in 5 minutes</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> Automatic backups — no remembering</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> 3 domains & SSL certs</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> Install custom modules via Git/QuickGIT</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="pcard-foot">No setup fee. Stripe Payment<br />Cancel at any time</div>
|
||||||
|
</div>
|
||||||
|
<!-- Powerhouse -->
|
||||||
|
<div class="pcard">
|
||||||
|
<div class="pcard-body">
|
||||||
|
<h3>Powerhouse</h3>
|
||||||
|
<div class="price">
|
||||||
|
<strong>$ 595.00</strong>
|
||||||
|
<small class="price-period">/ year</small>
|
||||||
|
</div>
|
||||||
|
<p class="desc">"ODOO Enterprise is a must have!"</p>
|
||||||
|
<a href="javascript:void(0)" class="btn btn-brass btn-buy plausible-event-name=Buy" data-id="5">Buy Now</a>
|
||||||
|
<ul>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> Launch Odoo CE in 5 minutes</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> Automatic backups — no remembering</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> 3 domains & SSL certs</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> Install custom modules via Git/QuickGIT</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> 2 workers for reliability</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="pcard-foot">No setup fee. Stripe Payment<br />Cancel at any time</div>
|
||||||
|
</div>
|
||||||
|
<!-- Empire -->
|
||||||
|
<div class="pcard">
|
||||||
|
<div class="pcard-body">
|
||||||
|
<h3>Empire</h3>
|
||||||
|
<div class="price">
|
||||||
|
<strong>>$ 950.00</strong>
|
||||||
|
<small class="price-period">/ year</small>
|
||||||
|
</div>
|
||||||
|
<p class="desc">"My house! My Horse! My Server!"</p>
|
||||||
|
<a href="javascript:void(0)" class="btn btn-brass btn-empire">Get Custom Quote</a>
|
||||||
|
<ul>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> Our service on your server</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> All modules & features</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> Unlimited customization</li>
|
||||||
|
<li><i class="fas fa-check" style="color: var(--success)"></i> Priority support & dedicated onboarding</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="pricing-cta-note">Save money, less administration</p>
|
||||||
|
<p class="pricing-cta-note"><a href="/odoo-hosting-2027.html"><strong>Compare every way to host Odoo in 2027 →</strong></a></p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Custom Quote Modal — the homepage's modal (Empire CTA) -->
|
||||||
|
<div id="customQuoteModal" class="ow-overlay" onclick="if(event.target===this)closeCustomQuoteModal()">
|
||||||
|
<div id="customQuotePanel" class="ow-panel" style="display:none">
|
||||||
|
<button class="ow-close" onclick="closeCustomQuoteModal()">×</button>
|
||||||
|
<div class="ow-content">
|
||||||
|
<h2 class="ow-title">Get Custom Quote</h2>
|
||||||
|
<p class="ow-sub">Tell us about your needs and we'll prepare a tailored offer.</p>
|
||||||
|
<form id="customQuoteForm" class="biz-form" style="text-align:left">
|
||||||
|
<div class="biz-field">
|
||||||
|
<label for="cqName">Name</label>
|
||||||
|
<input type="text" id="cqName" placeholder="Your full name" required />
|
||||||
|
</div>
|
||||||
|
<div class="biz-field">
|
||||||
|
<label for="cqEmail">Email</label>
|
||||||
|
<input type="email" id="cqEmail" placeholder="your@email.com" required />
|
||||||
|
</div>
|
||||||
|
<div class="biz-field">
|
||||||
|
<label for="cqRequirements">Your Requirements</label>
|
||||||
|
<textarea id="cqRequirements" placeholder="Describe your requirements (how many users? onsite, cloud? how many workers?)" required></textarea>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-brass btn-lg">Submit Request</button>
|
||||||
|
</form>
|
||||||
|
<div class="biz-success" id="customQuoteSuccess" style="display:none">
|
||||||
|
<i class="fas fa-check-circle"></i>
|
||||||
|
<h3>Request received</h3>
|
||||||
|
<p>We'll review your requirements and get back to you shortly.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- The Bootcamp offer — restored from the 2026-11-02 archive (webmaster/out/
|
||||||
|
2026-11-02-bootcamp-box-removed-archive.md) and moved here, to the foot of the page:
|
||||||
|
the last content section before the footer. Heading, USD 595.00 price, mechanism line,
|
||||||
|
deadline and CTA are exactly as archived. -->
|
||||||
|
<section class="section-light bf-box" id="bootcamp">
|
||||||
|
<div class="container">
|
||||||
|
<!-- Box — Bootcamp -->
|
||||||
|
<div class="bf-box-inner">
|
||||||
|
<h2 class="bf-box-title">Bootcamp: ten live sessions to a working system</h2>
|
||||||
|
<div class="bf-panel">
|
||||||
|
<p class="bf-teaser">A working system for your business in ten live sessions, USD 595 — with a second hosted year added for Black Friday.</p>
|
||||||
|
<p class="bf-price"><strong>USD 595.00</strong> for the full programme. Black Friday adds <strong>a second year of hosted Odoo Community Edition</strong>, on top of the one already included.</p>
|
||||||
|
<p class="bf-included">Ten live Thursday sessions, 18:00–19:00 Central Time, starting Thursday 21 January 2027. Six seats, and no more. Your first hosted year is included as standard; the second year is the Black Friday add-on.</p>
|
||||||
|
<!-- Bootcamp mechanism string — ONE reusable line, isolated exactly as the Hosting box's is
|
||||||
|
(copy §3b). Whether the discount code applies to the Bootcamp is UNCONFIRMED
|
||||||
|
(BOOTCAMP-CONFIRM), so the discounted figure stays a build placeholder and is NOT
|
||||||
|
printed. Swap this one line when it is confirmed. -->
|
||||||
|
<p class="bf-mechanism">Black Friday: <strong>a second year of hosted Odoo Community Edition</strong>. One redemption per customer.<!-- OPEN-SLOT: bootcamp Black Friday price line --></p>
|
||||||
|
<p class="bf-deadline">Ends Monday 30 November 2026.</p>
|
||||||
|
<!-- Buy = CLICK PROXY (offer-CTA click), NOT a sale. The real purchase event is fired on the
|
||||||
|
checkout host (20.odoo4projects.com) by odoo-dev. See wiki/concepts/conversion-tracking-contract. -->
|
||||||
|
<p class="bf-cta"><a class="plausible-event-name=Buy" href="/odoo-erp-automation-bootcamp/">See the Bootcamp and what you build</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
<!-- Footer (copied from index.html; icon-font glyphs replaced with inline SVG so the page
|
||||||
carries no external icon dependency) -->
|
carries no external icon dependency) -->
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
@@ -672,5 +911,8 @@
|
|||||||
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
<div class="fcopy">Copyright © ODOO4projects LLC</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
|
||||||
|
<script defer src="/static/black-friday.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -0,0 +1,426 @@
|
|||||||
|
/* Page-local script for /odoo-black-friday/.
|
||||||
|
The homepage behaviours this landing page needs, copied from the site's /script.js:
|
||||||
|
the hero slide-in image driven by the server-location selector, the Buy Now buttons,
|
||||||
|
the free-trial card, the Custom Quote modal and the footer contact form.
|
||||||
|
The blog, OCA-modules and project-plan blocks of /script.js are removed here because this
|
||||||
|
page does not carry those sections (and those blocks throw on a page without their markup).
|
||||||
|
Image paths are root-relative: this page lives in a subdirectory (/odoo-black-friday/).
|
||||||
|
ES5, no build step, no new dependency beyond the gsap the homepage already loads. */
|
||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/* ---- UTM tracking helpers (verbatim from /script.js) ---- */
|
||||||
|
(function () {
|
||||||
|
function getCookie(name) {
|
||||||
|
var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
|
||||||
|
return match ? decodeURIComponent(match[2]) : null;
|
||||||
|
}
|
||||||
|
function setCookie(name, value, days) {
|
||||||
|
var expires = '';
|
||||||
|
if (days) {
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||||
|
expires = '; expires=' + date.toUTCString();
|
||||||
|
}
|
||||||
|
document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/; SameSite=Lax';
|
||||||
|
}
|
||||||
|
function parseUTM() {
|
||||||
|
var urlParams = new URLSearchParams(window.location.search);
|
||||||
|
var utm = {};
|
||||||
|
var keys = ['source', 'medium', 'campaign'];
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var val = urlParams.get('utm_' + keys[i]);
|
||||||
|
if (val) {
|
||||||
|
utm[keys[i]] = val;
|
||||||
|
setCookie('utm_' + keys[i], val, 90);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return utm;
|
||||||
|
}
|
||||||
|
function getStoredUTM() {
|
||||||
|
var utm = {};
|
||||||
|
var keys = ['source', 'medium', 'campaign'];
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
var val = getCookie('utm_' + keys[i]);
|
||||||
|
if (val) utm[keys[i]] = val;
|
||||||
|
}
|
||||||
|
return utm;
|
||||||
|
}
|
||||||
|
function injectUTM(data) {
|
||||||
|
var stored = getStoredUTM();
|
||||||
|
if (Object.keys(stored).length > 0) {
|
||||||
|
data.utm_source = stored.source || null;
|
||||||
|
data.utm_medium = stored.medium || null;
|
||||||
|
data.utm_campaign = stored.campaign || null;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
function appendToForm(form) {
|
||||||
|
var stored = getStoredUTM();
|
||||||
|
var keys = ['source', 'medium', 'campaign'];
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
if (stored[keys[i]]) {
|
||||||
|
var input = document.createElement('input');
|
||||||
|
input.type = 'hidden';
|
||||||
|
input.name = 'utm_' + keys[i];
|
||||||
|
input.value = stored[keys[i]];
|
||||||
|
form.appendChild(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function toQuery() {
|
||||||
|
var stored = getStoredUTM();
|
||||||
|
var parts = [];
|
||||||
|
var keys = ['source', 'medium', 'campaign'];
|
||||||
|
for (var i = 0; i < keys.length; i++) {
|
||||||
|
if (stored[keys[i]]) {
|
||||||
|
parts.push('utm_' + keys[i] + '=' + encodeURIComponent(stored[keys[i]]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parts.join('&');
|
||||||
|
}
|
||||||
|
window.UTM = { parse: parseUTM, getStored: getStoredUTM, inject: injectUTM, appendToForm: appendToForm, toQuery: toQuery };
|
||||||
|
window.UTM.parse();
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* ---- Hero slide-in image + server-location selector (homepage behaviour) ---- */
|
||||||
|
(function () {
|
||||||
|
var SERVERS = [
|
||||||
|
{ host: 'api.meppel.odoo4projects.com', city: 'Amsterdam' },
|
||||||
|
{ host: 'api.boston.odoo4projects.com', city: 'Boston' },
|
||||||
|
{ host: 'api.manchester.odoo4projects.com', city: 'Manchester' },
|
||||||
|
{ host: 'api.mumbai.odoo4projects.com', city: 'Mumbai' },
|
||||||
|
{ host: 'api.saopaulo.odoo4projects.com', city: 'S\u00e3o Paulo' },
|
||||||
|
{ host: 'api.sydney.odoo4projects.com', city: 'Sydney' }
|
||||||
|
];
|
||||||
|
/* Root-relative on purpose: this page is served from /odoo-black-friday/. */
|
||||||
|
var heroImages = {
|
||||||
|
'api.meppel.odoo4projects.com': '/images/hero/amsterdam.webp',
|
||||||
|
'api.boston.odoo4projects.com': '/images/hero/boston.webp',
|
||||||
|
'api.manchester.odoo4projects.com': '/images/hero/london.webp',
|
||||||
|
'api.mumbai.odoo4projects.com': '/images/hero/mumbai.webp',
|
||||||
|
'api.saopaulo.odoo4projects.com': '/images/hero/brazil.webp',
|
||||||
|
'api.sydney.odoo4projects.com': '/images/hero/sydney.webp'
|
||||||
|
};
|
||||||
|
|
||||||
|
function pingServer(host) {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
var start = performance.now();
|
||||||
|
var img = new Image();
|
||||||
|
var timedOut = false;
|
||||||
|
var timer = setTimeout(function () {
|
||||||
|
timedOut = true; img.src = '';
|
||||||
|
resolve({ host: host, time: -1 });
|
||||||
|
}, 2000);
|
||||||
|
img.onload = function () {
|
||||||
|
var elapsed = performance.now() - start;
|
||||||
|
if (!timedOut) { clearTimeout(timer); resolve({ host: host, time: elapsed }); }
|
||||||
|
};
|
||||||
|
img.onerror = function () {
|
||||||
|
var elapsed = performance.now() - start;
|
||||||
|
if (!timedOut) { clearTimeout(timer); resolve({ host: host, time: elapsed }); }
|
||||||
|
};
|
||||||
|
img.src = 'https://' + host + '/favicon.ico?_=' + Date.now() + '_' + Math.random().toString(36).slice(2, 6);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function animateHero(city, image, showLabel) {
|
||||||
|
var hero = document.querySelector('.hero');
|
||||||
|
if (!hero || !window.gsap) return;
|
||||||
|
var bg = hero.querySelector('.hero-bg');
|
||||||
|
if (!bg) {
|
||||||
|
bg = document.createElement('div');
|
||||||
|
bg.className = 'hero-bg';
|
||||||
|
hero.insertBefore(bg, hero.firstChild);
|
||||||
|
}
|
||||||
|
var hasExisting = bg.children.length > 0;
|
||||||
|
var newEl = document.createElement('div');
|
||||||
|
newEl.className = 'hero-bg-slide';
|
||||||
|
newEl.style.backgroundImage = "url('" + image + "')";
|
||||||
|
bg.appendChild(newEl);
|
||||||
|
|
||||||
|
var tl = gsap.timeline();
|
||||||
|
gsap.set(newEl, { x: '100%' });
|
||||||
|
|
||||||
|
var label = null;
|
||||||
|
if (showLabel !== false && city) {
|
||||||
|
var oldLabel = hero.querySelector('.hero-city-label');
|
||||||
|
if (oldLabel) oldLabel.remove();
|
||||||
|
label = document.createElement('div');
|
||||||
|
label.className = 'hero-city-label';
|
||||||
|
label.innerHTML = 'Our <strong>' + city + '</strong> server fits your location';
|
||||||
|
hero.appendChild(label);
|
||||||
|
gsap.set(label, { x: '150%' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasExisting) {
|
||||||
|
var oldEl = bg.children[0];
|
||||||
|
gsap.set(oldEl, { x: '0%' });
|
||||||
|
tl.to(oldEl, { x: '100%', duration: 3, ease: 'power2.out' }, 0)
|
||||||
|
.to(newEl, { x: '0%', duration: 3, ease: 'power2.out' }, 0);
|
||||||
|
if (label) {
|
||||||
|
tl.to(label, { x: '0%', duration: 2.5, ease: 'power2.out' }, 0.3);
|
||||||
|
}
|
||||||
|
tl.call(function () { oldEl.remove(); });
|
||||||
|
} else {
|
||||||
|
tl.to(newEl, { x: '0%', duration: 3, ease: 'power2.out' }, 0);
|
||||||
|
if (label) {
|
||||||
|
tl.to(label, { x: '0%', duration: 2.5, ease: 'power2.out' }, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Location selector: click a server card to slide its city into the hero. */
|
||||||
|
var serverCards = document.querySelectorAll('.server-card');
|
||||||
|
serverCards.forEach(function (card, idx) {
|
||||||
|
card.addEventListener('click', function () {
|
||||||
|
var s = SERVERS[idx];
|
||||||
|
if (!s || !heroImages[s.host]) return;
|
||||||
|
serverCards.forEach(function (c) { c.classList.remove('server-best'); });
|
||||||
|
card.classList.add('server-best');
|
||||||
|
animateHero(null, heroImages[s.host], false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Populate the trial + pricing location selects. */
|
||||||
|
var trialLoc = document.getElementById('trialLocation');
|
||||||
|
var pricingLoc = document.getElementById('pricingServerLocation');
|
||||||
|
[trialLoc, pricingLoc].forEach(function (el) {
|
||||||
|
if (el) {
|
||||||
|
SERVERS.forEach(function (s) {
|
||||||
|
var opt = document.createElement('option');
|
||||||
|
var cityVal = s.host.replace('api.', '').replace('.odoo4projects.com', '');
|
||||||
|
opt.value = cityVal;
|
||||||
|
opt.textContent = s.city;
|
||||||
|
el.appendChild(opt);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Ping all servers, highlight the fastest, slide its image in. */
|
||||||
|
var results = [];
|
||||||
|
var pending = SERVERS.length;
|
||||||
|
SERVERS.forEach(function (s) {
|
||||||
|
pingServer(s.host).then(function (r) {
|
||||||
|
results.push(r);
|
||||||
|
pending--;
|
||||||
|
if (pending !== 0) return;
|
||||||
|
var valid = results.filter(function (x) { return x.time >= 0; });
|
||||||
|
if (valid.length === 0) return;
|
||||||
|
valid.sort(function (a, b) { return a.time - b.time; });
|
||||||
|
var best = valid[0];
|
||||||
|
var bestServer = SERVERS.filter(function (x) { return x.host === best.host; })[0];
|
||||||
|
if (bestServer) {
|
||||||
|
[trialLoc, pricingLoc].forEach(function (el) {
|
||||||
|
if (el) {
|
||||||
|
var cityVal = bestServer.host.replace('api.', '').replace('.odoo4projects.com', '');
|
||||||
|
for (var i = 0; i < el.options.length; i++) {
|
||||||
|
if (el.options[i].value === cityVal) { el.selectedIndex = i; break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (bestServer && heroImages[best.host]) {
|
||||||
|
var cards = document.querySelectorAll('.server-card');
|
||||||
|
for (var i = 0; i < SERVERS.length && i < cards.length; i++) {
|
||||||
|
if (SERVERS[i].host === best.host) { cards[i].classList.add('server-best'); break; }
|
||||||
|
}
|
||||||
|
var img = new Image();
|
||||||
|
img.onload = function () { animateHero(bestServer.city, heroImages[best.host]); };
|
||||||
|
img.src = heroImages[best.host];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Free-trial card. */
|
||||||
|
var trialForm = document.getElementById('trialForm');
|
||||||
|
if (trialForm) {
|
||||||
|
trialForm.addEventListener('submit', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var email = document.getElementById('trialEmail').value.trim();
|
||||||
|
var location = trialLoc ? trialLoc.value : '';
|
||||||
|
if (!email) return;
|
||||||
|
var btn = trialForm.querySelector('.btn-brass');
|
||||||
|
btn.textContent = 'Sending...';
|
||||||
|
btn.disabled = true;
|
||||||
|
fetch('https://n8n.odoo4projects.com/webhook/ODOO4projects/trial', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(UTM.inject({ email: email, location: location }))
|
||||||
|
}).then(function () {
|
||||||
|
if (window.plausible) window.plausible('Trial');
|
||||||
|
trialForm.style.display = 'none';
|
||||||
|
document.getElementById('trialSuccess').classList.add('visible');
|
||||||
|
}).catch(function () {
|
||||||
|
btn.textContent = 'Send';
|
||||||
|
btn.disabled = false;
|
||||||
|
var errorMsg = document.createElement('div');
|
||||||
|
errorMsg.className = 'trial-error visible';
|
||||||
|
errorMsg.textContent = 'Something went wrong. Please try again.';
|
||||||
|
trialForm.appendChild(errorMsg);
|
||||||
|
setTimeout(function () { errorMsg.classList.remove('visible'); }, 3000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* ---- Buy Now — POST the basket straight to the shop, open checkout in a new tab ---- */
|
||||||
|
window.buyNow = function (productId) {
|
||||||
|
var locSelect = document.getElementById('pricingServerLocation');
|
||||||
|
var location = locSelect ? locSelect.value : '';
|
||||||
|
var verSelect = document.getElementById('pricingOdooVersion');
|
||||||
|
var version = verSelect ? verSelect.value : '';
|
||||||
|
var form = document.createElement('form');
|
||||||
|
form.method = 'POST';
|
||||||
|
form.action = 'https://20.odoo4projects.com/shop/post_basket';
|
||||||
|
form.target = '_blank';
|
||||||
|
form.style.display = 'none';
|
||||||
|
var basket = document.createElement('input');
|
||||||
|
basket.type = 'hidden';
|
||||||
|
basket.name = 'basket';
|
||||||
|
var item = { product_id: productId, qty: 1 };
|
||||||
|
var info = location ? location.replace('.odoo4projects.com', '') : '';
|
||||||
|
if (version) { info += (info ? '|' : '') + version; }
|
||||||
|
if (info) { item.info = info; }
|
||||||
|
basket.value = JSON.stringify([item]);
|
||||||
|
form.appendChild(basket);
|
||||||
|
var clear = document.createElement('input');
|
||||||
|
clear.type = 'hidden';
|
||||||
|
clear.name = 'clear';
|
||||||
|
clear.value = '1';
|
||||||
|
form.appendChild(clear);
|
||||||
|
UTM.appendToForm(form);
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
document.body.removeChild(form);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ---- Buy buttons + Custom Quote modal ---- */
|
||||||
|
(function () {
|
||||||
|
document.querySelectorAll('.btn-buy').forEach(function (btn) {
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
var id = this.getAttribute('data-id');
|
||||||
|
if (id) buyNow(parseInt(id, 10));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function openCustomQuoteModal() {
|
||||||
|
document.getElementById('customQuotePanel').style.display = 'block';
|
||||||
|
document.getElementById('customQuoteModal').style.display = 'flex';
|
||||||
|
}
|
||||||
|
function closeCustomQuoteModal() {
|
||||||
|
document.getElementById('customQuoteModal').style.display = 'none';
|
||||||
|
document.getElementById('customQuoteForm').reset();
|
||||||
|
document.getElementById('customQuoteSuccess').style.display = 'none';
|
||||||
|
}
|
||||||
|
window.openCustomQuoteModal = openCustomQuoteModal;
|
||||||
|
window.closeCustomQuoteModal = closeCustomQuoteModal;
|
||||||
|
|
||||||
|
document.querySelectorAll('.btn-empire').forEach(function (btn) {
|
||||||
|
btn.addEventListener('click', function () { openCustomQuoteModal(); });
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
var modal = document.getElementById('customQuoteModal');
|
||||||
|
if (modal && modal.style.display === 'flex') { closeCustomQuoteModal(); }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var customQuoteForm = document.getElementById('customQuoteForm');
|
||||||
|
if (customQuoteForm) {
|
||||||
|
customQuoteForm.addEventListener('submit', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var name = document.getElementById('cqName').value.trim();
|
||||||
|
var email = document.getElementById('cqEmail').value.trim();
|
||||||
|
var requirements = document.getElementById('cqRequirements').value.trim();
|
||||||
|
if (!name || !email || !requirements) return;
|
||||||
|
var submitBtn = customQuoteForm.querySelector('.btn-lg');
|
||||||
|
submitBtn.textContent = 'Sending...';
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
fetch('https://n8n.odoo4projects.com/webhook/ODOO4projects/crm', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(UTM.inject({ name: name, email: email, requirements: requirements, area: 'quote' }))
|
||||||
|
}).then(function (r) {
|
||||||
|
if (!r.ok) throw new Error('bad status ' + r.status);
|
||||||
|
if (window.plausible) window.plausible('Custom Quote');
|
||||||
|
customQuoteForm.style.display = 'none';
|
||||||
|
document.getElementById('customQuoteSuccess').style.display = 'block';
|
||||||
|
submitBtn.textContent = 'Submit Request';
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
}).catch(function () {
|
||||||
|
submitBtn.textContent = 'Submit Request';
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
var errorMsg = document.createElement('div');
|
||||||
|
errorMsg.style.marginTop = '1rem';
|
||||||
|
errorMsg.style.color = '#dc3545';
|
||||||
|
errorMsg.textContent = 'Something went wrong. Please try again.';
|
||||||
|
customQuoteForm.appendChild(errorMsg);
|
||||||
|
setTimeout(function () { if (errorMsg.parentNode) errorMsg.parentNode.removeChild(errorMsg); }, 3000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* ---- Footer contact form ---- */
|
||||||
|
(function () {
|
||||||
|
var form = document.getElementById('footerContactForm');
|
||||||
|
if (!form) return;
|
||||||
|
var emailInput = document.getElementById('footerContactEmail');
|
||||||
|
var textInput = document.getElementById('footerContactText');
|
||||||
|
var submitBtn = form.querySelector('.footer-send-btn');
|
||||||
|
var status = document.getElementById('footerFormStatus');
|
||||||
|
function showStatus(message, isError) {
|
||||||
|
status.textContent = message;
|
||||||
|
status.classList.toggle('error', !!isError);
|
||||||
|
status.classList.add('visible');
|
||||||
|
}
|
||||||
|
form.addEventListener('submit', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var email = emailInput.value.trim();
|
||||||
|
var text = textInput.value.trim();
|
||||||
|
if (!email || !text) return;
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
status.classList.remove('visible');
|
||||||
|
fetch('https://n8n.odoo4projects.com/webhook/ODOO4projects/crm', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify(UTM.inject({ email: email, requirements: text, area: 'message' }))
|
||||||
|
}).then(function (r) {
|
||||||
|
if (!r.ok) throw new Error('bad status ' + r.status);
|
||||||
|
form.reset();
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
showStatus("Thanks! We'll get back to you shortly.", false);
|
||||||
|
}).catch(function () {
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
showStatus('Something went wrong. Please try again.', true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* ---- Scroll-triggered reveal (same grids as the homepage, minus blog / project-plan) ---- */
|
||||||
|
(function () {
|
||||||
|
if (!window.gsap || !('IntersectionObserver' in window)) return;
|
||||||
|
var animated = {};
|
||||||
|
var observer = new IntersectionObserver(function (entries) {
|
||||||
|
entries.forEach(function (entry) {
|
||||||
|
if (!entry.isIntersecting) return;
|
||||||
|
var grid = entry.target;
|
||||||
|
if (!grid || !grid.children || grid.children.length === 0) return;
|
||||||
|
var key = grid.className || 'anon';
|
||||||
|
if (animated[key]) return;
|
||||||
|
animated[key] = true;
|
||||||
|
gsap.fromTo(grid.children, { y: 30, opacity: 0 }, {
|
||||||
|
y: 0, opacity: 1, duration: 0.7, ease: 'power2.out', stagger: 0.08, overwrite: 'auto'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, { threshold: 0.1 });
|
||||||
|
|
||||||
|
var grids = document.querySelectorAll('.features-grid, .faq-grid, .pricing-grid');
|
||||||
|
grids.forEach(function (g) {
|
||||||
|
if (g.children.length > 0) { gsap.set(g.children, { y: 30, opacity: 0 }); }
|
||||||
|
observer.observe(g);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
})();
|
||||||
Reference in new issue
Block a user