80 | >
81 | );
82 | })
83 | }
84 |
--------------------------------------------------------------------------------
/docs/src/content/config.ts:
--------------------------------------------------------------------------------
1 | import { defineCollection } from 'astro:content';
2 | import { docsSchema } from '@astrojs/starlight/schema';
3 |
4 | export const collections = {
5 | docs: defineCollection({ schema: docsSchema() }),
6 | };
7 |
--------------------------------------------------------------------------------
/docs/src/content/docs/index.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Getting started
3 | description: Use your WordPress data in Astro projects
4 | tableOfContents: false
5 | hero:
6 | title: DeWP
7 | tagline: Use your WordPress data in Astro projects
8 | ---
9 |
10 | import { Card, CardGrid, Steps } from '@astrojs/starlight/components';
11 | import { PackageManagers } from 'starlight-package-managers';
12 |
13 | :::note
14 |
15 | This is early-release software.
16 | Please [report bugs](https://github.com/delucis/dewp) that you find.
17 |
18 | `dewp` requires Astro v5, which is currently in beta.
19 |
20 | :::
21 |
22 | ## Features
23 |
24 | This project contains several tools for using your WordPress data in Astro projects.
25 | You can use them to build headless WordPress sites with Astro or even migrate your data away from WordPress to Astro entirely.
26 |
27 |
28 |
29 | `dewp/loaders` loads your content using the WordPress REST API so you can use it with Astro’s
30 | content collection API.
31 |
32 |
33 | Use DeWP’s blog template to get started with an Astro project using headless WordPress data.
34 |
35 |
36 |
37 | More coming soon!
38 |
39 | ## Create a new project
40 |
41 | The easiest way to get started is to create a new Astro project using the DeWP blog template.
42 |
43 |
44 |
45 | 1. Run the following command in your terminal and follow the instructions in the Astro install wizard.
46 |
47 |
52 |
53 | :::tip[Browser preview]
54 | You can also test a [preview of the template on StackBlitz](https://stackblitz.com/github/delucis/dewp/tree/main/examples/blog-starter).
55 | :::
56 |
57 | 2. Update the `endpoint` option in `src/content/config.ts` to the URL of your WordPress REST API. Most commonly this is the URL of your website with `/wp-json/` at the end.
58 |
59 | ```ts title="src/content/config.ts" "'https://example.com/wp-json/'"
60 | import { wpCollections } from 'dewp/loaders';
61 |
62 | export const collections = wpCollections({
63 | endpoint: 'https://example.com/wp-json/',
64 | });
65 | ```
66 |
67 | 3. You can now [start the Astro dev server](https://docs.astro.build/en/install-and-setup/#start-the-astro-dev-server) and see a live preview of your project while you build.
68 |
69 |
70 |
71 | The template shows links to all the pages in the linked WordPress site on the homepage and links to the 10 most recent blog posts at `/blog`.
72 |
73 | ## Add to an existing project
74 |
75 | If you prefer to add the DeWP content loaders to an existing Astro project, follow these steps.
76 |
77 |
78 |
79 | 1. Install DeWP by running the following command in your project directory.
80 |
81 |
82 |
83 | 2. Add the DeWP content loaders to `src/content/config.ts`, setting `endpoint` to the URL of your WordPress REST API.
84 |
85 | ```ts title="src/content/config.ts" ins={2,6}
86 | import { z, defineCollection } from 'astro:content';
87 | import { wpCollections } from 'dewp/loaders';
88 |
89 | export const collections = {
90 | // existing collections ...
91 | ...wpCollections({ endpoint: 'https://example.com/wp-json/' }),
92 | };
93 | ```
94 |
95 | 3. You can now use Astro’s [content collection APIs](https://5-0-0-beta.docs.astro.build/en/guides/content-collections/) to get your WordPress data in your components.
96 |
97 | In the following example, the `posts` collection is loaded in order to display each post’s title:
98 |
99 | ```astro title="example.astro"
100 | ---
101 | import { getCollection } from 'astro:content';
102 | const posts = await getCollection('posts');
103 | ---
104 | {posts.map((post) =>
{post.data.title}
)}
105 | ```
106 |
107 |
108 |
--------------------------------------------------------------------------------
/docs/src/content/docs/reference/collections.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Collections Reference
3 | description: In-depth reference documentation for all the DeWP content collections and their data schemas.
4 | ---
5 |
6 | import CollectionSchema from '../../../components/CollectionSchema.astro';
7 |
8 | This reference page documents in detail the collections added to an Astro project by DeWP’s collection loaders.
9 |
10 | ## Data structure
11 |
12 | Each collection corresponds to one of WordPress’s data types available from the [WordPress REST API](https://developer.wordpress.org/rest-api/) and in general matches the schema of those endpoints.
13 |
14 | One important difference between the JSON responses returned by the REST API and DeWP’s content collections is that references between collections are encoded as [Astro collection references](https://5-0-0-beta.docs.astro.build/en/guides/content-collections/#defining-collection-references) instead of as raw integers.
15 | This simplifies looking up related entries using Astro’s `getEntry()` and `getEntries()` functions.
16 |
17 | For example, post data contains an array specifying the categories that post belongs to.
18 | You can turn that array of references into a fully resolved array of category data using `getEntries()`:
19 |
20 | ```js
21 | import { getEntry, getEntries } from 'astro:content';
22 |
23 | const myFirstPost = await getEntry('posts', '1');
24 | // [{ id: '1', data: { name: 'Hello world!', categories: [{ id: '1', collection: 'categories' }], ... } }]
25 | const categories = await getEntries(myFirstPost.data.categories);
26 | // [{ id: '1', data: { name: 'Uncategorized', ... } }]
27 | ```
28 |
29 | ## Collections
30 |
31 | Using `wpCollections()` in your content configuration adds the following content collections to your Astro project.
32 |
33 | ### `posts`
34 |
35 | The `posts` collection contains entries from WordPress’s [`wp/v2/posts` endpoint](https://developer.wordpress.org/rest-api/reference/posts/).
36 | These are the blog posts and include fully rendered post content.
37 |
38 | #### Example usage
39 |
40 | ```astro title="example-post.astro"
41 | ---
42 | import { getEntry, render } from 'astro:content';
43 | const post = await getEntry('posts', '1');
44 | // post = {
45 | // id: '1',
46 | // collection: 'posts',
47 | // data: {
48 | // title: { rendered: 'Hello world!' },
49 | // date: Wed Jun 04 2008
50 | // // ...
51 | // },
52 | // ...
53 | // }
54 |
55 | const { Content } = render(post);
56 | ---
57 |
58 |
59 |
60 | ```
61 |
62 |
63 |
64 | ### `pages`
65 |
66 | The `pages` collection contains content from WordPress’s [`wp/v2/pages` endpoint](https://developer.wordpress.org/rest-api/reference/pages/).
67 | Pages include fully rendered content.
68 |
69 | Unlike posts, pages are hierarchical and one page can have a `parent` page, allowing for the creation of tree-like page relationships.
70 |
71 | #### Example usage
72 |
73 | ```astro title="example-page.astro"
74 | ---
75 | import { getEntry, render } from 'astro:content';
76 |
77 | const page = await getEntry('pages', '49');
78 | const { Content } = render(page);
79 |
80 | // Get the parent page if there is one:
81 | const parent = page.data.parent && await getEntry(page.data.parent);
82 | ---
83 |
84 |
85 |
86 |
87 |
88 | {parent && (
89 |
90 | This page is a child of
91 |
92 | )}
93 | ```
94 |
95 |
96 |
97 | ### `categories`
98 |
99 | The `categories` collection contains entries from WordPress’s [`wp/v2/categories` endpoint](https://developer.wordpress.org/rest-api/reference/categories/).
100 | Entries in the `posts` collection can contain references to categories.
101 | Metadata about individual categories such as their name, description, and number of posts are stored in the `categories` collection.
102 |
103 |
104 |
105 | ### `tags`
106 |
107 | The `tags` collection contains entries from WordPress’s [`wp/v2/tags` endpoint](https://developer.wordpress.org/rest-api/reference/tags/).
108 | Entries in the `posts` collection can contain references to tags.
109 | Metadata about individual tags such as their name, description, and number of posts are stored in the `tags` collection.
110 |
111 |
112 |
113 | ### `users`
114 |
115 | The `users` collection contains users from WordPress’s [`wp/v2/users`](https://developer.wordpress.org/rest-api/reference/users/) endpoint.
116 |
117 |
118 |
119 | ### `comments`
120 |
121 | The `comments` collection contains user comments from WordPress’s [`wp/v2/comments`](https://developer.wordpress.org/rest-api/reference/comments/) endpoint.
122 |
123 |
124 |
125 | ### `media`
126 |
127 | The `media` collection contains media attachments from WordPress’s [`wp/v2/media`](https://developer.wordpress.org/rest-api/reference/media/) endpoint.
128 |
129 |
130 |
131 | ### `statuses`
132 |
133 | The `statuses` collection contains status definitions from WordPress’s [`wp/v2/statuses`](https://developer.wordpress.org/rest-api/reference/post-statuses/) endpoint.
134 |
135 |
136 |
137 | ### `taxonomies`
138 |
139 | The `taxonomies` collection contains taxonomy definitions from WordPress’s [`wp/v2/taxonomies`](https://developer.wordpress.org/rest-api/reference/taxonomies/) endpoint.
140 |
141 |
142 |
143 | ### `types`
144 |
145 | The `types` collection contains post type definitions from WordPress’s [`wp/v2/types`](https://developer.wordpress.org/rest-api/reference/types/) endpoint.
146 |
147 |
148 |
149 | ### `site-settings`
150 |
151 | The `site-settings` collection contains a single entry with some basic configuration options exposed by WordPress.
152 |
153 | #### Example usage
154 |
155 | The easiest way to load site settings is with DeWP’s `getSiteSettings` utility:
156 |
157 | ```ts
158 | import { getSiteSettings } from 'dewp/content-utils';
159 |
160 | const settings = await getSiteSettings();
161 | ```
162 |
163 |
164 |
--------------------------------------------------------------------------------
/docs/src/content/docs/reference/utilities.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Utilities Reference
3 | description: Documentation of DeWP’s utility functions for working with content.
4 | ---
5 |
6 | This reference page documents utility functions provided by DeWP for working with your WordPress content in Astro.
7 |
8 | ## Content utilities
9 |
10 | Content utilities help simplify common operations with your WordPress content.
11 |
12 | These utilities can be imported from the `dewp/content-utils` module.
13 |
14 | ```ts
15 | import { getSiteSettings, resolvePageSlug } from 'dewp/content-utils';
16 | ```
17 |
18 | ### `getSiteSettings()`
19 |
20 | **Type:** `() => Promise>`
21 |
22 | Get settings from the [`site-settings`](/dewp/reference/collections/#site-settings) content collection.
23 | Includes `name` (the site title), `description`, and a couple of other handy bits of metadata.
24 |
25 | ```ts
26 | const { name, description } = await getSiteSettings();
27 | ```
28 |
29 | ### `resolvePageSlug(page)`
30 |
31 | **Type:** `(page: CollectionEntry<'pages'>) => Promise`
32 |
33 | If pages have parents, WordPress prepends parent slugs to the page slug.
34 | For example, given a `lion` page with a `big-cats` parent, the page would be served at `big-cats/lion`.
35 |
36 | The `resolvePageSlug()` function resolves parent pages to construct a multi-segment path in the same way.
37 |
38 | ```ts
39 | const lionPage = await getEntry('pages', '🦁');
40 | console.log(lionPage.data.slug); // => "lion"
41 |
42 | const slug = await resolvePageSlug(lionPage);
43 | console.log(slug); // => "big-cats/lion"
44 | ```
45 |
--------------------------------------------------------------------------------
/docs/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/docs/src/overrides/Head.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import type { Props } from '@astrojs/starlight/props';
3 | import Default from '@astrojs/starlight/components/Head.astro';
4 |
5 | // Get the URL of the generated image for the current page using its
6 | // ID and replace the file extension with `.png`.
7 | const ogImageUrl = new URL(
8 | `${import.meta.env.BASE_URL}/og/${Astro.props.id.replace(/\.\w+$/, '.png')}`,
9 | Astro.site
10 | );
11 | ---
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/src/pages/og/[...slug].ts:
--------------------------------------------------------------------------------
1 | import { getCollection } from 'astro:content';
2 | import { OGImageRoute } from 'astro-og-canvas';
3 |
4 | // Get all entries from the `docs` content collection.
5 | const entries = await getCollection('docs');
6 |
7 | // Map the entry array to an object with the page ID as key and the
8 | // frontmatter data as value.
9 | const pages = Object.fromEntries(entries.map(({ data, id }) => [id, { data }]));
10 |
11 | export const { getStaticPaths, GET } = OGImageRoute({
12 | // Pass down the documentation pages.
13 | pages,
14 | // Define the name of the parameter used in the endpoint path, here `slug`
15 | // as the file is named `[...slug].ts`.
16 | param: 'slug',
17 | // Define a function called for each page to customize the generated image.
18 | getImageOptions: (_path, page: (typeof pages)[number]) => {
19 | return {
20 | // Use the page title and description as the image title and description.
21 | title: page.data.title,
22 | description: page.data.description || '',
23 | // Customize various colors and add a border.
24 | bgGradient: [[23, 24, 28] as const],
25 | border: { color: [179, 199, 255], width: 10, side: 'block-end' },
26 | font: {
27 | title: {
28 | size: 90,
29 | color: [255, 255, 255],
30 | families: ['IBM Plex Sans'],
31 | weight: 'Bold',
32 | },
33 | description: {
34 | color: [136, 140, 150],
35 | families: ['IBM Plex Sans'],
36 | lineHeight: 1.4,
37 | },
38 | },
39 | fonts: [
40 | 'https://cdn.jsdelivr.net/fontsource/fonts/ibm-plex-sans@latest/latin-400-normal.woff2',
41 | 'https://cdn.jsdelivr.net/fontsource/fonts/ibm-plex-sans@latest/latin-700-normal.woff2',
42 | ],
43 | padding: 90,
44 | logo: {
45 | path: './src/pages/og/_logo.png',
46 | },
47 | };
48 | },
49 | });
50 |
--------------------------------------------------------------------------------
/docs/src/pages/og/_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delucis/dewp/31304890bf4d44869f8ebc5a43a3be0a08bb1ebf/docs/src/pages/og/_logo.png
--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/strictest"
3 | }
4 |
--------------------------------------------------------------------------------
/examples/blog-starter/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 | # generated types
4 | .astro/
5 |
6 | # dependencies
7 | node_modules/
8 |
9 | # logs
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 |
23 | # jetbrains setting folder
24 | .idea/
25 |
--------------------------------------------------------------------------------
/examples/blog-starter/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["astro-build.astro-vscode"],
3 | "unwantedRecommendations": []
4 | }
5 |
--------------------------------------------------------------------------------
/examples/blog-starter/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "command": "./node_modules/.bin/astro dev",
6 | "name": "Development server",
7 | "request": "launch",
8 | "type": "node-terminal"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/examples/blog-starter/README.md:
--------------------------------------------------------------------------------
1 | # DeWP Starter Kit: Blog
2 |
3 | ```sh
4 | npm create astro@latest -- --template delucis/dewp/examples/blog-starter
5 | ```
6 |
7 | [](https://stackblitz.com/github/delucis/dewp/tree/main/examples/blog-starter)
8 | [](https://codesandbox.io/p/sandbox/github/delucis/dewp/tree/main/examples/blog-starter)
9 |
10 | > 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
11 |
12 | ## 🚀 Project Structure
13 |
14 | Inside of your Astro project, you'll see the following folders and files:
15 |
16 | ```text
17 | ├── public/
18 | ├── src/
19 | │ ├── components/
20 | │ ├── content/
21 | │ ├── layouts/
22 | │ └── pages/
23 | ├── astro.config.mjs
24 | ├── README.md
25 | ├── package.json
26 | └── tsconfig.json
27 | ```
28 |
29 | Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
30 |
31 | There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
32 |
33 | The `src/content/config.ts` file configures "collections" of data loaded from WordPress. Use `getCollection()` to retrieve blog posts and other content. See [Astro's Content Collections docs](https://docs.astro.build/en/guides/content-collections/) to learn more.
34 |
35 | Any static assets, like images, can be placed in the `public/` directory.
36 |
37 | ## 🧞 Commands
38 |
39 | All commands are run from the root of the project, from a terminal:
40 |
41 | | Command | Action |
42 | | :------------------------ | :----------------------------------------------- |
43 | | `npm install` | Installs dependencies |
44 | | `npm run dev` | Starts local dev server at `localhost:4321` |
45 | | `npm run build` | Build your production site to `./dist/` |
46 | | `npm run preview` | Preview your build locally, before deploying |
47 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
48 | | `npm run astro -- --help` | Get help using the Astro CLI |
49 |
50 | ## 👀 Want to learn more?
51 |
52 | Check out [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
53 |
54 | ## Credit
55 |
56 | This theme is based off of the lovely [Bear Blog](https://github.com/HermanMartinus/bearblog/).
57 |
--------------------------------------------------------------------------------
/examples/blog-starter/astro.config.mjs:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import sitemap from '@astrojs/sitemap';
3 | import { defineConfig } from 'astro/config';
4 |
5 | // https://astro.build/config
6 | export default defineConfig({
7 | site: 'https://example.com',
8 | integrations: [sitemap()],
9 | });
10 |
--------------------------------------------------------------------------------
/examples/blog-starter/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@examples/blog-starter",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "private": true,
6 | "scripts": {
7 | "dev": "astro dev",
8 | "start": "astro dev",
9 | "build": "astro build",
10 | "preview": "astro preview",
11 | "astro": "astro"
12 | },
13 | "dependencies": {
14 | "@astrojs/rss": "^4.0.8",
15 | "@astrojs/sitemap": "^3.2.0",
16 | "astro": "^5.0.8",
17 | "dewp": "^0.0.6"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/examples/blog-starter/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/examples/blog-starter/public/fonts/atkinson-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delucis/dewp/31304890bf4d44869f8ebc5a43a3be0a08bb1ebf/examples/blog-starter/public/fonts/atkinson-bold.woff
--------------------------------------------------------------------------------
/examples/blog-starter/public/fonts/atkinson-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delucis/dewp/31304890bf4d44869f8ebc5a43a3be0a08bb1ebf/examples/blog-starter/public/fonts/atkinson-regular.woff
--------------------------------------------------------------------------------
/examples/blog-starter/src/components/BaseHead.astro:
--------------------------------------------------------------------------------
1 | ---
2 | // Import the global.css file here so that it is included on
3 | // all pages through the use of the component.
4 | import '../styles/global.css';
5 |
6 | interface Props {
7 | /** Title of the current page used in SEO metadata like the `` tag. */
8 | title: string;
9 | /** Description of the current page used in SEO metadata like the `` tag. */
10 | description: string;
11 | /** Optional open graph image for the current page. */
12 | image?: string | undefined;
13 | }
14 |
15 | const canonicalURL = new URL(Astro.url.pathname, Astro.site);
16 |
17 | const { title, description, image } = Astro.props;
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 | {image && }
44 |
45 |
46 |
47 |
48 |
49 |
50 | {image && }
51 |
--------------------------------------------------------------------------------
/examples/blog-starter/src/components/Comments.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { getCollection } from 'astro:content';
3 |
4 | interface Props {
5 | id: number;
6 | }
7 |
8 | const { id } = Astro.props;
9 | const comments = await getCollection('comments', (comment) => comment.data.post?.id === String(id));
10 | ---
11 |
12 | {
13 | comments.length > 0 && (
14 |
15 |