Skip to main content
Glama
wordpress.ts6.05 kB
/** * WordPress-Specific Validation Utilities * * Validation functions specific to WordPress data structures including post parameters, * pagination, search queries, and status validation. */ import { WordPressAPIError } from "@/types/client.js"; import { validateId } from "./core.js"; import { validateString, validateArray } from "./core.js"; import { sanitizeHtml } from "./security.js"; /** * Validates WordPress post status values */ export function validatePostStatus(status: string): string { const validStatuses = ["publish", "draft", "pending", "private", "future", "auto-draft", "trash"]; if (!validStatuses.includes(status)) { throw new WordPressAPIError(`Invalid status: must be one of ${validStatuses.join(", ")}`, 400, "INVALID_PARAMETER"); } return status; } /** * Validates and sanitizes search queries */ export function validateSearchQuery(query: string): string { // Remove potentially dangerous characters while preserving search functionality let sanitized = query.trim(); // Limit length to prevent DoS if (sanitized.length > 200) { sanitized = sanitized.substring(0, 200); } // Remove SQL-like patterns (basic protection) sanitized = sanitized.replace(/(\b(union|select|insert|update|delete|drop|create)\b)/gi, ""); // Remove special characters that might be used for injection sanitized = sanitized.replace(/[<>'"`;\\]/g, ""); return sanitized; } /** * Validates pagination parameters as a set */ export function validatePaginationParams(params: { page?: unknown; per_page?: unknown; offset?: unknown }): { page?: number; per_page?: number; offset?: number; } { // Handle null/undefined params object if (!params || typeof params !== "object") { return {}; } const validated: { page?: number; per_page?: number; offset?: number } = {}; // Validate page if (params.page !== undefined) { const page = parseInt(String(params.page), 10); if (isNaN(page) || page < 1) { throw new WordPressAPIError("Page must be a positive integer", 400, "INVALID_PARAMETER"); } if (page > 10000) { throw new WordPressAPIError("Page number too high (max 10000)", 400, "INVALID_PARAMETER"); } validated.page = page; } // Validate per_page if (params.per_page !== undefined) { const perPage = parseInt(String(params.per_page), 10); if (isNaN(perPage) || perPage < 1) { throw new WordPressAPIError("Per page must be a positive integer", 400, "INVALID_PARAMETER"); } if (perPage > 100) { throw new WordPressAPIError(`Per page exceeds maximum allowed (100), got ${perPage}`, 400, "INVALID_PARAMETER"); } validated.per_page = perPage; } // Validate offset if (params.offset !== undefined) { const offset = parseInt(String(params.offset), 10); if (isNaN(offset) || offset < 0) { throw new WordPressAPIError("Offset must be a non-negative integer", 400, "INVALID_PARAMETER"); } if (offset > 1000000) { throw new WordPressAPIError("Offset too large (max 1000000)", 400, "INVALID_PARAMETER"); } validated.offset = offset; } // Check for conflicting parameters if (validated.page && validated.offset) { throw new WordPressAPIError( "Cannot use both 'page' and 'offset' parameters together", 400, "CONFLICTING_PARAMETERS", ); } return validated; } /** * Validates complex post creation parameters */ export function validatePostParams(params: unknown): Record<string, unknown> { const validated: Record<string, unknown> = {}; // Type guard to ensure params is an object if (typeof params !== "object" || params === null || Array.isArray(params)) { throw new WordPressAPIError("Post parameters must be an object", 400, "INVALID_PARAMETER"); } const typedParams = params as Record<string, unknown>; // Title validation if (!typedParams.title || typeof typedParams.title !== "string") { throw new WordPressAPIError("Post title is required and must be a string", 400, "INVALID_PARAMETER"); } validated.title = validateString(typedParams.title, "title", 1, 200); // Content validation if (typedParams.content !== undefined) { validated.content = sanitizeHtml(String(typedParams.content)); } // Status validation with context if (typedParams.status) { if (typeof typedParams.status !== "string") { throw new WordPressAPIError("Status must be a string", 400, "INVALID_PARAMETER"); } validated.status = validatePostStatus(typedParams.status); // Future posts need a date if (validated.status === "future" && !typedParams.date) { throw new WordPressAPIError("Future posts require a 'date' parameter", 400, "MISSING_PARAMETER"); } } // Categories and tags validation if (typedParams.categories) { const categories = validateArray<unknown>(typedParams.categories, "categories", 0, 50); validated.categories = categories.map((id: unknown) => validateId(id, "category ID")); } if (typedParams.tags) { const tags = validateArray<unknown>(typedParams.tags, "tags", 0, 100); validated.tags = tags.map((id: unknown) => validateId(id, "tag ID")); } // Featured media validation if (typedParams.featured_media !== undefined) { if (typedParams.featured_media === null || typedParams.featured_media === 0) { // Allow null or 0 to remove featured media validated.featured_media = 0; } else { validated.featured_media = validateId(typedParams.featured_media, "featured_media"); } } // Date validation for scheduled posts if (typedParams.date) { try { const date = new Date(String(typedParams.date)); if (isNaN(date.getTime())) { throw new Error("Invalid date"); } // WordPress expects ISO 8601 format validated.date = date.toISOString(); } catch { throw new WordPressAPIError( "Invalid date format. Use ISO 8601 format (YYYY-MM-DDTHH:mm:ss)", 400, "INVALID_PARAMETER", ); } } return validated; }

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/docdyhr/mcp-wordpress'

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