ADS-011
An ad slot manager with a fallback chain
Sponsor, then network, then house, then nothing. One function that means an unsold slot never leaves a hole in the page.
Ad slots spend most of their early life unsold. If an empty slot renders an empty box, the page looks broken, and if it renders a placeholder, it looks unfinished. Neither is what you want on a site you are trying to build traffic to.
A fallback chain fixes it with no conditionals scattered through the templates. Ask for a slot; get the direct sponsor if there is one, the network code if not, your own promotion after that, and an empty string if there is nothing at all. The template just prints whatever comes back.
Returning an empty string rather than an empty wrapper is the detail. Nothing rendered means nothing reserved, so the layout closes up cleanly.
function ad_slot(PDO $pdo, string $slug): string
{
static $cache = [];
if (!isset($cache[$slug])) {
$st = $pdo->prepare('SELECT * FROM ad_slots WHERE slug = ? AND active = 1');
$st->execute([$slug]);
$cache[$slug] = $st->fetch(PDO::FETCH_ASSOC) ?: null;
}
$slot = $cache[$slug];
if (!$slot) {
return '';
}
// 1. A directly sold sponsor, still inside its dates.
$sp = $pdo->prepare(
'SELECT html FROM sponsors
WHERE slot_id = ? AND active = 1 AND starts_at <= NOW() AND ends_at >= NOW()
ORDER BY RAND() LIMIT 1'
);
$sp->execute([$slot['id']]);
$inner = (string) ($sp->fetchColumn() ?: '');
// 2. Network embed code pasted in admin.
if ($inner === '') {
$inner = trim((string) $slot['code']);
}
// 3. Your own promotion.
if ($inner === '') {
$inner = house_promo();
}
// 4. Nothing. Render nothing at all — no wrapper, no reserved space.
if ($inner === '') {
return '';
}
return '<aside class="ad" data-size="' . e((string) $slot['size']) . '">'
. '<span class="ad-mark">Sponsored</span>'
. '<div class="ad-body">' . $inner . '</div></aside>';
}
Using it
Reserve the slot height in CSS keyed on the size attribute, so a slow network embed does not shift the page after it loads.
Keep the direct sponsor table separate from the pasted network code. They have different lifecycles: one has dates and an invoice, the other is a string that rarely changes.
What bites people
Cache the slot lookup per request. A page with five slots otherwise runs five identical queries.
Never escape the pasted code. It is markup on purpose — which is also why only an admin may write to that field.