Skip to content
New: Customize your theme with an AI assistant. Read the guide

Reviews & Projects

Files: src/content/reviews/english/, src/content/sections/english/trust-strip.md, src/content/projects/english/ · Skill level: Beginner

Two collections show proof of your work. Reviews are what customers wrote, one file per review. Projects are finished jobs with a before and an after photo, one file per job.

A Review

Each review is one file in src/content/reviews/english/. The file name is free; the samples use date-name-service.md:

---
# Sample review: replace with a real one, with the customer's consent.
name: "Tomas B." # sample; first name and last initial only, no photo
area: "north-harbor" # area id in src/content/areas/ (free text is shown as written)
service: "standard-cleaning" # service id in src/content/services/; drives the filter chips
rating: 5 # whole number, 1 to 5
source: "search" # rating source id from sections/trust-strip.md ("via ..." line)
date: 2025-10-17 # shown as month and year
featured: false # featured band on /reviews/, first pick on the homepage
text: "Two-bedroom flat, two people, just under three hours. …" # up to 700 characters
draft: false
---
FieldWhat it does
nameThe reviewer’s first name and last initial. Reviews never show a photo
areaAn area id (the review then shows on that area’s page) or plain text
serviceA service id. Sets the filter chip on /reviews/ and shows the review on that service’s page
ratingA whole number from 1 to 5
sourceWhere the review came from, as a source id from trust-strip.md (see below)
dateThe date of the review, shown as month and year
textThe review, up to 700 characters. npm run astro-check reports a longer one
featuredPuts the review in the featured band on /reviews/ and first on the homepages
replyOptional answer from you, shown under the review: reply: { text: "…", name: "Ana, office" }

Each language has its own review files. Copy each file to src/content/reviews/french/ with the same name, translate text (and reply), and keep the other fields the same.

Where Reviews Appear

PlaceWhich reviewsSet in
/reviews/Every review, with service chips, a featured band, and the ratings summary (wall layout)src/content/pages/english/reviews.md
HomepagesThe newest and featured reviewsreviewsSection in each homepage file
Service pagesReviews with that service. With fewer than 2, reviews of the same trade fill inreviewsSection in detail: of src/content/services/english/-index.md
Area pagesReviews with that areaThe area file

The section has eight layouts (default, marquee, wall, summary, carousel, spotlight, single, band); see Section Layouts. Its options:

reviewsSection:
summary: true # ratings ledger from sections/trust-strip.md
filter:
service: "" # service id; empty = every service
area: "" # area id; empty = every area
excludeFeatured: true # featured reviews render in the featured band only
limit: 0 # 0 = every review
options:
layout: "wall"

The Rating Summary

The average rating, the review count, and the per-source ratings are typed, not counted from the review files. You copy them from the places where customers review you. They are in src/content/sections/english/trust-strip.md:

rating:
enable: true
value: 4.9 # sample average out of 5
count: 1240 # sample number of reviews
label: "from {count} reviews" # {count} and {value} are replaced
url: "/reviews/"
sources: # Generic labels only; no third-party logos or names
# id: matched by review entries' `source` (reviews page); url: optional "Write a review" link
# updated: optional date the numbers were last copied
- id: "search"
label: "Search reviews"
value: 4.9 # sample
count: 820 # sample
url: "https://example.com/review"
updated: 2026-09-01
  • value and count feed the rating chip on the homepage hero, the trust strip, and the summary on /reviews/.
  • Each source is one row of the ratings summary. url adds a “Write a review” link; updated is the date you last copied the numbers.
  • Keep the labels generic. The shipped file uses “Search reviews”, “Neighbourhood app”, and “After-visit survey” instead of third-party names or logos.
  • Update the numbers when they change. A rating that is out of date or higher than your real one misleads customers.

Why Reviews Have No Rich Results Markup

Homio adds no Review or AggregateRating structured data, on purpose. These are reviews you collect and publish on your own site about your own business. Google does not show review stars for those (“self-serving” reviews), and marking them up anyway goes against its review snippet guidelines. The reviews still help: visitors read them, and search engines read the text. Your star rating in search comes from your business profile and the review sites themselves.

If a review platform you use offers its own widget, follow its terms. Don’t copy its reviews into review markup.

Projects (Before And After)

Each project is one file in src/content/projects/english/ and one page at /projects/<file-name>/. From bathroom-regrout.md:

title: "Shower re-grout and re-caulk"
description: "Cracked grout lines and a mouldy silicone seal around a tiled shower."
date: 2026-08-27 # job date: sorts the grid (newest first) and shows on the ticket
ticket: "4139" # job number, shown as #4139
trade: "repairs" # trade id from `trades:` in src/content/services/english/-index.md
service: "handyman" # service entry id: chip, service link, and /book/?service=
area: "old-mill" # area entry id from src/content/areas/
featured: false # the large card on /projects/ and the homepage job (first `true` wins)
before: "/images/projects/shower-grout-before.jpg" # same crop and angle as `after`
after: "/images/projects/shower-grout-after.jpg"
beforeAlt: "Shower tiles before: dull, stained grout lines"
afterAlt: "The same tiles after: fresh grout lines, tiles cleaned"
caption: "Shower wall, after new grout and a fresh seal" # under the large slider
duration: "4 h" # time on site, shown as written
crewSize: 1
scope: # check rows on the job ticket, in work order
- "Old silicone cut out and the joint cleaned"
- "New silicone seal at the tray"
price: # optional; remove to hide the total row
amount: 310 # sample
note: "Hourly rate, materials included"
quote: # optional customer words about this job
text: "He showed me the soft grout he had raked out …"
name: "Tomás L." # first name and last initial, no photo
detail: "Old Mill"

The Markdown body is the write-up (“The job”, “What we did”, “The result”). gallery adds more before/after pairs as static frames:

gallery: # optional extra pairs, shown as static split frames
- before: "/images/projects/range-degrease-before.jpg"
after: "/images/projects/range-degrease-after.jpg"
beforeAlt: "Range before: grates and steel trim dulled by grease"
afterAlt: "The same range after: grates and trim degreased"
caption: "Range and grates"

price.amount is a plain number in your currency. It is typed, not computed from the pricing file.

Where projects appear: /projects/ (a grid with trade buttons and the featured project large, set in src/content/projects/english/-index.md), the “Similar jobs” block on each project page (relatedProjects in the same file), a recent job on service pages (matched by service), area pages (matched by area), industry pages (matched by industry), and the handyman homepage. A page with no matching project hides the block.

The section’s layouts are default (one large slider beside the job ticket), grid (project cards), and gallery. Its defaults, including the frame shape, are in src/content/sections/english/before-after-section.md:

options:
layout: "default" # default | grid | gallery (masonry of job photos, button)
aspect: "3/2" # slider frame (default layout): 4/5 | square | 3/2 | 4/3
start: 50 # divider start, 0–100 % from the start edge

Align A Before/After Pair

The slider stacks the after photo on the before photo and reveals it as the visitor drags the line (or uses the arrow keys). Both photos are cropped to the same frame (aspect), from the center. If the two photos differ, the line shows a jump instead of a change.

  1. Shoot both from the same spot. Same position, height, lens, and zoom. Mark the spot (a piece of tape on the floor) or take the before photo again from the same marks before you start work.
  2. Keep the same orientation. Both landscape or both portrait.
  3. Crop both the same way. Crop the pair to the same aspect ratio and the same size, ideally the ratio of the frame (3:2 by default, square on service and area pages). The build prints a [BeforeAfter] warning when the two ratios differ by more than 5%.
  4. Save them in src/assets/images/projects/ with matching names (kitchen-before.jpg, kitchen-after.jpg), and write the paths as /images/projects/kitchen-before.jpg.
  5. Write both alt texts so the difference is clear without the image: “Before: …” and “The same … after: …”.
  6. Check the result at /projects/<file-name>/. Drag the line across a fixed point (a tap, a tile edge). It should not move between the two photos.

A project with no after photo shows the before photo alone, without a slider, and the build prints a warning.

To add a project, copy a project file, rename it (the name is the URL), change the fields and photos, and copy it to src/content/projects/french/ with the same name. The service, area, trade, and industry values must be ids that exist, or the project won’t show on those pages.

Do It With AI

Replace the sample reviews with these real ones (I have each customer's consent): [NAME, AREA,
SERVICE, RATING, SOURCE, DATE, TEXT; ...]. One file per review in src/content/reviews/english/,
with the service and area ids that exist in my content. Delete the samples. Then set the rating
in src/content/sections/english/trust-strip.md to [AVERAGE] from [COUNT] reviews, with sources
[LABEL: VALUE, COUNT, URL; ...]. Do the French files too.
Add a project: [TITLE], [SERVICE] in [AREA], [DATE], job number [N], [CREW] crew, [TIME] on site,
scope [STEPS], price [AMOUNT or none]. My photos are [BEFORE FILE] and [AFTER FILE]. Copy them
to src/assets/images/projects/, check they have the same aspect ratio and tell me if not, then
create the project file from src/content/projects/english/bathroom-regrout.md and its French copy.
Type something to search...