@masters-ws/react-seo 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1354 -97
- package/dist/chunk-6RBCF5I5.mjs +567 -0
- package/dist/chunk-FFE2ZOOC.mjs +945 -0
- package/dist/chunk-L6YRMB7H.mjs +988 -0
- package/dist/core/index.d.mts +2 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.js +684 -40
- package/dist/core/index.mjs +29 -3
- package/dist/index-CkB-Wt4c.d.mts +1272 -0
- package/dist/index-CkB-Wt4c.d.ts +1272 -0
- package/dist/index-DEE7ZyDx.d.mts +1193 -0
- package/dist/index-DEE7ZyDx.d.ts +1193 -0
- package/dist/index-Wu9j5oCk.d.mts +721 -0
- package/dist/index-Wu9j5oCk.d.ts +721 -0
- package/dist/index.d.mts +13 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +794 -129
- package/dist/index.mjs +57 -10
- package/package.json +1 -1
|
@@ -0,0 +1,1193 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface SiteConfig {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
url: string;
|
|
7
|
+
logo?: string;
|
|
8
|
+
publisher?: string;
|
|
9
|
+
twitterHandle?: string;
|
|
10
|
+
facebookAppId?: string;
|
|
11
|
+
language?: string;
|
|
12
|
+
socialLinks?: string[];
|
|
13
|
+
googleAnalyticsId?: string;
|
|
14
|
+
gtmId?: string;
|
|
15
|
+
facebookPixelId?: string;
|
|
16
|
+
yandexMetricaId?: string;
|
|
17
|
+
themeColor?: string;
|
|
18
|
+
manifest?: string;
|
|
19
|
+
}
|
|
20
|
+
interface SEOData {
|
|
21
|
+
title?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
image?: string;
|
|
24
|
+
canonical?: string;
|
|
25
|
+
type?: 'website' | 'article' | 'product' | 'profile' | 'video' | 'faq';
|
|
26
|
+
robots?: string;
|
|
27
|
+
noindex?: boolean;
|
|
28
|
+
keywords?: string[];
|
|
29
|
+
prev?: string;
|
|
30
|
+
next?: string;
|
|
31
|
+
alternates?: Array<{
|
|
32
|
+
hreflang: string;
|
|
33
|
+
href: string;
|
|
34
|
+
}>;
|
|
35
|
+
ogTitle?: string;
|
|
36
|
+
ogDescription?: string;
|
|
37
|
+
ogImage?: string;
|
|
38
|
+
ogImageWidth?: number;
|
|
39
|
+
ogImageHeight?: number;
|
|
40
|
+
ogImageAlt?: string;
|
|
41
|
+
ogType?: string;
|
|
42
|
+
ogLocale?: string;
|
|
43
|
+
twitterCard?: 'summary' | 'summary_large_image' | 'app' | 'player';
|
|
44
|
+
twitterTitle?: string;
|
|
45
|
+
twitterDescription?: string;
|
|
46
|
+
twitterImage?: string;
|
|
47
|
+
twitterImageAlt?: string;
|
|
48
|
+
publishedTime?: string;
|
|
49
|
+
modifiedTime?: string;
|
|
50
|
+
author?: {
|
|
51
|
+
name: string;
|
|
52
|
+
url?: string;
|
|
53
|
+
image?: string;
|
|
54
|
+
};
|
|
55
|
+
tags?: string[];
|
|
56
|
+
section?: string;
|
|
57
|
+
readingTime?: number;
|
|
58
|
+
product?: {
|
|
59
|
+
sku?: string;
|
|
60
|
+
brand?: string;
|
|
61
|
+
price?: number;
|
|
62
|
+
currency?: string;
|
|
63
|
+
availability?: string;
|
|
64
|
+
rating?: number;
|
|
65
|
+
reviewCount?: number;
|
|
66
|
+
};
|
|
67
|
+
dnsPrefetch?: string[];
|
|
68
|
+
preconnect?: string[];
|
|
69
|
+
prefetch?: string[];
|
|
70
|
+
preload?: Array<{
|
|
71
|
+
href: string;
|
|
72
|
+
as: string;
|
|
73
|
+
type?: string;
|
|
74
|
+
}>;
|
|
75
|
+
whatsappImage?: string;
|
|
76
|
+
whatsappDescription?: string;
|
|
77
|
+
schema?: any;
|
|
78
|
+
}
|
|
79
|
+
interface BreadcrumbItem {
|
|
80
|
+
name: string;
|
|
81
|
+
item: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Generate Organization Schema
|
|
86
|
+
*/
|
|
87
|
+
declare function generateOrganizationSchema(config: SiteConfig): {
|
|
88
|
+
"@context": string;
|
|
89
|
+
"@type": string;
|
|
90
|
+
name: string;
|
|
91
|
+
url: string;
|
|
92
|
+
logo: string | undefined;
|
|
93
|
+
description: string;
|
|
94
|
+
sameAs: string[];
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Generate WebSite Schema with SearchAction
|
|
98
|
+
*/
|
|
99
|
+
declare function generateWebSiteSchema(config: SiteConfig): {
|
|
100
|
+
"@context": string;
|
|
101
|
+
"@type": string;
|
|
102
|
+
name: string;
|
|
103
|
+
url: string;
|
|
104
|
+
description: string;
|
|
105
|
+
publisher: {
|
|
106
|
+
"@type": string;
|
|
107
|
+
name: string;
|
|
108
|
+
logo: string | undefined;
|
|
109
|
+
};
|
|
110
|
+
potentialAction: {
|
|
111
|
+
"@type": string;
|
|
112
|
+
target: string;
|
|
113
|
+
"query-input": string;
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Generate WebPage Schema
|
|
118
|
+
*/
|
|
119
|
+
declare function generateWebPageSchema(data: {
|
|
120
|
+
name: string;
|
|
121
|
+
description: string;
|
|
122
|
+
url: string;
|
|
123
|
+
image?: string;
|
|
124
|
+
datePublished?: string;
|
|
125
|
+
dateModified?: string;
|
|
126
|
+
breadcrumb?: Array<{
|
|
127
|
+
name: string;
|
|
128
|
+
item: string;
|
|
129
|
+
}>;
|
|
130
|
+
}, config: SiteConfig): {
|
|
131
|
+
"@context": string;
|
|
132
|
+
"@type": string;
|
|
133
|
+
name: string;
|
|
134
|
+
description: string;
|
|
135
|
+
url: string;
|
|
136
|
+
image: string | undefined;
|
|
137
|
+
datePublished: string | undefined;
|
|
138
|
+
dateModified: string | undefined;
|
|
139
|
+
isPartOf: {
|
|
140
|
+
"@type": string;
|
|
141
|
+
name: string;
|
|
142
|
+
url: string;
|
|
143
|
+
};
|
|
144
|
+
breadcrumb: {
|
|
145
|
+
"@context": string;
|
|
146
|
+
"@type": string;
|
|
147
|
+
itemListElement: {
|
|
148
|
+
"@type": string;
|
|
149
|
+
position: number;
|
|
150
|
+
name: string;
|
|
151
|
+
item: string;
|
|
152
|
+
}[];
|
|
153
|
+
} | undefined;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Generate CollectionPage Schema (for category / archive pages)
|
|
157
|
+
*/
|
|
158
|
+
declare function generateCollectionPageSchema(data: {
|
|
159
|
+
name: string;
|
|
160
|
+
description: string;
|
|
161
|
+
url: string;
|
|
162
|
+
image?: string;
|
|
163
|
+
numberOfItems?: number;
|
|
164
|
+
}, config: SiteConfig): {
|
|
165
|
+
"@context": string;
|
|
166
|
+
"@type": string;
|
|
167
|
+
name: string;
|
|
168
|
+
description: string;
|
|
169
|
+
url: string;
|
|
170
|
+
image: string | undefined;
|
|
171
|
+
numberOfItems: number | undefined;
|
|
172
|
+
isPartOf: {
|
|
173
|
+
"@type": string;
|
|
174
|
+
name: string;
|
|
175
|
+
url: string;
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
/**
|
|
179
|
+
* Generate ItemList Schema (for product listings, search results, etc.)
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* generateItemListSchema({
|
|
183
|
+
* name: "Electronics",
|
|
184
|
+
* url: "https://store.com/electronics",
|
|
185
|
+
* items: products.map(p => ({
|
|
186
|
+
* name: p.name,
|
|
187
|
+
* url: `https://store.com/products/${p.slug}`,
|
|
188
|
+
* image: p.image,
|
|
189
|
+
* position: p.index + 1,
|
|
190
|
+
* })),
|
|
191
|
+
* });
|
|
192
|
+
*/
|
|
193
|
+
declare function generateItemListSchema(data: {
|
|
194
|
+
name?: string;
|
|
195
|
+
url?: string;
|
|
196
|
+
itemListOrder?: 'ascending' | 'descending' | 'unordered';
|
|
197
|
+
items: Array<{
|
|
198
|
+
url: string;
|
|
199
|
+
name: string;
|
|
200
|
+
image?: string;
|
|
201
|
+
position?: number;
|
|
202
|
+
}>;
|
|
203
|
+
}): {
|
|
204
|
+
"@context": string;
|
|
205
|
+
"@type": string;
|
|
206
|
+
name: string | undefined;
|
|
207
|
+
url: string | undefined;
|
|
208
|
+
itemListOrder: string;
|
|
209
|
+
numberOfItems: number;
|
|
210
|
+
itemListElement: {
|
|
211
|
+
"@type": string;
|
|
212
|
+
position: number;
|
|
213
|
+
name: string;
|
|
214
|
+
url: string;
|
|
215
|
+
image: string | undefined;
|
|
216
|
+
}[];
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* Generate NewsArticle Schema
|
|
220
|
+
*/
|
|
221
|
+
declare function generateArticleSchema(data: {
|
|
222
|
+
title: string;
|
|
223
|
+
description: string;
|
|
224
|
+
image?: string | string[];
|
|
225
|
+
publishedTime?: string;
|
|
226
|
+
modifiedTime?: string;
|
|
227
|
+
author?: {
|
|
228
|
+
name: string;
|
|
229
|
+
url?: string;
|
|
230
|
+
};
|
|
231
|
+
url?: string;
|
|
232
|
+
wordCount?: number;
|
|
233
|
+
}, config: SiteConfig): {
|
|
234
|
+
"@context": string;
|
|
235
|
+
"@type": string;
|
|
236
|
+
headline: string;
|
|
237
|
+
description: string;
|
|
238
|
+
image: string | string[] | undefined;
|
|
239
|
+
datePublished: string | undefined;
|
|
240
|
+
dateModified: string | undefined;
|
|
241
|
+
mainEntityOfPage: string | undefined;
|
|
242
|
+
wordCount: number | undefined;
|
|
243
|
+
author: {
|
|
244
|
+
"@context": string;
|
|
245
|
+
"@type": string;
|
|
246
|
+
name: string;
|
|
247
|
+
url: string;
|
|
248
|
+
logo: string | undefined;
|
|
249
|
+
description: string;
|
|
250
|
+
sameAs: string[];
|
|
251
|
+
} | {
|
|
252
|
+
"@type": string;
|
|
253
|
+
name: string;
|
|
254
|
+
url: string | undefined;
|
|
255
|
+
};
|
|
256
|
+
publisher: {
|
|
257
|
+
"@context": string;
|
|
258
|
+
"@type": string;
|
|
259
|
+
name: string;
|
|
260
|
+
url: string;
|
|
261
|
+
logo: string | undefined;
|
|
262
|
+
description: string;
|
|
263
|
+
sameAs: string[];
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Product review for use in Product schema
|
|
268
|
+
*/
|
|
269
|
+
interface ProductReview {
|
|
270
|
+
author: string;
|
|
271
|
+
datePublished?: string;
|
|
272
|
+
reviewBody?: string;
|
|
273
|
+
ratingValue: number;
|
|
274
|
+
bestRating?: number;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Merchant return policy for Product schema
|
|
278
|
+
*/
|
|
279
|
+
interface MerchantReturnPolicy {
|
|
280
|
+
returnPolicyCategory?: 'MerchantReturnFiniteReturnWindow' | 'MerchantReturnNotPermitted' | 'MerchantReturnUnlimitedWindow';
|
|
281
|
+
returnWithin?: number;
|
|
282
|
+
returnMethod?: 'ReturnByMail' | 'ReturnInStore' | 'ReturnAtKiosk';
|
|
283
|
+
returnFees?: 'FreeReturn' | 'ReturnFeesCustomerResponsibility' | 'OriginalShippingFees';
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Shipping details for Product schema
|
|
287
|
+
*/
|
|
288
|
+
interface ShippingDetails {
|
|
289
|
+
shippingRate?: {
|
|
290
|
+
value: number;
|
|
291
|
+
currency: string;
|
|
292
|
+
};
|
|
293
|
+
shippingDestination?: string;
|
|
294
|
+
deliveryTime?: {
|
|
295
|
+
minDays: number;
|
|
296
|
+
maxDays: number;
|
|
297
|
+
};
|
|
298
|
+
freeShippingThreshold?: number;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Product offer variant
|
|
302
|
+
*/
|
|
303
|
+
interface ProductVariant {
|
|
304
|
+
name: string;
|
|
305
|
+
sku?: string;
|
|
306
|
+
price: number;
|
|
307
|
+
currency?: string;
|
|
308
|
+
availability?: string;
|
|
309
|
+
url?: string;
|
|
310
|
+
image?: string;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Generate Product Schema
|
|
314
|
+
* Supports multi-image, individual reviews, return policy, shipping, and variants.
|
|
315
|
+
*/
|
|
316
|
+
declare function generateProductSchema(data: {
|
|
317
|
+
name: string;
|
|
318
|
+
description: string;
|
|
319
|
+
image?: string | string[];
|
|
320
|
+
sku?: string;
|
|
321
|
+
gtin?: string;
|
|
322
|
+
mpn?: string;
|
|
323
|
+
brand?: string;
|
|
324
|
+
price?: number;
|
|
325
|
+
currency?: string;
|
|
326
|
+
availability?: string;
|
|
327
|
+
rating?: number;
|
|
328
|
+
reviewCount?: number;
|
|
329
|
+
url?: string;
|
|
330
|
+
condition?: 'NewCondition' | 'UsedCondition' | 'RefurbishedCondition' | 'DamagedCondition';
|
|
331
|
+
reviews?: ProductReview[];
|
|
332
|
+
returnPolicy?: MerchantReturnPolicy;
|
|
333
|
+
shipping?: ShippingDetails;
|
|
334
|
+
variants?: ProductVariant[];
|
|
335
|
+
seller?: {
|
|
336
|
+
name: string;
|
|
337
|
+
url?: string;
|
|
338
|
+
};
|
|
339
|
+
}): {
|
|
340
|
+
"@context": string;
|
|
341
|
+
"@type": string;
|
|
342
|
+
name: string;
|
|
343
|
+
description: string;
|
|
344
|
+
image: string | string[] | undefined;
|
|
345
|
+
sku: string | undefined;
|
|
346
|
+
gtin: string | undefined;
|
|
347
|
+
mpn: string | undefined;
|
|
348
|
+
brand: {
|
|
349
|
+
"@type": string;
|
|
350
|
+
name: string;
|
|
351
|
+
} | undefined;
|
|
352
|
+
offers: any;
|
|
353
|
+
aggregateRating: {
|
|
354
|
+
"@type": string;
|
|
355
|
+
ratingValue: number;
|
|
356
|
+
reviewCount: number;
|
|
357
|
+
} | undefined;
|
|
358
|
+
review: {
|
|
359
|
+
"@type": string;
|
|
360
|
+
author: {
|
|
361
|
+
"@type": string;
|
|
362
|
+
name: string;
|
|
363
|
+
};
|
|
364
|
+
datePublished: string | undefined;
|
|
365
|
+
reviewBody: string | undefined;
|
|
366
|
+
reviewRating: {
|
|
367
|
+
"@type": string;
|
|
368
|
+
ratingValue: number;
|
|
369
|
+
bestRating: number;
|
|
370
|
+
};
|
|
371
|
+
}[] | undefined;
|
|
372
|
+
};
|
|
373
|
+
/**
|
|
374
|
+
* Generate FAQ Schema
|
|
375
|
+
*/
|
|
376
|
+
declare function generateFAQSchema(questions: Array<{
|
|
377
|
+
q: string;
|
|
378
|
+
a: string;
|
|
379
|
+
}>): {
|
|
380
|
+
"@context": string;
|
|
381
|
+
"@type": string;
|
|
382
|
+
mainEntity: {
|
|
383
|
+
"@type": string;
|
|
384
|
+
name: string;
|
|
385
|
+
acceptedAnswer: {
|
|
386
|
+
"@type": string;
|
|
387
|
+
text: string;
|
|
388
|
+
};
|
|
389
|
+
}[];
|
|
390
|
+
};
|
|
391
|
+
/**
|
|
392
|
+
* Generate Breadcrumb Schema
|
|
393
|
+
*/
|
|
394
|
+
declare function generateBreadcrumbSchema(items: Array<{
|
|
395
|
+
name: string;
|
|
396
|
+
item: string;
|
|
397
|
+
}>): {
|
|
398
|
+
"@context": string;
|
|
399
|
+
"@type": string;
|
|
400
|
+
itemListElement: {
|
|
401
|
+
"@type": string;
|
|
402
|
+
position: number;
|
|
403
|
+
name: string;
|
|
404
|
+
item: string;
|
|
405
|
+
}[];
|
|
406
|
+
};
|
|
407
|
+
/**
|
|
408
|
+
* Generate Video Schema
|
|
409
|
+
*/
|
|
410
|
+
declare function generateVideoSchema(data: {
|
|
411
|
+
name: string;
|
|
412
|
+
description: string;
|
|
413
|
+
thumbnailUrl: string;
|
|
414
|
+
uploadDate: string;
|
|
415
|
+
duration?: string;
|
|
416
|
+
contentUrl?: string;
|
|
417
|
+
embedUrl?: string;
|
|
418
|
+
}): {
|
|
419
|
+
"@context": string;
|
|
420
|
+
"@type": string;
|
|
421
|
+
name: string;
|
|
422
|
+
description: string;
|
|
423
|
+
thumbnailUrl: string;
|
|
424
|
+
uploadDate: string;
|
|
425
|
+
duration: string | undefined;
|
|
426
|
+
contentUrl: string | undefined;
|
|
427
|
+
embedUrl: string | undefined;
|
|
428
|
+
};
|
|
429
|
+
/**
|
|
430
|
+
* Generate Event Schema
|
|
431
|
+
*/
|
|
432
|
+
declare function generateEventSchema(data: {
|
|
433
|
+
name: string;
|
|
434
|
+
description: string;
|
|
435
|
+
startDate: string;
|
|
436
|
+
endDate?: string;
|
|
437
|
+
location?: {
|
|
438
|
+
name: string;
|
|
439
|
+
address: string;
|
|
440
|
+
} | {
|
|
441
|
+
url: string;
|
|
442
|
+
};
|
|
443
|
+
image?: string;
|
|
444
|
+
offers?: {
|
|
445
|
+
price: number;
|
|
446
|
+
currency: string;
|
|
447
|
+
url: string;
|
|
448
|
+
};
|
|
449
|
+
}): {
|
|
450
|
+
"@context": string;
|
|
451
|
+
"@type": string;
|
|
452
|
+
name: string;
|
|
453
|
+
description: string;
|
|
454
|
+
startDate: string;
|
|
455
|
+
endDate: string | undefined;
|
|
456
|
+
eventAttendanceMode: string;
|
|
457
|
+
location: {
|
|
458
|
+
"@type": string;
|
|
459
|
+
url: string;
|
|
460
|
+
name?: undefined;
|
|
461
|
+
address?: undefined;
|
|
462
|
+
} | {
|
|
463
|
+
"@type": string;
|
|
464
|
+
name: string;
|
|
465
|
+
address: string;
|
|
466
|
+
url?: undefined;
|
|
467
|
+
} | undefined;
|
|
468
|
+
image: string | undefined;
|
|
469
|
+
offers: {
|
|
470
|
+
"@type": string;
|
|
471
|
+
price: number;
|
|
472
|
+
priceCurrency: string;
|
|
473
|
+
url: string;
|
|
474
|
+
} | undefined;
|
|
475
|
+
};
|
|
476
|
+
/**
|
|
477
|
+
* Generate LocalBusiness Schema
|
|
478
|
+
*/
|
|
479
|
+
declare function generateLocalBusinessSchema(data: {
|
|
480
|
+
name: string;
|
|
481
|
+
description: string;
|
|
482
|
+
image?: string;
|
|
483
|
+
telephone?: string;
|
|
484
|
+
address: {
|
|
485
|
+
street: string;
|
|
486
|
+
city: string;
|
|
487
|
+
region?: string;
|
|
488
|
+
postalCode?: string;
|
|
489
|
+
country: string;
|
|
490
|
+
};
|
|
491
|
+
geo?: {
|
|
492
|
+
lat: number;
|
|
493
|
+
lng: number;
|
|
494
|
+
};
|
|
495
|
+
openingHours?: string[];
|
|
496
|
+
priceRange?: string;
|
|
497
|
+
}): {
|
|
498
|
+
"@context": string;
|
|
499
|
+
"@type": string;
|
|
500
|
+
name: string;
|
|
501
|
+
description: string;
|
|
502
|
+
image: string | undefined;
|
|
503
|
+
telephone: string | undefined;
|
|
504
|
+
address: {
|
|
505
|
+
"@type": string;
|
|
506
|
+
streetAddress: string;
|
|
507
|
+
addressLocality: string;
|
|
508
|
+
addressRegion: string | undefined;
|
|
509
|
+
postalCode: string | undefined;
|
|
510
|
+
addressCountry: string;
|
|
511
|
+
};
|
|
512
|
+
geo: {
|
|
513
|
+
"@type": string;
|
|
514
|
+
latitude: number;
|
|
515
|
+
longitude: number;
|
|
516
|
+
} | undefined;
|
|
517
|
+
openingHours: string[] | undefined;
|
|
518
|
+
priceRange: string | undefined;
|
|
519
|
+
};
|
|
520
|
+
/**
|
|
521
|
+
* Generate SoftwareApplication Schema
|
|
522
|
+
*/
|
|
523
|
+
declare function generateSoftwareSchema(data: {
|
|
524
|
+
name: string;
|
|
525
|
+
description: string;
|
|
526
|
+
operatingSystem?: string;
|
|
527
|
+
applicationCategory?: string;
|
|
528
|
+
offers?: {
|
|
529
|
+
price: number;
|
|
530
|
+
currency: string;
|
|
531
|
+
};
|
|
532
|
+
rating?: number;
|
|
533
|
+
reviewCount?: number;
|
|
534
|
+
downloadUrl?: string;
|
|
535
|
+
screenshot?: string;
|
|
536
|
+
}): {
|
|
537
|
+
"@context": string;
|
|
538
|
+
"@type": string;
|
|
539
|
+
name: string;
|
|
540
|
+
description: string;
|
|
541
|
+
operatingSystem: string | undefined;
|
|
542
|
+
applicationCategory: string | undefined;
|
|
543
|
+
offers: {
|
|
544
|
+
"@type": string;
|
|
545
|
+
price: number;
|
|
546
|
+
priceCurrency: string;
|
|
547
|
+
} | undefined;
|
|
548
|
+
aggregateRating: {
|
|
549
|
+
"@type": string;
|
|
550
|
+
ratingValue: number;
|
|
551
|
+
reviewCount: number;
|
|
552
|
+
} | undefined;
|
|
553
|
+
downloadUrl: string | undefined;
|
|
554
|
+
screenshot: string | undefined;
|
|
555
|
+
};
|
|
556
|
+
/**
|
|
557
|
+
* Generate Book Schema
|
|
558
|
+
*/
|
|
559
|
+
declare function generateBookSchema(data: {
|
|
560
|
+
name: string;
|
|
561
|
+
author: string | {
|
|
562
|
+
name: string;
|
|
563
|
+
url?: string;
|
|
564
|
+
};
|
|
565
|
+
description: string;
|
|
566
|
+
isbn?: string;
|
|
567
|
+
numberOfPages?: number;
|
|
568
|
+
publisher?: string;
|
|
569
|
+
datePublished?: string;
|
|
570
|
+
image?: string;
|
|
571
|
+
inLanguage?: string;
|
|
572
|
+
genre?: string;
|
|
573
|
+
}): {
|
|
574
|
+
"@context": string;
|
|
575
|
+
"@type": string;
|
|
576
|
+
name: string;
|
|
577
|
+
author: {
|
|
578
|
+
"@type": string;
|
|
579
|
+
name: string;
|
|
580
|
+
url?: undefined;
|
|
581
|
+
} | {
|
|
582
|
+
"@type": string;
|
|
583
|
+
name: string;
|
|
584
|
+
url: string | undefined;
|
|
585
|
+
};
|
|
586
|
+
description: string;
|
|
587
|
+
isbn: string | undefined;
|
|
588
|
+
numberOfPages: number | undefined;
|
|
589
|
+
publisher: {
|
|
590
|
+
"@type": string;
|
|
591
|
+
name: string;
|
|
592
|
+
} | undefined;
|
|
593
|
+
datePublished: string | undefined;
|
|
594
|
+
image: string | undefined;
|
|
595
|
+
inLanguage: string | undefined;
|
|
596
|
+
genre: string | undefined;
|
|
597
|
+
};
|
|
598
|
+
/**
|
|
599
|
+
* Generate Movie Schema
|
|
600
|
+
*/
|
|
601
|
+
declare function generateMovieSchema(data: {
|
|
602
|
+
name: string;
|
|
603
|
+
description: string;
|
|
604
|
+
image?: string;
|
|
605
|
+
director?: string;
|
|
606
|
+
actor?: string[];
|
|
607
|
+
dateCreated?: string;
|
|
608
|
+
duration?: string;
|
|
609
|
+
genre?: string[];
|
|
610
|
+
rating?: number;
|
|
611
|
+
reviewCount?: number;
|
|
612
|
+
}): {
|
|
613
|
+
"@context": string;
|
|
614
|
+
"@type": string;
|
|
615
|
+
name: string;
|
|
616
|
+
description: string;
|
|
617
|
+
image: string | undefined;
|
|
618
|
+
director: {
|
|
619
|
+
"@type": string;
|
|
620
|
+
name: string;
|
|
621
|
+
} | undefined;
|
|
622
|
+
actor: {
|
|
623
|
+
"@type": string;
|
|
624
|
+
name: string;
|
|
625
|
+
}[] | undefined;
|
|
626
|
+
dateCreated: string | undefined;
|
|
627
|
+
duration: string | undefined;
|
|
628
|
+
genre: string[] | undefined;
|
|
629
|
+
aggregateRating: {
|
|
630
|
+
"@type": string;
|
|
631
|
+
ratingValue: number;
|
|
632
|
+
reviewCount: number;
|
|
633
|
+
} | undefined;
|
|
634
|
+
};
|
|
635
|
+
/**
|
|
636
|
+
* Generate Podcast Schema (PodcastSeries)
|
|
637
|
+
*/
|
|
638
|
+
declare function generatePodcastSchema(data: {
|
|
639
|
+
name: string;
|
|
640
|
+
description: string;
|
|
641
|
+
image?: string;
|
|
642
|
+
author?: string;
|
|
643
|
+
webFeed?: string;
|
|
644
|
+
url?: string;
|
|
645
|
+
genre?: string;
|
|
646
|
+
}): {
|
|
647
|
+
"@context": string;
|
|
648
|
+
"@type": string;
|
|
649
|
+
name: string;
|
|
650
|
+
description: string;
|
|
651
|
+
image: string | undefined;
|
|
652
|
+
author: {
|
|
653
|
+
"@type": string;
|
|
654
|
+
name: string;
|
|
655
|
+
} | undefined;
|
|
656
|
+
webFeed: string | undefined;
|
|
657
|
+
url: string | undefined;
|
|
658
|
+
genre: string | undefined;
|
|
659
|
+
};
|
|
660
|
+
/**
|
|
661
|
+
* Generate PodcastEpisode Schema
|
|
662
|
+
*/
|
|
663
|
+
declare function generatePodcastEpisodeSchema(data: {
|
|
664
|
+
name: string;
|
|
665
|
+
description: string;
|
|
666
|
+
datePublished: string;
|
|
667
|
+
duration?: string;
|
|
668
|
+
url?: string;
|
|
669
|
+
audio?: string;
|
|
670
|
+
partOfSeries?: {
|
|
671
|
+
name: string;
|
|
672
|
+
url: string;
|
|
673
|
+
};
|
|
674
|
+
}): {
|
|
675
|
+
"@context": string;
|
|
676
|
+
"@type": string;
|
|
677
|
+
name: string;
|
|
678
|
+
description: string;
|
|
679
|
+
datePublished: string;
|
|
680
|
+
timeRequired: string | undefined;
|
|
681
|
+
url: string | undefined;
|
|
682
|
+
associatedMedia: {
|
|
683
|
+
"@type": string;
|
|
684
|
+
contentUrl: string;
|
|
685
|
+
} | undefined;
|
|
686
|
+
partOfSeries: {
|
|
687
|
+
"@type": string;
|
|
688
|
+
name: string;
|
|
689
|
+
url: string;
|
|
690
|
+
} | undefined;
|
|
691
|
+
};
|
|
692
|
+
/**
|
|
693
|
+
* Generate HowTo Schema
|
|
694
|
+
*/
|
|
695
|
+
declare function generateHowToSchema(data: {
|
|
696
|
+
name: string;
|
|
697
|
+
description?: string;
|
|
698
|
+
image?: string;
|
|
699
|
+
totalTime?: string;
|
|
700
|
+
estimatedCost?: {
|
|
701
|
+
currency: string;
|
|
702
|
+
value: number;
|
|
703
|
+
};
|
|
704
|
+
supply?: string[];
|
|
705
|
+
tool?: string[];
|
|
706
|
+
steps: Array<{
|
|
707
|
+
name?: string;
|
|
708
|
+
text: string;
|
|
709
|
+
image?: string;
|
|
710
|
+
url?: string;
|
|
711
|
+
}> | string[];
|
|
712
|
+
}): {
|
|
713
|
+
"@context": string;
|
|
714
|
+
"@type": string;
|
|
715
|
+
name: string;
|
|
716
|
+
description: string | undefined;
|
|
717
|
+
image: string | undefined;
|
|
718
|
+
totalTime: string | undefined;
|
|
719
|
+
estimatedCost: {
|
|
720
|
+
"@type": string;
|
|
721
|
+
currency: string;
|
|
722
|
+
value: number;
|
|
723
|
+
} | undefined;
|
|
724
|
+
supply: {
|
|
725
|
+
"@type": string;
|
|
726
|
+
name: string;
|
|
727
|
+
}[] | undefined;
|
|
728
|
+
tool: {
|
|
729
|
+
"@type": string;
|
|
730
|
+
name: string;
|
|
731
|
+
}[] | undefined;
|
|
732
|
+
step: ({
|
|
733
|
+
"@type": string;
|
|
734
|
+
position: number;
|
|
735
|
+
name: string | undefined;
|
|
736
|
+
text: string;
|
|
737
|
+
image: string | undefined;
|
|
738
|
+
url: string | undefined;
|
|
739
|
+
} | {
|
|
740
|
+
"@type": string;
|
|
741
|
+
position: number;
|
|
742
|
+
text: string;
|
|
743
|
+
})[];
|
|
744
|
+
};
|
|
745
|
+
/**
|
|
746
|
+
* Generate Recipe Schema
|
|
747
|
+
*/
|
|
748
|
+
declare function generateRecipeSchema(data: {
|
|
749
|
+
name: string;
|
|
750
|
+
description: string;
|
|
751
|
+
image: string | string[];
|
|
752
|
+
author: string;
|
|
753
|
+
publishedDate?: string;
|
|
754
|
+
prepTime?: string;
|
|
755
|
+
cookTime?: string;
|
|
756
|
+
totalTime?: string;
|
|
757
|
+
recipeYield?: string;
|
|
758
|
+
recipeCategory?: string;
|
|
759
|
+
recipeCuisine?: string;
|
|
760
|
+
ingredients: string[];
|
|
761
|
+
instructions: Array<{
|
|
762
|
+
name?: string;
|
|
763
|
+
text: string;
|
|
764
|
+
image?: string;
|
|
765
|
+
}>;
|
|
766
|
+
rating?: number;
|
|
767
|
+
reviewCount?: number;
|
|
768
|
+
}): {
|
|
769
|
+
"@context": string;
|
|
770
|
+
"@type": string;
|
|
771
|
+
name: string;
|
|
772
|
+
description: string;
|
|
773
|
+
image: string | string[];
|
|
774
|
+
author: {
|
|
775
|
+
"@type": string;
|
|
776
|
+
name: string;
|
|
777
|
+
};
|
|
778
|
+
datePublished: string | undefined;
|
|
779
|
+
prepTime: string | undefined;
|
|
780
|
+
cookTime: string | undefined;
|
|
781
|
+
totalTime: string | undefined;
|
|
782
|
+
recipeYield: string | undefined;
|
|
783
|
+
recipeCategory: string | undefined;
|
|
784
|
+
recipeCuisine: string | undefined;
|
|
785
|
+
recipeIngredient: string[];
|
|
786
|
+
recipeInstructions: {
|
|
787
|
+
"@type": string;
|
|
788
|
+
name: string | undefined;
|
|
789
|
+
text: string;
|
|
790
|
+
image: string | undefined;
|
|
791
|
+
}[];
|
|
792
|
+
aggregateRating: {
|
|
793
|
+
"@type": string;
|
|
794
|
+
ratingValue: number;
|
|
795
|
+
reviewCount: number;
|
|
796
|
+
} | undefined;
|
|
797
|
+
};
|
|
798
|
+
/**
|
|
799
|
+
* Generate JobPosting Schema
|
|
800
|
+
*/
|
|
801
|
+
declare function generateJobPostingSchema(data: {
|
|
802
|
+
title: string;
|
|
803
|
+
description: string;
|
|
804
|
+
datePosted: string;
|
|
805
|
+
validThrough?: string;
|
|
806
|
+
employmentType?: string | string[];
|
|
807
|
+
hiringOrganization: {
|
|
808
|
+
name: string;
|
|
809
|
+
sameAs?: string;
|
|
810
|
+
logo?: string;
|
|
811
|
+
};
|
|
812
|
+
jobLocation: {
|
|
813
|
+
streetAddress: string;
|
|
814
|
+
addressLocality: string;
|
|
815
|
+
addressRegion?: string;
|
|
816
|
+
postalCode?: string;
|
|
817
|
+
addressCountry: string;
|
|
818
|
+
};
|
|
819
|
+
remote?: boolean;
|
|
820
|
+
baseSalary?: {
|
|
821
|
+
currency: string;
|
|
822
|
+
value: number | {
|
|
823
|
+
minValue: number;
|
|
824
|
+
maxValue: number;
|
|
825
|
+
};
|
|
826
|
+
unitText?: string;
|
|
827
|
+
};
|
|
828
|
+
}): {
|
|
829
|
+
"@context": string;
|
|
830
|
+
"@type": string;
|
|
831
|
+
title: string;
|
|
832
|
+
description: string;
|
|
833
|
+
datePosted: string;
|
|
834
|
+
validThrough: string | undefined;
|
|
835
|
+
employmentType: string | string[] | undefined;
|
|
836
|
+
jobLocationType: string | undefined;
|
|
837
|
+
hiringOrganization: {
|
|
838
|
+
"@type": string;
|
|
839
|
+
name: string;
|
|
840
|
+
sameAs: string | undefined;
|
|
841
|
+
logo: string | undefined;
|
|
842
|
+
};
|
|
843
|
+
jobLocation: {
|
|
844
|
+
"@type": string;
|
|
845
|
+
address: {
|
|
846
|
+
"@type": string;
|
|
847
|
+
streetAddress: string;
|
|
848
|
+
addressLocality: string;
|
|
849
|
+
addressRegion: string | undefined;
|
|
850
|
+
postalCode: string | undefined;
|
|
851
|
+
addressCountry: string;
|
|
852
|
+
};
|
|
853
|
+
};
|
|
854
|
+
baseSalary: {
|
|
855
|
+
"@type": string;
|
|
856
|
+
currency: string;
|
|
857
|
+
value: {
|
|
858
|
+
"@type": string;
|
|
859
|
+
value: number;
|
|
860
|
+
unitText: string;
|
|
861
|
+
minValue?: undefined;
|
|
862
|
+
maxValue?: undefined;
|
|
863
|
+
} | {
|
|
864
|
+
"@type": string;
|
|
865
|
+
minValue: number;
|
|
866
|
+
maxValue: number;
|
|
867
|
+
unitText: string;
|
|
868
|
+
value?: undefined;
|
|
869
|
+
};
|
|
870
|
+
} | undefined;
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Converts SEOData and SiteConfig to a Next.js compatible Metadata object.
|
|
875
|
+
* This is designed to be used in Server Components (App Router).
|
|
876
|
+
*
|
|
877
|
+
* @example
|
|
878
|
+
* // In page.tsx (Server Component - no 'use client')
|
|
879
|
+
* import { toNextMetadata } from '@masters-ws/react-seo/core';
|
|
880
|
+
*
|
|
881
|
+
* export async function generateMetadata({ params }) {
|
|
882
|
+
* const post = await getPost(params.id);
|
|
883
|
+
* return toNextMetadata({ title: post.title, ... }, siteConfig);
|
|
884
|
+
* }
|
|
885
|
+
*/
|
|
886
|
+
declare function toNextMetadata(props: SEOData, config: SiteConfig): any;
|
|
887
|
+
/**
|
|
888
|
+
* Generates pagination links for category/tag pages.
|
|
889
|
+
* Returns { prev, next, canonical } URLs.
|
|
890
|
+
*/
|
|
891
|
+
declare function generatePaginationLinks(baseUrl: string, currentPage: number, totalPages: number): {
|
|
892
|
+
next: string | undefined;
|
|
893
|
+
prev: string | undefined;
|
|
894
|
+
canonical: string;
|
|
895
|
+
};
|
|
896
|
+
/**
|
|
897
|
+
* Generates title with page number suffix for paginated pages.
|
|
898
|
+
*/
|
|
899
|
+
declare function generatePaginatedTitle(title: string, page: number, suffix?: string): string;
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* Deep-cleans a schema object by removing all undefined and null values.
|
|
903
|
+
* This prevents invalid JSON-LD output like {"sku": undefined}.
|
|
904
|
+
*
|
|
905
|
+
* @example
|
|
906
|
+
* const schema = cleanSchema({
|
|
907
|
+
* "@type": "Product",
|
|
908
|
+
* "name": "Shirt",
|
|
909
|
+
* "sku": undefined, // ← removed
|
|
910
|
+
* "brand": null, // ← removed
|
|
911
|
+
* "offers": {
|
|
912
|
+
* "@type": "Offer",
|
|
913
|
+
* "price": 29.99,
|
|
914
|
+
* "seller": undefined // ← removed
|
|
915
|
+
* }
|
|
916
|
+
* });
|
|
917
|
+
*/
|
|
918
|
+
declare function cleanSchema<T extends Record<string, any>>(obj: T): T;
|
|
919
|
+
/**
|
|
920
|
+
* SEO validation warnings for development mode.
|
|
921
|
+
* Only logs in development (process.env.NODE_ENV !== 'production').
|
|
922
|
+
*
|
|
923
|
+
* @example
|
|
924
|
+
* validateSEO('Product', {
|
|
925
|
+
* name: product.name,
|
|
926
|
+
* price: product.price,
|
|
927
|
+
* }, ['name', 'price', 'image']);
|
|
928
|
+
*/
|
|
929
|
+
declare function validateSEO(schemaType: string, data: Record<string, any>, requiredFields: string[]): string[];
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* Server-safe JSON-LD component for Next.js App Router.
|
|
933
|
+
* Renders schema markup as <script type="application/ld+json"> in server-rendered HTML.
|
|
934
|
+
*
|
|
935
|
+
* Unlike Helmet-based components, this works in Server Components,
|
|
936
|
+
* so Google sees the schemas on first crawl without JavaScript execution.
|
|
937
|
+
*
|
|
938
|
+
* @example
|
|
939
|
+
* // Single schema
|
|
940
|
+
* <JsonLd schema={productSchema} />
|
|
941
|
+
*
|
|
942
|
+
* // Multiple schemas (separate <script> tags)
|
|
943
|
+
* <JsonLd schema={[productSchema, breadcrumbSchema]} />
|
|
944
|
+
*
|
|
945
|
+
* // Multiple schemas using @graph pattern (single <script> tag — recommended)
|
|
946
|
+
* <JsonLd schema={[productSchema, breadcrumbSchema]} graph />
|
|
947
|
+
*/
|
|
948
|
+
interface JsonLdProps {
|
|
949
|
+
/** A single schema object or an array of schema objects */
|
|
950
|
+
schema: Record<string, any> | Record<string, any>[];
|
|
951
|
+
/**
|
|
952
|
+
* If true, combines all schemas into a single <script> using the @graph pattern.
|
|
953
|
+
* This is Google's recommended approach for pages with multiple related schemas.
|
|
954
|
+
*
|
|
955
|
+
* When graph is true, individual @context properties are removed from each schema
|
|
956
|
+
* and a single @context is added at the top level.
|
|
957
|
+
*
|
|
958
|
+
* @default false
|
|
959
|
+
*/
|
|
960
|
+
graph?: boolean;
|
|
961
|
+
}
|
|
962
|
+
declare function JsonLd({ schema, graph }: JsonLdProps): react_jsx_runtime.JSX.Element;
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Product metadata input for convenience helper
|
|
966
|
+
*/
|
|
967
|
+
interface ProductMetadataInput {
|
|
968
|
+
name: string;
|
|
969
|
+
description: string;
|
|
970
|
+
image?: string | string[];
|
|
971
|
+
sku?: string;
|
|
972
|
+
gtin?: string;
|
|
973
|
+
mpn?: string;
|
|
974
|
+
brand?: string;
|
|
975
|
+
price?: number;
|
|
976
|
+
currency?: string;
|
|
977
|
+
availability?: string;
|
|
978
|
+
rating?: number;
|
|
979
|
+
reviewCount?: number;
|
|
980
|
+
url: string;
|
|
981
|
+
condition?: 'NewCondition' | 'UsedCondition' | 'RefurbishedCondition' | 'DamagedCondition';
|
|
982
|
+
metaTitle?: string;
|
|
983
|
+
metaDescription?: string;
|
|
984
|
+
canonical?: string;
|
|
985
|
+
noindex?: boolean;
|
|
986
|
+
breadcrumbs?: Array<{
|
|
987
|
+
name: string;
|
|
988
|
+
item: string;
|
|
989
|
+
}>;
|
|
990
|
+
category?: string;
|
|
991
|
+
ogImage?: string;
|
|
992
|
+
ogImageWidth?: number;
|
|
993
|
+
ogImageHeight?: number;
|
|
994
|
+
reviews?: ProductReview[];
|
|
995
|
+
returnPolicy?: MerchantReturnPolicy;
|
|
996
|
+
shipping?: ShippingDetails;
|
|
997
|
+
variants?: ProductVariant[];
|
|
998
|
+
seller?: {
|
|
999
|
+
name: string;
|
|
1000
|
+
url?: string;
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Result from generateProductMetadata
|
|
1005
|
+
*/
|
|
1006
|
+
interface ProductMetadataResult {
|
|
1007
|
+
/** Next.js Metadata object - use as return from generateMetadata() */
|
|
1008
|
+
metadata: any;
|
|
1009
|
+
/** All JSON-LD schemas for the product page */
|
|
1010
|
+
schemas: Record<string, any>[];
|
|
1011
|
+
/** Individual schemas for granular control */
|
|
1012
|
+
productSchema: Record<string, any>;
|
|
1013
|
+
breadcrumbSchema: Record<string, any>;
|
|
1014
|
+
organizationSchema: Record<string, any>;
|
|
1015
|
+
websiteSchema: Record<string, any>;
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* All-in-one helper for product pages in Next.js App Router.
|
|
1019
|
+
* Generates both the Metadata object AND all JSON-LD schemas in one call.
|
|
1020
|
+
*
|
|
1021
|
+
* @example
|
|
1022
|
+
* ```tsx
|
|
1023
|
+
* // app/products/[slug]/page.tsx (Server Component)
|
|
1024
|
+
* import { generateProductMetadata, JsonLd } from '@masters-ws/react-seo/core';
|
|
1025
|
+
*
|
|
1026
|
+
* const siteConfig = { name: 'My Store', url: 'https://store.com', ... };
|
|
1027
|
+
*
|
|
1028
|
+
* export async function generateMetadata({ params }) {
|
|
1029
|
+
* const product = await fetchProduct(params.slug);
|
|
1030
|
+
* const { metadata } = generateProductMetadata(product, siteConfig);
|
|
1031
|
+
* return metadata;
|
|
1032
|
+
* }
|
|
1033
|
+
*
|
|
1034
|
+
* export default async function ProductPage({ params }) {
|
|
1035
|
+
* const product = await fetchProduct(params.slug);
|
|
1036
|
+
* const { schemas } = generateProductMetadata(product, siteConfig);
|
|
1037
|
+
* return (
|
|
1038
|
+
* <>
|
|
1039
|
+
* <JsonLd schema={schemas} graph />
|
|
1040
|
+
* <ProductDetailClient product={product} />
|
|
1041
|
+
* </>
|
|
1042
|
+
* );
|
|
1043
|
+
* }
|
|
1044
|
+
* ```
|
|
1045
|
+
*/
|
|
1046
|
+
declare function generateProductMetadata(product: ProductMetadataInput, config: SiteConfig): ProductMetadataResult;
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Article metadata input for convenience helper
|
|
1050
|
+
*/
|
|
1051
|
+
interface ArticleMetadataInput {
|
|
1052
|
+
title: string;
|
|
1053
|
+
description: string;
|
|
1054
|
+
image?: string | string[];
|
|
1055
|
+
publishedTime: string;
|
|
1056
|
+
modifiedTime?: string;
|
|
1057
|
+
author?: {
|
|
1058
|
+
name: string;
|
|
1059
|
+
url?: string;
|
|
1060
|
+
image?: string;
|
|
1061
|
+
};
|
|
1062
|
+
url: string;
|
|
1063
|
+
category?: string;
|
|
1064
|
+
tags?: string[];
|
|
1065
|
+
readingTime?: number;
|
|
1066
|
+
wordCount?: number;
|
|
1067
|
+
metaTitle?: string;
|
|
1068
|
+
metaDescription?: string;
|
|
1069
|
+
canonical?: string;
|
|
1070
|
+
noindex?: boolean;
|
|
1071
|
+
breadcrumbs?: Array<{
|
|
1072
|
+
name: string;
|
|
1073
|
+
item: string;
|
|
1074
|
+
}>;
|
|
1075
|
+
ogImage?: string;
|
|
1076
|
+
ogImageWidth?: number;
|
|
1077
|
+
ogImageHeight?: number;
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Result from generateArticleMetadata
|
|
1081
|
+
*/
|
|
1082
|
+
interface ArticleMetadataResult {
|
|
1083
|
+
/** Next.js Metadata object - use as return from generateMetadata() */
|
|
1084
|
+
metadata: any;
|
|
1085
|
+
/** All JSON-LD schemas for the article page */
|
|
1086
|
+
schemas: Record<string, any>[];
|
|
1087
|
+
/** Individual schemas for granular control */
|
|
1088
|
+
articleSchema: Record<string, any>;
|
|
1089
|
+
breadcrumbSchema: Record<string, any>;
|
|
1090
|
+
organizationSchema: Record<string, any>;
|
|
1091
|
+
websiteSchema: Record<string, any>;
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* All-in-one helper for article pages in Next.js App Router.
|
|
1095
|
+
* Generates both the Metadata object AND all JSON-LD schemas in one call.
|
|
1096
|
+
*
|
|
1097
|
+
* @example
|
|
1098
|
+
* ```tsx
|
|
1099
|
+
* // app/news/[slug]/page.tsx (Server Component)
|
|
1100
|
+
* import { generateArticleMetadata, JsonLd } from '@masters-ws/react-seo/core';
|
|
1101
|
+
*
|
|
1102
|
+
* export async function generateMetadata({ params }) {
|
|
1103
|
+
* const article = await fetchArticle(params.slug);
|
|
1104
|
+
* const { metadata } = generateArticleMetadata(article, siteConfig);
|
|
1105
|
+
* return metadata;
|
|
1106
|
+
* }
|
|
1107
|
+
*
|
|
1108
|
+
* export default async function ArticlePage({ params }) {
|
|
1109
|
+
* const article = await fetchArticle(params.slug);
|
|
1110
|
+
* const { schemas } = generateArticleMetadata(article, siteConfig);
|
|
1111
|
+
* return (
|
|
1112
|
+
* <>
|
|
1113
|
+
* <JsonLd schema={schemas} graph />
|
|
1114
|
+
* <article>...</article>
|
|
1115
|
+
* </>
|
|
1116
|
+
* );
|
|
1117
|
+
* }
|
|
1118
|
+
* ```
|
|
1119
|
+
*/
|
|
1120
|
+
declare function generateArticleMetadata(article: ArticleMetadataInput, config: SiteConfig): ArticleMetadataResult;
|
|
1121
|
+
|
|
1122
|
+
/**
|
|
1123
|
+
* Category/Collection metadata input
|
|
1124
|
+
*/
|
|
1125
|
+
interface CategoryMetadataInput {
|
|
1126
|
+
name: string;
|
|
1127
|
+
description: string;
|
|
1128
|
+
image?: string;
|
|
1129
|
+
url: string;
|
|
1130
|
+
page?: number;
|
|
1131
|
+
totalPages?: number;
|
|
1132
|
+
metaTitle?: string;
|
|
1133
|
+
metaDescription?: string;
|
|
1134
|
+
noindex?: boolean;
|
|
1135
|
+
breadcrumbs?: Array<{
|
|
1136
|
+
name: string;
|
|
1137
|
+
item: string;
|
|
1138
|
+
}>;
|
|
1139
|
+
parentCategory?: string;
|
|
1140
|
+
items?: Array<{
|
|
1141
|
+
url: string;
|
|
1142
|
+
name: string;
|
|
1143
|
+
image?: string;
|
|
1144
|
+
position?: number;
|
|
1145
|
+
}>;
|
|
1146
|
+
pageSuffix?: string;
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Result from generateCategoryMetadata
|
|
1150
|
+
*/
|
|
1151
|
+
interface CategoryMetadataResult {
|
|
1152
|
+
/** Next.js Metadata object */
|
|
1153
|
+
metadata: any;
|
|
1154
|
+
/** All JSON-LD schemas */
|
|
1155
|
+
schemas: Record<string, any>[];
|
|
1156
|
+
/** Individual schemas */
|
|
1157
|
+
collectionPageSchema: Record<string, any>;
|
|
1158
|
+
breadcrumbSchema: Record<string, any>;
|
|
1159
|
+
organizationSchema: Record<string, any>;
|
|
1160
|
+
itemListSchema?: Record<string, any>;
|
|
1161
|
+
}
|
|
1162
|
+
/**
|
|
1163
|
+
* All-in-one helper for category/collection pages in Next.js App Router.
|
|
1164
|
+
* Handles pagination, ItemList schema, and CollectionPage schema.
|
|
1165
|
+
*
|
|
1166
|
+
* @example
|
|
1167
|
+
* ```tsx
|
|
1168
|
+
* // app/categories/[slug]/page.tsx (Server Component)
|
|
1169
|
+
* import { generateCategoryMetadata, JsonLd } from '@masters-ws/react-seo/core';
|
|
1170
|
+
*
|
|
1171
|
+
* export async function generateMetadata({ params, searchParams }) {
|
|
1172
|
+
* const page = Number(searchParams.page) || 1;
|
|
1173
|
+
* const category = await fetchCategory(params.slug);
|
|
1174
|
+
* const { metadata } = generateCategoryMetadata({
|
|
1175
|
+
* name: category.name,
|
|
1176
|
+
* description: category.description,
|
|
1177
|
+
* url: `https://store.com/categories/${params.slug}`,
|
|
1178
|
+
* page,
|
|
1179
|
+
* totalPages: category.totalPages,
|
|
1180
|
+
* items: category.products.map((p, i) => ({
|
|
1181
|
+
* name: p.name,
|
|
1182
|
+
* url: `https://store.com/products/${p.slug}`,
|
|
1183
|
+
* image: p.image,
|
|
1184
|
+
* position: i + 1,
|
|
1185
|
+
* })),
|
|
1186
|
+
* }, siteConfig);
|
|
1187
|
+
* return metadata;
|
|
1188
|
+
* }
|
|
1189
|
+
* ```
|
|
1190
|
+
*/
|
|
1191
|
+
declare function generateCategoryMetadata(category: CategoryMetadataInput, config: SiteConfig): CategoryMetadataResult;
|
|
1192
|
+
|
|
1193
|
+
export { type ArticleMetadataInput as A, type BreadcrumbItem as B, type CategoryMetadataInput as C, generatePodcastSchema as D, generateProductMetadata as E, generateProductSchema as F, generateRecipeSchema as G, generateSoftwareSchema as H, generateVideoSchema as I, JsonLd as J, generateWebPageSchema as K, generateWebSiteSchema as L, type MerchantReturnPolicy as M, toNextMetadata as N, validateSEO as O, type ProductMetadataInput as P, type SiteConfig as S, type SEOData as a, type ArticleMetadataResult as b, type CategoryMetadataResult as c, type JsonLdProps as d, type ProductMetadataResult as e, type ProductReview as f, type ProductVariant as g, type ShippingDetails as h, cleanSchema as i, generateArticleMetadata as j, generateArticleSchema as k, generateBookSchema as l, generateBreadcrumbSchema as m, generateCategoryMetadata as n, generateCollectionPageSchema as o, generateEventSchema as p, generateFAQSchema as q, generateHowToSchema as r, generateItemListSchema as s, generateJobPostingSchema as t, generateLocalBusinessSchema as u, generateMovieSchema as v, generateOrganizationSchema as w, generatePaginatedTitle as x, generatePaginationLinks as y, generatePodcastEpisodeSchema as z };
|