diff --git a/src/content/docs/en/guides/content-collections.mdx b/src/content/docs/en/guides/content-collections.mdx index 4d8bdc19ad392..3ff2fe18530b7 100644 --- a/src/content/docs/en/guides/content-collections.mdx +++ b/src/content/docs/en/guides/content-collections.mdx @@ -208,13 +208,16 @@ Your blog post content here. You can also pass options to the `glob()` loader's [`generateID()` helper function](/en/reference/content-loader-reference/#generateid) when you define your build-time collection to adjust how `id`s are generated. For example, you may wish to revert the default behavior of converting uppercase letters to lowercase for each collection entry: ```js title="src/content.config.ts" +import { glob } from "astro/loaders"; +import { defineCollection } from "astro:content"; + const authors = defineCollection({ /* Retrieve all JSON files in your authors directory while retaining * uppercase letters in the ID. */ loader: glob({ - pattern: '**/*.json', + pattern: "**/*.json", base: "./src/data/authors", - generateId: ({ entry }) => entry.replace(/\.json$/, ''), + generateId: ({ entry }) => entry.replace(/\.json$/, ""), }), }); ``` @@ -224,8 +227,8 @@ const authors = defineCollection({ The [`file()` loader](/en/reference/content-loader-reference/#file-loader) fetches multiple entries from a single local file defined in your collection. The `file()` loader will automatically detect and parse (based on the file extension) a single array of objects from JSON and YAML files, and will treat each top-level table as an independent entry in TOML files. ```ts title="src/content.config.ts" {5} -import { defineCollection } from 'astro:content'; -import { file } from 'astro/loaders'; +import { defineCollection } from "astro:content"; +import { file } from "astro/loaders"; const dogs = defineCollection({ loader: file("src/data/dogs.json"), @@ -301,8 +304,8 @@ You can [build a custom loader](/en/reference/content-loader-reference/#building Then you can import and define your custom loader in your collections config, passing any required values: ```ts title="src/content.config.ts" -import { defineCollection } from 'astro:content'; -import { myLoader } from './loader.ts'; +import { defineCollection } from "astro:content"; +import { myLoader } from "./loader.ts"; const blog = defineCollection({ loader: myLoader({ @@ -335,9 +338,9 @@ In order for Astro to recognize a new or updated schema, you may need to restart Providing a `schema` is optional, but highly recommended! If you choose to use a schema, then every frontmatter or data property of your collection entries must be defined using a [Zod data type](/en/reference/modules/astro-zod/#common-data-type-validators): ```ts title="src/content.config.ts" {7-12,16-20} -import { defineCollection } from 'astro:content'; -import { z } from 'astro/zod'; -import { glob, file } from 'astro/loaders'; +import { defineCollection } from "astro:content"; +import { z } from "astro/zod"; +import { glob, file } from "astro/loaders"; const blog = defineCollection({ loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }), @@ -346,7 +349,7 @@ const blog = defineCollection({ description: z.string(), pubDate: z.coerce.date(), updatedDate: z.coerce.date().optional(), - }) + }), }); const dogs = defineCollection({ loader: file("src/data/dogs.json"), @@ -381,27 +384,27 @@ With the [`reference()` function](/en/reference/modules/astro-content/#reference A common example is a blog post that references reusable author profiles stored as JSON, or related post URLs stored in the same collection: ```ts title="src/content.config.ts" -import { defineCollection, reference } from 'astro:content'; -import { glob } from 'astro/loaders'; -import { z } from 'astro/zod'; +import { defineCollection, reference } from "astro:content"; +import { glob } from "astro/loaders"; +import { z } from "astro/zod"; const blog = defineCollection({ - loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }), + loader: glob({ base: "./src/content/blog", pattern: "**/*.{md,mdx}" }), schema: z.object({ title: z.string(), // Reference a single author from the `authors` collection by `id` - author: reference('authors'), + author: reference("authors"), // Reference an array of related posts from the `blog` collection by `id` - relatedPosts: z.array(reference('blog')), - }) + relatedPosts: z.array(reference("blog")), + }), }); const authors = defineCollection({ - loader: glob({ pattern: '**/*.json', base: "./src/data/authors" }), + loader: glob({ pattern: "**/*.json", base: "./src/data/authors" }), schema: z.object({ name: z.string(), portfolio: z.url(), - }) + }), }); export const collections = { blog, authors }; @@ -484,14 +487,19 @@ Once queried, you can render Markdown and MDX entries to HTML using the [`render ```astro title="src/pages/blog/post-1.astro" {2,6,10} --- -import { getEntry, render } from 'astro:content'; +import { getEntry, render } from "astro:content"; -const entry = await getEntry('blog', 'post-1'); +const entry = await getEntry("blog", "post-1"); + +if (!entry) { + throw new Error("Entry not found"); +} const { Content } = await render(entry); --- +

{entry.data.title}

-

Published on: {entry.data.published.toDateString()}

+

Published on: {entry.data.pubDate.toDateString()}

``` @@ -564,10 +572,15 @@ Then, you can use the `getEntry()` function again (or `getEntries()` to retrieve ```astro title="src/pages/blog/adventures-in-space.astro" --- -import { getEntry, getEntries } from 'astro:content'; +import { getEntry, getEntries } from "astro:content"; // First, query a blog post -const blogPost = await getEntry('blog', 'Adventures in Space'); +const blogPost = await getEntry("blog", "Adventures in Space"); + +// If the blog post doesn't exist, throw an error +if (!blogPost) { + throw new Error("Blog post not found"); +} // Retrieve a single reference item: the blog post's author // Equivalent to querying `{collection: "authors", id: "ben-holmes"}` @@ -584,9 +597,7 @@ const relatedPosts = await getEntries(blogPost.data.relatedPosts);

You might also like:

-{relatedPosts.map(post => ( - {post.data.title} -))} +{relatedPosts.map((post) => {post.data.title})} ``` ## Generating Routes from Content @@ -797,16 +808,20 @@ You can use these functions to access your live data, passing the name of the co --- export const prerender = false; // Not needed in 'server' mode -import { getLiveCollection, getLiveEntry } from 'astro:content'; +import { getLiveCollection, getLiveEntry } from "astro:content"; + +if (!Astro.params.slug) { + return Astro.redirect('/404'); +} // Use loader-specific filters -const { entries: draftArticles } = await getLiveCollection('articles', { - status: 'draft', - author: 'john-doe', +const { entries: draftArticles } = await getLiveCollection("articles", { + status: "draft", + author: "john-doe", }); // Get a specific product by ID -const { entry: product } = await getLiveEntry('products', Astro.params.slug); +const { entry: product } = await getLiveEntry("products", Astro.params.slug); --- ``` @@ -820,10 +835,14 @@ You also have access to any [error returned by the live loader](/en/reference/co --- export const prerender = false; // Not needed in 'server' mode -import { getLiveEntry, render } from 'astro:content'; -const { entry, error } = await getLiveEntry('articles', Astro.params.id); -if (error) { - return Astro.rewrite('/404'); +if (!Astro.params.id) { + return Astro.redirect("/404"); +} + +import { getLiveEntry, render } from "astro:content"; +const { entry, error } = await getLiveEntry("articles", Astro.params.id); +if (!entry || error) { + return Astro.rewrite("/404"); } const { Content } = await render(entry); @@ -851,10 +870,14 @@ You can use `instanceof` to check the type of an error at runtime: --- export const prerender = false; // Not needed in 'server' mode -import { LiveEntryNotFoundError } from 'astro/content/runtime'; -import { getLiveEntry } from 'astro:content'; +import { LiveEntryNotFoundError } from "astro/content/runtime"; +import { getLiveEntry } from "astro:content"; + +if (!Astro.params.id) { + return Astro.redirect("/404"); +} -const { entry, error } = await getLiveEntry('products', Astro.params.id); +const { entry, error } = await getLiveEntry("products", Astro.params.id); if (error) { if (error instanceof LiveEntryNotFoundError) { @@ -862,7 +885,7 @@ if (error) { Astro.response.status = 404; } else { console.error(`Error loading product: ${error.message}`); - return Astro.redirect('/500'); + return Astro.redirect("/500"); } } --- diff --git a/src/content/docs/en/guides/images.mdx b/src/content/docs/en/guides/images.mdx index f9fdc6958576c..f8ea67b961b2d 100644 --- a/src/content/docs/en/guides/images.mdx +++ b/src/content/docs/en/guides/images.mdx @@ -468,11 +468,12 @@ For example, you could create a component for your blog post images that receive ```astro title="src/components/BlogPostImage.astro" --- -import { Image } from 'astro:assets'; +import { Image } from "astro:assets"; -const { src, ...attrs } = Astro.props; +const { alt, src, ...attrs } = Astro.props; --- - + +{alt}