Skip to content

Commit a5e31e3

Browse files
josephfuscoclaude
andcommitted
feat(toolbar): Add real WordPress integration to demo
Integrate toolbar demo with real WordPress instance using wp-env: - Add CORS headers via mu-plugin for localhost:3000 - Fetch real WordPress user via REST API - Fetch posts using WPGraphQL - Update demo UI with real data workflow - Document WordPress integration in README Updates: - Use query parameter format for REST API (/?rest_route=) - Use query parameter format for GraphQL (/?graphql) - Add lifecycle script for permalink setup - Update demo instructions for real WordPress workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent eb31d3a commit a5e31e3

5 files changed

Lines changed: 180 additions & 42 deletions

File tree

examples/vanilla/toolbar-demo/.wp-env.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
},
1111
"port": 8888,
1212
"mappings": {
13-
"db": "./wp-env/db"
13+
"db": "./wp-env/db",
14+
"wp-content/mu-plugins": "./mu-plugin.php"
1415
},
1516
"lifecycleScripts": {
1617
"afterStart": "wp-env run cli -- wp rewrite structure '/%postname%/' && wp-env run cli -- wp rewrite flush"

examples/vanilla/toolbar-demo/README.md

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,18 @@ This example demonstrates how to integrate the Headless WordPress Toolbar into a
2626
From the example directory:
2727

2828
```bash
29-
# Install dependencies and start
29+
# Install dependencies and start WordPress + Vite
3030
npm run example:build
3131

3232
# Or, if already set up:
3333
npm run example:start
3434
```
3535

3636
The example will be available at:
37-
- Frontend: http://localhost:3000
38-
- WordPress Admin: http://localhost:8888/wp-admin (admin / password)
37+
- **Frontend**: http://localhost:3000
38+
- **WordPress**: http://localhost:8888
39+
- **WordPress Admin**: http://localhost:8888/wp-admin (`admin` / `password`)
40+
- **GraphQL**: http://localhost:8888/?graphql
3941

4042
## Project Structure
4143

@@ -72,34 +74,65 @@ const toolbar = new Toolbar({
7274
const renderer = new VanillaRenderer(toolbar, 'toolbar');
7375
```
7476

75-
### 2. WordPress Context
77+
### 2. Real WordPress Integration
78+
79+
The example fetches real data from WordPress:
7680

7781
```javascript
82+
// Fetch WordPress user via REST API
83+
const response = await fetch('http://localhost:8888/?rest_route=/wp/v2/users/1');
84+
const user = await response.json();
85+
7886
toolbar.setState({
79-
user: { id: 1, name: 'Admin' },
87+
user: {
88+
id: user.id,
89+
name: user.name,
90+
email: user.email
91+
},
8092
site: {
8193
url: 'http://localhost:8888',
8294
adminUrl: 'http://localhost:8888/wp-admin'
83-
},
84-
post: {
85-
id: 123,
86-
title: 'Hello World',
87-
type: 'post',
88-
status: 'draft',
89-
slug: 'hello-world'
9095
}
9196
});
9297
```
9398

94-
### 3. Custom Nodes
99+
### 3. GraphQL Posts
100+
101+
Fetch posts using WPGraphQL:
102+
103+
```javascript
104+
const response = await fetch('http://localhost:8888/?graphql', {
105+
method: 'POST',
106+
headers: { 'Content-Type': 'application/json' },
107+
body: JSON.stringify({
108+
query: `
109+
query GetPosts {
110+
posts(first: 5) {
111+
nodes {
112+
databaseId
113+
title
114+
slug
115+
status
116+
}
117+
}
118+
}
119+
`
120+
})
121+
});
122+
123+
const { data } = await response.json();
124+
// Use posts to populate toolbar
125+
```
126+
127+
### 4. Custom Nodes
95128

96129
```javascript
97130
toolbar.register('home', 'Home', () => {
98131
window.location.href = '/';
99132
});
100133
```
101134

102-
### 4. State Subscription
135+
### 5. State Subscription
103136

104137
```javascript
105138
toolbar.subscribe((nodes, state) => {
@@ -134,8 +167,10 @@ The wp-env configuration includes:
134167

135168
- WordPress with WPGraphQL plugin
136169
- Admin credentials: `admin` / `password`
137-
- GraphQL endpoint: http://localhost:8888/graphql
170+
- GraphQL endpoint: `http://localhost:8888/?graphql`
171+
- REST API endpoint: `http://localhost:8888/?rest_route=/wp/v2/...`
138172
- Pretty permalinks enabled
173+
- CORS headers enabled for localhost:3000
139174

140175
## Using with Vite
141176

examples/vanilla/toolbar-demo/example-app/index.html

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ <h2>User Context</h2>
1818

1919
<section class="controls">
2020
<h2>Post Context</h2>
21-
<button onclick="addPost()">Add Post</button>
22-
<button onclick="addPage()">Add Page</button>
21+
<button onclick="fetchPosts()">Fetch Posts</button>
22+
<button onclick="addPost()">Add Mock Post</button>
23+
<button onclick="addPage()">Add Mock Page</button>
2324
<button onclick="clearPost()">Clear Post</button>
25+
<div id="wordpress-posts"></div>
2426
</section>
2527

2628
<section class="controls">
@@ -37,12 +39,12 @@ <h2>Current State:</h2>
3739
<section class="info">
3840
<h2>Try This:</h2>
3941
<ol>
40-
<li>Click "Login" to authenticate</li>
41-
<li>Click "Add Post" to load content</li>
42-
<li>See WordPress controls appear in the toolbar at the bottom</li>
42+
<li>Click "Login" to fetch real WP user</li>
43+
<li>Click "Fetch Posts" to load real posts</li>
44+
<li>Click a post to add it to toolbar</li>
45+
<li>See WordPress controls appear in toolbar</li>
4346
<li>Click "Preview" to toggle preview mode</li>
4447
<li>Click "Edit post" to open in WordPress (opens new tab)</li>
45-
<li>Click "WP Admin" to open WordPress dashboard</li>
4648
</ol>
4749
</section>
4850

examples/vanilla/toolbar-demo/example-app/src/main.js

Lines changed: 98 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { Toolbar, VanillaRenderer } from '@wpengine/hwp-toolbar';
22
import '@wpengine/hwp-toolbar/styles';
33
import './style.css';
44

5+
const WP_URL = 'http://localhost:8888';
6+
57
// Create toolbar instance
68
const toolbar = new Toolbar({
79
onPreviewChange: (enabled) => {
@@ -18,20 +20,35 @@ toolbar.subscribe((nodes, state) => {
1820
document.getElementById('state').textContent = JSON.stringify(state, null, 2);
1921
});
2022

21-
// Control functions
22-
window.login = () => {
23-
toolbar.setState({
24-
user: {
25-
id: 1,
26-
name: 'Admin',
27-
email: 'admin@example.com'
28-
},
29-
site: {
30-
adminUrl: 'http://localhost:8888/wp-admin',
31-
url: 'http://localhost:8888'
23+
// Fetch real WordPress user
24+
window.login = async () => {
25+
try {
26+
// For demo: just set mock authenticated user
27+
// In production, you'd authenticate first via WordPress login
28+
const response = await fetch(`${WP_URL}/?rest_route=/wp/v2/users/1`);
29+
30+
if (response.ok) {
31+
const user = await response.json();
32+
toolbar.setState({
33+
user: {
34+
id: user.id,
35+
name: user.name,
36+
email: user.email || 'admin@example.com'
37+
},
38+
site: {
39+
adminUrl: `${WP_URL}/wp-admin`,
40+
url: WP_URL
41+
}
42+
});
43+
console.log('User logged in:', user.name);
44+
} else {
45+
console.error('WordPress not available');
46+
alert('WordPress is not running at ' + WP_URL);
3247
}
33-
});
34-
console.log('User logged in');
48+
} catch (error) {
49+
console.error('Error connecting to WordPress:', error);
50+
alert('Error: Make sure WordPress is running (npm run wp:start)');
51+
}
3552
};
3653

3754
window.logout = () => {
@@ -45,6 +62,66 @@ window.logout = () => {
4562
console.log('User logged out');
4663
};
4764

65+
// Fetch real posts from WordPress GraphQL
66+
window.fetchPosts = async () => {
67+
try {
68+
const response = await fetch(`${WP_URL}/?graphql`, {
69+
method: 'POST',
70+
headers: {
71+
'Content-Type': 'application/json',
72+
},
73+
body: JSON.stringify({
74+
query: `
75+
query GetPosts {
76+
posts(first: 5) {
77+
nodes {
78+
databaseId
79+
title
80+
slug
81+
status
82+
}
83+
}
84+
}
85+
`
86+
})
87+
});
88+
89+
const { data } = await response.json();
90+
91+
if (data?.posts?.nodes?.length > 0) {
92+
const posts = data.posts.nodes;
93+
console.log('Fetched posts:', posts);
94+
95+
// Display posts in UI
96+
const postsDiv = document.getElementById('wordpress-posts');
97+
postsDiv.innerHTML = '<h3>WordPress Posts:</h3>';
98+
posts.forEach(post => {
99+
const btn = document.createElement('button');
100+
btn.textContent = post.title;
101+
btn.onclick = () => loadPost(post);
102+
postsDiv.appendChild(btn);
103+
});
104+
}
105+
} catch (error) {
106+
console.error('Error fetching posts:', error);
107+
alert('Error fetching posts. Make sure WPGraphQL is installed.');
108+
}
109+
};
110+
111+
function loadPost(post) {
112+
toolbar.setState({
113+
post: {
114+
id: post.databaseId,
115+
title: post.title,
116+
type: 'post',
117+
status: post.status,
118+
slug: post.slug
119+
}
120+
});
121+
console.log('Post loaded:', post.title);
122+
}
123+
124+
// Mock data functions (for when WordPress isn't running)
48125
window.addPost = () => {
49126
toolbar.setState({
50127
post: {
@@ -55,7 +132,7 @@ window.addPost = () => {
55132
slug: 'hello-world'
56133
}
57134
});
58-
console.log('Post context added');
135+
console.log('Mock post added');
59136
};
60137

61138
window.addPage = () => {
@@ -68,7 +145,7 @@ window.addPage = () => {
68145
slug: 'about'
69146
}
70147
});
71-
console.log('Page context added');
148+
console.log('Mock page added');
72149
};
73150

74151
window.clearPost = () => {
@@ -104,14 +181,15 @@ window.clearAll = () => {
104181
// Initialize with home button
105182
toolbar.register('home', 'Home', () => {
106183
console.log('Navigate to home');
107-
alert('Navigate to Homepage');
184+
window.location.href = '/';
108185
});
109186

110187
// Console greeting
111188
console.log('%cHeadless WordPress Toolbar', 'font-size: 18px; font-weight: bold; color: #0073aa;');
112-
console.log('For headless WordPress implementations');
189+
console.log('WordPress at:', WP_URL);
113190
console.log('');
114191
console.log('Try this flow:');
115-
console.log('1. Click "Login" to authenticate');
116-
console.log('2. Click "Add Post" to load content');
117-
console.log('3. See WordPress controls appear in toolbar');
192+
console.log('1. Click "Login" to fetch real WP user');
193+
console.log('2. Click "Fetch Posts" to load real posts');
194+
console.log('3. Click a post to add it to toolbar');
195+
console.log('4. See WordPress controls appear in toolbar');
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* Plugin Name: Toolbar Demo CORS
4+
* Description: Enable CORS for Vite dev server
5+
*/
6+
7+
add_action('rest_api_init', function() {
8+
remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
9+
add_filter('rest_pre_serve_request', function($value) {
10+
header('Access-Control-Allow-Origin: http://localhost:3000');
11+
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
12+
header('Access-Control-Allow-Credentials: true');
13+
header('Access-Control-Allow-Headers: Content-Type, Authorization');
14+
15+
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
16+
status_header(200);
17+
exit();
18+
}
19+
20+
return $value;
21+
});
22+
});

0 commit comments

Comments
 (0)