From 4f50ffab736b9cd94c670f07dbfe12ac165a8d06 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Thu, 26 Mar 2026 12:04:27 +0100 Subject: [PATCH 1/3] fix: resolve structured data errors on app pages by switching to WebApplication type --- .../apps/[application]/page-jsonld.tsx | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/app/[locale]/apps/[application]/page-jsonld.tsx b/app/[locale]/apps/[application]/page-jsonld.tsx index 11b065c8824..a43af2dd456 100644 --- a/app/[locale]/apps/[application]/page-jsonld.tsx +++ b/app/[locale]/apps/[application]/page-jsonld.tsx @@ -1,4 +1,4 @@ -import { AppData, FileContributor } from "@/lib/types" +import { AppCategory, AppData, FileContributor } from "@/lib/types" import PageJsonLD from "@/components/PageJsonLD" @@ -8,6 +8,19 @@ import { } from "@/lib/utils/jsonld" import { normalizeUrlForJsonLd, slugify } from "@/lib/utils/url" +// Map internal app categories to schema.org enumerated applicationCategory values +// https://schema.org/applicationCategory +const APPLICATION_CATEGORY_MAP: Record = { + DeFi: "FinanceApplication", + Collectibles: "EntertainmentApplication", + Social: "SocialNetworkingApplication", + Gaming: "GameApplication", + Bridge: "UtilitiesApplication", + Productivity: "BusinessApplication", + Privacy: "SecurityApplication", + DAO: "BusinessApplication", +} + export default async function AppsAppJsonLD({ locale, app, @@ -71,15 +84,22 @@ export default async function AppsAppJsonLD({ mainEntity: { "@id": `${url}#applications` }, }, { - "@type": "SoftwareApplication", + "@type": "WebApplication", "@id": `${url}#applications`, name: app.name, description: app.description, url: app.url, image: app.image, - applicationCategory: app.category, + applicationCategory: + APPLICATION_CATEGORY_MAP[app.category] ?? "UtilitiesApplication", applicationSubCategory: app.subCategory.join(", "), operatingSystem: "Web Browser", + offers: { + "@type": "Offer", + price: "0", + priceCurrency: "USD", + availability: "https://schema.org/OnlineOnly", + }, author: [ { "@type": "Organization", From aba79d9690ff3abc7e0111569e0062b53d7121fa Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Thu, 26 Mar 2026 12:13:55 +0100 Subject: [PATCH 2/3] fix: use absolute urls and truncate descriptions in course structured data --- app/[locale]/developers/tutorials/page-jsonld.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/[locale]/developers/tutorials/page-jsonld.tsx b/app/[locale]/developers/tutorials/page-jsonld.tsx index 19ab014cde6..86068f8b1c5 100644 --- a/app/[locale]/developers/tutorials/page-jsonld.tsx +++ b/app/[locale]/developers/tutorials/page-jsonld.tsx @@ -87,12 +87,15 @@ export default async function TutorialsPageJsonLD({ "@type": "ListItem", position: index + 1, name: tutorial.title, - url: tutorial.href, + url: normalizeUrlForJsonLd(locale, tutorial.href), item: { "@type": "Course", name: tutorial.title, - description: tutorial.description, - url: tutorial.href, + description: + tutorial.description.length > 60 + ? tutorial.description.slice(0, 57) + "..." + : tutorial.description, + url: normalizeUrlForJsonLd(locale, tutorial.href), provider: ethereumFoundationOrganization, courseMode: "online", educationalLevel: tutorial.skill ?? "beginner", From e53af90917d01114677cf344c680b670d9c466a9 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Thu, 26 Mar 2026 12:28:26 +0100 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20resolve=20event=20structured=20data?= =?UTF-8?q?=20errors=20=E2=80=94=20add=20startdate,=20berlin=20address,=20?= =?UTF-8?q?use=20place=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/[locale]/community/events/page-jsonld.tsx | 8 ++++++-- src/data/community-hub-schemas.ts | 6 +++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/[locale]/community/events/page-jsonld.tsx b/app/[locale]/community/events/page-jsonld.tsx index 03dab23711d..1c460c9b037 100644 --- a/app/[locale]/community/events/page-jsonld.tsx +++ b/app/[locale]/community/events/page-jsonld.tsx @@ -45,7 +45,9 @@ function buildHubSchemaNodes( if (schema.address) { placeNode.address = { "@type": "PostalAddress" as const, - streetAddress: schema.address.streetAddress, + ...(schema.address.streetAddress && { + streetAddress: schema.address.streetAddress, + }), addressLocality: schema.address.addressLocality, ...(schema.address.postalCode && { postalCode: schema.address.postalCode, @@ -56,7 +58,7 @@ function buildHubSchemaNodes( if (schema.containedInPlace) { placeNode.containedInPlace = { - "@type": "LocalBusiness" as const, + "@type": "Place" as const, name: schema.containedInPlace.name, ...(schema.containedInPlace.url && { url: schema.containedInPlace.url, @@ -69,6 +71,8 @@ function buildHubSchemaNodes( "@id": seriesId, name: schema.eventSeriesName ?? "Open Ethereum Coworking Hours", description: schema.eventDescription, + startDate: + schema.schedule.startDate ?? new Date().toISOString().split("T")[0], isAccessibleForFree: true, url: hub.coworkingSignupUrl, eventStatus: "https://schema.org/EventScheduled", diff --git a/src/data/community-hub-schemas.ts b/src/data/community-hub-schemas.ts index 47f1f61c4d9..ea43f05846d 100644 --- a/src/data/community-hub-schemas.ts +++ b/src/data/community-hub-schemas.ts @@ -13,7 +13,7 @@ export type CommunityHubSchemaData = { eventSeriesName?: string eventDescription: string address?: { - streetAddress: string + streetAddress?: string addressLocality: string postalCode?: string addressCountry: string @@ -68,6 +68,10 @@ export const communityHubSchemas: Record = { eventSeriesName: "Ethereum Community Hub Berlin -- Co-working Wednesdays", eventDescription: "Every Wednesday the Ethereum Foundation office opens for builders, researchers, creators, students, and explorers to co-work, connect, and collaborate.", + address: { + addressLocality: "Berlin", + addressCountry: "DE", + }, schedule: { startTime: "10:00", endTime: "20:00",