Remove Ezoic ad integration
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
+1
-3
@@ -65,6 +65,4 @@ CRON_SECRET="your-secret-key-here"
|
||||
|
||||
# SENTRY_AUTH_TOKEN=sentry-auth-token
|
||||
|
||||
# GOOGLE_ADSENSE_ACCOUNT=ca-pub-xxxxxxxxxxxxxxxx
|
||||
# NEXT_PUBLIC_EZOIC_ENABLED=true
|
||||
# EZOIC_SITE_DOMAIN=prompts.chat
|
||||
# GOOGLE_ADSENSE_ACCOUNT=ca-pub-xxxxxxxxxxxxxxxx
|
||||
@@ -1,17 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
const domain = process.env.EZOIC_SITE_DOMAIN;
|
||||
|
||||
if (!domain) {
|
||||
return new NextResponse("# ads.txt not configured\n", {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "text/plain" },
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.redirect(
|
||||
`https://srv.adstxtmanager.com/19390/${domain}`,
|
||||
301
|
||||
);
|
||||
}
|
||||
@@ -802,73 +802,3 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Ezoic privacy policy container styling */
|
||||
#ezoic-privacy-policy-container {
|
||||
margin-top: 1rem;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
#ezoic-privacy-policy-container h2,
|
||||
#ezoic-privacy-policy-container h3,
|
||||
#ezoic-privacy-policy-container h4 {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
#ezoic-privacy-policy-container p {
|
||||
margin-top: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 1.7;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
#ezoic-privacy-policy-container a {
|
||||
color: var(--primary);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
|
||||
#ezoic-privacy-policy-container a:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
#ezoic-privacy-policy-container ul,
|
||||
#ezoic-privacy-policy-container ol {
|
||||
margin-top: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
padding-left: 1.5rem;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
#ezoic-privacy-policy-container li {
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
#ezoic-privacy-policy-container table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 1rem 0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
#ezoic-privacy-policy-container th,
|
||||
#ezoic-privacy-policy-container td {
|
||||
border: 1px solid var(--border);
|
||||
padding: 0.5rem 0.75rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#ezoic-privacy-policy-container th {
|
||||
background: var(--muted);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Ezoic ad content: center and constrain injected ad creatives */
|
||||
.ezoic-ad-content * {
|
||||
margin-left: auto !important;
|
||||
margin-right: auto !important;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { Header } from "@/components/layout/header";
|
||||
import { Footer } from "@/components/layout/footer";
|
||||
import { CookieConsentBanner } from "@/components/layout/cookie-consent";
|
||||
import { Analytics } from "@/components/layout/analytics";
|
||||
import { EzoicScripts, EzoicRouteHandler } from "@/components/layout/ezoic-ads";
|
||||
import { WebsiteStructuredData } from "@/components/seo/structured-data";
|
||||
import { AppBanner } from "@/components/layout/app-banner";
|
||||
import { LocaleDetector } from "@/components/providers/locale-detector";
|
||||
@@ -185,13 +184,11 @@ export default async function RootLayout({
|
||||
<meta name="google-adsense-account" content={process.env.GOOGLE_ADSENSE_ACCOUNT} />
|
||||
)}
|
||||
<WebsiteStructuredData />
|
||||
{process.env.NEXT_PUBLIC_EZOIC_ENABLED === "true" && <EzoicScripts />}
|
||||
</head>
|
||||
<body className={`${fontClasses} antialiased`}>
|
||||
{process.env.GOOGLE_ANALYTICS_ID && (
|
||||
<Analytics gaId={process.env.GOOGLE_ANALYTICS_ID} />
|
||||
)}
|
||||
{process.env.NEXT_PUBLIC_EZOIC_ENABLED === "true" && <EzoicRouteHandler />}
|
||||
<Providers locale={locale} messages={messages} theme={config.theme} branding={{ ...config.branding, useCloneBranding: config.homepage?.useCloneBranding }}>
|
||||
{isEmbedRoute || isKidsRoute ? (
|
||||
children
|
||||
|
||||
@@ -97,27 +97,6 @@ export default function PrivacyPage() {
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{process.env.NEXT_PUBLIC_EZOIC_ENABLED === "true" && (
|
||||
<section className="space-y-3">
|
||||
<h2 className="text-lg font-semibold">Advertising & Ezoic</h2>
|
||||
<p className="text-muted-foreground">
|
||||
We use Ezoic to provide personalized ads and analytics on this site. Ezoic and its partners
|
||||
may collect and use data about your visit to this and other websites to provide relevant
|
||||
advertisements. For full details on how Ezoic and its partners use your information, including
|
||||
a list of known cookies used on this site, please see the{" "}
|
||||
<a
|
||||
href="http://g.ezoic.net/privacy/prompts.chat"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline hover:text-foreground"
|
||||
>
|
||||
Ezoic privacy disclosures
|
||||
</a>.
|
||||
</p>
|
||||
<span id="ezoic-privacy-policy-embed"></span>
|
||||
</section>
|
||||
)}
|
||||
|
||||
<section className="space-y-3">
|
||||
<h2 className="text-lg font-semibold">Your Rights & CC0 License</h2>
|
||||
<p className="text-muted-foreground">
|
||||
|
||||
@@ -33,7 +33,6 @@ import { AddToCollectionButton } from "@/components/prompts/add-to-collection-bu
|
||||
import { getConfig } from "@/lib/config";
|
||||
import { StructuredData } from "@/components/seo/structured-data";
|
||||
import { AI_MODELS } from "@/lib/works-best-with";
|
||||
import { EzoicAd } from "@/components/ads/ezoic-ad";
|
||||
|
||||
interface PromptPageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
@@ -710,9 +709,6 @@ export default async function PromptPage({ params }: PromptPageProps) {
|
||||
locale={locale}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Ad Placement */}
|
||||
{process.env.NEXT_PUBLIC_EZOIC_ENABLED === "true" && <EzoicAd id={201} />}
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="versions" className="mt-0">
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { EzoicPlaceholder } from "./ezoic-placeholder";
|
||||
|
||||
interface EzoicAdProps {
|
||||
id: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client-only wrapper for EzoicPlaceholder.
|
||||
* Renders the placeholder div after mount so it's in the DOM
|
||||
* when Ezoic's showAds() runs.
|
||||
*
|
||||
* @see https://docs.ezoic.com/docs/ezoicadsadvanced/nextjs/
|
||||
*/
|
||||
export function EzoicAd({ id }: EzoicAdProps) {
|
||||
return <EzoicPlaceholder id={id} />;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { runEzoic } from "@/lib/ezoic";
|
||||
|
||||
interface EzoicPlaceholderProps {
|
||||
id: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages the lifecycle of a single Ezoic ad slot.
|
||||
* The placeholder div is always in the DOM so Ezoic can find it
|
||||
* when showAds() runs. Destroys the placeholder on unmount.
|
||||
*
|
||||
* @see https://docs.ezoic.com/docs/ezoicadsadvanced/nextjs/
|
||||
*/
|
||||
export function EzoicPlaceholder({ id }: EzoicPlaceholderProps) {
|
||||
const t = useTranslations("common");
|
||||
|
||||
useEffect(() => {
|
||||
runEzoic(() => {
|
||||
window.ezstandalone?.showAds(id);
|
||||
});
|
||||
|
||||
return () => {
|
||||
runEzoic(() => {
|
||||
window.ezstandalone?.destroyPlaceholders(id);
|
||||
});
|
||||
};
|
||||
}, [id]);
|
||||
|
||||
return (
|
||||
<div className="ezoic-ad-container my-2 overflow-hidden">
|
||||
<div className="flex items-center justify-center">
|
||||
<span className="text-[10px] font-medium uppercase tracking-widest text-muted-foreground/50 select-none">
|
||||
{t("ad")}
|
||||
</span>
|
||||
</div>
|
||||
<div id={`ezoic-pub-ad-placeholder-${id}`} className="overflow-hidden" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import Script from "next/script";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { runEzoic } from "@/lib/ezoic";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
ezstandalone?: {
|
||||
cmd: Array<() => void>;
|
||||
showAds: (...ids: number[]) => void;
|
||||
destroyAll: () => void;
|
||||
destroyPlaceholders: (...ids: number[]) => void;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ezoic script loader — renders all required <Script> tags.
|
||||
* Place inside <head> in layout.tsx per official docs.
|
||||
*
|
||||
* @see https://docs.ezoic.com/docs/ezoicadsadvanced/nextjs/
|
||||
*/
|
||||
export function EzoicScripts() {
|
||||
return (
|
||||
<>
|
||||
{/* Ezoic Privacy / Consent Management */}
|
||||
<Script
|
||||
id="ezoic-cmp"
|
||||
src="https://cmp.gatekeeperconsent.com/min.js"
|
||||
strategy="beforeInteractive"
|
||||
data-cfasync="false"
|
||||
/>
|
||||
<Script
|
||||
id="ezoic-cmp-2"
|
||||
src="https://the.gatekeeperconsent.com/cmp.min.js"
|
||||
strategy="beforeInteractive"
|
||||
data-cfasync="false"
|
||||
/>
|
||||
|
||||
{/* Ezoic standalone script */}
|
||||
<Script
|
||||
id="ezoic-sa"
|
||||
src="//www.ezojs.com/ezoic/sa.min.js"
|
||||
strategy="afterInteractive"
|
||||
/>
|
||||
|
||||
{/* Ezoic init — cmd queue must exist before any runEzoic() calls */}
|
||||
<Script id="ezoic-init" strategy="afterInteractive">
|
||||
{`
|
||||
window.ezstandalone = window.ezstandalone || {};
|
||||
window.ezstandalone.cmd = window.ezstandalone.cmd || [];
|
||||
`}
|
||||
</Script>
|
||||
|
||||
{/* Ezoic Analytics */}
|
||||
<Script
|
||||
id="ezoic-analytics"
|
||||
src="//ezoicanalytics.com/analytics.js"
|
||||
strategy="afterInteractive"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles SPA route changes for Ezoic.
|
||||
* Destroys stale placeholders and re-scans the DOM on each navigation.
|
||||
*
|
||||
* @see https://docs.ezoic.com/docs/ezoicadsadvanced/nextjs/
|
||||
*/
|
||||
export function EzoicRouteHandler() {
|
||||
const pathname = usePathname();
|
||||
|
||||
useEffect(() => {
|
||||
runEzoic(() => {
|
||||
window.ezstandalone?.destroyPlaceholders();
|
||||
requestAnimationFrame(() => {
|
||||
window.ezstandalone?.showAds();
|
||||
});
|
||||
});
|
||||
}, [pathname]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import { db } from "@/lib/db";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Masonry } from "@/components/ui/masonry";
|
||||
import { PromptCard } from "@/components/prompts/prompt-card";
|
||||
import { EzoicAd } from "@/components/ads/ezoic-ad";
|
||||
|
||||
interface DiscoveryPromptsProps {
|
||||
isHomepage?: boolean;
|
||||
@@ -158,15 +157,6 @@ export async function DiscoveryPrompts({ isHomepage = false }: DiscoveryPromptsP
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Ad Placement - after featured */}
|
||||
{isHomepage && process.env.NEXT_PUBLIC_EZOIC_ENABLED === "true" && (
|
||||
<section className="py-8 border-b">
|
||||
<div className="container max-w-2xl">
|
||||
<EzoicAd id={202} />
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Today's Most Upvoted Section */}
|
||||
{todaysMostUpvoted.length > 0 && (
|
||||
<section className={isHomepage ? "py-12 border-b" : "pb-8 mb-8 border-b"}>
|
||||
@@ -217,15 +207,6 @@ export async function DiscoveryPrompts({ isHomepage = false }: DiscoveryPromptsP
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Ad Placement - after latest */}
|
||||
{isHomepage && process.env.NEXT_PUBLIC_EZOIC_ENABLED === "true" && (
|
||||
<section className="py-8 border-b">
|
||||
<div className="container max-w-2xl">
|
||||
<EzoicAd id={203} />
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Recently Updated Section */}
|
||||
{recentlyUpdated.length > 0 && (
|
||||
<section className={isHomepage ? "py-12 border-b" : "pb-8 mb-8 border-b"}>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Safely push a function to the Ezoic command queue.
|
||||
* Initializes window.ezstandalone and cmd array if they don't exist yet,
|
||||
* preventing errors when components mount before the Ezoic script loads.
|
||||
*
|
||||
* @see https://docs.ezoic.com/docs/ezoicadsadvanced/nextjs/
|
||||
*/
|
||||
export function runEzoic(fn: () => void) {
|
||||
if (typeof window === "undefined") return;
|
||||
const ez = (window.ezstandalone ??= {} as NonNullable<typeof window.ezstandalone>);
|
||||
ez.cmd = ez.cmd || [];
|
||||
ez.cmd.push(fn);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { EzoicPlaceholder } from "@/components/ads/ezoic-placeholder";
|
||||
import type { WidgetPlugin } from "./types";
|
||||
|
||||
// Placeholder IDs must match those created in the Ezoic dashboard.
|
||||
// Each repeated instance uses a unique ID (101, 102, 103, ...) to avoid
|
||||
// "unpredictable ad behaviour" per Ezoic infinite scroll docs.
|
||||
const EZOIC_FEED_BASE_ID = 101;
|
||||
|
||||
export const ezoicWidget: WidgetPlugin = {
|
||||
id: "ezoic",
|
||||
name: "Ezoic Ads",
|
||||
prompts: [
|
||||
{
|
||||
id: "ezoic-feed-ad",
|
||||
slug: "ezoic-feed-ad",
|
||||
title: "",
|
||||
description: "",
|
||||
content: "",
|
||||
type: "TEXT",
|
||||
positioning: {
|
||||
position: 4,
|
||||
mode: "repeat",
|
||||
repeatEvery: 12,
|
||||
maxCount: 20,
|
||||
},
|
||||
shouldInject: () => process.env.NEXT_PUBLIC_EZOIC_ENABLED === "true",
|
||||
render: (instanceIndex: number) => (
|
||||
<EzoicPlaceholder id={EZOIC_FEED_BASE_ID + instanceIndex} />
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -3,7 +3,6 @@ import { coderabbitWidget } from "./coderabbit";
|
||||
import { bookWidget } from "./book";
|
||||
import { textreamWidget } from "./textream";
|
||||
import { commandcodeWidget } from "./commandcode";
|
||||
import { ezoicWidget } from "./ezoic";
|
||||
|
||||
export * from "./types";
|
||||
|
||||
@@ -13,7 +12,6 @@ const widgetPlugins: WidgetPlugin[] = [
|
||||
bookWidget,
|
||||
textreamWidget,
|
||||
commandcodeWidget,
|
||||
ezoicWidget,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user