Scope blog to UP Parivaar tag via GHOST_BLOG_TAG; allow http Ghost images

This commit is contained in:
2026-07-23 21:09:22 +05:30
parent 5e457f4f39
commit 52a8e486b9
3 changed files with 34 additions and 6 deletions
+3
View File
@@ -6,6 +6,9 @@ GHOST_CONTENT_API_KEY=your_content_api_key
# Admin API key (id:secret) — only needed for server-side write tooling, not the blog. # Admin API key (id:secret) — only needed for server-side write tooling, not the blog.
GHOST_ADMIN_API_KEY= GHOST_ADMIN_API_KEY=
# Only show posts tagged with this slug. Leave empty to show all posts.
GHOST_BLOG_TAG=upparivaar
# Optional # Optional
GHOST_API_VERSION=v5.0 GHOST_API_VERSION=v5.0
GHOST_REVALIDATE=60 GHOST_REVALIDATE=60
+24 -5
View File
@@ -15,6 +15,10 @@ const GHOST_URL = process.env.GHOST_URL?.replace(/\/$/, "");
const GHOST_KEY = process.env.GHOST_CONTENT_API_KEY; const GHOST_KEY = process.env.GHOST_CONTENT_API_KEY;
const GHOST_API_VERSION = process.env.GHOST_API_VERSION ?? "v5.0"; const GHOST_API_VERSION = process.env.GHOST_API_VERSION ?? "v5.0";
// Only show posts carrying this tag slug. The shared Ghost instance hosts many
// clients' blogs, each tagged separately — this scopes the site to just ours.
const GHOST_BLOG_TAG = process.env.GHOST_BLOG_TAG?.trim();
// How long (seconds) Next.js caches Ghost responses before revalidating. // How long (seconds) Next.js caches Ghost responses before revalidating.
const REVALIDATE = Number(process.env.GHOST_REVALIDATE ?? 60); const REVALIDATE = Number(process.env.GHOST_REVALIDATE ?? 60);
@@ -81,25 +85,40 @@ async function ghostFetch<T>(path: string, params: Record<string, string>): Prom
} }
} }
/** All published posts, newest first. Falls back to demo posts when unconfigured. */ // Ghost NQL filter, always published and (when set) scoped to our tag.
function scopedFilter(extra?: string): string {
const parts = ["status:published"];
if (GHOST_BLOG_TAG) parts.push(`tag:${GHOST_BLOG_TAG}`);
if (extra) parts.push(extra);
return parts.join("+");
}
/** All published posts for our tag, newest first. Falls back to demo posts when unconfigured. */
export async function getPosts(): Promise<GhostPost[]> { export async function getPosts(): Promise<GhostPost[]> {
const data = await ghostFetch<{ posts: GhostPost[] }>("/posts/", { const data = await ghostFetch<{ posts: GhostPost[] }>("/posts/", {
include: "tags,authors", include: "tags,authors",
fields: POST_FIELDS, fields: POST_FIELDS,
limit: "all", limit: "all",
order: "published_at desc", order: "published_at desc",
filter: "status:published", filter: scopedFilter(),
}); });
return data?.posts ?? DEMO_POSTS; return data?.posts ?? DEMO_POSTS;
} }
/** A single post by slug, with full HTML. Returns null when not found. */ /**
* A single post by slug, with full HTML. The tag scope is enforced here too, so
* another client's post can't be opened via a direct /blog/<slug> URL.
* Returns null when not found (or not in our tag).
*/
export async function getPost(slug: string): Promise<GhostPost | null> { export async function getPost(slug: string): Promise<GhostPost | null> {
const data = await ghostFetch<{ posts: GhostPost[] }>(`/posts/slug/${slug}/`, { const data = await ghostFetch<{ posts: GhostPost[] }>("/posts/", {
include: "tags,authors", include: "tags,authors",
filter: scopedFilter(`slug:${slug}`),
limit: "1",
}); });
if (data?.posts?.[0]) return data.posts[0]; if (data?.posts?.[0]) return data.posts[0];
return DEMO_POSTS.find((p) => p.slug === slug) ?? null; if (!ghostConfigured) return DEMO_POSTS.find((p) => p.slug === slug) ?? null;
return null;
} }
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
+7 -1
View File
@@ -13,7 +13,13 @@ const nextConfig = {
images: { images: {
remotePatterns: [ remotePatterns: [
{ protocol: "https", hostname: "images.unsplash.com" }, { protocol: "https", hostname: "images.unsplash.com" },
...(ghostHost ? [{ protocol: "https", hostname: ghostHost }] : []), // Ghost may serve feature images over either http or https, so allow both.
...(ghostHost
? [
{ protocol: "https", hostname: ghostHost },
{ protocol: "http", hostname: ghostHost },
]
: []),
], ],
}, },
}; };