ads: route all clicks through advertising.RMP.com/r/<id> + cache-aware banner reads
Two compounding bugs caused 0 clicks since May 22: 1. lib/ads.ts exported ADS_728X90 / ADS_300X250 / FIXED_300X600 as IIFE-evaluated module constants. They captured the FALLBACK array at module-load time, before the centralized RMP banner cache populates. Every render that referenced them got FALLBACK banners whose click_url was the direct advertiser URL — bypassing the centralized click logger entirely. 300x250s escaped because every page reads them via rotateAll() at render time. 2. Even when the new RMP-cache banners did render, click_url pointed at www.RMP.com/<property>/<slug>, which logs to adv.banner_clicks. The RMP analytics dashboard reads bb.ad_clicks. Repointed click URLs at advertising.RMP.com/r/<campaign_id> so all clicks land in the single table the dashboard queries. Files: lib/ads.ts (remove broken IIFE exports + repoint click_url), SidebarAdStack, Header, Footer, and 9 pages (reading-list, forum, forum/thread, search, gear, technology, authors, show-coverage x2). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -99,15 +99,18 @@ async function fetchPlacement(size: Ad["size"]): Promise<Ad[]> {
|
||||
if (!res.ok) return [];
|
||||
const data = await res.json() as { banners?: RmpBanner[] };
|
||||
return (data.banners || []).map((b): Ad => ({
|
||||
// Prefer the human-readable slug for the centralized click URL; fall back
|
||||
// to the campaign UUID if the slug column ever ends up empty.
|
||||
slug: b.slug || b.campaign_id,
|
||||
campaign_id: b.campaign_id,
|
||||
label: b.name,
|
||||
size: b.placement,
|
||||
src: b.image_url,
|
||||
alt: b.name,
|
||||
click_url: `https://www.relevantmediaproperties.com/${PROPERTY}/${b.slug || b.campaign_id}`,
|
||||
// All clicks route through advertising.RMP.com/r/<campaign_id> so they
|
||||
// land in bb.ad_clicks — the single table the RMP analytics dashboard
|
||||
// reads. Do not change to a different host or path; the legacy
|
||||
// www.RMP.com/<property>/<slug> path writes to adv.banner_clicks which
|
||||
// the dashboard does not query.
|
||||
click_url: `${RMP_API}/r/${b.campaign_id}`,
|
||||
}));
|
||||
} catch {
|
||||
return [];
|
||||
@@ -207,11 +210,8 @@ export function pickAds(
|
||||
return all.slice(0, Math.min(n, all.length));
|
||||
}
|
||||
|
||||
// Sync exports for callers that still want the bare arrays. These also
|
||||
// read the cache (so live edits surface) but fall back to FALLBACK.
|
||||
export const ADS_728X90: Ad[] = (() => readCachedAds().filter((a) => a.size === "728x90"))();
|
||||
export const ADS_300X250: Ad[] = (() => readCachedAds().filter((a) => a.size === "300x250"))();
|
||||
export const FIXED_300X600: Ad | null = (() => readCachedAds().find((a) => a.size === "300x600") || null)();
|
||||
|
||||
// Prime the cache once at module load.
|
||||
// Prime the cache once at module load. Callers must use rotateAll() or
|
||||
// pickAds() so the live cache (which fills async after import) is read at
|
||||
// render time — the previous module-level IIFE constants captured the
|
||||
// FALLBACK array forever and silently bypassed the centralized click logger.
|
||||
triggerRefresh();
|
||||
|
||||
Reference in New Issue
Block a user