Skip to content

Commit

Permalink
Update SEO and Structured Data
Browse files Browse the repository at this point in the history
  • Loading branch information
ruchernchong committed Nov 20, 2024
1 parent ba510d5 commit 8dcc266
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 138 deletions.
42 changes: 25 additions & 17 deletions app/cars/fuel-types/[fuelType]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { capitaliseWords } from "@/utils/capitaliseWords";
import { fetchApi } from "@/utils/fetchApi";
import { mergeCarsByMake } from "@/utils/mergeCarsByMake";
import type { Metadata } from "next";
import type { Dataset, WithContext } from "schema-dts";
import type { WebPage, WithContext } from "schema-dts";

type Params = Promise<{ fuelType: string }>;
type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>;
Expand All @@ -34,20 +34,30 @@ export const generateMetadata = async (props: {
const latestMonth = await fetchApi<LatestMonth>(`${API_URL}/months/latest`);
month = latestMonth.cars;
}

const title = `${capitaliseWords(fuelType)} Cars in Singapore`;
const description = `Explore registration trends and statistics for ${fuelType} in Singapore.`;
const images = `${SITE_URL}/api/og?type=${fuelType}&month=${month}`;
const pageUrl = `/cars/fuel-types/${fuelType}`;

return {
title: capitaliseWords(fuelType),
description: `Car registration trends for ${fuelType} fuel type`,
title,
description,
openGraph: {
title,
description,
images,
url: pageUrl,
siteName: SITE_TITLE,
locale: "en_SG",
type: "website",
},
twitter: { images, creator: "@sgcarstrends" },
twitter: {
title,
description,
images,
creator: "@sgcarstrends",
},
alternates: {
canonical: pageUrl,
},
Expand Down Expand Up @@ -81,24 +91,22 @@ const CarsByFuelTypePage = async (props: {

const filteredCars = mergeCarsByMake(cars);

const structuredData: WithContext<Dataset> = {
const structuredData: WithContext<WebPage> = {
"@context": "https://schema.org",
"@type": "Dataset",
name: `${capitaliseWords(fuelType)} Car Registrations in Singapore`,
description: `Overview and registration statistics for ${fuelType} cars in Singapore by make`,
"@type": "WebPage",
name: `${capitaliseWords(fuelType)} Car in Singapore`,
description: `Explore registration trends and statistics for ${fuelType} in Singapore.`,
url: `${SITE_URL}/cars/fuel-types/${fuelType}`,
creator: {
publisher: {
"@type": "Organization",
name: SITE_TITLE,
url: SITE_URL,
},
isPartOf: {
"@type": "WebSite",
name: SITE_TITLE,
url: SITE_URL,
},
// TODO: For future use
// distribution: [
// {
// "@type": "DataDownload",
// encodingFormat: "image/png",
// contentUrl: `${SITE_URL}/images/${type}-car-stats.png`,
// },
// ],
};

return (
Expand Down
43 changes: 8 additions & 35 deletions app/cars/makes/[make]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { type Car, type Make, RevalidateTags } from "@/types";
import { fetchApi } from "@/utils/fetchApi";
import { formatDateToMonthYear } from "@/utils/formatDateToMonthYear";
import type { Metadata } from "next";
import type { Dataset, WithContext } from "schema-dts";
import type { WebPage, WithContext } from "schema-dts";

type Params = Promise<{ [slug: string]: string }>;

Expand Down Expand Up @@ -73,44 +73,17 @@ const CarMakePage = async (props: { params: Params }) => {
const filteredCars = mergeCarData(cars);

const formattedMake = decodeURIComponent(make);
const structuredData: WithContext<Dataset> = {
const structuredData: WithContext<WebPage> = {
"@context": "https://schema.org",
"@type": "Dataset",
"@type": "WebPage",
name: `${formattedMake} Car Registrations in Singapore`,
description: `Historical trend and monthly breakdown of ${formattedMake} car registrations by fuel type and vehicle type in Singapore`,
url: `${SITE_URL}/cars/makes/${make}`,
// TODO: Suggested by Google
// temporalCoverage: "2016-06/2024-07",
variableMeasured: [
{
"@type": "PropertyValue",
name: "Month",
description: "Month of registration",
},
{
"@type": "PropertyValue",
name: "Fuel Type",
description: "Type of fuel used by the vehicle",
},
{
"@type": "PropertyValue",
name: "Vehicle Type",
description: `Type of ${formattedMake} vehicle`,
},
{
"@type": "PropertyValue",
name: "Count",
description: "Number of registrations",
},
],
// TODO: For future use
// distribution: [
// {
// "@type": "DataDownload",
// encodingFormat: "text/html",
// contentUrl: `https://sgcarstrends.com/cars/${make}-trends.png`,
// },
// ],
publisher: {
"@type": "Organization",
name: SITE_TITLE,
url: SITE_URL,
},
};

return (
Expand Down
88 changes: 29 additions & 59 deletions app/cars/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import { fetchApi } from "@/utils/fetchApi";
import { formatDateToMonthYear } from "@/utils/formatDateToMonthYear";
import type { Metadata } from "next";
import type { Dataset, Report, WithContext } from "schema-dts";
import type { WebPage, WithContext } from "schema-dts";

type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>;

Expand All @@ -38,16 +38,32 @@ export const generateMetadata = async (props: {
}

const formattedDate = formatDateToMonthYear(month);

const title = "Car Registrations";
const description = `Breakdown of cars registered in ${formattedDate} by fuel types and vehicle types.`;
const pageUrl = `/cars`;

// const images = `/api/og?title=Car Registrations for ${formattedDate}`;

return {
title: "Car Registrations",
description: `Breakdown of cars registered in ${formattedDate} by fuel types and vehicle types.`,
openGraph: { url: pageUrl },
twitter: { card: "summary_large_image" },
alternates: { canonical: pageUrl },
title,
description,
openGraph: {
title,
description,
url: pageUrl,
siteName: SITE_TITLE,
locale: "en_SG",
type: "website",
},
twitter: {
title,
description,
card: "summary_large_image",
},
alternates: {
canonical: pageUrl,
},
};
};

Expand Down Expand Up @@ -111,68 +127,22 @@ const CarsPage = async (props: { searchParams: SearchParams }) => {
findTopEntry(numberByVehicleType);

const formattedMonth = formatDateToMonthYear(month);
const datasetJsonLd: WithContext<Dataset> = {
const structuredData: WithContext<WebPage> = {
"@context": "https://schema.org",
"@type": "Dataset",
name: `Singapore Car Registrations ${formattedMonth}`,
description: `Comprehensive overview of car registrations in Singapore for ${formattedMonth}, including total registrations, fuel types, vehicle types, and top manufacturers.`,
"@type": "WebPage",
name: `${formattedMonth} Car Registrations in Singapore`,
description: `Breakdown of the cars registered in ${formattedMonth} by fuel type and vehicle type.`,
url: `${SITE_URL}/cars`,
creator: {
publisher: {
"@type": "Organization",
name: SITE_TITLE,
url: SITE_URL,
},
variableMeasured: [
{
"@type": "PropertyValue",
name: "Total Registrations",
value: total,
},
{
"@type": "PropertyValue",
name: "Top Fuel Type",
value: `${topFuelType} (${topFuelTypeValue})`,
},
{
"@type": "PropertyValue",
name: "Top Vehicle Type",
value: `${topVehicleType} (${topVehicleTypeValue})`,
},
],
};
const reportJsonLd: WithContext<Report> = {
"@context": "https://schema.org",
"@type": "Report",
name: `Singapore Car Registrations Report - ${formattedMonth}`,
description: `Breakdown of the cars registered in ${formattedMonth} by fuel type and vehicle type`,
url: `${SITE_URL}/cars`,
author: {
"@type": "Organization",
name: "SGCarsTrends",
},
genre: "Statistical Report",
mentions: [
{
"@type": "Thing",
name: "Toyota",
description: "Top overall manufacturer with 652 registrations",
},
{
"@type": "Thing",
name: `${topFuelType}`,
description: `Most popular fuel type with ${topFuelTypeValue} registrations`,
},
{
"@type": "Thing",
name: `${topVehicleType}`,
description: `Most popular vehicle type with ${topVehicleTypeValue} registrations`,
},
],
};

return (
<>
<StructuredData data={datasetJsonLd} />
<StructuredData data={reportJsonLd} />
<StructuredData data={structuredData} />
<div className="flex flex-col gap-4">
<div className="grid grid-cols-1 gap-2 lg:grid-cols-2">
<div className="flex items-end gap-2">
Expand Down
31 changes: 14 additions & 17 deletions app/cars/vehicle-types/[vehicleType]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { capitaliseWords } from "@/utils/capitaliseWords";
import { fetchApi } from "@/utils/fetchApi";
import { mergeCarsByMake } from "@/utils/mergeCarsByMake";
import type { Metadata } from "next";
import type { Dataset, WithContext } from "schema-dts";
import type { WebPage, WithContext } from "schema-dts";

type Params = Promise<{ vehicleType: string }>;
type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>;
Expand All @@ -27,13 +27,12 @@ export const generateMetadata = async (props: {
const params = await props.params;
let { vehicleType } = params;
vehicleType = decodeURIComponent(vehicleType);
const description = `${capitaliseWords(vehicleType)} historical trends`;
const images = `/api/og?title=Historical Trend&type=${vehicleType}`;
const canonicalUrl = `/cars/vehicle-types/${vehicleType}`;

return {
title: capitaliseWords(vehicleType),
description,
title: `${capitaliseWords(vehicleType)} Cars in Singapore`,
description: `Explore registration trends and statistics for ${vehicleType} in Singapore.`,
openGraph: {
images,
url: canonicalUrl,
Expand Down Expand Up @@ -85,24 +84,22 @@ const CarsByVehicleTypePage = async (props: {

const filteredCars = mergeCarsByMake(cars);

const structuredData: WithContext<Dataset> = {
const structuredData: WithContext<WebPage> = {
"@context": "https://schema.org",
"@type": "Dataset",
name: `${capitaliseWords(vehicleType)} Car Registrations in Singapore`,
description: `Overview and registration statistics for ${vehicleType} cars in Singapore by vehicle type`,
"@type": "WebPage",
name: `${capitaliseWords(vehicleType)} Cars in Singapore`,
description: `Explore registration trends and statistics for ${vehicleType} in Singapore.`,
url: `${SITE_URL}/cars/vehicle-types/${vehicleType}`,
creator: {
publisher: {
"@type": "Organization",
name: SITE_TITLE,
url: SITE_URL,
},
isPartOf: {
"@type": "WebSite",
name: SITE_TITLE,
url: SITE_URL,
},
// TODO: For future use
// distribution: [
// {
// "@type": "DataDownload",
// encodingFormat: "image/png",
// contentUrl: `${SITE_URL}/images/${type}-car-stats.png`,
// },
// ],
};

return (
Expand Down
36 changes: 26 additions & 10 deletions app/coe/(prices)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { API_URL, SITE_URL } from "@/config";
import { API_URL, SITE_TITLE, SITE_URL } from "@/config";
import {
type COEBiddingResult,
type COEResult,
Expand All @@ -23,14 +23,29 @@ import type { WebPage, WithContext } from "schema-dts";

type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>;

const title = "COE Dashboard";
const description =
"Explore historical trends and bidding results for COE in Singapore.";

export const generateMetadata = async (): Promise<Metadata> => {
const pageUrl = "/coe";

return {
title: "COE Dashboard",
description: "COE bidding results and historical trends",
openGraph: { url: pageUrl },
twitter: { card: "summary_large_image" },
title,
description,
openGraph: {
url: pageUrl,
title: "COE Dashboard",
description,
siteName: SITE_TITLE,
locale: "en_SG",
type: "website",
},
twitter: {
card: "summary_large_image",
title,
description,
},
alternates: {
canonical: pageUrl,
},
Expand Down Expand Up @@ -88,12 +103,13 @@ const COEPricesPage = async (props: { searchParams: SearchParams }) => {
const structuredData: WithContext<WebPage> = {
"@context": "https://schema.org",
"@type": "WebPage",
name: "COE Dashboard",
description: "COE bidding results and historical trends",
url: `${SITE_URL}/car`,
author: {
name: title,
description,
url: `${SITE_URL}/coe`,
publisher: {
"@type": "Organization",
name: "SGCarsTrends",
name: SITE_TITLE,
url: SITE_URL,
},
};

Expand Down

0 comments on commit 8dcc266

Please sign in to comment.