wp-astrojs-integration 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/README.md +466 -0
- package/dist/client/auth.d.ts +11 -0
- package/dist/client/auth.js +7 -0
- package/dist/client/categories.d.ts +39 -0
- package/dist/client/categories.js +69 -0
- package/dist/client/index.d.ts +102 -0
- package/dist/client/index.js +164 -0
- package/dist/client/media.d.ts +47 -0
- package/dist/client/media.js +82 -0
- package/dist/client/pages.d.ts +39 -0
- package/dist/client/pages.js +69 -0
- package/dist/client/posts.d.ts +39 -0
- package/dist/client/posts.js +69 -0
- package/dist/client/settings.d.ts +13 -0
- package/dist/client/settings.js +19 -0
- package/dist/client/tags.d.ts +39 -0
- package/dist/client/tags.js +69 -0
- package/dist/client/types.d.ts +166 -0
- package/dist/client/types.js +33 -0
- package/dist/client/users.d.ts +42 -0
- package/dist/client/users.js +74 -0
- package/dist/components/index.d.ts +7 -0
- package/dist/components/index.js +8 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +19 -0
- package/dist/loaders/index.d.ts +9 -0
- package/dist/loaders/index.js +10 -0
- package/dist/loaders/live.d.ts +104 -0
- package/dist/loaders/live.js +253 -0
- package/dist/loaders/static.d.ts +77 -0
- package/dist/loaders/static.js +193 -0
- package/dist/loaders/types.d.ts +59 -0
- package/dist/loaders/types.js +4 -0
- package/dist/schemas/index.d.ts +992 -0
- package/dist/schemas/index.js +199 -0
- package/package.json +60 -0
- package/src/components/WPContent.astro +48 -0
- package/src/components/WPImage.astro +106 -0
- package/src/components/index.ts +9 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { z } from 'astro/zod';
|
|
2
|
+
/**
|
|
3
|
+
* Base schema shared by all WordPress content types
|
|
4
|
+
* Can be extended with custom fields using .extend() or .merge()
|
|
5
|
+
*/
|
|
6
|
+
export const baseWordPressSchema = z.object({
|
|
7
|
+
id: z.number(),
|
|
8
|
+
date: z.string(),
|
|
9
|
+
date_gmt: z.string(),
|
|
10
|
+
guid: z.object({
|
|
11
|
+
rendered: z.string(),
|
|
12
|
+
}),
|
|
13
|
+
modified: z.string(),
|
|
14
|
+
modified_gmt: z.string(),
|
|
15
|
+
slug: z.string(),
|
|
16
|
+
status: z.string(),
|
|
17
|
+
type: z.string(),
|
|
18
|
+
link: z.string().url(),
|
|
19
|
+
title: z.object({
|
|
20
|
+
rendered: z.string(),
|
|
21
|
+
}),
|
|
22
|
+
author: z.number(),
|
|
23
|
+
meta: z.union([z.record(z.any()), z.array(z.any())]).optional(),
|
|
24
|
+
_links: z.any(),
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* Schema for content types (posts and pages)
|
|
28
|
+
* Extend this for custom post types with content fields
|
|
29
|
+
*/
|
|
30
|
+
export const contentWordPressSchema = baseWordPressSchema.extend({
|
|
31
|
+
content: z.object({
|
|
32
|
+
rendered: z.string(),
|
|
33
|
+
protected: z.boolean(),
|
|
34
|
+
}),
|
|
35
|
+
excerpt: z.object({
|
|
36
|
+
rendered: z.string(),
|
|
37
|
+
protected: z.boolean(),
|
|
38
|
+
}),
|
|
39
|
+
featured_media: z.number().optional(),
|
|
40
|
+
comment_status: z.string(),
|
|
41
|
+
ping_status: z.string(),
|
|
42
|
+
template: z.string(),
|
|
43
|
+
acf: z.union([z.record(z.any()), z.array(z.any())]).optional(),
|
|
44
|
+
_embedded: z.any().optional(),
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* Default schema for WordPress posts
|
|
48
|
+
* Extend with .extend() to add custom ACF fields or taxonomies
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const customPostSchema = postSchema.extend({
|
|
52
|
+
* acf: z.object({
|
|
53
|
+
* custom_field: z.string().optional(),
|
|
54
|
+
* }).optional(),
|
|
55
|
+
* });
|
|
56
|
+
*/
|
|
57
|
+
export const postSchema = contentWordPressSchema.extend({
|
|
58
|
+
sticky: z.boolean(),
|
|
59
|
+
format: z.string(),
|
|
60
|
+
categories: z.array(z.number()).default([]),
|
|
61
|
+
tags: z.array(z.number()).default([]),
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Default schema for WordPress pages
|
|
65
|
+
* Extend with .extend() to add custom ACF fields
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* const customPageSchema = pageSchema.extend({
|
|
69
|
+
* acf: z.object({
|
|
70
|
+
* hero_image: z.number().optional(),
|
|
71
|
+
* }).optional(),
|
|
72
|
+
* });
|
|
73
|
+
*/
|
|
74
|
+
export const pageSchema = contentWordPressSchema.extend({
|
|
75
|
+
parent: z.number().default(0),
|
|
76
|
+
menu_order: z.number().default(0),
|
|
77
|
+
class_list: z.array(z.string()).default([]),
|
|
78
|
+
});
|
|
79
|
+
/**
|
|
80
|
+
* Schema for WordPress media items
|
|
81
|
+
*/
|
|
82
|
+
export const mediaSchema = baseWordPressSchema.extend({
|
|
83
|
+
comment_status: z.string(),
|
|
84
|
+
ping_status: z.string(),
|
|
85
|
+
alt_text: z.string(),
|
|
86
|
+
caption: z.object({
|
|
87
|
+
rendered: z.string(),
|
|
88
|
+
}),
|
|
89
|
+
description: z.object({
|
|
90
|
+
rendered: z.string(),
|
|
91
|
+
}),
|
|
92
|
+
media_type: z.string(),
|
|
93
|
+
mime_type: z.string(),
|
|
94
|
+
media_details: z.object({
|
|
95
|
+
width: z.number(),
|
|
96
|
+
height: z.number(),
|
|
97
|
+
file: z.string(),
|
|
98
|
+
filesize: z.number().optional(),
|
|
99
|
+
sizes: z.record(z.object({
|
|
100
|
+
file: z.string(),
|
|
101
|
+
width: z.number(),
|
|
102
|
+
height: z.number(),
|
|
103
|
+
filesize: z.number().optional(),
|
|
104
|
+
mime_type: z.string(),
|
|
105
|
+
source_url: z.string(),
|
|
106
|
+
})),
|
|
107
|
+
image_meta: z.any(),
|
|
108
|
+
}),
|
|
109
|
+
source_url: z.string(),
|
|
110
|
+
});
|
|
111
|
+
/**
|
|
112
|
+
* Schema for WordPress categories and taxonomies
|
|
113
|
+
* Extend with .extend() to add custom ACF fields to taxonomies
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* const customCategorySchema = categorySchema.extend({
|
|
117
|
+
* acf: z.object({
|
|
118
|
+
* color: z.string().optional(),
|
|
119
|
+
* }).optional(),
|
|
120
|
+
* });
|
|
121
|
+
*/
|
|
122
|
+
export const categorySchema = z.object({
|
|
123
|
+
id: z.number(),
|
|
124
|
+
count: z.number(),
|
|
125
|
+
description: z.string(),
|
|
126
|
+
link: z.string().url(),
|
|
127
|
+
name: z.string(),
|
|
128
|
+
slug: z.string(),
|
|
129
|
+
taxonomy: z.string(),
|
|
130
|
+
parent: z.number().default(0),
|
|
131
|
+
meta: z.array(z.any()).or(z.record(z.any())),
|
|
132
|
+
acf: z.union([z.record(z.any()), z.array(z.any())]).optional(),
|
|
133
|
+
_embedded: z.any().optional(),
|
|
134
|
+
_links: z.any(),
|
|
135
|
+
});
|
|
136
|
+
/**
|
|
137
|
+
* Schema for WordPress embedded media (used in _embedded field)
|
|
138
|
+
*/
|
|
139
|
+
export const embeddedMediaSchema = z.object({
|
|
140
|
+
id: z.number(),
|
|
141
|
+
date: z.string(),
|
|
142
|
+
slug: z.string(),
|
|
143
|
+
type: z.string(),
|
|
144
|
+
link: z.string(),
|
|
145
|
+
title: z.object({
|
|
146
|
+
rendered: z.string(),
|
|
147
|
+
}),
|
|
148
|
+
author: z.number(),
|
|
149
|
+
featured_media: z.number(),
|
|
150
|
+
caption: z.object({
|
|
151
|
+
rendered: z.string(),
|
|
152
|
+
}),
|
|
153
|
+
alt_text: z.string(),
|
|
154
|
+
media_type: z.string(),
|
|
155
|
+
mime_type: z.string(),
|
|
156
|
+
media_details: z.object({
|
|
157
|
+
width: z.number(),
|
|
158
|
+
height: z.number(),
|
|
159
|
+
file: z.string(),
|
|
160
|
+
filesize: z.number().optional(),
|
|
161
|
+
sizes: z.record(z.object({
|
|
162
|
+
file: z.string(),
|
|
163
|
+
width: z.number(),
|
|
164
|
+
height: z.number(),
|
|
165
|
+
filesize: z.number().optional(),
|
|
166
|
+
mime_type: z.string(),
|
|
167
|
+
source_url: z.string(),
|
|
168
|
+
})),
|
|
169
|
+
image_meta: z.any().optional(),
|
|
170
|
+
}),
|
|
171
|
+
source_url: z.string(),
|
|
172
|
+
acf: z.any().optional(),
|
|
173
|
+
_links: z.any().optional(),
|
|
174
|
+
});
|
|
175
|
+
/**
|
|
176
|
+
* Schema for WordPress site settings (requires authentication)
|
|
177
|
+
*/
|
|
178
|
+
export const settingsSchema = z.object({
|
|
179
|
+
title: z.string(),
|
|
180
|
+
description: z.string(),
|
|
181
|
+
url: z.string().url(),
|
|
182
|
+
email: z.string().email().optional(),
|
|
183
|
+
timezone: z.string(),
|
|
184
|
+
date_format: z.string(),
|
|
185
|
+
time_format: z.string(),
|
|
186
|
+
start_of_week: z.number(),
|
|
187
|
+
language: z.string(),
|
|
188
|
+
use_smilies: z.boolean(),
|
|
189
|
+
default_category: z.number(),
|
|
190
|
+
default_post_format: z.string(),
|
|
191
|
+
posts_per_page: z.number(),
|
|
192
|
+
show_on_front: z.string(),
|
|
193
|
+
page_on_front: z.number(),
|
|
194
|
+
page_for_posts: z.number(),
|
|
195
|
+
default_ping_status: z.string(),
|
|
196
|
+
default_comment_status: z.string(),
|
|
197
|
+
site_logo: z.number().nullable().optional(),
|
|
198
|
+
site_icon: z.number().nullable().optional(),
|
|
199
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wp-astrojs-integration",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Fast and better WordPress integration for Astro.js with live loaders, client API, and Gutenberg block support",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./components": {
|
|
14
|
+
"import": "./src/components/index.ts"
|
|
15
|
+
},
|
|
16
|
+
"./components/WPImage.astro": {
|
|
17
|
+
"import": "./src/components/WPImage.astro"
|
|
18
|
+
},
|
|
19
|
+
"./components/WPContent.astro": {
|
|
20
|
+
"import": "./src/components/WPContent.astro"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"src/components"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc",
|
|
29
|
+
"dev": "tsc --watch",
|
|
30
|
+
"prepublishOnly": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"astro",
|
|
34
|
+
"wordpress",
|
|
35
|
+
"cms",
|
|
36
|
+
"gutenberg",
|
|
37
|
+
"headless",
|
|
38
|
+
"astro-integration",
|
|
39
|
+
"wp-api"
|
|
40
|
+
],
|
|
41
|
+
"author": "juvojustin",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/JUVOJustin/astrojs-wp-integration.git"
|
|
45
|
+
},
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/JUVOJustin/astrojs-wp-integration/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/JUVOJustin/astrojs-wp-integration#readme",
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"astro": "^5.0.0"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"astro": "^5.16.6"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"typescript": "^5.7.2"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* WPContent component for rendering WordPress Gutenberg content
|
|
4
|
+
* Automatically loads block styles from WordPress site
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Dynamically loads Gutenberg block CSS from WordPress
|
|
8
|
+
* - Supports both posts and pages with Gutenberg content
|
|
9
|
+
* - Handles embedded media and custom blocks
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
/** Rendered HTML content from WordPress */
|
|
14
|
+
content: string;
|
|
15
|
+
/** WordPress base URL for loading block styles */
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
/** Additional CSS classes to apply */
|
|
18
|
+
class?: string;
|
|
19
|
+
/** Whether to load block styles (default: true) */
|
|
20
|
+
loadBlockStyles?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const {
|
|
24
|
+
content,
|
|
25
|
+
baseUrl,
|
|
26
|
+
class: className = '',
|
|
27
|
+
loadBlockStyles = true,
|
|
28
|
+
} = Astro.props;
|
|
29
|
+
|
|
30
|
+
// Build the block styles URL
|
|
31
|
+
const blockStylesUrl = loadBlockStyles
|
|
32
|
+
? `${baseUrl}/wp-includes/css/dist/block-library/style.min.css`
|
|
33
|
+
: null;
|
|
34
|
+
|
|
35
|
+
// Optional: Load theme styles for blocks
|
|
36
|
+
const themeBlockStylesUrl = loadBlockStyles
|
|
37
|
+
? `${baseUrl}/wp-includes/css/dist/block-library/theme.min.css`
|
|
38
|
+
: null;
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
{loadBlockStyles && blockStylesUrl && (
|
|
42
|
+
<>
|
|
43
|
+
<link rel="stylesheet" href={blockStylesUrl} />
|
|
44
|
+
{themeBlockStylesUrl && <link rel="stylesheet" href={themeBlockStylesUrl} />}
|
|
45
|
+
</>
|
|
46
|
+
)}
|
|
47
|
+
|
|
48
|
+
<div class:list={['wp-block-content', className]} set:html={content} />
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { WordPressMedia, WordPressEmbeddedMedia } from '../schemas';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Props for the WPImage component.
|
|
6
|
+
* Accepts either a mediaId for fetching, or pre-loaded media data from embedded responses.
|
|
7
|
+
*/
|
|
8
|
+
interface Props {
|
|
9
|
+
/** Media ID for fetching from WordPress API */
|
|
10
|
+
mediaId?: number;
|
|
11
|
+
/** Pre-loaded media data from _embed=true responses */
|
|
12
|
+
media?: WordPressMedia | WordPressEmbeddedMedia;
|
|
13
|
+
/** WordPress base URL (required if using mediaId) */
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
class?: string;
|
|
16
|
+
loading?: 'lazy' | 'eager';
|
|
17
|
+
decoding?: 'async' | 'auto' | 'sync';
|
|
18
|
+
width?: number;
|
|
19
|
+
height?: number;
|
|
20
|
+
sizes?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const {
|
|
24
|
+
mediaId,
|
|
25
|
+
media: providedMedia,
|
|
26
|
+
baseUrl,
|
|
27
|
+
class: className = '',
|
|
28
|
+
loading = 'lazy',
|
|
29
|
+
decoding = 'async',
|
|
30
|
+
width: customWidth,
|
|
31
|
+
height: customHeight,
|
|
32
|
+
sizes = 'auto',
|
|
33
|
+
} = Astro.props;
|
|
34
|
+
|
|
35
|
+
let media: WordPressMedia | WordPressEmbeddedMedia | undefined;
|
|
36
|
+
|
|
37
|
+
if (providedMedia) {
|
|
38
|
+
media = providedMedia;
|
|
39
|
+
} else if (mediaId && baseUrl) {
|
|
40
|
+
try {
|
|
41
|
+
const url = new URL(`${baseUrl}/index.php?rest_route=/wp/v2/media/${mediaId}`);
|
|
42
|
+
const response = await fetch(url.toString());
|
|
43
|
+
if (response.ok) {
|
|
44
|
+
media = await response.json();
|
|
45
|
+
}
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error(`Failed to fetch media ${mediaId}:`, error);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!media) {
|
|
52
|
+
console.error('WPImage: Either (mediaId + baseUrl) or media prop must be provided');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Size data structure from WordPress media_details.sizes */
|
|
57
|
+
type MediaSize = {
|
|
58
|
+
file: string;
|
|
59
|
+
width: number;
|
|
60
|
+
height: number;
|
|
61
|
+
filesize?: number;
|
|
62
|
+
mime_type: string;
|
|
63
|
+
source_url: string;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Generates srcset string from WordPress media sizes for responsive images.
|
|
68
|
+
*/
|
|
69
|
+
function generateSrcset(media: WordPressMedia | WordPressEmbeddedMedia): string {
|
|
70
|
+
if (!media.media_details?.sizes) {
|
|
71
|
+
return '';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const srcsetItems: string[] = [];
|
|
75
|
+
const sizes = media.media_details.sizes as Record<string, MediaSize>;
|
|
76
|
+
|
|
77
|
+
Object.entries(sizes).forEach(([_sizeName, sizeData]) => {
|
|
78
|
+
srcsetItems.push(`${sizeData.source_url} ${sizeData.width}w`);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
srcsetItems.sort((a, b) => {
|
|
82
|
+
const widthA = parseInt(a.split(' ')[1]);
|
|
83
|
+
const widthB = parseInt(b.split(' ')[1]);
|
|
84
|
+
return widthA - widthB;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
return srcsetItems.join(', ');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const alt = media.alt_text || media.title?.rendered || '';
|
|
91
|
+
const width = customWidth || media.media_details?.width;
|
|
92
|
+
const height = customHeight || media.media_details?.height;
|
|
93
|
+
const srcset = generateSrcset(media);
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
<img
|
|
97
|
+
src={media.source_url}
|
|
98
|
+
srcset={srcset || undefined}
|
|
99
|
+
alt={alt}
|
|
100
|
+
width={width}
|
|
101
|
+
height={height}
|
|
102
|
+
loading={loading}
|
|
103
|
+
decoding={decoding}
|
|
104
|
+
sizes={sizes}
|
|
105
|
+
class={className}
|
|
106
|
+
/>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress Astro.js Integration Components
|
|
3
|
+
*
|
|
4
|
+
* Export Astro components for WordPress content rendering
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Re-export components for named imports
|
|
8
|
+
export { default as WPImage } from './WPImage.astro';
|
|
9
|
+
export { default as WPContent } from './WPContent.astro';
|