shipping scheduled campaigns reliably in Hyvä
A sale banner that appears right at midnight, and a campaign page that automatically vanishes again on Monday morning, sound simple until the Full Page Cache and edge caching have to cooperate. Content staging campaigns with Page Builder solve that cleanly in a Hyvä theme once preview mode and cache invalidation are planned in from the start.
Table of Contents
- 1. What content staging does and why it matters in a Hyvä theme
- 2. Creating staging campaigns for scheduled content updates
- 3. Technically testing preview mode in the Hyvä frontend
- 4. How content staging and the Full Page Cache interact on time-delayed changes
- 5. Accounting for CDN and edge caching at campaign go-live
- 6. Editing Page Builder content types inside a staging campaign
- 7. Rolling back faulty campaigns and handling conflicts
- 8. A practical example: a scheduled weekend sale campaign
- 9. Checklist for reliable content staging in a Hyvä theme
- 10. Summary
- 11. FAQ
1. What content staging does and why it matters in a Hyvä theme
Content staging bundles changes to CMS pages, CMS blocks, or category content into a campaign with a fixed start time and an optional end time, instead of every change going live the moment it is saved. That lets a sale banner be fully designed days in advance and scheduled for the exact campaign start, with no one needing to intervene manually at the actual go-live moment.
In a Hyvä theme, staged content renders through exactly the same Page Builder Content Type templates as live content, because staging operates below the template layer and simply determines which version of a piece of content counts as current at a given time. For theme development that means no content type needs special staging support, but preview and cache behavior deserve deliberate attention.
2. Creating staging campaigns for scheduled content updates
A campaign is created in the admin through the Schedule New Update action on a CMS page or CMS block, bundling every change made up to the scheduled time into a single atomic update. Only once the cron job runs at the scheduled time do the staged changes get merged into the active version, and until then the live content stays unchanged for every visitor.
A typical weekend sale fits this pattern well: the sale banner on the homepage, the adjusted category landing page, and an extra CMS block with the promotion terms all get assigned to a single campaign, so all three elements appear in sync on Friday evening without a developer needing to be active at that hour.
3. Technically testing preview mode in the Hyvä frontend
Preview mode loads a staged version through a special preview URL inside the admin panel, usually embedded in an iframe, and marks the request internally so Magento serves the staged version instead of the active one. For the Hyvä theme, that means every Alpine component built on top of Page Builder content types, sliders or countdown banners included, has to initialize correctly inside that iframe context too, since a script that fails to load stands out immediately during preview.
A commonly missed point is that tracking and analytics scripts should not fire during preview, otherwise every test view by an editor gets counted as a real page visit. A simple server-side check for whether the current request is a staging preview lets those scripts be suppressed deliberately, without affecting the actual content rendering.
<?php
/** @var \Magento\Framework\View\Element\Template $block */
/** @var \Magento\Staging\Model\VersionManager $versionManager */
$versionManager = $block->getData('version_manager');
$isPreview = $versionManager !== null && $versionManager->isPreviewVersion();
?>
<?php if (!$isPreview): ?>
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({ event: 'page_view' });
</script>
<?php $hyvaCsp->registerInlineScript(); ?>
<?php endif; ?>
4. How content staging and the Full Page Cache interact on time-delayed changes
The real challenge only starts at the campaign's go-live moment: the Full Page Cache may keep serving the last rendered, not-yet-staged version of a page well past the planned start time if nobody actively invalidates the affected cache entries. The cron job responsible for this, staging_update_cache_context, merges the staged version into the active content at the scheduled time and triggers the matching cache invalidation for the affected entities.
The interval at which that cron job runs is decisive here: with a default configuration of a few minutes, a campaign meant to start exactly at midnight can actually only become visible a few minutes later. For time-critical campaigns, such as a flash sale with a start time set to the exact minute, shortening that interval or triggering a targeted, manual cache flush shortly after the scheduled start pays off.
5. Accounting for CDN and edge caching at campaign go-live
Even when Magento's own Full Page Cache invalidates correctly, an upstream CDN or a Varnish layer can keep serving the old page for the duration of its own TTL, since these systems typically know nothing about Magento's internal cache invalidation. For pages that are regular targets of staging campaigns, such as the homepage or central category landing pages, a noticeably shorter edge TTL than for static content like product detail pages pays off.
Alternatively, a targeted purge call to the CDN can be tied directly to the staging update event, so the affected URL is removed from the edge cache exactly at campaign start instead of waiting for a fixed TTL to expire. That keeps the TTL high for the rest of the shop while time-critical campaign pages still update on time.
<?php
declare(strict_types=1);
namespace Mironsoft\StagingCache\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\HTTP\Client\Curl;
/**
* Purges affected URLs at the edge cache as soon as a staging campaign
* goes live, instead of waiting for the CDN TTL to expire.
*/
class PurgeCdnOnCampaignActivate implements ObserverInterface
{
/**
* @param Curl $curl
*/
public function __construct(private readonly Curl $curl)
{
}
/**
* Triggers the purge request at the CDN for the affected URLs.
*
* @param Observer $observer
* @return void
*/
public function execute(Observer $observer): void
{
$urls = (array) $observer->getEvent()->getData('affected_urls');
foreach ($urls as $url) {
$this->curl->setHeaders(['X-Purge-Method' => 'single']);
$this->curl->post($url, []);
}
}
}
6. Editing Page Builder content types inside a staging campaign
Editors work on Page Builder content types inside a campaign with the same drag-and-drop editor used for direct changes, and every custom content type registered in the theme is automatically available there, with no extra registration needed for the staging context. It gets important with custom content types that run their own logic at render time, such as a countdown banner that computes the remaining time until an event.
A countdown like that must not rely on the actual server date during preview, it has to use the preview date stored in the staging context, otherwise the preview shows a completely wrong countdown state to the editor. The content type's view model should therefore consistently work through an injected date source that returns the staged date during preview and the real server date in live operation.
<?php
declare(strict_types=1);
namespace Mironsoft\CountdownBanner\ViewModel;
use Magento\Framework\View\Element\Block\ArgumentInterface;
use Magento\Staging\Model\VersionManager;
use Magento\Framework\Stdlib\DateTime\DateTime;
/**
* Provides the date relevant for countdown calculations, taking the
* staging preview context into account.
*/
class CountdownDateProvider implements ArgumentInterface
{
/**
* @param VersionManager $versionManager
* @param DateTime $dateTime
*/
public function __construct(
private readonly VersionManager $versionManager,
private readonly DateTime $dateTime,
) {
}
/**
* Returns the currently relevant date as a Unix timestamp.
*
* @return int
*/
public function getReferenceTimestamp(): int
{
if ($this->versionManager->isPreviewVersion()) {
return (int) $this->versionManager->getVersion()->getData('created_at');
}
return $this->dateTime->gmtTimestamp();
}
}
7. Rolling back faulty campaigns and handling conflicts
As long as a campaign has not gone live yet, it can be rescheduled or deleted in the admin without any effect on the live content whatsoever. Once it has merged into the active version, there is no simple undo button anymore, a rollback in practice means creating a new campaign that restores the original state, which is why taking a snapshot of the prior state before a large campaign always pays off.
If two campaigns overlap on the same entity, for example because an editor accidentally creates two sale campaigns with overlapping time windows, Magento resolves the conflict based on priority and creation time, which is rarely intuitive for the people involved. Ahead of revenue-critical periods like a Black Friday weekend, deliberately testing overlapping campaigns on a staging environment prevents that kind of surprise.
8. A practical example: a scheduled weekend sale campaign
A typical weekend campaign starts Friday at six in the evening and ends Sunday at eleven fifty-nine, with a homepage banner, an adjusted category landing page, and a reduced edge TTL for exactly those two pages. The preview gets signed off with the marketing team as early as Wednesday, while the technical side checks in parallel whether the cache purge mechanism is configured correctly for the scheduled start time.
During the actual campaign start, a bit of active monitoring pays off: a look at the cron log to confirm the staging update job ran on time, and a look at the cache hit rate to make sure visitors are actually seeing the new version. In case the scheduled job is delayed, a prepared manual cache flush command helps push the start through by hand if needed, instead of passively waiting for the next cron run.
9. Checklist for reliable content staging in a Hyvä theme
Content staging shows its value mainly when preview, cache invalidation, and edge caching are treated as one connected system instead of considering each part in isolation. An editorial team that can prepare a campaign cleanly but gets held back at go-live by a sluggish CDN will still experience the feature as unreliable in the end, even though Magento itself worked correctly.
The overview below summarizes the key checkpoints for a time-critical campaign setup, so nothing fundamental gets overlooked before the next campaign goes live.
| Checkpoint | When to Check | Owner | Consequence if Skipped |
|---|---|---|---|
| Campaign fully tested in preview | Several days before go-live | Editorial + Development | Faulty content becomes visible live |
| Cron interval for staging updates matches time criticality | Before every time-critical launch | Development | Delayed visibility after the scheduled start |
| Edge TTL reduced or purge configured for affected pages | Before campaign start | Development / DevOps | Old content stays visible despite Magento having updated |
| Tracking scripts suppressed during preview | When setting up new content types | Development | Skewed analytics data from editor test views |
| Overlapping campaigns tested on staging | Ahead of revenue-critical periods | Editorial + Development | Unpredictable conflict resolution in live operation |
| Manual cache flush procedure documented | Once, before the first time-critical campaign | DevOps | No fast response if the cron run is delayed |
Mironsoft
Hyvä theme development and Luma migration
Still running Luma, or a Hyvä theme that just doesn't feel right?
We build Hyvä themes for Magento from scratch or migrate existing Luma shops cleanly, with Tailwind CSS, Alpine.js, and none of the unnecessary JavaScript baggage.
Luma-to-Hyvä Migration
Move an existing shop to Hyvä in a structured way, without losing functionality.
Custom Theme Development
Build a custom Hyvä theme from scratch based on your design.
Performance Optimization
Improve Core Web Vitals and load times in the Hyvä frontend with purpose.
10. Summary
Content Staging with Page Builder in Hyvä
Core idea
Content staging campaigns bundle scheduled changes so nobody needs to intervene manually at the go-live moment.
Preview
Preview mode runs in the same template system but needs its own handling of tracking scripts and date logic.
Cache coupling
The Full Page Cache and edge caching need to be actively tied to campaign start, otherwise visibility is delayed.
Practice
Time-critical campaigns need short cron intervals, targeted purges, and active monitoring during the go-live window.