Pages
Skill level: Beginner to edit, light code to add a page made of sections
Every Page And Its File
The route file decides which sections a page shows. The content file holds the page’s title, SEO fields, page header, and named blocks. Paths below are for English. French uses the same files in french/, served under /fr/, and Arabic in arabic/, served under /ar/.
| Page | URL | Route (src/pages/[...lang]/) | Content (src/content/) |
|---|---|---|---|
| Homepage | / | index.astro | homepage/english/-index.md and the section files |
| Demo homepages | /home-two/, /home-three/, /home-four/ | home-two.astro, home-three.astro, home-four.astro | homepage/english/home-two.md, home-three.md, home-four.md |
| Services overview | /services/ | services/index.astro | services/english/-index.md |
| Service page | /services/<customSlug>/ | services/[single].astro | services/english/service-0X.mdx |
| Projects | /projects/ | projects/index.astro | projects/english/-index.md |
| Project page | /projects/<customSlug>/ | projects/[single].astro | projects/english/project-X.mdx |
| Pricing | /pricing/ | pricing.astro | pricing/english/-index.md |
| Savings calculator | /calculator/ | calculator.astro | calculator/english/-index.md |
| About | /about/ | about.astro | about-us/english/-index.md |
| Team | /team/ | team/index.astro | team/english/-index.md |
| Careers | /careers/, /careers/<role>/ | careers/ | careers/english/ |
| FAQ | /faq/ | faq.astro | faq/english/-index.md |
| Blog | /blog/, posts, /blog/page/<n>/, /blog/category/<name>/, /blog/tag/<name>/ | blog/ | blog/english/ |
| Contact and quote | /contact/ | contact.astro | contact/english/-index.md and sections/english/contact-section-two.md |
| Legal and text pages | /privacy-policy/, /terms-conditions/ | [page].astro | pages/english/*.md |
| Shortcode demo | /components/ | [page].astro | pages/english/components.mdx |
| 404 | any missing URL | 404.astro (and src/pages/404.astro) | notFound in src/i18n/en.json |
| RSS feed | /rss.xml | rss.xml.ts | built from the blog posts |
Each collection (services, projects, careers, blog, team, testimonials) is explained in Collections.
Page Header
Inner pages such as pricing, the calculator, contact, FAQ, team, careers, projects, and blog start with a page header: a small badge, the title, and a description. It is set by fields at the top of the page’s content file:
badge: "Careers"title: "Build the clean energy around you"description: "We hire installers, electricians, and advisors who take pride in tidy work..."headerImage: "/images/photos/cta-unsplash-pIcseKMisrs.jpg" # optional photo under the headerheaderImageAlt: "Two installers fitting solar panels on a roof"headerAlign: "left" # left | centerThe about page and the services overview open with a section instead (the about intro, and the services band).
Service and project pages show the entry’s title in the header. Their badge comes from badgeSecondary in services/english/-index.md and from the project’s first category, and a project’s header photo is its image.
Fields Every Page Accepts
These frontmatter fields work on page and entry files. src/content/_file_format.md explains most of them; the full list is the page schema in src/content.config.ts.
| Field | What it does |
|---|---|
title, description | The page title and summary |
badge | The small label above the title in the page header |
metaTitle, metaDescription | Replace the title and description in search results only |
image | Social preview image for this page (and the photo on cards, for entries) |
draft | true hides the page from the built site (it still shows in npm run dev) |
customSlug | A different URL segment than the file name. Use the same value in every language |
canonical, robots, keywords | SEO overrides |
excludeFromSitemap, excludeFromAi | Leave the page out of the sitemap, or out of llms.txt and the Markdown copies |
disableTagline | Don’t add the site tagline to this page’s title |
footerLayout | wordmark, newsletter, cta, or contact: another footer on this page. See Footer |
headerLayout | classic, transparent, floating, or promo: another header on this page. See Header |
headerAnnouncement | The announcement strip text on this page (Markdown) |
date, updated | Publish date and last meaningful edit, used in structured data |
Add A Page
For policies, guides, or any page of text. Ecozen renders every file in src/content/pages/ as a page.
-
Copy
src/content/pages/english/terms-conditions.mdto a new file, for examplesrc/content/pages/english/warranty.md. The file name becomes the URL:/warranty/. -
Change
title,description,date, and the Markdown body. -
Create a version in each other language folder of
src/content/pages/with the same file name. -
Add a link to it in every
src/config/menu.*.jsonfile, for example infooterSecondary.
For landing pages that reuse Ecozen’s sections. The demo homepages are the model: their routes read a file from the homepage collection, which accepts every named block.
-
Copy
src/pages/[...lang]/home-two.astrotosrc/pages/[...lang]/battery-offer.astro. The file name becomes the URL:/battery-offer/. -
In the new route, change
getEntryCTM("homepage", "home-two", ...)togetEntryCTM("homepage", "battery-offer", Astro.currentLocale), and createsrc/content/homepage/english/battery-offer.mdwith atitle, ametaDescription, and the named blocks you need, each withenable: true. -
Replace the sections inside
<Base>with the ones you want, and pass each its block:<FaqSection content={data.faqSection} />. -
Create the content file in each other language folder of
src/content/homepage/and add the page to the menus.
Don’t create a section page from a file in src/content/pages/: every file there is also built as a text page at the same URL.
Remove A Page
- Delete its route file in
src/pages/[...lang]/and its content (file or folder) insrc/content/, in every language. - Remove its links from every
src/config/menu.*.jsonfile and any content file or button that links to it (search the project for the URL). - Run
npm run astro-check, thennpm run build, to make sure nothing still points to it.
To hide a page without deleting it, set draft: true in its content file.