@respira/wordpress-mcp-server 8.1.5 → 8.1.6

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/CHANGELOG.md CHANGED
@@ -5,6 +5,16 @@ All notable changes to Respira WordPress MCP Server will be documented in this f
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [8.1.6] - 2026-08-02
9
+
10
+ ### Fixed
11
+
12
+ - **An authentication failure was reported as "respira/v2 is not available on this site".** The version probe swallowed its own error and fell back to v1, so every failure mode reached you as the same message followed by four suggested causes: a security plugin, Plain permalinks, a WAF or CDN, an outdated plugin. For M.O. all four were false. Permalinks were `/%postname%/`, there was no CDN, the plugin was already current, and `/wp-json/respira/v2/status` was answering `401` rather than `404`, which proves the opposite of what the message said: the route existed, WordPress routed to it, and it ran far enough to reach its auth check. That cost most of a day chasing firewall rules for a deactivated key. The probe now keeps the reason and reports it. A `401` or `403` says the key was rejected and points at reconnecting, a `5xx` reports the status and sends you to the debug log, a connection failure says so, and the original text is kept only for a real `404`, which is the one case it was ever true for.
13
+
14
+ ### Added
15
+
16
+ - **`excerpt` on `update_page`, `update_post` and `update_custom_post`.** There was no way to ask for it, so callers put it in `meta`, where it became a post meta row that reads back perfectly and renders nowhere. The description says as much. Requires plugin 8.2.1 for the write to land in the native field. Reported by P.F.
17
+
8
18
  ## [8.1.5] - 2026-08-01
9
19
 
10
20
  ### Fixed
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=v2-negotiation-failure.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-negotiation-failure.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/v2-negotiation-failure.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,104 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { classifyV2Failure, describeV2Failure } from '../wordpress-client.js';
4
+ /**
5
+ * The v2 probe used to swallow its own error:
6
+ *
7
+ * try { ...get('/wp-json/respira/v2/status')... } catch { }
8
+ * return 'v1'
9
+ *
10
+ * so every failure mode reached the user as one message: "respira/v2 is not
11
+ * available on this site", followed by four suggested causes (security plugin,
12
+ * Plain permalinks, WAF/CDN, outdated plugin).
13
+ *
14
+ * M.O. hit this with a 401. All four suggestions were false: permalinks were
15
+ * /%postname%/, there was no CDN, the plugin was on the newest version, and
16
+ * /wp-json/respira/v2/status answered 401 rather than 404 — meaning the route
17
+ * existed, WordPress routed to it, and it ran far enough to reach its auth
18
+ * check. The message described the one situation that provably was not
19
+ * happening, and cost most of a day.
20
+ */
21
+ const SITE = 'https://example.com';
22
+ const err = (status, data) => ({ response: { status, data } });
23
+ describe('classifyV2Failure', () => {
24
+ it('401 is auth, not a missing namespace', () => {
25
+ const f = classifyV2Failure(err(401, { code: 'respira_invalid_site_token', message: 'token out of date' }));
26
+ assert.equal(f.kind, 'auth');
27
+ assert.equal(f.status, 401);
28
+ assert.equal(f.code, 'respira_invalid_site_token');
29
+ });
30
+ it('403 is auth too', () => {
31
+ assert.equal(classifyV2Failure(err(403)).kind, 'auth');
32
+ });
33
+ it('404 is the one case that really means unavailable', () => {
34
+ assert.equal(classifyV2Failure(err(404)).kind, 'missing');
35
+ });
36
+ it('500 is a server fault, distinct from both', () => {
37
+ assert.equal(classifyV2Failure(err(500)).kind, 'server');
38
+ });
39
+ it('no response at all is a network failure', () => {
40
+ assert.equal(classifyV2Failure({ message: 'ECONNREFUSED' }).kind, 'network');
41
+ });
42
+ it('an undefined error does not throw', () => {
43
+ assert.equal(classifyV2Failure(undefined).kind, 'network');
44
+ });
45
+ });
46
+ describe('describeV2Failure', () => {
47
+ it("the auth message does NOT repeat the four causes that misled the reporter", () => {
48
+ const msg = describeV2Failure(classifyV2Failure(err(401)), SITE);
49
+ assert.ok(!/Wordfence/.test(msg), msg);
50
+ assert.ok(!/permalinks/i.test(msg), msg);
51
+ assert.ok(!/Cloudflare/.test(msg), msg);
52
+ assert.ok(!/outdated/i.test(msg), msg);
53
+ });
54
+ it('the auth message states what a 401 actually proves', () => {
55
+ const msg = describeV2Failure(classifyV2Failure(err(401)), SITE);
56
+ assert.ok(/routes exist and are reachable/.test(msg), msg);
57
+ assert.ok(/authentication result, not a missing namespace/.test(msg), msg);
58
+ });
59
+ it('it names the deactivated-key cause, which is the one that actually happened', () => {
60
+ const msg = describeV2Failure(classifyV2Failure(err(401)), SITE);
61
+ assert.ok(/lapsed licence disables API keys/.test(msg), msg);
62
+ assert.ok(/reconnect the site/i.test(msg), msg);
63
+ });
64
+ it("it quotes the site's own words when they were given", () => {
65
+ const msg = describeV2Failure(classifyV2Failure(err(401, { message: 'The saved connection token for this site is out of date.' })), SITE);
66
+ assert.ok(msg.includes('The saved connection token for this site is out of date.'), msg);
67
+ });
68
+ it('a real 404 keeps the original guidance, which is correct for a 404', () => {
69
+ const msg = describeV2Failure(classifyV2Failure(err(404)), SITE);
70
+ assert.ok(/is not available on this site/.test(msg), msg);
71
+ assert.ok(/Wordfence/.test(msg), msg);
72
+ });
73
+ it('a null failure falls back to the 404 text rather than inventing a cause', () => {
74
+ const msg = describeV2Failure(null, SITE);
75
+ assert.ok(/is not available on this site/.test(msg), msg);
76
+ });
77
+ it('the server branch reports the status instead of blaming the namespace', () => {
78
+ const msg = describeV2Failure(classifyV2Failure(err(500, { message: 'Fatal error' })), SITE);
79
+ assert.ok(/HTTP 500/.test(msg), msg);
80
+ assert.ok(/debug\.log/.test(msg), msg);
81
+ assert.ok(!/Wordfence/.test(msg), msg);
82
+ });
83
+ it('the network branch says connectivity, not configuration', () => {
84
+ const msg = describeV2Failure(classifyV2Failure({ message: 'ETIMEDOUT' }), SITE);
85
+ assert.ok(/connectivity failure, not a plugin problem/.test(msg), msg);
86
+ assert.ok(msg.includes('ETIMEDOUT'), msg);
87
+ });
88
+ it('branches where probing helps point at the probe URL for the specific site', () => {
89
+ // Not the auth branch: /v2/status answers 401 to an unauthenticated browser
90
+ // whether or not the key is the problem, so sending someone there proves
91
+ // nothing. Its next step is reconnecting, asserted above.
92
+ for (const e of [err(404), err(500), { message: 'x' }]) {
93
+ const msg = describeV2Failure(classifyV2Failure(e), SITE);
94
+ assert.ok(msg.includes(`${SITE}/wp-json/respira/v2/status`), msg);
95
+ }
96
+ });
97
+ it('no branch ever tells the reader the namespace is missing when it is not', () => {
98
+ for (const e of [err(401), err(403), err(500), { message: 'x' }]) {
99
+ const msg = describeV2Failure(classifyV2Failure(e), SITE);
100
+ assert.ok(!/is not available on this site/.test(msg), msg);
101
+ }
102
+ });
103
+ });
104
+ //# sourceMappingURL=v2-negotiation-failure.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-negotiation-failure.test.js","sourceRoot":"","sources":["../../src/__tests__/v2-negotiation-failure.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=v2-negotiation-through-real-client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-negotiation-through-real-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/v2-negotiation-through-real-client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,104 @@
1
+ import { describe, it, after } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import http from 'node:http';
4
+ import { WordPressClient } from '../wordpress-client.js';
5
+ /**
6
+ * The check the pure-unit tests structurally cannot make.
7
+ *
8
+ * v2-negotiation-failure.test.ts feeds classifyV2Failure a hand-built
9
+ * `{response:{status:401}}`. In production no such object ever reaches it: the
10
+ * shared axios error interceptor funnels every non-2xx through handleError ->
11
+ * codedError, which returns `new Error(message)` with the status recorded only
12
+ * in `.name`. `.response` is gone.
13
+ *
14
+ * So an implementation that reads `error.response.status` passes every unit
15
+ * test and misclassifies *every real failure* as a network problem — telling a
16
+ * customer with a deactivated key that the site could not be reached. That is
17
+ * the same trap that made the first PUT->POST fallback fix a no-op (it needed
18
+ * isRetryableAsPost() matching on `.name` for exactly this reason).
19
+ *
20
+ * These tests run a real HTTP server, a real WordPressClient with its real
21
+ * interceptors, and assert on the message a user would actually see.
22
+ */
23
+ const servers = [];
24
+ after(() => {
25
+ for (const s of servers)
26
+ s.close();
27
+ });
28
+ /** Start a server that answers the v2 status probe with a fixed status. */
29
+ async function clientAnswering(status, body) {
30
+ const server = http.createServer((_req, res) => {
31
+ res.writeHead(status, { 'Content-Type': 'application/json' });
32
+ res.end(JSON.stringify(body));
33
+ });
34
+ servers.push(server);
35
+ await new Promise((resolve) => server.listen(0, resolve));
36
+ const { port } = server.address();
37
+ return new WordPressClient({
38
+ id: 'probe',
39
+ name: 'probe',
40
+ url: `http://127.0.0.1:${port}`,
41
+ apiKey: 'respira_test_key',
42
+ });
43
+ }
44
+ /** Drive a v2-gated call and return the message the user would see. */
45
+ async function v2FailureMessage(client) {
46
+ try {
47
+ await client.listSnapshots({ post_id: 1 });
48
+ return '(no error thrown)';
49
+ }
50
+ catch (err) {
51
+ return String(err?.message ?? err);
52
+ }
53
+ }
54
+ describe('v2 negotiation through the real client', () => {
55
+ it('a real 401 is reported as an auth rejection, not a missing namespace', async () => {
56
+ const client = await clientAnswering(401, {
57
+ code: 'respira_invalid_site_token',
58
+ message: 'The saved connection token for this site is out of date.',
59
+ });
60
+ const msg = await v2FailureMessage(client);
61
+ assert.match(msg, /rejected this API key \(HTTP 401/);
62
+ assert.doesNotMatch(msg, /is not available on this site/);
63
+ // The four causes that sent the reporter chasing firewall rules for a day.
64
+ assert.doesNotMatch(msg, /Wordfence/);
65
+ assert.doesNotMatch(msg, /permalinks/i);
66
+ assert.doesNotMatch(msg, /Cloudflare/);
67
+ });
68
+ it("and quotes the site's own explanation", async () => {
69
+ const client = await clientAnswering(401, {
70
+ code: 'respira_invalid_site_token',
71
+ message: 'The saved connection token for this site is out of date.',
72
+ });
73
+ const msg = await v2FailureMessage(client);
74
+ assert.match(msg, /The saved connection token for this site is out of date\./);
75
+ assert.match(msg, /respira_invalid_site_token/);
76
+ });
77
+ it('a 403 is auth too', async () => {
78
+ const client = await clientAnswering(403, { code: 'respira_scope_denied', message: 'nope' });
79
+ const msg = await v2FailureMessage(client);
80
+ assert.match(msg, /rejected this API key \(HTTP 403/);
81
+ });
82
+ it('a real 404 keeps the original guidance, which is correct only for a 404', async () => {
83
+ const client = await clientAnswering(404, { code: 'rest_no_route', message: 'No route' });
84
+ const msg = await v2FailureMessage(client);
85
+ assert.match(msg, /is not available on this site/);
86
+ assert.match(msg, /Wordfence/);
87
+ });
88
+ it('a 500 names the status instead of blaming the namespace', async () => {
89
+ const client = await clientAnswering(500, { code: 'fatal', message: 'Fatal error' });
90
+ const msg = await v2FailureMessage(client);
91
+ assert.match(msg, /returned HTTP 500 on this site/);
92
+ assert.doesNotMatch(msg, /is not available on this site/);
93
+ });
94
+ it('a dead host is reported as connectivity, not configuration', async () => {
95
+ // Nothing listening: a genuine transport failure, where there IS no status.
96
+ const client = new WordPressClient({
97
+ id: 'probe', name: 'probe', url: 'http://127.0.0.1:1', apiKey: 'respira_test_key',
98
+ });
99
+ const msg = await v2FailureMessage(client);
100
+ assert.match(msg, /Could not reach respira\/v2|connectivity failure/);
101
+ assert.doesNotMatch(msg, /Wordfence/);
102
+ });
103
+ });
104
+ //# sourceMappingURL=v2-negotiation-through-real-client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-negotiation-through-real-client.test.js","sourceRoot":"","sources":["../../src/__tests__/v2-negotiation-through-real-client.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgBH,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,kBAAkB,CAAC;AAsQzE,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,KAAK,CAA2C;IACxD,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,YAAY,CAA4B;IAChD,8EAA8E;IAC9E,OAAO,CAAC,YAAY,CAA4B;IAChD,8EAA8E;IAC9E,OAAO,CAAC,mBAAmB,CAAS;IACpC,iFAAiF;IACjF,OAAO,CAAC,iBAAiB,CAAK;IAC9B,iFAAiF;IACjF,OAAO,CAAC,mBAAmB,CAAgC;IAE3D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;IAEhE;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;gBA4Bb,WAAW,EAAE,mBAAmB,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE;IAiVvE,OAAO,CAAC,cAAc;IAItB;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IA4BrB,gEAAgE;IAChE,OAAO,CAAC,aAAa;IAUrB;;;;;;OAMG;YACW,UAAU;IA2CxB;;;;;;;;;;;;;;OAcG;YACW,WAAW;IAiJzB;;;;;;;;;OASG;YACW,kBAAkB;IA6KhC;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;YACW,qBAAqB;YAiBrB,kBAAkB;IA6FhC,yFAAyF;IACzF,OAAO,CAAC,gBAAgB;IASxB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,6BAA6B;IA0BrC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IA+BjC,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,aAAa;YAmQP,kBAAkB;YA6BlB,yBAAyB;IASvC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;YAyBd,QAAQ;IA+xGtB;;;;;;OAMG;IACH;;;;;;;;;;;;;oDAagD;IAChD,OAAO,CAAC,mBAAmB,CAAoD;IAC/E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAU;IAC1D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAS;IAC1D;;mDAE+C;IAC/C,OAAO,CAAC,0BAA0B,CAAoC;IAEtE;;;;;;;;OAQG;YACW,0BAA0B;YAyC1B,oBAAoB;YA6CpB,2BAA2B;IAQzC;;;;OAIG;YACW,cAAc;IAQ5B,OAAO,CAAC,mBAAmB;IAo7C3B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAe3C;IAEF;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;YAmCpB,cAAc;IA4G5B,oEAAoE;IACpE,OAAO,CAAC,iBAAiB;IAoBzB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,eAAe;YAuCT,gBAAgB;IA+0C9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAkZzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA6UxB,GAAG;CA+CV"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgBH,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,kBAAkB,CAAC;AAsQzE,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,KAAK,CAA2C;IACxD,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,YAAY,CAA4B;IAChD,8EAA8E;IAC9E,OAAO,CAAC,YAAY,CAA4B;IAChD,8EAA8E;IAC9E,OAAO,CAAC,mBAAmB,CAAS;IACpC,iFAAiF;IACjF,OAAO,CAAC,iBAAiB,CAAK;IAC9B,iFAAiF;IACjF,OAAO,CAAC,mBAAmB,CAAgC;IAE3D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;IAEhE;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;gBA4Bb,WAAW,EAAE,mBAAmB,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE;IAiVvE,OAAO,CAAC,cAAc;IAItB;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IA4BrB,gEAAgE;IAChE,OAAO,CAAC,aAAa;IAUrB;;;;;;OAMG;YACW,UAAU;IA2CxB;;;;;;;;;;;;;;OAcG;YACW,WAAW;IAiJzB;;;;;;;;;OASG;YACW,kBAAkB;IA6KhC;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;YACW,qBAAqB;YAiBrB,kBAAkB;IA6FhC,yFAAyF;IACzF,OAAO,CAAC,gBAAgB;IASxB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,6BAA6B;IA0BrC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IA+BjC,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,aAAa;YAmQP,kBAAkB;YA6BlB,yBAAyB;IASvC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;YAyBd,QAAQ;IA2yGtB;;;;;;OAMG;IACH;;;;;;;;;;;;;oDAagD;IAChD,OAAO,CAAC,mBAAmB,CAAoD;IAC/E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAU;IAC1D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAS;IAC1D;;mDAE+C;IAC/C,OAAO,CAAC,0BAA0B,CAAoC;IAEtE;;;;;;;;OAQG;YACW,0BAA0B;YAyC1B,oBAAoB;YA6CpB,2BAA2B;IAQzC;;;;OAIG;YACW,cAAc;IAQ5B,OAAO,CAAC,mBAAmB;IAo7C3B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAe3C;IAEF;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;YAmCpB,cAAc;IA4G5B,oEAAoE;IACpE,OAAO,CAAC,iBAAiB;IAoBzB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,eAAe;YAuCT,gBAAgB;IA+0C9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAkZzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA6UxB,GAAG;CA+CV"}
package/dist/server.js CHANGED
@@ -1860,6 +1860,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
1860
1860
  type: 'string',
1861
1861
  description: 'URL slug (post_name). Example: "about-us" produces /about-us/.',
1862
1862
  },
1863
+ excerpt: {
1864
+ type: 'string',
1865
+ description: 'Post excerpt (wp_posts.post_excerpt) — the "Excerpt"/"Zajawka" panel, RSS summaries and archive teasers. Do NOT pass this inside meta: an excerpt written as post meta reads back fine and renders nowhere.',
1866
+ },
1863
1867
  custom_css: {
1864
1868
  type: 'string',
1865
1869
  description: 'Custom CSS for the page. Auto-detects builder: Divi → _et_pb_custom_css, Elementor → _elementor_page_settings.custom_css.',
@@ -2137,6 +2141,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
2137
2141
  type: 'string',
2138
2142
  description: 'URL slug (post_name). Example: "my-post" produces /my-post/.',
2139
2143
  },
2144
+ excerpt: {
2145
+ type: 'string',
2146
+ description: 'Post excerpt (wp_posts.post_excerpt) — the "Excerpt"/"Zajawka" panel, RSS summaries and archive teasers. Do NOT pass this inside meta: an excerpt written as post meta reads back fine and renders nowhere.',
2147
+ },
2140
2148
  author: {
2141
2149
  description: 'Author (user id or user login). Requires edit_others_posts capability when different from the acting user.',
2142
2150
  oneOf: [
@@ -4424,6 +4432,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
4424
4432
  type: 'string',
4425
4433
  description: 'URL slug (post_name).',
4426
4434
  },
4435
+ excerpt: {
4436
+ type: 'string',
4437
+ description: 'Post excerpt (wp_posts.post_excerpt) — the "Excerpt"/"Zajawka" panel, RSS summaries and archive teasers. Do NOT pass this inside meta: an excerpt written as post meta reads back fine and renders nowhere.',
4438
+ },
4427
4439
  author: {
4428
4440
  description: 'Author (user id or user login). Requires edit_others_posts capability when different from the acting user.',
4429
4441
  oneOf: [