@marvalt/digivalt-core 0.2.30 → 0.2.33
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/CHANGELOG.md +35 -0
- package/GLOBAL-SHORTCODES.md +7 -7
- package/README.md +10 -8
- package/bin/env-example-fragments.cjs +6 -0
- package/bin/init.cjs +44 -5
- package/dist/generators/index.d.ts +3 -0
- package/dist/generators/prerender-seo.d.ts +6 -0
- package/dist/generators/seo-manifest.d.ts +3 -0
- package/dist/generators/seo-urls.d.ts +29 -0
- package/dist/generators/sitemap-paths.d.ts +5 -9
- package/dist/generators.cjs +1005 -155
- package/dist/generators.cjs.map +1 -1
- package/dist/generators.d.ts +86 -6
- package/dist/generators.esm.js +992 -156
- package/dist/generators.esm.js.map +1 -1
- package/dist/index.cjs +1019 -156
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +103 -9
- package/dist/index.esm.js +1006 -157
- package/dist/index.esm.js.map +1 -1
- package/dist/registry/index.d.ts +20 -0
- package/dist/registry.cjs +1528 -0
- package/dist/registry.cjs.map +1 -0
- package/dist/registry.d.ts +26 -0
- package/dist/registry.esm.js +1523 -0
- package/dist/registry.esm.js.map +1 -0
- package/dist/seo/DigiValtRouteSeo.d.ts +12 -0
- package/dist/seo/DigiValtSeoHead.d.ts +2 -0
- package/dist/seo/buildPageJsonLd.d.ts +11 -0
- package/dist/seo/html.d.ts +8 -0
- package/dist/seo/index.d.ts +7 -0
- package/dist/seo/resolvePageSeo.d.ts +17 -0
- package/dist/seo/seoTypes.d.ts +57 -0
- package/dist/seo.cjs +307 -86
- package/dist/seo.cjs.map +1 -1
- package/dist/seo.d.ts +105 -2
- package/dist/seo.esm.js +300 -87
- package/dist/seo.esm.js.map +1 -1
- package/dist/static/wpStatic.d.ts +16 -0
- package/dist/static.cjs +10 -0
- package/dist/static.cjs.map +1 -1
- package/dist/static.d.ts +38 -2
- package/dist/static.esm.js +10 -1
- package/dist/static.esm.js.map +1 -1
- package/dist/utils/notifications.d.ts +3 -0
- package/docs/AI-LOCAL-WORDPRESS-BOOTSTRAP.md +7 -3
- package/docs/AI-MASTER-PROMPT.md +37 -0
- package/docs/ENVIRONMENT.md +3 -3
- package/docs/README.md +6 -4
- package/docs/SEO-AIO.md +59 -0
- package/docs/SEO-PERFORMANCE.md +44 -11
- package/docs/SHORTCODES.md +4 -5
- package/package.json +17 -6
- package/template/DIGIVALT_SETUP.md +14 -8
- package/template/functions/robots.txt.ts +27 -0
- package/template/functions/sitemap.xml.ts +143 -65
- package/template/scripts/generate.ts +3 -10
- package/template/scripts/prerender-seo.ts +10 -0
- package/docs/LOVABLE-MASTER-PROMPT.md +0 -140
package/dist/index.cjs
CHANGED
|
@@ -9,6 +9,7 @@ var sadapter = require('@marvalt/sadapter');
|
|
|
9
9
|
var promises = require('fs/promises');
|
|
10
10
|
var fs = require('fs');
|
|
11
11
|
|
|
12
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
12
13
|
const DEFAULT_ENABLED_POST_TYPES = 'posts,pages';
|
|
13
14
|
/** Integration tokens in VITE_ENABLED_POST_TYPES that are not WordPress CPTs. */
|
|
14
15
|
const PSEUDO_POST_TYPES = new Set(['google_reviews']);
|
|
@@ -363,21 +364,6 @@ async function generateGoogleReviewsData(options) {
|
|
|
363
364
|
}
|
|
364
365
|
}
|
|
365
366
|
|
|
366
|
-
const SITEMAP_SKIP_TOP_LEVEL_KEYS = new Set([
|
|
367
|
-
'config',
|
|
368
|
-
'site_settings',
|
|
369
|
-
'header',
|
|
370
|
-
'footer',
|
|
371
|
-
'theme_styles',
|
|
372
|
-
'navigation_menu',
|
|
373
|
-
'menus',
|
|
374
|
-
'categories',
|
|
375
|
-
'tags',
|
|
376
|
-
'generated_at',
|
|
377
|
-
'frontend_id',
|
|
378
|
-
'frontend_name',
|
|
379
|
-
'front_page',
|
|
380
|
-
]);
|
|
381
367
|
function normalizePathname(pathname) {
|
|
382
368
|
const decoded = decodeURIComponent(pathname);
|
|
383
369
|
if (!decoded || decoded === '/')
|
|
@@ -385,43 +371,265 @@ function normalizePathname(pathname) {
|
|
|
385
371
|
const stripped = decoded.replace(/\/+$/, '');
|
|
386
372
|
return stripped === '' ? '/' : stripped;
|
|
387
373
|
}
|
|
388
|
-
function
|
|
389
|
-
const
|
|
390
|
-
const
|
|
391
|
-
if (
|
|
392
|
-
|
|
393
|
-
|
|
374
|
+
function joinPath(prefix, slug) {
|
|
375
|
+
const p = prefix.replace(/\/+$/, '');
|
|
376
|
+
const s = slug.replace(/^\/+/, '');
|
|
377
|
+
if (!p || p === '/')
|
|
378
|
+
return normalizePathname(`/${s}`);
|
|
379
|
+
return normalizePathname(`${p.startsWith('/') ? p : `/${p}`}/${s}`);
|
|
380
|
+
}
|
|
381
|
+
function stripHtml(html) {
|
|
382
|
+
return html
|
|
383
|
+
.replace(/<script[\s\S]*?<\/script>/gi, ' ')
|
|
384
|
+
.replace(/<style[\s\S]*?<\/style>/gi, ' ')
|
|
385
|
+
.replace(/<[^>]+>/g, ' ')
|
|
386
|
+
.replace(/\s+/g, ' ')
|
|
387
|
+
.trim();
|
|
388
|
+
}
|
|
389
|
+
function sanitizeBodyHtml(html) {
|
|
390
|
+
return html
|
|
391
|
+
.replace(/<script[\s\S]*?<\/script>/gi, '')
|
|
392
|
+
.replace(/<style[\s\S]*?<\/style>/gi, '')
|
|
393
|
+
.replace(/\son\w+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, '');
|
|
394
|
+
}
|
|
395
|
+
function renderedText(value) {
|
|
396
|
+
if (typeof value === 'string')
|
|
397
|
+
return stripHtml(value);
|
|
398
|
+
if (value && typeof value === 'object' && 'rendered' in value) {
|
|
399
|
+
const r = value.rendered;
|
|
400
|
+
if (typeof r === 'string')
|
|
401
|
+
return stripHtml(r);
|
|
402
|
+
}
|
|
403
|
+
return '';
|
|
404
|
+
}
|
|
405
|
+
function renderedHtml(value) {
|
|
406
|
+
if (typeof value === 'string')
|
|
407
|
+
return value;
|
|
408
|
+
if (value && typeof value === 'object' && 'rendered' in value) {
|
|
409
|
+
const r = value.rendered;
|
|
410
|
+
if (typeof r === 'string')
|
|
411
|
+
return r;
|
|
412
|
+
}
|
|
413
|
+
return '';
|
|
414
|
+
}
|
|
415
|
+
function escapeHtml(s) {
|
|
416
|
+
return s
|
|
417
|
+
.replace(/&/g, '&')
|
|
418
|
+
.replace(/</g, '<')
|
|
419
|
+
.replace(/>/g, '>')
|
|
420
|
+
.replace(/"/g, '"');
|
|
421
|
+
}
|
|
422
|
+
function escapeAttr(s) {
|
|
423
|
+
return escapeHtml(s).replace(/'/g, ''');
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const SITEMAP_URL_SHARD_SIZE = 45000;
|
|
427
|
+
function parseRoutePrefixes(raw) {
|
|
428
|
+
const out = {};
|
|
429
|
+
const src = (raw ?? process.env.VITE_SEO_ROUTE_PREFIXES ?? '').trim();
|
|
430
|
+
if (!src)
|
|
431
|
+
return out;
|
|
432
|
+
for (const part of src.split(',')) {
|
|
433
|
+
const trimmed = part.trim();
|
|
434
|
+
if (!trimmed)
|
|
435
|
+
continue;
|
|
436
|
+
const idx = trimmed.indexOf(':');
|
|
437
|
+
if (idx <= 0)
|
|
438
|
+
continue;
|
|
439
|
+
const key = trimmed.slice(0, idx).trim();
|
|
440
|
+
const prefix = trimmed.slice(idx + 1).trim();
|
|
441
|
+
if (key)
|
|
442
|
+
out[key] = prefix || '/';
|
|
443
|
+
}
|
|
444
|
+
return out;
|
|
445
|
+
}
|
|
446
|
+
function isPublishedEntity(item) {
|
|
447
|
+
const s = item.status;
|
|
448
|
+
if (s === undefined || s === null || s === '')
|
|
449
|
+
return true;
|
|
450
|
+
return s === 'publish';
|
|
451
|
+
}
|
|
452
|
+
function isNoindexEntity(item) {
|
|
453
|
+
return item.digivalt_seo?.robots_index === false;
|
|
454
|
+
}
|
|
455
|
+
function entityLastmod(item) {
|
|
456
|
+
const v = item.modified_gmt || item.modified || item.date_gmt || item.date;
|
|
457
|
+
return typeof v === 'string' && v.trim() ? v.trim() : undefined;
|
|
458
|
+
}
|
|
459
|
+
function entityImage(item) {
|
|
460
|
+
const v = item.digivalt_seo?.og_image ||
|
|
461
|
+
item.featured_media_cloudflare_url ||
|
|
462
|
+
item.featured_media_url;
|
|
463
|
+
return typeof v === 'string' && v.trim() ? v.trim() : undefined;
|
|
464
|
+
}
|
|
465
|
+
function getFrontPageRef(data) {
|
|
466
|
+
const fp = data.front_page;
|
|
467
|
+
const envSlug = (process.env.VITE_SEO_FRONT_PAGE_SLUG || '').trim();
|
|
468
|
+
let slug;
|
|
469
|
+
let id;
|
|
470
|
+
if (fp && typeof fp === 'object') {
|
|
471
|
+
const rec = fp;
|
|
472
|
+
if (typeof rec.slug === 'string' && rec.slug.trim())
|
|
473
|
+
slug = rec.slug.trim();
|
|
474
|
+
if (typeof rec.id === 'number')
|
|
475
|
+
id = rec.id;
|
|
476
|
+
else if (typeof rec.id === 'string')
|
|
477
|
+
id = Number(rec.id) || undefined;
|
|
478
|
+
}
|
|
479
|
+
if (envSlug)
|
|
480
|
+
slug = envSlug;
|
|
481
|
+
return { slug, id };
|
|
482
|
+
}
|
|
483
|
+
function getFrontPageSlug(data) {
|
|
484
|
+
return getFrontPageRef(data).slug;
|
|
485
|
+
}
|
|
486
|
+
function asRecord(item) {
|
|
487
|
+
if (!item || typeof item !== 'object')
|
|
488
|
+
return null;
|
|
489
|
+
return item;
|
|
490
|
+
}
|
|
491
|
+
function newsletterRouteBase() {
|
|
492
|
+
const raw = process.env.VITE_PHPLIST_NEWSLETTER_ROUTE_BASE || '/newsletters';
|
|
493
|
+
return normalizePathname(raw.startsWith('/') ? raw : `/${raw}`);
|
|
494
|
+
}
|
|
495
|
+
function collectSitemapUrls(args) {
|
|
496
|
+
const prefixes = args.prefixes ?? parseRoutePrefixes();
|
|
497
|
+
const front = args.wpData ? getFrontPageRef(args.wpData) : {};
|
|
498
|
+
const byPath = new Map();
|
|
499
|
+
const add = (entry) => {
|
|
500
|
+
const path = normalizePathname(entry.path);
|
|
501
|
+
if (!path)
|
|
502
|
+
return;
|
|
503
|
+
const prev = byPath.get(path);
|
|
504
|
+
if (!prev) {
|
|
505
|
+
byPath.set(path, { ...entry, path });
|
|
506
|
+
return;
|
|
394
507
|
}
|
|
395
|
-
|
|
396
|
-
|
|
508
|
+
byPath.set(path, {
|
|
509
|
+
path,
|
|
510
|
+
lastmod: entry.lastmod || prev.lastmod,
|
|
511
|
+
image: entry.image || prev.image,
|
|
512
|
+
});
|
|
513
|
+
};
|
|
514
|
+
add({ path: '/' });
|
|
515
|
+
for (const p of args.staticPaths) {
|
|
516
|
+
add({ path: p });
|
|
517
|
+
}
|
|
518
|
+
const pages = args.wpData && Array.isArray(args.wpData.pages) ? args.wpData.pages : [];
|
|
519
|
+
for (const raw of pages) {
|
|
520
|
+
const item = asRecord(raw);
|
|
521
|
+
if (!item || !isPublishedEntity(item) || isNoindexEntity(item))
|
|
522
|
+
continue;
|
|
523
|
+
const slug = typeof item.slug === 'string' ? item.slug.trim() : '';
|
|
524
|
+
if (!slug)
|
|
525
|
+
continue;
|
|
526
|
+
const isFront = (front.slug && slug === front.slug) ||
|
|
527
|
+
(typeof front.id === 'number' && typeof item.id === 'number' && item.id === front.id);
|
|
528
|
+
const path = isFront ? '/' : joinPath('/', slug);
|
|
529
|
+
add({
|
|
530
|
+
path,
|
|
531
|
+
lastmod: entityLastmod(item),
|
|
532
|
+
image: entityImage(item),
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
if (args.wpData) {
|
|
536
|
+
for (const [type, prefix] of Object.entries(prefixes)) {
|
|
537
|
+
if (type === 'pages' || type === 'page')
|
|
538
|
+
continue;
|
|
539
|
+
const arr = args.wpData[type];
|
|
540
|
+
if (!Array.isArray(arr))
|
|
541
|
+
continue;
|
|
542
|
+
for (const raw of arr) {
|
|
543
|
+
const item = asRecord(raw);
|
|
544
|
+
if (!item || !isPublishedEntity(item) || isNoindexEntity(item))
|
|
545
|
+
continue;
|
|
546
|
+
const slug = typeof item.slug === 'string' ? item.slug.trim() : '';
|
|
547
|
+
if (!slug)
|
|
548
|
+
continue;
|
|
549
|
+
add({
|
|
550
|
+
path: joinPath(prefix, slug),
|
|
551
|
+
lastmod: entityLastmod(item),
|
|
552
|
+
image: entityImage(item),
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
const newsletters = args.phplistData && Array.isArray(args.phplistData.newsletters)
|
|
558
|
+
? args.phplistData.newsletters
|
|
559
|
+
: [];
|
|
560
|
+
const nBase = newsletterRouteBase();
|
|
561
|
+
for (const raw of newsletters) {
|
|
562
|
+
if (!raw || typeof raw !== 'object')
|
|
563
|
+
continue;
|
|
564
|
+
const rec = raw;
|
|
565
|
+
if (typeof rec.slug !== 'string' || !rec.slug.trim())
|
|
566
|
+
continue;
|
|
567
|
+
add({
|
|
568
|
+
path: joinPath(nBase, rec.slug.trim()),
|
|
569
|
+
lastmod: typeof rec.sent_at === 'string' ? rec.sent_at : undefined,
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
const known = new Set(byPath.keys());
|
|
573
|
+
const considerMenu = (items) => {
|
|
574
|
+
if (!Array.isArray(items))
|
|
575
|
+
return;
|
|
576
|
+
for (const item of items) {
|
|
577
|
+
if (!item || typeof item !== 'object')
|
|
578
|
+
continue;
|
|
579
|
+
const rec = item;
|
|
580
|
+
if (typeof rec.url === 'string') {
|
|
581
|
+
const path = menuUrlToFrontendPath(rec.url, front.slug);
|
|
582
|
+
if (path && known.has(path)) {
|
|
583
|
+
add({ path });
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
considerMenu(rec.children);
|
|
397
587
|
}
|
|
588
|
+
};
|
|
589
|
+
if (args.wpData) {
|
|
590
|
+
const header = args.wpData.navigation_menu;
|
|
591
|
+
const footer = args.wpData.footer_navigation_menu;
|
|
592
|
+
considerMenu(header?.items);
|
|
593
|
+
considerMenu(footer?.items);
|
|
398
594
|
}
|
|
399
|
-
|
|
595
|
+
const sorted = [...byPath.values()].sort((a, b) => {
|
|
596
|
+
if (a.path === '/')
|
|
597
|
+
return -1;
|
|
598
|
+
if (b.path === '/')
|
|
599
|
+
return 1;
|
|
600
|
+
return a.path.localeCompare(b.path);
|
|
601
|
+
});
|
|
602
|
+
return sorted;
|
|
400
603
|
}
|
|
401
|
-
|
|
402
|
-
* When CMS host is unknown, accept any http(s) URL so local/offline merges still produce paths.
|
|
403
|
-
*/
|
|
404
|
-
function urlToPath(urlStr, allowedHosts) {
|
|
604
|
+
function menuUrlToFrontendPath(urlStr, frontSlug) {
|
|
405
605
|
const t = urlStr.trim();
|
|
406
606
|
if (!t || t === '#' || t.toLowerCase().startsWith('mailto:') || t.toLowerCase().startsWith('tel:')) {
|
|
407
607
|
return null;
|
|
408
608
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
let u;
|
|
413
|
-
try {
|
|
414
|
-
u = new URL(t);
|
|
609
|
+
let pathname;
|
|
610
|
+
if (t.startsWith('/')) {
|
|
611
|
+
pathname = normalizePathname(t.split('?')[0]);
|
|
415
612
|
}
|
|
416
|
-
|
|
417
|
-
|
|
613
|
+
else if (/^https?:\/\//i.test(t)) {
|
|
614
|
+
try {
|
|
615
|
+
pathname = normalizePathname(new URL(t).pathname);
|
|
616
|
+
}
|
|
617
|
+
catch {
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
418
620
|
}
|
|
419
|
-
|
|
621
|
+
else {
|
|
420
622
|
return null;
|
|
421
623
|
}
|
|
422
|
-
|
|
624
|
+
if (pathname === '/')
|
|
625
|
+
return '/';
|
|
626
|
+
const slug = pathname.replace(/^\//, '');
|
|
627
|
+
if (frontSlug && slug === frontSlug)
|
|
628
|
+
return '/';
|
|
629
|
+
return pathname;
|
|
423
630
|
}
|
|
424
|
-
|
|
631
|
+
|
|
632
|
+
function parseStaticPathsJson(raw) {
|
|
425
633
|
try {
|
|
426
634
|
const data = JSON.parse(raw);
|
|
427
635
|
if (Array.isArray(data)) {
|
|
@@ -436,130 +644,70 @@ function parsePathsJson(raw) {
|
|
|
436
644
|
}
|
|
437
645
|
return [];
|
|
438
646
|
}
|
|
439
|
-
function
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
const out = [];
|
|
447
|
-
for (const p of paths) {
|
|
448
|
-
if (p.startsWith('http://') || p.startsWith('https://')) {
|
|
449
|
-
const normalized = urlToPath(p, allowedHosts);
|
|
450
|
-
if (normalized)
|
|
451
|
-
out.push(normalized);
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
out.push(normalizePathname(p));
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
return out;
|
|
458
|
-
}
|
|
459
|
-
function walkMenuItems(items, allowedHosts, out) {
|
|
460
|
-
if (!Array.isArray(items))
|
|
461
|
-
return;
|
|
462
|
-
for (const item of items) {
|
|
463
|
-
if (!item || typeof item !== 'object')
|
|
464
|
-
continue;
|
|
465
|
-
const rec = item;
|
|
466
|
-
if (typeof rec.url === 'string') {
|
|
467
|
-
const p = urlToPath(rec.url, allowedHosts);
|
|
468
|
-
if (p)
|
|
469
|
-
out.add(p);
|
|
470
|
-
}
|
|
471
|
-
if (Array.isArray(rec.children)) {
|
|
472
|
-
walkMenuItems(rec.children, allowedHosts, out);
|
|
647
|
+
function loadJson$1(full) {
|
|
648
|
+
if (!fs.existsSync(full))
|
|
649
|
+
return undefined;
|
|
650
|
+
try {
|
|
651
|
+
const data = JSON.parse(fs.readFileSync(full, 'utf8'));
|
|
652
|
+
if (data && typeof data === 'object' && !Array.isArray(data)) {
|
|
653
|
+
return data;
|
|
473
654
|
}
|
|
474
655
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
for (const item of arr) {
|
|
478
|
-
if (!item || typeof item !== 'object')
|
|
479
|
-
continue;
|
|
480
|
-
const link = item.link;
|
|
481
|
-
if (typeof link === 'string') {
|
|
482
|
-
const p = urlToPath(link, allowedHosts);
|
|
483
|
-
if (p)
|
|
484
|
-
out.add(p);
|
|
485
|
-
}
|
|
656
|
+
catch (e) {
|
|
657
|
+
console.warn('⚠️ Could not parse JSON for sitemap:', full, e.message);
|
|
486
658
|
}
|
|
659
|
+
return undefined;
|
|
487
660
|
}
|
|
488
|
-
function
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
}
|
|
494
|
-
const config = data.config;
|
|
495
|
-
const postTypeKeys = config?.post_types && typeof config.post_types === 'object'
|
|
496
|
-
? Object.keys(config.post_types)
|
|
497
|
-
: null;
|
|
498
|
-
if (postTypeKeys && postTypeKeys.length > 0) {
|
|
499
|
-
for (const key of postTypeKeys) {
|
|
500
|
-
const arr = data[key];
|
|
501
|
-
if (Array.isArray(arr)) {
|
|
502
|
-
collectLinksFromArray(arr, allowedHosts, out);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
else {
|
|
507
|
-
for (const [key, value] of Object.entries(data)) {
|
|
508
|
-
if (SITEMAP_SKIP_TOP_LEVEL_KEYS.has(key))
|
|
509
|
-
continue;
|
|
510
|
-
if (Array.isArray(value)) {
|
|
511
|
-
collectLinksFromArray(value, allowedHosts, out);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
return out;
|
|
661
|
+
function loadStaticPaths(cwd, staticInputPath) {
|
|
662
|
+
const full = path.join(cwd, staticInputPath);
|
|
663
|
+
if (!fs.existsSync(full))
|
|
664
|
+
return [];
|
|
665
|
+
return parseStaticPathsJson(fs.readFileSync(full, 'utf8')).map((p) => normalizePathname(p));
|
|
516
666
|
}
|
|
517
667
|
function writeFallback(cwd, outputPath) {
|
|
518
668
|
const full = path.join(cwd, outputPath);
|
|
519
669
|
fs.mkdirSync(path.dirname(full), { recursive: true });
|
|
520
|
-
|
|
670
|
+
const payload = { urls: [{ path: '/' }], paths: ['/'] };
|
|
671
|
+
fs.writeFileSync(full, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
|
|
672
|
+
}
|
|
673
|
+
function writeShard(full, urls) {
|
|
674
|
+
const paths = urls.map((u) => u.path);
|
|
675
|
+
fs.writeFileSync(full, `${JSON.stringify({ urls, paths }, null, 2)}\n`, 'utf8');
|
|
521
676
|
}
|
|
522
677
|
/**
|
|
523
|
-
* Merge
|
|
678
|
+
* Merge static app routes, WP pages (frontend paths), opt-in CPT prefixes, and PHPList issues.
|
|
524
679
|
*/
|
|
525
680
|
async function generateSitemapPaths(options = {}) {
|
|
526
681
|
dotenv.config();
|
|
527
682
|
dotenv.config({ path: '.env.local' });
|
|
528
683
|
const cwd = options.cwd ?? process.cwd();
|
|
529
684
|
const wpDataPath = options.wpDataPath ?? 'public/wordpress-data.json';
|
|
685
|
+
const phplistDataPath = options.phplistDataPath ?? 'public/phplist-data.json';
|
|
530
686
|
const staticInputPath = options.staticInputPath ?? 'public/sitemap-static-paths.json';
|
|
531
687
|
const outputPath = options.outputPath ?? 'public/sitemap-paths.json';
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
const wpFull = path.join(cwd, wpDataPath);
|
|
538
|
-
if (fs.existsSync(wpFull)) {
|
|
539
|
-
try {
|
|
540
|
-
const raw = fs.readFileSync(wpFull, 'utf8');
|
|
541
|
-
const data = JSON.parse(raw);
|
|
542
|
-
const fromWp = collectPathsFromWpData(data, allowedHosts);
|
|
543
|
-
for (const p of fromWp) {
|
|
544
|
-
merged.add(p);
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
catch (e) {
|
|
548
|
-
console.warn('⚠️ Could not parse wordpress-data.json for sitemap paths:', e.message);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
merged.add('/');
|
|
552
|
-
const sorted = [...merged].sort((a, b) => {
|
|
553
|
-
if (a === '/')
|
|
554
|
-
return -1;
|
|
555
|
-
if (b === '/')
|
|
556
|
-
return 1;
|
|
557
|
-
return a.localeCompare(b);
|
|
688
|
+
const urls = collectSitemapUrls({
|
|
689
|
+
wpData: loadJson$1(path.join(cwd, wpDataPath)),
|
|
690
|
+
phplistData: loadJson$1(path.join(cwd, phplistDataPath)),
|
|
691
|
+
staticPaths: loadStaticPaths(cwd, staticInputPath),
|
|
692
|
+
prefixes: parseRoutePrefixes(),
|
|
558
693
|
});
|
|
559
694
|
const outFull = path.join(cwd, outputPath);
|
|
560
695
|
fs.mkdirSync(path.dirname(outFull), { recursive: true });
|
|
561
|
-
|
|
562
|
-
|
|
696
|
+
if (urls.length <= SITEMAP_URL_SHARD_SIZE) {
|
|
697
|
+
writeShard(outFull, urls);
|
|
698
|
+
console.log(`📍 Sitemap paths written (${urls.length} URLs): ${outFull}`);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
const parts = Math.ceil(urls.length / SITEMAP_URL_SHARD_SIZE);
|
|
702
|
+
const dir = path.dirname(outFull);
|
|
703
|
+
const base = path.basename(outFull, path.extname(outFull));
|
|
704
|
+
const ext = path.extname(outFull) || '.json';
|
|
705
|
+
for (let i = 0; i < parts; i++) {
|
|
706
|
+
const slice = urls.slice(i * SITEMAP_URL_SHARD_SIZE, (i + 1) * SITEMAP_URL_SHARD_SIZE);
|
|
707
|
+
writeShard(path.join(dir, `${base}-${i}${ext}`), slice);
|
|
708
|
+
}
|
|
709
|
+
fs.writeFileSync(outFull, `${JSON.stringify({ index: true, parts }, null, 2)}\n`, 'utf8');
|
|
710
|
+
console.log(`📍 Sitemap index written (${urls.length} URLs, ${parts} parts): ${outFull}`);
|
|
563
711
|
}
|
|
564
712
|
async function generateSitemapPathsSafe(options = {}) {
|
|
565
713
|
try {
|
|
@@ -573,45 +721,747 @@ async function generateSitemapPathsSafe(options = {}) {
|
|
|
573
721
|
}
|
|
574
722
|
}
|
|
575
723
|
|
|
724
|
+
const getImportMetaEnv = () => {
|
|
725
|
+
try {
|
|
726
|
+
return typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== 'undefined' ? undefined : undefined;
|
|
727
|
+
}
|
|
728
|
+
catch {
|
|
729
|
+
return undefined;
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
const getEnv = (key) => {
|
|
733
|
+
const viteEnv = getImportMetaEnv();
|
|
734
|
+
if (viteEnv && key in viteEnv) {
|
|
735
|
+
const value = viteEnv[key];
|
|
736
|
+
return value == null ? undefined : String(value);
|
|
737
|
+
}
|
|
738
|
+
if (typeof process !== 'undefined' && process.env && key in process.env) {
|
|
739
|
+
const value = process.env[key];
|
|
740
|
+
return value == null ? undefined : String(value);
|
|
741
|
+
}
|
|
742
|
+
return undefined;
|
|
743
|
+
};
|
|
744
|
+
const isDevEnvironment = () => {
|
|
745
|
+
const viteEnv = getImportMetaEnv();
|
|
746
|
+
if (viteEnv && 'DEV' in viteEnv) {
|
|
747
|
+
return Boolean(viteEnv.DEV);
|
|
748
|
+
}
|
|
749
|
+
return typeof process !== 'undefined' && process.env?.NODE_ENV === 'development';
|
|
750
|
+
};
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Integration Configuration
|
|
754
|
+
* Centralized configuration for all third-party integrations
|
|
755
|
+
*/
|
|
756
|
+
function envBool(key, defaultValue) {
|
|
757
|
+
const v = getEnv(key);
|
|
758
|
+
if (v === undefined || v === '')
|
|
759
|
+
return defaultValue;
|
|
760
|
+
const lower = v.toLowerCase();
|
|
761
|
+
if (lower === 'false' || lower === '0' || lower === 'no')
|
|
762
|
+
return false;
|
|
763
|
+
if (lower === 'true' || lower === '1' || lower === 'yes')
|
|
764
|
+
return true;
|
|
765
|
+
return defaultValue;
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Get integration configuration with environment variable fallbacks
|
|
769
|
+
*/
|
|
770
|
+
function getIntegrationConfig() {
|
|
771
|
+
isDevEnvironment();
|
|
772
|
+
return {
|
|
773
|
+
wordpress: {
|
|
774
|
+
enabled: true,
|
|
775
|
+
apiUrl: getEnv('VITE_WORDPRESS_API_URL') || '',
|
|
776
|
+
authMode: getEnv('VITE_AUTH_MODE') || 'direct',
|
|
777
|
+
},
|
|
778
|
+
supabase: {
|
|
779
|
+
enabled: getEnv('VITE_AUTH_MODE') === 'supabase_proxy',
|
|
780
|
+
url: getEnv('VITE_SUPABASE_URL') || '',
|
|
781
|
+
anonKey: getEnv('VITE_SUPABASE_ANON_KEY') || '',
|
|
782
|
+
serviceRoleKey: getEnv('VITE_SUPABASE_SERVICE_ROLE_KEY'),
|
|
783
|
+
},
|
|
784
|
+
gravityForms: {
|
|
785
|
+
enabled: !!(getEnv('VITE_CLOUDFLARE_WORKER_URL') || getEnv('VITE_WORDPRESS_API_URL')),
|
|
786
|
+
url: getEnv('VITE_WORDPRESS_API_URL'),
|
|
787
|
+
proxyUrl: getEnv('VITE_CLOUDFLARE_WORKER_URL'),
|
|
788
|
+
consumerKey: getEnv('VITE_GF_CONSUMER_KEY'),
|
|
789
|
+
consumerSecret: getEnv('VITE_GF_CONSUMER_SECRET'),
|
|
790
|
+
forms: {
|
|
791
|
+
'contact': {
|
|
792
|
+
name: 'Contact Form',
|
|
793
|
+
type: 'contact',
|
|
794
|
+
successMessage: 'Thank you for your message. We\'ll get back to you soon!',
|
|
795
|
+
},
|
|
796
|
+
'newsletter': {
|
|
797
|
+
name: 'Newsletter Signup',
|
|
798
|
+
type: 'newsletter',
|
|
799
|
+
successMessage: 'Thank you for subscribing to our newsletter!',
|
|
800
|
+
},
|
|
801
|
+
'support': {
|
|
802
|
+
name: 'Support Request',
|
|
803
|
+
type: 'support',
|
|
804
|
+
successMessage: 'Your support request has been submitted successfully.',
|
|
805
|
+
},
|
|
806
|
+
},
|
|
807
|
+
},
|
|
808
|
+
mautic: {
|
|
809
|
+
enabled: !!(getEnv('VITE_MAUTIC_PROXY_URL') || getEnv('VITE_MAUTIC_URL')),
|
|
810
|
+
url: getEnv('VITE_MAUTIC_URL') || '',
|
|
811
|
+
proxyUrl: getEnv('VITE_MAUTIC_PROXY_URL'),
|
|
812
|
+
forms: {
|
|
813
|
+
'1': {
|
|
814
|
+
name: 'Newsletter Signup',
|
|
815
|
+
type: 'newsletter',
|
|
816
|
+
successMessage: 'Thank you for subscribing to our newsletter!',
|
|
817
|
+
postAction: 'message',
|
|
818
|
+
postActionProperty: 'Thank you for your submission!'
|
|
819
|
+
},
|
|
820
|
+
'2': {
|
|
821
|
+
name: 'Contact Form',
|
|
822
|
+
type: 'contact',
|
|
823
|
+
successMessage: 'Thank you for contacting us! We\'ll get back to you soon.',
|
|
824
|
+
postAction: 'message',
|
|
825
|
+
postActionProperty: 'Thank you for your message!'
|
|
826
|
+
},
|
|
827
|
+
'3': {
|
|
828
|
+
name: 'Lead Capture',
|
|
829
|
+
type: 'lead',
|
|
830
|
+
successMessage: 'Thank you for your interest! We\'ll be in touch.',
|
|
831
|
+
postAction: 'message',
|
|
832
|
+
postActionProperty: 'Thank you for your submission!'
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
},
|
|
836
|
+
phplist: {
|
|
837
|
+
enabled: !!(getEnv('VITE_PHPLIST_URL') || getEnv('PHPLIST_URL')),
|
|
838
|
+
url: getEnv('VITE_PHPLIST_URL') || getEnv('PHPLIST_URL'),
|
|
839
|
+
proxyUrl: getEnv('VITE_PHPLIST_PROXY_URL') || getEnv('PHPLIST_PROXY_URL'),
|
|
840
|
+
listId: parseInt(getEnv('VITE_PHPLIST_LIST_ID') || getEnv('PHPLIST_LIST_ID') || '0', 10) || undefined,
|
|
841
|
+
subscribePageIds: (getEnv('VITE_PHPLIST_SUBSCRIBE_PAGE_IDS') || getEnv('PHPLIST_SUBSCRIBE_PAGE_IDS') || '')
|
|
842
|
+
.split(',')
|
|
843
|
+
.map((s) => parseInt(s.trim(), 10))
|
|
844
|
+
.filter((n) => !Number.isNaN(n)),
|
|
845
|
+
newsletterRouteBase: getEnv('VITE_PHPLIST_NEWSLETTER_ROUTE_BASE') || '/newsletters',
|
|
846
|
+
},
|
|
847
|
+
suiteCRM: {
|
|
848
|
+
enabled: !!(getEnv('VITE_SUITECRM_URL') && getEnv('VITE_SUITECRM_CLIENT_ID') && getEnv('VITE_SUITECRM_CLIENT_SECRET')),
|
|
849
|
+
url: getEnv('VITE_SUITECRM_URL'),
|
|
850
|
+
proxyUrl: getEnv('VITE_SUITECRM_PROXY_URL'),
|
|
851
|
+
appId: undefined,
|
|
852
|
+
workerSecret: undefined,
|
|
853
|
+
oauth2: {
|
|
854
|
+
clientId: getEnv('VITE_SUITECRM_CLIENT_ID'),
|
|
855
|
+
clientSecret: getEnv('VITE_SUITECRM_CLIENT_SECRET'),
|
|
856
|
+
username: getEnv('VITE_SUITECRM_USERNAME'),
|
|
857
|
+
password: getEnv('VITE_SUITECRM_PASSWORD'),
|
|
858
|
+
},
|
|
859
|
+
},
|
|
860
|
+
chatwoot: {
|
|
861
|
+
enabled: !!(getEnv('VITE_CHATWOOT_WEBSITE_TOKEN') && getEnv('VITE_CHATWOOT_BASE_URL')),
|
|
862
|
+
websiteToken: getEnv('VITE_CHATWOOT_WEBSITE_TOKEN') || '',
|
|
863
|
+
baseUrl: getEnv('VITE_CHATWOOT_BASE_URL') || '',
|
|
864
|
+
locale: 'en',
|
|
865
|
+
type: 'standard',
|
|
866
|
+
launcherTitle: 'Chat',
|
|
867
|
+
hideMessageBubble: false,
|
|
868
|
+
position: 'right',
|
|
869
|
+
showPopoutButton: false,
|
|
870
|
+
},
|
|
871
|
+
analytics: {
|
|
872
|
+
googleAnalytics: { enabled: false },
|
|
873
|
+
googleTagManager: { enabled: false },
|
|
874
|
+
facebookPixel: { enabled: false },
|
|
875
|
+
linkedinInsight: { enabled: false },
|
|
876
|
+
},
|
|
877
|
+
seo: (() => {
|
|
878
|
+
const opt = (key) => {
|
|
879
|
+
const v = getEnv(key);
|
|
880
|
+
if (v === undefined || v === '')
|
|
881
|
+
return undefined;
|
|
882
|
+
const t = v.trim();
|
|
883
|
+
return t || undefined;
|
|
884
|
+
};
|
|
885
|
+
const siteUrl = (getEnv('VITE_SEO_SITE_URL') || '').replace(/\/+$/, '').trim();
|
|
886
|
+
const siteName = (getEnv('VITE_SEO_SITE_NAME') || '').trim();
|
|
887
|
+
const defaultTitle = (getEnv('VITE_SEO_DEFAULT_TITLE') || '').trim() || siteName || '';
|
|
888
|
+
return {
|
|
889
|
+
defaultTitle,
|
|
890
|
+
defaultDescription: (getEnv('VITE_SEO_DEFAULT_DESCRIPTION') || '').trim(),
|
|
891
|
+
defaultKeywords: opt('VITE_SEO_DEFAULT_KEYWORDS'),
|
|
892
|
+
defaultImage: (getEnv('VITE_SEO_DEFAULT_OG_IMAGE') || '').trim(),
|
|
893
|
+
siteName,
|
|
894
|
+
siteUrl,
|
|
895
|
+
twitterHandle: opt('VITE_SEO_TWITTER_SITE'),
|
|
896
|
+
facebookAppId: opt('VITE_SEO_FACEBOOK_APP_ID'),
|
|
897
|
+
googleSiteVerification: opt('VITE_SEO_GOOGLE_SITE_VERIFICATION'),
|
|
898
|
+
bingSiteVerification: opt('VITE_SEO_BING_SITE_VERIFICATION'),
|
|
899
|
+
};
|
|
900
|
+
})(),
|
|
901
|
+
performance: {
|
|
902
|
+
enableLazyLoading: envBool('VITE_PERF_LAZY_LOADING', true),
|
|
903
|
+
enableImageOptimization: envBool('VITE_PERF_IMAGE_OPTIMIZATION', true),
|
|
904
|
+
enableCodeSplitting: envBool('VITE_PERF_CODE_SPLITTING', true),
|
|
905
|
+
enableServiceWorker: envBool('VITE_PERF_SERVICE_WORKER', false),
|
|
906
|
+
enableCaching: envBool('VITE_PERF_CACHING', true),
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
function getSEOConfig() {
|
|
911
|
+
return getIntegrationConfig().seo;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* SEO defaults from env-backed integration config (see `VITE_SEO_*` in docs).
|
|
916
|
+
*/
|
|
917
|
+
function getSeoDefaultsFromEnv() {
|
|
918
|
+
const seo = getSEOConfig();
|
|
919
|
+
return {
|
|
920
|
+
siteUrl: seo.siteUrl,
|
|
921
|
+
siteName: seo.siteName,
|
|
922
|
+
defaultTitle: seo.defaultTitle,
|
|
923
|
+
defaultDescription: seo.defaultDescription,
|
|
924
|
+
defaultKeywords: seo.defaultKeywords,
|
|
925
|
+
defaultImage: seo.defaultImage,
|
|
926
|
+
twitterHandle: seo.twitterHandle,
|
|
927
|
+
facebookAppId: seo.facebookAppId,
|
|
928
|
+
googleSiteVerification: seo.googleSiteVerification,
|
|
929
|
+
bingSiteVerification: seo.bingSiteVerification,
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
function firstNonEmpty(...values) {
|
|
934
|
+
for (const v of values) {
|
|
935
|
+
if (typeof v === 'string' && v.trim())
|
|
936
|
+
return v.trim();
|
|
937
|
+
}
|
|
938
|
+
return '';
|
|
939
|
+
}
|
|
940
|
+
function resolvePageSeo(entity, pathname, overrides) {
|
|
941
|
+
const d = getSeoDefaultsFromEnv();
|
|
942
|
+
const seo = entity?.digivalt_seo;
|
|
943
|
+
const title = firstNonEmpty(overrides?.title, seo?.title, renderedText(entity?.title), d.defaultTitle, d.siteName);
|
|
944
|
+
const description = firstNonEmpty(overrides?.description, seo?.description, renderedText(entity?.excerpt), d.defaultDescription);
|
|
945
|
+
const imageUrl = firstNonEmpty(overrides?.imageUrl, seo?.og_image, entity?.featured_media_cloudflare_url, entity?.featured_media_url, d.defaultImage);
|
|
946
|
+
const noindex = overrides?.noindex ?? seo?.robots_index === false;
|
|
947
|
+
const ogType = overrides?.ogType || seo?.og_type || 'website';
|
|
948
|
+
const canonicalUrl = firstNonEmpty(overrides?.canonicalUrl, seo?.canonical) || undefined;
|
|
949
|
+
const robotsFollow = seo?.robots_follow !== false;
|
|
950
|
+
let robots;
|
|
951
|
+
if (noindex && robotsFollow)
|
|
952
|
+
robots = 'noindex, follow';
|
|
953
|
+
else if (noindex)
|
|
954
|
+
robots = 'noindex, nofollow';
|
|
955
|
+
else if (!robotsFollow)
|
|
956
|
+
robots = 'index, nofollow';
|
|
957
|
+
return {
|
|
958
|
+
entity,
|
|
959
|
+
noindex,
|
|
960
|
+
head: {
|
|
961
|
+
pathname,
|
|
962
|
+
title: title || undefined,
|
|
963
|
+
description: description || undefined,
|
|
964
|
+
imageUrl: imageUrl || undefined,
|
|
965
|
+
canonicalUrl,
|
|
966
|
+
ogType,
|
|
967
|
+
noindex,
|
|
968
|
+
robots,
|
|
969
|
+
},
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
const createOrganizationSchema = (data) => ({
|
|
974
|
+
'@context': 'https://schema.org',
|
|
975
|
+
'@type': 'Organization',
|
|
976
|
+
name: data.name,
|
|
977
|
+
url: data.url,
|
|
978
|
+
...(data.logo && { logo: data.logo }),
|
|
979
|
+
...(data.description && { description: data.description }),
|
|
980
|
+
...(data.address && {
|
|
981
|
+
address: {
|
|
982
|
+
'@type': 'PostalAddress',
|
|
983
|
+
...data.address,
|
|
984
|
+
},
|
|
985
|
+
}),
|
|
986
|
+
...(data.contactPoint && {
|
|
987
|
+
contactPoint: {
|
|
988
|
+
'@type': 'ContactPoint',
|
|
989
|
+
...data.contactPoint,
|
|
990
|
+
},
|
|
991
|
+
}),
|
|
992
|
+
});
|
|
993
|
+
const createWebSiteSchema = (data) => ({
|
|
994
|
+
'@context': 'https://schema.org',
|
|
995
|
+
'@type': 'WebSite',
|
|
996
|
+
name: data.name,
|
|
997
|
+
url: data.url,
|
|
998
|
+
...(data.description && { description: data.description }),
|
|
999
|
+
...(data.publisher && { publisher: data.publisher }),
|
|
1000
|
+
});
|
|
1001
|
+
const createArticleSchema = (data) => ({
|
|
1002
|
+
'@context': 'https://schema.org',
|
|
1003
|
+
'@type': 'Article',
|
|
1004
|
+
headline: data.headline,
|
|
1005
|
+
description: data.description,
|
|
1006
|
+
...(data.image && { image: data.image }),
|
|
1007
|
+
author: {
|
|
1008
|
+
'@type': 'Person',
|
|
1009
|
+
name: data.author,
|
|
1010
|
+
},
|
|
1011
|
+
publisher: {
|
|
1012
|
+
'@type': 'Organization',
|
|
1013
|
+
name: data.publisher,
|
|
1014
|
+
},
|
|
1015
|
+
datePublished: data.datePublished,
|
|
1016
|
+
...(data.dateModified && { dateModified: data.dateModified }),
|
|
1017
|
+
url: data.url,
|
|
1018
|
+
});
|
|
1019
|
+
const createServiceSchema = (data) => ({
|
|
1020
|
+
'@context': 'https://schema.org',
|
|
1021
|
+
'@type': 'Service',
|
|
1022
|
+
name: data.name,
|
|
1023
|
+
description: data.description,
|
|
1024
|
+
provider: {
|
|
1025
|
+
'@type': 'Organization',
|
|
1026
|
+
name: data.provider,
|
|
1027
|
+
},
|
|
1028
|
+
url: data.url,
|
|
1029
|
+
...(data.areaServed && { areaServed: data.areaServed }),
|
|
1030
|
+
...(data.serviceType && { serviceType: data.serviceType }),
|
|
1031
|
+
});
|
|
1032
|
+
const createFAQSchema = (faqs) => ({
|
|
1033
|
+
'@context': 'https://schema.org',
|
|
1034
|
+
'@type': 'FAQPage',
|
|
1035
|
+
mainEntity: faqs.map(faq => ({
|
|
1036
|
+
'@type': 'Question',
|
|
1037
|
+
name: faq.question,
|
|
1038
|
+
acceptedAnswer: {
|
|
1039
|
+
'@type': 'Answer',
|
|
1040
|
+
text: faq.answer,
|
|
1041
|
+
},
|
|
1042
|
+
})),
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
function joinAbsoluteUrl(siteUrl, pathname) {
|
|
1046
|
+
const base = siteUrl.replace(/\/+$/, '');
|
|
1047
|
+
if (pathname === '/')
|
|
1048
|
+
return base || pathname;
|
|
1049
|
+
const p = pathname.startsWith('/') ? pathname : `/${pathname}`;
|
|
1050
|
+
return base ? `${base}${p}` : p;
|
|
1051
|
+
}
|
|
1052
|
+
function extraToList(extra) {
|
|
1053
|
+
if (!extra)
|
|
1054
|
+
return [];
|
|
1055
|
+
if (Array.isArray(extra)) {
|
|
1056
|
+
return extra.filter((x) => !!x && typeof x === 'object');
|
|
1057
|
+
}
|
|
1058
|
+
if (typeof extra === 'object')
|
|
1059
|
+
return [extra];
|
|
1060
|
+
return [];
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* JSON-LD for a route: WebSite + Organization (from env) plus page schema from DigiValt SEO fields.
|
|
1064
|
+
*/
|
|
1065
|
+
function buildPageJsonLd(entity, pathname, options) {
|
|
1066
|
+
const d = getSeoDefaultsFromEnv();
|
|
1067
|
+
const seo = entity?.digivalt_seo;
|
|
1068
|
+
const title = options?.title ||
|
|
1069
|
+
seo?.title ||
|
|
1070
|
+
renderedText(entity?.title) ||
|
|
1071
|
+
d.defaultTitle ||
|
|
1072
|
+
d.siteName;
|
|
1073
|
+
const description = options?.description ||
|
|
1074
|
+
seo?.description ||
|
|
1075
|
+
renderedText(entity?.excerpt) ||
|
|
1076
|
+
d.defaultDescription;
|
|
1077
|
+
const image = options?.imageUrl ||
|
|
1078
|
+
seo?.og_image ||
|
|
1079
|
+
entity?.featured_media_cloudflare_url ||
|
|
1080
|
+
entity?.featured_media_url ||
|
|
1081
|
+
d.defaultImage;
|
|
1082
|
+
const url = options?.canonicalUrl ||
|
|
1083
|
+
seo?.canonical ||
|
|
1084
|
+
(d.siteUrl ? joinAbsoluteUrl(d.siteUrl, pathname || '/') : pathname);
|
|
1085
|
+
const out = [];
|
|
1086
|
+
if (d.siteName && d.siteUrl) {
|
|
1087
|
+
out.push(createWebSiteSchema({
|
|
1088
|
+
name: d.siteName,
|
|
1089
|
+
url: d.siteUrl,
|
|
1090
|
+
description: d.defaultDescription || undefined,
|
|
1091
|
+
}));
|
|
1092
|
+
out.push(createOrganizationSchema({
|
|
1093
|
+
name: d.siteName,
|
|
1094
|
+
url: d.siteUrl,
|
|
1095
|
+
logo: d.defaultImage || undefined,
|
|
1096
|
+
description: d.defaultDescription || undefined,
|
|
1097
|
+
}));
|
|
1098
|
+
}
|
|
1099
|
+
const schemaType = seo?.schema_type || 'WebPage';
|
|
1100
|
+
if (schemaType === 'Article') {
|
|
1101
|
+
out.push(createArticleSchema({
|
|
1102
|
+
headline: title,
|
|
1103
|
+
description: description || title,
|
|
1104
|
+
image: image || undefined,
|
|
1105
|
+
author: d.siteName || 'Publisher',
|
|
1106
|
+
publisher: d.siteName || 'Publisher',
|
|
1107
|
+
datePublished: entity?.date_gmt || entity?.date || new Date().toISOString(),
|
|
1108
|
+
dateModified: entity?.modified_gmt || entity?.modified,
|
|
1109
|
+
url,
|
|
1110
|
+
}));
|
|
1111
|
+
}
|
|
1112
|
+
else if (schemaType === 'Service') {
|
|
1113
|
+
out.push(createServiceSchema({
|
|
1114
|
+
name: title,
|
|
1115
|
+
description: description || title,
|
|
1116
|
+
provider: d.siteName || title,
|
|
1117
|
+
url,
|
|
1118
|
+
}));
|
|
1119
|
+
}
|
|
1120
|
+
else if (schemaType === 'FAQPage' || (seo?.faq && seo.faq.length > 0)) {
|
|
1121
|
+
const faqs = (seo?.faq || []).filter((f) => f.question && f.answer);
|
|
1122
|
+
if (faqs.length) {
|
|
1123
|
+
out.push(createFAQSchema(faqs));
|
|
1124
|
+
}
|
|
1125
|
+
else {
|
|
1126
|
+
out.push({
|
|
1127
|
+
'@context': 'https://schema.org',
|
|
1128
|
+
'@type': 'WebPage',
|
|
1129
|
+
name: title,
|
|
1130
|
+
description: description || undefined,
|
|
1131
|
+
url,
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
else {
|
|
1136
|
+
out.push({
|
|
1137
|
+
'@context': 'https://schema.org',
|
|
1138
|
+
'@type': 'WebPage',
|
|
1139
|
+
name: title,
|
|
1140
|
+
description: description || undefined,
|
|
1141
|
+
url,
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
out.push(...extraToList(seo?.extra_json_ld));
|
|
1145
|
+
return out;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
function loadJson(full) {
|
|
1149
|
+
if (!fs.existsSync(full))
|
|
1150
|
+
return undefined;
|
|
1151
|
+
try {
|
|
1152
|
+
const data = JSON.parse(fs.readFileSync(full, 'utf8'));
|
|
1153
|
+
if (data && typeof data === 'object' && !Array.isArray(data)) {
|
|
1154
|
+
return data;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
catch {
|
|
1158
|
+
/* ignore */
|
|
1159
|
+
}
|
|
1160
|
+
return undefined;
|
|
1161
|
+
}
|
|
1162
|
+
function parseStaticPaths(full) {
|
|
1163
|
+
if (!fs.existsSync(full))
|
|
1164
|
+
return [];
|
|
1165
|
+
try {
|
|
1166
|
+
const data = JSON.parse(fs.readFileSync(full, 'utf8'));
|
|
1167
|
+
const list = Array.isArray(data)
|
|
1168
|
+
? data
|
|
1169
|
+
: data && typeof data === 'object' && Array.isArray(data.paths)
|
|
1170
|
+
? data.paths
|
|
1171
|
+
: [];
|
|
1172
|
+
return list.filter((p) => typeof p === 'string' && p.startsWith('/')).map(normalizePathname);
|
|
1173
|
+
}
|
|
1174
|
+
catch {
|
|
1175
|
+
return [];
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
function asEntity(item) {
|
|
1179
|
+
if (!item || typeof item !== 'object')
|
|
1180
|
+
return undefined;
|
|
1181
|
+
return item;
|
|
1182
|
+
}
|
|
1183
|
+
function findEntityForPath(pathname, wpData, phplistData) {
|
|
1184
|
+
const front = wpData ? getFrontPageRef(wpData) : {};
|
|
1185
|
+
const pages = wpData && Array.isArray(wpData.pages) ? wpData.pages : [];
|
|
1186
|
+
if (pathname === '/') {
|
|
1187
|
+
const hit = pages.find((p) => {
|
|
1188
|
+
const ent = asEntity(p);
|
|
1189
|
+
if (!ent)
|
|
1190
|
+
return false;
|
|
1191
|
+
if (front.slug && ent.slug === front.slug)
|
|
1192
|
+
return true;
|
|
1193
|
+
if (typeof front.id === 'number' && typeof p.id === 'number') {
|
|
1194
|
+
return p.id === front.id;
|
|
1195
|
+
}
|
|
1196
|
+
return false;
|
|
1197
|
+
});
|
|
1198
|
+
return asEntity(hit);
|
|
1199
|
+
}
|
|
1200
|
+
const pageSlug = pathname.replace(/^\//, '');
|
|
1201
|
+
const pageHit = pages.find((p) => asEntity(p)?.slug === pageSlug);
|
|
1202
|
+
if (pageHit)
|
|
1203
|
+
return asEntity(pageHit);
|
|
1204
|
+
const prefixes = parseRoutePrefixes();
|
|
1205
|
+
for (const [type, prefix] of Object.entries(prefixes)) {
|
|
1206
|
+
const normalizedPrefix = normalizePathname(prefix.startsWith('/') ? prefix : `/${prefix}`);
|
|
1207
|
+
if (pathname === normalizedPrefix)
|
|
1208
|
+
continue;
|
|
1209
|
+
if (!pathname.startsWith(`${normalizedPrefix}/`))
|
|
1210
|
+
continue;
|
|
1211
|
+
const slug = pathname.slice(normalizedPrefix.length).replace(/^\//, '');
|
|
1212
|
+
const arr = wpData?.[type];
|
|
1213
|
+
if (!Array.isArray(arr))
|
|
1214
|
+
continue;
|
|
1215
|
+
const hit = arr.find((p) => asEntity(p)?.slug === slug);
|
|
1216
|
+
if (hit)
|
|
1217
|
+
return asEntity(hit);
|
|
1218
|
+
}
|
|
1219
|
+
const nBase = newsletterRouteBase();
|
|
1220
|
+
if (pathname.startsWith(`${nBase}/`) || (nBase !== '/' && pathname.startsWith(`${nBase}/`))) {
|
|
1221
|
+
const slug = nBase === '/' ? pathname.replace(/^\//, '') : pathname.slice(nBase.length).replace(/^\//, '');
|
|
1222
|
+
const newsletters = phplistData && Array.isArray(phplistData.newsletters) ? phplistData.newsletters : [];
|
|
1223
|
+
const hit = newsletters.find((n) => n && typeof n === 'object' && n.slug === slug);
|
|
1224
|
+
if (hit && typeof hit === 'object') {
|
|
1225
|
+
const rec = hit;
|
|
1226
|
+
return {
|
|
1227
|
+
slug: rec.slug,
|
|
1228
|
+
title: { rendered: rec.subject || '' },
|
|
1229
|
+
excerpt: { rendered: rec.excerpt || '' },
|
|
1230
|
+
content: { rendered: rec.html || '' },
|
|
1231
|
+
date: rec.sent_at,
|
|
1232
|
+
modified: rec.sent_at,
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
return undefined;
|
|
1237
|
+
}
|
|
1238
|
+
async function generateSeoManifest(options = {}) {
|
|
1239
|
+
dotenv.config();
|
|
1240
|
+
dotenv.config({ path: '.env.local' });
|
|
1241
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1242
|
+
const wpDataPath = options.wpDataPath ?? 'public/wordpress-data.json';
|
|
1243
|
+
const phplistDataPath = options.phplistDataPath ?? 'public/phplist-data.json';
|
|
1244
|
+
const staticInputPath = options.staticInputPath ?? 'public/sitemap-static-paths.json';
|
|
1245
|
+
const manifestOutputPath = options.manifestOutputPath ?? 'public/seo-manifest.json';
|
|
1246
|
+
const wpData = loadJson(path.join(cwd, wpDataPath));
|
|
1247
|
+
const phplistData = loadJson(path.join(cwd, phplistDataPath));
|
|
1248
|
+
const staticPaths = parseStaticPaths(path.join(cwd, staticInputPath));
|
|
1249
|
+
const urls = collectSitemapUrls({
|
|
1250
|
+
wpData,
|
|
1251
|
+
phplistData,
|
|
1252
|
+
staticPaths,
|
|
1253
|
+
prefixes: parseRoutePrefixes(),
|
|
1254
|
+
});
|
|
1255
|
+
const defaults = getSeoDefaultsFromEnv();
|
|
1256
|
+
const entries = urls.map((u) => {
|
|
1257
|
+
const entity = findEntityForPath(u.path, wpData, phplistData);
|
|
1258
|
+
const resolved = resolvePageSeo(entity, u.path);
|
|
1259
|
+
const jsonLd = buildPageJsonLd(entity, u.path, {
|
|
1260
|
+
title: resolved.head.title,
|
|
1261
|
+
description: resolved.head.description,
|
|
1262
|
+
imageUrl: resolved.head.imageUrl,
|
|
1263
|
+
canonicalUrl: resolved.head.canonicalUrl,
|
|
1264
|
+
});
|
|
1265
|
+
const bodySource = (typeof entity?.content_cloudflare === 'string' && entity.content_cloudflare) ||
|
|
1266
|
+
renderedHtml(entity?.content);
|
|
1267
|
+
return {
|
|
1268
|
+
path: u.path,
|
|
1269
|
+
title: resolved.head.title || defaults.defaultTitle || defaults.siteName || '',
|
|
1270
|
+
description: resolved.head.description || defaults.defaultDescription || '',
|
|
1271
|
+
canonical: resolved.head.canonicalUrl,
|
|
1272
|
+
image: resolved.head.imageUrl || u.image,
|
|
1273
|
+
noindex: resolved.noindex,
|
|
1274
|
+
ogType: resolved.head.ogType,
|
|
1275
|
+
jsonLd,
|
|
1276
|
+
bodyHtml: bodySource ? sanitizeBodyHtml(bodySource) : '',
|
|
1277
|
+
};
|
|
1278
|
+
});
|
|
1279
|
+
const full = path.join(cwd, manifestOutputPath);
|
|
1280
|
+
fs.mkdirSync(path.dirname(full), { recursive: true });
|
|
1281
|
+
fs.writeFileSync(full, `${JSON.stringify({ generated_at: new Date().toISOString(), urls: entries }, null, 2)}\n`, 'utf8');
|
|
1282
|
+
console.log(`📍 SEO manifest written (${entries.length} URLs): ${full}`);
|
|
1283
|
+
}
|
|
1284
|
+
async function generateSeoManifestSafe(options = {}) {
|
|
1285
|
+
try {
|
|
1286
|
+
await generateSeoManifest(options);
|
|
1287
|
+
}
|
|
1288
|
+
catch (e) {
|
|
1289
|
+
console.error('❌ SEO manifest generation failed:', e.message);
|
|
1290
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1291
|
+
const manifestOutputPath = options.manifestOutputPath ?? 'public/seo-manifest.json';
|
|
1292
|
+
const full = path.join(cwd, manifestOutputPath);
|
|
1293
|
+
fs.mkdirSync(path.dirname(full), { recursive: true });
|
|
1294
|
+
fs.writeFileSync(full, `${JSON.stringify({ urls: [] }, null, 2)}\n`, 'utf8');
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
function upsertMeta(html, attrName, attrValue, content) {
|
|
1299
|
+
const re = new RegExp(`<meta\\s+[^>]*${attrName}=["']${attrValue.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}["'][^>]*>`, 'i');
|
|
1300
|
+
const tag = `<meta ${attrName}="${escapeAttr(attrValue)}" content="${escapeAttr(content)}" />`;
|
|
1301
|
+
if (re.test(html))
|
|
1302
|
+
return html.replace(re, tag);
|
|
1303
|
+
return html.replace(/<\/head>/i, ` ${tag}\n </head>`);
|
|
1304
|
+
}
|
|
1305
|
+
function upsertLink(html, rel, href) {
|
|
1306
|
+
const re = new RegExp(`<link\\s+[^>]*rel=["']${rel}["'][^>]*>`, 'i');
|
|
1307
|
+
const tag = `<link rel="${escapeAttr(rel)}" href="${escapeAttr(href)}" />`;
|
|
1308
|
+
if (re.test(html))
|
|
1309
|
+
return html.replace(re, tag);
|
|
1310
|
+
return html.replace(/<\/head>/i, ` ${tag}\n </head>`);
|
|
1311
|
+
}
|
|
1312
|
+
function injectJsonLd(html, blocks) {
|
|
1313
|
+
if (!blocks?.length)
|
|
1314
|
+
return html;
|
|
1315
|
+
const scripts = blocks
|
|
1316
|
+
.map((b) => `<script type="application/ld+json">${JSON.stringify(b).replace(/</g, '\\u003c')}</script>`)
|
|
1317
|
+
.join('\n ');
|
|
1318
|
+
return html.replace(/<\/head>/i, ` ${scripts}\n </head>`);
|
|
1319
|
+
}
|
|
1320
|
+
function applyEntry(html, entry) {
|
|
1321
|
+
let out = html;
|
|
1322
|
+
if (entry.title) {
|
|
1323
|
+
out = out.replace(/<title>[\s\S]*?<\/title>/i, `<title>${escapeHtml(entry.title)}</title>`);
|
|
1324
|
+
}
|
|
1325
|
+
if (entry.description) {
|
|
1326
|
+
out = upsertMeta(out, 'name', 'description', entry.description);
|
|
1327
|
+
out = upsertMeta(out, 'property', 'og:description', entry.description);
|
|
1328
|
+
}
|
|
1329
|
+
if (entry.title) {
|
|
1330
|
+
out = upsertMeta(out, 'property', 'og:title', entry.title);
|
|
1331
|
+
out = upsertMeta(out, 'name', 'twitter:title', entry.title);
|
|
1332
|
+
}
|
|
1333
|
+
if (entry.canonical) {
|
|
1334
|
+
out = upsertLink(out, 'canonical', entry.canonical);
|
|
1335
|
+
out = upsertMeta(out, 'property', 'og:url', entry.canonical);
|
|
1336
|
+
}
|
|
1337
|
+
if (entry.image) {
|
|
1338
|
+
out = upsertMeta(out, 'property', 'og:image', entry.image);
|
|
1339
|
+
out = upsertMeta(out, 'name', 'twitter:image', entry.image);
|
|
1340
|
+
}
|
|
1341
|
+
if (entry.ogType) {
|
|
1342
|
+
out = upsertMeta(out, 'property', 'og:type', entry.ogType);
|
|
1343
|
+
}
|
|
1344
|
+
if (entry.noindex) {
|
|
1345
|
+
out = upsertMeta(out, 'name', 'robots', 'noindex, nofollow');
|
|
1346
|
+
}
|
|
1347
|
+
out = injectJsonLd(out, entry.jsonLd);
|
|
1348
|
+
const snapshot = `<article data-digivalt-prerender><h1>${escapeHtml(entry.title || '')}</h1>${entry.description ? `<p>${escapeHtml(entry.description)}</p>` : ''}${entry.bodyHtml || ''}</article>`;
|
|
1349
|
+
if (/<div id="root"><\/div>/i.test(out)) {
|
|
1350
|
+
out = out.replace(/<div id="root"><\/div>/i, `<div id="root">${snapshot}</div>`);
|
|
1351
|
+
}
|
|
1352
|
+
else if (/<div id="root">[\s\S]*?<\/div>/i.test(out)) {
|
|
1353
|
+
out = out.replace(/<div id="root">[\s\S]*?<\/div>/i, `<div id="root">${snapshot}</div>`);
|
|
1354
|
+
}
|
|
1355
|
+
return out;
|
|
1356
|
+
}
|
|
1357
|
+
function distFileForPath(distAbs, urlPath) {
|
|
1358
|
+
if (urlPath === '/')
|
|
1359
|
+
return path.join(distAbs, 'index.html');
|
|
1360
|
+
const rel = urlPath.replace(/^\//, '');
|
|
1361
|
+
return path.join(distAbs, rel, 'index.html');
|
|
1362
|
+
}
|
|
1363
|
+
async function prerenderSeoHtml(options = {}) {
|
|
1364
|
+
dotenv.config();
|
|
1365
|
+
dotenv.config({ path: '.env.local' });
|
|
1366
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1367
|
+
const distDir = options.distDir ?? 'dist';
|
|
1368
|
+
const distAbs = path.join(cwd, distDir);
|
|
1369
|
+
const indexFile = path.join(distAbs, 'index.html');
|
|
1370
|
+
if (!fs.existsSync(indexFile)) {
|
|
1371
|
+
console.warn('⚠️ prerenderSeoHtml: dist/index.html missing; skip.');
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
const manifestCandidates = [
|
|
1375
|
+
options.manifestPath ? path.join(cwd, options.manifestPath) : '',
|
|
1376
|
+
path.join(distAbs, 'seo-manifest.json'),
|
|
1377
|
+
path.join(cwd, 'public', 'seo-manifest.json'),
|
|
1378
|
+
].filter(Boolean);
|
|
1379
|
+
let manifestRaw;
|
|
1380
|
+
for (const p of manifestCandidates) {
|
|
1381
|
+
if (fs.existsSync(p)) {
|
|
1382
|
+
manifestRaw = fs.readFileSync(p, 'utf8');
|
|
1383
|
+
break;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
if (!manifestRaw) {
|
|
1387
|
+
console.warn('⚠️ prerenderSeoHtml: seo-manifest.json missing; skip.');
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
let urls = [];
|
|
1391
|
+
try {
|
|
1392
|
+
const data = JSON.parse(manifestRaw);
|
|
1393
|
+
urls = Array.isArray(data.urls) ? data.urls : [];
|
|
1394
|
+
}
|
|
1395
|
+
catch (e) {
|
|
1396
|
+
console.warn('⚠️ prerenderSeoHtml: invalid manifest:', e.message);
|
|
1397
|
+
return;
|
|
1398
|
+
}
|
|
1399
|
+
const template = fs.readFileSync(indexFile, 'utf8');
|
|
1400
|
+
let written = 0;
|
|
1401
|
+
for (const entry of urls) {
|
|
1402
|
+
if (!entry?.path)
|
|
1403
|
+
continue;
|
|
1404
|
+
const html = applyEntry(template, entry);
|
|
1405
|
+
const dest = distFileForPath(distAbs, entry.path);
|
|
1406
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
1407
|
+
fs.writeFileSync(dest, html, 'utf8');
|
|
1408
|
+
written += 1;
|
|
1409
|
+
}
|
|
1410
|
+
console.log(`📍 Prerendered ${written} HTML snapshots into ${distAbs}`);
|
|
1411
|
+
}
|
|
1412
|
+
|
|
576
1413
|
async function generateAllData() {
|
|
577
|
-
// Load .env files if they exist (for local development)
|
|
578
1414
|
dotenv.config();
|
|
579
1415
|
dotenv.config({ path: '.env.local' });
|
|
580
1416
|
console.log('🚀 Starting DigiVAlt static data generation...');
|
|
581
1417
|
if (process.env.VITE_IS_LOVABLE === 'true') {
|
|
582
|
-
console.log('⚡
|
|
583
|
-
return;
|
|
1418
|
+
console.log('⚡ Fixture mode (`VITE_IS_LOVABLE`) enabled. Skipping remote fetch; refreshing sitemap and SEO manifest from committed JSON.');
|
|
584
1419
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
1420
|
+
else {
|
|
1421
|
+
const wpSuccess = await generateWordPressData();
|
|
1422
|
+
const gfSuccess = await generateGravityFormsData();
|
|
1423
|
+
await generateMauticData();
|
|
1424
|
+
await generatePhplistData();
|
|
1425
|
+
await generateSuiteCRMData();
|
|
1426
|
+
await generateGoogleReviewsData();
|
|
1427
|
+
if (!wpSuccess || !gfSuccess) {
|
|
1428
|
+
console.error('❌ Required generation failed (WordPress or Gravity Forms). See above for details.');
|
|
1429
|
+
process.exit(1);
|
|
1430
|
+
}
|
|
595
1431
|
}
|
|
596
1432
|
await generateSitemapPathsSafe();
|
|
1433
|
+
await generateSeoManifestSafe();
|
|
597
1434
|
console.log('✅ Generation complete!');
|
|
598
1435
|
}
|
|
599
1436
|
|
|
600
1437
|
var index = /*#__PURE__*/Object.freeze({
|
|
601
1438
|
__proto__: null,
|
|
602
1439
|
PSEUDO_POST_TYPES: PSEUDO_POST_TYPES,
|
|
1440
|
+
SITEMAP_URL_SHARD_SIZE: SITEMAP_URL_SHARD_SIZE,
|
|
1441
|
+
collectSitemapUrls: collectSitemapUrls,
|
|
1442
|
+
entityImage: entityImage,
|
|
1443
|
+
entityLastmod: entityLastmod,
|
|
603
1444
|
generateAllData: generateAllData,
|
|
604
1445
|
generateGoogleReviewsData: generateGoogleReviewsData,
|
|
605
1446
|
generateGravityFormsData: generateGravityFormsData,
|
|
606
1447
|
generateMauticData: generateMauticData,
|
|
607
1448
|
generatePhplistData: generatePhplistData,
|
|
1449
|
+
generateSeoManifest: generateSeoManifest,
|
|
1450
|
+
generateSeoManifestSafe: generateSeoManifestSafe,
|
|
608
1451
|
generateSitemapPaths: generateSitemapPaths,
|
|
609
1452
|
generateSitemapPathsSafe: generateSitemapPathsSafe,
|
|
610
1453
|
generateSuiteCRMData: generateSuiteCRMData,
|
|
611
1454
|
generateWordPressData: generateWordPressData,
|
|
1455
|
+
getFrontPageRef: getFrontPageRef,
|
|
1456
|
+
getFrontPageSlug: getFrontPageSlug,
|
|
612
1457
|
getWordPressPostTypes: getWordPressPostTypes,
|
|
613
1458
|
isGoogleReviewsEnabled: isGoogleReviewsEnabled,
|
|
614
|
-
|
|
1459
|
+
isNoindexEntity: isNoindexEntity,
|
|
1460
|
+
isPublishedEntity: isPublishedEntity,
|
|
1461
|
+
newsletterRouteBase: newsletterRouteBase,
|
|
1462
|
+
parseEnabledPostTypes: parseEnabledPostTypes,
|
|
1463
|
+
parseRoutePrefixes: parseRoutePrefixes,
|
|
1464
|
+
prerenderSeoHtml: prerenderSeoHtml
|
|
615
1465
|
});
|
|
616
1466
|
|
|
617
1467
|
/**
|
|
@@ -623,18 +1473,31 @@ const getDigiValtVersion = () => {
|
|
|
623
1473
|
};
|
|
624
1474
|
|
|
625
1475
|
exports.PSEUDO_POST_TYPES = PSEUDO_POST_TYPES;
|
|
1476
|
+
exports.SITEMAP_URL_SHARD_SIZE = SITEMAP_URL_SHARD_SIZE;
|
|
1477
|
+
exports.collectSitemapUrls = collectSitemapUrls;
|
|
1478
|
+
exports.entityImage = entityImage;
|
|
1479
|
+
exports.entityLastmod = entityLastmod;
|
|
626
1480
|
exports.generateAllData = generateAllData;
|
|
627
1481
|
exports.generateGoogleReviewsData = generateGoogleReviewsData;
|
|
628
1482
|
exports.generateGravityFormsData = generateGravityFormsData;
|
|
629
1483
|
exports.generateMauticData = generateMauticData;
|
|
630
1484
|
exports.generatePhplistData = generatePhplistData;
|
|
1485
|
+
exports.generateSeoManifest = generateSeoManifest;
|
|
1486
|
+
exports.generateSeoManifestSafe = generateSeoManifestSafe;
|
|
631
1487
|
exports.generateSitemapPaths = generateSitemapPaths;
|
|
632
1488
|
exports.generateSitemapPathsSafe = generateSitemapPathsSafe;
|
|
633
1489
|
exports.generateSuiteCRMData = generateSuiteCRMData;
|
|
634
1490
|
exports.generateWordPressData = generateWordPressData;
|
|
635
1491
|
exports.generators = index;
|
|
636
1492
|
exports.getDigiValtVersion = getDigiValtVersion;
|
|
1493
|
+
exports.getFrontPageRef = getFrontPageRef;
|
|
1494
|
+
exports.getFrontPageSlug = getFrontPageSlug;
|
|
637
1495
|
exports.getWordPressPostTypes = getWordPressPostTypes;
|
|
638
1496
|
exports.isGoogleReviewsEnabled = isGoogleReviewsEnabled;
|
|
1497
|
+
exports.isNoindexEntity = isNoindexEntity;
|
|
1498
|
+
exports.isPublishedEntity = isPublishedEntity;
|
|
1499
|
+
exports.newsletterRouteBase = newsletterRouteBase;
|
|
639
1500
|
exports.parseEnabledPostTypes = parseEnabledPostTypes;
|
|
1501
|
+
exports.parseRoutePrefixes = parseRoutePrefixes;
|
|
1502
|
+
exports.prerenderSeoHtml = prerenderSeoHtml;
|
|
640
1503
|
//# sourceMappingURL=index.cjs.map
|