Skip to main content
Glama
wordpress-api.ts18.5 kB
import axios, { AxiosInstance, AxiosResponse } from 'axios'; import FormData from 'form-data'; export interface WordPressConfig { url: string; username: string; password?: string; applicationPassword?: string; } export interface WordPressPost { id?: number; title: string; content: string; excerpt?: string; status?: 'publish' | 'draft' | 'private' | 'pending'; slug?: string; categories?: number[]; tags?: number[]; featured_media?: number; author?: number; date?: string; date_gmt?: string; modified?: string; modified_gmt?: string; format?: string; meta?: Record<string, any>; sticky?: boolean; template?: string; password?: string; comment_status?: 'open' | 'closed'; ping_status?: 'open' | 'closed'; } export interface WordPressPage { id?: number; title: string; content: string; excerpt?: string; status?: 'publish' | 'draft' | 'private' | 'pending'; slug?: string; parent?: number; menu_order?: number; featured_media?: number; author?: number; date?: string; date_gmt?: string; modified?: string; modified_gmt?: string; template?: string; meta?: Record<string, any>; password?: string; comment_status?: 'open' | 'closed'; ping_status?: 'open' | 'closed'; } export interface WordPressMedia { id?: number; title: string; alt_text?: string; caption?: string; description?: string; media_type?: 'image' | 'video' | 'audio' | 'application'; mime_type?: string; source_url?: string; media_details?: { width?: number; height?: number; file?: string; sizes?: Record<string, any>; }; date?: string; date_gmt?: string; modified?: string; modified_gmt?: string; slug?: string; status?: 'inherit' | 'private' | 'trash'; author?: number; parent?: number; link?: string; } export interface WordPressUser { id?: number; username: string; name?: string; first_name?: string; last_name?: string; email: string; url?: string; description?: string; link?: string; locale?: string; nickname?: string; slug?: string; registered_date?: string; roles?: string[]; password?: string; capabilities?: Record<string, boolean>; extra_capabilities?: Record<string, boolean>; avatar_urls?: Record<string, string>; meta?: Record<string, any>; } export interface WordPressCategory { id?: number; count?: number; description?: string; link?: string; name: string; slug?: string; taxonomy?: string; parent?: number; meta?: Record<string, any>; } export interface WordPressTag { id?: number; count?: number; description?: string; link?: string; name: string; slug?: string; taxonomy?: string; meta?: Record<string, any>; } export class WordPressAPI { private client: AxiosInstance; private config: WordPressConfig; constructor(config: WordPressConfig) { this.config = config; // Try alternative REST API route for sites with permalink issues const baseURL = `${config.url}/index.php?rest_route=/wp/v2`; this.client = axios.create({ baseURL: baseURL, timeout: 30000, headers: { 'Content-Type': 'application/json', 'User-Agent': 'Telegram-MCP-Server/2.2.0' } }); // Set up authentication if (config.applicationPassword) { const credentials = Buffer.from(`${config.username}:${config.applicationPassword}`).toString('base64'); this.client.defaults.headers.common['Authorization'] = `Basic ${credentials}`; } else if (config.password) { const credentials = Buffer.from(`${config.username}:${config.password}`).toString('base64'); this.client.defaults.headers.common['Authorization'] = `Basic ${credentials}`; } } // Posts async getPosts(params: { page?: number; per_page?: number; search?: string; after?: string; before?: string; author?: number; author_exclude?: number[]; before_gmt?: string; after_gmt?: string; exclude?: number[]; include?: number[]; offset?: number; order?: 'asc' | 'desc'; orderby?: 'date' | 'id' | 'include' | 'relevance' | 'slug' | 'title'; slug?: string; status?: string; categories?: number[]; categories_exclude?: number[]; tags?: number[]; tags_exclude?: number[]; sticky?: boolean; } = {}): Promise<WordPressPost[]> { const response = await this.client.get('/posts', { params }); return response.data; } async getPost(id: number): Promise<WordPressPost> { const response = await this.client.get(`/posts/${id}`); return response.data; } async createPost(post: WordPressPost): Promise<WordPressPost> { const response = await this.client.post('/posts', post); return response.data; } async updatePost(id: number, post: Partial<WordPressPost>): Promise<WordPressPost> { const response = await this.client.post(`/posts/${id}`, post); return response.data; } async deletePost(id: number, force: boolean = false): Promise<WordPressPost> { const response = await this.client.delete(`/posts/${id}`, { params: { force } }); return response.data; } // Pages async getPages(params: { page?: number; per_page?: number; search?: string; after?: string; before?: string; author?: number; author_exclude?: number[]; before_gmt?: string; after_gmt?: string; exclude?: number[]; include?: number[]; offset?: number; order?: 'asc' | 'desc'; orderby?: 'date' | 'id' | 'include' | 'relevance' | 'slug' | 'title'; slug?: string; status?: string; parent?: number; parent_exclude?: number[]; menu_order?: number; } = {}): Promise<WordPressPage[]> { const response = await this.client.get('/pages', { params }); return response.data; } async getPage(id: number): Promise<WordPressPage> { const response = await this.client.get(`/pages/${id}`); return response.data; } async createPage(page: WordPressPage): Promise<WordPressPage> { const response = await this.client.post('/pages', page); return response.data; } async updatePage(id: number, page: Partial<WordPressPage>): Promise<WordPressPage> { const response = await this.client.post(`/pages/${id}`, page); return response.data; } async deletePage(id: number, force: boolean = false): Promise<WordPressPage> { const response = await this.client.delete(`/pages/${id}`, { params: { force } }); return response.data; } // Media async getMedia(params: { page?: number; per_page?: number; search?: string; after?: string; before?: string; author?: number; author_exclude?: number[]; before_gmt?: string; after_gmt?: string; exclude?: number[]; include?: number[]; offset?: number; order?: 'asc' | 'desc'; orderby?: 'date' | 'id' | 'include' | 'relevance' | 'slug' | 'title'; slug?: string; status?: string; media_type?: 'image' | 'video' | 'audio' | 'application'; mime_type?: string; parent?: number; parent_exclude?: number[]; } = {}): Promise<WordPressMedia[]> { const response = await this.client.get('/media', { params }); return response.data; } async getMediaItem(id: number): Promise<WordPressMedia> { const response = await this.client.get(`/media/${id}`); return response.data; } async uploadMedia(file: Buffer | string, filename: string, title?: string, alt_text?: string, caption?: string, description?: string): Promise<WordPressMedia> { const formData = new FormData(); if (typeof file === 'string') { // If file is a URL, download it first const fileResponse = await axios.get(file, { responseType: 'arraybuffer' }); formData.append('file', Buffer.from(fileResponse.data), filename); } else { formData.append('file', file, filename); } if (title) formData.append('title', title); if (alt_text) formData.append('alt_text', alt_text); if (caption) formData.append('caption', caption); if (description) formData.append('description', description); const response = await this.client.post('/media', formData, { headers: { ...formData.getHeaders(), 'Content-Type': 'multipart/form-data' } }); return response.data; } /** * Upload media file directly as binary data (more efficient for large files) */ async uploadMediaBinary(fileBuffer: Buffer, filename: string, mimeType: string, title?: string, alt_text?: string, caption?: string, description?: string): Promise<WordPressMedia> { // WordPress authorization const auth = "Basic " + Buffer.from( `${this.config.username}:${this.config.applicationPassword}` ).toString("base64"); // Upload to WordPress using fetch with direct binary const response = await fetch(`${this.config.url}/wp-json/wp/v2/media`, { method: "POST", headers: { "Authorization": auth, "Content-Disposition": `attachment; filename="${filename}"`, "Content-Type": mimeType }, body: new Uint8Array(fileBuffer) }); const data = await response.json(); if (!response.ok) { throw new Error("Upload failed: " + JSON.stringify(data)); } // Update metadata if provided if (title || alt_text || caption || description) { const updateData: any = {}; if (title) updateData.title = title; if (alt_text) updateData.alt_text = alt_text; if (caption) updateData.caption = caption; if (description) updateData.description = description; const updateResponse = await fetch(`${this.config.url}/wp-json/wp/v2/media/${data.id}`, { method: "POST", headers: { "Authorization": auth, "Content-Type": "application/json" }, body: JSON.stringify(updateData) }); if (updateResponse.ok) { return await updateResponse.json(); } } return data; } /** * Upload media file directly as binary data without JSON (for large files) */ async uploadMediaDirect(fileBuffer: Buffer, filename: string, mimeType: string, title?: string, alt_text?: string, caption?: string, description?: string): Promise<WordPressMedia> { const auth = Buffer.from(`${this.config.username}:${this.config.applicationPassword}`).toString('base64'); // Use fetch for direct binary upload without JSON const response = await fetch(`${this.config.url}/wp-json/wp/v2/media`, { method: 'POST', headers: { 'Content-Disposition': `attachment; filename="${filename}"`, 'Content-Type': mimeType, 'Authorization': `Basic ${auth}` }, body: new Uint8Array(fileBuffer) }); if (!response.ok) { const errorText = await response.text(); throw new Error(`WordPress API error: ${response.status} ${response.statusText} - ${errorText}`); } const media = await response.json(); // Update metadata if provided if (title || alt_text || caption || description) { const updateData: any = {}; if (title) updateData.title = title; if (alt_text) updateData.alt_text = alt_text; if (caption) updateData.caption = caption; if (description) updateData.description = description; const updateResponse = await this.client.post(`/media/${media.id}`, updateData); return updateResponse.data; } return media; } /** * Update media metadata (alt_text, caption, description) */ async updateMediaMetadata(id: number, metadata: { title?: string; alt_text?: string; caption?: string; description?: string; }): Promise<WordPressMedia> { const response = await this.client.post(`/media/${id}`, metadata); return response.data; } async updateMedia(id: number, media: Partial<WordPressMedia>): Promise<WordPressMedia> { const response = await this.client.post(`/media/${id}`, media); return response.data; } async deleteMedia(id: number, force: boolean = false): Promise<WordPressMedia> { const response = await this.client.delete(`/media/${id}`, { params: { force } }); return response.data; } // Users async getUsers(params: { page?: number; per_page?: number; search?: string; exclude?: number[]; include?: number[]; offset?: number; order?: 'asc' | 'desc'; orderby?: 'id' | 'include' | 'name' | 'registered_date' | 'slug' | 'email' | 'url'; slug?: string; roles?: string[]; who?: 'authors'; } = {}): Promise<WordPressUser[]> { const response = await this.client.get('/users', { params }); return response.data; } async getUser(id: number): Promise<WordPressUser> { const response = await this.client.get(`/users/${id}`); return response.data; } async createUser(user: WordPressUser): Promise<WordPressUser> { const response = await this.client.post('/users', user); return response.data; } async updateUser(id: number, user: Partial<WordPressUser>): Promise<WordPressUser> { const response = await this.client.post(`/users/${id}`, user); return response.data; } async deleteUser(id: number, force: boolean = false, reassign?: number): Promise<WordPressUser> { const response = await this.client.delete(`/users/${id}`, { params: { force, reassign } }); return response.data; } // Categories async getCategories(params: { page?: number; per_page?: number; search?: string; exclude?: number[]; include?: number[]; offset?: number; order?: 'asc' | 'desc'; orderby?: 'id' | 'include' | 'name' | 'slug' | 'term_group' | 'description' | 'count'; hide_empty?: boolean; parent?: number; post?: number; slug?: string; } = {}): Promise<WordPressCategory[]> { const response = await this.client.get('/categories', { params }); return response.data; } async getCategory(id: number): Promise<WordPressCategory> { const response = await this.client.get(`/categories/${id}`); return response.data; } async createCategory(category: WordPressCategory): Promise<WordPressCategory> { const response = await this.client.post('/categories', category); return response.data; } async updateCategory(id: number, category: Partial<WordPressCategory>): Promise<WordPressCategory> { const response = await this.client.post(`/categories/${id}`, category); return response.data; } async deleteCategory(id: number, force: boolean = false): Promise<WordPressCategory> { const response = await this.client.delete(`/categories/${id}`, { params: { force } }); return response.data; } // Tags async getTags(params: { page?: number; per_page?: number; search?: string; exclude?: number[]; include?: number[]; offset?: number; order?: 'asc' | 'desc'; orderby?: 'id' | 'include' | 'name' | 'slug' | 'term_group' | 'description' | 'count'; hide_empty?: boolean; post?: number; slug?: string; } = {}): Promise<WordPressTag[]> { const response = await this.client.get('/tags', { params }); return response.data; } async getTag(id: number): Promise<WordPressTag> { const response = await this.client.get(`/tags/${id}`); return response.data; } async createTag(tag: WordPressTag): Promise<WordPressTag> { const response = await this.client.post('/tags', tag); return response.data; } async updateTag(id: number, tag: Partial<WordPressTag>): Promise<WordPressTag> { const response = await this.client.post(`/tags/${id}`, tag); return response.data; } async deleteTag(id: number, force: boolean = false): Promise<WordPressTag> { const response = await this.client.delete(`/tags/${id}`, { params: { force } }); return response.data; } // Comments async getComments(params: { page?: number; per_page?: number; search?: string; after?: string; before?: string; exclude?: number[]; include?: number[]; offset?: number; order?: 'asc' | 'desc'; orderby?: 'date' | 'date_gmt' | 'id' | 'include' | 'post' | 'parent' | 'type'; parent?: number; parent_exclude?: number[]; post?: number; status?: 'hold' | 'approve' | 'spam' | 'trash'; type?: string; password?: string; } = {}): Promise<any[]> { const response = await this.client.get('/comments', { params }); return response.data; } async getComment(id: number): Promise<any> { const response = await this.client.get(`/comments/${id}`); return response.data; } async createComment(comment: { author?: number; author_email?: string; author_name?: string; author_url?: string; content: string; date?: string; date_gmt?: string; parent?: number; post: number; status?: 'hold' | 'approve' | 'spam' | 'trash'; meta?: Record<string, any>; }): Promise<any> { const response = await this.client.post('/comments', comment); return response.data; } async updateComment(id: number, comment: any): Promise<any> { const response = await this.client.post(`/comments/${id}`, comment); return response.data; } async deleteComment(id: number, force: boolean = false): Promise<any> { const response = await this.client.delete(`/comments/${id}`, { params: { force } }); return response.data; } // Site info async getSiteInfo(): Promise<any> { // Use direct API call for site info since it's at root level const response = await axios.get(`${this.config.url}/index.php?rest_route=/`); return response.data; } async getSettings(): Promise<any> { const response = await this.client.get('/settings'); return response.data; } async updateSettings(settings: any): Promise<any> { const response = await this.client.post('/settings', settings); return response.data; } // Search async search(query: string, type?: 'post' | 'page' | 'attachment' | 'any'): Promise<any[]> { const params: any = { search: query }; if (type) params.type = type; const response = await this.client.get('/search', { params }); return response.data; } // Test connection async testConnection(): Promise<boolean> { try { await this.client.get('/'); return true; } catch (error) { return false; } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bobidk91-ops/telegram-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server