vite-wp 0.1.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/LICENSE +21 -0
- package/README.md +132 -0
- package/dist/astro.d.ts +5 -0
- package/dist/astro.js +27 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +40 -0
- package/dist/commands/dev.d.ts +1 -0
- package/dist/commands/dev.js +62 -0
- package/dist/commands/doctor.d.ts +6 -0
- package/dist/commands/doctor.js +139 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +55 -0
- package/dist/commands/smoke.d.ts +1 -0
- package/dist/commands/smoke.js +138 -0
- package/dist/commands/types.d.ts +1 -0
- package/dist/commands/types.js +67 -0
- package/dist/config.d.ts +71 -0
- package/dist/config.js +74 -0
- package/dist/content.d.ts +44 -0
- package/dist/content.js +190 -0
- package/dist/dev-toolbar/vitewp-toolbar.d.ts +23 -0
- package/dist/dev-toolbar/vitewp-toolbar.js +144 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/live.config.d.ts +64 -0
- package/dist/live.config.js +21 -0
- package/dist/runtime/astro.d.ts +4 -0
- package/dist/runtime/astro.js +69 -0
- package/dist/runtime/composer.d.ts +2 -0
- package/dist/runtime/composer.js +36 -0
- package/dist/runtime/php.d.ts +3 -0
- package/dist/runtime/php.js +79 -0
- package/dist/runtime/ports.d.ts +3 -0
- package/dist/runtime/ports.js +38 -0
- package/dist/runtime/process.d.ts +12 -0
- package/dist/runtime/process.js +51 -0
- package/dist/runtime/proxy.d.ts +6 -0
- package/dist/runtime/proxy.js +204 -0
- package/dist/runtime/wp-config.d.ts +3 -0
- package/dist/runtime/wp-config.js +82 -0
- package/dist/wordpress/client.d.ts +98 -0
- package/dist/wordpress/client.js +133 -0
- package/dist/wordpress/generated-types.d.ts +33 -0
- package/dist/wordpress/generated-types.js +2 -0
- package/dist/wordpress/menus.d.ts +24 -0
- package/dist/wordpress/menus.js +20 -0
- package/dist/wordpress/schemas.d.ts +58 -0
- package/dist/wordpress/schemas.js +39 -0
- package/dist/wordpress/templates.d.ts +19 -0
- package/dist/wordpress/templates.js +88 -0
- package/package.json +78 -0
- package/starter/.env.example +15 -0
- package/starter/astro.config.mjs +16 -0
- package/starter/composer.json +37 -0
- package/starter/src/env.d.ts +1 -0
- package/starter/src/live.config.ts +22 -0
- package/starter/src/pages/[...slug].astro +101 -0
- package/starter/src/templates/404.astro +11 -0
- package/starter/src/templates/pages/.gitkeep +0 -0
- package/starter/src/templates/pages/default.astro +12 -0
- package/starter/src/templates/pages/front-page.astro +13 -0
- package/starter/src/templates/partials/Header.astro +23 -0
- package/starter/src/templates/partials/Pagination.astro +21 -0
- package/starter/src/templates/post-types/.gitkeep +0 -0
- package/starter/src/templates/posts/.gitkeep +0 -0
- package/starter/src/templates/posts/archive.astro +25 -0
- package/starter/src/templates/posts/single.astro +12 -0
- package/starter/src/templates/search.astro +30 -0
- package/starter/src/templates/taxonomies/.gitkeep +0 -0
- package/starter/src/templates/taxonomies/taxonomy-[taxonomy].astro +28 -0
- package/starter/src/wordpress/client.ts +263 -0
- package/starter/src/wordpress/generated-types.ts +38 -0
- package/starter/src/wordpress/menus.ts +51 -0
- package/starter/src/wordpress/schemas.ts +44 -0
- package/starter/src/wordpress/templates.ts +113 -0
- package/starter/tsconfig.json +4 -0
- package/starter/vitewp.config.ts +29 -0
- package/starter/wordpress/content/mu-plugins/.gitkeep +0 -0
- package/starter/wordpress/content/mu-plugins/vitewp-bridge.php +560 -0
- package/starter/wordpress/content/themes/vitewp/functions.php +9 -0
- package/starter/wordpress/content/themes/vitewp/index.php +22 -0
- package/starter/wordpress/content/themes/vitewp/style.css +10 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { mkdirSync, symlinkSync, writeFileSync, existsSync, lstatSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
3
|
+
import { randomBytes } from 'node:crypto';
|
|
4
|
+
export function writeWordPressConfig(config) {
|
|
5
|
+
const docroot = resolve(config.root, config.wordpress.docroot);
|
|
6
|
+
const contentDir = resolve(config.root, config.wordpress.contentDir);
|
|
7
|
+
const wpConfigPath = join(docroot, 'wp-config.php');
|
|
8
|
+
const publicUrl = config.wordpress.url;
|
|
9
|
+
mkdirSync(docroot, { recursive: true });
|
|
10
|
+
mkdirSync(join(contentDir, 'plugins'), { recursive: true });
|
|
11
|
+
mkdirSync(join(contentDir, 'mu-plugins'), { recursive: true });
|
|
12
|
+
mkdirSync(join(contentDir, 'uploads'), { recursive: true });
|
|
13
|
+
ensureContentSymlink(docroot, contentDir);
|
|
14
|
+
writeFileSync(wpConfigPath, renderWpConfig(config, publicUrl, contentDir), 'utf8');
|
|
15
|
+
console.log(`✓ wp-config.php generated at ${relative(config.root, wpConfigPath)}`);
|
|
16
|
+
}
|
|
17
|
+
export function phpServerUrl(config) {
|
|
18
|
+
return `http://${config.dev.phpHost}:${config.dev.phpPort}`;
|
|
19
|
+
}
|
|
20
|
+
function renderWpConfig(config, publicUrl, contentDir) {
|
|
21
|
+
const database = config.database;
|
|
22
|
+
return `<?php
|
|
23
|
+
/**
|
|
24
|
+
* Generated by ViteWP for local development.
|
|
25
|
+
* Do not edit this file by hand; update vitewp.config.ts or environment variables instead.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
define('DB_NAME', ${phpString(database.name)});
|
|
29
|
+
define('DB_USER', ${phpString(database.user)});
|
|
30
|
+
define('DB_PASSWORD', ${phpString(database.password)});
|
|
31
|
+
define('DB_HOST', ${phpString(`${database.host}:${database.port}`)});
|
|
32
|
+
define('DB_CHARSET', 'utf8mb4');
|
|
33
|
+
define('DB_COLLATE', '');
|
|
34
|
+
|
|
35
|
+
${authKeys()}
|
|
36
|
+
|
|
37
|
+
$table_prefix = ${phpString(database.tablePrefix)};
|
|
38
|
+
|
|
39
|
+
define('WP_DEBUG', true);
|
|
40
|
+
define('WP_DEBUG_DISPLAY', false);
|
|
41
|
+
define('WP_DEBUG_LOG', true);
|
|
42
|
+
@ini_set('display_errors', '0');
|
|
43
|
+
define('WP_ENVIRONMENT_TYPE', 'local');
|
|
44
|
+
define('WP_DEFAULT_THEME', 'vitewp');
|
|
45
|
+
define('WP_HOME', ${phpString(publicUrl)});
|
|
46
|
+
define('WP_SITEURL', ${phpString(publicUrl)});
|
|
47
|
+
define('WP_CONTENT_DIR', ${phpString(contentDir)});
|
|
48
|
+
define('WP_CONTENT_URL', WP_HOME . '/wp-content');
|
|
49
|
+
|
|
50
|
+
if (! defined('ABSPATH')) {
|
|
51
|
+
define('ABSPATH', __DIR__ . '/');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
require_once ABSPATH . 'wp-settings.php';
|
|
55
|
+
`;
|
|
56
|
+
}
|
|
57
|
+
function authKeys() {
|
|
58
|
+
const names = [
|
|
59
|
+
'AUTH_KEY',
|
|
60
|
+
'SECURE_AUTH_KEY',
|
|
61
|
+
'LOGGED_IN_KEY',
|
|
62
|
+
'NONCE_KEY',
|
|
63
|
+
'AUTH_SALT',
|
|
64
|
+
'SECURE_AUTH_SALT',
|
|
65
|
+
'LOGGED_IN_SALT',
|
|
66
|
+
'NONCE_SALT',
|
|
67
|
+
];
|
|
68
|
+
return names.map((name) => `define('${name}', '${randomBytes(32).toString('base64')}');`).join('\n');
|
|
69
|
+
}
|
|
70
|
+
function phpString(value) {
|
|
71
|
+
return `'${value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
72
|
+
}
|
|
73
|
+
function ensureContentSymlink(docroot, contentDir) {
|
|
74
|
+
const link = join(docroot, 'wp-content');
|
|
75
|
+
if (existsSync(link)) {
|
|
76
|
+
if (lstatSync(link).isSymbolicLink())
|
|
77
|
+
return;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const target = relative(dirname(link), contentDir);
|
|
81
|
+
symlinkSync(target, link, 'dir');
|
|
82
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export interface WpRenderedField {
|
|
2
|
+
rendered: string;
|
|
3
|
+
}
|
|
4
|
+
export interface WpContentItem {
|
|
5
|
+
id: number;
|
|
6
|
+
slug: string;
|
|
7
|
+
type: string;
|
|
8
|
+
link: string;
|
|
9
|
+
title: WpRenderedField;
|
|
10
|
+
content: WpRenderedField;
|
|
11
|
+
excerpt?: WpRenderedField;
|
|
12
|
+
date?: string;
|
|
13
|
+
modified?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface WpArchivePayload {
|
|
16
|
+
items: WpContentItem[];
|
|
17
|
+
page: number;
|
|
18
|
+
perPage: number;
|
|
19
|
+
total: number;
|
|
20
|
+
totalPages: number;
|
|
21
|
+
}
|
|
22
|
+
interface BaseArchiveResolution {
|
|
23
|
+
found: true;
|
|
24
|
+
slug: string;
|
|
25
|
+
postType: string;
|
|
26
|
+
restBase: string;
|
|
27
|
+
title: string;
|
|
28
|
+
page?: number;
|
|
29
|
+
}
|
|
30
|
+
export type WpBridgeResolution = {
|
|
31
|
+
found: true;
|
|
32
|
+
kind: 'page' | 'single';
|
|
33
|
+
id: number;
|
|
34
|
+
slug: string;
|
|
35
|
+
postType: string;
|
|
36
|
+
restBase: string;
|
|
37
|
+
isFrontPage?: boolean;
|
|
38
|
+
isPostsPage?: boolean;
|
|
39
|
+
} | (BaseArchiveResolution & {
|
|
40
|
+
kind: 'postsArchive' | 'postTypeArchive';
|
|
41
|
+
}) | (BaseArchiveResolution & {
|
|
42
|
+
kind: 'taxonomyArchive';
|
|
43
|
+
taxonomy: string;
|
|
44
|
+
taxonomyRestBase: string;
|
|
45
|
+
termId: number;
|
|
46
|
+
termName: string;
|
|
47
|
+
}) | (BaseArchiveResolution & {
|
|
48
|
+
kind: 'search';
|
|
49
|
+
search: string;
|
|
50
|
+
}) | {
|
|
51
|
+
found: false;
|
|
52
|
+
kind: 'notFound';
|
|
53
|
+
};
|
|
54
|
+
export type WpResolvedRoute = {
|
|
55
|
+
kind: 'page';
|
|
56
|
+
postType: 'page';
|
|
57
|
+
restBase: 'pages';
|
|
58
|
+
slug: string;
|
|
59
|
+
item: WpContentItem;
|
|
60
|
+
isFrontPage?: boolean;
|
|
61
|
+
} | {
|
|
62
|
+
kind: 'single';
|
|
63
|
+
postType: string;
|
|
64
|
+
restBase: string;
|
|
65
|
+
slug: string;
|
|
66
|
+
item: WpContentItem;
|
|
67
|
+
} | {
|
|
68
|
+
kind: 'postsArchive' | 'postTypeArchive' | 'search';
|
|
69
|
+
postType: string;
|
|
70
|
+
restBase: string;
|
|
71
|
+
slug: string;
|
|
72
|
+
title: string;
|
|
73
|
+
items: WpContentItem[];
|
|
74
|
+
page: number;
|
|
75
|
+
perPage: number;
|
|
76
|
+
total: number;
|
|
77
|
+
totalPages: number;
|
|
78
|
+
search?: string;
|
|
79
|
+
} | {
|
|
80
|
+
kind: 'taxonomyArchive';
|
|
81
|
+
postType: string;
|
|
82
|
+
restBase: string;
|
|
83
|
+
slug: string;
|
|
84
|
+
title: string;
|
|
85
|
+
items: WpContentItem[];
|
|
86
|
+
page: number;
|
|
87
|
+
perPage: number;
|
|
88
|
+
total: number;
|
|
89
|
+
totalPages: number;
|
|
90
|
+
taxonomy: string;
|
|
91
|
+
taxonomyRestBase: string;
|
|
92
|
+
termId: number;
|
|
93
|
+
termName: string;
|
|
94
|
+
};
|
|
95
|
+
export declare function resolveWordPressRoute(pathname: string): Promise<WpResolvedRoute | null>;
|
|
96
|
+
export declare function getWordPressApiBase(): string;
|
|
97
|
+
export declare function getWordPressBaseUrl(): string;
|
|
98
|
+
export {};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
export async function resolveWordPressRoute(pathname) {
|
|
2
|
+
const resolution = await resolveViaWordPress(pathname);
|
|
3
|
+
if (!resolution.found) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
switch (resolution.kind) {
|
|
7
|
+
case 'postsArchive':
|
|
8
|
+
case 'postTypeArchive': {
|
|
9
|
+
const archive = await getArchive({
|
|
10
|
+
kind: resolution.kind,
|
|
11
|
+
postType: resolution.postType,
|
|
12
|
+
page: resolution.page ?? 1,
|
|
13
|
+
});
|
|
14
|
+
return {
|
|
15
|
+
kind: resolution.kind,
|
|
16
|
+
postType: resolution.postType,
|
|
17
|
+
restBase: resolution.restBase,
|
|
18
|
+
slug: resolution.slug,
|
|
19
|
+
title: resolution.title,
|
|
20
|
+
...archive,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
case 'taxonomyArchive': {
|
|
24
|
+
const archive = await getArchive({
|
|
25
|
+
kind: resolution.kind,
|
|
26
|
+
postType: resolution.postType,
|
|
27
|
+
taxonomy: resolution.taxonomy,
|
|
28
|
+
termId: resolution.termId,
|
|
29
|
+
page: resolution.page ?? 1,
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
kind: 'taxonomyArchive',
|
|
33
|
+
postType: resolution.postType,
|
|
34
|
+
restBase: resolution.restBase,
|
|
35
|
+
slug: resolution.slug,
|
|
36
|
+
title: resolution.title,
|
|
37
|
+
taxonomy: resolution.taxonomy,
|
|
38
|
+
taxonomyRestBase: resolution.taxonomyRestBase,
|
|
39
|
+
termId: resolution.termId,
|
|
40
|
+
termName: resolution.termName,
|
|
41
|
+
...archive,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
case 'search': {
|
|
45
|
+
const archive = await getArchive({
|
|
46
|
+
kind: resolution.kind,
|
|
47
|
+
search: resolution.search,
|
|
48
|
+
page: resolution.page ?? 1,
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
kind: 'search',
|
|
52
|
+
postType: resolution.postType,
|
|
53
|
+
restBase: resolution.restBase,
|
|
54
|
+
slug: resolution.slug,
|
|
55
|
+
title: resolution.title,
|
|
56
|
+
search: resolution.search,
|
|
57
|
+
...archive,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
case 'page':
|
|
61
|
+
case 'single':
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
if (resolution.isPostsPage) {
|
|
65
|
+
const archive = await getArchive({ kind: 'postsArchive', postType: 'post', page: 1 });
|
|
66
|
+
return {
|
|
67
|
+
kind: 'postsArchive',
|
|
68
|
+
postType: 'post',
|
|
69
|
+
restBase: 'posts',
|
|
70
|
+
slug: resolution.slug,
|
|
71
|
+
title: '',
|
|
72
|
+
...archive,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const item = await getById(resolution.restBase, resolution.id);
|
|
76
|
+
if (resolution.kind === 'page') {
|
|
77
|
+
return {
|
|
78
|
+
kind: 'page',
|
|
79
|
+
postType: 'page',
|
|
80
|
+
restBase: 'pages',
|
|
81
|
+
slug: resolution.slug,
|
|
82
|
+
item,
|
|
83
|
+
isFrontPage: resolution.isFrontPage,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
kind: 'single',
|
|
88
|
+
postType: resolution.postType,
|
|
89
|
+
restBase: resolution.restBase,
|
|
90
|
+
slug: resolution.slug,
|
|
91
|
+
item,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export function getWordPressApiBase() {
|
|
95
|
+
const base = getWordPressBaseUrl();
|
|
96
|
+
return `${base}/wp-json/wp/v2`;
|
|
97
|
+
}
|
|
98
|
+
export function getWordPressBaseUrl() {
|
|
99
|
+
return (process.env.VITEWP_PUBLIC_URL ?? process.env.WP_URL ?? 'http://localhost:3000').replace(/\/$/, '');
|
|
100
|
+
}
|
|
101
|
+
async function resolveViaWordPress(pathname) {
|
|
102
|
+
const url = new URL(`${getWordPressBaseUrl()}/wp-json/vitewp/v1/resolve`);
|
|
103
|
+
url.searchParams.set('path', pathname || '/');
|
|
104
|
+
const response = await fetch(url);
|
|
105
|
+
if (response.status === 404) {
|
|
106
|
+
return { found: false, kind: 'notFound' };
|
|
107
|
+
}
|
|
108
|
+
if (!response.ok) {
|
|
109
|
+
throw new Error(`ViteWP route resolution failed: ${response.status} ${response.statusText}`);
|
|
110
|
+
}
|
|
111
|
+
return response.json();
|
|
112
|
+
}
|
|
113
|
+
async function getById(restBase, id) {
|
|
114
|
+
const url = new URL(`${getWordPressApiBase()}/${restBase}/${id}`);
|
|
115
|
+
url.searchParams.set('_embed', '1');
|
|
116
|
+
return getJson(url);
|
|
117
|
+
}
|
|
118
|
+
async function getArchive(params) {
|
|
119
|
+
const url = new URL(`${getWordPressBaseUrl()}/wp-json/vitewp/v1/archive`);
|
|
120
|
+
for (const [key, value] of Object.entries(params)) {
|
|
121
|
+
if (value !== undefined) {
|
|
122
|
+
url.searchParams.set(key, String(value));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return getJson(url);
|
|
126
|
+
}
|
|
127
|
+
async function getJson(url) {
|
|
128
|
+
const response = await fetch(url);
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
throw new Error(`WordPress REST request failed: ${response.status} ${response.statusText}`);
|
|
131
|
+
}
|
|
132
|
+
return response.json();
|
|
133
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type WpPostType = "post" | "page" | "attachment";
|
|
2
|
+
export type WpTaxonomy = "category" | "post_tag";
|
|
3
|
+
export type WpRestBaseByPostType = {
|
|
4
|
+
"post": "posts";
|
|
5
|
+
"page": "pages";
|
|
6
|
+
"attachment": "media";
|
|
7
|
+
};
|
|
8
|
+
export type WpArchiveSlugByPostType = {
|
|
9
|
+
"post": null;
|
|
10
|
+
"page": null;
|
|
11
|
+
"attachment": null;
|
|
12
|
+
};
|
|
13
|
+
export type WpRestBaseByTaxonomy = {
|
|
14
|
+
"category": "categories";
|
|
15
|
+
"post_tag": "tags";
|
|
16
|
+
};
|
|
17
|
+
export interface WpRenderedField {
|
|
18
|
+
rendered: string;
|
|
19
|
+
protected?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface WpContentItem<PostType extends WpPostType = WpPostType> {
|
|
22
|
+
id: number;
|
|
23
|
+
slug: string;
|
|
24
|
+
type: PostType;
|
|
25
|
+
link: string;
|
|
26
|
+
title: WpRenderedField;
|
|
27
|
+
content: WpRenderedField;
|
|
28
|
+
excerpt?: WpRenderedField;
|
|
29
|
+
date?: string;
|
|
30
|
+
modified?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface WpArchiveItem<PostType extends WpPostType = WpPostType> extends WpContentItem<PostType> {
|
|
33
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface WpMenuItem {
|
|
2
|
+
id: number;
|
|
3
|
+
parent: number;
|
|
4
|
+
title: string;
|
|
5
|
+
url: string;
|
|
6
|
+
target: string;
|
|
7
|
+
classes: string[];
|
|
8
|
+
object: string;
|
|
9
|
+
objectId: number;
|
|
10
|
+
type: string;
|
|
11
|
+
}
|
|
12
|
+
export interface WpMenu {
|
|
13
|
+
id: number;
|
|
14
|
+
slug: string;
|
|
15
|
+
name: string;
|
|
16
|
+
items: WpMenuItem[];
|
|
17
|
+
}
|
|
18
|
+
export interface WpMenusPayload {
|
|
19
|
+
locations: Record<string, number>;
|
|
20
|
+
menus: WpMenu[];
|
|
21
|
+
}
|
|
22
|
+
export declare function getMenus(): Promise<WpMenusPayload>;
|
|
23
|
+
export declare function getMenuByLocation(location: string): Promise<WpMenu | null>;
|
|
24
|
+
export declare function getMenuBySlug(slug: string): Promise<WpMenu | null>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getWordPressBaseUrl } from './client.js';
|
|
2
|
+
export async function getMenus() {
|
|
3
|
+
const response = await fetch(`${getWordPressBaseUrl()}/wp-json/vitewp/v1/menus`);
|
|
4
|
+
if (!response.ok) {
|
|
5
|
+
throw new Error(`Could not fetch WordPress menus: ${response.status} ${response.statusText}`);
|
|
6
|
+
}
|
|
7
|
+
return response.json();
|
|
8
|
+
}
|
|
9
|
+
export async function getMenuByLocation(location) {
|
|
10
|
+
const payload = await getMenus();
|
|
11
|
+
const menuId = payload.locations[location];
|
|
12
|
+
if (!menuId) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return payload.menus.find((menu) => menu.id === menuId) ?? null;
|
|
16
|
+
}
|
|
17
|
+
export async function getMenuBySlug(slug) {
|
|
18
|
+
const payload = await getMenus();
|
|
19
|
+
return payload.menus.find((menu) => menu.slug === slug) ?? null;
|
|
20
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from 'astro/zod';
|
|
2
|
+
export declare const wpRenderedFieldSchema: z.ZodObject<{
|
|
3
|
+
rendered: z.ZodString;
|
|
4
|
+
protected: z.ZodOptional<z.ZodBoolean>;
|
|
5
|
+
}, z.core.$loose>;
|
|
6
|
+
export declare const wpContentItemSchema: z.ZodObject<{
|
|
7
|
+
id: z.ZodNumber;
|
|
8
|
+
slug: z.ZodString;
|
|
9
|
+
type: z.ZodString;
|
|
10
|
+
link: z.ZodString;
|
|
11
|
+
title: z.ZodObject<{
|
|
12
|
+
rendered: z.ZodString;
|
|
13
|
+
protected: z.ZodOptional<z.ZodBoolean>;
|
|
14
|
+
}, z.core.$loose>;
|
|
15
|
+
content: z.ZodObject<{
|
|
16
|
+
rendered: z.ZodString;
|
|
17
|
+
protected: z.ZodOptional<z.ZodBoolean>;
|
|
18
|
+
}, z.core.$loose>;
|
|
19
|
+
excerpt: z.ZodOptional<z.ZodObject<{
|
|
20
|
+
rendered: z.ZodString;
|
|
21
|
+
protected: z.ZodOptional<z.ZodBoolean>;
|
|
22
|
+
}, z.core.$loose>>;
|
|
23
|
+
date: z.ZodOptional<z.ZodString>;
|
|
24
|
+
modified: z.ZodOptional<z.ZodString>;
|
|
25
|
+
}, z.core.$loose>;
|
|
26
|
+
export declare const wpResolvedRouteSchema: z.ZodObject<{
|
|
27
|
+
kind: z.ZodString;
|
|
28
|
+
postType: z.ZodString;
|
|
29
|
+
restBase: z.ZodString;
|
|
30
|
+
slug: z.ZodString;
|
|
31
|
+
}, z.core.$loose>;
|
|
32
|
+
export declare const wpMenuItemSchema: z.ZodObject<{
|
|
33
|
+
id: z.ZodNumber;
|
|
34
|
+
parent: z.ZodNumber;
|
|
35
|
+
title: z.ZodString;
|
|
36
|
+
url: z.ZodString;
|
|
37
|
+
target: z.ZodString;
|
|
38
|
+
classes: z.ZodArray<z.ZodString>;
|
|
39
|
+
object: z.ZodString;
|
|
40
|
+
objectId: z.ZodNumber;
|
|
41
|
+
type: z.ZodString;
|
|
42
|
+
}, z.core.$loose>;
|
|
43
|
+
export declare const wpMenuSchema: z.ZodObject<{
|
|
44
|
+
id: z.ZodNumber;
|
|
45
|
+
slug: z.ZodString;
|
|
46
|
+
name: z.ZodString;
|
|
47
|
+
items: z.ZodArray<z.ZodObject<{
|
|
48
|
+
id: z.ZodNumber;
|
|
49
|
+
parent: z.ZodNumber;
|
|
50
|
+
title: z.ZodString;
|
|
51
|
+
url: z.ZodString;
|
|
52
|
+
target: z.ZodString;
|
|
53
|
+
classes: z.ZodArray<z.ZodString>;
|
|
54
|
+
object: z.ZodString;
|
|
55
|
+
objectId: z.ZodNumber;
|
|
56
|
+
type: z.ZodString;
|
|
57
|
+
}, z.core.$loose>>;
|
|
58
|
+
}, z.core.$loose>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from 'astro/zod';
|
|
2
|
+
export const wpRenderedFieldSchema = z.looseObject({
|
|
3
|
+
rendered: z.string(),
|
|
4
|
+
protected: z.boolean().optional(),
|
|
5
|
+
});
|
|
6
|
+
export const wpContentItemSchema = z.looseObject({
|
|
7
|
+
id: z.number(),
|
|
8
|
+
slug: z.string(),
|
|
9
|
+
type: z.string(),
|
|
10
|
+
link: z.string(),
|
|
11
|
+
title: wpRenderedFieldSchema,
|
|
12
|
+
content: wpRenderedFieldSchema,
|
|
13
|
+
excerpt: wpRenderedFieldSchema.optional(),
|
|
14
|
+
date: z.string().optional(),
|
|
15
|
+
modified: z.string().optional(),
|
|
16
|
+
});
|
|
17
|
+
export const wpResolvedRouteSchema = z.looseObject({
|
|
18
|
+
kind: z.string(),
|
|
19
|
+
postType: z.string(),
|
|
20
|
+
restBase: z.string(),
|
|
21
|
+
slug: z.string(),
|
|
22
|
+
});
|
|
23
|
+
export const wpMenuItemSchema = z.looseObject({
|
|
24
|
+
id: z.number(),
|
|
25
|
+
parent: z.number(),
|
|
26
|
+
title: z.string(),
|
|
27
|
+
url: z.string(),
|
|
28
|
+
target: z.string(),
|
|
29
|
+
classes: z.array(z.string()),
|
|
30
|
+
object: z.string(),
|
|
31
|
+
objectId: z.number(),
|
|
32
|
+
type: z.string(),
|
|
33
|
+
});
|
|
34
|
+
export const wpMenuSchema = z.looseObject({
|
|
35
|
+
id: z.number(),
|
|
36
|
+
slug: z.string(),
|
|
37
|
+
name: z.string(),
|
|
38
|
+
items: z.array(wpMenuItemSchema),
|
|
39
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { WpContentItem, WpResolvedRoute } from './client.js';
|
|
2
|
+
export interface TemplateContext {
|
|
3
|
+
route: WpResolvedRoute;
|
|
4
|
+
title: string;
|
|
5
|
+
content: string;
|
|
6
|
+
excerpt: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
postType: string;
|
|
9
|
+
items: WpContentItem[];
|
|
10
|
+
page: number;
|
|
11
|
+
perPage: number;
|
|
12
|
+
total: number;
|
|
13
|
+
totalPages: number;
|
|
14
|
+
search?: string;
|
|
15
|
+
taxonomy?: string;
|
|
16
|
+
termName?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function createTemplateContext(route: WpResolvedRoute): TemplateContext;
|
|
19
|
+
export declare function templateCandidates(route: WpResolvedRoute): string[];
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export function createTemplateContext(route) {
|
|
2
|
+
switch (route.kind) {
|
|
3
|
+
case 'postsArchive':
|
|
4
|
+
case 'postTypeArchive':
|
|
5
|
+
case 'search':
|
|
6
|
+
return {
|
|
7
|
+
route,
|
|
8
|
+
title: route.title,
|
|
9
|
+
content: '',
|
|
10
|
+
excerpt: '',
|
|
11
|
+
slug: route.slug,
|
|
12
|
+
postType: route.postType,
|
|
13
|
+
items: route.items,
|
|
14
|
+
page: route.page,
|
|
15
|
+
perPage: route.perPage,
|
|
16
|
+
total: route.total,
|
|
17
|
+
totalPages: route.totalPages,
|
|
18
|
+
search: route.search,
|
|
19
|
+
};
|
|
20
|
+
case 'taxonomyArchive':
|
|
21
|
+
return {
|
|
22
|
+
route,
|
|
23
|
+
title: route.title,
|
|
24
|
+
content: '',
|
|
25
|
+
excerpt: '',
|
|
26
|
+
slug: route.slug,
|
|
27
|
+
postType: route.postType,
|
|
28
|
+
items: route.items,
|
|
29
|
+
page: route.page,
|
|
30
|
+
perPage: route.perPage,
|
|
31
|
+
total: route.total,
|
|
32
|
+
totalPages: route.totalPages,
|
|
33
|
+
taxonomy: route.taxonomy,
|
|
34
|
+
termName: route.termName,
|
|
35
|
+
};
|
|
36
|
+
case 'page':
|
|
37
|
+
case 'single':
|
|
38
|
+
return {
|
|
39
|
+
route,
|
|
40
|
+
title: route.item.title.rendered,
|
|
41
|
+
content: route.item.content.rendered,
|
|
42
|
+
excerpt: route.item.excerpt?.rendered ?? '',
|
|
43
|
+
slug: route.slug,
|
|
44
|
+
postType: route.postType,
|
|
45
|
+
items: [],
|
|
46
|
+
page: 1,
|
|
47
|
+
perPage: 0,
|
|
48
|
+
total: 0,
|
|
49
|
+
totalPages: 0,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function templateCandidates(route) {
|
|
54
|
+
if (route.kind === 'search') {
|
|
55
|
+
return ['search.astro', 'posts/archive.astro'];
|
|
56
|
+
}
|
|
57
|
+
if (route.kind === 'taxonomyArchive') {
|
|
58
|
+
return [
|
|
59
|
+
`taxonomies/${route.taxonomy}-${route.slug}.astro`,
|
|
60
|
+
`taxonomies/${route.taxonomy}.astro`,
|
|
61
|
+
'taxonomies/taxonomy-[taxonomy].astro',
|
|
62
|
+
'posts/archive.astro',
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
if (route.kind === 'postsArchive') {
|
|
66
|
+
return ['posts/archive.astro'];
|
|
67
|
+
}
|
|
68
|
+
if (route.kind === 'postTypeArchive') {
|
|
69
|
+
return [
|
|
70
|
+
`post-types/${route.postType}/archive.astro`,
|
|
71
|
+
'posts/archive.astro',
|
|
72
|
+
];
|
|
73
|
+
}
|
|
74
|
+
if (route.kind === 'page') {
|
|
75
|
+
return [
|
|
76
|
+
...(route.isFrontPage ? ['pages/front-page.astro'] : []),
|
|
77
|
+
`pages/page-${route.slug}.astro`,
|
|
78
|
+
'pages/default.astro',
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
return [
|
|
82
|
+
`post-types/${route.postType}/single-${route.slug}.astro`,
|
|
83
|
+
`post-types/${route.postType}/single.astro`,
|
|
84
|
+
...(route.postType === 'post' ? [] : ['posts/single.astro']),
|
|
85
|
+
`posts/single-${route.slug}.astro`,
|
|
86
|
+
'posts/single.astro',
|
|
87
|
+
];
|
|
88
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vite-wp",
|
|
3
|
+
"private": false,
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"vitewp": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./astro": {
|
|
15
|
+
"types": "./dist/astro.d.ts",
|
|
16
|
+
"import": "./dist/astro.js"
|
|
17
|
+
},
|
|
18
|
+
"./content": {
|
|
19
|
+
"types": "./dist/content.d.ts",
|
|
20
|
+
"import": "./dist/content.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"dev": "tsx src/cli.ts dev",
|
|
25
|
+
"doctor": "tsx src/cli.ts doctor",
|
|
26
|
+
"build": "rm -rf dist && tsc",
|
|
27
|
+
"prepack": "npm run build",
|
|
28
|
+
"pack:dry": "npm pack --dry-run",
|
|
29
|
+
"publish:npm": "npm publish --access public",
|
|
30
|
+
"preview": "node dist/cli.js doctor",
|
|
31
|
+
"astro:dev": "astro dev",
|
|
32
|
+
"astro:check": "astro check",
|
|
33
|
+
"types": "tsx src/cli.ts types",
|
|
34
|
+
"smoke": "tsx src/cli.ts smoke"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"astro": "^7.0.6",
|
|
38
|
+
"vite": "^8.1.1"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@astrojs/check": "^0.9.9",
|
|
42
|
+
"@types/node": "^24.10.2",
|
|
43
|
+
"tsx": "^4.21.0",
|
|
44
|
+
"typescript": "~6.0.2"
|
|
45
|
+
},
|
|
46
|
+
"description": "Astro-first WordPress development framework with a Composer-managed local WordPress runtime.",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"author": "Didair",
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/didair/vitewp.git"
|
|
52
|
+
},
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/didair/vitewp/issues"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://github.com/didair/vitewp#readme",
|
|
57
|
+
"keywords": [
|
|
58
|
+
"wordpress",
|
|
59
|
+
"astro",
|
|
60
|
+
"vite",
|
|
61
|
+
"headless",
|
|
62
|
+
"php",
|
|
63
|
+
"composer"
|
|
64
|
+
],
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=20"
|
|
67
|
+
},
|
|
68
|
+
"files": [
|
|
69
|
+
"dist",
|
|
70
|
+
"starter",
|
|
71
|
+
"README.md",
|
|
72
|
+
"LICENSE"
|
|
73
|
+
],
|
|
74
|
+
"types": "./dist/index.d.ts",
|
|
75
|
+
"publishConfig": {
|
|
76
|
+
"access": "public"
|
|
77
|
+
}
|
|
78
|
+
}
|