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
package/README.md
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
# WordPress Astro.js Integration
|
|
2
|
+
|
|
3
|
+
Fast and better WordPress integration for Astro.js with live loaders, static loaders, client API, and full Gutenberg block support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Live Loaders**: Real-time data fetching from WordPress REST API (server-side rendering)
|
|
8
|
+
- **Static Loaders**: Build-time data fetching for static site generation
|
|
9
|
+
- **WordPress Client**: Direct runtime API access for dynamic content
|
|
10
|
+
- **Gutenberg Support**: Automatic block styles loading for proper rendering
|
|
11
|
+
- **TypeScript First**: Fully typed with extensible schemas
|
|
12
|
+
- **Easy Extension**: Simple API for adding custom ACF fields, post types, and taxonomies
|
|
13
|
+
- **Optimized Images**: Responsive image component with srcset support
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install wp-astrojs-integration
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
### Option 1: Live Collections (Server-Side Rendering)
|
|
24
|
+
|
|
25
|
+
Use live loaders for SSR or when you need real-time data:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// src/live.config.ts
|
|
29
|
+
import { defineLiveCollection } from 'astro:content';
|
|
30
|
+
import {
|
|
31
|
+
wordPressPostLoader,
|
|
32
|
+
wordPressPageLoader,
|
|
33
|
+
wordPressCategoryLoader,
|
|
34
|
+
postSchema,
|
|
35
|
+
pageSchema,
|
|
36
|
+
categorySchema,
|
|
37
|
+
} from 'wp-astrojs-integration';
|
|
38
|
+
|
|
39
|
+
const WORDPRESS_BASE_URL = import.meta.env.PUBLIC_WORDPRESS_BASE_URL;
|
|
40
|
+
|
|
41
|
+
const posts = defineLiveCollection({
|
|
42
|
+
loader: wordPressPostLoader({ baseUrl: WORDPRESS_BASE_URL }),
|
|
43
|
+
schema: postSchema,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const pages = defineLiveCollection({
|
|
47
|
+
loader: wordPressPageLoader({ baseUrl: WORDPRESS_BASE_URL }),
|
|
48
|
+
schema: pageSchema,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const categories = defineLiveCollection({
|
|
52
|
+
loader: wordPressCategoryLoader({ baseUrl: WORDPRESS_BASE_URL }),
|
|
53
|
+
schema: categorySchema,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const collections = { posts, pages, categories };
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Option 2: Static Collections (Build-Time Only)
|
|
60
|
+
|
|
61
|
+
Use static loaders for fully static site generation:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// src/content.config.ts
|
|
65
|
+
import { defineCollection } from 'astro:content';
|
|
66
|
+
import {
|
|
67
|
+
wordPressPostStaticLoader,
|
|
68
|
+
wordPressPageStaticLoader,
|
|
69
|
+
wordPressCategoryStaticLoader,
|
|
70
|
+
postSchema,
|
|
71
|
+
pageSchema,
|
|
72
|
+
categorySchema,
|
|
73
|
+
} from 'wp-astrojs-integration';
|
|
74
|
+
|
|
75
|
+
const WORDPRESS_BASE_URL = import.meta.env.PUBLIC_WORDPRESS_BASE_URL;
|
|
76
|
+
|
|
77
|
+
const posts = defineCollection({
|
|
78
|
+
loader: wordPressPostStaticLoader({ baseUrl: WORDPRESS_BASE_URL }),
|
|
79
|
+
schema: postSchema,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const pages = defineCollection({
|
|
83
|
+
loader: wordPressPageStaticLoader({ baseUrl: WORDPRESS_BASE_URL }),
|
|
84
|
+
schema: pageSchema,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const categories = defineCollection({
|
|
88
|
+
loader: wordPressCategoryStaticLoader({ baseUrl: WORDPRESS_BASE_URL }),
|
|
89
|
+
schema: categorySchema,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export const collections = { posts, pages, categories };
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Environment Variable
|
|
96
|
+
|
|
97
|
+
Create `.env`:
|
|
98
|
+
|
|
99
|
+
```env
|
|
100
|
+
PUBLIC_WORDPRESS_BASE_URL=https://your-wordpress-site.com
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Using in Pages
|
|
104
|
+
|
|
105
|
+
```astro
|
|
106
|
+
---
|
|
107
|
+
// For live collections
|
|
108
|
+
import { getLiveEntry } from 'astro:content';
|
|
109
|
+
import WPContent from 'wp-astrojs-integration/components/WPContent.astro';
|
|
110
|
+
import WPImage from 'wp-astrojs-integration/components/WPImage.astro';
|
|
111
|
+
|
|
112
|
+
const { slug } = Astro.params;
|
|
113
|
+
const { entry: post } = await getLiveEntry('posts', { slug });
|
|
114
|
+
|
|
115
|
+
const featuredMedia = post.data._embedded?.['wp:featuredmedia']?.[0];
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
<article>
|
|
119
|
+
{featuredMedia && (
|
|
120
|
+
<WPImage media={featuredMedia} loading="eager" />
|
|
121
|
+
)}
|
|
122
|
+
|
|
123
|
+
<h1 set:html={post.data.title.rendered} />
|
|
124
|
+
|
|
125
|
+
<WPContent
|
|
126
|
+
content={post.data.content.rendered}
|
|
127
|
+
baseUrl={import.meta.env.PUBLIC_WORDPRESS_BASE_URL}
|
|
128
|
+
/>
|
|
129
|
+
</article>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```astro
|
|
133
|
+
---
|
|
134
|
+
// For static collections
|
|
135
|
+
import { getCollection, getEntry } from 'astro:content';
|
|
136
|
+
import WPContent from 'wp-astrojs-integration/components/WPContent.astro';
|
|
137
|
+
|
|
138
|
+
const { slug } = Astro.params;
|
|
139
|
+
const post = await getEntry('posts', slug);
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
<article>
|
|
143
|
+
<h1 set:html={post.data.title.rendered} />
|
|
144
|
+
|
|
145
|
+
<WPContent
|
|
146
|
+
content={post.data.content.rendered}
|
|
147
|
+
baseUrl={import.meta.env.PUBLIC_WORDPRESS_BASE_URL}
|
|
148
|
+
/>
|
|
149
|
+
</article>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Extending with Custom Fields
|
|
153
|
+
|
|
154
|
+
### Custom ACF Fields
|
|
155
|
+
|
|
156
|
+
Extend the default schemas with your ACF fields:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
import { postSchema } from 'wp-astrojs-integration';
|
|
160
|
+
import { z } from 'astro/zod';
|
|
161
|
+
|
|
162
|
+
const customPostSchema = postSchema.extend({
|
|
163
|
+
acf: z.object({
|
|
164
|
+
video_url: z.string().optional(),
|
|
165
|
+
featured_color: z.string().optional(),
|
|
166
|
+
custom_field: z.string().optional(),
|
|
167
|
+
}).optional(),
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const posts = defineLiveCollection({
|
|
171
|
+
loader: wordPressPostLoader({ baseUrl: WORDPRESS_BASE_URL }),
|
|
172
|
+
schema: customPostSchema,
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Custom Post Types
|
|
177
|
+
|
|
178
|
+
Create a custom post type loader:
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import { contentWordPressSchema } from 'wp-astrojs-integration';
|
|
182
|
+
import { z } from 'astro/zod';
|
|
183
|
+
|
|
184
|
+
const productSchema = contentWordPressSchema.extend({
|
|
185
|
+
acf: z.object({
|
|
186
|
+
price: z.number().optional(),
|
|
187
|
+
sku: z.string().optional(),
|
|
188
|
+
}).optional(),
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Use the base loader pattern for custom post types
|
|
192
|
+
import { wordPressPostLoader } from 'wp-astrojs-integration';
|
|
193
|
+
|
|
194
|
+
const products = defineLiveCollection({
|
|
195
|
+
loader: wordPressPostLoader({ baseUrl: WORDPRESS_BASE_URL }),
|
|
196
|
+
schema: productSchema,
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Custom Taxonomies
|
|
201
|
+
|
|
202
|
+
Extend category schema for custom taxonomies:
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { categorySchema } from 'wp-astrojs-integration';
|
|
206
|
+
|
|
207
|
+
const customCategorySchema = categorySchema.extend({
|
|
208
|
+
acf: z.object({
|
|
209
|
+
color: z.string().optional(),
|
|
210
|
+
icon: z.string().optional(),
|
|
211
|
+
}).optional(),
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
const categories = defineLiveCollection({
|
|
215
|
+
loader: wordPressCategoryLoader({ baseUrl: WORDPRESS_BASE_URL }),
|
|
216
|
+
schema: customCategorySchema,
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Components
|
|
221
|
+
|
|
222
|
+
### WPContent
|
|
223
|
+
|
|
224
|
+
Renders WordPress Gutenberg content with automatic block styles loading:
|
|
225
|
+
|
|
226
|
+
```astro
|
|
227
|
+
---
|
|
228
|
+
import WPContent from 'wp-astrojs-integration/components/WPContent.astro';
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
<WPContent
|
|
232
|
+
content={post.data.content.rendered}
|
|
233
|
+
baseUrl={import.meta.env.PUBLIC_WORDPRESS_BASE_URL}
|
|
234
|
+
class="custom-class"
|
|
235
|
+
loadBlockStyles={true}
|
|
236
|
+
/>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Props:**
|
|
240
|
+
- `content` (string, required): Rendered HTML from WordPress
|
|
241
|
+
- `baseUrl` (string, required): WordPress site URL
|
|
242
|
+
- `class` (string): Additional CSS classes
|
|
243
|
+
- `loadBlockStyles` (boolean): Load Gutenberg block styles (default: true)
|
|
244
|
+
|
|
245
|
+
### WPImage
|
|
246
|
+
|
|
247
|
+
Optimized responsive images with srcset support:
|
|
248
|
+
|
|
249
|
+
```astro
|
|
250
|
+
---
|
|
251
|
+
import WPImage from 'wp-astrojs-integration/components/WPImage.astro';
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
<!-- With embedded media -->
|
|
255
|
+
<WPImage media={featuredMedia} loading="eager" />
|
|
256
|
+
|
|
257
|
+
<!-- With media ID -->
|
|
258
|
+
<WPImage
|
|
259
|
+
mediaId={123}
|
|
260
|
+
baseUrl={import.meta.env.PUBLIC_WORDPRESS_BASE_URL}
|
|
261
|
+
loading="lazy"
|
|
262
|
+
/>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Props:**
|
|
266
|
+
- `media` (object): Pre-loaded media data from `_embedded`
|
|
267
|
+
- `mediaId` (number): WordPress media ID
|
|
268
|
+
- `baseUrl` (string): Required if using `mediaId`
|
|
269
|
+
- `class` (string): CSS classes
|
|
270
|
+
- `loading` ('lazy' | 'eager'): Image loading strategy
|
|
271
|
+
- `width` (number): Custom width
|
|
272
|
+
- `height` (number): Custom height
|
|
273
|
+
- `sizes` (string): Responsive sizes attribute
|
|
274
|
+
|
|
275
|
+
## WordPress Client (Runtime API)
|
|
276
|
+
|
|
277
|
+
For runtime data fetching:
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
import { WordPressClient } from 'wp-astrojs-integration';
|
|
281
|
+
|
|
282
|
+
const wp = new WordPressClient({ baseUrl: 'https://your-wordpress-site.com' });
|
|
283
|
+
|
|
284
|
+
// Get posts
|
|
285
|
+
const posts = await wp.getPosts();
|
|
286
|
+
const post = await wp.getPostBySlug('my-post');
|
|
287
|
+
|
|
288
|
+
// Get pages
|
|
289
|
+
const pages = await wp.getPages();
|
|
290
|
+
const page = await wp.getPageBySlug('about');
|
|
291
|
+
|
|
292
|
+
// Get media
|
|
293
|
+
const media = await wp.getMedia();
|
|
294
|
+
const image = await wp.getMediaItem(123);
|
|
295
|
+
|
|
296
|
+
// Get categories and tags
|
|
297
|
+
const categories = await wp.getCategories();
|
|
298
|
+
const tags = await wp.getTags();
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### With Authentication
|
|
302
|
+
|
|
303
|
+
For endpoints requiring authentication (e.g., `/settings`, `/users/me`):
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
import { WordPressClient } from 'wp-astrojs-integration';
|
|
307
|
+
|
|
308
|
+
const wp = new WordPressClient({
|
|
309
|
+
baseUrl: 'https://your-wordpress-site.com',
|
|
310
|
+
auth: {
|
|
311
|
+
username: 'your-username',
|
|
312
|
+
password: 'your-application-password'
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Get WordPress site settings (requires auth)
|
|
317
|
+
const settings = await wp.getSettings();
|
|
318
|
+
console.log(settings.title, settings.description);
|
|
319
|
+
|
|
320
|
+
// Get current authenticated user
|
|
321
|
+
const currentUser = await wp.getCurrentUser();
|
|
322
|
+
console.log(currentUser.name, currentUser.email);
|
|
323
|
+
|
|
324
|
+
// Check if credentials are valid
|
|
325
|
+
const isValid = await wp.isAuthenticated();
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Astro Middleware Authentication Example
|
|
329
|
+
|
|
330
|
+
Use the WordPress client in Astro middleware to protect routes with WordPress authentication:
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
// src/middleware.ts
|
|
334
|
+
import { defineMiddleware } from 'astro:middleware';
|
|
335
|
+
import { WordPressClient } from 'wp-astrojs-integration';
|
|
336
|
+
|
|
337
|
+
const WORDPRESS_BASE_URL = import.meta.env.PUBLIC_WORDPRESS_BASE_URL;
|
|
338
|
+
|
|
339
|
+
export const onRequest = defineMiddleware(async (context, next) => {
|
|
340
|
+
// Only protect /admin routes
|
|
341
|
+
if (!context.url.pathname.startsWith('/admin')) {
|
|
342
|
+
return next();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Get credentials from Authorization header (Basic Auth)
|
|
346
|
+
const authHeader = context.request.headers.get('Authorization');
|
|
347
|
+
if (!authHeader?.startsWith('Basic ')) {
|
|
348
|
+
return new Response('Authentication required', {
|
|
349
|
+
status: 401,
|
|
350
|
+
headers: { 'WWW-Authenticate': 'Basic realm="Admin Area"' }
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Decode credentials
|
|
355
|
+
const base64Credentials = authHeader.slice(6);
|
|
356
|
+
const credentials = atob(base64Credentials);
|
|
357
|
+
const [username, password] = credentials.split(':');
|
|
358
|
+
|
|
359
|
+
// Verify against WordPress
|
|
360
|
+
const wp = new WordPressClient({
|
|
361
|
+
baseUrl: WORDPRESS_BASE_URL,
|
|
362
|
+
auth: { username, password }
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const isAuthenticated = await wp.isAuthenticated();
|
|
366
|
+
if (!isAuthenticated) {
|
|
367
|
+
return new Response('Invalid credentials', {
|
|
368
|
+
status: 401,
|
|
369
|
+
headers: { 'WWW-Authenticate': 'Basic realm="Admin Area"' }
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Store user in locals for use in routes
|
|
374
|
+
const user = await wp.getCurrentUser();
|
|
375
|
+
context.locals.user = user;
|
|
376
|
+
|
|
377
|
+
return next();
|
|
378
|
+
});
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Then access the authenticated user in your protected routes:
|
|
382
|
+
|
|
383
|
+
```astro
|
|
384
|
+
---
|
|
385
|
+
// src/pages/admin/index.astro
|
|
386
|
+
const user = Astro.locals.user;
|
|
387
|
+
---
|
|
388
|
+
<h1>Welcome, {user.name}!</h1>
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## API Reference
|
|
392
|
+
|
|
393
|
+
### Live Loaders (for `defineLiveCollection`)
|
|
394
|
+
|
|
395
|
+
Use these for server-side rendering or real-time data:
|
|
396
|
+
|
|
397
|
+
- `wordPressPostLoader(config)`: Live loader for posts
|
|
398
|
+
- `wordPressPageLoader(config)`: Live loader for pages
|
|
399
|
+
- `wordPressMediaLoader(config)`: Live loader for media
|
|
400
|
+
- `wordPressCategoryLoader(config)`: Live loader for categories/taxonomies
|
|
401
|
+
|
|
402
|
+
### Static Loaders (for `defineCollection`)
|
|
403
|
+
|
|
404
|
+
Use these for static site generation (build-time only):
|
|
405
|
+
|
|
406
|
+
- `wordPressPostStaticLoader(config)`: Static loader for posts
|
|
407
|
+
- `wordPressPageStaticLoader(config)`: Static loader for pages
|
|
408
|
+
- `wordPressMediaStaticLoader(config)`: Static loader for media
|
|
409
|
+
- `wordPressCategoryStaticLoader(config)`: Static loader for categories
|
|
410
|
+
- `wordPressTagStaticLoader(config)`: Static loader for tags
|
|
411
|
+
|
|
412
|
+
**Static Loader Config:**
|
|
413
|
+
```typescript
|
|
414
|
+
interface WordPressStaticLoaderConfig {
|
|
415
|
+
baseUrl: string;
|
|
416
|
+
perPage?: number; // Items per page (default: 100)
|
|
417
|
+
params?: Record<string, string>; // Additional query params
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Schemas
|
|
422
|
+
|
|
423
|
+
Default schemas for WordPress content:
|
|
424
|
+
|
|
425
|
+
- `baseWordPressSchema`: Base fields for all content
|
|
426
|
+
- `contentWordPressSchema`: Content-specific fields (posts/pages)
|
|
427
|
+
- `postSchema`: WordPress posts
|
|
428
|
+
- `pageSchema`: WordPress pages
|
|
429
|
+
- `mediaSchema`: WordPress media
|
|
430
|
+
- `categorySchema`: Categories and taxonomies
|
|
431
|
+
- `embeddedMediaSchema`: Embedded media from `_embedded` field
|
|
432
|
+
|
|
433
|
+
### Types
|
|
434
|
+
|
|
435
|
+
TypeScript types inferred from schemas:
|
|
436
|
+
|
|
437
|
+
- `WordPressPost`
|
|
438
|
+
- `WordPressPage`
|
|
439
|
+
- `WordPressMedia`
|
|
440
|
+
- `WordPressCategory`
|
|
441
|
+
- `WordPressTag`
|
|
442
|
+
- `WordPressAuthor`
|
|
443
|
+
- `WordPressEmbeddedMedia`
|
|
444
|
+
|
|
445
|
+
## Live vs Static Loaders
|
|
446
|
+
|
|
447
|
+
| Feature | Live Loaders | Static Loaders |
|
|
448
|
+
|---------|-------------|----------------|
|
|
449
|
+
| Data freshness | Real-time | Build-time snapshot |
|
|
450
|
+
| Use case | SSR, dynamic content | SSG, static sites |
|
|
451
|
+
| Performance | Fetches on each request | Fetches once at build |
|
|
452
|
+
| Astro API | `defineLiveCollection` | `defineCollection` |
|
|
453
|
+
| Content access | `getLiveEntry`, `getLiveCollection` | `getEntry`, `getCollection` |
|
|
454
|
+
|
|
455
|
+
## Why This Package?
|
|
456
|
+
|
|
457
|
+
- **Flexible**: Choose between live (SSR) and static (SSG) data fetching
|
|
458
|
+
- **Type Safety**: Full TypeScript support with extensible schemas
|
|
459
|
+
- **Gutenberg Ready**: Automatic block styles ensure proper rendering
|
|
460
|
+
- **Easy Extension**: Simple API for custom fields and post types
|
|
461
|
+
- **Modern Workflow**: Works seamlessly with Astro's content collections
|
|
462
|
+
- **Optimized**: Responsive images, efficient caching, and minimal overhead
|
|
463
|
+
|
|
464
|
+
## License
|
|
465
|
+
|
|
466
|
+
MIT
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Basic authentication credentials for WordPress API
|
|
3
|
+
*/
|
|
4
|
+
export interface BasicAuthCredentials {
|
|
5
|
+
username: string;
|
|
6
|
+
password: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Creates Basic Auth header from credentials
|
|
10
|
+
*/
|
|
11
|
+
export declare function createBasicAuthHeader(credentials: BasicAuthCredentials): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { WordPressCategory } from '../schemas';
|
|
2
|
+
import type { FetchResult } from './index';
|
|
3
|
+
import type { CategoriesFilter, PaginatedResponse } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Categories API methods factory
|
|
6
|
+
* Creates type-safe methods for fetching WordPress categories with filtering and pagination
|
|
7
|
+
*/
|
|
8
|
+
export declare function createCategoriesMethods(fetchAPI: <T>(endpoint: string, params?: Record<string, string>) => Promise<T>, fetchAPIPaginated: <T>(endpoint: string, params?: Record<string, string>) => Promise<FetchResult<T>>): {
|
|
9
|
+
/**
|
|
10
|
+
* Gets categories with optional filtering (single page, max 100 items)
|
|
11
|
+
*
|
|
12
|
+
* @param filter - Filter options (hideEmpty, parent, include, exclude, search, etc.)
|
|
13
|
+
* @returns Array of categories matching the filter criteria
|
|
14
|
+
*/
|
|
15
|
+
getCategories(filter?: CategoriesFilter): Promise<WordPressCategory[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Gets ALL categories by automatically paginating through all pages
|
|
18
|
+
* Use this for static site generation to ensure all content is fetched
|
|
19
|
+
*
|
|
20
|
+
* @param filter - Filter options (hideEmpty, parent, include, exclude, search, etc.)
|
|
21
|
+
* @returns Array of all categories matching the filter criteria
|
|
22
|
+
*/
|
|
23
|
+
getAllCategories(filter?: Omit<CategoriesFilter, "page">): Promise<WordPressCategory[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Gets categories with pagination metadata
|
|
26
|
+
*
|
|
27
|
+
* @param filter - Filter options including pagination (perPage, page)
|
|
28
|
+
* @returns Paginated response with categories and total counts
|
|
29
|
+
*/
|
|
30
|
+
getCategoriesPaginated(filter?: CategoriesFilter): Promise<PaginatedResponse<WordPressCategory>>;
|
|
31
|
+
/**
|
|
32
|
+
* Gets a single category by ID
|
|
33
|
+
*/
|
|
34
|
+
getCategory(id: number): Promise<WordPressCategory>;
|
|
35
|
+
/**
|
|
36
|
+
* Gets a single category by slug
|
|
37
|
+
*/
|
|
38
|
+
getCategoryBySlug(slug: string): Promise<WordPressCategory | undefined>;
|
|
39
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { filterToParams } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Categories API methods factory
|
|
4
|
+
* Creates type-safe methods for fetching WordPress categories with filtering and pagination
|
|
5
|
+
*/
|
|
6
|
+
export function createCategoriesMethods(fetchAPI, fetchAPIPaginated) {
|
|
7
|
+
return {
|
|
8
|
+
/**
|
|
9
|
+
* Gets categories with optional filtering (single page, max 100 items)
|
|
10
|
+
*
|
|
11
|
+
* @param filter - Filter options (hideEmpty, parent, include, exclude, search, etc.)
|
|
12
|
+
* @returns Array of categories matching the filter criteria
|
|
13
|
+
*/
|
|
14
|
+
async getCategories(filter = {}) {
|
|
15
|
+
const params = filterToParams(filter);
|
|
16
|
+
return fetchAPI('/categories', params);
|
|
17
|
+
},
|
|
18
|
+
/**
|
|
19
|
+
* Gets ALL categories by automatically paginating through all pages
|
|
20
|
+
* Use this for static site generation to ensure all content is fetched
|
|
21
|
+
*
|
|
22
|
+
* @param filter - Filter options (hideEmpty, parent, include, exclude, search, etc.)
|
|
23
|
+
* @returns Array of all categories matching the filter criteria
|
|
24
|
+
*/
|
|
25
|
+
async getAllCategories(filter = {}) {
|
|
26
|
+
const allCategories = [];
|
|
27
|
+
let page = 1;
|
|
28
|
+
let totalPages = 1;
|
|
29
|
+
do {
|
|
30
|
+
const params = filterToParams({ ...filter, page, perPage: 100 });
|
|
31
|
+
const result = await fetchAPIPaginated('/categories', params);
|
|
32
|
+
allCategories.push(...result.data);
|
|
33
|
+
totalPages = result.totalPages;
|
|
34
|
+
page++;
|
|
35
|
+
} while (page <= totalPages);
|
|
36
|
+
return allCategories;
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* Gets categories with pagination metadata
|
|
40
|
+
*
|
|
41
|
+
* @param filter - Filter options including pagination (perPage, page)
|
|
42
|
+
* @returns Paginated response with categories and total counts
|
|
43
|
+
*/
|
|
44
|
+
async getCategoriesPaginated(filter = {}) {
|
|
45
|
+
const params = filterToParams(filter);
|
|
46
|
+
const result = await fetchAPIPaginated('/categories', params);
|
|
47
|
+
return {
|
|
48
|
+
data: result.data,
|
|
49
|
+
total: result.total,
|
|
50
|
+
totalPages: result.totalPages,
|
|
51
|
+
page: filter.page || 1,
|
|
52
|
+
perPage: filter.perPage || 100,
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
/**
|
|
56
|
+
* Gets a single category by ID
|
|
57
|
+
*/
|
|
58
|
+
async getCategory(id) {
|
|
59
|
+
return fetchAPI(`/categories/${id}`);
|
|
60
|
+
},
|
|
61
|
+
/**
|
|
62
|
+
* Gets a single category by slug
|
|
63
|
+
*/
|
|
64
|
+
async getCategoryBySlug(slug) {
|
|
65
|
+
const categories = await fetchAPI('/categories', { slug });
|
|
66
|
+
return categories[0];
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { type BasicAuthCredentials } from './auth';
|
|
2
|
+
import { createPostsMethods } from './posts';
|
|
3
|
+
import { createPagesMethods } from './pages';
|
|
4
|
+
import { createMediaMethods } from './media';
|
|
5
|
+
import { createCategoriesMethods } from './categories';
|
|
6
|
+
import { createTagsMethods } from './tags';
|
|
7
|
+
import { createUsersMethods } from './users';
|
|
8
|
+
import { createSettingsMethods } from './settings';
|
|
9
|
+
import type { PaginatedResponse } from './types';
|
|
10
|
+
/**
|
|
11
|
+
* WordPress client configuration
|
|
12
|
+
*/
|
|
13
|
+
export interface WordPressClientConfig {
|
|
14
|
+
/** WordPress site URL (e.g., 'https://example.com') */
|
|
15
|
+
baseUrl: string;
|
|
16
|
+
/** Authentication credentials for all API requests */
|
|
17
|
+
auth?: BasicAuthCredentials;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Internal fetch result with pagination headers
|
|
21
|
+
*/
|
|
22
|
+
export interface FetchResult<T> {
|
|
23
|
+
data: T;
|
|
24
|
+
total: number;
|
|
25
|
+
totalPages: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* WordPress API Client
|
|
29
|
+
* Provides direct access to WordPress REST API endpoints
|
|
30
|
+
* Used internally by loaders and available for runtime data fetching
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // Without auth
|
|
34
|
+
* const wp = new WordPressClient({ baseUrl: 'https://example.com' });
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* // With auth
|
|
38
|
+
* const wp = new WordPressClient({
|
|
39
|
+
* baseUrl: 'https://example.com',
|
|
40
|
+
* auth: { username: 'admin', password: 'app-password' }
|
|
41
|
+
* });
|
|
42
|
+
*/
|
|
43
|
+
export declare class WordPressClient {
|
|
44
|
+
private baseUrl;
|
|
45
|
+
private apiBase;
|
|
46
|
+
private authHeader;
|
|
47
|
+
getPosts: ReturnType<typeof createPostsMethods>['getPosts'];
|
|
48
|
+
getAllPosts: ReturnType<typeof createPostsMethods>['getAllPosts'];
|
|
49
|
+
getPostsPaginated: ReturnType<typeof createPostsMethods>['getPostsPaginated'];
|
|
50
|
+
getPost: ReturnType<typeof createPostsMethods>['getPost'];
|
|
51
|
+
getPostBySlug: ReturnType<typeof createPostsMethods>['getPostBySlug'];
|
|
52
|
+
getPages: ReturnType<typeof createPagesMethods>['getPages'];
|
|
53
|
+
getAllPages: ReturnType<typeof createPagesMethods>['getAllPages'];
|
|
54
|
+
getPagesPaginated: ReturnType<typeof createPagesMethods>['getPagesPaginated'];
|
|
55
|
+
getPage: ReturnType<typeof createPagesMethods>['getPage'];
|
|
56
|
+
getPageBySlug: ReturnType<typeof createPagesMethods>['getPageBySlug'];
|
|
57
|
+
getMedia: ReturnType<typeof createMediaMethods>['getMedia'];
|
|
58
|
+
getAllMedia: ReturnType<typeof createMediaMethods>['getAllMedia'];
|
|
59
|
+
getMediaPaginated: ReturnType<typeof createMediaMethods>['getMediaPaginated'];
|
|
60
|
+
getMediaItem: ReturnType<typeof createMediaMethods>['getMediaItem'];
|
|
61
|
+
getMediaBySlug: ReturnType<typeof createMediaMethods>['getMediaBySlug'];
|
|
62
|
+
getImageUrl: ReturnType<typeof createMediaMethods>['getImageUrl'];
|
|
63
|
+
getCategories: ReturnType<typeof createCategoriesMethods>['getCategories'];
|
|
64
|
+
getAllCategories: ReturnType<typeof createCategoriesMethods>['getAllCategories'];
|
|
65
|
+
getCategoriesPaginated: ReturnType<typeof createCategoriesMethods>['getCategoriesPaginated'];
|
|
66
|
+
getCategory: ReturnType<typeof createCategoriesMethods>['getCategory'];
|
|
67
|
+
getCategoryBySlug: ReturnType<typeof createCategoriesMethods>['getCategoryBySlug'];
|
|
68
|
+
getTags: ReturnType<typeof createTagsMethods>['getTags'];
|
|
69
|
+
getAllTags: ReturnType<typeof createTagsMethods>['getAllTags'];
|
|
70
|
+
getTagsPaginated: ReturnType<typeof createTagsMethods>['getTagsPaginated'];
|
|
71
|
+
getTag: ReturnType<typeof createTagsMethods>['getTag'];
|
|
72
|
+
getTagBySlug: ReturnType<typeof createTagsMethods>['getTagBySlug'];
|
|
73
|
+
getUsers: ReturnType<typeof createUsersMethods>['getUsers'];
|
|
74
|
+
getAllUsers: ReturnType<typeof createUsersMethods>['getAllUsers'];
|
|
75
|
+
getUsersPaginated: ReturnType<typeof createUsersMethods>['getUsersPaginated'];
|
|
76
|
+
getUser: ReturnType<typeof createUsersMethods>['getUser'];
|
|
77
|
+
getCurrentUser: ReturnType<typeof createUsersMethods>['getCurrentUser'];
|
|
78
|
+
getSettings: ReturnType<typeof createSettingsMethods>['getSettings'];
|
|
79
|
+
constructor(config: WordPressClientConfig);
|
|
80
|
+
/**
|
|
81
|
+
* Checks if authentication is configured
|
|
82
|
+
*/
|
|
83
|
+
hasAuth(): boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Fetches data from WordPress REST API
|
|
86
|
+
* Auth header is automatically added if configured
|
|
87
|
+
*
|
|
88
|
+
* @param endpoint - API endpoint path (e.g., '/posts', '/settings')
|
|
89
|
+
* @param params - Query parameters to append to the request
|
|
90
|
+
*/
|
|
91
|
+
fetchAPI<T>(endpoint: string, params?: Record<string, string>): Promise<T>;
|
|
92
|
+
/**
|
|
93
|
+
* Fetches data from WordPress REST API with pagination info
|
|
94
|
+
* Auth header is automatically added if configured
|
|
95
|
+
*
|
|
96
|
+
* @param endpoint - API endpoint path (e.g., '/posts', '/settings')
|
|
97
|
+
* @param params - Query parameters to append to the request
|
|
98
|
+
* @returns Object with data and pagination headers
|
|
99
|
+
*/
|
|
100
|
+
fetchAPIPaginated<T>(endpoint: string, params?: Record<string, string>): Promise<FetchResult<T>>;
|
|
101
|
+
}
|
|
102
|
+
export type { PaginatedResponse };
|