claude-plugin-wordpress-manager 1.5.0 → 1.7.1
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/.claude-plugin/plugin.json +2 -2
- package/CHANGELOG.md +97 -0
- package/README.md +27 -13
- package/agents/wp-accessibility-auditor.md +206 -0
- package/agents/wp-content-strategist.md +18 -0
- package/agents/wp-deployment-engineer.md +34 -2
- package/agents/wp-performance-optimizer.md +12 -0
- package/agents/wp-security-auditor.md +20 -0
- package/agents/wp-security-hardener.md +266 -0
- package/agents/wp-site-manager.md +14 -0
- package/agents/wp-test-engineer.md +207 -0
- package/docs/guides/INDEX.md +46 -0
- package/docs/guides/wp-blog.md +590 -0
- package/docs/guides/wp-design-system.md +976 -0
- package/docs/guides/wp-ecommerce.md +786 -0
- package/docs/guides/wp-landing-page.md +762 -0
- package/docs/guides/wp-portfolio.md +713 -0
- package/docs/plans/2026-02-27-design-system-guide-design.md +30 -0
- package/docs/plans/2026-02-27-site-type-guides-design.md +44 -0
- package/package.json +2 -2
- package/skills/wordpress-router/references/decision-tree.md +12 -2
- package/skills/wp-accessibility/SKILL.md +170 -0
- package/skills/wp-accessibility/references/a11y-audit-tools.md +248 -0
- package/skills/wp-accessibility/references/a11y-testing.md +222 -0
- package/skills/wp-accessibility/references/block-a11y.md +247 -0
- package/skills/wp-accessibility/references/interactive-a11y.md +272 -0
- package/skills/wp-accessibility/references/media-a11y.md +254 -0
- package/skills/wp-accessibility/references/theme-a11y.md +309 -0
- package/skills/wp-audit/SKILL.md +4 -0
- package/skills/wp-block-development/SKILL.md +5 -0
- package/skills/wp-block-themes/SKILL.md +4 -0
- package/skills/wp-e2e-testing/SKILL.md +186 -0
- package/skills/wp-e2e-testing/references/ci-integration.md +174 -0
- package/skills/wp-e2e-testing/references/jest-wordpress.md +114 -0
- package/skills/wp-e2e-testing/references/phpunit-wordpress.md +141 -0
- package/skills/wp-e2e-testing/references/playwright-wordpress.md +108 -0
- package/skills/wp-e2e-testing/references/test-data-generation.md +127 -0
- package/skills/wp-e2e-testing/references/visual-regression.md +107 -0
- package/skills/wp-e2e-testing/references/wp-env-setup.md +97 -0
- package/skills/wp-e2e-testing/scripts/test_inspect.mjs +375 -0
- package/skills/wp-headless/SKILL.md +168 -0
- package/skills/wp-headless/references/api-layer-choice.md +160 -0
- package/skills/wp-headless/references/cors-config.md +245 -0
- package/skills/wp-headless/references/frontend-integration.md +331 -0
- package/skills/wp-headless/references/headless-auth.md +286 -0
- package/skills/wp-headless/references/webhooks.md +277 -0
- package/skills/wp-headless/references/wpgraphql.md +331 -0
- package/skills/wp-headless/scripts/headless_inspect.mjs +321 -0
- package/skills/wp-i18n/SKILL.md +170 -0
- package/skills/wp-i18n/references/js-i18n.md +201 -0
- package/skills/wp-i18n/references/multilingual-setup.md +219 -0
- package/skills/wp-i18n/references/php-i18n.md +196 -0
- package/skills/wp-i18n/references/rtl-support.md +206 -0
- package/skills/wp-i18n/references/translation-workflow.md +178 -0
- package/skills/wp-i18n/references/wpcli-i18n.md +177 -0
- package/skills/wp-i18n/scripts/i18n_inspect.mjs +330 -0
- package/skills/wp-interactivity-api/SKILL.md +4 -0
- package/skills/wp-plugin-development/SKILL.md +6 -0
- package/skills/wp-rest-api/SKILL.md +4 -0
- package/skills/wp-security/SKILL.md +179 -0
- package/skills/wp-security/references/api-restriction.md +147 -0
- package/skills/wp-security/references/authentication-hardening.md +105 -0
- package/skills/wp-security/references/filesystem-hardening.md +105 -0
- package/skills/wp-security/references/http-headers.md +105 -0
- package/skills/wp-security/references/incident-response.md +144 -0
- package/skills/wp-security/references/user-capabilities.md +115 -0
- package/skills/wp-security/references/wp-config-security.md +129 -0
- package/skills/wp-security/scripts/security_inspect.mjs +393 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# Theme Accessibility
|
|
2
|
+
|
|
3
|
+
Use this file when building accessible WordPress themes and achieving `accessibility-ready` tag compliance.
|
|
4
|
+
|
|
5
|
+
## accessibility-ready tag requirements
|
|
6
|
+
|
|
7
|
+
WordPress.org requires these for the `accessibility-ready` tag:
|
|
8
|
+
|
|
9
|
+
1. **Skip links** — must be the first focusable element
|
|
10
|
+
2. **Keyboard navigation** — all interactive elements reachable and operable
|
|
11
|
+
3. **Contrast ratios** — text meets WCAG 2.1 AA (4.5:1 normal, 3:1 large)
|
|
12
|
+
4. **Resize text** — content usable at 200% zoom
|
|
13
|
+
5. **Form labels** — all inputs have associated labels
|
|
14
|
+
6. **Image alt text** — all images have alt attributes (decorative = `alt=""`)
|
|
15
|
+
7. **Visible focus** — focus indicators on all interactive elements
|
|
16
|
+
8. **Landmarks** — proper use of HTML5 landmark elements
|
|
17
|
+
9. **No autoplay** — media must not autoplay with sound
|
|
18
|
+
|
|
19
|
+
## Landmarks and page structure
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<body <?php body_class(); ?>>
|
|
23
|
+
<?php wp_body_open(); ?>
|
|
24
|
+
|
|
25
|
+
<a class="skip-link screen-reader-text" href="#primary">
|
|
26
|
+
<?php esc_html_e('Skip to content', 'my-theme'); ?>
|
|
27
|
+
</a>
|
|
28
|
+
|
|
29
|
+
<header id="masthead" role="banner">
|
|
30
|
+
<nav id="site-navigation" role="navigation"
|
|
31
|
+
aria-label="<?php esc_attr_e('Primary Menu', 'my-theme'); ?>">
|
|
32
|
+
<?php wp_nav_menu(['theme_location' => 'primary']); ?>
|
|
33
|
+
</nav>
|
|
34
|
+
</header>
|
|
35
|
+
|
|
36
|
+
<main id="primary" role="main">
|
|
37
|
+
<!-- page content -->
|
|
38
|
+
</main>
|
|
39
|
+
|
|
40
|
+
<aside id="sidebar" role="complementary"
|
|
41
|
+
aria-label="<?php esc_attr_e('Sidebar', 'my-theme'); ?>">
|
|
42
|
+
<?php dynamic_sidebar('sidebar-1'); ?>
|
|
43
|
+
</aside>
|
|
44
|
+
|
|
45
|
+
<footer id="colophon" role="contentinfo">
|
|
46
|
+
<!-- footer content -->
|
|
47
|
+
</footer>
|
|
48
|
+
</body>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Skip link CSS
|
|
52
|
+
|
|
53
|
+
```css
|
|
54
|
+
.skip-link {
|
|
55
|
+
position: absolute;
|
|
56
|
+
top: -100%;
|
|
57
|
+
left: 0;
|
|
58
|
+
z-index: 999999;
|
|
59
|
+
padding: 0.5rem 1rem;
|
|
60
|
+
background: #000;
|
|
61
|
+
color: #fff;
|
|
62
|
+
text-decoration: none;
|
|
63
|
+
font-size: 1rem;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.skip-link:focus {
|
|
67
|
+
top: 0;
|
|
68
|
+
clip: auto;
|
|
69
|
+
clip-path: none;
|
|
70
|
+
width: auto;
|
|
71
|
+
height: auto;
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Focus indicators
|
|
76
|
+
|
|
77
|
+
```css
|
|
78
|
+
/* Visible focus for all interactive elements */
|
|
79
|
+
a:focus,
|
|
80
|
+
button:focus,
|
|
81
|
+
input:focus,
|
|
82
|
+
select:focus,
|
|
83
|
+
textarea:focus,
|
|
84
|
+
[tabindex]:focus {
|
|
85
|
+
outline: 2px solid var(--wp--preset--color--primary, #0073aa);
|
|
86
|
+
outline-offset: 2px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Remove default only if replacing with custom indicator */
|
|
90
|
+
a:focus-visible {
|
|
91
|
+
outline: 3px solid #0073aa;
|
|
92
|
+
outline-offset: 2px;
|
|
93
|
+
border-radius: 2px;
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Never use `outline: none` without providing an alternative visible focus indicator.
|
|
98
|
+
|
|
99
|
+
## Navigation menus
|
|
100
|
+
|
|
101
|
+
### Menu walker with ARIA
|
|
102
|
+
|
|
103
|
+
```php
|
|
104
|
+
// In header.php or navigation template
|
|
105
|
+
wp_nav_menu([
|
|
106
|
+
'theme_location' => 'primary',
|
|
107
|
+
'container' => 'nav',
|
|
108
|
+
'container_class' => 'main-navigation',
|
|
109
|
+
'container_id' => 'primary-menu',
|
|
110
|
+
'items_wrap' => '<ul id="%1$s" class="%2$s" role="menubar">%3$s</ul>',
|
|
111
|
+
]);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Dropdown submenus
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
// Accessible submenu toggle
|
|
118
|
+
document.querySelectorAll('.menu-item-has-children > a').forEach((link) => {
|
|
119
|
+
const submenu = link.nextElementSibling;
|
|
120
|
+
const toggle = document.createElement('button');
|
|
121
|
+
toggle.className = 'submenu-toggle';
|
|
122
|
+
toggle.setAttribute('aria-expanded', 'false');
|
|
123
|
+
toggle.setAttribute('aria-label',
|
|
124
|
+
link.textContent.trim() + ' submenu');
|
|
125
|
+
toggle.innerHTML = '<span class="screen-reader-text">Toggle submenu</span>';
|
|
126
|
+
|
|
127
|
+
toggle.addEventListener('click', () => {
|
|
128
|
+
const expanded = toggle.getAttribute('aria-expanded') === 'true';
|
|
129
|
+
toggle.setAttribute('aria-expanded', String(!expanded));
|
|
130
|
+
submenu.hidden = expanded;
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
link.after(toggle);
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Forms
|
|
138
|
+
|
|
139
|
+
```html
|
|
140
|
+
<!-- Every input needs a label -->
|
|
141
|
+
<label for="search-input">
|
|
142
|
+
<?php esc_html_e('Search', 'my-theme'); ?>
|
|
143
|
+
</label>
|
|
144
|
+
<input type="search" id="search-input" name="s"
|
|
145
|
+
placeholder="<?php esc_attr_e('Search...', 'my-theme'); ?>">
|
|
146
|
+
|
|
147
|
+
<!-- Group related fields -->
|
|
148
|
+
<fieldset>
|
|
149
|
+
<legend><?php esc_html_e('Contact Information', 'my-theme'); ?></legend>
|
|
150
|
+
<label for="name"><?php esc_html_e('Name', 'my-theme'); ?></label>
|
|
151
|
+
<input type="text" id="name" name="name" required
|
|
152
|
+
aria-required="true">
|
|
153
|
+
<label for="email"><?php esc_html_e('Email', 'my-theme'); ?></label>
|
|
154
|
+
<input type="email" id="email" name="email" required
|
|
155
|
+
aria-required="true">
|
|
156
|
+
</fieldset>
|
|
157
|
+
|
|
158
|
+
<!-- Error messages -->
|
|
159
|
+
<input type="email" id="email" name="email"
|
|
160
|
+
aria-describedby="email-error" aria-invalid="true">
|
|
161
|
+
<p id="email-error" class="form-error" role="alert">
|
|
162
|
+
<?php esc_html_e('Please enter a valid email address.', 'my-theme'); ?>
|
|
163
|
+
</p>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Images in themes
|
|
167
|
+
|
|
168
|
+
```php
|
|
169
|
+
<!-- Content images: meaningful alt -->
|
|
170
|
+
<img src="<?php echo esc_url($image_url); ?>"
|
|
171
|
+
alt="<?php echo esc_attr($image_alt); ?>">
|
|
172
|
+
|
|
173
|
+
<!-- Decorative images: empty alt -->
|
|
174
|
+
<img src="decorative-border.png" alt="" role="presentation">
|
|
175
|
+
|
|
176
|
+
<!-- Background images with text: ensure contrast or provide alt -->
|
|
177
|
+
<div class="hero" style="background-image: url(hero.jpg);"
|
|
178
|
+
role="img" aria-label="<?php esc_attr_e('Mountain landscape', 'my-theme'); ?>">
|
|
179
|
+
<h1><?php esc_html_e('Welcome', 'my-theme'); ?></h1>
|
|
180
|
+
</div>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Post thumbnails
|
|
184
|
+
|
|
185
|
+
```php
|
|
186
|
+
// Theme support with alt text
|
|
187
|
+
if (has_post_thumbnail()) {
|
|
188
|
+
the_post_thumbnail('large', [
|
|
189
|
+
'alt' => get_the_title(), // fallback if no alt set
|
|
190
|
+
]);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Color and typography
|
|
195
|
+
|
|
196
|
+
```css
|
|
197
|
+
/* Ensure readable text sizes */
|
|
198
|
+
body {
|
|
199
|
+
font-size: 1rem; /* At least 16px */
|
|
200
|
+
line-height: 1.5; /* WCAG recommends 1.5 for body text */
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* Respect user preferences */
|
|
204
|
+
@media (prefers-reduced-motion: reduce) {
|
|
205
|
+
*,
|
|
206
|
+
*::before,
|
|
207
|
+
*::after {
|
|
208
|
+
animation-duration: 0.01ms !important;
|
|
209
|
+
transition-duration: 0.01ms !important;
|
|
210
|
+
scroll-behavior: auto !important;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
@media (prefers-contrast: more) {
|
|
215
|
+
:root {
|
|
216
|
+
--text-color: #000;
|
|
217
|
+
--bg-color: #fff;
|
|
218
|
+
--link-color: #00008b;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Screen reader utilities
|
|
224
|
+
|
|
225
|
+
```css
|
|
226
|
+
/* WordPress core screen-reader-text class */
|
|
227
|
+
.screen-reader-text {
|
|
228
|
+
border: 0;
|
|
229
|
+
clip: rect(1px, 1px, 1px, 1px);
|
|
230
|
+
clip-path: inset(50%);
|
|
231
|
+
height: 1px;
|
|
232
|
+
margin: -1px;
|
|
233
|
+
overflow: hidden;
|
|
234
|
+
padding: 0;
|
|
235
|
+
position: absolute !important;
|
|
236
|
+
width: 1px;
|
|
237
|
+
word-wrap: normal !important;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.screen-reader-text:focus {
|
|
241
|
+
background-color: #f1f1f1;
|
|
242
|
+
clip: auto !important;
|
|
243
|
+
clip-path: none;
|
|
244
|
+
display: block;
|
|
245
|
+
font-size: 0.875rem;
|
|
246
|
+
height: auto;
|
|
247
|
+
left: 5px;
|
|
248
|
+
line-height: normal;
|
|
249
|
+
padding: 15px 23px 14px;
|
|
250
|
+
text-decoration: none;
|
|
251
|
+
top: 5px;
|
|
252
|
+
width: auto;
|
|
253
|
+
z-index: 100000;
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## theme.json accessibility settings
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{
|
|
261
|
+
"settings": {
|
|
262
|
+
"color": {
|
|
263
|
+
"palette": [
|
|
264
|
+
{
|
|
265
|
+
"slug": "primary",
|
|
266
|
+
"color": "#0073aa",
|
|
267
|
+
"name": "Primary"
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"slug": "foreground",
|
|
271
|
+
"color": "#1e1e1e",
|
|
272
|
+
"name": "Foreground"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"slug": "background",
|
|
276
|
+
"color": "#ffffff",
|
|
277
|
+
"name": "Background"
|
|
278
|
+
}
|
|
279
|
+
]
|
|
280
|
+
},
|
|
281
|
+
"typography": {
|
|
282
|
+
"fluid": true,
|
|
283
|
+
"fontSizes": [
|
|
284
|
+
{ "slug": "small", "size": "0.875rem", "name": "Small" },
|
|
285
|
+
{ "slug": "medium", "size": "1rem", "name": "Medium" },
|
|
286
|
+
{ "slug": "large", "size": "1.25rem", "name": "Large" }
|
|
287
|
+
]
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Ensure all palette color combinations meet WCAG AA contrast ratios.
|
|
294
|
+
|
|
295
|
+
## Verification
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
# Test theme accessibility-ready requirements
|
|
299
|
+
npx @axe-core/cli https://localhost:8888/ --tags wcag2a,wcag2aa
|
|
300
|
+
|
|
301
|
+
# Check for missing alt attributes
|
|
302
|
+
curl -s https://site.com/ | grep -oP '<img[^>]*>' | grep -v 'alt='
|
|
303
|
+
|
|
304
|
+
# Check for skip link
|
|
305
|
+
curl -s https://site.com/ | grep -i "skip"
|
|
306
|
+
|
|
307
|
+
# Validate landmarks
|
|
308
|
+
curl -s https://site.com/ | grep -cE "<(main|nav|header|footer|aside|section)"
|
|
309
|
+
```
|
package/skills/wp-audit/SKILL.md
CHANGED
|
@@ -112,3 +112,7 @@ Combine findings into a unified report with:
|
|
|
112
112
|
- **`references/security-checklist.md`** - WordPress security audit checklist
|
|
113
113
|
- **`references/performance-checklist.md`** - Performance analysis checklist
|
|
114
114
|
- **`references/seo-checklist.md`** - SEO audit checklist
|
|
115
|
+
|
|
116
|
+
## Related skills
|
|
117
|
+
|
|
118
|
+
- `wp-security` — Deep security hardening, filesystem permissions, HTTP headers, incident response procedures
|
|
@@ -174,3 +174,8 @@ If you’re uncertain about upstream behavior/version support, consult canonical
|
|
|
174
174
|
|
|
175
175
|
- WordPress Developer Resources (Block Editor Handbook, Theme Handbook, Plugin Handbook)
|
|
176
176
|
- Gutenberg repo docs for bleeding-edge behaviors
|
|
177
|
+
|
|
178
|
+
## Related skills
|
|
179
|
+
|
|
180
|
+
- `wp-e2e-testing` — Playwright E2E tests, Jest unit tests for block JavaScript, wp-env test environments
|
|
181
|
+
- `wp-accessibility` — Block ARIA patterns, keyboard navigation, color contrast checks
|
|
@@ -116,3 +116,7 @@ Common issues:
|
|
|
116
116
|
If upstream behavior is unclear, consult canonical docs:
|
|
117
117
|
|
|
118
118
|
- Theme Handbook and Block Editor Handbook for `theme.json`, templates, patterns, and style variations.
|
|
119
|
+
|
|
120
|
+
## Related skills
|
|
121
|
+
|
|
122
|
+
- `wp-accessibility` — Theme accessibility-ready requirements, skip links, focus indicators, WCAG compliance
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wp-e2e-testing
|
|
3
|
+
description: "Use when setting up, writing, or debugging WordPress tests: E2E with Playwright, unit tests with PHPUnit, JavaScript tests with Jest, visual regression, test data generation, wp-env test environment, and CI pipeline integration."
|
|
4
|
+
compatibility: "Targets WordPress 6.9+ (PHP 7.2.24+). Filesystem-based agent with bash + node. Some workflows require WP-CLI and Docker."
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
source: "vinmor/wordpress-manager"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# WP E2E Testing
|
|
10
|
+
|
|
11
|
+
## When to use
|
|
12
|
+
|
|
13
|
+
Use this skill when the task involves WordPress testing workflows:
|
|
14
|
+
|
|
15
|
+
- Setting up a test suite from scratch for a WordPress plugin, theme, or block
|
|
16
|
+
- Writing E2E tests with Playwright against a running WordPress instance
|
|
17
|
+
- Adding PHPUnit tests for PHP code (hooks, filters, REST endpoints, custom post types)
|
|
18
|
+
- Writing Jest unit tests for JavaScript/React block code
|
|
19
|
+
- Debugging test failures in CI or locally
|
|
20
|
+
- Setting up a CI pipeline (GitHub Actions) for WordPress test automation
|
|
21
|
+
- Adding visual regression testing to catch unintended UI changes
|
|
22
|
+
- Generating test data and fixtures for reproducible test runs
|
|
23
|
+
- Configuring wp-env as a Docker-based test environment
|
|
24
|
+
|
|
25
|
+
## Inputs required
|
|
26
|
+
|
|
27
|
+
- **Repo root**: current working directory or `--cwd` path
|
|
28
|
+
- **Project kind**: plugin, theme, or block (auto-detected via `detect_wp_project.mjs`)
|
|
29
|
+
- **Existing test setup**: which frameworks are already configured (auto-detected via `test_inspect.mjs`)
|
|
30
|
+
- **CI platform**: GitHub Actions is the primary target; adaptable to others
|
|
31
|
+
|
|
32
|
+
## Procedure
|
|
33
|
+
|
|
34
|
+
### 0) Detect existing test setup
|
|
35
|
+
|
|
36
|
+
Run the detection scripts to understand what is already in place:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
node skills/wp-e2e-testing/scripts/test_inspect.mjs
|
|
40
|
+
node skills/wp-project-triage/scripts/detect_wp_project.mjs
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The `test_inspect.mjs` script outputs JSON with:
|
|
44
|
+
- `frameworks` — which test frameworks are configured (Playwright, Jest, PHPUnit, visual regression)
|
|
45
|
+
- `testEnvironment` — whether wp-env and Docker are available
|
|
46
|
+
- `ci` — whether CI workflows exist and which platform
|
|
47
|
+
- `summary` — boolean flags for quick decision-making
|
|
48
|
+
|
|
49
|
+
Use this output to skip steps that are already complete and focus on gaps.
|
|
50
|
+
|
|
51
|
+
### 1) Choose testing strategy by project kind
|
|
52
|
+
|
|
53
|
+
Different WordPress project types need different testing approaches:
|
|
54
|
+
|
|
55
|
+
| Project kind | E2E (Playwright) | Unit JS (Jest) | Unit PHP (PHPUnit) | Visual regression |
|
|
56
|
+
|-------------|:-:|:-:|:-:|:-:|
|
|
57
|
+
| Plugin (classic) | Optional | If has JS | Recommended | Optional |
|
|
58
|
+
| Plugin (block) | Recommended | Recommended | Recommended | Recommended |
|
|
59
|
+
| Theme (classic) | Optional | Rare | Optional | Recommended |
|
|
60
|
+
| Theme (block/FSE) | Recommended | If has JS | Optional | Recommended |
|
|
61
|
+
| Gutenberg contrib | Required | Required | Required | Required |
|
|
62
|
+
|
|
63
|
+
**General rule**: if the project has a user-facing UI, add E2E tests. If it has PHP logic (hooks, filters, REST), add PHPUnit. If it has JS/React, add Jest. If appearance matters, add visual regression.
|
|
64
|
+
|
|
65
|
+
### 2) Set up test environment (wp-env)
|
|
66
|
+
|
|
67
|
+
wp-env provides a Docker-based WordPress instance purpose-built for testing. It spins up two environments: development (port 8888) and tests (port 8889).
|
|
68
|
+
|
|
69
|
+
Key steps:
|
|
70
|
+
1. Ensure Docker is running (`docker info`)
|
|
71
|
+
2. Create or verify `.wp-env.json` in the project root
|
|
72
|
+
3. Start the environment with `npx wp-env start`
|
|
73
|
+
4. Verify with `npx wp-env run tests-cli wp option get siteurl`
|
|
74
|
+
|
|
75
|
+
The tests environment is isolated and can be reset without affecting development data. PHPUnit runs inside the tests container. Playwright connects to the development or tests URL.
|
|
76
|
+
|
|
77
|
+
Read: `references/wp-env-setup.md`
|
|
78
|
+
|
|
79
|
+
### 3) E2E tests with Playwright
|
|
80
|
+
|
|
81
|
+
WordPress provides `@wordpress/e2e-test-utils-playwright` which wraps Playwright with WordPress-specific utilities: authenticated admin sessions, block editor helpers, REST API seeding.
|
|
82
|
+
|
|
83
|
+
Key steps:
|
|
84
|
+
1. Install Playwright and WP utilities
|
|
85
|
+
2. Configure `playwright.config.ts` with WordPress base URL
|
|
86
|
+
3. Write tests using `admin`, `editor`, and `requestUtils` fixtures
|
|
87
|
+
4. Run with `npx wp-scripts test-playwright` or `npx playwright test`
|
|
88
|
+
|
|
89
|
+
Read: `references/playwright-wordpress.md`
|
|
90
|
+
|
|
91
|
+
### 4) JavaScript unit tests with Jest
|
|
92
|
+
|
|
93
|
+
`@wordpress/scripts` bundles a preconfigured Jest setup. It handles JSX/TSX transforms, WordPress global mocks, and module resolution.
|
|
94
|
+
|
|
95
|
+
Key steps:
|
|
96
|
+
1. Ensure `@wordpress/scripts` is a devDependency
|
|
97
|
+
2. Add a `test-unit-js` script to package.json (or use the default)
|
|
98
|
+
3. Create test files alongside source (`*.test.js`) or in `__tests__/`
|
|
99
|
+
4. Mock WordPress globals (`wp`, `jQuery`) as needed
|
|
100
|
+
5. Run with `npx wp-scripts test-unit-js`
|
|
101
|
+
|
|
102
|
+
Read: `references/jest-wordpress.md`
|
|
103
|
+
|
|
104
|
+
### 5) PHP unit tests with PHPUnit
|
|
105
|
+
|
|
106
|
+
WordPress ships a PHPUnit test bootstrapper. The `wp scaffold plugin-tests` WP-CLI command generates the full scaffolding.
|
|
107
|
+
|
|
108
|
+
Key steps:
|
|
109
|
+
1. Scaffold test files with `wp scaffold plugin-tests my-plugin`
|
|
110
|
+
2. Extend `WP_UnitTestCase` for WordPress-aware tests
|
|
111
|
+
3. Use `set_up()` and `tear_down()` for test lifecycle
|
|
112
|
+
4. Test hooks, filters, REST endpoints, and custom post types
|
|
113
|
+
5. Run with `npx wp-env run tests-cli --env-cwd=wp-content/plugins/my-plugin phpunit`
|
|
114
|
+
|
|
115
|
+
Read: `references/phpunit-wordpress.md`
|
|
116
|
+
|
|
117
|
+
### 6) Visual regression testing
|
|
118
|
+
|
|
119
|
+
Screenshot comparison catches unintended UI changes. Playwright's built-in `toHaveScreenshot()` matcher is the simplest approach for WordPress projects already using Playwright.
|
|
120
|
+
|
|
121
|
+
Key steps:
|
|
122
|
+
1. Add screenshot assertions to existing Playwright tests
|
|
123
|
+
2. Generate baseline screenshots on the main branch
|
|
124
|
+
3. Configure threshold tolerance for acceptable pixel differences
|
|
125
|
+
4. Store baselines in the repository or as CI artifacts
|
|
126
|
+
5. Review diffs on failure before updating baselines
|
|
127
|
+
|
|
128
|
+
Read: `references/visual-regression.md`
|
|
129
|
+
|
|
130
|
+
### 7) Test data and fixtures
|
|
131
|
+
|
|
132
|
+
Reproducible tests need predictable data. WordPress provides factory methods for PHP tests and REST API utilities for E2E tests.
|
|
133
|
+
|
|
134
|
+
Key steps:
|
|
135
|
+
1. Use `self::factory()->post->create()` in PHPUnit tests
|
|
136
|
+
2. Use `requestUtils.createPost()` in Playwright E2E tests
|
|
137
|
+
3. Seed bulk data via WP-CLI (`wp post generate`)
|
|
138
|
+
4. Clean up after each test to prevent state leakage
|
|
139
|
+
|
|
140
|
+
Read: `references/test-data-generation.md`
|
|
141
|
+
|
|
142
|
+
### 8) CI pipeline integration
|
|
143
|
+
|
|
144
|
+
GitHub Actions is the standard CI platform for WordPress projects. A typical pipeline runs PHPUnit across a PHP version matrix, Jest for JS tests, and Playwright for E2E.
|
|
145
|
+
|
|
146
|
+
Key steps:
|
|
147
|
+
1. Create `.github/workflows/tests.yml`
|
|
148
|
+
2. Add MySQL service container for PHPUnit
|
|
149
|
+
3. Define a test matrix for PHP and WP version combinations
|
|
150
|
+
4. Cache node_modules and Composer vendor
|
|
151
|
+
5. Upload Playwright traces and screenshots as artifacts on failure
|
|
152
|
+
|
|
153
|
+
Read: `references/ci-integration.md`
|
|
154
|
+
|
|
155
|
+
## Verification
|
|
156
|
+
|
|
157
|
+
After completing the setup, verify:
|
|
158
|
+
|
|
159
|
+
- `npx wp-scripts test-unit-js` passes (if Jest tests exist)
|
|
160
|
+
- `npx wp-env run tests-cli --env-cwd=wp-content/plugins/<plugin> phpunit` passes (if PHPUnit tests exist)
|
|
161
|
+
- `npx wp-scripts test-playwright` passes (if E2E tests exist)
|
|
162
|
+
- Visual regression baselines are generated and stored
|
|
163
|
+
- CI workflow runs green on push and pull request events
|
|
164
|
+
- Test coverage meets project threshold (aim for 80%+ on critical paths)
|
|
165
|
+
|
|
166
|
+
## Failure modes / debugging
|
|
167
|
+
|
|
168
|
+
- **wp-env fails to start**: check Docker is running (`docker info`), check port conflicts (`lsof -i :8888`), try `npx wp-env destroy` then `npx wp-env start`
|
|
169
|
+
- **Playwright tests timeout**: increase `timeout` in `playwright.config.ts`, ensure wp-env is fully started before tests run, check `baseURL` matches the running instance
|
|
170
|
+
- **PHPUnit "No tests executed"**: verify `phpunit.xml` points to the correct test directory, ensure test class extends `WP_UnitTestCase`, ensure method names start with `test_`
|
|
171
|
+
- **Jest "Cannot find module"**: check `moduleNameMapper` in jest config, ensure `@wordpress/scripts` is installed, run `npm install` to refresh dependencies
|
|
172
|
+
- **Visual regression false positives**: increase pixel threshold, mask dynamic elements (timestamps, ads), use consistent viewport sizes, disable animations in test config
|
|
173
|
+
- **CI MySQL connection refused**: ensure the `mysql` service container is healthy before running PHPUnit, add a wait step or health check
|
|
174
|
+
- **"Class WP_UnitTestCase not found"**: the test bootstrap is missing or the WordPress test library is not installed; re-run `bin/install-wp-tests.sh` or use wp-env which handles this automatically
|
|
175
|
+
|
|
176
|
+
## Escalation
|
|
177
|
+
|
|
178
|
+
- For Gutenberg-specific testing: https://developer.wordpress.org/block-editor/contributors/code/testing-overview/
|
|
179
|
+
- For @wordpress/scripts: https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/
|
|
180
|
+
- For wp-env: https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/
|
|
181
|
+
- For Playwright WP utilities: https://developer.wordpress.org/block-editor/reference-guides/packages/packages-e2e-test-utils-playwright/
|
|
182
|
+
- For PHPUnit with WordPress: https://make.wordpress.org/core/handbook/testing/automated-testing/phpunit/
|
|
183
|
+
|
|
184
|
+
## Recommended Agent
|
|
185
|
+
|
|
186
|
+
For hands-on test execution, debugging, and CI setup, use the **`wp-test-engineer`** agent.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# CI Pipeline Integration for WordPress Tests
|
|
2
|
+
|
|
3
|
+
Use this file when setting up GitHub Actions (or similar CI) for WordPress test automation.
|
|
4
|
+
|
|
5
|
+
## GitHub Actions workflow
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
# .github/workflows/tests.yml
|
|
9
|
+
name: Tests
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
push:
|
|
13
|
+
branches: [main]
|
|
14
|
+
pull_request:
|
|
15
|
+
branches: [main]
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
php-tests:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
matrix:
|
|
22
|
+
php: ['8.1', '8.2', '8.3']
|
|
23
|
+
wp: ['6.8', '6.9']
|
|
24
|
+
services:
|
|
25
|
+
mysql:
|
|
26
|
+
image: mysql:8.0
|
|
27
|
+
env:
|
|
28
|
+
MYSQL_ROOT_PASSWORD: root
|
|
29
|
+
MYSQL_DATABASE: wordpress_test
|
|
30
|
+
ports: ['3306:3306']
|
|
31
|
+
options: >-
|
|
32
|
+
--health-cmd="mysqladmin ping"
|
|
33
|
+
--health-interval=10s
|
|
34
|
+
--health-timeout=5s
|
|
35
|
+
--health-retries=5
|
|
36
|
+
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v4
|
|
39
|
+
|
|
40
|
+
- name: Setup PHP
|
|
41
|
+
uses: shivammathur/setup-php@v2
|
|
42
|
+
with:
|
|
43
|
+
php-version: ${{ matrix.php }}
|
|
44
|
+
extensions: mysqli
|
|
45
|
+
coverage: xdebug
|
|
46
|
+
|
|
47
|
+
- name: Cache Composer
|
|
48
|
+
uses: actions/cache@v4
|
|
49
|
+
with:
|
|
50
|
+
path: vendor
|
|
51
|
+
key: composer-${{ hashFiles('composer.lock') }}
|
|
52
|
+
|
|
53
|
+
- name: Install dependencies
|
|
54
|
+
run: composer install --no-interaction
|
|
55
|
+
|
|
56
|
+
- name: Install WP test suite
|
|
57
|
+
run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wp }}
|
|
58
|
+
|
|
59
|
+
- name: Run PHPUnit
|
|
60
|
+
run: vendor/bin/phpunit
|
|
61
|
+
|
|
62
|
+
js-tests:
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@v4
|
|
66
|
+
|
|
67
|
+
- name: Setup Node.js
|
|
68
|
+
uses: actions/setup-node@v4
|
|
69
|
+
with:
|
|
70
|
+
node-version: 20
|
|
71
|
+
cache: npm
|
|
72
|
+
|
|
73
|
+
- name: Install dependencies
|
|
74
|
+
run: npm ci
|
|
75
|
+
|
|
76
|
+
- name: Run Jest
|
|
77
|
+
run: npx wp-scripts test-unit-js --ci --coverage
|
|
78
|
+
|
|
79
|
+
e2e-tests:
|
|
80
|
+
runs-on: ubuntu-latest
|
|
81
|
+
steps:
|
|
82
|
+
- uses: actions/checkout@v4
|
|
83
|
+
|
|
84
|
+
- name: Setup Node.js
|
|
85
|
+
uses: actions/setup-node@v4
|
|
86
|
+
with:
|
|
87
|
+
node-version: 20
|
|
88
|
+
cache: npm
|
|
89
|
+
|
|
90
|
+
- name: Install dependencies
|
|
91
|
+
run: npm ci
|
|
92
|
+
|
|
93
|
+
- name: Install Playwright browsers
|
|
94
|
+
run: npx playwright install chromium --with-deps
|
|
95
|
+
|
|
96
|
+
- name: Start wp-env
|
|
97
|
+
run: npx wp-env start
|
|
98
|
+
|
|
99
|
+
- name: Run Playwright tests
|
|
100
|
+
run: npx wp-scripts test-playwright
|
|
101
|
+
|
|
102
|
+
- name: Upload artifacts on failure
|
|
103
|
+
uses: actions/upload-artifact@v4
|
|
104
|
+
if: failure()
|
|
105
|
+
with:
|
|
106
|
+
name: playwright-artifacts
|
|
107
|
+
path: artifacts/
|
|
108
|
+
retention-days: 7
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Caching strategies
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
# Node modules
|
|
115
|
+
- uses: actions/cache@v4
|
|
116
|
+
with:
|
|
117
|
+
path: ~/.npm
|
|
118
|
+
key: npm-${{ hashFiles('package-lock.json') }}
|
|
119
|
+
|
|
120
|
+
# Playwright browsers
|
|
121
|
+
- uses: actions/cache@v4
|
|
122
|
+
with:
|
|
123
|
+
path: ~/.cache/ms-playwright
|
|
124
|
+
key: playwright-${{ hashFiles('package-lock.json') }}
|
|
125
|
+
|
|
126
|
+
# Docker images for wp-env
|
|
127
|
+
- uses: ScribeMD/docker-cache@0.5.0
|
|
128
|
+
with:
|
|
129
|
+
key: docker-${{ hashFiles('.wp-env.json') }}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Parallel test execution
|
|
133
|
+
|
|
134
|
+
Split Playwright tests across multiple workers:
|
|
135
|
+
|
|
136
|
+
```yaml
|
|
137
|
+
e2e-tests:
|
|
138
|
+
strategy:
|
|
139
|
+
matrix:
|
|
140
|
+
shard: [1, 2, 3]
|
|
141
|
+
steps:
|
|
142
|
+
# ...
|
|
143
|
+
- run: npx playwright test --shard=${{ matrix.shard }}/3
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## PHPUnit without wp-env (standalone)
|
|
147
|
+
|
|
148
|
+
For projects that don't use wp-env, the `install-wp-tests.sh` script sets up the WP test suite:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 latest true
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Arguments: `db_name db_user db_pass db_host wp_version skip_db_create`
|
|
155
|
+
|
|
156
|
+
## Conditional jobs
|
|
157
|
+
|
|
158
|
+
Run expensive E2E tests only when relevant files change:
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
e2e-tests:
|
|
162
|
+
if: |
|
|
163
|
+
contains(github.event.pull_request.labels.*.name, 'e2e') ||
|
|
164
|
+
github.ref == 'refs/heads/main'
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Best practices
|
|
168
|
+
|
|
169
|
+
- Run PHPUnit with matrix strategy for PHP/WP version coverage
|
|
170
|
+
- Cache aggressively (npm, Composer, Playwright browsers, Docker)
|
|
171
|
+
- Upload test artifacts (traces, screenshots) on failure for debugging
|
|
172
|
+
- Use `--ci` flag for Jest to disable interactive mode
|
|
173
|
+
- Set reasonable timeouts to catch hanging tests early
|
|
174
|
+
- Run lint/format checks as a separate job (fast fail)
|