@marvalt/digivalt-core 0.2.29 → 0.2.32
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 +39 -0
- package/GLOBAL-SHORTCODES.md +99 -0
- package/README.md +11 -9
- 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/dist/utils/wpRegistry.d.ts +1 -1
- 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 +8 -5
- package/docs/SEO-PERFORMANCE.md +42 -11
- package/docs/SHORTCODES.md +39 -0
- package/package.json +20 -8
- 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
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# WordPress shortcodes — `@marvalt/digivalt-core`
|
|
2
|
+
|
|
3
|
+
After install: `node_modules/@marvalt/digivalt-core/docs/SHORTCODES.md`.
|
|
4
|
+
|
|
5
|
+
The same list lives at the package root as `GLOBAL-SHORTCODES.md`.
|
|
6
|
+
|
|
7
|
+
Content editors type shortcodes into WordPress. `@marvalt/wparser` finds `[name attr="value"]` in block HTML. `createContentRegistry()` from `@marvalt/digivalt-core/registry` maps package-supported names to React components. `digivalt-init` does not copy a registry file.
|
|
8
|
+
|
|
9
|
+
**Do not register these as WordPress PHP shortcodes.** They must stay literal in REST content.
|
|
10
|
+
|
|
11
|
+
## What the app already merges
|
|
12
|
+
|
|
13
|
+
| Shortcode | Package | Notes |
|
|
14
|
+
|-----------|---------|--------|
|
|
15
|
+
| `[mautic_form id="1"]` | `@marvalt/madapter` `getMauticShortcodeHandlers()` | Optional `title`, `description`. See `node_modules/@marvalt/madapter/docs/SHORTCODES.md`. |
|
|
16
|
+
| `[phplist_subscribe list="1" attrs="firstname,lastname"]` | `@marvalt/plister` `getPhplistShortcodeHandlers()` | Visible fields only. Optional `page`, `title`, `intro`. See `node_modules/@marvalt/plister/docs/SHORTCODES.md`. |
|
|
17
|
+
| `[gf_embed id="1"]` / `[gform …]` | core | Gravity Forms inline. |
|
|
18
|
+
| `[popupbtn_gf …]` / `[popupbtn_mautic …]` | core | Package-local popup controls. |
|
|
19
|
+
|
|
20
|
+
Full attribute list: package root [GLOBAL-SHORTCODES.md](../GLOBAL-SHORTCODES.md).
|
|
21
|
+
|
|
22
|
+
## If shortcodes stay as raw text
|
|
23
|
+
|
|
24
|
+
1. The shortcode is not in `registry.shortcodes` — use `createContentRegistry()` or merge the required custom handler.
|
|
25
|
+
2. Someone registered a PHP shortcode in WordPress — undo that so the token remains in the API response.
|
|
26
|
+
3. Mautic/PHPList JSON was not generated, or `QueryClientProvider` is missing.
|
|
27
|
+
|
|
28
|
+
## Standalone custom registry
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { getMauticShortcodeHandlers } from '@marvalt/madapter';
|
|
32
|
+
import { getPhplistShortcodeHandlers } from '@marvalt/plister';
|
|
33
|
+
|
|
34
|
+
Object.assign(
|
|
35
|
+
registry.shortcodes,
|
|
36
|
+
getMauticShortcodeHandlers(),
|
|
37
|
+
getPhplistShortcodeHandlers()
|
|
38
|
+
);
|
|
39
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marvalt/digivalt-core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.32",
|
|
4
4
|
"description": "Core glue logic and shared context for DigiVAlt frontend applications",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -42,6 +42,11 @@
|
|
|
42
42
|
"import": "./dist/seo.esm.js",
|
|
43
43
|
"require": "./dist/seo.cjs"
|
|
44
44
|
},
|
|
45
|
+
"./registry": {
|
|
46
|
+
"types": "./dist/registry.d.ts",
|
|
47
|
+
"import": "./dist/registry.esm.js",
|
|
48
|
+
"require": "./dist/registry.cjs"
|
|
49
|
+
},
|
|
45
50
|
"./integrations": {
|
|
46
51
|
"types": "./dist/integrations.d.ts",
|
|
47
52
|
"import": "./dist/integrations.esm.js",
|
|
@@ -62,6 +67,7 @@
|
|
|
62
67
|
"README.md",
|
|
63
68
|
"LICENSE",
|
|
64
69
|
"CHANGELOG.md",
|
|
70
|
+
"GLOBAL-SHORTCODES.md",
|
|
65
71
|
"bin",
|
|
66
72
|
"template"
|
|
67
73
|
],
|
|
@@ -100,24 +106,30 @@
|
|
|
100
106
|
"typescript": "^5.5.3"
|
|
101
107
|
},
|
|
102
108
|
"peerDependencies": {
|
|
109
|
+
"@tanstack/react-query": ">=5",
|
|
103
110
|
"react": ">=18",
|
|
104
111
|
"react-dom": ">=18",
|
|
105
112
|
"react-helmet-async": ">=2"
|
|
106
113
|
},
|
|
114
|
+
"peerDependenciesMeta": {
|
|
115
|
+
"@tanstack/react-query": {
|
|
116
|
+
"optional": true
|
|
117
|
+
}
|
|
118
|
+
},
|
|
107
119
|
"engines": {
|
|
108
120
|
"node": ">=18.0.0",
|
|
109
121
|
"npm": ">=8.0.0"
|
|
110
122
|
},
|
|
111
123
|
"dependencies": {
|
|
112
124
|
"@digivalt/tracker": "^0.1.1",
|
|
113
|
-
"@marvalt/dstyler": "^0.1.
|
|
114
|
-
"@marvalt/madapter": "^2.3.
|
|
115
|
-
"@marvalt/plister": "^0.
|
|
116
|
-
"@marvalt/sadapter": "^0.1.
|
|
117
|
-
"@marvalt/shcoder": "^0.1.
|
|
118
|
-
"@marvalt/tadapter": "^1.0.
|
|
125
|
+
"@marvalt/dstyler": "^0.1.53",
|
|
126
|
+
"@marvalt/madapter": "^2.3.11",
|
|
127
|
+
"@marvalt/plister": "^0.3.0",
|
|
128
|
+
"@marvalt/sadapter": "^0.1.6",
|
|
129
|
+
"@marvalt/shcoder": "^0.1.37",
|
|
130
|
+
"@marvalt/tadapter": "^1.0.14",
|
|
119
131
|
"@marvalt/wadapter": "^2.3.61",
|
|
120
|
-
"@marvalt/wparser": "^0.1.
|
|
132
|
+
"@marvalt/wparser": "^0.1.82",
|
|
121
133
|
"@radix-ui/react-toast": "^1.2.15",
|
|
122
134
|
"class-variance-authority": "^0.7.1",
|
|
123
135
|
"clsx": "^2.1.1",
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Welcome to your new **DigiVAlt** architecture project!
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Your Vite interface is decoupled from the data pipeline. `@marvalt/digivalt-core` supplies static generation and runtime helpers for your Cloudflare Pages app.
|
|
6
6
|
|
|
7
|
-
Follow these instructions
|
|
7
|
+
Follow these instructions to hydrate a new Vite project with real data.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -17,7 +17,7 @@ npm install -D vite-node
|
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
## 🛠️ 2. Wire the Build Scripts
|
|
20
|
-
`digivalt-init`
|
|
20
|
+
`digivalt-init` preflights your app and patches safe script cases automatically. In a standard Vite app, it should add or update the DigiValt build wiring for you.
|
|
21
21
|
|
|
22
22
|
Still verify your `package.json` after running init. The expected result is:
|
|
23
23
|
|
|
@@ -58,7 +58,7 @@ VITE_GRAVITY_FORMS_SECRET="your_cs_secret"
|
|
|
58
58
|
# Local Execution Mode (Set to "direct" internally so your local UI bypasses Cloudflare)
|
|
59
59
|
VITE_AUTH_MODE="direct"
|
|
60
60
|
```
|
|
61
|
-
*⚠️ **CRITICAL WARNING:**
|
|
61
|
+
*⚠️ **CRITICAL WARNING:** Never enable fixture mode (`VITE_IS_LOVABLE=true`) in `.env.local` when you need live generation. The backwards-compatible flag skips API traffic and uses committed data.*
|
|
62
62
|
|
|
63
63
|
## 🌩️ 5. Deploy Infrastructure to Cloudflare
|
|
64
64
|
Once you connect this GitHub repository to the Cloudflare Pages dashboard:
|
|
@@ -77,15 +77,21 @@ Init will:
|
|
|
77
77
|
- refresh older DigiVAlt-managed `scripts/generate.ts` files
|
|
78
78
|
- reconcile the DigiValt-managed sections inside `.env.example` and `.env.local.example`
|
|
79
79
|
- warn instead of overwriting custom build logic or custom generator scripts
|
|
80
|
-
- report stale legacy workarounds that may no longer be needed
|
|
80
|
+
- report stale legacy workarounds and local registry files that may no longer be needed
|
|
81
|
+
|
|
82
|
+
## App chrome and WordPress page bodies
|
|
83
|
+
|
|
84
|
+
Use `DigiValtProviders`, `DigiValtWpPage`, and `createContentRegistry` from `@marvalt/digivalt-core/registry`. Read static chrome content with `getAppChrome()` from `@marvalt/digivalt-core/static`.
|
|
85
|
+
|
|
86
|
+
> Build Header/Footer in the app. Read menus, logo, and copy from WordPress static data (`getAppChrome()`). Apply the app’s layout and Tailwind. Do not render the WordPress header/footer template part and do not pipe `footer.blocks` / `header.blocks` through wparser.
|
|
81
87
|
|
|
82
88
|
## 7. SEO and PageSpeed (optional)
|
|
83
89
|
|
|
84
90
|
1. Install **`react-helmet-async`** and wrap your app with **`HelmetProvider`** at the root (next to the router).
|
|
85
91
|
2. Set at least **`VITE_SEO_SITE_URL`** (no trailing slash), **`VITE_SEO_SITE_NAME`**, **`VITE_SEO_DEFAULT_TITLE`**, **`VITE_SEO_DEFAULT_DESCRIPTION`**, and **`VITE_SEO_DEFAULT_OG_IMAGE`** in Cloudflare Pages / `.env.local`.
|
|
86
|
-
3. Import **`DigiValtSeoHead`**
|
|
87
|
-
4. **Sitemap:** **`/sitemap.xml`**
|
|
88
|
-
5. Read the full guide shipped with the package: **`node_modules/@marvalt/digivalt-core/docs/SEO-PERFORMANCE.md
|
|
92
|
+
3. Import **`DigiValtRouteSeo`** (or **`DigiValtSeoHead`** / **`JsonLd`**) from **`@marvalt/digivalt-core/seo`**; pass **`pathname`** per route.
|
|
93
|
+
4. **Sitemap / robots / prerender:** **`/sitemap.xml`** and **`/robots.txt`** are Pages Functions. **`public/sitemap-paths.json`** and **`seo-manifest.json`** are generated on `generate` / `build`. After `vite build`, run **`scripts/prerender-seo.ts`**. Edit **`public/sitemap-static-paths.json`** for app-only indexable routes. Do not add **`public/sitemap.xml`** or **`public/robots.txt`**. Per-URL meta lives in the **DigiValt SEO** WordPress plugin; site identity stays in **`VITE_SEO_*`**. Optional **`VITE_SEO_ROUTE_PREFIXES`** maps CPT REST slugs to app path prefixes. See **`docs/SEO-PERFORMANCE.md`**.
|
|
94
|
+
5. Read the full guide shipped with the package: **`node_modules/@marvalt/digivalt-core/docs/SEO-PERFORMANCE.md`**.
|
|
89
95
|
|
|
90
96
|
## 8. Analytics (Google Analytics / Matomo)
|
|
91
97
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serves /robots.txt with a Sitemap directive using VITE_SEO_SITE_URL when set.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
function normalizeBase(raw: string | undefined): string | null {
|
|
6
|
+
if (!raw || typeof raw !== 'string') return null;
|
|
7
|
+
const t = raw.trim().replace(/\/+$/, '');
|
|
8
|
+
return t || null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function onRequestGet(context: { request: Request; env: Record<string, string | undefined> }) {
|
|
12
|
+
const { request, env } = context;
|
|
13
|
+
const fromEnv = normalizeBase(env.VITE_SEO_SITE_URL || env.SITE_URL);
|
|
14
|
+
const origin = new URL(request.url).origin.replace(/\/+$/, '');
|
|
15
|
+
const base = fromEnv || origin;
|
|
16
|
+
const body = `User-agent: *
|
|
17
|
+
Allow: /
|
|
18
|
+
|
|
19
|
+
Sitemap: ${base}/sitemap.xml
|
|
20
|
+
`;
|
|
21
|
+
return new Response(body, {
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
24
|
+
'Cache-Control': 'public, max-age=300',
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -1,65 +1,143 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Serves /sitemap.xml from canonical site URL + public/sitemap-paths.json (generated at build).
|
|
3
|
-
* Set VITE_SEO_SITE_URL (or SITE_URL) on Cloudflare Pages for production canonical hosts.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Serves /sitemap.xml from canonical site URL + public/sitemap-paths.json (generated at build).
|
|
3
|
+
* Set VITE_SEO_SITE_URL (or SITE_URL) on Cloudflare Pages for production canonical hosts.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const IMAGE_NS = 'http://www.google.com/schemas/sitemap-image/1.1';
|
|
7
|
+
|
|
8
|
+
function normalizeBase(raw: string | undefined): string | null {
|
|
9
|
+
if (!raw || typeof raw !== 'string') return null;
|
|
10
|
+
const t = raw.trim().replace(/\/+$/, '');
|
|
11
|
+
return t || null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function escapeXml(s: string): string {
|
|
15
|
+
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type SitemapUrl = { path: string; lastmod?: string; image?: string };
|
|
19
|
+
|
|
20
|
+
function asUrls(data: unknown): SitemapUrl[] {
|
|
21
|
+
if (!data || typeof data !== 'object') return [];
|
|
22
|
+
const rec = data as { urls?: unknown; paths?: unknown };
|
|
23
|
+
if (Array.isArray(rec.urls)) {
|
|
24
|
+
return rec.urls
|
|
25
|
+
.map((u) => {
|
|
26
|
+
if (typeof u === 'string' && u.startsWith('/')) return { path: u };
|
|
27
|
+
if (u && typeof u === 'object' && typeof (u as { path?: unknown }).path === 'string') {
|
|
28
|
+
const row = u as { path: string; lastmod?: unknown; image?: unknown };
|
|
29
|
+
return {
|
|
30
|
+
path: row.path,
|
|
31
|
+
lastmod: typeof row.lastmod === 'string' ? row.lastmod : undefined,
|
|
32
|
+
image: typeof row.image === 'string' ? row.image : undefined,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
})
|
|
37
|
+
.filter((u): u is SitemapUrl => !!u && u.path.startsWith('/'));
|
|
38
|
+
}
|
|
39
|
+
if (Array.isArray(rec.paths)) {
|
|
40
|
+
return rec.paths.filter((p): p is string => typeof p === 'string' && p.startsWith('/')).map((path) => ({ path }));
|
|
41
|
+
}
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function fetchJson(request: Request, pathname: string): Promise<unknown> {
|
|
46
|
+
const jsonUrl = new URL(pathname, request.url);
|
|
47
|
+
const res = await fetch(jsonUrl.toString());
|
|
48
|
+
if (!res.ok) return null;
|
|
49
|
+
return res.json();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function loadUrls(request: Request): Promise<SitemapUrl[]> {
|
|
53
|
+
try {
|
|
54
|
+
const data = await fetchJson(request, '/sitemap-paths.json');
|
|
55
|
+
if (!data || typeof data !== 'object') return [{ path: '/' }];
|
|
56
|
+
const rec = data as { index?: unknown; parts?: unknown };
|
|
57
|
+
if (rec.index === true && typeof rec.parts === 'number' && rec.parts > 1) {
|
|
58
|
+
const partParam = new URL(request.url).searchParams.get('part');
|
|
59
|
+
if (partParam === null) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
const part = Number(partParam);
|
|
63
|
+
if (!Number.isInteger(part) || part < 0 || part >= rec.parts) return [{ path: '/' }];
|
|
64
|
+
const shard = await fetchJson(request, `/sitemap-paths-${part}.json`);
|
|
65
|
+
const urls = asUrls(shard);
|
|
66
|
+
return urls.length ? urls : [{ path: '/' }];
|
|
67
|
+
}
|
|
68
|
+
const urls = asUrls(data);
|
|
69
|
+
return urls.length ? urls : [{ path: '/' }];
|
|
70
|
+
} catch {
|
|
71
|
+
return [{ path: '/' }];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function loadIndexParts(request: Request): Promise<number | null> {
|
|
76
|
+
try {
|
|
77
|
+
const data = await fetchJson(request, '/sitemap-paths.json');
|
|
78
|
+
if (data && typeof data === 'object') {
|
|
79
|
+
const rec = data as { index?: unknown; parts?: unknown };
|
|
80
|
+
if (rec.index === true && typeof rec.parts === 'number' && rec.parts > 1) return rec.parts;
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
/* ignore */
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function locFor(base: string, p: string): string {
|
|
89
|
+
return p === '/' ? base : `${base}${p.startsWith('/') ? p : `/${p}`}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function buildUrlset(base: string, urls: SitemapUrl[]): string {
|
|
93
|
+
const lines = urls.map((u) => {
|
|
94
|
+
const loc = locFor(base, u.path);
|
|
95
|
+
const lastmod = u.lastmod ? `\n <lastmod>${escapeXml(u.lastmod)}</lastmod>` : '';
|
|
96
|
+
const image = u.image
|
|
97
|
+
? `\n <image:image>\n <image:loc>${escapeXml(u.image)}</image:loc>\n </image:image>`
|
|
98
|
+
: '';
|
|
99
|
+
return ` <url>\n <loc>${escapeXml(loc)}</loc>${lastmod}${image}\n </url>`;
|
|
100
|
+
});
|
|
101
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
102
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="${IMAGE_NS}">
|
|
103
|
+
${lines.join('\n')}
|
|
104
|
+
</urlset>`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function buildIndex(base: string, parts: number): string {
|
|
108
|
+
const items = [];
|
|
109
|
+
for (let i = 0; i < parts; i++) {
|
|
110
|
+
items.push(` <sitemap><loc>${escapeXml(`${base}/sitemap.xml?part=${i}`)}</loc></sitemap>`);
|
|
111
|
+
}
|
|
112
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
113
|
+
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
114
|
+
${items.join('\n')}
|
|
115
|
+
</sitemapindex>`;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export async function onRequestGet(context: { request: Request; env: Record<string, string | undefined> }) {
|
|
119
|
+
const { request, env } = context;
|
|
120
|
+
const fromEnv = normalizeBase(env.VITE_SEO_SITE_URL || env.SITE_URL);
|
|
121
|
+
const origin = new URL(request.url).origin.replace(/\/+$/, '');
|
|
122
|
+
const base = fromEnv || origin;
|
|
123
|
+
const part = new URL(request.url).searchParams.get('part');
|
|
124
|
+
|
|
125
|
+
const indexParts = await loadIndexParts(request);
|
|
126
|
+
if (indexParts && part === null) {
|
|
127
|
+
return new Response(buildIndex(base, indexParts), {
|
|
128
|
+
headers: {
|
|
129
|
+
'Content-Type': 'application/xml; charset=utf-8',
|
|
130
|
+
'Cache-Control': 'public, max-age=300',
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const urls = await loadUrls(request);
|
|
136
|
+
const xml = buildUrlset(base, urls.length ? urls : [{ path: '/' }]);
|
|
137
|
+
return new Response(xml, {
|
|
138
|
+
headers: {
|
|
139
|
+
'Content-Type': 'application/xml; charset=utf-8',
|
|
140
|
+
'Cache-Control': 'public, max-age=300',
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
import { generateAllData, generateSitemapPathsSafe } from '@marvalt/digivalt-core/generators';
|
|
1
|
+
import { generateAllData, generateSitemapPathsSafe, generateSeoManifestSafe } from '@marvalt/digivalt-core/generators';
|
|
2
2
|
|
|
3
3
|
async function runGenerators() {
|
|
4
|
-
console.log('🚀 Starting DigiVAlt static data generation
|
|
5
|
-
|
|
6
|
-
if (process.env.VITE_IS_LOVABLE === 'true') {
|
|
7
|
-
console.log(
|
|
8
|
-
'⚡ Lovable Environment Detected (VITE_IS_LOVABLE). Skipping static data fetch; refreshing sitemap paths from committed JSON.'
|
|
9
|
-
);
|
|
10
|
-
await generateSitemapPathsSafe();
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
4
|
+
console.log('🚀 Starting DigiVAlt static data generation...');
|
|
13
5
|
|
|
14
6
|
try {
|
|
15
7
|
await generateAllData();
|
|
@@ -17,6 +9,7 @@ async function runGenerators() {
|
|
|
17
9
|
} catch (error) {
|
|
18
10
|
console.error('❌ Data fetching encountered an error, but continuing build gracefully:', error);
|
|
19
11
|
await generateSitemapPathsSafe();
|
|
12
|
+
await generateSeoManifestSafe();
|
|
20
13
|
}
|
|
21
14
|
}
|
|
22
15
|
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# AI master prompt — DigiVAlt full local WordPress control
|
|
2
|
-
|
|
3
|
-
Use this as a single copy-paste master prompt in Cursor, Claude Code, Antigravity, Lovable, or similar AI coding tools.
|
|
4
|
-
|
|
5
|
-
The objective is a DigiValt app scaffold that is production-shaped from day one, where after generation a human only needs to set `.env` / `.env.local` values before first local run:
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm run build && npm run dev
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Scope
|
|
12
|
-
|
|
13
|
-
- **AI responsibilities:** scaffold code, install/wire dependencies, run `digivalt-init`, ensure scripts/files are correct, keep cloud/function wiring and SEO enabled, and build a WordPress-driven shell.
|
|
14
|
-
- **Human responsibilities:** set real env values on local PC and cloud dashboard, run first local build/dev, replace placeholder static data with real generated exports as needed.
|
|
15
|
-
|
|
16
|
-
## Canonical sources
|
|
17
|
-
|
|
18
|
-
- [README.md](../README.md)
|
|
19
|
-
- [template/DIGIVALT_SETUP.md](../template/DIGIVALT_SETUP.md)
|
|
20
|
-
- [template/scripts/generate.ts](../template/scripts/generate.ts)
|
|
21
|
-
- [docs/SEO-PERFORMANCE.md](./SEO-PERFORMANCE.md)
|
|
22
|
-
- [digivalt-landing/DIGIVALT_SETUP.md](../../../digivalt-landing/DIGIVALT_SETUP.md)
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## Master prompt text (paste below into your AI tool)
|
|
27
|
-
|
|
28
|
-
You are a senior full-stack engineer scaffolding a DigiValt consumer app (Vite + React + TypeScript) with full WordPress-controlled static content behavior. This workflow must work the same whether run from Cursor, Claude Code, Antigravity, Lovable, or another AI assistant.
|
|
29
|
-
|
|
30
|
-
### Non-negotiables
|
|
31
|
-
|
|
32
|
-
- Install `@marvalt/digivalt-core@latest`.
|
|
33
|
-
- Use `npx digivalt-init` to enforce DigiValt-managed scaffold files and scripts.
|
|
34
|
-
- Keep Cloudflare Pages Functions + `wrangler.toml` enabled.
|
|
35
|
-
- Keep SEO enabled by default (Helmet provider + DigiValt SEO helpers).
|
|
36
|
-
- Keep local secrets out of git and ignore `.env`, `.env.local`, `.env.*.local`, `.dev.vars`.
|
|
37
|
-
- Do not hand-maintain `public/sitemap-paths.json`; it is generated.
|
|
38
|
-
- Do not create `public/sitemap.xml` when using `functions/sitemap.xml.ts`.
|
|
39
|
-
|
|
40
|
-
### File/path requirements
|
|
41
|
-
|
|
42
|
-
Use these exact static data paths:
|
|
43
|
-
|
|
44
|
-
- `public/wordpress-data.json`
|
|
45
|
-
- `public/gravity-forms-data.json`
|
|
46
|
-
- `src/data/mautic-data.json`
|
|
47
|
-
|
|
48
|
-
If real exports are unavailable, use template starter fixtures (or equivalent minimal placeholders) so the app boots. Mark placeholders clearly.
|
|
49
|
-
|
|
50
|
-
### Build wiring requirements
|
|
51
|
-
|
|
52
|
-
Ensure these commands exist and are used:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
npm install @marvalt/digivalt-core@latest
|
|
56
|
-
npm install -D vite-node
|
|
57
|
-
npx digivalt-init
|
|
58
|
-
npm install react-helmet-async
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
Expected scripts:
|
|
62
|
-
|
|
63
|
-
- `generate`: `npx vite-node --options.deps.inline="@marvalt/digivalt-core/generators" scripts/generate.ts`
|
|
64
|
-
- `build`: `npx vite-node --options.deps.inline="@marvalt/digivalt-core/generators" scripts/generate.ts && vite build`
|
|
65
|
-
- `build:dev`: `npx vite-node --options.deps.inline="@marvalt/digivalt-core/generators" scripts/generate.ts && vite build --mode development`
|
|
66
|
-
- `dev`: `vite`
|
|
67
|
-
|
|
68
|
-
### `scripts/generate.ts` behavior
|
|
69
|
-
|
|
70
|
-
Import from `@marvalt/digivalt-core/generators` only:
|
|
71
|
-
|
|
72
|
-
- In hosted fixture mode (`VITE_IS_LOVABLE=true`): skip fetch, run `generateSitemapPathsSafe()`.
|
|
73
|
-
- In normal local mode (default): run `generateAllData()` then sitemap; on fetch failure still run sitemap safe fallback.
|
|
74
|
-
|
|
75
|
-
### WordPress-driven runtime wiring (must implement)
|
|
76
|
-
|
|
77
|
-
After `loadWordPressData()` from `@marvalt/digivalt-core/static`, wire the app shell and routes using WordPress static data:
|
|
78
|
-
|
|
79
|
-
1. Menus from `getNavigationMenu()` / `getFooterNavigationMenu()` / `getMenuById()` (+ `getParsedHeader()` / `getHeaderMenuId()` / `getFooterMenuId()`). Assign classic menus in WP under **Appearance → Menus → Manage Locations** (`{frontendId}-header|footer`, then `default-*`).
|
|
80
|
-
2. Optional header/footer template blocks from `getHeader()` / `getFooter()` (legacy). Prefer app-owned chrome + location menus for multi-frontend.
|
|
81
|
-
3. Site identity from `getSiteSettings()` / `getLogoUrl()` / `getSiteIconUrl()`.
|
|
82
|
-
4. Theme styles from `getWordPressData().theme_styles` mapped into app styling/tokens.
|
|
83
|
-
5. Pages/posts/CPT routes from `getWordPressPages()`, `getWordPressPageBySlug()`, `getWordPressPosts()`, and `front_page`.
|
|
84
|
-
|
|
85
|
-
For forms, support Gravity Forms and Mautic via `@marvalt/digivalt-core/services` and/or JSON static stores.
|
|
86
|
-
|
|
87
|
-
### Cloudflare and sitemap requirements
|
|
88
|
-
|
|
89
|
-
- Keep `functions/sitemap.xml.ts`.
|
|
90
|
-
- Keep `functions/api/*` handlers from template and keep `wrangler.toml`.
|
|
91
|
-
- Ensure sitemap flow is active:
|
|
92
|
-
- input: `public/sitemap-static-paths.json`
|
|
93
|
-
- generated output: `public/sitemap-paths.json`
|
|
94
|
-
- runtime endpoint: `/sitemap.xml` from Pages Function
|
|
95
|
-
|
|
96
|
-
### AI output constraints
|
|
97
|
-
|
|
98
|
-
- Do not request humans to hand-edit code before first run.
|
|
99
|
-
- After scaffolding, the only required manual step before first run is env values in `.env` / `.env.local`.
|
|
100
|
-
- Provide a final validation checklist and commands:
|
|
101
|
-
- `npm run build`
|
|
102
|
-
- `npm run dev`
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## Built-in defaults (use unless humans override later)
|
|
107
|
-
|
|
108
|
-
- Package: `@marvalt/digivalt-core@latest`
|
|
109
|
-
- Static data: template starter fixtures for WordPress, Gravity Forms, Mautic
|
|
110
|
-
- SEO: ON
|
|
111
|
-
- Cloudflare Functions + `wrangler.toml`: ON
|
|
112
|
-
- Form/page mapping: derive from WordPress content and shortcodes first
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## Pre-flight checklist
|
|
117
|
-
|
|
118
|
-
| Step | Done |
|
|
119
|
-
|------|------|
|
|
120
|
-
| `@marvalt/digivalt-core@latest` installed | ☐ |
|
|
121
|
-
| `digivalt-init` run and scripts verified | ☐ |
|
|
122
|
-
| Required static data files exist (`wordpress`, `gravity-forms`, `mautic`) | ☐ |
|
|
123
|
-
| `sitemap-static-paths.json` exists and `sitemap-paths.json` is generated | ☐ |
|
|
124
|
-
| Cloudflare functions/wrangler files present | ☐ |
|
|
125
|
-
| SEO imports + `HelmetProvider` wired | ☐ |
|
|
126
|
-
| `.gitignore` excludes local secret files | ☐ |
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
## Reference paths in this monorepo
|
|
131
|
-
|
|
132
|
-
| Concern | File |
|
|
133
|
-
|---------|------|
|
|
134
|
-
| Local setup baseline | [digivalt-landing/DIGIVALT_SETUP.md](../../../digivalt-landing/DIGIVALT_SETUP.md) |
|
|
135
|
-
| Template setup baseline | [template/DIGIVALT_SETUP.md](../template/DIGIVALT_SETUP.md) |
|
|
136
|
-
| Init behavior and script expectations | [README.md](../README.md) |
|
|
137
|
-
| Generator script template | [template/scripts/generate.ts](../template/scripts/generate.ts) |
|
|
138
|
-
| Landing generator implementation | [digivalt-landing/scripts/generate.ts](../../../digivalt-landing/scripts/generate.ts) |
|
|
139
|
-
| SEO and sitemap behavior | [docs/SEO-PERFORMANCE.md](./SEO-PERFORMANCE.md) |
|
|
140
|
-
| WP static getters and shell helpers | [src/static/wpStatic.ts](../src/static/wpStatic.ts) |
|