Skip to content

Commit 545a5ea

Browse files
committed
feat: expand and refine JSON-LD structured data
- Introduced additional nodes for Organization, WebPage, and Website entities with deterministic `@id` values. - Enhanced metadata for `Person`, including fallback logic and enriched `sameAs` handling. - Added rich details for `BlogPosting` and `WebPage` entities, including language handling and absolute URL linking. - Improved logic for managing `memberOf` and `worksFor` fields with accurate `id` generation. - Excluded invalid `sameAs` URLs to ensure data quality. - Refined logic for image handling and updated conditional checks for date modification.
1 parent 34c3c04 commit 545a5ea

3 files changed

Lines changed: 406 additions & 49 deletions

File tree

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
# JSON-LD Master Instructions (Agent Playbook)
2+
3+
## 0) Mission
4+
Your task is to produce high-quality JSON-LD structured data that is:
5+
- valid JSON
6+
- aligned with Schema.org
7+
- consistent across the site
8+
- strictly accurate to what the page shows
9+
- safe from spam patterns and conflicting markup
10+
11+
You may be asked to create new JSON-LD or to review and improve existing JSON-LD already present on the page. In all cases, follow these instructions.
12+
13+
---
14+
15+
## 1) Non-negotiables (must always hold)
16+
1. **Visible truth only**
17+
Do not mark up facts that are not present on the page (or globally true and clearly represented elsewhere on the site). If it is not visible, do not include it.
18+
19+
2. **One primary intent per page**
20+
Each page must have one clear primary entity. Support entities are allowed but must not confuse what the page is about.
21+
22+
3. **No spam and no shortcuts**
23+
Do not add:
24+
- fake FAQ blocks
25+
- fake reviews or ratings
26+
- misleading offers, availability, pricing
27+
- keyword stuffing or irrelevant schema types
28+
29+
4. **No contradictions**
30+
JSON-LD must not conflict with:
31+
- visible page content
32+
- canonical URL
33+
- other structured data on the same page
34+
35+
5. **Strict JSON**
36+
Must be valid JSON:
37+
- double quotes only
38+
- no trailing commas
39+
- no comments
40+
- no NaN/Infinity
41+
- no dangling undefined fields
42+
43+
---
44+
45+
## 2) Inputs and assumptions
46+
When you receive a page, you must base JSON-LD on:
47+
- the visible content of that page
48+
- the page URL (and canonical URL if provided)
49+
- known site-wide facts (organization/site name, logo, social profiles) only if they can be verified from site-wide context
50+
51+
If key data is missing from the page (example: publish date on an article), do not invent it. Omit the field.
52+
53+
---
54+
55+
## 3) Global entity model (use everywhere)
56+
Implement JSON-LD as a graph whenever possible, with stable nodes that can be reused across pages.
57+
58+
### 3.1 Required stable IDs
59+
Use deterministic @id patterns based on the canonical domain and canonical path. Use absolute URLs.
60+
61+
- Organization:
62+
- `https://{domain}/#org`
63+
- Website:
64+
- `https://{domain}/#website`
65+
- Logo:
66+
- `https://{domain}/#logo`
67+
- WebPage:
68+
- `https://{domain}{path}/#webpage`
69+
- Primary entity (choose by type):
70+
- Article: `https://{domain}{path}/#article`
71+
- BlogPosting: `https://{domain}{path}/#article`
72+
- Product: `https://{domain}{path}/#product`
73+
- Service: `https://{domain}{path}/#service`
74+
- FAQPage: `https://{domain}{path}/#faq`
75+
- Event: `https://{domain}{path}/#event`
76+
77+
Rules:
78+
- Never include query strings or tracking parameters in @id.
79+
- The same entity must always reuse the same @id.
80+
- Do not generate multiple Organization nodes with different @id values.
81+
82+
---
83+
84+
## 4) Base graph (the minimum baseline for most pages)
85+
Unless a page is genuinely exceptional, include these nodes:
86+
- Organization (or LocalBusiness when it is a single-location local business site)
87+
- WebSite
88+
- WebPage
89+
90+
Recommended pattern uses `@graph`:
91+
92+
### Base graph template (fill with real values)
93+
- Always use:
94+
- `@context: "https://schema.org"`
95+
- absolute URLs
96+
- stable @id values
97+
98+
Include:
99+
- Organization:
100+
- name, url
101+
- logo (ImageObject) if available
102+
- sameAs (official social profiles) only if verified
103+
- WebSite:
104+
- url, name, publisher -> Organization
105+
- WebPage:
106+
- url, name
107+
- isPartOf -> WebSite
108+
109+
---
110+
111+
## 5) Pick the correct primary entity
112+
You must choose exactly one primary entity type per page based on page intent.
113+
114+
### 5.1 Common page intents and types
115+
- Home page:
116+
- Primary focus is the site itself: use WebPage as main, plus Organization and WebSite
117+
- Blog post:
118+
- Use `BlogPosting` (or `Article` if not a blog)
119+
- News post:
120+
- Use `NewsArticle` only if it is truly news-style content and the site is operating as a news publisher
121+
- Product detail page:
122+
- Use `Product` and attach `Offer` or `AggregateOffer` if pricing is shown
123+
- Service page:
124+
- Use `Service`
125+
- FAQ page:
126+
- Use `FAQPage` with Question/Answer pairs only if those Q/As are visible on the page
127+
- Category/listing page:
128+
- Use `CollectionPage` and optionally `ItemList` if items are visible and linkable
129+
- About/Company page:
130+
- Often Organization-focused, but keep WebPage and Organization nodes consistent
131+
- Contact page:
132+
- Organization or LocalBusiness plus ContactPoint and PostalAddress if shown
133+
- Event page:
134+
- Use `Event`
135+
136+
### 5.2 Primary entity linkage
137+
Link the page and primary entity using one of these patterns:
138+
- On the primary entity: `mainEntityOfPage` -> WebPage @id or URL
139+
- On WebPage: `mainEntity` -> primary entity @id
140+
141+
Choose one approach and keep it consistent across the site.
142+
143+
---
144+
145+
## 6) Type-specific minimum fields (do not invent)
146+
147+
### 6.1 BlogPosting / Article
148+
Minimum:
149+
- @id
150+
- headline (must match visible title)
151+
- author (Person or Organization, whichever is shown)
152+
- datePublished (only if visible)
153+
- dateModified (only if visible)
154+
- image (only if shown)
155+
- mainEntityOfPage
156+
157+
Recommended:
158+
- publisher -> Organization
159+
- description (only if it matches visible excerpt/summary)
160+
161+
### 6.2 Product + Offer
162+
Product minimum:
163+
- @id
164+
- name
165+
Recommended:
166+
- image, description, brand, sku (only if shown)
167+
168+
Offer minimum (only if price is shown):
169+
- price
170+
- priceCurrency
171+
- availability (only if availability is explicitly shown)
172+
- url
173+
174+
Never add AggregateRating unless real reviews/ratings are visible and supported.
175+
176+
### 6.3 Service
177+
Minimum:
178+
- @id
179+
- name
180+
Recommended:
181+
- description
182+
- provider -> Organization
183+
- areaServed only if clearly stated
184+
185+
### 6.4 FAQPage
186+
Only use if the page visibly contains Q/A pairs.
187+
Minimum:
188+
- mainEntity: array of Question items with acceptedAnswer
189+
190+
Do not add marketing text as fake questions.
191+
192+
### 6.5 Event
193+
Minimum:
194+
- name
195+
- startDate
196+
- location (Place with address or name)
197+
Recommended:
198+
- endDate if known
199+
- offers if tickets/pricing are shown
200+
201+
---
202+
203+
## 7) Breadcrumbs (recommended when UI has breadcrumbs)
204+
If the page UI shows breadcrumbs, include BreadcrumbList:
205+
- itemListElement with ListItem positions
206+
- each item is a name + URL
207+
208+
Do not invent breadcrumb structure if the UI does not show it.
209+
210+
---
211+
212+
## 8) Multi-language handling
213+
If a site supports multiple locales:
214+
- ensure the JSON-LD strings match the page language
215+
- ensure url points to the current locale page URL
216+
- optionally use `inLanguage` on WebPage/Article when known
217+
218+
---
219+
220+
## 9) Cleaning up existing JSON-LD (important)
221+
If JSON-LD already exists on the page:
222+
1. Do not blindly add more.
223+
2. First detect:
224+
- duplicates (multiple Organization nodes, repeated Products, conflicting WebPage URLs)
225+
- invalid JSON
226+
- fields not supported by visible content
227+
- missing linking between WebPage and primary entity
228+
3. Then propose a single consolidated solution:
229+
- one consistent @graph is preferred
230+
- remove duplicated entities
231+
- standardize @id format
232+
- ensure canonical URL alignment
233+
234+
Goal: fewer, cleaner nodes that are correctly linked.
235+
236+
---
237+
238+
## 10) Output requirements (what you must deliver)
239+
When you respond with a solution, provide:
240+
241+
1. **A short summary** of what you changed and why (no fluff).
242+
2. **The final JSON-LD snippet** ready to paste into the page.
243+
3. **A checklist** confirming:
244+
- valid JSON
245+
- matches visible content
246+
- consistent @id strategy
247+
- no spam patterns
248+
4. **Notes** listing anything you intentionally omitted because it was not visible on the page.
249+
250+
---
251+
252+
## 11) Safety rails (common “do not do this”)
253+
Do not:
254+
- add Review or AggregateRating without real visible reviews and required fields
255+
- mark up FAQPage without visible Q/A
256+
- mark up Product on category pages
257+
- use relative URLs for images or @id
258+
- include phone/address/opening hours unless shown
259+
- include social profile sameAs links unless verified
260+
- create multiple conflicting Organization / WebSite nodes
261+
- include invalid availability or price fields
262+
263+
---
264+
265+
## 12) Minimal base graph example (for reference only)
266+
You must adapt to real values. Do not copy as-is.
267+
268+
{
269+
"@context": "https://schema.org",
270+
"@graph": [
271+
{
272+
"@type": "Organization",
273+
"@id": "https://example.com/#org",
274+
"name": "Example",
275+
"url": "https://example.com/",
276+
"logo": {
277+
"@type": "ImageObject",
278+
"@id": "https://example.com/#logo",
279+
"url": "https://example.com/logo.png"
280+
}
281+
},
282+
{
283+
"@type": "WebSite",
284+
"@id": "https://example.com/#website",
285+
"url": "https://example.com/",
286+
"name": "Example",
287+
"publisher": { "@id": "https://example.com/#org" }
288+
},
289+
{
290+
"@type": "WebPage",
291+
"@id": "https://example.com/blog/my-post/#webpage",
292+
"url": "https://example.com/blog/my-post/",
293+
"name": "My Post",
294+
"isPartOf": { "@id": "https://example.com/#website" }
295+
}
296+
]
297+
}
298+
299+
End of file.

content/over-mij/index.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ <h1 class="text-3xl font-semibold text-slate-900 dark:text-slate-100">Maarten Ca
5151
{{< icon name="bluesky" class="h-5 w-5" size="24" >}}
5252
<span>Bluesky</span>
5353
</a>
54+
55+
<a
56+
class="inline-flex items-center gap-2 rounded-full border border-slate-300 bg-white px-4 py-2 text-sm font-semibold text-slate-800 shadow-sm transition hover:border-slate-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-900 motion-reduce:transition-none dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100 dark:hover:border-slate-500 dark:focus-visible:outline-slate-100"
57+
href="https://x.com/denmette"
58+
target="_blank"
59+
rel="noopener"
60+
>
61+
{{< icon name="x" class="h-5 w-5" size="24" >}}
62+
<span>X</span>
63+
</a>
5464
</nav>
5565
</div>
5666
</div>

0 commit comments

Comments
 (0)