@linchpinagency/skills 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 +337 -0
- package/bin/install.mjs +231 -0
- package/package.json +44 -0
- package/skills/browser-automation/SKILL.md +93 -0
- package/skills/commit-and-release/SKILL.md +135 -0
- package/skills/dependency-updates/SKILL.md +102 -0
- package/skills/design-previews/SKILL.md +118 -0
- package/skills/engagement-types/SKILL.md +108 -0
- package/skills/investigate/SKILL.md +95 -0
- package/skills/project-context/SKILL.md +89 -0
- package/skills/quality-gates/SKILL.md +94 -0
- package/skills/quality-gates/references/toolchain.md +104 -0
- package/skills/safety-hooks/SKILL.md +121 -0
- package/skills/safety-hooks/scripts/check-destructive.sh +80 -0
- package/skills/safety-hooks/scripts/check-edit-boundary.sh +65 -0
- package/skills/support-triage/SKILL.md +103 -0
- package/skills/task-tracking/SKILL.md +243 -0
- package/skills/web-qa/SKILL.md +108 -0
- package/skills/web-qa/references/qa-checklist.md +98 -0
- package/skills/wordpress-blocks/SKILL.md +110 -0
- package/skills/wordpress-blocks/references/block-grammar.md +94 -0
- package/skills/wordpress-blocks/references/core-blocks.md +123 -0
- package/skills/wordpress-blocks/references/patterns-and-parts.md +70 -0
- package/skills/wordpress-blocks/references/recipes/faq.md +56 -0
- package/skills/wordpress-blocks/references/recipes/hero.md +74 -0
- package/skills/wordpress-blocks/references/recipes/pricing-table.md +77 -0
- package/skills/wordpress-blocks/references/tool-contract.md +167 -0
- package/skills/wordpress-blocks/references/validation.md +38 -0
- package/skills/wp-audit/SKILL.md +115 -0
- package/skills/wp-block-conventions/SKILL.md +134 -0
- package/skills/wp-block-conventions/references/block-anatomy.md +175 -0
- package/skills/wp-implementation-choice/SKILL.md +88 -0
- package/skills/wp-local-setup/SKILL.md +262 -0
- package/skills/wp-pressable/SKILL.md +172 -0
- package/skills/wp-studio-cli/SKILL.md +165 -0
- package/skills/write-a-linchpin-skill/SKILL.md +195 -0
- package/skills/write-a-linchpin-skill/references/template.md +83 -0
- package/upstream.json +20 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wp-local-setup
|
|
3
|
+
description: Stand up the Linchpin baseline WordPress local environment — scaffold a new wp-content-shaped project repo (Composer-managed plugins from wpackagist.org + packagist.linchpin.com, a theme started from base-wp-theme-2026, release-please deploys) and/or wire a project repo into a WordPress Studio site by symlinking the repo in as the site's wp-content while preserving Studio's SQLite runtime pieces. Use when starting a new Linchpin WordPress project or setting up local development for an existing one.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# WordPress local setup (Linchpin baseline)
|
|
8
|
+
|
|
9
|
+
Every Linchpin WordPress project follows the same baseline, driven by three facts:
|
|
10
|
+
|
|
11
|
+
1. **The project repo IS `wp-content`.** The repo root contains `themes/`, `plugins/`
|
|
12
|
+
(and sometimes `mu-plugins/`) plus tooling — not a full WordPress install. WordPress
|
|
13
|
+
core is never committed.
|
|
14
|
+
2. **Local dev runs on [WordPress Studio](https://developer.wordpress.com/studio/).**
|
|
15
|
+
The Studio site's `wp-content` directory is replaced with a **symlink to the repo
|
|
16
|
+
checkout**, so edits in the repo are live on the local site instantly.
|
|
17
|
+
3. **Plugins and themes are Composer dependencies**, resolved from
|
|
18
|
+
[wpackagist.org](https://wpackagist.org) (wordpress.org mirrors) and
|
|
19
|
+
`https://packagist.linchpin.com` (private/premium packages, `linchpin/<slug>`).
|
|
20
|
+
Only project-specific code — the project theme and a client-functionality plugin —
|
|
21
|
+
is committed; everything else is gitignored and installed.
|
|
22
|
+
|
|
23
|
+
## When to use
|
|
24
|
+
|
|
25
|
+
**Use this when** you're starting a new WordPress project (scaffold the repo) or
|
|
26
|
+
setting up local development for an existing one (wire it into Studio).
|
|
27
|
+
|
|
28
|
+
**Not this for:**
|
|
29
|
+
|
|
30
|
+
- **Operating a running Studio site** (WP-CLI, credentials, `eval`) → `wp-studio-cli`.
|
|
31
|
+
- **Live servers** (Pressable prod/staging, deploy pipeline detail) → `wp-pressable`.
|
|
32
|
+
- **Seeding local content/database** → out of scope; follow that project's own docs.
|
|
33
|
+
- **One site's specific blocks/conventions** → that project's `AGENTS.md`/`CLAUDE.md`.
|
|
34
|
+
|
|
35
|
+
## Part 1 — Scaffold a new project repo
|
|
36
|
+
|
|
37
|
+
Target shape (the repo root doubles as `wp-content`):
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
<project>/
|
|
41
|
+
themes/<project>/ # committed — the project theme (from base-wp-theme-2026)
|
|
42
|
+
plugins/<project>-functionality/ # committed — client-functionality plugin (if needed)
|
|
43
|
+
composer.json # plugin/theme dependencies + PHP QA tooling
|
|
44
|
+
package.json # JS tooling (theme builds via @wordpress/scripts)
|
|
45
|
+
index.php # "Silence is golden."
|
|
46
|
+
phpcs.xml.dist # WordPress coding standards config
|
|
47
|
+
release-please-config.json # automated releases (see wp-pressable for the pipeline)
|
|
48
|
+
renovate.json # dependency automation
|
|
49
|
+
.gitignore # allowlist pattern — see below
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### composer.json baseline
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"name": "linchpin/<project>",
|
|
57
|
+
"repositories": [
|
|
58
|
+
{ "type": "composer", "url": "https://wpackagist.org" },
|
|
59
|
+
{ "type": "composer", "url": "https://packagist.linchpin.com" }
|
|
60
|
+
],
|
|
61
|
+
"require": {
|
|
62
|
+
"php": ">=8.2"
|
|
63
|
+
},
|
|
64
|
+
"require-dev": {
|
|
65
|
+
"composer/installers": "^2"
|
|
66
|
+
},
|
|
67
|
+
"extra": {
|
|
68
|
+
"installer-paths": {
|
|
69
|
+
"plugins/{$name}/": ["type:wordpress-plugin"],
|
|
70
|
+
"themes/{$name}/": ["type:wordpress-theme"]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- wordpress.org plugins/themes → `wpackagist-plugin/<slug>` / `wpackagist-theme/<slug>`.
|
|
77
|
+
- Premium or shared-private packages → `linchpin/<slug>` from packagist.linchpin.com.
|
|
78
|
+
- A plugin built **only for this client** is committed to `plugins/` instead (and
|
|
79
|
+
allowlisted in `.gitignore`).
|
|
80
|
+
- Which plugins a project needs is project-specific — don't copy another site's list.
|
|
81
|
+
- Mature projects add the PHP QA stack to `require-dev` (`wp-coding-standards/wpcs`,
|
|
82
|
+
`phpstan/phpstan` + `szepeviktor/phpstan-wordpress`, `php-parallel-lint/php-parallel-lint`,
|
|
83
|
+
`friendsofphp/php-cs-fixer`) — mirror `linchpin/linchpin.com` when setting that up.
|
|
84
|
+
|
|
85
|
+
### .gitignore baseline (allowlist pattern)
|
|
86
|
+
|
|
87
|
+
Ignore everything Composer or the runtime writes; explicitly re-include what's ours:
|
|
88
|
+
|
|
89
|
+
```gitignore
|
|
90
|
+
# Plugins/themes are Composer-installed — commit only project code
|
|
91
|
+
/plugins/*
|
|
92
|
+
!plugins/<project>-functionality/
|
|
93
|
+
!plugins/<project>-functionality/**
|
|
94
|
+
/themes/*
|
|
95
|
+
!themes/<project>/
|
|
96
|
+
!themes/<project>/**
|
|
97
|
+
/vendor
|
|
98
|
+
node_modules
|
|
99
|
+
|
|
100
|
+
# WordPress runtime
|
|
101
|
+
debug.log
|
|
102
|
+
/uploads/
|
|
103
|
+
/upgrade/
|
|
104
|
+
|
|
105
|
+
# WordPress Studio runtime (SQLite) — never commit these
|
|
106
|
+
db.php
|
|
107
|
+
/database
|
|
108
|
+
/mu-plugins/sqlite-database-integration
|
|
109
|
+
mu-plugins/99-studio-loader.php
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Adding a new **committed** plugin later requires a new `!plugins/<name>/` pair —
|
|
113
|
+
otherwise the `/plugins/*` rule silently keeps it out of git.
|
|
114
|
+
|
|
115
|
+
### The project theme
|
|
116
|
+
|
|
117
|
+
Start from the baseline theme, don't build from scratch:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
git clone https://github.com/linchpin/base-wp-theme-2026.git themes/<project>
|
|
121
|
+
rm -rf themes/<project>/.git
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Then rebrand: update `style.css` (`Theme Name`, `Theme URI`, `Description`,
|
|
125
|
+
`Text Domain`) and `package.json` (`name`), and search-replace the text domain in PHP
|
|
126
|
+
files. It's a block theme (`theme.json`, `templates/`, `parts/`, `patterns/`) built
|
|
127
|
+
with `@wordpress/scripts`:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cd themes/<project> && npm install && npm run build # npm start = watch mode
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Part 2 — Wire the repo into a Studio site
|
|
134
|
+
|
|
135
|
+
Prereq: the `studio` CLI on `PATH` (Studio app → **Settings → General → Studio CLI**),
|
|
136
|
+
and the repo cloned somewhere like `~/GitHub/<project>` — **not** inside `~/Studio`.
|
|
137
|
+
|
|
138
|
+
1. **Create a Studio site** for the project. Convention: site path `~/Studio/<project>`.
|
|
139
|
+
```bash
|
|
140
|
+
studio create --path ~/Studio/<project> --name "<Project>"
|
|
141
|
+
```
|
|
142
|
+
(The Studio app's **Add site** or the Studio MCP `site_create` work too.)
|
|
143
|
+
2. **Stop the site** before touching its filesystem:
|
|
144
|
+
```bash
|
|
145
|
+
studio stop --path ~/Studio/<project>
|
|
146
|
+
```
|
|
147
|
+
3. **Rescue Studio's SQLite runtime pieces** from the freshly provisioned
|
|
148
|
+
`wp-content` into the repo checkout (they're gitignored, so this is safe):
|
|
149
|
+
```bash
|
|
150
|
+
SITE=~/Studio/<project>; REPO=~/GitHub/<project>
|
|
151
|
+
mkdir -p "$REPO/mu-plugins"
|
|
152
|
+
cp "$SITE/wp-content/db.php" "$REPO/"
|
|
153
|
+
cp -R "$SITE/wp-content/mu-plugins/." "$REPO/mu-plugins/" # sqlite-database-integration
|
|
154
|
+
cp -R "$SITE/wp-content/database" "$REPO/" # .ht.sqlite lives here
|
|
155
|
+
```
|
|
156
|
+
(The trailing `/.` merges into an existing committed `mu-plugins/` dir instead of
|
|
157
|
+
nesting a second one inside it.)
|
|
158
|
+
Without these three the site cannot boot — Studio has no MySQL; the `db.php`
|
|
159
|
+
drop-in + SQLite mu-plugin **are** the database layer.
|
|
160
|
+
4. **Symlink the repo in as `wp-content`:**
|
|
161
|
+
```bash
|
|
162
|
+
mv "$SITE/wp-content" "$SITE/wp-content-studio-default" # keep as fallback
|
|
163
|
+
ln -s "$REPO" "$SITE/wp-content"
|
|
164
|
+
```
|
|
165
|
+
5. **Install dependencies and build:**
|
|
166
|
+
```bash
|
|
167
|
+
cd "$REPO" && composer install
|
|
168
|
+
cd themes/<project> && npm install && npm run build
|
|
169
|
+
```
|
|
170
|
+
6. **Start and activate:**
|
|
171
|
+
```bash
|
|
172
|
+
studio start --skip-browser --path ~/Studio/<project>
|
|
173
|
+
studio wp theme activate <project> --path ~/Studio/<project>
|
|
174
|
+
studio config set --debug-log --path ~/Studio/<project> # baseline: log to wp-content/debug.log
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
If the started site can't read the symlinked files (blank page, file-not-found
|
|
178
|
+
errors), allow PHP to follow the symlink out of the site directory:
|
|
179
|
+
`studio config set --file-access all-files --path ~/Studio/<project>`. The default
|
|
180
|
+
`site-directory` mode normally follows the symlink fine — this is a fallback only.
|
|
181
|
+
|
|
182
|
+
### Verify
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
studio site status --path ~/Studio/<project> --format json # URL + admin credentials
|
|
186
|
+
studio wp theme list --status=active --path ~/Studio/<project>
|
|
187
|
+
studio wp plugin list --path ~/Studio/<project> # Composer-installed plugins visible
|
|
188
|
+
studio wp eval 'echo ABSPATH;' --path ~/Studio/<project> # runtime answers
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Then load the site URL — a booted front page on the project theme means the wiring is
|
|
192
|
+
correct. From here, day-to-day operation is `wp-studio-cli`.
|
|
193
|
+
|
|
194
|
+
## Gotchas
|
|
195
|
+
|
|
196
|
+
- **`--path` targets the SITE, not the repo.** `studio` commands take
|
|
197
|
+
`~/Studio/<project>` (or run from that directory). The repo path only appears in the
|
|
198
|
+
symlink.
|
|
199
|
+
- **`wp-config.php` lives in the site root**, above `wp-content` — never in the repo.
|
|
200
|
+
Studio strips the MySQL `DB_*` constants; don't add them back, and don't reference
|
|
201
|
+
them in code (SQLite handles the connection via `db.php`).
|
|
202
|
+
- **Never commit the Studio runtime pieces** (`db.php`, `/database`,
|
|
203
|
+
`mu-plugins/sqlite-database-integration`). They're local-only; on a Pressable deploy
|
|
204
|
+
they would shadow the host's real MySQL setup.
|
|
205
|
+
- **Never delete them locally either** — the site dies without its database layer.
|
|
206
|
+
- **Composer writes into `plugins/` and `themes/`** (via `installer-paths`) and those
|
|
207
|
+
paths are gitignored — that's by design. CI runs `composer install` at deploy time;
|
|
208
|
+
a plugin "missing from git" is usually just Composer-managed.
|
|
209
|
+
- **The symlink cuts both ways:** edits in the repo are live immediately, but
|
|
210
|
+
`wp plugin update`/`wp plugin install` run against the live site also **write into
|
|
211
|
+
your repo checkout**. Manage plugin versions through `composer.json`, not the admin
|
|
212
|
+
or WP-CLI, or the next `composer install` reverts them.
|
|
213
|
+
- **Media isn't in git** (`/uploads/` is ignored). Getting real content/uploads locally
|
|
214
|
+
is per-project — check that project's docs.
|
|
215
|
+
|
|
216
|
+
## Quick reference
|
|
217
|
+
|
|
218
|
+
| Task | Command |
|
|
219
|
+
| --- | --- |
|
|
220
|
+
| Clone base theme | `git clone https://github.com/linchpin/base-wp-theme-2026.git themes/<project>` (then `rm -rf .git`, rebrand) |
|
|
221
|
+
| Install plugins | `composer install` (repo root) |
|
|
222
|
+
| Add a wordpress.org plugin | `composer require wpackagist-plugin/<slug>` |
|
|
223
|
+
| Add a premium/shared plugin | `composer require linchpin/<slug>` (packagist.linchpin.com) |
|
|
224
|
+
| Build the theme | `npm run build` in `themes/<project>` (`npm start` to watch) |
|
|
225
|
+
| Symlink repo into Studio | `mv <site>/wp-content <site>/wp-content-studio-default && ln -s <repo> <site>/wp-content` |
|
|
226
|
+
| Start the site | `studio start --skip-browser --path ~/Studio/<project>` |
|
|
227
|
+
| Activate the theme | `studio wp theme activate <project> --path ~/Studio/<project>` |
|
|
228
|
+
| Site URL + credentials | `studio site status --path ~/Studio/<project> --format json` |
|
|
229
|
+
|
|
230
|
+
## Guardrails
|
|
231
|
+
|
|
232
|
+
- **Never commit WordPress core, `wp-config.php`, or Studio's SQLite runtime**
|
|
233
|
+
(`db.php`, `/database`, `mu-plugins/sqlite-database-integration`) — on a real host they
|
|
234
|
+
shadow the live MySQL setup.
|
|
235
|
+
- **Never delete the Studio runtime pieces locally** either; the site dies without them.
|
|
236
|
+
- **Never move `wp-content` without preserving the original.** Rename it
|
|
237
|
+
(`wp-content-studio-default`) before symlinking, so the site can be restored.
|
|
238
|
+
- **Never manage plugin versions through the admin or `wp plugin update`** when the repo is
|
|
239
|
+
symlinked in — those writes land in your checkout and get reverted by the next
|
|
240
|
+
`composer install`. Versions change in `composer.json`.
|
|
241
|
+
- **Never commit Composer-installed plugins/themes** — `installer-paths` writes into
|
|
242
|
+
gitignored directories by design.
|
|
243
|
+
- Don't hand-edit versions or `CHANGELOG.md` in a scaffolded repo — release-please owns
|
|
244
|
+
them ([`commit-and-release`](../commit-and-release/SKILL.md)).
|
|
245
|
+
|
|
246
|
+
## Done
|
|
247
|
+
|
|
248
|
+
- [ ] Repo root is `wp-content`-shaped (`themes/`, `plugins/`, tooling) with no core files.
|
|
249
|
+
- [ ] `composer install` resolves all plugins from wpackagist / packagist.linchpin.com.
|
|
250
|
+
- [ ] The Studio site's `wp-content` is a symlink to the repo, with the original preserved
|
|
251
|
+
and the SQLite runtime pieces intact.
|
|
252
|
+
- [ ] The site loads, the project theme is active, and the admin URL/credentials are known.
|
|
253
|
+
- [ ] `.gitignore` allowlists only project code; `git status` is clean of vendored plugins.
|
|
254
|
+
|
|
255
|
+
## Related skills
|
|
256
|
+
|
|
257
|
+
- [`wp-studio-cli`](../wp-studio-cli/SKILL.md) — operating the running Studio site (WP-CLI
|
|
258
|
+
passthrough, `eval`, the PHP-WASM `ABSPATH` rule).
|
|
259
|
+
- [`wp-pressable`](../wp-pressable/SKILL.md) — the hosted environments this baseline deploys
|
|
260
|
+
to, and the release-please → `linchpin/actions` pipeline.
|
|
261
|
+
- [`task-tracking`](../task-tracking/SKILL.md) — tie the setup work to a ClickUp task before
|
|
262
|
+
committing.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wp-pressable
|
|
3
|
+
description: Operate a Pressable-hosted WordPress site (production or staging) from an agent — connect via the Pressable MCP or SSH+WP-CLI, run read-first diagnostics, and safely fix the classic "renders locally but not on production" Full-Site-Editing bug where database template/part overrides shadow the deployed theme files. Use for any WordPress project hosted on Pressable when you need to inspect or change the live server (not just the repo).
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# WordPress on Pressable (agent operations)
|
|
8
|
+
|
|
9
|
+
[Pressable](https://pressable.com/) is Automattic's managed WordPress host. Code reaches it
|
|
10
|
+
through a deploy pipeline (Linchpin convention: `release-please` → a published GitHub
|
|
11
|
+
Release → `linchpin/actions` deploy workflow), while the **database lives only on the
|
|
12
|
+
server**. Two facts drive everything in this skill:
|
|
13
|
+
|
|
14
|
+
1. **Change code by deploying, never by editing files on the server.** The next deploy
|
|
15
|
+
overwrites server files.
|
|
16
|
+
2. **Change content/templates by operating on the server database** (MCP or SSH+WP-CLI),
|
|
17
|
+
because **deploys never touch the database**.
|
|
18
|
+
|
|
19
|
+
Most "I shipped it but it's not on prod" tickets are a collision of those two facts. See
|
|
20
|
+
[The signature bug](#the-signature-bug-it-shows-locally-but-not-on-production).
|
|
21
|
+
|
|
22
|
+
## When to use
|
|
23
|
+
|
|
24
|
+
**Use this when** you need to inspect or change a **live Pressable environment**
|
|
25
|
+
(production or staging) — its database, templates/parts, caches, users, or runtime state —
|
|
26
|
+
via the Pressable MCP or SSH+WP-CLI.
|
|
27
|
+
|
|
28
|
+
**Not this for:**
|
|
29
|
+
|
|
30
|
+
- **Local development** → use `wp-studio-cli` (Studio / PHP-WASM).
|
|
31
|
+
- **Shipping code** → code reaches Pressable only through the deploy pipeline; never edit
|
|
32
|
+
theme/plugin files on the server (the next deploy overwrites them).
|
|
33
|
+
- **Task tracking / commits** → that's `task-tracking`.
|
|
34
|
+
|
|
35
|
+
This skill operates the **server and its database** — nothing else.
|
|
36
|
+
|
|
37
|
+
## Two ways in
|
|
38
|
+
|
|
39
|
+
### A) Pressable MCP (preferred when connected)
|
|
40
|
+
|
|
41
|
+
A remote MCP server at `https://mcp.pressable.com/mcp`, authenticated with a bearer token.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Native HTTP transport — cleaner than the mcp-remote wrapper.
|
|
45
|
+
claude mcp add --transport http pressable https://mcp.pressable.com/mcp \
|
|
46
|
+
--header "Authorization: Bearer <TOKEN>"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- **Quote the whole header as one argument.** A common footgun is
|
|
50
|
+
`--header Authorization:Bearer <TOKEN>` (no space / unquoted) — the shell splits it into
|
|
51
|
+
separate argv tokens and the server gets a malformed header, then fails to connect.
|
|
52
|
+
- **Restart to connect.** MCP servers connect at agent **startup**. After adding/rotating,
|
|
53
|
+
restart the session, then confirm with `claude mcp list` → `pressable … ✔ Connected`.
|
|
54
|
+
- **`401 Invalid Authorization token` = dead token.** Regenerate it from your Pressable
|
|
55
|
+
account and re-add the server. Verify a token fast without restarting:
|
|
56
|
+
```bash
|
|
57
|
+
curl -s -o /dev/null -w '%{http_code}\n' -X POST https://mcp.pressable.com/mcp \
|
|
58
|
+
-H "Authorization: Bearer <TOKEN>" -H "Content-Type: application/json" \
|
|
59
|
+
-H "Accept: application/json, text/event-stream" \
|
|
60
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"diag","version":"1"}}}'
|
|
61
|
+
# 200 = good, 401 = regenerate the token
|
|
62
|
+
```
|
|
63
|
+
- **Don't leave the raw token in `~/.claude.json`.** Pull it from a secret manager
|
|
64
|
+
(1Password, etc.). The token grants control of the host.
|
|
65
|
+
|
|
66
|
+
### B) SSH + WP-CLI (always available; the fallback and the scripting route)
|
|
67
|
+
|
|
68
|
+
When the MCP is down (or you want deterministic, scriptable fixes), use SSH.
|
|
69
|
+
|
|
70
|
+
- Get SSH/SFTP credentials from the Pressable dashboard (**Sites → <site> → SSH/SFTP**).
|
|
71
|
+
- Connect; you land in the site root with `wp` on `PATH`. Confirm: `wp --info`.
|
|
72
|
+
- Everything below is plain WP-CLI, so it works identically whether you reach `wp` over SSH
|
|
73
|
+
or through the MCP's WP-CLI tool.
|
|
74
|
+
|
|
75
|
+
## Guardrails
|
|
76
|
+
|
|
77
|
+
- **It's production.** Confirm with the user before any mutating action on a live prod
|
|
78
|
+
site; lead with read-only diagnostics and back up first.
|
|
79
|
+
- **Read before write.** List and inspect first; mutate only after you've confirmed the
|
|
80
|
+
cause.
|
|
81
|
+
- **Back up before any DB change:** `wp db export ~/backup-$(date +%F-%H%M).sql`.
|
|
82
|
+
- **Never edit theme/plugin files on the server** — deploys overwrite them. File changes go
|
|
83
|
+
through the repo + deploy pipeline.
|
|
84
|
+
- **Flush caches after content/DB changes.** Pressable runs object + edge (page) cache:
|
|
85
|
+
`wp cache flush`, then clear the page cache from the Pressable dashboard (or
|
|
86
|
+
`wp pressable-cache clear` if the helper plugin is present). Stale cache makes a correct
|
|
87
|
+
fix look like it didn't work.
|
|
88
|
+
|
|
89
|
+
## The signature bug: "it shows locally but not on production"
|
|
90
|
+
|
|
91
|
+
**Symptom.** A block / pattern / section lives in the theme's template **files** and renders
|
|
92
|
+
on your local site, but is missing on the Pressable site — even though the theme and plugin
|
|
93
|
+
are deployed.
|
|
94
|
+
|
|
95
|
+
**Cause.** In block (Full-Site-Editing) themes, the moment a template or template part is
|
|
96
|
+
edited in the Site Editor, WordPress writes a copy to the database (a `wp_template` or
|
|
97
|
+
`wp_template_part` post) and **that DB copy permanently shadows the theme file**. Deploys
|
|
98
|
+
ship files, not the DB — so a block you added to the file never appears, because the server
|
|
99
|
+
keeps serving the older DB copy.
|
|
100
|
+
|
|
101
|
+
**Diagnose (read-only):**
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# 1. Is the code actually deployed? (rules out a stale release)
|
|
105
|
+
wp plugin get <plugin-slug> --field=version
|
|
106
|
+
wp eval 'var_export( WP_Block_Type_Registry::get_instance()->is_registered("<namespace/block>") );'
|
|
107
|
+
# -> false or an old version => deploy problem, not a DB problem. Ship/redeploy.
|
|
108
|
+
|
|
109
|
+
# 2. Which templates/parts are DB overrides that shadow the files?
|
|
110
|
+
wp post list --post_type=wp_template --post_status=any --fields=ID,post_name,post_title
|
|
111
|
+
wp post list --post_type=wp_template_part --post_status=any --fields=ID,post_name,post_title
|
|
112
|
+
# -> a row for the template that should show the block (e.g. front-page, page, home) is an override.
|
|
113
|
+
|
|
114
|
+
# 3. Confirm the override is what's hiding it
|
|
115
|
+
wp eval 'echo has_block("<namespace/block>", get_post(<ID>)->post_content) ? "HAS" : "MISSING";'
|
|
116
|
+
# -> "MISSING" confirms the stale DB copy is the culprit.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**Fix (pick one):**
|
|
120
|
+
|
|
121
|
+
- **Clean revert to the deployed file** (recommended when templates are version-controlled
|
|
122
|
+
in the repo): delete the DB override so WordPress falls back to the theme file, which
|
|
123
|
+
already has the block in the right place.
|
|
124
|
+
```bash
|
|
125
|
+
wp post delete <ID> --force # repeat per template
|
|
126
|
+
```
|
|
127
|
+
⚠️ This discards **all** Site-Editor edits to that template, reverting it entirely to the
|
|
128
|
+
repo's file. Admin equivalent: **Appearance → Editor → Templates → ⋯ → Clear
|
|
129
|
+
customizations**.
|
|
130
|
+
- **Surgical** (when production has intentional Site-Editor-only edits you must keep): add
|
|
131
|
+
the block in the Site Editor, or `wp post update <ID>` the override's `post_content`,
|
|
132
|
+
instead of deleting.
|
|
133
|
+
|
|
134
|
+
Then `wp cache flush` and clear the Pressable page cache.
|
|
135
|
+
|
|
136
|
+
## Deploy & rollback awareness (Linchpin convention)
|
|
137
|
+
|
|
138
|
+
- `main` → `release-please` opens a release PR → merging it **publishes a GitHub Release** →
|
|
139
|
+
`linchpin/actions` deploy workflow builds and deploys to Pressable (`environment:
|
|
140
|
+
production`), attaching a `release.zip`.
|
|
141
|
+
- **Staging** deploys on push to the `staging` branch.
|
|
142
|
+
- **Rollback** re-deploys a previous `release.zip` (no rebuild) via the repo's
|
|
143
|
+
`rollback.yml` workflow.
|
|
144
|
+
- **Implication:** a **code** fix is not live until a release is published and deployed — a
|
|
145
|
+
merge to `main` alone is not on prod. A **content/template** fix is applied directly on
|
|
146
|
+
the server (MCP/SSH), as above, and is independent of deploys.
|
|
147
|
+
|
|
148
|
+
## Quick reference
|
|
149
|
+
|
|
150
|
+
| Task | Command |
|
|
151
|
+
| --- | --- |
|
|
152
|
+
| Add the MCP | `claude mcp add --transport http pressable https://mcp.pressable.com/mcp --header "Authorization: Bearer <TOKEN>"` |
|
|
153
|
+
| Verify MCP connects | `claude mcp list` → `pressable … ✔ Connected` (restart session after adding) |
|
|
154
|
+
| SSH in | dashboard **Sites → <site> → SSH/SFTP**, then `wp --info` |
|
|
155
|
+
| Back up DB | `wp db export ~/backup-$(date +%F-%H%M).sql` |
|
|
156
|
+
| Deployed plugin version | `wp plugin get <plugin> --field=version` |
|
|
157
|
+
| Is a block registered | `wp eval 'var_export( WP_Block_Type_Registry::get_instance()->is_registered("<ns/block>") );'` |
|
|
158
|
+
| List template overrides | `wp post list --post_type=wp_template --post_status=any --fields=ID,post_name,post_title` |
|
|
159
|
+
| List part overrides | `wp post list --post_type=wp_template_part --post_status=any --fields=ID,post_name,post_title` |
|
|
160
|
+
| Override has block? | `wp eval 'echo has_block("<ns/block>", get_post(<ID>)->post_content) ? "HAS" : "MISSING";'` |
|
|
161
|
+
| Revert template to file | `wp post delete <ID> --force` (wipes that template's Site-Editor edits) |
|
|
162
|
+
| Flush caches | `wp cache flush` + clear page cache in the Pressable dashboard |
|
|
163
|
+
|
|
164
|
+
## Done
|
|
165
|
+
|
|
166
|
+
- [ ] The environment you touched (production vs staging) is stated explicitly.
|
|
167
|
+
- [ ] Diagnosis ran read-only first, and the cause is named — deploy gap vs DB override.
|
|
168
|
+
- [ ] Any DB change was preceded by `wp db export` and confirmed with the user.
|
|
169
|
+
- [ ] No theme or plugin file was edited on the server.
|
|
170
|
+
- [ ] Object and page caches flushed, and the fix verified on the live URL.
|
|
171
|
+
- [ ] If the fix belongs in code, it's tracked back to the repo and the deploy pipeline —
|
|
172
|
+
the server change is not the permanent fix.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wp-studio-cli
|
|
3
|
+
description: Operate a local WordPress Studio site — preferring the wordpress-studio MCP (site_list, site_start, wp_cli, validate_blocks, take_screenshot, inspect_design) and falling back to the `studio` CLI when MCP isn't connected. Use whenever working against a Linchpin local dev install, running WP-CLI locally, reading admin credentials, validating block markup, or screenshotting a local site. Studio runs PHP-WASM, so file paths inside `wp eval` must use ABSPATH (resolves to /wordpress/), never host filesystem paths.
|
|
4
|
+
version: 1.1.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# WordPress Studio
|
|
8
|
+
|
|
9
|
+
[WordPress Studio](https://developer.wordpress.com/studio/) is **Linchpin's default local
|
|
10
|
+
environment**, running each site in a **PHP-WASM** runtime. Older projects still on wp-env
|
|
11
|
+
or LocalWP predate that switch — new work is Studio.
|
|
12
|
+
|
|
13
|
+
Two interfaces reach the same site: the **wordpress-studio MCP** (structured tools, richer
|
|
14
|
+
capabilities) and the **`studio` CLI** (always present with the app). Prefer MCP; the CLI is
|
|
15
|
+
the fallback and the scripting route.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
- Running WP-CLI, inspecting options/posts, or evaluating PHP against a local Studio site.
|
|
20
|
+
- Needing the site's admin URL or credentials.
|
|
21
|
+
- Validating serialized block markup, or screenshotting a local page.
|
|
22
|
+
- Reproducing a bug locally before touching a server.
|
|
23
|
+
|
|
24
|
+
**Not this skill:** creating the site or symlinking a repo into it —
|
|
25
|
+
[`wp-local-setup`](../wp-local-setup/SKILL.md). Live servers —
|
|
26
|
+
[`wp-pressable`](../wp-pressable/SKILL.md). Performance/accessibility audits —
|
|
27
|
+
[`wp-audit`](../wp-audit/SKILL.md). A legacy project on wp-env or LocalWP — use that
|
|
28
|
+
project's tooling ([`quality-gates`](../quality-gates/SKILL.md) detects which).
|
|
29
|
+
|
|
30
|
+
## Preflight — pick the interface
|
|
31
|
+
|
|
32
|
+
1. **Try MCP first.** A cheap call like `site_list` confirms it's connected.
|
|
33
|
+
2. **Fall back to the CLI** when MCP is absent, erroring, or you need something scriptable
|
|
34
|
+
in a shell pipeline: `studio site list`.
|
|
35
|
+
3. **If neither works**, say so — Studio isn't installed or the CLI isn't enabled. Don't
|
|
36
|
+
guess at site paths.
|
|
37
|
+
|
|
38
|
+
Whichever you use, **resolve the target site explicitly**. Never assume the current
|
|
39
|
+
directory is the site.
|
|
40
|
+
|
|
41
|
+
## MCP tools (preferred)
|
|
42
|
+
|
|
43
|
+
| Need | Tool |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| List sites, find paths/URLs | `site_list` |
|
|
46
|
+
| Site detail, admin credentials | `site_info` |
|
|
47
|
+
| Start / stop a site | `site_start`, `site_stop` |
|
|
48
|
+
| Run any WP-CLI command | `wp_cli` |
|
|
49
|
+
| Validate serialized block markup | `validate_blocks` |
|
|
50
|
+
| Screenshot a page | `take_screenshot` |
|
|
51
|
+
| Inspect rendered DOM / computed styles | `inspect_design` |
|
|
52
|
+
| Push/pull against a connected remote | `site_push`, `site_pull` |
|
|
53
|
+
|
|
54
|
+
`wp_cli` is the general-purpose escape hatch — anything the CLI can do, it can do. Reach for
|
|
55
|
+
a shell only when you need to pipe output into other commands.
|
|
56
|
+
|
|
57
|
+
**`site_push` / `site_pull` move real data.** Treat them like a deploy: confirm the direction
|
|
58
|
+
and the target with the user first, and never push to a production-connected site from here.
|
|
59
|
+
|
|
60
|
+
## CLI fallback
|
|
61
|
+
|
|
62
|
+
Every `studio` command takes a global `--path` pointing at the site's WordPress files. It
|
|
63
|
+
**defaults to the current directory**, so `cd` in or pass `--path`. Running outside a
|
|
64
|
+
registered site path fails with "The specified directory is not added to Studio."
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
studio site list # names, paths, URLs, online status
|
|
68
|
+
studio site start --path ~/Studio/<site> # a site must be Online for `wp`
|
|
69
|
+
studio site status --path ~/Studio/<site> --format json # adminUsername/adminPassword/URL
|
|
70
|
+
studio wp <args> --path ~/Studio/<site> # full WP-CLI passthrough
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Eval PHP — and the ABSPATH rule
|
|
74
|
+
|
|
75
|
+
This applies to **both** interfaces — MCP `wp_cli` and `studio wp` run in the same runtime.
|
|
76
|
+
|
|
77
|
+
> **The PHP-WASM runtime cannot see your host filesystem.** Inside `eval`, file paths must
|
|
78
|
+
> be WASM paths. Use the `ABSPATH` constant, which resolves to `/wordpress/` — not
|
|
79
|
+
> `/Users/...` host paths.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# ✅ correct — ABSPATH-relative path inside the WASM FS
|
|
83
|
+
studio wp eval 'echo ABSPATH;' --path ~/Studio/<site>
|
|
84
|
+
# -> /wordpress/
|
|
85
|
+
|
|
86
|
+
# ✅ read/render a theme file from inside the site
|
|
87
|
+
studio wp eval 'echo file_get_contents(ABSPATH . "wp-content/themes/<theme>/style.css");' \
|
|
88
|
+
--path ~/Studio/<site>
|
|
89
|
+
|
|
90
|
+
# ❌ wrong — a host path is invisible to PHP-WASM and returns nothing/false
|
|
91
|
+
studio wp eval 'echo file_get_contents("/Users/me/Documents/GitHub/<repo>/themes/<theme>/style.css");' \
|
|
92
|
+
--path ~/Studio/<site>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Even when Studio **hardlinks** `wp-content/themes/<x>` and `wp-content/plugins/<x>` from a
|
|
96
|
+
host repo (so editor changes show up live), the PHP runtime still resolves them only via
|
|
97
|
+
WASM/`ABSPATH` paths.
|
|
98
|
+
|
|
99
|
+
To operate on host files (grep, list, edit), use ordinary shell tools against the **repo
|
|
100
|
+
path**; switch to `eval` + `ABSPATH` only when the running site must read or execute them.
|
|
101
|
+
|
|
102
|
+
## Common recipes
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Render a block pattern's PHP to inspect its output
|
|
106
|
+
studio wp eval 'ob_start(); include ABSPATH . "wp-content/themes/<theme>/patterns/<name>.php"; echo ob_get_clean();' \
|
|
107
|
+
--path ~/Studio/<site>
|
|
108
|
+
|
|
109
|
+
# Flush rewrite rules / caches after changes
|
|
110
|
+
studio wp rewrite flush --path ~/Studio/<site>
|
|
111
|
+
studio wp cache flush --path ~/Studio/<site>
|
|
112
|
+
|
|
113
|
+
# Search-replace a URL across the DB (dry run first!)
|
|
114
|
+
studio wp search-replace 'http://old.test' 'https://new.test' --dry-run --path ~/Studio/<site>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Gotchas
|
|
118
|
+
|
|
119
|
+
- **Deprecation noise:** Studio's WP-CLI may print `Deprecated: Case statements followed
|
|
120
|
+
by a semicolon …` lines (from a bundled dependency). They're benign — the real result is
|
|
121
|
+
still on stdout. When scripting, parse stdout and ignore stderr (`2>/dev/null`), and be
|
|
122
|
+
ready to strip a stray leading/trailing deprecation line.
|
|
123
|
+
- **`--path` is required** on the CLI unless you `cd` into the site directory first.
|
|
124
|
+
- **Site must be Online** before `wp` — `site_start` or `studio site start`.
|
|
125
|
+
- **Block markup gets validated, not eyeballed.** When you write serialized block markup
|
|
126
|
+
into templates or content, run `validate_blocks` and repair until clean — see
|
|
127
|
+
[`wordpress-blocks`](../wordpress-blocks/SKILL.md).
|
|
128
|
+
|
|
129
|
+
## Quick reference
|
|
130
|
+
|
|
131
|
+
| Task | MCP | CLI fallback |
|
|
132
|
+
| --- | --- | --- |
|
|
133
|
+
| List sites + paths | `site_list` | `studio site list` |
|
|
134
|
+
| Start a site | `site_start` | `studio site start --path ~/Studio/<site>` |
|
|
135
|
+
| Admin user/pass | `site_info` | `studio site status --path … --format json` |
|
|
136
|
+
| Run WP-CLI | `wp_cli` | `studio wp <args> --path ~/Studio/<site>` |
|
|
137
|
+
| Eval PHP | `wp_cli` (`eval`, use `ABSPATH`) | `studio wp eval '<php>' --path …` |
|
|
138
|
+
| Validate blocks | `validate_blocks` | — |
|
|
139
|
+
| Screenshot | `take_screenshot` | — |
|
|
140
|
+
|
|
141
|
+
## Guardrails
|
|
142
|
+
|
|
143
|
+
- **Never use host paths inside `eval`** — PHP-WASM can't see them and returns `false`
|
|
144
|
+
rather than an error, which reads as "the file is empty" and sends you debugging the wrong
|
|
145
|
+
thing. Always build paths from `ABSPATH`.
|
|
146
|
+
- **`--dry-run` first** on anything that rewrites the database (`search-replace`, bulk
|
|
147
|
+
`wp post` operations). A local site is cheap to break but expensive to re-seed.
|
|
148
|
+
- **Never `site_push`** without explicit confirmation of direction and target — it writes to
|
|
149
|
+
a remote site.
|
|
150
|
+
- **Don't edit files through the site directory** when `wp-content` is a symlink to a repo
|
|
151
|
+
checkout — edit the repo, which is the same files with git history attached.
|
|
152
|
+
- **Don't treat a green local result as a production result.** Studio runs SQLite and
|
|
153
|
+
PHP-WASM; MySQL-specific behavior and server caches differ. Verify on the server via
|
|
154
|
+
[`wp-pressable`](../wp-pressable/SKILL.md) when it matters.
|
|
155
|
+
- Don't fabricate output when a command prints deprecation noise — parse stdout, and say so
|
|
156
|
+
if a command produced nothing.
|
|
157
|
+
|
|
158
|
+
## Done
|
|
159
|
+
|
|
160
|
+
- [ ] Interface chosen deliberately — MCP tried first, CLI fallback only if needed.
|
|
161
|
+
- [ ] The target site was resolved explicitly, not assumed from the working directory.
|
|
162
|
+
- [ ] The site was Online before running `wp`.
|
|
163
|
+
- [ ] Any `eval` path is `ABSPATH`-relative.
|
|
164
|
+
- [ ] Destructive DB commands were dry-run first; no unconfirmed `site_push`.
|
|
165
|
+
- [ ] Reported output is what the command actually returned, deprecation noise excluded.
|