@imwz/wp-pattern-sentinel 0.1.0 → 0.2.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/README.md +3 -0
- package/package.json +1 -1
- package/src/args.js +16 -3
- package/src/login.js +3 -3
- package/src/main.js +4 -4
- package/src/trellis.js +21 -1
package/README.md
CHANGED
|
@@ -57,6 +57,8 @@ Sentinel auto-discovers the Trellis directory by walking up from the current wor
|
|
|
57
57
|
| `--env` | `development` | Trellis environment (`development`, `staging`, `production`) |
|
|
58
58
|
| `--subsite` | — | Multisite subsite slug (appended to URL) |
|
|
59
59
|
|
|
60
|
+
**Bedrock support:** When `--trellis` is used, sentinel auto-detects Bedrock installs by reading `WP_SITEURL` from the site's `.env` file. Bedrock puts WordPress core in `/wp/`, so admin URLs become `/wp/wp-admin/` instead of `/wp-admin/`. No extra flags needed — this is handled automatically.
|
|
61
|
+
|
|
60
62
|
---
|
|
61
63
|
|
|
62
64
|
## Quickstart with `.env`
|
|
@@ -111,6 +113,7 @@ node bin/sentinel.js --concurrency=6 --url=... path/to/patterns/
|
|
|
111
113
|
| `--url` | `http://localhost` | WordPress site URL |
|
|
112
114
|
| `--user` | `admin` | Admin username |
|
|
113
115
|
| `--pass` | `password` | Admin password |
|
|
116
|
+
| `--wp-subdir` | — | WP core subdir when not using `--trellis` (e.g. `wp` for Bedrock). Sets admin URL to `{url}/{subdir}`. Auto-detected from `WP_SITEURL` when `--trellis` is used. |
|
|
114
117
|
| `--headless` | `true` | Run browser headless |
|
|
115
118
|
| `--concurrency` | `4` | Parallel workers |
|
|
116
119
|
| `--json` | `false` | Output JSON (one result per line) |
|
package/package.json
CHANGED
package/src/args.js
CHANGED
|
@@ -24,6 +24,9 @@ const ARG_OPTIONS = {
|
|
|
24
24
|
site: { type: 'string' },
|
|
25
25
|
env: { type: 'string', default: 'development' },
|
|
26
26
|
subsite: { type: 'string' },
|
|
27
|
+
// Bedrock / WP core subdir (e.g. "wp" for Bedrock installs where core lives at /wp/)
|
|
28
|
+
// Auto-detected via WP_SITEURL when --trellis is used; set manually otherwise.
|
|
29
|
+
'wp-subdir': { type: 'string' },
|
|
27
30
|
// Behaviour
|
|
28
31
|
headless: { type: 'boolean', default: true },
|
|
29
32
|
json: { type: 'boolean', default: false },
|
|
@@ -65,7 +68,7 @@ export async function parseArgs(args) {
|
|
|
65
68
|
allowPositionals: true,
|
|
66
69
|
});
|
|
67
70
|
|
|
68
|
-
let url, user, pass;
|
|
71
|
+
let url, adminUrl, user, pass;
|
|
69
72
|
|
|
70
73
|
// --- Source 1: Trellis vault ---
|
|
71
74
|
if (values.trellis) {
|
|
@@ -73,7 +76,7 @@ export async function parseArgs(args) {
|
|
|
73
76
|
? path.resolve(values['trellis-dir'])
|
|
74
77
|
: findTrellisDir();
|
|
75
78
|
|
|
76
|
-
({ url, user, pass } = loadTrellisCredentials({
|
|
79
|
+
({ url, adminUrl, user, pass } = loadTrellisCredentials({
|
|
77
80
|
trellisDir,
|
|
78
81
|
site: values.site,
|
|
79
82
|
env: values.env,
|
|
@@ -104,10 +107,20 @@ export async function parseArgs(args) {
|
|
|
104
107
|
pass = await prompt('WordPress admin password: ', { hidden: true });
|
|
105
108
|
if (!pass) throw new Error('WordPress password is required.');
|
|
106
109
|
}
|
|
110
|
+
|
|
111
|
+
// --wp-subdir: manually specify the WP core subdir (e.g. "wp" for Bedrock)
|
|
112
|
+
const wpSubdir = values['wp-subdir'];
|
|
113
|
+
adminUrl = wpSubdir
|
|
114
|
+
? `${url.replace(/\/$/, '')}/${wpSubdir}`
|
|
115
|
+
: url;
|
|
107
116
|
}
|
|
108
117
|
|
|
118
|
+
const cleanUrl = url.replace(/\/$/, '');
|
|
119
|
+
const cleanAdminUrl = (adminUrl ?? url).replace(/\/$/, '');
|
|
120
|
+
|
|
109
121
|
return {
|
|
110
|
-
url:
|
|
122
|
+
url: cleanUrl,
|
|
123
|
+
adminUrl: cleanAdminUrl,
|
|
111
124
|
user,
|
|
112
125
|
pass,
|
|
113
126
|
headless: values.headless,
|
package/src/login.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { log } from './format.js';
|
|
2
2
|
|
|
3
|
-
export async function loginToWordPress(page,
|
|
3
|
+
export async function loginToWordPress(page, adminUrl, user, pass) {
|
|
4
4
|
try {
|
|
5
|
-
await page.goto(`${
|
|
5
|
+
await page.goto(`${adminUrl}/wp-login.php`, {
|
|
6
6
|
waitUntil: 'domcontentloaded',
|
|
7
7
|
timeout: 30000,
|
|
8
8
|
});
|
|
9
9
|
await page.fill('#user_login', user);
|
|
10
10
|
await page.fill('#user_pass', pass);
|
|
11
11
|
await page.click('#wp-submit');
|
|
12
|
-
await page.waitForURL(
|
|
12
|
+
await page.waitForURL(/\/wp-admin\//, { timeout: 15000 });
|
|
13
13
|
return true;
|
|
14
14
|
} catch (error) {
|
|
15
15
|
log(`Login failed: ${error.message}`, 'red');
|
package/src/main.js
CHANGED
|
@@ -38,7 +38,7 @@ export async function main() {
|
|
|
38
38
|
const context = await browser.newContext({ viewport: options.viewport });
|
|
39
39
|
const page = await context.newPage();
|
|
40
40
|
page.setDefaultTimeout(60000);
|
|
41
|
-
const ok = await loginToWordPress(page, options.
|
|
41
|
+
const ok = await loginToWordPress(page, options.adminUrl, options.user, options.pass);
|
|
42
42
|
await page.close();
|
|
43
43
|
if (!ok) throw new Error('Failed to authenticate with WordPress');
|
|
44
44
|
return context;
|
|
@@ -94,13 +94,13 @@ async function validatePatternFile(patternPath, options, context) {
|
|
|
94
94
|
page.setDefaultTimeout(60000);
|
|
95
95
|
|
|
96
96
|
try {
|
|
97
|
-
const pageId = await createDraftPage(page, options.
|
|
97
|
+
const pageId = await createDraftPage(page, options.adminUrl);
|
|
98
98
|
if (pageId === null) {
|
|
99
99
|
return fail(patternName, startTime, 'page_creation_error', 'Failed to create test page');
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
if (!(await insertPatternIntoEditor(page, blockContent))) {
|
|
103
|
-
await deletePage(page, options.
|
|
103
|
+
await deletePage(page, options.adminUrl, pageId);
|
|
104
104
|
return fail(patternName, startTime, 'insertion_error', 'Failed to insert pattern into editor');
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -119,7 +119,7 @@ async function validatePatternFile(patternPath, options, context) {
|
|
|
119
119
|
saveResult.warnings.push(...comparison.warnings);
|
|
120
120
|
|
|
121
121
|
if (!options.keepPage) {
|
|
122
|
-
await deletePage(page, options.
|
|
122
|
+
await deletePage(page, options.adminUrl, pageId);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
return {
|
package/src/trellis.js
CHANGED
|
@@ -108,6 +108,26 @@ export function loadTrellisCredentials({ trellisDir, site, env = 'development',
|
|
|
108
108
|
? `${protocol}://${canonical}/${subsite}`
|
|
109
109
|
: `${protocol}://${canonical}`;
|
|
110
110
|
|
|
111
|
+
// For the main site, detect Bedrock's WP core subdir via WP_SITEURL in local .env.
|
|
112
|
+
// Bedrock puts WP core at /wp/, so admin ops must target /wp/wp-admin/ not /wp-admin/.
|
|
113
|
+
// Subsites are accessed at /<subsite>/wp-admin/ and don't carry the /wp/ prefix.
|
|
114
|
+
let adminUrl = url;
|
|
115
|
+
if (!subsite) {
|
|
116
|
+
const localPath = wordpressSites[siteKey].local_path;
|
|
117
|
+
if (localPath) {
|
|
118
|
+
const envFile = path.join(path.resolve(trellisDir, localPath), '.env');
|
|
119
|
+
if (fs.existsSync(envFile)) {
|
|
120
|
+
try {
|
|
121
|
+
const envContent = fs.readFileSync(envFile, 'utf8');
|
|
122
|
+
const match = envContent.match(/^WP_SITEURL=["']?(.+?)["']?\s*$/m);
|
|
123
|
+
if (match) adminUrl = match[1].trim();
|
|
124
|
+
} catch {
|
|
125
|
+
// Fall back to url
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
111
131
|
// Trellis admin username is always "admin" — not stored in the vault
|
|
112
|
-
return { url, user: 'admin', pass: adminPassword };
|
|
132
|
+
return { url, adminUrl, user: 'admin', pass: adminPassword };
|
|
113
133
|
}
|