wpnav_update_post
Update WordPress posts by modifying title, content, excerpt, or status while maintaining an audit trail for tracking changes.
Instructions
Update a WordPress post. Requires post ID and at least one field to update. Changes are logged in audit trail.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | WordPress post ID | |
| title | No | New post title | |
| content | No | New post content (HTML). | |
| excerpt | No | Post excerpt | |
| status | No | Post status: publish, draft, private | |
| force | No | Skip safety validation |
Implementation Reference
- src/tools/content/index.ts:461-512 (handler)The handler function implementing the wpnav_update_post tool logic: validates args, builds JSON Patch operations for title/content/excerpt/status, calls applyContentChanges safety wrapper, returns result or formatted error.handler: async (args, context) => { try { validateRequired(args, ['id']); const id = validateId(args.id, 'Post'); const ops: any[] = []; if (args.title != null) ops.push({ op: 'replace', path: '/title', value: String(args.title) }); if (args.content != null) ops.push({ op: 'replace', path: '/content', value: String(args.content) }); if (args.excerpt != null) ops.push({ op: 'replace', path: '/excerpt', value: String(args.excerpt) }); if (args.status != null) ops.push({ op: 'replace', path: '/status', value: String(args.status) }); if (!ops.length) { return { content: [{ type: 'text', text: JSON.stringify({ error: 'validation_failed', code: 'VALIDATION_FAILED', message: 'At least one of title, content, excerpt, or status must be provided', context: { resource_type: 'post', resource_id: id }, }, null, 2), }], isError: true, }; } const result = await applyContentChanges(context.wpRequest as any, context.config, { postId: id, operations: ops, force: !!args.force, }); return { content: [{ type: 'text', text: context.clampText(JSON.stringify(result, null, 2)) }], }; } catch (error: any) { const errorMessage = error.message || 'Unknown error'; const isWritesDisabled = errorMessage.includes('WRITES_DISABLED'); return { content: [{ type: 'text', text: JSON.stringify({ error: isWritesDisabled ? 'writes_disabled' : 'operation_failed', code: isWritesDisabled ? 'WRITES_DISABLED' : 'UPDATE_FAILED', message: errorMessage, context: { resource_type: 'post', resource_id: args.id, suggestion: 'Use wpnav_get_post to verify post exists' }, }, null, 2), }], isError: true, }; } },
- src/tools/content/index.ts:448-459 (schema)JSON Schema defining input parameters and validation for wpnav_update_post tool.inputSchema: { type: 'object', properties: { id: { type: 'number', description: 'WordPress post ID' }, title: { type: 'string', description: 'New post title' }, content: { type: 'string', description: 'New post content (HTML).' }, excerpt: { type: 'string', description: 'Post excerpt' }, status: { type: 'string', enum: ['publish', 'draft', 'private'], description: 'Post status: publish, draft, private' }, force: { type: 'boolean', description: 'Skip safety validation', default: false }, }, required: ['id'], },
- src/tools/content/index.ts:444-514 (registration)Registration of the wpnav_update_post tool with toolRegistry, including definition, handler, and category.toolRegistry.register({ definition: { name: 'wpnav_update_post', description: 'Update a WordPress post. Requires post ID and at least one field to update. Changes are logged in audit trail.', inputSchema: { type: 'object', properties: { id: { type: 'number', description: 'WordPress post ID' }, title: { type: 'string', description: 'New post title' }, content: { type: 'string', description: 'New post content (HTML).' }, excerpt: { type: 'string', description: 'Post excerpt' }, status: { type: 'string', enum: ['publish', 'draft', 'private'], description: 'Post status: publish, draft, private' }, force: { type: 'boolean', description: 'Skip safety validation', default: false }, }, required: ['id'], }, }, handler: async (args, context) => { try { validateRequired(args, ['id']); const id = validateId(args.id, 'Post'); const ops: any[] = []; if (args.title != null) ops.push({ op: 'replace', path: '/title', value: String(args.title) }); if (args.content != null) ops.push({ op: 'replace', path: '/content', value: String(args.content) }); if (args.excerpt != null) ops.push({ op: 'replace', path: '/excerpt', value: String(args.excerpt) }); if (args.status != null) ops.push({ op: 'replace', path: '/status', value: String(args.status) }); if (!ops.length) { return { content: [{ type: 'text', text: JSON.stringify({ error: 'validation_failed', code: 'VALIDATION_FAILED', message: 'At least one of title, content, excerpt, or status must be provided', context: { resource_type: 'post', resource_id: id }, }, null, 2), }], isError: true, }; } const result = await applyContentChanges(context.wpRequest as any, context.config, { postId: id, operations: ops, force: !!args.force, }); return { content: [{ type: 'text', text: context.clampText(JSON.stringify(result, null, 2)) }], }; } catch (error: any) { const errorMessage = error.message || 'Unknown error'; const isWritesDisabled = errorMessage.includes('WRITES_DISABLED'); return { content: [{ type: 'text', text: JSON.stringify({ error: isWritesDisabled ? 'writes_disabled' : 'operation_failed', code: isWritesDisabled ? 'WRITES_DISABLED' : 'UPDATE_FAILED', message: errorMessage, context: { resource_type: 'post', resource_id: args.id, suggestion: 'Use wpnav_get_post to verify post exists' }, }, null, 2), }], isError: true, }; } }, category: ToolCategory.CONTENT, });
- src/safety.ts:33-76 (helper)Core helper function applyContentChanges that performs the safe plan/diff/apply workflow via WP Navigator endpoints for content updates, called by the tool handler.export async function applyContentChanges( wpRequest: WpRequest, config: WPConfig, opts: ApplyContentOptions ) { const idempotencyKey = makeIdempotencyKey(); // 1) Plan const plan = await wpRequest('/wpnav/v1/content/plan', { method: 'POST', body: JSON.stringify({ post_id: opts.postId, operations: opts.operations, idempotency_key: idempotencyKey, }), }); const planId = plan?.plan_id ?? plan?.id ?? plan?.planId; if (!planId) { throw new Error(`PLAN_FAILED: Could not retrieve plan_id from response`); } // 2) Diff (json format; small context) const diff = await wpRequest('/wpnav/v1/content/diff', { method: 'POST', body: JSON.stringify({ plan_id: planId, format: 'json', context_lines: 3, }), }); // 3) Apply const apply = await wpRequest('/wpnav/v1/content/apply', { method: 'POST', body: JSON.stringify({ plan_id: planId, idempotency_key: idempotencyKey, force: !!opts.force, }), }); return { plan, diff, apply }; }