Scope blog to UP Parivaar tag via GHOST_BLOG_TAG; allow http Ghost images
This commit is contained in:
@@ -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
@@ -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
@@ -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 },
|
||||||
|
]
|
||||||
|
: []),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user