@gravitykit/block-mcp 2.0.0-beta
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/.env.example +15 -0
- package/LICENSE +26 -0
- package/README.md +592 -0
- package/dist/index.cjs +52721 -0
- package/package.json +70 -0
- package/src/__tests__/fixtures/block-trees.ts +199 -0
- package/src/__tests__/fixtures/error-envelopes.ts +115 -0
- package/src/__tests__/fixtures/rest-responses.ts +280 -0
- package/src/__tests__/helpers/mock-client.ts +185 -0
- package/src/__tests__/helpers/request-matchers.ts +88 -0
- package/src/__tests__/helpers/schema-asserts.ts +132 -0
- package/src/__tests__/integration/concurrency.test.ts +129 -0
- package/src/__tests__/integration/dual-storage.test.ts +156 -0
- package/src/__tests__/integration/error-envelopes.test.ts +238 -0
- package/src/__tests__/integration/global-setup.ts +17 -0
- package/src/__tests__/integration/rate-limit.test.ts +88 -0
- package/src/__tests__/integration/read-edit-read.test.ts +141 -0
- package/src/__tests__/integration/ref-stability.test.ts +175 -0
- package/src/__tests__/integration/setup.ts +201 -0
- package/src/__tests__/tools/discovery/get_pattern.test.ts +58 -0
- package/src/__tests__/tools/discovery/get_post_info.test.ts +100 -0
- package/src/__tests__/tools/discovery/get_site_usage.test.ts +41 -0
- package/src/__tests__/tools/discovery/list_block_types.test.ts +103 -0
- package/src/__tests__/tools/discovery/list_patterns.test.ts +106 -0
- package/src/__tests__/tools/discovery/list_posts.test.ts +47 -0
- package/src/__tests__/tools/discovery/resolve_url.test.ts +69 -0
- package/src/__tests__/tools/discovery/scan_storage_modes.test.ts +34 -0
- package/src/__tests__/tools/media/upload_media.test.ts +123 -0
- package/src/__tests__/tools/mutate/edit_block_tree.test.ts +439 -0
- package/src/__tests__/tools/mutate/ref_routing.test.ts +105 -0
- package/src/__tests__/tools/patterns/insert_pattern.test.ts +117 -0
- package/src/__tests__/tools/posts/create_post.test.ts +84 -0
- package/src/__tests__/tools/posts/update_post.test.ts +93 -0
- package/src/__tests__/tools/read/get_block.test.ts +96 -0
- package/src/__tests__/tools/read/get_page_blocks.test.ts +184 -0
- package/src/__tests__/tools/read/persist_refs.test.ts +35 -0
- package/src/__tests__/tools/terms/list_terms.test.ts +91 -0
- package/src/__tests__/tools/write/delete_block.test.ts +91 -0
- package/src/__tests__/tools/write/insert_blocks.test.ts +149 -0
- package/src/__tests__/tools/write/ref_routing.test.ts +177 -0
- package/src/__tests__/tools/write/replace_block_range.test.ts +90 -0
- package/src/__tests__/tools/write/rewrite_post_blocks.test.ts +126 -0
- package/src/__tests__/tools/write/update_block.test.ts +206 -0
- package/src/__tests__/tools/write/update_blocks.test.ts +173 -0
- package/src/__tests__/tools/yoast/yoast_bulk_update_seo.test.ts +112 -0
- package/src/__tests__/tools/yoast/yoast_get_seo.test.ts +78 -0
- package/src/__tests__/tools/yoast/yoast_update_seo.test.ts +105 -0
- package/src/__tests__/unit/client/ref-endpoints.test.ts +232 -0
- package/src/__tests__/unit/enrichers/cbp-enricher.test.ts +457 -0
- package/src/__tests__/unit/error-translator/translate-wp-error.test.ts +318 -0
- package/src/__tests__/unit/instructions.test.ts +374 -0
- package/src/__tests__/unit/preferences/enrich-block-list.test.ts +175 -0
- package/src/__tests__/unit/preferences/enrich-pattern-list.test.ts +227 -0
- package/src/client.ts +964 -0
- package/src/connect.ts +877 -0
- package/src/enrichers.ts +348 -0
- package/src/error-translator.ts +156 -0
- package/src/index.ts +450 -0
- package/src/instructions.ts +270 -0
- package/src/preferences.ts +273 -0
- package/src/tools/discovery.ts +251 -0
- package/src/tools/media.ts +75 -0
- package/src/tools/mutate.ts +243 -0
- package/src/tools/patterns.ts +94 -0
- package/src/tools/posts.ts +200 -0
- package/src/tools/read.ts +201 -0
- package/src/tools/terms.ts +44 -0
- package/src/tools/write.ts +542 -0
- package/src/tools/yoast.ts +224 -0
- package/src/types.ts +862 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,862 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript interfaces for the GravityKit Block MCP server.
|
|
3
|
+
*
|
|
4
|
+
* Defines all data structures exchanged between the MCP server,
|
|
5
|
+
* the WordPress REST API (gk-block-api), and AI agent consumers.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ============================================
|
|
9
|
+
// Configuration
|
|
10
|
+
// ============================================
|
|
11
|
+
|
|
12
|
+
/** MCP server configuration read from environment variables. */
|
|
13
|
+
export interface BlockMCPConfig {
|
|
14
|
+
/** WordPress site URL (e.g. "https://www.gravitykit.com") */
|
|
15
|
+
wordpress_url: string;
|
|
16
|
+
auth: {
|
|
17
|
+
/** WordPress username for Application Password auth */
|
|
18
|
+
username: string;
|
|
19
|
+
/** WordPress Application Password (space-separated groups) */
|
|
20
|
+
application_password: string;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ============================================
|
|
25
|
+
// Block Types
|
|
26
|
+
// ============================================
|
|
27
|
+
|
|
28
|
+
/** Preference metadata attached to a block type. */
|
|
29
|
+
export interface BlockPreference {
|
|
30
|
+
/** Numeric score (0-100 typical; can be negative for legacy) */
|
|
31
|
+
score: number;
|
|
32
|
+
/** Human-readable tier derived from score */
|
|
33
|
+
tier: 'preferred' | 'acceptable' | 'avoid' | 'legacy';
|
|
34
|
+
/** Namespace-level policy label */
|
|
35
|
+
namespace_policy?: string;
|
|
36
|
+
/** Suggested replacement block name (e.g. "core/heading") */
|
|
37
|
+
replacement?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Usage statistics for a single block type. */
|
|
41
|
+
export interface BlockTypeUsage {
|
|
42
|
+
/** Total occurrences across all published content */
|
|
43
|
+
count: number;
|
|
44
|
+
/** Date the block was last used (ISO date string) */
|
|
45
|
+
last_used?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** A registered WordPress block type with preference metadata. */
|
|
49
|
+
export interface BlockType {
|
|
50
|
+
/** Fully-qualified block name (e.g. "filter/testimonial-wall") */
|
|
51
|
+
name: string;
|
|
52
|
+
/** Human-readable title */
|
|
53
|
+
title: string;
|
|
54
|
+
/** Block category slug */
|
|
55
|
+
category: string;
|
|
56
|
+
/** Short description of the block's purpose */
|
|
57
|
+
description?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Block attribute definitions.
|
|
60
|
+
* `source` (when present) signals the attribute reads from innerHTML at
|
|
61
|
+
* edit time — strong hint a block is dual-storage.
|
|
62
|
+
*/
|
|
63
|
+
attributes?: Record<string, { type: string; default?: unknown; source?: string }>;
|
|
64
|
+
/** Preference scoring metadata */
|
|
65
|
+
preference: BlockPreference;
|
|
66
|
+
/** Site-wide usage statistics */
|
|
67
|
+
usage?: BlockTypeUsage;
|
|
68
|
+
/**
|
|
69
|
+
* Storage mode — `"static"` (innerHTML is source of truth),
|
|
70
|
+
* `"dynamic"` (server-rendered, attributes are source of truth),
|
|
71
|
+
* `"dual"` (both must stay in sync — write enforcement applies).
|
|
72
|
+
*/
|
|
73
|
+
storage_mode?: 'static' | 'dynamic' | 'dual';
|
|
74
|
+
/** Block names this block replaces (e.g. legacy equivalents) */
|
|
75
|
+
replaces?: string[];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ============================================
|
|
79
|
+
// Patterns
|
|
80
|
+
// ============================================
|
|
81
|
+
|
|
82
|
+
/** Preference metadata attached to a pattern. */
|
|
83
|
+
export interface PatternPreference {
|
|
84
|
+
/** Computed preference score */
|
|
85
|
+
score: number;
|
|
86
|
+
/** Human-readable tier */
|
|
87
|
+
tier: 'recommended' | 'acceptable' | 'avoid' | 'legacy';
|
|
88
|
+
/** Reasons contributing to the score */
|
|
89
|
+
reasons: string[];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** A WordPress block pattern (synced or registered). */
|
|
93
|
+
export interface Pattern {
|
|
94
|
+
/** Post ID for synced patterns, or a generated ID for registered ones */
|
|
95
|
+
id: number | string;
|
|
96
|
+
/** Pattern display name */
|
|
97
|
+
name: string;
|
|
98
|
+
/** "synced" (wp_block post) or "registered" */
|
|
99
|
+
type: 'synced' | 'registered';
|
|
100
|
+
/** Creation date (ISO date string) */
|
|
101
|
+
created: string;
|
|
102
|
+
/** Last modification date (ISO date string) */
|
|
103
|
+
modified: string;
|
|
104
|
+
/** Number of pages referencing this pattern (synced only) */
|
|
105
|
+
reference_count: number;
|
|
106
|
+
/** Preference scoring metadata */
|
|
107
|
+
preference: PatternPreference;
|
|
108
|
+
/** Block names contained within this pattern */
|
|
109
|
+
contains_blocks: string[];
|
|
110
|
+
/** Whether the pattern contains any legacy/avoid-tier blocks */
|
|
111
|
+
has_legacy_blocks: boolean;
|
|
112
|
+
/** Specific legacy block names found in the pattern */
|
|
113
|
+
legacy_blocks?: string[];
|
|
114
|
+
/** Truncated HTML preview of the pattern content */
|
|
115
|
+
preview_html?: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ============================================
|
|
119
|
+
// Page Blocks
|
|
120
|
+
// ============================================
|
|
121
|
+
|
|
122
|
+
/** A single parsed block from a page's post_content. */
|
|
123
|
+
export interface Block {
|
|
124
|
+
/** Zero-based position in the flat block array (counts every block including innerBlocks). Used by `update_block.flat_index`. */
|
|
125
|
+
index: number;
|
|
126
|
+
/**
|
|
127
|
+
* Zero-based sequential position among non-empty top-level blocks only.
|
|
128
|
+
* Only set on top-level blocks (omitted on inner blocks).
|
|
129
|
+
* Used by `delete_block.top_level_counter`, `insert_blocks.before_top_level`/`after_top_level`, and `replace_block_range.start`.
|
|
130
|
+
*/
|
|
131
|
+
top_level_counter?: number;
|
|
132
|
+
/** Path array (raw `parse_blocks()` indices). e.g. `[0, 2, 1]` = block 0 → innerBlock 2 → innerBlock 1. Used by `edit_block_tree`. */
|
|
133
|
+
path?: number[];
|
|
134
|
+
/**
|
|
135
|
+
* Stable identity ref (e.g. "blk_a3f2c1q9"). Persisted in attrs.metadata.gk_ref.
|
|
136
|
+
* Survives sibling shifts — pass `ref` to update_block/delete_block/edit_block_tree
|
|
137
|
+
* instead of `index`/`path` to chain mutations without re-fetching the page.
|
|
138
|
+
*/
|
|
139
|
+
ref?: string;
|
|
140
|
+
/** Fully-qualified block name (e.g. "core/paragraph") */
|
|
141
|
+
name: string;
|
|
142
|
+
/** Block attributes (key-value pairs) */
|
|
143
|
+
attributes: Record<string, unknown>;
|
|
144
|
+
/** Raw inner HTML content of the block */
|
|
145
|
+
innerHTML?: string;
|
|
146
|
+
/** Whether the registered block type uses a server-side render callback. */
|
|
147
|
+
dynamic?: boolean;
|
|
148
|
+
/**
|
|
149
|
+
* How this block stores content.
|
|
150
|
+
* - `"static"`: innerHTML is the source of truth (most core/* blocks).
|
|
151
|
+
* - `"dynamic"`: attributes is the source of truth; innerHTML is regenerated on render.
|
|
152
|
+
* - `"dual"`: BOTH attributes and innerHTML carry the same data — sending one without
|
|
153
|
+
* the other corrupts the block (e.g., yoast/faq-block, yoast/how-to-block).
|
|
154
|
+
*/
|
|
155
|
+
storage_mode?: 'static' | 'dynamic' | 'dual';
|
|
156
|
+
/**
|
|
157
|
+
* Per-block preference info attached by the server when the block is non-preferred.
|
|
158
|
+
* Driven by the (admin-editable) Preferences config — no client-side namespace
|
|
159
|
+
* hardcoding. Absent when tier === 'preferred' (the common case).
|
|
160
|
+
*/
|
|
161
|
+
preference?: {
|
|
162
|
+
tier: 'preferred' | 'acceptable' | 'avoid' | 'legacy';
|
|
163
|
+
suggested_replacement?: string;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Children of container blocks (core/group, core/columns, etc.). Each
|
|
167
|
+
* child has the same Block shape, including its own ref / preference /
|
|
168
|
+
* innerBlocks fields, so policy walks recurse cleanly.
|
|
169
|
+
*/
|
|
170
|
+
innerBlocks?: Block[];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ============================================
|
|
174
|
+
// Write Responses
|
|
175
|
+
// ============================================
|
|
176
|
+
|
|
177
|
+
/** Warning returned when a write operation uses a non-preferred block. */
|
|
178
|
+
export interface PreferenceWarning {
|
|
179
|
+
/** Block name that triggered the warning */
|
|
180
|
+
block: string;
|
|
181
|
+
/** Human-readable warning message */
|
|
182
|
+
message: string;
|
|
183
|
+
/** Suggested replacement block name */
|
|
184
|
+
suggested_replacement?: string;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Canonical post-save snapshot of one block. Echoed in write responses
|
|
189
|
+
* (`update_block`, `update_blocks` with `verbose: true`) and returned by
|
|
190
|
+
* `get_block` — same shape on both sides, so the contract is identical
|
|
191
|
+
* for "what just got saved" and "what's there now".
|
|
192
|
+
*
|
|
193
|
+
* For dynamic blocks (`is_dynamic: true`), `inner_html` is the stored
|
|
194
|
+
* template, not the rendered output — render happens at page-load time.
|
|
195
|
+
*/
|
|
196
|
+
export interface SavedBlock {
|
|
197
|
+
/** Flat index of this block in the post (matches `get_page_blocks` index). */
|
|
198
|
+
flat_index: number;
|
|
199
|
+
/** Fully-qualified block name (e.g., `core/paragraph`). */
|
|
200
|
+
block_name: string;
|
|
201
|
+
/** Post-save attributes, post-transform (matches what's now in post_content). */
|
|
202
|
+
attributes: Record<string, unknown>;
|
|
203
|
+
/** Post-save innerHTML — exactly what was just serialized into post_content. */
|
|
204
|
+
inner_html: string;
|
|
205
|
+
/**
|
|
206
|
+
* True if this block type has a PHP render callback. When true, `inner_html`
|
|
207
|
+
* is the stored template, not the rendered HTML the visitor sees.
|
|
208
|
+
*/
|
|
209
|
+
is_dynamic: boolean;
|
|
210
|
+
/** Stable gk_ref (when the block has one). */
|
|
211
|
+
ref?: string;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Response from block update (PATCH) operations. */
|
|
215
|
+
export interface BlockUpdateResponse {
|
|
216
|
+
success: boolean;
|
|
217
|
+
/** The updated block */
|
|
218
|
+
block: {
|
|
219
|
+
index: number;
|
|
220
|
+
name: string;
|
|
221
|
+
attributes: Record<string, unknown>;
|
|
222
|
+
/** Stable gk_ref UUID (present when the block had/has a ref). Use to chain follow-up mutations. */
|
|
223
|
+
ref?: string;
|
|
224
|
+
};
|
|
225
|
+
/**
|
|
226
|
+
* Canonical post-save snapshot — exactly what's now in `post_content` for
|
|
227
|
+
* this block. The write call is the verification: no need to re-read the
|
|
228
|
+
* block to confirm what saved.
|
|
229
|
+
*/
|
|
230
|
+
saved: SavedBlock;
|
|
231
|
+
/** WordPress revision ID of the pre-edit snapshot */
|
|
232
|
+
before_revision_id: number;
|
|
233
|
+
/** WordPress revision ID of the post-edit state */
|
|
234
|
+
revision_id: number;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Response from `get_block` — single-block fetch by ref or flat_index. */
|
|
238
|
+
export interface GetBlockResponse {
|
|
239
|
+
success: boolean;
|
|
240
|
+
/** Canonical snapshot — same shape as `BlockUpdateResponse.saved`. */
|
|
241
|
+
saved: SavedBlock;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** Single entry describing a block written by `insert_blocks` / `rewrite_post_blocks`. */
|
|
245
|
+
export interface InsertedBlockRef {
|
|
246
|
+
/** Top-level visible index — matches `index` from get_page_blocks for top-level blocks. */
|
|
247
|
+
index: number;
|
|
248
|
+
/** Sequential top-level position. Same as `index` for inserts (always top-level). */
|
|
249
|
+
top_level_counter?: number;
|
|
250
|
+
/**
|
|
251
|
+
* Path array consumable by `edit_block_tree`. e.g. `[12]` for the 13th
|
|
252
|
+
* raw top-level slot. Returned by `insert_blocks` so callers can chain a
|
|
253
|
+
* `edit_block_tree op: insert-child` without an extra get_page_blocks lookup.
|
|
254
|
+
*/
|
|
255
|
+
path?: number[];
|
|
256
|
+
/** Stable gk_ref. Returned so callers can chain mutations against it. */
|
|
257
|
+
ref?: string;
|
|
258
|
+
/** Fully-qualified block name. */
|
|
259
|
+
name: string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Response from block insert (POST) and replace (PUT) operations. */
|
|
263
|
+
export interface BlockWriteResponse {
|
|
264
|
+
success: boolean;
|
|
265
|
+
/** Inserted blocks with their new indices, top-level counters, and mutation paths. */
|
|
266
|
+
inserted: InsertedBlockRef[];
|
|
267
|
+
/** Preference warnings for non-preferred blocks */
|
|
268
|
+
warnings: PreferenceWarning[];
|
|
269
|
+
/** WordPress revision ID of the pre-edit snapshot */
|
|
270
|
+
before_revision_id: number;
|
|
271
|
+
/** WordPress revision ID of the post-edit state */
|
|
272
|
+
revision_id: number;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** Response from block delete (DELETE) operations. */
|
|
276
|
+
export interface BlockDeleteResponse {
|
|
277
|
+
success: boolean;
|
|
278
|
+
/** Number of blocks removed */
|
|
279
|
+
removed: number;
|
|
280
|
+
/** WordPress revision ID of the pre-edit snapshot */
|
|
281
|
+
before_revision_id: number;
|
|
282
|
+
/** WordPress revision ID of the post-edit state */
|
|
283
|
+
revision_id: number;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Response from atomic `replace_block_range` (POST /posts/{id}/blocks/replace). */
|
|
287
|
+
export interface BlockReplaceRangeResponse {
|
|
288
|
+
success: boolean;
|
|
289
|
+
/** Number of blocks removed before the new shape was inserted. */
|
|
290
|
+
removed: number;
|
|
291
|
+
/** New block refs (same shape as `BlockWriteResponse.inserted`). */
|
|
292
|
+
inserted: InsertedBlockRef[];
|
|
293
|
+
warnings: PreferenceWarning[];
|
|
294
|
+
before_revision_id: number;
|
|
295
|
+
revision_id: number;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* One item in a `update_blocks` batch. Targets exactly one block by stable
|
|
300
|
+
* `ref` (recommended) OR `flat_index` (legacy), with `attributes` and/or
|
|
301
|
+
* `innerHTML` to apply.
|
|
302
|
+
*/
|
|
303
|
+
export interface BlockBatchUpdateItem {
|
|
304
|
+
/** Stable gk_ref (e.g. `blk_a3f2c1q9`). Provide this OR `flat_index`. */
|
|
305
|
+
ref?: string;
|
|
306
|
+
/** Flat index from `get_page_blocks`. Provide this OR `ref`. */
|
|
307
|
+
flat_index?: number;
|
|
308
|
+
/** Block type — surfaces enrichers (e.g. CBP codeHTML) when `attributes` is provided. */
|
|
309
|
+
block_name?: string;
|
|
310
|
+
/** Partial attributes (top-level shallow merge). */
|
|
311
|
+
attributes?: Record<string, unknown>;
|
|
312
|
+
/** Replacement innerHTML. */
|
|
313
|
+
innerHTML?: string;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** Per-item validation error returned with `batch_validation_failed` (400). */
|
|
317
|
+
export interface BlockBatchValidationError {
|
|
318
|
+
/** Position of the failing item in the request `updates` array. */
|
|
319
|
+
index: number;
|
|
320
|
+
/** Machine-readable error code (e.g. `ref_stale`, `invalid_index`, `duplicate_target`). */
|
|
321
|
+
code: string;
|
|
322
|
+
/** Human-readable message. */
|
|
323
|
+
message: string;
|
|
324
|
+
/** Original `ref` (when applicable). */
|
|
325
|
+
ref?: string;
|
|
326
|
+
/** Original `flat_index` (when applicable). */
|
|
327
|
+
flat_index?: number;
|
|
328
|
+
/** Block name (when applicable). */
|
|
329
|
+
block?: string;
|
|
330
|
+
/** Earlier batch index that already targeted the same block (duplicate_target only). */
|
|
331
|
+
first_seen_at?: number;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** Per-item success result inside a `BlockBatchUpdateResponse`. */
|
|
335
|
+
export interface BlockBatchUpdateResult {
|
|
336
|
+
/** Batch position this result corresponds to. */
|
|
337
|
+
batch_index: number;
|
|
338
|
+
/** Updated block summary, mirroring `BlockUpdateResponse.block`. */
|
|
339
|
+
block: {
|
|
340
|
+
index: number;
|
|
341
|
+
name: string;
|
|
342
|
+
attributes: Record<string, unknown>;
|
|
343
|
+
ref?: string;
|
|
344
|
+
};
|
|
345
|
+
/**
|
|
346
|
+
* Canonical post-save snapshot. Present only when the batch was called
|
|
347
|
+
* with `verbose: true` (default is false to keep batch responses compact).
|
|
348
|
+
*/
|
|
349
|
+
saved?: SavedBlock;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Response from `POST /posts/{id}/blocks/batch-update`. ONE revision for N updates. */
|
|
353
|
+
export interface BlockBatchUpdateResponse {
|
|
354
|
+
success: boolean;
|
|
355
|
+
/** Number of items applied. Equals `updates.length` (validation is all-or-nothing). */
|
|
356
|
+
count: number;
|
|
357
|
+
/** Per-item updated block summaries, in the same order as the request. */
|
|
358
|
+
results: BlockBatchUpdateResult[];
|
|
359
|
+
/** WordPress revision ID of the pre-batch snapshot. */
|
|
360
|
+
before_revision_id: number;
|
|
361
|
+
/** WordPress revision ID of the post-batch state. ONE revision regardless of N. */
|
|
362
|
+
revision_id: number;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/** Response from URL resolution (GET /resolve). */
|
|
366
|
+
export interface ResolveUrlResponse {
|
|
367
|
+
post_id: number;
|
|
368
|
+
post_type: string;
|
|
369
|
+
title: string;
|
|
370
|
+
status: string;
|
|
371
|
+
slug: string;
|
|
372
|
+
edit_url: string;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/** Single post stub returned by GET /find-posts. */
|
|
376
|
+
export interface PostStub {
|
|
377
|
+
post_id: number;
|
|
378
|
+
title: string;
|
|
379
|
+
slug: string;
|
|
380
|
+
post_type: string;
|
|
381
|
+
post_status: string;
|
|
382
|
+
post_url: string;
|
|
383
|
+
modified: string;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/** Response from GET /find-posts. */
|
|
387
|
+
export interface FindPostsResponse {
|
|
388
|
+
posts: PostStub[];
|
|
389
|
+
count: number;
|
|
390
|
+
total: number;
|
|
391
|
+
total_pages: number;
|
|
392
|
+
page: number;
|
|
393
|
+
per_page: number;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** Query params for GET /find-posts. */
|
|
397
|
+
export interface FindPostsParams {
|
|
398
|
+
search?: string;
|
|
399
|
+
post_type?: string;
|
|
400
|
+
post_status?: string;
|
|
401
|
+
per_page?: number;
|
|
402
|
+
page?: number;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/** Response from GET /post-info. */
|
|
406
|
+
export interface PostInfoResponse {
|
|
407
|
+
post_id: number;
|
|
408
|
+
title: string;
|
|
409
|
+
slug: string;
|
|
410
|
+
post_type: string;
|
|
411
|
+
post_status: string;
|
|
412
|
+
post_url: string;
|
|
413
|
+
edit_url: string;
|
|
414
|
+
modified: string;
|
|
415
|
+
created: string;
|
|
416
|
+
parent_id: number;
|
|
417
|
+
author: {
|
|
418
|
+
id: number;
|
|
419
|
+
display_name: string;
|
|
420
|
+
};
|
|
421
|
+
mime_type: string;
|
|
422
|
+
comment_count: number;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Query params for GET /post-info — provide one of {post_id, url, slug+post_type}. */
|
|
426
|
+
export interface PostInfoParams {
|
|
427
|
+
post_id?: number;
|
|
428
|
+
url?: string;
|
|
429
|
+
slug?: string;
|
|
430
|
+
post_type?: string;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/** Response from pattern insertion (POST /posts/{id}/insert-pattern). */
|
|
434
|
+
export interface PatternInsertResponse {
|
|
435
|
+
success: boolean;
|
|
436
|
+
/** Inserted block(s) — single object for synced, array for inline */
|
|
437
|
+
inserted: {
|
|
438
|
+
index: number;
|
|
439
|
+
name: string;
|
|
440
|
+
attributes?: Record<string, unknown>;
|
|
441
|
+
pattern_name?: string;
|
|
442
|
+
synced?: boolean;
|
|
443
|
+
} | Array<{ index: number; name: string }>;
|
|
444
|
+
/** Pattern display name */
|
|
445
|
+
pattern_name?: string;
|
|
446
|
+
/** Whether inserted as synced (core/block ref) or inline */
|
|
447
|
+
synced?: boolean;
|
|
448
|
+
/** WordPress revision ID of the pre-edit snapshot */
|
|
449
|
+
before_revision_id: number;
|
|
450
|
+
/** WordPress revision ID of the post-edit state */
|
|
451
|
+
revision_id: number;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// ============================================
|
|
455
|
+
// Site Usage
|
|
456
|
+
// ============================================
|
|
457
|
+
|
|
458
|
+
/** Block usage entry in site-wide statistics. */
|
|
459
|
+
export interface BlockUsageEntry {
|
|
460
|
+
count: number;
|
|
461
|
+
post_count: number;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** Pattern reference entry in site-wide statistics. */
|
|
465
|
+
export interface PatternReferenceEntry {
|
|
466
|
+
name: string;
|
|
467
|
+
refs: number;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/** Legacy pattern entry in site-wide statistics. */
|
|
471
|
+
export interface LegacyPatternEntry {
|
|
472
|
+
id: number;
|
|
473
|
+
name: string;
|
|
474
|
+
refs: number;
|
|
475
|
+
legacy_blocks: string[];
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** Result of `scan_storage_modes` — block_name → "static" | "dynamic" | "dual". */
|
|
479
|
+
export interface StorageModeScanResult {
|
|
480
|
+
scanned_posts: number;
|
|
481
|
+
unique_blocks: number;
|
|
482
|
+
classification: Record<string, 'static' | 'dynamic' | 'dual'>;
|
|
483
|
+
dual_count: number;
|
|
484
|
+
dynamic_count: number;
|
|
485
|
+
static_count: number;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/** Site-wide block and pattern usage statistics. */
|
|
489
|
+
export interface SiteUsage {
|
|
490
|
+
/** Per-block-type usage counts */
|
|
491
|
+
block_usage: Record<string, BlockUsageEntry>;
|
|
492
|
+
/** Per-namespace total block counts */
|
|
493
|
+
namespace_totals: Record<string, number>;
|
|
494
|
+
/** Synced pattern reference counts keyed by pattern ID */
|
|
495
|
+
pattern_references: Record<string, PatternReferenceEntry>;
|
|
496
|
+
/** Patterns containing legacy blocks */
|
|
497
|
+
legacy_patterns: LegacyPatternEntry[];
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// ============================================
|
|
501
|
+
// API Parameter Types
|
|
502
|
+
// ============================================
|
|
503
|
+
|
|
504
|
+
/** Parameters for the list_block_types tool. */
|
|
505
|
+
export interface ListBlockTypesParams {
|
|
506
|
+
namespace?: string;
|
|
507
|
+
category?: string;
|
|
508
|
+
preferred_only?: boolean;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/** Parameters for the list_patterns tool. */
|
|
512
|
+
export interface ListPatternsParams {
|
|
513
|
+
search?: string;
|
|
514
|
+
synced?: boolean;
|
|
515
|
+
min_score?: number;
|
|
516
|
+
limit?: number;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/** Parameters for the insert_blocks tool. */
|
|
520
|
+
export interface InsertBlocksParams {
|
|
521
|
+
post_id: number;
|
|
522
|
+
after?: number | 'start';
|
|
523
|
+
before?: number;
|
|
524
|
+
/** Insert after the top-level block with this gk_ref. Takes precedence over `after`. */
|
|
525
|
+
after_ref?: string;
|
|
526
|
+
/** Insert before the top-level block with this gk_ref. Takes precedence over `before`. */
|
|
527
|
+
before_ref?: string;
|
|
528
|
+
blocks: Array<{
|
|
529
|
+
name: string;
|
|
530
|
+
attributes?: Record<string, unknown>;
|
|
531
|
+
innerHTML?: string;
|
|
532
|
+
}>;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/** Parameters for the insert_pattern tool. */
|
|
536
|
+
export interface InsertPatternParams {
|
|
537
|
+
post_id: number;
|
|
538
|
+
pattern_id: number | string;
|
|
539
|
+
after?: number;
|
|
540
|
+
before?: number;
|
|
541
|
+
synced?: boolean;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// ============================================
|
|
545
|
+
// Mutation Types
|
|
546
|
+
// ============================================
|
|
547
|
+
|
|
548
|
+
/** Valid mutation operation names. */
|
|
549
|
+
export type MutationOp =
|
|
550
|
+
| 'update-attrs'
|
|
551
|
+
| 'update-html'
|
|
552
|
+
| 'replace-block'
|
|
553
|
+
| 'remove-block'
|
|
554
|
+
| 'wrap-in-group'
|
|
555
|
+
| 'unwrap-group'
|
|
556
|
+
| 'insert-child'
|
|
557
|
+
| 'duplicate'
|
|
558
|
+
| 'move';
|
|
559
|
+
|
|
560
|
+
/** Request body for the mutate endpoint. Provide either `path` or `ref`. */
|
|
561
|
+
export interface MutationRequest {
|
|
562
|
+
op: MutationOp;
|
|
563
|
+
/** Integer path to the target. Provide either this or `ref`. */
|
|
564
|
+
path?: number[];
|
|
565
|
+
/** Stable gk_ref of the target block. Survives sibling shifts. */
|
|
566
|
+
ref?: string;
|
|
567
|
+
attributes?: Record<string, unknown>;
|
|
568
|
+
innerHTML?: string;
|
|
569
|
+
block?: {
|
|
570
|
+
name: string;
|
|
571
|
+
attributes?: Record<string, unknown>;
|
|
572
|
+
innerHTML?: string;
|
|
573
|
+
innerBlocks?: Array<{
|
|
574
|
+
name: string;
|
|
575
|
+
attributes?: Record<string, unknown>;
|
|
576
|
+
innerHTML?: string;
|
|
577
|
+
}>;
|
|
578
|
+
};
|
|
579
|
+
wrapper?: {
|
|
580
|
+
name?: string;
|
|
581
|
+
attributes?: Record<string, unknown>;
|
|
582
|
+
};
|
|
583
|
+
position?: number | 'start' | 'end';
|
|
584
|
+
destination?: number[];
|
|
585
|
+
/** Alternative to `destination` — resolve from a ref instead of a path. */
|
|
586
|
+
destination_ref?: string;
|
|
587
|
+
/** Alias for destination — path of block to insert BEFORE (pre-move indexing). */
|
|
588
|
+
before?: number[];
|
|
589
|
+
/** Alternative to `before` — resolve from a ref instead of a path. */
|
|
590
|
+
before_ref?: string;
|
|
591
|
+
/** Number of consecutive blocks to move/operate on. Default: 1. */
|
|
592
|
+
count?: number;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/** Warning about static block markup staleness. */
|
|
596
|
+
export interface StaticBlockWarning {
|
|
597
|
+
type: 'static_markup_stale_risk';
|
|
598
|
+
block_name: string;
|
|
599
|
+
changed_attrs: string[];
|
|
600
|
+
message: string;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/** Response from the mutate endpoint. */
|
|
604
|
+
export interface MutationResponse {
|
|
605
|
+
success: boolean;
|
|
606
|
+
op: MutationOp;
|
|
607
|
+
path: number[];
|
|
608
|
+
block?: {
|
|
609
|
+
name: string;
|
|
610
|
+
attributes: Record<string, unknown>;
|
|
611
|
+
/** Set when the op produced a new block (replace, wrap, insert-child, duplicate). */
|
|
612
|
+
ref?: string;
|
|
613
|
+
/** Set on `duplicate` — path of the new clone. */
|
|
614
|
+
new_path?: number[];
|
|
615
|
+
};
|
|
616
|
+
warnings: Array<PreferenceWarning | StaticBlockWarning>;
|
|
617
|
+
before_revision_id: number;
|
|
618
|
+
revision_id: number;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// ============================================
|
|
622
|
+
// v1.2 — Docs Lifecycle: Posts
|
|
623
|
+
// ============================================
|
|
624
|
+
|
|
625
|
+
/** A block in structured form, suitable for create_post's `blocks` input. */
|
|
626
|
+
export interface BlockInput {
|
|
627
|
+
name: string;
|
|
628
|
+
attributes?: Record<string, unknown>;
|
|
629
|
+
innerBlocks?: BlockInput[];
|
|
630
|
+
innerHTML?: string;
|
|
631
|
+
innerContent?: unknown[];
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
export type CreatePostStatus = 'draft' | 'pending' | 'private' | 'publish' | 'future';
|
|
635
|
+
export type UpdatePostStatus = CreatePostStatus | 'trash';
|
|
636
|
+
export type CommentPingStatus = 'open' | 'closed';
|
|
637
|
+
|
|
638
|
+
/** Body of POST /posts. `content` and `blocks` are mutually exclusive. */
|
|
639
|
+
export interface CreatePostRequest {
|
|
640
|
+
title: string;
|
|
641
|
+
post_type?: string;
|
|
642
|
+
status?: CreatePostStatus;
|
|
643
|
+
content?: string;
|
|
644
|
+
blocks?: BlockInput[];
|
|
645
|
+
slug?: string;
|
|
646
|
+
parent?: number;
|
|
647
|
+
excerpt?: string;
|
|
648
|
+
/** Attachment ID. Send 0 to leave unset. Validated as image MIME. */
|
|
649
|
+
featured_media?: number;
|
|
650
|
+
/** Term IDs in the `category` taxonomy. */
|
|
651
|
+
categories?: number[];
|
|
652
|
+
/** Term IDs in the `post_tag` taxonomy. */
|
|
653
|
+
tags?: number[];
|
|
654
|
+
/** Map of taxonomy slug → term IDs (for non-built-in taxonomies on CPTs). */
|
|
655
|
+
terms?: Record<string, number[]>;
|
|
656
|
+
date?: string;
|
|
657
|
+
menu_order?: number;
|
|
658
|
+
comment_status?: CommentPingStatus;
|
|
659
|
+
ping_status?: CommentPingStatus;
|
|
660
|
+
author?: number;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Body of PATCH /posts/{id}. All fields optional. Send `[]` to clear
|
|
665
|
+
* `categories`/`tags`. Send `0` to clear `featured_media`. Use `status: trash`
|
|
666
|
+
* to trash; any non-trash status untrashes a trashed post.
|
|
667
|
+
*/
|
|
668
|
+
export interface UpdatePostRequest {
|
|
669
|
+
title?: string;
|
|
670
|
+
status?: UpdatePostStatus;
|
|
671
|
+
slug?: string;
|
|
672
|
+
parent?: number;
|
|
673
|
+
excerpt?: string;
|
|
674
|
+
featured_media?: number;
|
|
675
|
+
categories?: number[];
|
|
676
|
+
tags?: number[];
|
|
677
|
+
terms?: Record<string, number[]>;
|
|
678
|
+
date?: string;
|
|
679
|
+
menu_order?: number;
|
|
680
|
+
comment_status?: CommentPingStatus;
|
|
681
|
+
ping_status?: CommentPingStatus;
|
|
682
|
+
author?: number;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/** Common response shape for create_post and update_post. */
|
|
686
|
+
export interface PostMutationResponse {
|
|
687
|
+
success: boolean;
|
|
688
|
+
id: number;
|
|
689
|
+
post_type: string;
|
|
690
|
+
status: string;
|
|
691
|
+
title: string;
|
|
692
|
+
slug: string;
|
|
693
|
+
permalink: string;
|
|
694
|
+
edit_link: string;
|
|
695
|
+
before_revision_id: number | null;
|
|
696
|
+
revision_id: number | null;
|
|
697
|
+
/** Set on update_post when the post moves into `publish` from a non-publish status. */
|
|
698
|
+
transitioned_to_publish?: boolean;
|
|
699
|
+
/** Set on update_post when the post moved out of `trash`. */
|
|
700
|
+
untrashed?: boolean;
|
|
701
|
+
/** Avoid-tier warnings emitted by Block_CRUD when blocks are passed at create time. */
|
|
702
|
+
warnings: PreferenceWarning[];
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// ============================================
|
|
706
|
+
// v1.2 — Docs Lifecycle: Terms
|
|
707
|
+
// ============================================
|
|
708
|
+
|
|
709
|
+
export type TermOrderBy = 'name' | 'count' | 'term_id' | 'slug';
|
|
710
|
+
export type SortOrder = 'asc' | 'desc';
|
|
711
|
+
|
|
712
|
+
export interface ListTermsRequest {
|
|
713
|
+
taxonomy?: string;
|
|
714
|
+
search?: string;
|
|
715
|
+
parent?: number;
|
|
716
|
+
hide_empty?: boolean;
|
|
717
|
+
per_page?: number;
|
|
718
|
+
page?: number;
|
|
719
|
+
orderby?: TermOrderBy;
|
|
720
|
+
order?: SortOrder;
|
|
721
|
+
include?: number[];
|
|
722
|
+
slug?: string;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
export interface Term {
|
|
726
|
+
id: number;
|
|
727
|
+
name: string;
|
|
728
|
+
slug: string;
|
|
729
|
+
description: string;
|
|
730
|
+
parent: number;
|
|
731
|
+
count: number;
|
|
732
|
+
taxonomy: string;
|
|
733
|
+
link: string;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
export interface ListTermsResponse {
|
|
737
|
+
taxonomy: string;
|
|
738
|
+
total: number;
|
|
739
|
+
page: number;
|
|
740
|
+
per_page: number;
|
|
741
|
+
terms: Term[];
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// ============================================
|
|
745
|
+
// v1.2 — Docs Lifecycle: Media
|
|
746
|
+
// ============================================
|
|
747
|
+
|
|
748
|
+
/** Exactly one of `path`, `url`, or `data_base64` is required. */
|
|
749
|
+
export interface UploadMediaRequest {
|
|
750
|
+
/** Local filesystem path on the MCP host. Read and POSTed as multipart. */
|
|
751
|
+
path?: string;
|
|
752
|
+
/** Public URL the WordPress site can fetch. Server-side sideload. */
|
|
753
|
+
url?: string;
|
|
754
|
+
/** Base64-encoded file contents. Requires `filename`. */
|
|
755
|
+
data_base64?: string;
|
|
756
|
+
/** Override filename (required when using `data_base64`). */
|
|
757
|
+
filename?: string;
|
|
758
|
+
title?: string;
|
|
759
|
+
/** Saved as `_wp_attachment_image_alt`. Critical for accessibility. */
|
|
760
|
+
alt_text?: string;
|
|
761
|
+
caption?: string;
|
|
762
|
+
description?: string;
|
|
763
|
+
/** Attach to a parent post (sets post_parent). */
|
|
764
|
+
post_id?: number;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
export interface AttachmentSize {
|
|
768
|
+
url: string;
|
|
769
|
+
width: number;
|
|
770
|
+
height: number;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
export interface UploadMediaResponse {
|
|
774
|
+
success: boolean;
|
|
775
|
+
id: number;
|
|
776
|
+
title: string;
|
|
777
|
+
filename: string;
|
|
778
|
+
url: string;
|
|
779
|
+
source_url: string;
|
|
780
|
+
mime_type: string;
|
|
781
|
+
alt_text: string;
|
|
782
|
+
caption?: string;
|
|
783
|
+
description?: string;
|
|
784
|
+
post_parent: number;
|
|
785
|
+
/** Image-only fields (absent for non-image attachments). */
|
|
786
|
+
width?: number;
|
|
787
|
+
height?: number;
|
|
788
|
+
sizes?: Record<string, AttachmentSize>;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// ============================================
|
|
792
|
+
// v1.3 — Yoast SEO Metadata
|
|
793
|
+
//
|
|
794
|
+
// Backed by Yoast_Bridge inside gk-block-api (`gk-block-api/v1/yoast/*`).
|
|
795
|
+
// Routes only register when Yoast SEO is active on the target site.
|
|
796
|
+
// ============================================
|
|
797
|
+
|
|
798
|
+
export type YoastSchemaPageType =
|
|
799
|
+
| 'WebPage' | 'ItemPage' | 'AboutPage' | 'FAQPage' | 'QAPage'
|
|
800
|
+
| 'ProfilePage' | 'ContactPage' | 'MedicalWebPage' | 'CollectionPage'
|
|
801
|
+
| 'CheckoutPage' | 'RealEstateListing' | 'SearchResultsPage';
|
|
802
|
+
|
|
803
|
+
export type YoastSchemaArticleType =
|
|
804
|
+
| 'Article' | 'BlogPosting' | 'SocialMediaPosting' | 'NewsArticle'
|
|
805
|
+
| 'AdvertiserContentArticle' | 'SatiricalArticle' | 'ScholarlyArticle'
|
|
806
|
+
| 'TechArticle' | 'Report' | 'None';
|
|
807
|
+
|
|
808
|
+
export type YoastRobotsAdvanced = 'noimageindex' | 'noarchive' | 'nosnippet';
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Writable Yoast SEO fields. All optional in update payloads — only the
|
|
812
|
+
* fields you include get written.
|
|
813
|
+
*
|
|
814
|
+
* NOTE: `noindex` is intentionally tri-state — `true` = noindex, `false` =
|
|
815
|
+
* explicit index, `null` = post-type default (Yoast clears the meta).
|
|
816
|
+
*/
|
|
817
|
+
export interface YoastSEOFields {
|
|
818
|
+
title?: string;
|
|
819
|
+
description?: string;
|
|
820
|
+
canonical?: string;
|
|
821
|
+
focus_keyword?: string;
|
|
822
|
+
noindex?: boolean | null;
|
|
823
|
+
nofollow?: boolean;
|
|
824
|
+
robots_advanced?: YoastRobotsAdvanced[];
|
|
825
|
+
og_title?: string;
|
|
826
|
+
og_description?: string;
|
|
827
|
+
og_image?: string;
|
|
828
|
+
og_image_id?: number;
|
|
829
|
+
twitter_title?: string;
|
|
830
|
+
twitter_description?: string;
|
|
831
|
+
twitter_image?: string;
|
|
832
|
+
twitter_image_id?: number;
|
|
833
|
+
schema_page_type?: YoastSchemaPageType;
|
|
834
|
+
schema_article_type?: YoastSchemaArticleType;
|
|
835
|
+
is_cornerstone?: boolean;
|
|
836
|
+
breadcrumb_title?: string;
|
|
837
|
+
redirect?: string;
|
|
838
|
+
primary_terms?: Record<string, number>;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/** Full Yoast SEO metadata returned by `yoast_get_seo`. Includes read-only scores. */
|
|
842
|
+
export interface YoastSEOMeta extends YoastSEOFields {
|
|
843
|
+
post_id: number;
|
|
844
|
+
/** Yoast SEO score (0-100), null if unscored. */
|
|
845
|
+
seo_score?: number | null;
|
|
846
|
+
/** Readability score (0-100), null if unscored. */
|
|
847
|
+
readability_score?: number | null;
|
|
848
|
+
/** Inclusive language score (0-100), null if unscored. */
|
|
849
|
+
inclusive_language_score?: number | null;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
export type YoastUpdateRequest = YoastSEOFields;
|
|
853
|
+
|
|
854
|
+
/** One entry in a `yoast_bulk_update_seo` request. */
|
|
855
|
+
export interface YoastBulkUpdateItem extends YoastSEOFields {
|
|
856
|
+
post_id: number;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
export type YoastBulkUpdateResponse = Array<
|
|
860
|
+
| { post_id: number; success: true; seo: YoastSEOMeta }
|
|
861
|
+
| { post_id: number; success: false; error: string }
|
|
862
|
+
>;
|