diff --git a/src/app/api/submission-receive/route.ts b/src/app/api/submission-receive/route.ts index d49ff77..1ce0ba6 100644 --- a/src/app/api/submission-receive/route.ts +++ b/src/app/api/submission-receive/route.ts @@ -110,8 +110,52 @@ export async function POST(request: NextRequest) { .trim() .slice(0, 240); + // Passthrough mode (skip_rewrite=true): publish the original PR body + // VERBATIM with byline = firm + noindex=true on the wp_imported_posts + // row. No AI rewrite, no Google News indexing, no sitemap. For clients + // flagged in distribute.users.skip_rewrite (e.g. Mike Nann / Writeturn). + const skipRewrite = !!body?.skip_rewrite; + if (skipRewrite) { + const wpId = Math.floor(900_000 + Math.random() * 99_000_000); + const wpSlug = `${baseSlug}-pr-${randSuffix()}`; + const byline = contributor?.contact_name || contributor?.firm_name || 'PR Submission'; + const { error: wpErr } = await supabase + .schema('av') + .from('wp_imported_posts') + .insert({ + wp_id: wpId, + wp_slug: wpSlug, + title, + excerpt, + content, + author_name: byline, + category: 'Industry News', + status: 'published', + wp_published_at: new Date().toISOString(), + noindex: true, + }); + if (wpErr) { + return NextResponse.json({ error: wpErr.message, where: 'passthrough wp_imported_posts insert' }, { status: 500 }); + } + + // Keep the audit trail in original_submissions even for passthrough. + await supabase.schema('av').from('original_submissions').insert({ + submission_id: submissionId, + property, + title, + body: content, + featured_image_url: featuredImage, + attachments, + contributor, + contributor_email: contributor?.email || null, + raw_payload: body, + native_article_id: null, + }); + return NextResponse.json({ ok: true, slug: wpSlug, status: 'published_passthrough', noindex: true }, { status: 201 }); + } + const { data: article, error: artErr } = await supabase - .schema('bb') + .schema('av') .from('native_articles') .insert({ slug, @@ -129,7 +173,7 @@ export async function POST(request: NextRequest) { if (artErr) return NextResponse.json({ error: artErr.message, where: 'native_articles insert' }, { status: 500 }); const { error: subErr } = await supabase - .schema('bb') + .schema('av') .from('original_submissions') .insert({ submission_id: submissionId, diff --git a/src/app/articles/[slug]/page.tsx b/src/app/articles/[slug]/page.tsx index 81f613c..0a9557b 100644 --- a/src/app/articles/[slug]/page.tsx +++ b/src/app/articles/[slug]/page.tsx @@ -52,10 +52,15 @@ export async function generateMetadata({ params }: PageProps): Promise if (!article) { return { title: "Article Not Found", description: "The article you are looking for does not exist." }; } + const noindex = !!article.noindex; return { title: article.title, description: cleanExcerpt(article.excerpt), alternates: { canonical: `/articles/${article.slug}` }, + robots: noindex + ? { index: false, follow: false, nocache: true, googleBot: { index: false, follow: false, noimageindex: true } } + : undefined, + other: noindex ? { "googlebot-news": "noindex" } : undefined, openGraph: { type: "article", title: article.title, diff --git a/src/app/news-sitemap.xml/route.ts b/src/app/news-sitemap.xml/route.ts index bff4779..b78df43 100644 --- a/src/app/news-sitemap.xml/route.ts +++ b/src/app/news-sitemap.xml/route.ts @@ -28,6 +28,7 @@ export async function GET() { .select('wp_slug, title, wp_published_at, ai_rewritten_at, author_name, tags') .eq('status', 'published') .not('ai_rewritten_at', 'is', null) + .or('noindex.is.null,noindex.eq.false') // exclude noindex=true (passthrough PRs) .gte('wp_published_at', since) .order('wp_published_at', { ascending: false }) .limit(1000), diff --git a/src/app/news/[slug]/page.tsx b/src/app/news/[slug]/page.tsx index b7238ef..2f5a010 100644 --- a/src/app/news/[slug]/page.tsx +++ b/src/app/news/[slug]/page.tsx @@ -64,10 +64,17 @@ export async function generateMetadata({ params }: PageProps): Promise // contain

...

, which Next.js then HTML-escapes, surfacing as // literal `<p>` in page source. const cleanDesc = cleanExcerpt(article.excerpt); + const noindex = !!article.noindex; return { title: `${article.title} — AV Beat`, description: cleanDesc, alternates: { canonical: `/news/${article.slug}` }, + // Passthrough PR submissions (Mike Nann / Writeturn etc.) get a hard + // noindex on robots + googlebot-news so they don't pollute Google News. + robots: noindex + ? { index: false, follow: false, nocache: true, googleBot: { index: false, follow: false, noimageindex: true } } + : undefined, + other: noindex ? { "googlebot-news": "noindex" } : undefined, openGraph: { type: "article", title: article.title, diff --git a/src/app/rss/route.ts b/src/app/rss/route.ts index fccd916..6306d8f 100644 --- a/src/app/rss/route.ts +++ b/src/app/rss/route.ts @@ -19,6 +19,7 @@ export async function GET() { try { const articles = await getLegacyArticlesBySection("news", 50); items = articles + .filter((a) => !a.noindex) // exclude passthrough PR submissions .map((a) => { const url = `${SITE_URL}/news/${a.slug}`; const pubDate = a.date ? new Date(a.date).toUTCString() : new Date().toUTCString(); diff --git a/src/lib/articles/legacy-source.ts b/src/lib/articles/legacy-source.ts index bcf330b..48b61a4 100644 --- a/src/lib/articles/legacy-source.ts +++ b/src/lib/articles/legacy-source.ts @@ -26,6 +26,7 @@ interface ImportedPostRow { featured_image_alt: string | null; status: string; wp_published_at: string | null; + noindex: boolean | null; } interface RewriteRow { @@ -146,6 +147,7 @@ function rowToArticle(row: ImportedPostRow, section: Section = "news"): Article readTime: readTime(row.content), tags: row.tags || [], content, + noindex: !!row.noindex, }; } @@ -193,7 +195,7 @@ function humanBeat(beat: string): string { } const SELECT_COLS = - "wp_id,wp_slug,title,excerpt,content,author_name,category,tags,featured_image,featured_image_alt,status,wp_published_at"; + "wp_id,wp_slug,title,excerpt,content,author_name,category,tags,featured_image,featured_image_alt,status,wp_published_at,noindex"; const REWRITE_SELECT_COLS = "id,slug,title,excerpt,body,category,tags,status,published_at,created_at,persona:ai_personas(slug,name,beat,avatar_url)"; diff --git a/src/lib/articles/types.ts b/src/lib/articles/types.ts index c6a12b9..b6e9755 100644 --- a/src/lib/articles/types.ts +++ b/src/lib/articles/types.ts @@ -14,4 +14,8 @@ export interface Article { readTime: string; tags: string[]; content: string; + /** When true, render robots noindex + googlebot-news noindex and exclude + * from sitemap / RSS. Set on passthrough-mode imports from contributors + * flagged in distribute.users.skip_rewrite (e.g. Mike Nann / Writeturn). */ + noindex?: boolean; }