chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+117
View File
@@ -0,0 +1,117 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressCreateCategoryParams,
type WordPressCreateCategoryResponse,
} from '@/tools/wordpress/types'
export const createCategoryTool: ToolConfig<
WordPressCreateCategoryParams,
WordPressCreateCategoryResponse
> = {
id: 'wordpress_create_category',
name: 'WordPress Create Category',
description: 'Create a new category in WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Category name',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Category description',
},
parent: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Parent category ID for hierarchical categories',
},
slug: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'URL slug for the category',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/categories`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {
name: params.name,
}
if (params.description) body.description = params.description
if (params.parent !== undefined) body.parent = params.parent
if (params.slug) body.slug = params.slug
return body
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
category: {
id: data.id,
count: data.count,
description: data.description,
link: data.link,
name: data.name,
slug: data.slug,
taxonomy: data.taxonomy,
parent: data.parent,
},
},
}
},
outputs: {
category: {
type: 'object',
description: 'The created category',
properties: {
id: { type: 'number', description: 'Category ID' },
count: { type: 'number', description: 'Number of posts in this category' },
description: { type: 'string', description: 'Category description' },
link: { type: 'string', description: 'Category archive URL' },
name: { type: 'string', description: 'Category name' },
slug: { type: 'string', description: 'Category slug' },
taxonomy: { type: 'string', description: 'Taxonomy name' },
parent: { type: 'number', description: 'Parent category ID' },
},
},
},
}
+137
View File
@@ -0,0 +1,137 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressCreateCommentParams,
type WordPressCreateCommentResponse,
} from '@/tools/wordpress/types'
export const createCommentTool: ToolConfig<
WordPressCreateCommentParams,
WordPressCreateCommentResponse
> = {
id: 'wordpress_create_comment',
name: 'WordPress Create Comment',
description: 'Create a new comment on a WordPress.com post',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
postId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the post to comment on',
},
content: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Comment content',
},
parent: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Parent comment ID for replies',
},
authorName: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Comment author display name',
},
authorEmail: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Comment author email',
},
authorUrl: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Comment author URL',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/comments`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {
post: params.postId,
content: params.content,
}
if (params.parent !== undefined) body.parent = params.parent
if (params.authorName) body.author_name = params.authorName
if (params.authorEmail) body.author_email = params.authorEmail
if (params.authorUrl) body.author_url = params.authorUrl
return body
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
comment: {
id: data.id,
post: data.post,
parent: data.parent,
author: data.author,
author_name: data.author_name,
author_email: data.author_email,
author_url: data.author_url,
date: data.date,
content: data.content,
link: data.link,
status: data.status,
},
},
}
},
outputs: {
comment: {
type: 'object',
description: 'The created comment',
properties: {
id: { type: 'number', description: 'Comment ID' },
post: { type: 'number', description: 'Post ID' },
parent: { type: 'number', description: 'Parent comment ID' },
author: { type: 'number', description: 'Author user ID' },
author_name: { type: 'string', description: 'Author display name' },
author_email: { type: 'string', description: 'Author email' },
author_url: { type: 'string', description: 'Author URL' },
date: { type: 'string', description: 'Comment date' },
content: { type: 'object', description: 'Comment content object' },
link: { type: 'string', description: 'Comment permalink' },
status: { type: 'string', description: 'Comment status' },
},
},
},
}
+154
View File
@@ -0,0 +1,154 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressCreatePageParams,
type WordPressCreatePageResponse,
} from '@/tools/wordpress/types'
export const createPageTool: ToolConfig<WordPressCreatePageParams, WordPressCreatePageResponse> = {
id: 'wordpress_create_page',
name: 'WordPress Create Page',
description: 'Create a new page in WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
title: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Page title',
},
content: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Page content (HTML or plain text)',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Page status: publish, draft, pending, private',
},
excerpt: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Page excerpt',
},
parent: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Parent page ID for hierarchical pages',
},
menuOrder: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Order in page menu',
},
featuredMedia: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Featured image media ID',
},
slug: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'URL slug for the page',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/pages`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {
title: params.title,
}
if (params.content) body.content = params.content
if (params.status) body.status = params.status
if (params.excerpt) body.excerpt = params.excerpt
if (params.slug) body.slug = params.slug
if (params.parent !== undefined) body.parent = params.parent
if (params.menuOrder !== undefined) body.menu_order = params.menuOrder
if (params.featuredMedia !== undefined) body.featured_media = params.featuredMedia
return body
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
page: {
id: data.id,
date: data.date,
modified: data.modified,
slug: data.slug,
status: data.status,
type: data.type,
link: data.link,
title: data.title,
content: data.content,
excerpt: data.excerpt,
author: data.author,
featured_media: data.featured_media,
parent: data.parent,
menu_order: data.menu_order,
},
},
}
},
outputs: {
page: {
type: 'object',
description: 'The created page',
properties: {
id: { type: 'number', description: 'Page ID' },
date: { type: 'string', description: 'Page creation date' },
modified: { type: 'string', description: 'Page modification date' },
slug: { type: 'string', description: 'Page slug' },
status: { type: 'string', description: 'Page status' },
type: { type: 'string', description: 'Content type' },
link: { type: 'string', description: 'Page URL' },
title: { type: 'object', description: 'Page title object' },
content: { type: 'object', description: 'Page content object' },
excerpt: { type: 'object', description: 'Page excerpt object' },
author: { type: 'number', description: 'Author ID' },
featured_media: { type: 'number', description: 'Featured media ID' },
parent: { type: 'number', description: 'Parent page ID' },
menu_order: { type: 'number', description: 'Menu order' },
},
},
},
}
+166
View File
@@ -0,0 +1,166 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressCreatePostParams,
type WordPressCreatePostResponse,
} from '@/tools/wordpress/types'
export const createPostTool: ToolConfig<WordPressCreatePostParams, WordPressCreatePostResponse> = {
id: 'wordpress_create_post',
name: 'WordPress Create Post',
description: 'Create a new blog post in WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
title: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Post title',
},
content: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Post content (HTML or plain text)',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Post status: publish, draft, pending, private, or future',
},
excerpt: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Post excerpt',
},
categories: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated category IDs',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated tag IDs',
},
featuredMedia: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Featured image media ID',
},
slug: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'URL slug for the post',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/posts`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {
title: params.title,
}
if (params.content) body.content = params.content
if (params.status) body.status = params.status
if (params.excerpt) body.excerpt = params.excerpt
if (params.slug) body.slug = params.slug
if (params.featuredMedia !== undefined) body.featured_media = params.featuredMedia
if (params.categories) {
body.categories = params.categories
.split(',')
.map((id: string) => Number.parseInt(id.trim(), 10))
.filter((id: number) => !Number.isNaN(id))
}
if (params.tags) {
body.tags = params.tags
.split(',')
.map((id: string) => Number.parseInt(id.trim(), 10))
.filter((id: number) => !Number.isNaN(id))
}
return body
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
post: {
id: data.id,
date: data.date,
modified: data.modified,
slug: data.slug,
status: data.status,
type: data.type,
link: data.link,
title: data.title,
content: data.content,
excerpt: data.excerpt,
author: data.author,
featured_media: data.featured_media,
categories: data.categories || [],
tags: data.tags || [],
},
},
}
},
outputs: {
post: {
type: 'object',
description: 'The created post',
properties: {
id: { type: 'number', description: 'Post ID' },
date: { type: 'string', description: 'Post creation date' },
modified: { type: 'string', description: 'Post modification date' },
slug: { type: 'string', description: 'Post slug' },
status: { type: 'string', description: 'Post status' },
type: { type: 'string', description: 'Post type' },
link: { type: 'string', description: 'Post URL' },
title: { type: 'object', description: 'Post title object' },
content: { type: 'object', description: 'Post content object' },
excerpt: { type: 'object', description: 'Post excerpt object' },
author: { type: 'number', description: 'Author ID' },
featured_media: { type: 'number', description: 'Featured media ID' },
categories: { type: 'array', description: 'Category IDs' },
tags: { type: 'array', description: 'Tag IDs' },
},
},
},
}
+105
View File
@@ -0,0 +1,105 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressCreateTagParams,
type WordPressCreateTagResponse,
} from '@/tools/wordpress/types'
export const createTagTool: ToolConfig<WordPressCreateTagParams, WordPressCreateTagResponse> = {
id: 'wordpress_create_tag',
name: 'WordPress Create Tag',
description: 'Create a new tag in WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Tag name',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Tag description',
},
slug: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'URL slug for the tag',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/tags`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {
name: params.name,
}
if (params.description) body.description = params.description
if (params.slug) body.slug = params.slug
return body
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
tag: {
id: data.id,
count: data.count,
description: data.description,
link: data.link,
name: data.name,
slug: data.slug,
taxonomy: data.taxonomy,
},
},
}
},
outputs: {
tag: {
type: 'object',
description: 'The created tag',
properties: {
id: { type: 'number', description: 'Tag ID' },
count: { type: 'number', description: 'Number of posts with this tag' },
description: { type: 'string', description: 'Tag description' },
link: { type: 'string', description: 'Tag archive URL' },
name: { type: 'string', description: 'Tag name' },
slug: { type: 'string', description: 'Tag slug' },
taxonomy: { type: 'string', description: 'Taxonomy name' },
},
},
},
}
@@ -0,0 +1,96 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressDeleteCategoryParams,
type WordPressDeleteCategoryResponse,
} from '@/tools/wordpress/types'
export const deleteCategoryTool: ToolConfig<
WordPressDeleteCategoryParams,
WordPressDeleteCategoryResponse
> = {
id: 'wordpress_delete_category',
name: 'WordPress Delete Category',
description: 'Delete a category from WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
categoryId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the category to delete',
},
},
request: {
url: (params) => {
// Terms do not support trashing, so force=true is required to delete.
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/categories/${params.categoryId}?force=true`
},
method: 'DELETE',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
deleted: data.deleted ?? true,
category: {
id: data.id ?? data.previous?.id,
count: data.count ?? data.previous?.count,
description: data.description || data.previous?.description,
link: data.link || data.previous?.link,
name: data.name || data.previous?.name,
slug: data.slug || data.previous?.slug,
taxonomy: data.taxonomy || data.previous?.taxonomy,
parent: data.parent ?? data.previous?.parent,
},
},
}
},
outputs: {
deleted: {
type: 'boolean',
description: 'Whether the category was deleted',
},
category: {
type: 'object',
description: 'The deleted category',
properties: {
id: { type: 'number', description: 'Category ID' },
count: { type: 'number', description: 'Number of posts in this category' },
description: { type: 'string', description: 'Category description' },
link: { type: 'string', description: 'Category archive URL' },
name: { type: 'string', description: 'Category name' },
slug: { type: 'string', description: 'Category slug' },
taxonomy: { type: 'string', description: 'Taxonomy name' },
parent: { type: 'number', description: 'Parent category ID' },
},
},
},
}
+108
View File
@@ -0,0 +1,108 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressDeleteCommentParams,
type WordPressDeleteCommentResponse,
} from '@/tools/wordpress/types'
export const deleteCommentTool: ToolConfig<
WordPressDeleteCommentParams,
WordPressDeleteCommentResponse
> = {
id: 'wordpress_delete_comment',
name: 'WordPress Delete Comment',
description: 'Delete a comment from WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
commentId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the comment to delete',
},
force: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'Bypass trash and force delete permanently',
},
},
request: {
url: (params) => {
const forceParam = params.force ? '?force=true' : ''
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/comments/${params.commentId}${forceParam}`
},
method: 'DELETE',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
deleted: data.deleted ?? true,
comment: {
id: data.id ?? data.previous?.id,
post: data.post ?? data.previous?.post,
parent: data.parent ?? data.previous?.parent,
author: data.author ?? data.previous?.author,
author_name: data.author_name || data.previous?.author_name,
author_email: data.author_email || data.previous?.author_email,
author_url: data.author_url || data.previous?.author_url,
date: data.date || data.previous?.date,
content: data.content || data.previous?.content,
link: data.link || data.previous?.link,
status: data.status || data.previous?.status || 'trash',
},
},
}
},
outputs: {
deleted: {
type: 'boolean',
description: 'Whether the comment was deleted',
},
comment: {
type: 'object',
description: 'The deleted comment',
properties: {
id: { type: 'number', description: 'Comment ID' },
post: { type: 'number', description: 'Post ID' },
parent: { type: 'number', description: 'Parent comment ID' },
author: { type: 'number', description: 'Author user ID' },
author_name: { type: 'string', description: 'Author display name' },
author_email: { type: 'string', description: 'Author email' },
author_url: { type: 'string', description: 'Author URL' },
date: { type: 'string', description: 'Comment date' },
content: { type: 'object', description: 'Comment content object' },
link: { type: 'string', description: 'Comment permalink' },
status: { type: 'string', description: 'Comment status' },
},
},
},
}
+102
View File
@@ -0,0 +1,102 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressDeleteMediaParams,
type WordPressDeleteMediaResponse,
} from '@/tools/wordpress/types'
export const deleteMediaTool: ToolConfig<WordPressDeleteMediaParams, WordPressDeleteMediaResponse> =
{
id: 'wordpress_delete_media',
name: 'WordPress Delete Media',
description: 'Delete a media item from WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
mediaId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the media item to delete',
},
},
request: {
url: (params) => {
// Media has no trash — deletion always requires force=true to take effect
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/media/${params.mediaId}?force=true`
},
method: 'DELETE',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
deleted: data.deleted ?? true,
media: {
id: data.id ?? data.previous?.id,
date: data.date || data.previous?.date,
slug: data.slug || data.previous?.slug,
type: data.type || data.previous?.type,
link: data.link || data.previous?.link,
title: data.title || data.previous?.title,
caption: data.caption || data.previous?.caption,
alt_text: data.alt_text || data.previous?.alt_text,
media_type: data.media_type || data.previous?.media_type,
mime_type: data.mime_type || data.previous?.mime_type,
source_url: data.source_url || data.previous?.source_url,
media_details: data.media_details || data.previous?.media_details,
},
},
}
},
outputs: {
deleted: {
type: 'boolean',
description: 'Whether the media was deleted',
},
media: {
type: 'object',
description: 'The deleted media item',
properties: {
id: { type: 'number', description: 'Media ID' },
date: { type: 'string', description: 'Upload date' },
slug: { type: 'string', description: 'Media slug' },
type: { type: 'string', description: 'Content type' },
link: { type: 'string', description: 'Media page URL' },
title: { type: 'object', description: 'Media title object' },
caption: { type: 'object', description: 'Media caption object' },
alt_text: { type: 'string', description: 'Alt text' },
media_type: { type: 'string', description: 'Media type (image, video, etc.)' },
mime_type: { type: 'string', description: 'MIME type' },
source_url: { type: 'string', description: 'Direct URL to the media file' },
media_details: { type: 'object', description: 'Media details (dimensions, etc.)' },
},
},
},
}
+111
View File
@@ -0,0 +1,111 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressDeletePageParams,
type WordPressDeletePageResponse,
} from '@/tools/wordpress/types'
export const deletePageTool: ToolConfig<WordPressDeletePageParams, WordPressDeletePageResponse> = {
id: 'wordpress_delete_page',
name: 'WordPress Delete Page',
description: 'Delete a page from WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
pageId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the page to delete',
},
force: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'Bypass trash and force delete permanently',
},
},
request: {
url: (params) => {
const forceParam = params.force ? '?force=true' : ''
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/pages/${params.pageId}${forceParam}`
},
method: 'DELETE',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
deleted: data.deleted ?? true,
page: {
id: data.id ?? data.previous?.id,
date: data.date || data.previous?.date,
modified: data.modified || data.previous?.modified,
slug: data.slug || data.previous?.slug,
status: data.status || data.previous?.status || 'trash',
type: data.type || data.previous?.type,
link: data.link || data.previous?.link,
title: data.title || data.previous?.title,
content: data.content || data.previous?.content,
excerpt: data.excerpt || data.previous?.excerpt,
author: data.author ?? data.previous?.author,
featured_media: data.featured_media ?? data.previous?.featured_media,
parent: data.parent ?? data.previous?.parent,
menu_order: data.menu_order ?? data.previous?.menu_order,
},
},
}
},
outputs: {
deleted: {
type: 'boolean',
description: 'Whether the page was deleted',
},
page: {
type: 'object',
description: 'The deleted page',
properties: {
id: { type: 'number', description: 'Page ID' },
date: { type: 'string', description: 'Page creation date' },
modified: { type: 'string', description: 'Page modification date' },
slug: { type: 'string', description: 'Page slug' },
status: { type: 'string', description: 'Page status' },
type: { type: 'string', description: 'Content type' },
link: { type: 'string', description: 'Page URL' },
title: { type: 'object', description: 'Page title object' },
content: { type: 'object', description: 'Page content object' },
excerpt: { type: 'object', description: 'Page excerpt object' },
author: { type: 'number', description: 'Author ID' },
featured_media: { type: 'number', description: 'Featured media ID' },
parent: { type: 'number', description: 'Parent page ID' },
menu_order: { type: 'number', description: 'Menu order' },
},
},
},
}
+111
View File
@@ -0,0 +1,111 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressDeletePostParams,
type WordPressDeletePostResponse,
} from '@/tools/wordpress/types'
export const deletePostTool: ToolConfig<WordPressDeletePostParams, WordPressDeletePostResponse> = {
id: 'wordpress_delete_post',
name: 'WordPress Delete Post',
description: 'Delete a blog post from WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
postId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the post to delete',
},
force: {
type: 'boolean',
required: false,
visibility: 'user-only',
description: 'Bypass trash and force delete permanently',
},
},
request: {
url: (params) => {
const forceParam = params.force ? '?force=true' : ''
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/posts/${params.postId}${forceParam}`
},
method: 'DELETE',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
deleted: data.deleted ?? true,
post: {
id: data.id ?? data.previous?.id,
date: data.date || data.previous?.date,
modified: data.modified || data.previous?.modified,
slug: data.slug || data.previous?.slug,
status: data.status || data.previous?.status || 'trash',
type: data.type || data.previous?.type,
link: data.link || data.previous?.link,
title: data.title || data.previous?.title,
content: data.content || data.previous?.content,
excerpt: data.excerpt || data.previous?.excerpt,
author: data.author ?? data.previous?.author,
featured_media: data.featured_media ?? data.previous?.featured_media,
categories: data.categories || data.previous?.categories || [],
tags: data.tags || data.previous?.tags || [],
},
},
}
},
outputs: {
deleted: {
type: 'boolean',
description: 'Whether the post was deleted',
},
post: {
type: 'object',
description: 'The deleted post',
properties: {
id: { type: 'number', description: 'Post ID' },
date: { type: 'string', description: 'Post creation date' },
modified: { type: 'string', description: 'Post modification date' },
slug: { type: 'string', description: 'Post slug' },
status: { type: 'string', description: 'Post status' },
type: { type: 'string', description: 'Post type' },
link: { type: 'string', description: 'Post URL' },
title: { type: 'object', description: 'Post title object' },
content: { type: 'object', description: 'Post content object' },
excerpt: { type: 'object', description: 'Post excerpt object' },
author: { type: 'number', description: 'Author ID' },
featured_media: { type: 'number', description: 'Featured media ID' },
categories: { type: 'array', description: 'Category IDs' },
tags: { type: 'array', description: 'Tag IDs' },
},
},
},
}
+91
View File
@@ -0,0 +1,91 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressDeleteTagParams,
type WordPressDeleteTagResponse,
} from '@/tools/wordpress/types'
export const deleteTagTool: ToolConfig<WordPressDeleteTagParams, WordPressDeleteTagResponse> = {
id: 'wordpress_delete_tag',
name: 'WordPress Delete Tag',
description: 'Delete a tag from WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
tagId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the tag to delete',
},
},
request: {
url: (params) => {
// Terms do not support trashing, so force=true is required to delete.
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/tags/${params.tagId}?force=true`
},
method: 'DELETE',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
deleted: data.deleted ?? true,
tag: {
id: data.id ?? data.previous?.id,
count: data.count ?? data.previous?.count,
description: data.description || data.previous?.description,
link: data.link || data.previous?.link,
name: data.name || data.previous?.name,
slug: data.slug || data.previous?.slug,
taxonomy: data.taxonomy || data.previous?.taxonomy,
},
},
}
},
outputs: {
deleted: {
type: 'boolean',
description: 'Whether the tag was deleted',
},
tag: {
type: 'object',
description: 'The deleted tag',
properties: {
id: { type: 'number', description: 'Tag ID' },
count: { type: 'number', description: 'Number of posts with this tag' },
description: { type: 'string', description: 'Tag description' },
link: { type: 'string', description: 'Tag archive URL' },
name: { type: 'string', description: 'Tag name' },
slug: { type: 'string', description: 'Tag slug' },
taxonomy: { type: 'string', description: 'Taxonomy name' },
},
},
},
}
+86
View File
@@ -0,0 +1,86 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressGetCategoryParams,
type WordPressGetCategoryResponse,
} from '@/tools/wordpress/types'
export const getCategoryTool: ToolConfig<WordPressGetCategoryParams, WordPressGetCategoryResponse> =
{
id: 'wordpress_get_category',
name: 'WordPress Get Category',
description: 'Get a single category from WordPress.com by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
categoryId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the category to retrieve',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/categories/${params.categoryId}`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
category: {
id: data.id,
count: data.count,
description: data.description,
link: data.link,
name: data.name,
slug: data.slug,
taxonomy: data.taxonomy,
parent: data.parent,
},
},
}
},
outputs: {
category: {
type: 'object',
description: 'The retrieved category',
properties: {
id: { type: 'number', description: 'Category ID' },
count: { type: 'number', description: 'Number of posts in this category' },
description: { type: 'string', description: 'Category description' },
link: { type: 'string', description: 'Category archive URL' },
name: { type: 'string', description: 'Category name' },
slug: { type: 'string', description: 'Category slug' },
taxonomy: { type: 'string', description: 'Taxonomy name' },
parent: { type: 'number', description: 'Parent category ID' },
},
},
},
}
@@ -0,0 +1,90 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressGetCurrentUserParams,
type WordPressGetCurrentUserResponse,
} from '@/tools/wordpress/types'
export const getCurrentUserTool: ToolConfig<
WordPressGetCurrentUserParams,
WordPressGetCurrentUserResponse
> = {
id: 'wordpress_get_current_user',
name: 'WordPress Get Current User',
description: 'Get information about the currently authenticated WordPress.com user',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/users/me`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
user: {
id: data.id,
username: data.username,
name: data.name,
first_name: data.first_name,
last_name: data.last_name,
email: data.email,
url: data.url,
description: data.description,
link: data.link,
slug: data.slug,
roles: data.roles || [],
avatar_urls: data.avatar_urls,
},
},
}
},
outputs: {
user: {
type: 'object',
description: 'The current user',
properties: {
id: { type: 'number', description: 'User ID' },
username: { type: 'string', description: 'Username' },
name: { type: 'string', description: 'Display name' },
first_name: { type: 'string', description: 'First name' },
last_name: { type: 'string', description: 'Last name' },
email: { type: 'string', description: 'Email address' },
url: { type: 'string', description: 'User website URL' },
description: { type: 'string', description: 'User bio' },
link: { type: 'string', description: 'Author archive URL' },
slug: { type: 'string', description: 'User slug' },
roles: { type: 'array', description: 'User roles' },
avatar_urls: { type: 'object', description: 'Avatar URLs at different sizes' },
},
},
},
}
+93
View File
@@ -0,0 +1,93 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressGetMediaParams,
type WordPressGetMediaResponse,
} from '@/tools/wordpress/types'
export const getMediaTool: ToolConfig<WordPressGetMediaParams, WordPressGetMediaResponse> = {
id: 'wordpress_get_media',
name: 'WordPress Get Media',
description: 'Get a single media item from WordPress.com by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
mediaId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the media item to retrieve',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/media/${params.mediaId}`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
media: {
id: data.id,
date: data.date,
slug: data.slug,
type: data.type,
link: data.link,
title: data.title,
caption: data.caption,
alt_text: data.alt_text,
media_type: data.media_type,
mime_type: data.mime_type,
source_url: data.source_url,
media_details: data.media_details,
},
},
}
},
outputs: {
media: {
type: 'object',
description: 'The retrieved media item',
properties: {
id: { type: 'number', description: 'Media ID' },
date: { type: 'string', description: 'Upload date' },
slug: { type: 'string', description: 'Media slug' },
type: { type: 'string', description: 'Content type' },
link: { type: 'string', description: 'Media page URL' },
title: { type: 'object', description: 'Media title object' },
caption: { type: 'object', description: 'Media caption object' },
alt_text: { type: 'string', description: 'Alt text' },
media_type: { type: 'string', description: 'Media type (image, video, etc.)' },
mime_type: { type: 'string', description: 'MIME type' },
source_url: { type: 'string', description: 'Direct URL to the media file' },
media_details: { type: 'object', description: 'Media details (dimensions, etc.)' },
},
},
},
}
+97
View File
@@ -0,0 +1,97 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressGetPageParams,
type WordPressGetPageResponse,
} from '@/tools/wordpress/types'
export const getPageTool: ToolConfig<WordPressGetPageParams, WordPressGetPageResponse> = {
id: 'wordpress_get_page',
name: 'WordPress Get Page',
description: 'Get a single page from WordPress.com by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
pageId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the page to retrieve',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/pages/${params.pageId}`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
page: {
id: data.id,
date: data.date,
modified: data.modified,
slug: data.slug,
status: data.status,
type: data.type,
link: data.link,
title: data.title,
content: data.content,
excerpt: data.excerpt,
author: data.author,
featured_media: data.featured_media,
parent: data.parent,
menu_order: data.menu_order,
},
},
}
},
outputs: {
page: {
type: 'object',
description: 'The retrieved page',
properties: {
id: { type: 'number', description: 'Page ID' },
date: { type: 'string', description: 'Page creation date' },
modified: { type: 'string', description: 'Page modification date' },
slug: { type: 'string', description: 'Page slug' },
status: { type: 'string', description: 'Page status' },
type: { type: 'string', description: 'Content type' },
link: { type: 'string', description: 'Page URL' },
title: { type: 'object', description: 'Page title object' },
content: { type: 'object', description: 'Page content object' },
excerpt: { type: 'object', description: 'Page excerpt object' },
author: { type: 'number', description: 'Author ID' },
featured_media: { type: 'number', description: 'Featured media ID' },
parent: { type: 'number', description: 'Parent page ID' },
menu_order: { type: 'number', description: 'Menu order' },
},
},
},
}
+97
View File
@@ -0,0 +1,97 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressGetPostParams,
type WordPressGetPostResponse,
} from '@/tools/wordpress/types'
export const getPostTool: ToolConfig<WordPressGetPostParams, WordPressGetPostResponse> = {
id: 'wordpress_get_post',
name: 'WordPress Get Post',
description: 'Get a single blog post from WordPress.com by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
postId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the post to retrieve',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/posts/${params.postId}`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
post: {
id: data.id,
date: data.date,
modified: data.modified,
slug: data.slug,
status: data.status,
type: data.type,
link: data.link,
title: data.title,
content: data.content,
excerpt: data.excerpt,
author: data.author,
featured_media: data.featured_media,
categories: data.categories || [],
tags: data.tags || [],
},
},
}
},
outputs: {
post: {
type: 'object',
description: 'The retrieved post',
properties: {
id: { type: 'number', description: 'Post ID' },
date: { type: 'string', description: 'Post creation date' },
modified: { type: 'string', description: 'Post modification date' },
slug: { type: 'string', description: 'Post slug' },
status: { type: 'string', description: 'Post status' },
type: { type: 'string', description: 'Post type' },
link: { type: 'string', description: 'Post URL' },
title: { type: 'object', description: 'Post title object' },
content: { type: 'object', description: 'Post content object' },
excerpt: { type: 'object', description: 'Post excerpt object' },
author: { type: 'number', description: 'Author ID' },
featured_media: { type: 'number', description: 'Featured media ID' },
categories: { type: 'array', description: 'Category IDs' },
tags: { type: 'array', description: 'Tag IDs' },
},
},
},
}
+83
View File
@@ -0,0 +1,83 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressGetTagParams,
type WordPressGetTagResponse,
} from '@/tools/wordpress/types'
export const getTagTool: ToolConfig<WordPressGetTagParams, WordPressGetTagResponse> = {
id: 'wordpress_get_tag',
name: 'WordPress Get Tag',
description: 'Get a single tag from WordPress.com by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
tagId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the tag to retrieve',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/tags/${params.tagId}`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
tag: {
id: data.id,
count: data.count,
description: data.description,
link: data.link,
name: data.name,
slug: data.slug,
taxonomy: data.taxonomy,
},
},
}
},
outputs: {
tag: {
type: 'object',
description: 'The retrieved tag',
properties: {
id: { type: 'number', description: 'Tag ID' },
count: { type: 'number', description: 'Number of posts with this tag' },
description: { type: 'string', description: 'Tag description' },
link: { type: 'string', description: 'Tag archive URL' },
name: { type: 'string', description: 'Tag name' },
slug: { type: 'string', description: 'Tag slug' },
taxonomy: { type: 'string', description: 'Taxonomy name' },
},
},
},
}
+93
View File
@@ -0,0 +1,93 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressGetUserParams,
type WordPressGetUserResponse,
} from '@/tools/wordpress/types'
export const getUserTool: ToolConfig<WordPressGetUserParams, WordPressGetUserResponse> = {
id: 'wordpress_get_user',
name: 'WordPress Get User',
description: 'Get a specific user from WordPress.com by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
userId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the user to retrieve',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/users/${params.userId}`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
user: {
id: data.id,
username: data.username,
name: data.name,
first_name: data.first_name,
last_name: data.last_name,
email: data.email,
url: data.url,
description: data.description,
link: data.link,
slug: data.slug,
roles: data.roles || [],
avatar_urls: data.avatar_urls,
},
},
}
},
outputs: {
user: {
type: 'object',
description: 'The retrieved user',
properties: {
id: { type: 'number', description: 'User ID' },
username: { type: 'string', description: 'Username' },
name: { type: 'string', description: 'Display name' },
first_name: { type: 'string', description: 'First name' },
last_name: { type: 'string', description: 'Last name' },
email: { type: 'string', description: 'Email address' },
url: { type: 'string', description: 'User website URL' },
description: { type: 'string', description: 'User bio' },
link: { type: 'string', description: 'Author archive URL' },
slug: { type: 'string', description: 'User slug' },
roles: { type: 'array', description: 'User roles' },
avatar_urls: { type: 'object', description: 'Avatar URLs at different sizes' },
},
},
},
}
+81
View File
@@ -0,0 +1,81 @@
// WordPress tools exports
import { createCategoryTool } from '@/tools/wordpress/create_category'
import { createCommentTool } from '@/tools/wordpress/create_comment'
import { createPageTool } from '@/tools/wordpress/create_page'
import { createPostTool } from '@/tools/wordpress/create_post'
import { createTagTool } from '@/tools/wordpress/create_tag'
import { deleteCategoryTool } from '@/tools/wordpress/delete_category'
import { deleteCommentTool } from '@/tools/wordpress/delete_comment'
import { deleteMediaTool } from '@/tools/wordpress/delete_media'
import { deletePageTool } from '@/tools/wordpress/delete_page'
import { deletePostTool } from '@/tools/wordpress/delete_post'
import { deleteTagTool } from '@/tools/wordpress/delete_tag'
import { getCategoryTool } from '@/tools/wordpress/get_category'
import { getCurrentUserTool } from '@/tools/wordpress/get_current_user'
import { getMediaTool } from '@/tools/wordpress/get_media'
import { getPageTool } from '@/tools/wordpress/get_page'
import { getPostTool } from '@/tools/wordpress/get_post'
import { getTagTool } from '@/tools/wordpress/get_tag'
import { getUserTool } from '@/tools/wordpress/get_user'
import { listCategoriesTool } from '@/tools/wordpress/list_categories'
import { listCommentsTool } from '@/tools/wordpress/list_comments'
import { listMediaTool } from '@/tools/wordpress/list_media'
import { listPagesTool } from '@/tools/wordpress/list_pages'
import { listPostsTool } from '@/tools/wordpress/list_posts'
import { listTagsTool } from '@/tools/wordpress/list_tags'
import { listUsersTool } from '@/tools/wordpress/list_users'
import { searchContentTool } from '@/tools/wordpress/search_content'
import { updateCategoryTool } from '@/tools/wordpress/update_category'
import { updateCommentTool } from '@/tools/wordpress/update_comment'
import { updatePageTool } from '@/tools/wordpress/update_page'
import { updatePostTool } from '@/tools/wordpress/update_post'
import { updateTagTool } from '@/tools/wordpress/update_tag'
import { uploadMediaTool } from '@/tools/wordpress/upload_media'
// Post operations
export const wordpressCreatePostTool = createPostTool
export const wordpressUpdatePostTool = updatePostTool
export const wordpressDeletePostTool = deletePostTool
export const wordpressGetPostTool = getPostTool
export const wordpressListPostsTool = listPostsTool
// Page operations
export const wordpressCreatePageTool = createPageTool
export const wordpressUpdatePageTool = updatePageTool
export const wordpressDeletePageTool = deletePageTool
export const wordpressGetPageTool = getPageTool
export const wordpressListPagesTool = listPagesTool
// Media operations
export const wordpressUploadMediaTool = uploadMediaTool
export const wordpressGetMediaTool = getMediaTool
export const wordpressListMediaTool = listMediaTool
export const wordpressDeleteMediaTool = deleteMediaTool
// Comment operations
export const wordpressCreateCommentTool = createCommentTool
export const wordpressListCommentsTool = listCommentsTool
export const wordpressUpdateCommentTool = updateCommentTool
export const wordpressDeleteCommentTool = deleteCommentTool
// Category operations
export const wordpressCreateCategoryTool = createCategoryTool
export const wordpressListCategoriesTool = listCategoriesTool
export const wordpressGetCategoryTool = getCategoryTool
export const wordpressUpdateCategoryTool = updateCategoryTool
export const wordpressDeleteCategoryTool = deleteCategoryTool
// Tag operations
export const wordpressCreateTagTool = createTagTool
export const wordpressListTagsTool = listTagsTool
export const wordpressGetTagTool = getTagTool
export const wordpressUpdateTagTool = updateTagTool
export const wordpressDeleteTagTool = deleteTagTool
// User operations
export const wordpressGetCurrentUserTool = getCurrentUserTool
export const wordpressListUsersTool = listUsersTool
export const wordpressGetUserTool = getUserTool
// Search operations
export const wordpressSearchContentTool = searchContentTool
+131
View File
@@ -0,0 +1,131 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressListCategoriesParams,
type WordPressListCategoriesResponse,
} from '@/tools/wordpress/types'
export const listCategoriesTool: ToolConfig<
WordPressListCategoriesParams,
WordPressListCategoriesResponse
> = {
id: 'wordpress_list_categories',
name: 'WordPress List Categories',
description: 'List categories from WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of categories per request (e.g., 10, 25, 50). Default: 10, max: 100',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (e.g., 1, 2, 3)',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter categories (e.g., "news", "technology")',
},
order: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Order direction: asc or desc',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.perPage) queryParams.append('per_page', String(params.perPage))
if (params.page) queryParams.append('page', String(params.page))
if (params.search) queryParams.append('search', params.search)
if (params.order) queryParams.append('order', params.order)
const queryString = queryParams.toString()
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/categories${queryString ? `?${queryString}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
const total = Number.parseInt(response.headers.get('X-WP-Total') || '0', 10)
const totalPages = Number.parseInt(response.headers.get('X-WP-TotalPages') || '0', 10)
return {
success: true,
output: {
categories: data.map((cat: any) => ({
id: cat.id,
count: cat.count,
description: cat.description,
link: cat.link,
name: cat.name,
slug: cat.slug,
taxonomy: cat.taxonomy,
parent: cat.parent,
})),
total,
totalPages,
},
}
},
outputs: {
categories: {
type: 'array',
description: 'List of categories',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Category ID' },
count: { type: 'number', description: 'Number of posts in this category' },
description: { type: 'string', description: 'Category description' },
link: { type: 'string', description: 'Category archive URL' },
name: { type: 'string', description: 'Category name' },
slug: { type: 'string', description: 'Category slug' },
taxonomy: { type: 'string', description: 'Taxonomy name' },
parent: { type: 'number', description: 'Parent category ID' },
},
},
},
total: {
type: 'number',
description: 'Total number of categories',
},
totalPages: {
type: 'number',
description: 'Total number of result pages',
},
},
}
+158
View File
@@ -0,0 +1,158 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressListCommentsParams,
type WordPressListCommentsResponse,
} from '@/tools/wordpress/types'
export const listCommentsTool: ToolConfig<
WordPressListCommentsParams,
WordPressListCommentsResponse
> = {
id: 'wordpress_list_comments',
name: 'WordPress List Comments',
description: 'List comments from WordPress.com with optional filters',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of comments per request (e.g., 10, 25, 50). Default: 10, max: 100',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (e.g., 1, 2, 3)',
},
postId: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Filter by post ID (e.g., 123, 456)',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by comment status: approved, hold, spam, trash',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter comments (e.g., "question", "feedback")',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Order by field: date, id, parent',
},
order: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Order direction: asc or desc',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.perPage) queryParams.append('per_page', String(params.perPage))
if (params.page) queryParams.append('page', String(params.page))
if (params.postId) queryParams.append('post', String(params.postId))
if (params.status) queryParams.append('status', params.status)
if (params.search) queryParams.append('search', params.search)
if (params.orderBy) queryParams.append('orderby', params.orderBy)
if (params.order) queryParams.append('order', params.order)
const queryString = queryParams.toString()
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/comments${queryString ? `?${queryString}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
const total = Number.parseInt(response.headers.get('X-WP-Total') || '0', 10)
const totalPages = Number.parseInt(response.headers.get('X-WP-TotalPages') || '0', 10)
return {
success: true,
output: {
comments: data.map((comment: any) => ({
id: comment.id,
post: comment.post,
parent: comment.parent,
author: comment.author,
author_name: comment.author_name,
author_email: comment.author_email,
author_url: comment.author_url,
date: comment.date,
content: comment.content,
link: comment.link,
status: comment.status,
})),
total,
totalPages,
},
}
},
outputs: {
comments: {
type: 'array',
description: 'List of comments',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Comment ID' },
post: { type: 'number', description: 'Post ID' },
parent: { type: 'number', description: 'Parent comment ID' },
author: { type: 'number', description: 'Author user ID' },
author_name: { type: 'string', description: 'Author display name' },
author_email: { type: 'string', description: 'Author email' },
author_url: { type: 'string', description: 'Author URL' },
date: { type: 'string', description: 'Comment date' },
content: { type: 'object', description: 'Comment content object' },
link: { type: 'string', description: 'Comment permalink' },
status: { type: 'string', description: 'Comment status' },
},
},
},
total: {
type: 'number',
description: 'Total number of comments',
},
totalPages: {
type: 'number',
description: 'Total number of result pages',
},
},
}
+157
View File
@@ -0,0 +1,157 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressListMediaParams,
type WordPressListMediaResponse,
} from '@/tools/wordpress/types'
export const listMediaTool: ToolConfig<WordPressListMediaParams, WordPressListMediaResponse> = {
id: 'wordpress_list_media',
name: 'WordPress List Media',
description: 'List media items from the WordPress.com media library',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of media items per request (e.g., 10, 25, 50). Default: 10, max: 100',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (e.g., 1, 2, 3)',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter media (e.g., "logo", "banner")',
},
mediaType: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by media type: image, video, audio, application',
},
mimeType: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by specific MIME type (e.g., image/jpeg, image/png)',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Order by field: date, id, title, slug',
},
order: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Order direction: asc or desc',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.perPage) queryParams.append('per_page', String(params.perPage))
if (params.page) queryParams.append('page', String(params.page))
if (params.search) queryParams.append('search', params.search)
if (params.mediaType) queryParams.append('media_type', params.mediaType)
if (params.mimeType) queryParams.append('mime_type', params.mimeType)
if (params.orderBy) queryParams.append('orderby', params.orderBy)
if (params.order) queryParams.append('order', params.order)
const queryString = queryParams.toString()
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/media${queryString ? `?${queryString}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
const total = Number.parseInt(response.headers.get('X-WP-Total') || '0', 10)
const totalPages = Number.parseInt(response.headers.get('X-WP-TotalPages') || '0', 10)
return {
success: true,
output: {
media: data.map((item: any) => ({
id: item.id,
date: item.date,
slug: item.slug,
type: item.type,
link: item.link,
title: item.title,
caption: item.caption,
alt_text: item.alt_text,
media_type: item.media_type,
mime_type: item.mime_type,
source_url: item.source_url,
media_details: item.media_details,
})),
total,
totalPages,
},
}
},
outputs: {
media: {
type: 'array',
description: 'List of media items',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Media ID' },
date: { type: 'string', description: 'Upload date' },
slug: { type: 'string', description: 'Media slug' },
type: { type: 'string', description: 'Content type' },
link: { type: 'string', description: 'Media page URL' },
title: { type: 'object', description: 'Media title object' },
caption: { type: 'object', description: 'Media caption object' },
alt_text: { type: 'string', description: 'Alt text' },
media_type: { type: 'string', description: 'Media type (image, video, etc.)' },
mime_type: { type: 'string', description: 'MIME type' },
source_url: { type: 'string', description: 'Direct URL to the media file' },
media_details: { type: 'object', description: 'Media details (dimensions, etc.)' },
},
},
},
total: {
type: 'number',
description: 'Total number of media items',
},
totalPages: {
type: 'number',
description: 'Total number of result pages',
},
},
}
+161
View File
@@ -0,0 +1,161 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressListPagesParams,
type WordPressListPagesResponse,
} from '@/tools/wordpress/types'
export const listPagesTool: ToolConfig<WordPressListPagesParams, WordPressListPagesResponse> = {
id: 'wordpress_list_pages',
name: 'WordPress List Pages',
description: 'List pages from WordPress.com with optional filters',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of pages per request (e.g., 10, 25, 50). Default: 10, max: 100',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (e.g., 1, 2, 3)',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Page status filter: publish, draft, pending, private',
},
parent: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Filter by parent page ID (e.g., 123)',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter pages (e.g., "about", "contact")',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Order by field: date, id, title, slug, modified, menu_order',
},
order: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Order direction: asc or desc',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.perPage) queryParams.append('per_page', String(params.perPage))
if (params.page) queryParams.append('page', String(params.page))
if (params.status) queryParams.append('status', params.status)
if (params.parent !== undefined) queryParams.append('parent', String(params.parent))
if (params.search) queryParams.append('search', params.search)
if (params.orderBy) queryParams.append('orderby', params.orderBy)
if (params.order) queryParams.append('order', params.order)
const queryString = queryParams.toString()
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/pages${queryString ? `?${queryString}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
const total = Number.parseInt(response.headers.get('X-WP-Total') || '0', 10)
const totalPages = Number.parseInt(response.headers.get('X-WP-TotalPages') || '0', 10)
return {
success: true,
output: {
pages: data.map((page: any) => ({
id: page.id,
date: page.date,
modified: page.modified,
slug: page.slug,
status: page.status,
type: page.type,
link: page.link,
title: page.title,
content: page.content,
excerpt: page.excerpt,
author: page.author,
featured_media: page.featured_media,
parent: page.parent,
menu_order: page.menu_order,
})),
total,
totalPages,
},
}
},
outputs: {
pages: {
type: 'array',
description: 'List of pages',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Page ID' },
date: { type: 'string', description: 'Page creation date' },
modified: { type: 'string', description: 'Page modification date' },
slug: { type: 'string', description: 'Page slug' },
status: { type: 'string', description: 'Page status' },
type: { type: 'string', description: 'Content type' },
link: { type: 'string', description: 'Page URL' },
title: { type: 'object', description: 'Page title object' },
content: { type: 'object', description: 'Page content object' },
excerpt: { type: 'object', description: 'Page excerpt object' },
author: { type: 'number', description: 'Author ID' },
featured_media: { type: 'number', description: 'Featured media ID' },
parent: { type: 'number', description: 'Parent page ID' },
menu_order: { type: 'number', description: 'Menu order' },
},
},
},
total: {
type: 'number',
description: 'Total number of pages',
},
totalPages: {
type: 'number',
description: 'Total number of result pages',
},
},
}
+189
View File
@@ -0,0 +1,189 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressListPostsParams,
type WordPressListPostsResponse,
} from '@/tools/wordpress/types'
export const listPostsTool: ToolConfig<WordPressListPostsParams, WordPressListPostsResponse> = {
id: 'wordpress_list_posts',
name: 'WordPress List Posts',
description: 'List blog posts from WordPress.com with optional filters',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of posts per page (e.g., 10, 25, 50). Default: 10, max: 100',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (e.g., 1, 2, 3)',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Post status filter: publish, draft, pending, private',
},
author: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Filter by author ID (e.g., 1, 42)',
},
categories: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated category IDs to filter by (e.g., "1,2,3")',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated tag IDs to filter by (e.g., "5,10,15")',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter posts (e.g., "tutorial", "announcement")',
},
orderBy: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Order by field: date, id, title, slug, modified',
},
order: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Order direction: asc or desc',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.perPage) queryParams.append('per_page', String(params.perPage))
if (params.page) queryParams.append('page', String(params.page))
if (params.status) queryParams.append('status', params.status)
if (params.author) queryParams.append('author', String(params.author))
if (params.search) queryParams.append('search', params.search)
if (params.orderBy) queryParams.append('orderby', params.orderBy)
if (params.order) queryParams.append('order', params.order)
if (params.categories) {
const catIds = params.categories
.split(',')
.map((id: string) => id.trim())
.filter((id: string) => id.length > 0)
queryParams.append('categories', catIds.join(','))
}
if (params.tags) {
const tagIds = params.tags
.split(',')
.map((id: string) => id.trim())
.filter((id: string) => id.length > 0)
queryParams.append('tags', tagIds.join(','))
}
const queryString = queryParams.toString()
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/posts${queryString ? `?${queryString}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
const total = Number.parseInt(response.headers.get('X-WP-Total') || '0', 10)
const totalPages = Number.parseInt(response.headers.get('X-WP-TotalPages') || '0', 10)
return {
success: true,
output: {
posts: data.map((post: any) => ({
id: post.id,
date: post.date,
modified: post.modified,
slug: post.slug,
status: post.status,
type: post.type,
link: post.link,
title: post.title,
content: post.content,
excerpt: post.excerpt,
author: post.author,
featured_media: post.featured_media,
categories: post.categories || [],
tags: post.tags || [],
})),
total,
totalPages,
},
}
},
outputs: {
posts: {
type: 'array',
description: 'List of posts',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Post ID' },
date: { type: 'string', description: 'Post creation date' },
modified: { type: 'string', description: 'Post modification date' },
slug: { type: 'string', description: 'Post slug' },
status: { type: 'string', description: 'Post status' },
type: { type: 'string', description: 'Post type' },
link: { type: 'string', description: 'Post URL' },
title: { type: 'object', description: 'Post title object' },
content: { type: 'object', description: 'Post content object' },
excerpt: { type: 'object', description: 'Post excerpt object' },
author: { type: 'number', description: 'Author ID' },
featured_media: { type: 'number', description: 'Featured media ID' },
categories: { type: 'array', description: 'Category IDs' },
tags: { type: 'array', description: 'Tag IDs' },
},
},
},
total: {
type: 'number',
description: 'Total number of posts',
},
totalPages: {
type: 'number',
description: 'Total number of pages',
},
},
}
+126
View File
@@ -0,0 +1,126 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressListTagsParams,
type WordPressListTagsResponse,
} from '@/tools/wordpress/types'
export const listTagsTool: ToolConfig<WordPressListTagsParams, WordPressListTagsResponse> = {
id: 'wordpress_list_tags',
name: 'WordPress List Tags',
description: 'List tags from WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of tags per request (e.g., 10, 25, 50). Default: 10, max: 100',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (e.g., 1, 2, 3)',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter tags (e.g., "javascript", "tutorial")',
},
order: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Order direction: asc or desc',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.perPage) queryParams.append('per_page', String(params.perPage))
if (params.page) queryParams.append('page', String(params.page))
if (params.search) queryParams.append('search', params.search)
if (params.order) queryParams.append('order', params.order)
const queryString = queryParams.toString()
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/tags${queryString ? `?${queryString}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
const total = Number.parseInt(response.headers.get('X-WP-Total') || '0', 10)
const totalPages = Number.parseInt(response.headers.get('X-WP-TotalPages') || '0', 10)
return {
success: true,
output: {
tags: data.map((tag: any) => ({
id: tag.id,
count: tag.count,
description: tag.description,
link: tag.link,
name: tag.name,
slug: tag.slug,
taxonomy: tag.taxonomy,
})),
total,
totalPages,
},
}
},
outputs: {
tags: {
type: 'array',
description: 'List of tags',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Tag ID' },
count: { type: 'number', description: 'Number of posts with this tag' },
description: { type: 'string', description: 'Tag description' },
link: { type: 'string', description: 'Tag archive URL' },
name: { type: 'string', description: 'Tag name' },
slug: { type: 'string', description: 'Tag slug' },
taxonomy: { type: 'string', description: 'Taxonomy name' },
},
},
},
total: {
type: 'number',
description: 'Total number of tags',
},
totalPages: {
type: 'number',
description: 'Total number of result pages',
},
},
}
+143
View File
@@ -0,0 +1,143 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressListUsersParams,
type WordPressListUsersResponse,
} from '@/tools/wordpress/types'
export const listUsersTool: ToolConfig<WordPressListUsersParams, WordPressListUsersResponse> = {
id: 'wordpress_list_users',
name: 'WordPress List Users',
description: 'List users from WordPress.com (requires admin privileges)',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of users per request (e.g., 10, 25, 50). Default: 10, max: 100',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination (e.g., 1, 2, 3)',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter users (e.g., "john", "admin")',
},
roles: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated role names to filter by (e.g., "administrator,editor")',
},
order: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Order direction: asc or desc',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.perPage) queryParams.append('per_page', String(params.perPage))
if (params.page) queryParams.append('page', String(params.page))
if (params.search) queryParams.append('search', params.search)
if (params.roles) queryParams.append('roles', params.roles)
if (params.order) queryParams.append('order', params.order)
const queryString = queryParams.toString()
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/users${queryString ? `?${queryString}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
const total = Number.parseInt(response.headers.get('X-WP-Total') || '0', 10)
const totalPages = Number.parseInt(response.headers.get('X-WP-TotalPages') || '0', 10)
return {
success: true,
output: {
users: data.map((user: any) => ({
id: user.id,
username: user.username,
name: user.name,
first_name: user.first_name,
last_name: user.last_name,
email: user.email,
url: user.url,
description: user.description,
link: user.link,
slug: user.slug,
roles: user.roles || [],
avatar_urls: user.avatar_urls,
})),
total,
totalPages,
},
}
},
outputs: {
users: {
type: 'array',
description: 'List of users',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'User ID' },
username: { type: 'string', description: 'Username' },
name: { type: 'string', description: 'Display name' },
first_name: { type: 'string', description: 'First name' },
last_name: { type: 'string', description: 'Last name' },
email: { type: 'string', description: 'Email address' },
url: { type: 'string', description: 'User website URL' },
description: { type: 'string', description: 'User bio' },
link: { type: 'string', description: 'Author archive URL' },
slug: { type: 'string', description: 'User slug' },
roles: { type: 'array', description: 'User roles' },
avatar_urls: { type: 'object', description: 'Avatar URLs at different sizes' },
},
},
},
total: {
type: 'number',
description: 'Total number of users',
},
totalPages: {
type: 'number',
description: 'Total number of result pages',
},
},
}
+135
View File
@@ -0,0 +1,135 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressSearchContentParams,
type WordPressSearchContentResponse,
} from '@/tools/wordpress/types'
export const searchContentTool: ToolConfig<
WordPressSearchContentParams,
WordPressSearchContentResponse
> = {
id: 'wordpress_search_content',
name: 'WordPress Search Content',
description: 'Search across all content types in WordPress.com (posts, pages, media)',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
query: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Search query',
},
perPage: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per request (default: 10, max: 100)',
},
page: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination',
},
type: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Filter by search index type: post, term, or post-format',
},
subtype: {
type: 'string',
required: false,
visibility: 'user-only',
description:
'Filter by subtype within the selected type (e.g., post or page when type is post)',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
queryParams.append('search', params.query)
if (params.perPage) queryParams.append('per_page', String(params.perPage))
if (params.page) queryParams.append('page', String(params.page))
if (params.type) queryParams.append('type', params.type)
if (params.subtype) queryParams.append('subtype', params.subtype)
return `${WORDPRESS_COM_API_BASE}/${params.siteId}/search?${queryParams.toString()}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
const total = Number.parseInt(response.headers.get('X-WP-Total') || '0', 10)
const totalPages = Number.parseInt(response.headers.get('X-WP-TotalPages') || '0', 10)
return {
success: true,
output: {
results: data.map((result: any) => ({
id: result.id,
title: result.title,
url: result.url,
type: result.type,
subtype: result.subtype,
})),
total,
totalPages,
},
}
},
outputs: {
results: {
type: 'array',
description: 'Search results',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Content ID' },
title: { type: 'string', description: 'Content title' },
url: { type: 'string', description: 'Content URL' },
type: { type: 'string', description: 'Content type (post, term, or post-format)' },
subtype: {
type: 'string',
description: 'Subtype within the content type (e.g., post, page)',
},
},
},
},
total: {
type: 'number',
description: 'Total number of results',
},
totalPages: {
type: 'number',
description: 'Total number of result pages',
},
},
}
+708
View File
@@ -0,0 +1,708 @@
// Common types for WordPress REST API tools
import type { UserFile } from '@/executor/types'
import type { ToolResponse } from '@/tools/types'
// Common parameters for all WordPress tools (WordPress.com OAuth)
// Note: accessToken is injected by the OAuth system at runtime, not defined in tool params
interface WordPressBaseParams {
siteId: string // WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)
accessToken: string // OAuth access token (injected by OAuth system)
}
// WordPress.com API base URL
export const WORDPRESS_COM_API_BASE = 'https://public-api.wordpress.com/wp/v2/sites'
// Post status types
export type PostStatus = 'publish' | 'draft' | 'pending' | 'private' | 'future'
// Comment status types
export type CommentStatus = 'approved' | 'hold' | 'spam' | 'trash'
// ============================================
// POST OPERATIONS
// ============================================
// Create Post
export interface WordPressCreatePostParams extends WordPressBaseParams {
title: string
content?: string
status?: PostStatus
excerpt?: string
categories?: string // Comma-separated category IDs
tags?: string // Comma-separated tag IDs
featuredMedia?: number
slug?: string
}
interface WordPressPost {
id: number
date: string
modified: string
slug: string
status: PostStatus
type: string
link: string
title: {
rendered: string
}
content: {
rendered: string
}
excerpt: {
rendered: string
}
author: number
featured_media: number
categories: number[]
tags: number[]
}
export interface WordPressCreatePostResponse extends ToolResponse {
output: {
post: WordPressPost
}
}
// Update Post
export interface WordPressUpdatePostParams extends WordPressBaseParams {
postId: number
title?: string
content?: string
status?: PostStatus
excerpt?: string
categories?: string
tags?: string
featuredMedia?: number
slug?: string
}
export interface WordPressUpdatePostResponse extends ToolResponse {
output: {
post: WordPressPost
}
}
// Delete Post
export interface WordPressDeletePostParams extends WordPressBaseParams {
postId: number
force?: boolean // Bypass trash and force delete
}
export interface WordPressDeletePostResponse extends ToolResponse {
output: {
deleted: boolean
post: WordPressPost
}
}
// Get Post
export interface WordPressGetPostParams extends WordPressBaseParams {
postId: number
}
export interface WordPressGetPostResponse extends ToolResponse {
output: {
post: WordPressPost
}
}
// List Posts
export interface WordPressListPostsParams extends WordPressBaseParams {
perPage?: number
page?: number
status?: PostStatus
author?: number
categories?: string
tags?: string
search?: string
orderBy?: 'date' | 'id' | 'title' | 'slug' | 'modified'
order?: 'asc' | 'desc'
}
export interface WordPressListPostsResponse extends ToolResponse {
output: {
posts: WordPressPost[]
total: number
totalPages: number
}
}
// Search Posts
interface WordPressSearchPostsParams extends WordPressBaseParams {
query: string
perPage?: number
page?: number
}
interface WordPressSearchPostsResponse extends ToolResponse {
output: {
posts: WordPressPost[]
total: number
totalPages: number
}
}
// ============================================
// PAGE OPERATIONS
// ============================================
// Create Page
export interface WordPressCreatePageParams extends WordPressBaseParams {
title: string
content?: string
status?: PostStatus
excerpt?: string
parent?: number
menuOrder?: number
featuredMedia?: number
slug?: string
}
interface WordPressPage {
id: number
date: string
modified: string
slug: string
status: PostStatus
type: string
link: string
title: {
rendered: string
}
content: {
rendered: string
}
excerpt: {
rendered: string
}
author: number
featured_media: number
parent: number
menu_order: number
}
export interface WordPressCreatePageResponse extends ToolResponse {
output: {
page: WordPressPage
}
}
// Update Page
export interface WordPressUpdatePageParams extends WordPressBaseParams {
pageId: number
title?: string
content?: string
status?: PostStatus
excerpt?: string
parent?: number
menuOrder?: number
featuredMedia?: number
slug?: string
}
export interface WordPressUpdatePageResponse extends ToolResponse {
output: {
page: WordPressPage
}
}
// Delete Page
export interface WordPressDeletePageParams extends WordPressBaseParams {
pageId: number
force?: boolean
}
export interface WordPressDeletePageResponse extends ToolResponse {
output: {
deleted: boolean
page: WordPressPage
}
}
// Get Page
export interface WordPressGetPageParams extends WordPressBaseParams {
pageId: number
}
export interface WordPressGetPageResponse extends ToolResponse {
output: {
page: WordPressPage
}
}
// List Pages
export interface WordPressListPagesParams extends WordPressBaseParams {
perPage?: number
page?: number
status?: PostStatus
parent?: number
search?: string
orderBy?: 'date' | 'id' | 'title' | 'slug' | 'modified' | 'menu_order'
order?: 'asc' | 'desc'
}
export interface WordPressListPagesResponse extends ToolResponse {
output: {
pages: WordPressPage[]
total: number
totalPages: number
}
}
// ============================================
// MEDIA OPERATIONS
// ============================================
// Upload Media
export interface WordPressUploadMediaParams extends WordPressBaseParams {
file: UserFile
filename?: string // Optional filename override
title?: string
caption?: string
altText?: string
description?: string
}
interface WordPressMedia {
id: number
date: string
slug: string
type: string
link: string
title: {
rendered: string
}
caption: {
rendered: string
}
alt_text: string
media_type: string
mime_type: string
source_url: string
media_details?: {
width?: number
height?: number
file?: string
}
}
export interface WordPressUploadMediaResponse extends ToolResponse {
output: {
media: WordPressMedia
}
}
// Get Media
export interface WordPressGetMediaParams extends WordPressBaseParams {
mediaId: number
}
export interface WordPressGetMediaResponse extends ToolResponse {
output: {
media: WordPressMedia
}
}
// List Media
export interface WordPressListMediaParams extends WordPressBaseParams {
perPage?: number
page?: number
search?: string
mediaType?: 'image' | 'video' | 'audio' | 'application'
mimeType?: string
orderBy?: 'date' | 'id' | 'title' | 'slug'
order?: 'asc' | 'desc'
}
export interface WordPressListMediaResponse extends ToolResponse {
output: {
media: WordPressMedia[]
total: number
totalPages: number
}
}
// Delete Media
export interface WordPressDeleteMediaParams extends WordPressBaseParams {
mediaId: number
}
export interface WordPressDeleteMediaResponse extends ToolResponse {
output: {
deleted: boolean
media: WordPressMedia
}
}
// ============================================
// COMMENT OPERATIONS
// ============================================
// Create Comment
export interface WordPressCreateCommentParams extends WordPressBaseParams {
postId: number
content: string
parent?: number
authorName?: string
authorEmail?: string
authorUrl?: string
}
interface WordPressComment {
id: number
post: number
parent: number
author: number
author_name: string
author_email?: string
author_url: string
date: string
content: {
rendered: string
}
link: string
status: string
}
export interface WordPressCreateCommentResponse extends ToolResponse {
output: {
comment: WordPressComment
}
}
// Get Comment
interface WordPressGetCommentParams extends WordPressBaseParams {
commentId: number
}
interface WordPressGetCommentResponse extends ToolResponse {
output: {
comment: WordPressComment
}
}
// List Comments
export interface WordPressListCommentsParams extends WordPressBaseParams {
perPage?: number
page?: number
postId?: number
status?: CommentStatus
search?: string
orderBy?: 'date' | 'id' | 'parent'
order?: 'asc' | 'desc'
}
export interface WordPressListCommentsResponse extends ToolResponse {
output: {
comments: WordPressComment[]
total: number
totalPages: number
}
}
// Update Comment
export interface WordPressUpdateCommentParams extends WordPressBaseParams {
commentId: number
content?: string
status?: CommentStatus
}
export interface WordPressUpdateCommentResponse extends ToolResponse {
output: {
comment: WordPressComment
}
}
// Delete Comment
export interface WordPressDeleteCommentParams extends WordPressBaseParams {
commentId: number
force?: boolean
}
export interface WordPressDeleteCommentResponse extends ToolResponse {
output: {
deleted: boolean
comment: WordPressComment
}
}
// ============================================
// TAXONOMY OPERATIONS (Categories & Tags)
// ============================================
// Create Category
export interface WordPressCreateCategoryParams extends WordPressBaseParams {
name: string
description?: string
parent?: number
slug?: string
}
interface WordPressCategory {
id: number
count: number
description: string
link: string
name: string
slug: string
taxonomy: string
parent: number
}
export interface WordPressCreateCategoryResponse extends ToolResponse {
output: {
category: WordPressCategory
}
}
// List Categories
export interface WordPressListCategoriesParams extends WordPressBaseParams {
perPage?: number
page?: number
search?: string
order?: 'asc' | 'desc'
}
export interface WordPressListCategoriesResponse extends ToolResponse {
output: {
categories: WordPressCategory[]
total: number
totalPages: number
}
}
// Get Category
export interface WordPressGetCategoryParams extends WordPressBaseParams {
categoryId: number
}
export interface WordPressGetCategoryResponse extends ToolResponse {
output: {
category: WordPressCategory
}
}
// Update Category
export interface WordPressUpdateCategoryParams extends WordPressBaseParams {
categoryId: number
name?: string
description?: string
parent?: number
slug?: string
}
export interface WordPressUpdateCategoryResponse extends ToolResponse {
output: {
category: WordPressCategory
}
}
// Delete Category
export interface WordPressDeleteCategoryParams extends WordPressBaseParams {
categoryId: number
}
export interface WordPressDeleteCategoryResponse extends ToolResponse {
output: {
deleted: boolean
category: WordPressCategory
}
}
// Create Tag
export interface WordPressCreateTagParams extends WordPressBaseParams {
name: string
description?: string
slug?: string
}
interface WordPressTag {
id: number
count: number
description: string
link: string
name: string
slug: string
taxonomy: string
}
export interface WordPressCreateTagResponse extends ToolResponse {
output: {
tag: WordPressTag
}
}
// List Tags
export interface WordPressListTagsParams extends WordPressBaseParams {
perPage?: number
page?: number
search?: string
order?: 'asc' | 'desc'
}
export interface WordPressListTagsResponse extends ToolResponse {
output: {
tags: WordPressTag[]
total: number
totalPages: number
}
}
// Get Tag
export interface WordPressGetTagParams extends WordPressBaseParams {
tagId: number
}
export interface WordPressGetTagResponse extends ToolResponse {
output: {
tag: WordPressTag
}
}
// Update Tag
export interface WordPressUpdateTagParams extends WordPressBaseParams {
tagId: number
name?: string
description?: string
slug?: string
}
export interface WordPressUpdateTagResponse extends ToolResponse {
output: {
tag: WordPressTag
}
}
// Delete Tag
export interface WordPressDeleteTagParams extends WordPressBaseParams {
tagId: number
}
export interface WordPressDeleteTagResponse extends ToolResponse {
output: {
deleted: boolean
tag: WordPressTag
}
}
// ============================================
// USER OPERATIONS
// ============================================
// Get Current User
export interface WordPressGetCurrentUserParams extends WordPressBaseParams {}
interface WordPressUser {
id: number
username: string
name: string
first_name: string
last_name: string
email?: string
url: string
description: string
link: string
slug: string
roles: string[]
avatar_urls?: Record<string, string>
}
export interface WordPressGetCurrentUserResponse extends ToolResponse {
output: {
user: WordPressUser
}
}
// List Users
export interface WordPressListUsersParams extends WordPressBaseParams {
perPage?: number
page?: number
search?: string
roles?: string
order?: 'asc' | 'desc'
}
export interface WordPressListUsersResponse extends ToolResponse {
output: {
users: WordPressUser[]
total: number
totalPages: number
}
}
// Get User
export interface WordPressGetUserParams extends WordPressBaseParams {
userId: number
}
export interface WordPressGetUserResponse extends ToolResponse {
output: {
user: WordPressUser
}
}
// ============================================
// SEARCH OPERATIONS
// ============================================
// Search Content
export interface WordPressSearchContentParams extends WordPressBaseParams {
query: string
perPage?: number
page?: number
type?: 'post' | 'term' | 'post-format'
subtype?: string
}
interface WordPressSearchResult {
id: number
title: string
url: string
type: string
subtype: string
}
export interface WordPressSearchContentResponse extends ToolResponse {
output: {
results: WordPressSearchResult[]
total: number
totalPages: number
}
}
// Union type for all WordPress responses
export type WordPressResponse =
| WordPressCreatePostResponse
| WordPressUpdatePostResponse
| WordPressDeletePostResponse
| WordPressGetPostResponse
| WordPressListPostsResponse
| WordPressSearchPostsResponse
| WordPressCreatePageResponse
| WordPressUpdatePageResponse
| WordPressDeletePageResponse
| WordPressGetPageResponse
| WordPressListPagesResponse
| WordPressUploadMediaResponse
| WordPressGetMediaResponse
| WordPressListMediaResponse
| WordPressDeleteMediaResponse
| WordPressCreateCommentResponse
| WordPressGetCommentResponse
| WordPressListCommentsResponse
| WordPressUpdateCommentResponse
| WordPressDeleteCommentResponse
| WordPressCreateCategoryResponse
| WordPressListCategoriesResponse
| WordPressGetCategoryResponse
| WordPressUpdateCategoryResponse
| WordPressDeleteCategoryResponse
| WordPressCreateTagResponse
| WordPressListTagsResponse
| WordPressGetTagResponse
| WordPressUpdateTagResponse
| WordPressDeleteTagResponse
| WordPressGetCurrentUserResponse
| WordPressListUsersResponse
| WordPressGetUserResponse
| WordPressSearchContentResponse
+122
View File
@@ -0,0 +1,122 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressUpdateCategoryParams,
type WordPressUpdateCategoryResponse,
} from '@/tools/wordpress/types'
export const updateCategoryTool: ToolConfig<
WordPressUpdateCategoryParams,
WordPressUpdateCategoryResponse
> = {
id: 'wordpress_update_category',
name: 'WordPress Update Category',
description: 'Update an existing category in WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
categoryId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the category to update',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Category name',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Category description',
},
parent: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Parent category ID for hierarchical categories',
},
slug: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'URL slug for the category',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/categories/${params.categoryId}`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.name) body.name = params.name
if (params.description) body.description = params.description
if (params.parent !== undefined) body.parent = params.parent
if (params.slug) body.slug = params.slug
return body
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
category: {
id: data.id,
count: data.count,
description: data.description,
link: data.link,
name: data.name,
slug: data.slug,
taxonomy: data.taxonomy,
parent: data.parent,
},
},
}
},
outputs: {
category: {
type: 'object',
description: 'The updated category',
properties: {
id: { type: 'number', description: 'Category ID' },
count: { type: 'number', description: 'Number of posts in this category' },
description: { type: 'string', description: 'Category description' },
link: { type: 'string', description: 'Category archive URL' },
name: { type: 'string', description: 'Category name' },
slug: { type: 'string', description: 'Category slug' },
taxonomy: { type: 'string', description: 'Taxonomy name' },
parent: { type: 'number', description: 'Parent category ID' },
},
},
},
}
+114
View File
@@ -0,0 +1,114 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressUpdateCommentParams,
type WordPressUpdateCommentResponse,
} from '@/tools/wordpress/types'
export const updateCommentTool: ToolConfig<
WordPressUpdateCommentParams,
WordPressUpdateCommentResponse
> = {
id: 'wordpress_update_comment',
name: 'WordPress Update Comment',
description: 'Update a comment in WordPress.com (content or status)',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
commentId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the comment to update',
},
content: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated comment content',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comment status: approved, hold, spam, trash',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/comments/${params.commentId}`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.content) body.content = params.content
if (params.status) body.status = params.status
return body
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
comment: {
id: data.id,
post: data.post,
parent: data.parent,
author: data.author,
author_name: data.author_name,
author_email: data.author_email,
author_url: data.author_url,
date: data.date,
content: data.content,
link: data.link,
status: data.status,
},
},
}
},
outputs: {
comment: {
type: 'object',
description: 'The updated comment',
properties: {
id: { type: 'number', description: 'Comment ID' },
post: { type: 'number', description: 'Post ID' },
parent: { type: 'number', description: 'Parent comment ID' },
author: { type: 'number', description: 'Author user ID' },
author_name: { type: 'string', description: 'Author display name' },
author_email: { type: 'string', description: 'Author email' },
author_url: { type: 'string', description: 'Author URL' },
date: { type: 'string', description: 'Comment date' },
content: { type: 'object', description: 'Comment content object' },
link: { type: 'string', description: 'Comment permalink' },
status: { type: 'string', description: 'Comment status' },
},
},
},
}
+159
View File
@@ -0,0 +1,159 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressUpdatePageParams,
type WordPressUpdatePageResponse,
} from '@/tools/wordpress/types'
export const updatePageTool: ToolConfig<WordPressUpdatePageParams, WordPressUpdatePageResponse> = {
id: 'wordpress_update_page',
name: 'WordPress Update Page',
description: 'Update an existing page in WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
pageId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the page to update',
},
title: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Page title',
},
content: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Page content (HTML or plain text)',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Page status: publish, draft, pending, private',
},
excerpt: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Page excerpt',
},
parent: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Parent page ID for hierarchical pages',
},
menuOrder: {
type: 'number',
required: false,
visibility: 'user-only',
description: 'Order in page menu',
},
featuredMedia: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Featured image media ID',
},
slug: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'URL slug for the page',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/pages/${params.pageId}`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.title) body.title = params.title
if (params.content) body.content = params.content
if (params.status) body.status = params.status
if (params.excerpt) body.excerpt = params.excerpt
if (params.slug) body.slug = params.slug
if (params.parent !== undefined) body.parent = params.parent
if (params.menuOrder !== undefined) body.menu_order = params.menuOrder
if (params.featuredMedia !== undefined) body.featured_media = params.featuredMedia
return body
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
page: {
id: data.id,
date: data.date,
modified: data.modified,
slug: data.slug,
status: data.status,
type: data.type,
link: data.link,
title: data.title,
content: data.content,
excerpt: data.excerpt,
author: data.author,
featured_media: data.featured_media,
parent: data.parent,
menu_order: data.menu_order,
},
},
}
},
outputs: {
page: {
type: 'object',
description: 'The updated page',
properties: {
id: { type: 'number', description: 'Page ID' },
date: { type: 'string', description: 'Page creation date' },
modified: { type: 'string', description: 'Page modification date' },
slug: { type: 'string', description: 'Page slug' },
status: { type: 'string', description: 'Page status' },
type: { type: 'string', description: 'Content type' },
link: { type: 'string', description: 'Page URL' },
title: { type: 'object', description: 'Page title object' },
content: { type: 'object', description: 'Page content object' },
excerpt: { type: 'object', description: 'Page excerpt object' },
author: { type: 'number', description: 'Author ID' },
featured_media: { type: 'number', description: 'Featured media ID' },
parent: { type: 'number', description: 'Parent page ID' },
menu_order: { type: 'number', description: 'Menu order' },
},
},
},
}
+171
View File
@@ -0,0 +1,171 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressUpdatePostParams,
type WordPressUpdatePostResponse,
} from '@/tools/wordpress/types'
export const updatePostTool: ToolConfig<WordPressUpdatePostParams, WordPressUpdatePostResponse> = {
id: 'wordpress_update_post',
name: 'WordPress Update Post',
description: 'Update an existing blog post in WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
postId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the post to update',
},
title: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Post title',
},
content: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Post content (HTML or plain text)',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Post status: publish, draft, pending, private, or future',
},
excerpt: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Post excerpt',
},
categories: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated category IDs',
},
tags: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated tag IDs',
},
featuredMedia: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Featured image media ID',
},
slug: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'URL slug for the post',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/posts/${params.postId}`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.title) body.title = params.title
if (params.content) body.content = params.content
if (params.status) body.status = params.status
if (params.excerpt) body.excerpt = params.excerpt
if (params.slug) body.slug = params.slug
if (params.featuredMedia !== undefined) body.featured_media = params.featuredMedia
if (params.categories) {
body.categories = params.categories
.split(',')
.map((id: string) => Number.parseInt(id.trim(), 10))
.filter((id: number) => !Number.isNaN(id))
}
if (params.tags) {
body.tags = params.tags
.split(',')
.map((id: string) => Number.parseInt(id.trim(), 10))
.filter((id: number) => !Number.isNaN(id))
}
return body
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
post: {
id: data.id,
date: data.date,
modified: data.modified,
slug: data.slug,
status: data.status,
type: data.type,
link: data.link,
title: data.title,
content: data.content,
excerpt: data.excerpt,
author: data.author,
featured_media: data.featured_media,
categories: data.categories || [],
tags: data.tags || [],
},
},
}
},
outputs: {
post: {
type: 'object',
description: 'The updated post',
properties: {
id: { type: 'number', description: 'Post ID' },
date: { type: 'string', description: 'Post creation date' },
modified: { type: 'string', description: 'Post modification date' },
slug: { type: 'string', description: 'Post slug' },
status: { type: 'string', description: 'Post status' },
type: { type: 'string', description: 'Post type' },
link: { type: 'string', description: 'Post URL' },
title: { type: 'object', description: 'Post title object' },
content: { type: 'object', description: 'Post content object' },
excerpt: { type: 'object', description: 'Post excerpt object' },
author: { type: 'number', description: 'Author ID' },
featured_media: { type: 'number', description: 'Featured media ID' },
categories: { type: 'array', description: 'Category IDs' },
tags: { type: 'array', description: 'Tag IDs' },
},
},
},
}
+110
View File
@@ -0,0 +1,110 @@
import type { ToolConfig } from '@/tools/types'
import {
WORDPRESS_COM_API_BASE,
type WordPressUpdateTagParams,
type WordPressUpdateTagResponse,
} from '@/tools/wordpress/types'
export const updateTagTool: ToolConfig<WordPressUpdateTagParams, WordPressUpdateTagResponse> = {
id: 'wordpress_update_tag',
name: 'WordPress Update Tag',
description: 'Update an existing tag in WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
tagId: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the tag to update',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Tag name',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Tag description',
},
slug: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'URL slug for the tag',
},
},
request: {
url: (params) => `${WORDPRESS_COM_API_BASE}/${params.siteId}/tags/${params.tagId}`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}),
body: (params) => {
const body: Record<string, any> = {}
if (params.name) body.name = params.name
if (params.description) body.description = params.description
if (params.slug) body.slug = params.slug
return body
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const error = await response.json().catch(() => ({}))
throw new Error(error.message || `WordPress API error: ${response.status}`)
}
const data = await response.json()
return {
success: true,
output: {
tag: {
id: data.id,
count: data.count,
description: data.description,
link: data.link,
name: data.name,
slug: data.slug,
taxonomy: data.taxonomy,
},
},
}
},
outputs: {
tag: {
type: 'object',
description: 'The updated tag',
properties: {
id: { type: 'number', description: 'Tag ID' },
count: { type: 'number', description: 'Number of posts with this tag' },
description: { type: 'string', description: 'Tag description' },
link: { type: 'string', description: 'Tag archive URL' },
name: { type: 'string', description: 'Tag name' },
slug: { type: 'string', description: 'Tag slug' },
taxonomy: { type: 'string', description: 'Taxonomy name' },
},
},
},
}
+118
View File
@@ -0,0 +1,118 @@
import type { ToolConfig } from '@/tools/types'
import type {
WordPressUploadMediaParams,
WordPressUploadMediaResponse,
} from '@/tools/wordpress/types'
export const uploadMediaTool: ToolConfig<WordPressUploadMediaParams, WordPressUploadMediaResponse> =
{
id: 'wordpress_upload_media',
name: 'WordPress Upload Media',
description: 'Upload a media file (image, video, document) to WordPress.com',
version: '1.0.0',
oauth: {
required: true,
provider: 'wordpress',
requiredScopes: ['global'],
},
params: {
siteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'WordPress.com site ID or domain (e.g., 12345678 or mysite.wordpress.com)',
},
file: {
type: 'file',
required: false,
visibility: 'user-only',
description: 'File to upload (UserFile object)',
},
filename: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional filename override (e.g., image.jpg)',
},
title: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Media title',
},
caption: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Media caption',
},
altText: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Alternative text for accessibility',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Media description',
},
},
request: {
url: () => '/api/tools/wordpress/upload',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
siteId: params.siteId,
file: params.file,
filename: params.filename,
title: params.title,
caption: params.caption,
altText: params.altText,
description: params.description,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!data.success) {
throw new Error(data.error || 'Failed to upload media to WordPress')
}
return {
success: true,
output: {
media: data.output.media,
},
}
},
outputs: {
media: {
type: 'object',
description: 'The uploaded media item',
properties: {
id: { type: 'number', description: 'Media ID' },
date: { type: 'string', description: 'Upload date' },
slug: { type: 'string', description: 'Media slug' },
type: { type: 'string', description: 'Content type' },
link: { type: 'string', description: 'Media page URL' },
title: { type: 'object', description: 'Media title object' },
caption: { type: 'object', description: 'Media caption object' },
alt_text: { type: 'string', description: 'Alt text' },
media_type: { type: 'string', description: 'Media type (image, video, etc.)' },
mime_type: { type: 'string', description: 'MIME type' },
source_url: { type: 'string', description: 'Direct URL to the media file' },
media_details: { type: 'object', description: 'Media details (dimensions, etc.)' },
},
},
},
}