Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web

Creating Blogging Sites with Astro

5.00/5 (2 votes)
9 Oct 2024CPOL22 min read 2.1K  
This article explains how to use the open-source Astro package create a full-featured blogging site.
This article explains how to generate blogs using the Astro static site generator (SSG). Astro accepts Astro files as input and produces HTML as output. To code an Astro file, you'll need a solid understanding of HTML and JavaScript/TypeScript.

For my upcoming blog, I decided that I didn't want to use a traditional CMS platform like Wordpress. I'm a programmer, and I'd rather use a tool that generates the blog from source code. These tools are called static site generators, or SSGs, and the big names are Hugo, Jekyll, Gatsby, and Astro. I chose Astro because of its support for TypeScript, and though it took some time to learn, I'm satisfied with its flexibility and performance.

The goal of this article is to explain how to build a full-featured blogging site with Astro. The first part walks through the process of creating an example blog project and then generating blog files from the project. Then we'll look at the format of Astro files and the files that make up an Astro project. The last parts of the article cover routing and customization.

1. Getting Started

Astro's mission is to convert a project containing Astro files (*.astro) into a folder containing web site files (mostly *.html). Rather than start from scratch, it's easier to create Astro's default blogging project and customize it as needed. This section explains how to create the default project, convert it into a blogging site, and then view the site in a browser. 

1.1  Creating the Project

Access to Astro is provided through the Node package manager, or npm. Node refers to Node.js, a runtime environment that provides access to over two million software packages. The vast majority of these packages are free, so if you’re building a web application, you’ll probably find several packages that will help.

Before you can use npm to create an Astro project, you'll need to install Node.js. The download page is https://nodejs.org, and you can download the installer by clicking the link for your operating system and processor type (probably 64-bit). This discussion assumes you’re running version 22 of Node or higher.

After you’ve installed Node, you can run npm from a command line. Every command starts with npm cmd_name where cmd_name identifies the command. To create a new Astro project, execute the following:

npm create astro@latest

Before creating the new project, Astro will ask six questions:

  1. Where should we create this project? - Enter the desired location of the project folder, either as an absolute path (C:\newblog) or as a path relative to the current directory (newblog).
  2. How would you like to start your project? - You can choose between Empty, Use blog template, and Include sample files. This article focuses on blogs, so select Use blog template.
  3. Do you plan to write TypeScript? - You can choose to write code in TypeScript (Yes) or JavaScript (No). For this article, select Yes.
  4. How strict should TypeScript be? - You can choose between Relaxed, Strict, and Strictest. For this article, Strict will be fine.
  5. Install dependencies? Choose Yes to have Node install the required packages needed to create an Astro project in TypeScript.
  6. Initialize a new Git repository? Choose Yes to have Node create a git repository to enable version control for the project.

After these questions are answered, the package manager will download the Astro package and its dependencies, and then create a project for a simple blogging site. Table 1 lists the files and folders in the project's top-level directory.

Table 1: Files and Folders in an Astro Project
File/Folder Name Description
.git The Git repository folder
.vscode Settings for the Visual Studio Code IDE
node_modules Node dependencies required by Astro
public Static assets to deploy to the web site
src Source files of the Astro project
.gitignore Names of files not to be included in the Git repository
astro.config.mjs Astro configuration settings
package.json Project configuration settings
package-lock.json Lists dependencies and their dependencies
README.md Describes the project
tsconfig.json Contains settings for the TypeScript compiler

You can leave most of these files alone, but the src folder deserves attention. This contains the source files of the Astro project, and a large part of this article is concerned with the content of this directory. But before we delve into the details, it's a good idea to create and view the blog.

1.2  Building and Viewing the Blog

After you've created an Astro project, it's easy to compile all the *.astro files into *.html files. Open a command prompt in the project's top-level directory and execute the following command:

npm run build

As the build proceeds, the utility will display the project files and the HTML files generated from them. The following text provides an example:

▶ src/pages/about.astro
  └─ /about/index.html (+12ms)
▶ src/pages/blog/index.astro
  └─ /blog/index.html (+13ms)
▶ src/pages/index.astro
  └─ /index.html (+3ms)

Once the build completes, the generated files will be stored in a new top-level directory named dist. You can view the HTML files by opening them in a browser. You can also launch a local server by executing npm run dev. Then visit http://localhost:4321 in a browser to see the blog. Figure 1 presents a condensed illustration of the blog's main page.

Image 1

Each page in the default blog has a header and a footer. The content between them is determined by the template of one or more Astro files. The next section explains what templates are.

2. The Astro File Format

If you look through the project's src folder, you'll see that most of the files are Astro (*.astro) files. Before we explore the project, it's important to understand the content of these files and how the content is structured. Every Astro file has (at most) two sections:

  • frontmatter - TypeScript that imports components, defines variables, and performs other operations
  • template - Markup to be rendered into HTML during the build, can access components and variables from frontmatter

Frontmatter is optional, but if it's present, it must be enclosed within lines made up of three hyphens. These are called code fences, and the following text shows how code fences separate the frontmatter from the template:

---
frontmatter written in TypeScript
---
template written in markup

This discussion looks at both of these sections. If you have a solid grasp of TypeScript and HTML, you'll have no trouble working with Astro files.

2.1  Frontmatter

The frontmatter of an Astro file contains code that executes just before the template is rendered. The most common frontmatter operations involve importing data structures and declaring variables and types.

Structures can be imported with the familiar import statement. These statements can access JavaScript files (*.js), TypeScript files (*.ts), and other Astro files (*.astro). For example, if a data structure named XYZ is defined in ABC.astro, it can be imported with the following code:

TypeScript
import XYZ from 'ABC.astro';

Declaring variables and types is just as easy. Variables in a let statement can be updated, variables in a const statement can't be updated, and the type statement declares a custom type. Here are some typical declarations:

TypeScript
const today = new Date();

type Props = CollectionEntry<'blog'>['data'];

The frontmatter of an Astro file isn't limited to imports and declarations, but these statements make up the majority of the code I've encountered.

2.2  Template

Every Astro file has a template that will be converted to HTML during the build process. These sections are written in a format that resembles JavaScript XML (JSX), which resembles HTML. There are two points to know about templates:

  1. A template can use regular HTML tags like <div>, <a>, <head>, and <body>. It can also create HTML tags from imported components, and a later section will explain what components are.
  2. The template can include TypeScript variables and expressions surrounded by curly braces. For example, if x is a variable declared in the frontmatter, its value can be inserted in the template with {x}.

To demonstrate these points, suppose the frontmatter of an Astro file imports a component named MyComp and declares a variable named compName. In the template, the following tag creates an instance of MyComp and sets its name attribute to compName:

HTML
<MyComp name={compName} />

When the project is built, MyComp's template will be inserted and its name attribute will be set to compName.

Astro's template syntax resembles JSX in many respects, but there's one major difference: the template of an Astro file doesn't change after the build. That is, the code in the frontmatter will only be executed during the build, so the inserted variables can only take one value.

3. Exploring the Project

At this point, you should be comfortable with Astro and Astro files. Now we'll dive deeper and look through the project's src directory. If you open this directory, you'll find the folders and files listed in Table 2.

Table 2: Folders and Files in the Project's Source (src) Directory
Folder/File Name Description
pages Astro files (*.astro) that represent pages to be generated
components Astro files (*.astro) that define components
content Markdown files (*.md or *.mdx) that provide the blog's posts
layouts Astro files (*.astro) that define a re-usable structure for pages
styles CSS files (*.css) that define style settings for the web site
consts.ts Global constants that can be accessed throughout the project
env.d.ts Tells the TypeScript compiler where to find Astro's type declarations

The goal of this section is to explore these folders and explain what their files accomplish. The better you understand the project structure, the easier it will be to customize the project for your blog.

3.1  The Pages Folder

If you look through the src/pages folder, you'll find index.astro, about.astro, and a folder named blog, which contains another index.astro and an odd but important file named [...slug].astro. During the build, each file in src/pages will be converted into one or more HTML files.

If you look through these files, you'll see that their frontmatter contains import statements like the following:

TypeScript
import Header from '../components/Header.astro';

import Layout from '../layouts/BlogPost.astro';

Header is imported from a file in the components folder, so it's safe to assume that it's a component. Layout is imported from a file in the layouts folder, so it's a special type of component called a layout. A proper introduction to components and layouts will be provided shortly.

If you compare index.astro and about.astro, you'll see that their templates are quite different. index.astro has <head> and <body> tags like a regular HTML file, but about.astro doesn't contain any of those tags. This is because the page structure of about.astro is defined using a layout, and I'll explain what layouts are shortly.

3.2  The Components Folder

Like many web frameworks, Astro is a component-centric toolset. Astro files can access components with import statements and insert them into a template as though they were regular HTML elements.

Each component is defined in a separate Astro file with frontmatter and template sections. A component's template can access two important capabilities:

  • props - global properties available to every component
  • template directives - special attributes that control how a component/element behaves

This discussion looks at each of these capabilities.

3.2.1  Accessing Props

Let's say that a component named MyComp has two attributes named attr1 and attr2. And let's say that a layout component imports MyComp and inserts it into its template in the following way:

HTML
<code><MyComp attr1="abc" attr2="xyz" /></code>

In its frontmatter, the MyComp component can access the attribute values through the global Astro.props value (which doesn't need to be imported). The following code gives an idea of how this works:

TypeScript
const { attr1, attr2 } = Astro.props;

This code declares the variables attr1 and attr2 and sets their values equal to the values of the component's attributes ("abc" and "xyz" in this example). These variables can be used throughout the template by surrounding them in curly braces: {attr1} and {attr2}.

To enable type-checking, many components create an interface that assigns types to the incoming attributes. In the following code, the interface contains attr1 and attr2 and assigns them both to the string type:

TypeScript
interface Props {
    attr1: string;
    attr2?: string;
}

If either attribute isn't a string, Astro will produce a warning/error during the build. The question mark following attr2 tells Astro that the attribute is optional.

3.2.2  Template Directives

Template directives are special attributes that can be inserted into components or other HTML elements in an Astro template. Every directive name consists of two words separated by a colon, and there are three general directives:

  • class:list - converts an array of elements into a string
  • set:html - injects a string into an element (similar to innerHTML)
  • set:text - injects text into an element (similar to innerText)

A template can contain JavaScript, but by default, components aren't hydrated in the client. To control when a component is hydrated, you need to insert a client directive into the component. Astro provides six client directives:

  • client:load - hydrate the component immediately when the page is loaded
  • client:idle - hydrate the component after the page is loaded and the requestIdleCallback event has fired
  • timeout - maximum time to wait before hydrating the component
  • client:visible - hydrate the component when it enters the user's viewport
  • client:media - hydrate the component when a CSS media query is met
  • client:only - skips server rendering, and renders only on the client

If you look at the HeaderLink.astro file in the src/components folder, you'll see that it uses the class:list directive to set an anchor's text. Unfortunately, none of the component templates demonstrate how client directives are used.

3.3  The Layouts Folder

Astro files in the src/layouts directory define special components called layouts. A layout's goal is to specify a page structure that can be used throughout the blog. Astro files in the src/pages directory can import layouts to define the page's fundamental elements, such as <html>, <head>, <body>, <style>, and so on.

For example, if you look at src/pages/about.astro, you'll see that its frontmatter and template have the following structure:

HTML
---
import Layout from '../layouts/BlogPost.astro';
---
<Layout ...>
   ...
</Layout>

The frontmatter imports the Layout component, which serves as the top-level element in the template. This provides the page's structure, and if you look at BlogPost.astro, you'll see that its template has the following content:

HTML
<html ...>
    <head>
        <BaseHead ... />
        <style>
            ...
        </style>
    </head>

    <body>
        <Header />
        <article>
            <div class="hero-image">
                ...
            </div>
            <div class="prose">
                <div class="title">
                    ...
                </div>
                <slot />
            </div>
        </article>
        <Footer />
    </body>
</html>

As shown, the layout contains components like BaseHead, Header, and Footer. The template of BaseHead consists of <meta> and <link> elements, and during the build process, these elements will be inserted into the <head> of every page that uses this layout.

In the <div> element of class prose, there's an important element named <slot />. This is where the content inside the layout component will be placed. Returning to the template in about.astro, the markup between <Layout> and </Layout> will be placed in the <slot /> element in the template of the Layout component.

Most blogs display one post per page. For Astro blogs, the structure of these pages is determined by a single layout component. This makes it important to write the layout component correctly.

3.4  The Content Folder

In essence, the purpose of an Astro project is to package the blog's content for deployment. If you look in src/content, you'll find a folder named blog and a file named config.ts. The files in the blog folder contain the blog's posts, which are are written using Markdown (*.md) and Markdown eXtended (*.mdx). The config.ts file exports a collection that enables components to access the blog's posts.

3.4.1  Content Files

Thanks to Github, the Markdown language has exploded in popularity for formatting text. If a content file has the suffix *.md, its text can be formatted using Markdown's syntax rules. Table 3 lists nine of the basic rules and provides a description of each.

Table 3: Basic Markdown Syntax
Formatting Rule Example Description
Heading # Heading 1
## Heading 2
The more pound signs,
the smaller the heading
Italics * italicized text * One asterisk prints text in italics
Boldface ** boldface text** Two asterisks print text in boldface
Unordered List - unordered
- unordered
Dashes create items in an unordered list
Ordered List 1. Item 1
2. Item 2
Number-dot-space creates items in
an ordered list
Code `code font` Back ticks print text in code font
Horizontal Rule --- Three hyphens create a horizontal line
Image ![alt](img.png) Alternative text in square brackets,
then the image file in parentheses
Hyperlink [text](https://www.xyz.com) Printed text in square brackets,
then the URL in parentheses

In addition to these rules, Markdown supports its own frontmatter, which is usually used to provide metadata. As in an Astro file, frontmatter in a Markdown file is surrounded by code fences. Unlike an Astro file, Markdown frontmatter is written in YAML, which means names and values are separated by colons. The following text gives an idea of what this looks like.

---
title: "Title"
author: "Tom Smith"
---
# This is an important heading!

If a file has the suffix *.mdx, it's written in Markdown eXtended (MDX), which combines the simplicity of Markup formatting and with the flexibility of Astro files. MDX is a superset of Markdown, so fit supports regular formatting rules and frontmatter. In addition, there are four points to know:

  1. TypeScript import/export statements can be inserted throughout the text.
  2. Once imported, components can be inserted into text using markup similar to Astro templates.
  3. Names in frontmatter can be accessed as properties of a frontmatter class. For example, if title is assigned a value in the frontmatter, it can be accessed in text as {frontmatter.value}.
  4. MDX can be used for files in src/pages as well as files in src/content. 

If you look in the project's src/content/blog folder, you'll see a file named using-mdx.mdx. This demonstrates how MDX can be used in a blog post.

3.4.2  Content Collections and config.ts

Any file in src/content is called a content entry and any top-level folder in src/content is called a content collection. Each collection contains a specific type of content, so if your site contains blog posts and source code files, they should be stored in separate collections.

In code, content collections are created by calling the defineCollection function exported by astro:content. In the example project, this is called by the config.ts file in src/content, and its full code is given as follows:

TypeScript
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
    type: 'content',
    // Type-check frontmatter using a schema
    schema: z.object({
        title: z.string(),
        description: z.string(),
        // Transform string to Date object
        pubDate: z.coerce.date(),
        updatedDate: z.coerce.date().optional(),
        heroImage: z.string().optional(),
    }),
});
export const collections = { blog };

In this code, the schema property accesses the frontmatter of each content entry. By default, the title, description, and pubDate fields are required, and the updatedData and heroImage fields are optional. The export statement makes the content collection available throughout the project. Later in the article, I'll explain how components access this content and insert it into a page.

3.5  Styles

If you open the src/styles directory, you'll find a file named global.css. The rules defined in this stylesheet apply throughout the project, and don't need to be imported.

You can change the blog's font by changing the font-face rules. The settings for the body rule are particularly important, as they apply to every component in the body of a web page.

4. Routing

If you build the default project by running npm run build, the generated blog files will be stored in  the project's dist folder. The HTML files in this folder were generated from the files in the project's src/pages and src/content folders.

Table 3 clarifies the relationships between six of the project's source files and generated files. The first column lists the paths of the source files, the second column lists the paths of the generated files, and the third column lists the URLs of the generated files. The URLs are given relative to www.example.com because this is the default site given in astro.config.mjs.

Table 4: Generated Files and URLs
Source File Generated File URL
src/pages/index.astro dist/index.html www.example.com
src/pages/about.astro dist/about.html www.example.com/about
src/pages/blog/index.astro dist/blog/index.html www.example.com/blog
src/content/blog/first-post.md dist/blog/first-post/index.html www.example.com/blog/first-post
src/content/blog/second-post.md dist/blog/second-post/index.html www.example.com/blog/second-post
src/content/blog/third-post.md dist/blog/third-post/index.html www.example.com/blog/third-post

As shown, Astro creates a directory for each Markdown file (*.md) in src/content/blog, and each directory has an index.html file. As discussed earlier, Astro refers to the src/content/blog folder as a content collection and each file in the folder is a content entry.

This table is misleading because Astro doesn't directly convert content entries into HTML files. To understand how this conversion is performed, you need to be familiar with two topics:

  1. Astro's CollectionEntry type
  2. The [...slug].astro file in the src/content/blog folder

Once you understand these topics, you'll have a solid grasp of Astro's dynamic routing, which automatically generates HTML files for blog posts.

4.1  The CollectionEntry Type

As mentioned earlier, the src/content/config.ts file calls the defineCollection function with an object with properties named type and schema. The type property is set to content and schema contains fields of the blog post's frontmatter. The function's return value is a CollectionConfig.

Astro's getCollection function accepts a CollectionConfig and returns a CollectionEntry. This important object has five properties:

  • id - for content entries, this is the name of the markdown file (*.md or *.mdx)
  • collection - the name of the content collection containing the entry (blog)
  • data - contains fields from the schema property of the CollectionConfig
  • slug - text to serve as the last segment of the entry's URL
  • body - the text in the content file

By default, Astro sets the slug property to the id property after removing the file suffix, setting each character to lowercase, and replacing each space and underscore with a hyphen. You can set a custom slug for an entry by adding a slug field to the frontmatter of the blog post file.

In addition to these properties, each CollectionEntry has a method named render. This compiles the entry's content and returns an Astro component that displays the compiled result.

4.2  The [...slug].astro File

In the /src/pages/blog folder, the [...slug].astro file is responsible for creating a page for each content entry in /src/content/blog. Its content is given as follows:

---
import { type CollectionEntry, getCollection } from 'astro:content';
import BlogPost from '../../layouts/BlogPost.astro';

export async function getStaticPaths() {
    const posts = await getCollection('blog');
    return posts.map((post) => ({
        params: { slug: post.slug },
        props: post,
    }));
}
type Props = CollectionEntry<'blog'>;

const post = Astro.props;
const { Content } = await post.render();
---

<BlogPost {...post.data}>
    <Content />
</BlogPost>

The code in the frontmatter forms a list of content entries and tells Astro to create a page for each element in the list. There are four points to be aware of:

  1. If the name of an Astro file is enclosed in square brackets, its frontmatter can access its name as a variable. The frontmatter of [...slug].astro accesses a variable named slug.
  2. The frontmatter calls getCollection to access CollectionEntry objects in the collection named blog.
  3. The frontmatter iterates through the entries and creates an array of elements. Each element of this array has a property named params, and each params has a property named slug whose value equals the slug property of the CollectionEntry.
  4. The frontmatter exports a function named getStaticPaths that returns the array constructed in Step 4. When Astro invokes this function, it creates a directory for each element of the array and set its name to params.slug. This explains why Astro creates dist/blog/first-post, dist/blog/second-post, and so on.

To set the content of these generated pages, [...slug].astro performs four operations:

  1. The frontmatter calls the render method of each CollectionEntry. The resulting component is assigned the name Content.
  2. The template contains a BlogPost component that defines the page's layout. 
  3. The template passes the CollectionEntry's data field to the BlogPost, which it can access through Astro.props.
  4. The template inserts the Content component inside the BlogPost component. As a result, the CollectionEntry content will replace the <slot /> element in the template of the layout component.

Astro refers to this page-generation process as static mode because the pages are generated during the build process. Astro also supports a server mode, in which pages are rendered by the server. This doesn't use getStaticPaths, and you can read more about server mode here.

5. Customizing the Blog

At this point, you should have a solid understanding of how to add posts to an Astro project and convert the project to HTML. This section presents a handful of customization tasks that blog authors may want to perform.

5.1  Project Configuration

If you're creating a new blog, the first file to change is astro.config.mjs in the project's top-level directory. This is the project's central configuration file, and by default, its content is given as follows:

JavaScript
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

import sitemap from '@astrojs/sitemap';

// https://astro.build/config
export default defineConfig({
    site: 'https://example.com',
    integrations: [mdx(), sitemap()],
});

At minimum, you should change the site property to the URL of your site. If you don't want to include MDX, you can remove the second import statement and delete the mdx() element from the integrations array.

Astro supports many other configuration options in astro.config.mjs. You can read the full list of them here.

5.2  The Header and Header Links

The default blog has a title in the upper left (Astro Blog), three links in the upper center (Home, Blog, and About), and social links in the upper right (Mastodon, Twitter, and Github). The banner across the top is defined in src/components/Header.astro with the following template markup:

HTML
<h2><a href="/">{SITE_TITLE}</a></h2>
<div class="internal-links">
    <HeaderLink href="/">Home</HeaderLink>
    <HeaderLink href="/blog">Blog</HeaderLink>
    <HeaderLink href="/about">About</HeaderLink>
</div>
<div class="social-links">
    ...
</div>

The first line of this markup sets the blog's title in the upper left, and the text is imported from consts.ts in the project's src directory. The default content of this file is given as:

JavaScript
export const SITE_TITLE = 'Astro Blog';
export const SITE_DESCRIPTION = 'Welcome to my website!';

You'll probably want to change these constants. In addition, if there are any strings that you'd like to use throughout the site (such as a copyright notice), it's a good idea to add them to src/consts.ts.

In the Header component's template, the division with class internal-links creates the Home, Blog, and About links in the upper center. These links are implemented as instances of the HeaderLink component, which is defined in src/components/HeaderLink.astro. 

5.3  The BaseHead Component

If search engine optimization (SEO) is a concern, you can add keywords and other items to the BaseHead component defined in src/components/BaseHead.astro. The BlogPost layout inserts a BaseHead into the <head> element of every page that uses the layout.

The Basehead also sets the site's favicon, and the following markup sets the default image:

HTML
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />

You'll probably want to change the canonical URL, which sets a page's preferred URL if it can be accessed through multiple URLs. The default canonical URL is set in the following way:

HTML
<link rel="canonical" href={canonicalURL} />

The BaseHead receives title and description attributes from the BlogPost component, which sets them to the SITE_TITLE and SITE_DESCRIPTION constants in src/consts.ts. In the BaseHead template, these attributes are used to set the primary meta elements of the page:

HTML
<title>{title}</title>
<meta name="title" content={title} />
<meta name="description" content={description} />

If you'd like your blogging site to be shared on social media, you can add metadata defined by the Open Graph protocol. For this end, the BaseHead contains the following lines:

HTML
<meta property="og:type" content="website" />
<meta property="og:url" content={Astro.url} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={new URL(image, Astro.url)} />

In these tags, the variable Astro.url is always set to the URL of the page in which these tags are inserted.

5.4  The Footer Component

At the bottom of the blog, the footer displays the copyright notice and social media links. The abbreviated structure of the Footer component is given as:

HTML
<footer>
    &copy; {today.getFullYear()} Your name here. All rights reserved.
    <div class="social-links">
        ...
    </div>
</footer>
<style>
    ...
</style>

Naturally, you'll want to add your name to the footer. You can set the footer's background color and padding by setting attributes in the <style>...</style> tags.

5.5  Really Simple Syndication (RSS)

RSS allows users to access the blog's content without having to manually visit the site. To support RSS, a blog needs to provide a file formatted according to the RSS 2.0 standard. This format is based on XML, and uses <rss> and </rss> as the root elements. 

If you look in the dist folder, you'll see that the Astro build generated a file named rss.xml. The content of this file is determined by the rss.xml.js file in the project's src/pages folder. This defines a function named GET, which is defined in the following way:

JavaScript
export async function GET(context) {
    const posts = await getCollection('blog');
    return rss({
        title: SITE_TITLE,
        description: SITE_DESCRIPTION,
        site: context.site,
        items: posts.map((post) => ({
            ...post.data,
            link: `/blog/${post.slug}/`,
        })),
    });
}

In the RSS feed, the <title> element is set to SITE_TITLE and the <description> element is set to SITE_DESCRIPTION. The feed will also have an <item> element for each blog post. If you'd like to customize the RSS feed with different elements, rss.xml.js is the file to modify.

History

This article was initially submitted on October 9, 2024.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)