mcp-wordpress 1.5.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/README.md +332 -61
  2. package/dist/cache/CacheInvalidation.d.ts.map +1 -1
  3. package/dist/cache/CacheInvalidation.js +4 -4
  4. package/dist/cache/CacheInvalidation.js.map +1 -1
  5. package/dist/client/MockWordPressClient.d.ts +55 -0
  6. package/dist/client/MockWordPressClient.d.ts.map +1 -0
  7. package/dist/client/MockWordPressClient.js +369 -0
  8. package/dist/client/MockWordPressClient.js.map +1 -0
  9. package/dist/client/api.d.ts +1 -0
  10. package/dist/client/api.d.ts.map +1 -1
  11. package/dist/client/api.js +26 -60
  12. package/dist/client/api.js.map +1 -1
  13. package/dist/client/managers/AuthenticationManager.d.ts.map +1 -1
  14. package/dist/client/managers/AuthenticationManager.js +4 -3
  15. package/dist/client/managers/AuthenticationManager.js.map +1 -1
  16. package/dist/config/ConfigurationSchema.d.ts +3 -3
  17. package/dist/config/ConfigurationSchema.d.ts.map +1 -1
  18. package/dist/config/ConfigurationSchema.js +7 -24
  19. package/dist/config/ConfigurationSchema.js.map +1 -1
  20. package/dist/config/ServerConfiguration.d.ts +8 -0
  21. package/dist/config/ServerConfiguration.d.ts.map +1 -1
  22. package/dist/config/ServerConfiguration.js +80 -31
  23. package/dist/config/ServerConfiguration.js.map +1 -1
  24. package/dist/docs/DocumentationGenerator.d.ts.map +1 -1
  25. package/dist/docs/DocumentationGenerator.js +5 -7
  26. package/dist/docs/DocumentationGenerator.js.map +1 -1
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +33 -29
  29. package/dist/index.js.map +1 -1
  30. package/dist/security/InputValidator.d.ts.map +1 -1
  31. package/dist/security/InputValidator.js +3 -11
  32. package/dist/security/InputValidator.js.map +1 -1
  33. package/dist/server/ToolRegistry.d.ts +4 -0
  34. package/dist/server/ToolRegistry.d.ts.map +1 -1
  35. package/dist/server/ToolRegistry.js +71 -8
  36. package/dist/server/ToolRegistry.js.map +1 -1
  37. package/dist/tools/auth.d.ts.map +1 -1
  38. package/dist/tools/auth.js +8 -3
  39. package/dist/tools/auth.js.map +1 -1
  40. package/dist/tools/posts.d.ts.map +1 -1
  41. package/dist/tools/posts.js +287 -20
  42. package/dist/tools/posts.js.map +1 -1
  43. package/dist/tools/site.d.ts.map +1 -1
  44. package/dist/tools/site.js +47 -9
  45. package/dist/tools/site.js.map +1 -1
  46. package/dist/tools/users.d.ts.map +1 -1
  47. package/dist/tools/users.js +113 -10
  48. package/dist/tools/users.js.map +1 -1
  49. package/dist/utils/enhancedError.d.ts +61 -0
  50. package/dist/utils/enhancedError.d.ts.map +1 -0
  51. package/dist/utils/enhancedError.js +221 -0
  52. package/dist/utils/enhancedError.js.map +1 -0
  53. package/dist/utils/streaming.d.ts +104 -0
  54. package/dist/utils/streaming.d.ts.map +1 -0
  55. package/dist/utils/streaming.js +312 -0
  56. package/dist/utils/streaming.js.map +1 -0
  57. package/dist/utils/validation.d.ts +19 -3
  58. package/dist/utils/validation.d.ts.map +1 -1
  59. package/dist/utils/validation.js +174 -24
  60. package/dist/utils/validation.js.map +1 -1
  61. package/docs/ARCHITECTURE.md +850 -0
  62. package/docs/CACHING.md +20 -17
  63. package/docs/CONFIGURATION.md +660 -0
  64. package/docs/DOCKER.md +61 -60
  65. package/docs/EVALUATION.md +397 -0
  66. package/docs/INSTALLATION.md +423 -0
  67. package/docs/PERFORMANCE_MONITORING.md +17 -15
  68. package/docs/SECURITY.md +621 -0
  69. package/docs/SECURITY_TESTING.md +22 -26
  70. package/docs/TEST_SITE_SETUP.md +136 -0
  71. package/docs/TROUBLESHOOTING.md +578 -0
  72. package/docs/api/README.md +76 -91
  73. package/docs/api/categories/auth.md +0 -2
  74. package/docs/api/categories/cache.md +0 -2
  75. package/docs/api/categories/comment.md +0 -2
  76. package/docs/api/categories/media.md +0 -2
  77. package/docs/api/categories/page.md +0 -2
  78. package/docs/api/categories/performance.md +0 -2
  79. package/docs/api/categories/post.md +0 -2
  80. package/docs/api/categories/site.md +0 -2
  81. package/docs/api/categories/taxonomy.md +0 -2
  82. package/docs/api/categories/user.md +0 -2
  83. package/docs/api/summary.json +1 -1
  84. package/docs/api/tools/wp_approve_comment.md +11 -3
  85. package/docs/api/tools/wp_cache_clear.md +14 -5
  86. package/docs/api/tools/wp_cache_info.md +14 -5
  87. package/docs/api/tools/wp_cache_stats.md +14 -5
  88. package/docs/api/tools/wp_cache_warm.md +14 -5
  89. package/docs/api/tools/wp_create_application_password.md +11 -3
  90. package/docs/api/tools/wp_create_category.md +11 -3
  91. package/docs/api/tools/wp_create_comment.md +14 -5
  92. package/docs/api/tools/wp_create_page.md +13 -5
  93. package/docs/api/tools/wp_create_post.md +14 -7
  94. package/docs/api/tools/wp_create_tag.md +11 -3
  95. package/docs/api/tools/wp_create_user.md +13 -5
  96. package/docs/api/tools/wp_delete_application_password.md +11 -3
  97. package/docs/api/tools/wp_delete_category.md +11 -3
  98. package/docs/api/tools/wp_delete_comment.md +11 -3
  99. package/docs/api/tools/wp_delete_media.md +10 -3
  100. package/docs/api/tools/wp_delete_page.md +10 -3
  101. package/docs/api/tools/wp_delete_post.md +11 -5
  102. package/docs/api/tools/wp_delete_tag.md +11 -3
  103. package/docs/api/tools/wp_delete_user.md +10 -3
  104. package/docs/api/tools/wp_get_application_passwords.md +11 -3
  105. package/docs/api/tools/wp_get_auth_status.md +11 -3
  106. package/docs/api/tools/wp_get_category.md +11 -3
  107. package/docs/api/tools/wp_get_comment.md +11 -3
  108. package/docs/api/tools/wp_get_current_user.md +11 -3
  109. package/docs/api/tools/wp_get_media.md +11 -3
  110. package/docs/api/tools/wp_get_page.md +11 -3
  111. package/docs/api/tools/wp_get_page_revisions.md +11 -3
  112. package/docs/api/tools/wp_get_post.md +12 -5
  113. package/docs/api/tools/wp_get_post_revisions.md +11 -3
  114. package/docs/api/tools/wp_get_site_settings.md +10 -3
  115. package/docs/api/tools/wp_get_tag.md +11 -3
  116. package/docs/api/tools/wp_get_user.md +11 -3
  117. package/docs/api/tools/wp_list_categories.md +11 -3
  118. package/docs/api/tools/wp_list_comments.md +11 -3
  119. package/docs/api/tools/wp_list_media.md +14 -5
  120. package/docs/api/tools/wp_list_pages.md +14 -5
  121. package/docs/api/tools/wp_list_posts.md +15 -7
  122. package/docs/api/tools/wp_list_tags.md +11 -3
  123. package/docs/api/tools/wp_list_users.md +11 -3
  124. package/docs/api/tools/wp_performance_alerts.md +17 -7
  125. package/docs/api/tools/wp_performance_benchmark.md +17 -7
  126. package/docs/api/tools/wp_performance_export.md +17 -7
  127. package/docs/api/tools/wp_performance_history.md +17 -7
  128. package/docs/api/tools/wp_performance_optimize.md +17 -7
  129. package/docs/api/tools/wp_performance_stats.md +17 -7
  130. package/docs/api/tools/wp_search_site.md +11 -3
  131. package/docs/api/tools/wp_spam_comment.md +11 -3
  132. package/docs/api/tools/wp_switch_auth_method.md +14 -5
  133. package/docs/api/tools/wp_test_auth.md +11 -3
  134. package/docs/api/tools/wp_update_category.md +11 -3
  135. package/docs/api/tools/wp_update_comment.md +14 -5
  136. package/docs/api/tools/wp_update_media.md +14 -5
  137. package/docs/api/tools/wp_update_page.md +13 -5
  138. package/docs/api/tools/wp_update_post.md +14 -7
  139. package/docs/api/tools/wp_update_site_settings.md +14 -5
  140. package/docs/api/tools/wp_update_tag.md +11 -3
  141. package/docs/api/tools/wp_update_user.md +13 -5
  142. package/docs/api/tools/wp_upload_media.md +13 -5
  143. package/docs/api/types/WordPressPost.md +2 -0
  144. package/docs/code-improvements.md +40 -0
  145. package/docs/contract-testing.md +1 -1
  146. package/docs/developer/API_REFERENCE.md +19 -59
  147. package/docs/developer/ARCHITECTURE.md +8 -11
  148. package/docs/developer/BUILD_SYSTEM.md +2 -2
  149. package/docs/developer/CONTRIBUTING.md +3 -5
  150. package/docs/developer/GITHUB_ACTIONS_SETUP.md +2 -2
  151. package/docs/developer/MIGRATION_GUIDE.md +5 -6
  152. package/docs/developer/README.md +2 -1
  153. package/docs/developer/REFACTORING.md +9 -15
  154. package/docs/developer/RELEASE_PROCESS.md +4 -3
  155. package/docs/developer/TESTING.md +2 -2
  156. package/docs/examples/claude-desktop-config.md +8 -0
  157. package/docs/integrations/claude-desktop.md +426 -0
  158. package/docs/integrations/cline.md +537 -0
  159. package/docs/integrations/vs-code.md +515 -0
  160. package/docs/releases/COMMUNITY_ANNOUNCEMENT_v1.1.2.md +30 -23
  161. package/docs/releases/RELEASE_NOTES_v1.1.2.md +7 -6
  162. package/docs/testing-configurations.md +11 -0
  163. package/docs/user-guides/DOCKER_NPM_DTX_SETUP.md +3 -2
  164. package/docs/user-guides/DOCKER_SETUP.md +3 -2
  165. package/docs/user-guides/DTX_SETUP.md +6 -5
  166. package/docs/user-guides/DXT_INSTALLATION.md +4 -4
  167. package/docs/user-guides/NPM_SETUP.md +4 -2
  168. package/docs/user-guides/NPX_SETUP.md +4 -2
  169. package/docs/user-guides/SMITHERY_SETUP.md +402 -0
  170. package/docs/wordpress-rest-api-authentication-troubleshooting.md +45 -42
  171. package/package.json +12 -2
  172. package/src/cache/CacheInvalidation.ts +7 -18
  173. package/src/client/MockWordPressClient.ts +398 -0
  174. package/src/client/api.ts +77 -237
  175. package/src/client/managers/AuthenticationManager.ts +19 -56
  176. package/src/config/ConfigurationSchema.ts +14 -45
  177. package/src/config/ServerConfiguration.ts +98 -71
  178. package/src/docs/DocumentationGenerator.ts +39 -123
  179. package/src/dxt-entry.cjs +4 -1
  180. package/src/index.ts +35 -54
  181. package/src/security/InputValidator.ts +15 -57
  182. package/src/server/ToolRegistry.ts +88 -17
  183. package/src/tools/auth.ts +15 -22
  184. package/src/tools/posts.ts +347 -64
  185. package/src/tools/site.ts +69 -46
  186. package/src/tools/users.ts +142 -44
  187. package/src/utils/enhancedError.ts +248 -0
  188. package/src/utils/streaming.ts +428 -0
  189. package/src/utils/validation.ts +253 -92
  190. package/dist/mcp-wordpress-1.5.2.tgz +0 -0
@@ -295,28 +295,20 @@ export class CacheInvalidation {
295
295
  /**
296
296
  * Apply invalidation rule to cache
297
297
  */
298
- private async applyInvalidationRule(
299
- event: InvalidationEvent,
300
- rule: InvalidationRule,
301
- ): Promise<void> {
298
+ private async applyInvalidationRule(event: InvalidationEvent, rule: InvalidationRule): Promise<void> {
302
299
  for (const pattern of rule.patterns) {
303
300
  let invalidationPattern = pattern;
304
301
 
305
302
  // Replace placeholders with actual values
306
303
  if (event.id) {
307
- invalidationPattern = invalidationPattern.replace(
308
- "\\d+",
309
- event.id.toString(),
310
- );
304
+ invalidationPattern = invalidationPattern.replace("\\d+", event.id.toString());
311
305
  }
312
306
 
313
307
  // Invalidate matching cache entries
314
308
  const invalidated = this.httpCache.invalidatePattern(invalidationPattern);
315
309
 
316
310
  if (invalidated > 0) {
317
- console.log(
318
- `Invalidated ${invalidated} cache entries for pattern: ${invalidationPattern}`,
319
- );
311
+ console.error(`INFO: Invalidated ${invalidated} cache entries for pattern: ${invalidationPattern}`);
320
312
  }
321
313
  }
322
314
  }
@@ -331,10 +323,7 @@ export class CacheInvalidation {
331
323
  } {
332
324
  return {
333
325
  queueSize: this.eventQueue.length,
334
- rulesCount: Array.from(this.invalidationRules.values()).reduce(
335
- (acc, rules) => acc + rules.length,
336
- 0,
337
- ),
326
+ rulesCount: Array.from(this.invalidationRules.values()).reduce((acc, rules) => acc + rules.length, 0),
338
327
  processing: this.processing,
339
328
  };
340
329
  }
@@ -410,20 +399,20 @@ export class CacheWarmer {
410
399
  async warmEssentials(): Promise<void> {
411
400
  // Implementation would depend on your specific WordPress client
412
401
  // This is a placeholder for the structure
413
- console.log("Warming essential caches...");
402
+ console.error("INFO: Warming essential caches...");
414
403
  }
415
404
 
416
405
  /**
417
406
  * Warm cache with taxonomy data
418
407
  */
419
408
  async warmTaxonomies(): Promise<void> {
420
- console.log("Warming taxonomy caches...");
409
+ console.error("INFO: Warming taxonomy caches...");
421
410
  }
422
411
 
423
412
  /**
424
413
  * Warm cache with user data
425
414
  */
426
415
  async warmUsers(): Promise<void> {
427
- console.log("Warming user caches...");
416
+ console.error("INFO: Warming user caches...");
428
417
  }
429
418
  }
@@ -0,0 +1,398 @@
1
+ import { WordPressClient } from "./api.js";
2
+ import { WordPressClientConfig } from "../types/client.js";
3
+ import type {
4
+ WordPressPost,
5
+ WordPressUser,
6
+ WordPressSiteSettings,
7
+ PostQueryParams,
8
+ CreatePostRequest,
9
+ UpdatePostRequest,
10
+ } from "../types/wordpress.js";
11
+
12
+ /**
13
+ * Mock WordPress client for CI environments
14
+ * Provides realistic responses without connecting to actual WordPress
15
+ */
16
+ export class MockWordPressClient extends WordPressClient {
17
+ private isMockMode = true;
18
+
19
+ constructor(config: WordPressClientConfig) {
20
+ super(config);
21
+ }
22
+
23
+ /**
24
+ * Override authenticate to not make actual requests
25
+ */
26
+ async authenticate(): Promise<boolean> {
27
+ console.log("INFO: Mock authentication - skipping actual connection");
28
+ return true;
29
+ }
30
+
31
+ /**
32
+ * Mock getPosts with realistic data
33
+ */
34
+ async getPosts(params?: PostQueryParams): Promise<WordPressPost[]> {
35
+ const mockPosts: WordPressPost[] = [
36
+ {
37
+ id: 1,
38
+ date: "2024-01-15T10:00:00",
39
+ date_gmt: "2024-01-15T10:00:00",
40
+ guid: { rendered: "https://demo.wordpress.com/?p=1" },
41
+ modified: "2024-01-15T10:00:00",
42
+ modified_gmt: "2024-01-15T10:00:00",
43
+ slug: "hello-world",
44
+ status: "publish",
45
+ type: "post",
46
+ link: "https://demo.wordpress.com/hello-world/",
47
+ title: { rendered: "Hello World - Demo Post" },
48
+ content: { rendered: "<p>This is a demo post for CI testing.</p>" },
49
+ excerpt: { rendered: "<p>This is a demo post for CI testing.</p>" },
50
+ author: 1,
51
+ featured_media: 0,
52
+ comment_status: "open",
53
+ ping_status: "open",
54
+ sticky: false,
55
+ template: "",
56
+ format: "standard",
57
+ meta: [],
58
+ categories: [1],
59
+ tags: [],
60
+ },
61
+ {
62
+ id: 2,
63
+ date: "2024-01-16T12:00:00",
64
+ date_gmt: "2024-01-16T12:00:00",
65
+ guid: { rendered: "https://demo.wordpress.com/?p=2" },
66
+ modified: "2024-01-16T12:00:00",
67
+ modified_gmt: "2024-01-16T12:00:00",
68
+ slug: "sample-post",
69
+ status: "publish",
70
+ type: "post",
71
+ link: "https://demo.wordpress.com/sample-post/",
72
+ title: { rendered: "Sample Post for Testing" },
73
+ content: { rendered: "<p>This is another demo post with sample content.</p>" },
74
+ excerpt: { rendered: "<p>This is another demo post with sample content.</p>" },
75
+ author: 1,
76
+ featured_media: 0,
77
+ comment_status: "open",
78
+ ping_status: "open",
79
+ sticky: false,
80
+ template: "",
81
+ format: "standard",
82
+ meta: [],
83
+ categories: [1],
84
+ tags: [1],
85
+ },
86
+ {
87
+ id: 3,
88
+ date: "2024-01-17T14:30:00",
89
+ date_gmt: "2024-01-17T14:30:00",
90
+ guid: { rendered: "https://demo.wordpress.com/?p=3" },
91
+ modified: "2024-01-17T14:30:00",
92
+ modified_gmt: "2024-01-17T14:30:00",
93
+ slug: "latest-news",
94
+ status: "publish",
95
+ type: "post",
96
+ link: "https://demo.wordpress.com/latest-news/",
97
+ title: { rendered: "Latest News Update" },
98
+ content: { rendered: "<p>This is the latest news update for demonstration.</p>" },
99
+ excerpt: { rendered: "<p>This is the latest news update for demonstration.</p>" },
100
+ author: 1,
101
+ featured_media: 0,
102
+ comment_status: "open",
103
+ ping_status: "open",
104
+ sticky: false,
105
+ template: "",
106
+ format: "standard",
107
+ meta: [],
108
+ categories: [1, 2],
109
+ tags: [1, 2],
110
+ },
111
+ ];
112
+
113
+ // Apply basic filtering based on params
114
+ let filteredPosts = mockPosts;
115
+ if (params?.per_page) {
116
+ filteredPosts = filteredPosts.slice(0, parseInt(params.per_page.toString()));
117
+ }
118
+
119
+ return filteredPosts;
120
+ }
121
+
122
+ /**
123
+ * Mock getPost with realistic data
124
+ */
125
+ async getPost(id: number): Promise<WordPressPost> {
126
+ if (id === 999999) {
127
+ throw new Error("Invalid post ID.");
128
+ }
129
+
130
+ const mockPost: WordPressPost = {
131
+ id: id,
132
+ date: "2024-01-15T10:00:00",
133
+ date_gmt: "2024-01-15T10:00:00",
134
+ guid: { rendered: `https://demo.wordpress.com/?p=${id}` },
135
+ modified: "2024-01-15T10:00:00",
136
+ modified_gmt: "2024-01-15T10:00:00",
137
+ slug: `demo-post-${id}`,
138
+ status: "publish",
139
+ type: "post",
140
+ link: `https://demo.wordpress.com/demo-post-${id}/`,
141
+ title: { rendered: `Demo Post ${id}` },
142
+ content: { rendered: `<p>This is demo content for post ${id}.</p>` },
143
+ excerpt: { rendered: `<p>This is demo content for post ${id}.</p>` },
144
+ author: 1,
145
+ featured_media: 0,
146
+ comment_status: "open",
147
+ ping_status: "open",
148
+ sticky: false,
149
+ template: "",
150
+ format: "standard",
151
+ meta: [],
152
+ categories: [1],
153
+ tags: [],
154
+ };
155
+
156
+ return mockPost;
157
+ }
158
+
159
+ /**
160
+ * Mock getCurrentUser with realistic data
161
+ */
162
+ async getCurrentUser(): Promise<WordPressUser> {
163
+ const mockUser: WordPressUser = {
164
+ id: 1,
165
+ name: "CI Demo User",
166
+ username: "ci-demo-user",
167
+ first_name: "CI",
168
+ last_name: "Demo",
169
+ slug: "ci-demo-user",
170
+ email: "demo@example.com",
171
+ url: "https://demo.wordpress.com",
172
+ description: "Demo user for CI testing",
173
+ link: "https://demo.wordpress.com/author/ci-demo-user/",
174
+ locale: "en_US",
175
+ nickname: "CI Demo",
176
+ registered_date: "2024-01-01T00:00:00+00:00",
177
+ roles: ["administrator"],
178
+ capabilities: {
179
+ read: true,
180
+ level_0: true,
181
+ level_1: true,
182
+ level_2: true,
183
+ level_3: true,
184
+ level_4: true,
185
+ level_5: true,
186
+ level_6: true,
187
+ level_7: true,
188
+ level_8: true,
189
+ level_9: true,
190
+ level_10: true,
191
+ delete_others_pages: true,
192
+ delete_others_posts: true,
193
+ delete_pages: true,
194
+ delete_posts: true,
195
+ delete_private_pages: true,
196
+ delete_private_posts: true,
197
+ delete_published_pages: true,
198
+ delete_published_posts: true,
199
+ edit_dashboard: true,
200
+ edit_others_pages: true,
201
+ edit_others_posts: true,
202
+ edit_pages: true,
203
+ edit_posts: true,
204
+ edit_private_pages: true,
205
+ edit_private_posts: true,
206
+ edit_published_pages: true,
207
+ edit_published_posts: true,
208
+ edit_theme_options: true,
209
+ export: true,
210
+ import: true,
211
+ list_users: true,
212
+ manage_categories: true,
213
+ manage_links: true,
214
+ manage_options: true,
215
+ moderate_comments: true,
216
+ promote_users: true,
217
+ publish_pages: true,
218
+ publish_posts: true,
219
+ read_private_pages: true,
220
+ read_private_posts: true,
221
+ remove_users: true,
222
+ switch_themes: true,
223
+ upload_files: true,
224
+ customize: true,
225
+ delete_site: true,
226
+ },
227
+ extra_capabilities: {
228
+ administrator: true,
229
+ },
230
+ avatar_urls: {
231
+ "24": "https://secure.gravatar.com/avatar/example?s=24&d=mm&r=g",
232
+ "48": "https://secure.gravatar.com/avatar/example?s=48&d=mm&r=g",
233
+ "96": "https://secure.gravatar.com/avatar/example?s=96&d=mm&r=g",
234
+ },
235
+ meta: [],
236
+ };
237
+
238
+ return mockUser;
239
+ }
240
+
241
+ /**
242
+ * Mock getSiteSettings with realistic data
243
+ */
244
+ async getSiteSettings(): Promise<WordPressSiteSettings> {
245
+ const mockSettings: WordPressSiteSettings = {
246
+ title: "Demo WordPress Site",
247
+ description: "A demonstration site for CI testing",
248
+ url: "https://demo.wordpress.com",
249
+ email: "admin@demo.wordpress.com",
250
+ timezone: "UTC",
251
+ date_format: "F j, Y",
252
+ time_format: "g:i a",
253
+ start_of_week: 1,
254
+ language: "en_US",
255
+ use_smilies: true,
256
+ default_category: 1,
257
+ default_post_format: "0",
258
+ posts_per_page: 10,
259
+ default_ping_status: "open",
260
+ default_comment_status: "open",
261
+ };
262
+
263
+ return mockSettings;
264
+ }
265
+
266
+ /**
267
+ * Mock createPost
268
+ */
269
+ async createPost(data: CreatePostRequest): Promise<WordPressPost> {
270
+ const mockPost: WordPressPost = {
271
+ id: Math.floor(Math.random() * 1000) + 100,
272
+ date: new Date().toISOString(),
273
+ date_gmt: new Date().toISOString(),
274
+ guid: { rendered: `https://demo.wordpress.com/?p=${Math.floor(Math.random() * 1000) + 100}` },
275
+ modified: new Date().toISOString(),
276
+ modified_gmt: new Date().toISOString(),
277
+ slug: data.title?.toLowerCase().replace(/\s+/g, "-") || "new-post",
278
+ status: data.status || "publish",
279
+ type: "post",
280
+ link: `https://demo.wordpress.com/${data.title?.toLowerCase().replace(/\s+/g, "-") || "new-post"}/`,
281
+ title: { rendered: data.title || "New Post" },
282
+ content: { rendered: data.content || "<p>New post content</p>" },
283
+ excerpt: { rendered: data.excerpt || "<p>New post excerpt</p>" },
284
+ author: 1,
285
+ featured_media: 0,
286
+ comment_status: "open",
287
+ ping_status: "open",
288
+ sticky: false,
289
+ template: "",
290
+ format: "standard",
291
+ meta: [],
292
+ categories: [1],
293
+ tags: [],
294
+ };
295
+
296
+ return mockPost;
297
+ }
298
+
299
+ /**
300
+ * Mock updatePost
301
+ */
302
+ async updatePost(data: UpdatePostRequest): Promise<WordPressPost> {
303
+ const mockPost: WordPressPost = {
304
+ id: data.id,
305
+ date: "2024-01-15T10:00:00",
306
+ date_gmt: "2024-01-15T10:00:00",
307
+ guid: { rendered: `https://demo.wordpress.com/?p=${data.id}` },
308
+ modified: new Date().toISOString(),
309
+ modified_gmt: new Date().toISOString(),
310
+ slug: data.title?.toLowerCase().replace(/\s+/g, "-") || `post-${data.id}`,
311
+ status: data.status || "publish",
312
+ type: "post",
313
+ link: `https://demo.wordpress.com/${data.title?.toLowerCase().replace(/\s+/g, "-") || `post-${data.id}`}/`,
314
+ title: { rendered: data.title || `Updated Post ${data.id}` },
315
+ content: { rendered: data.content || "<p>Updated content</p>" },
316
+ excerpt: { rendered: data.excerpt || "<p>Updated excerpt</p>" },
317
+ author: 1,
318
+ featured_media: 0,
319
+ comment_status: "open",
320
+ ping_status: "open",
321
+ sticky: false,
322
+ template: "",
323
+ format: "standard",
324
+ meta: [],
325
+ categories: [1],
326
+ tags: [],
327
+ };
328
+
329
+ return mockPost;
330
+ }
331
+
332
+ /**
333
+ * Mock search
334
+ */
335
+ async search(query: string, types?: string[], subtype?: string): Promise<any[]> {
336
+ if (!query) {
337
+ return [];
338
+ }
339
+
340
+ return [
341
+ {
342
+ id: 1,
343
+ title: `Search Result for "${query}"`,
344
+ url: `https://demo.wordpress.com/search-result-1/`,
345
+ type: "post",
346
+ subtype: "post",
347
+ },
348
+ {
349
+ id: 2,
350
+ title: `Another result for "${query}"`,
351
+ url: `https://demo.wordpress.com/search-result-2/`,
352
+ type: "post",
353
+ subtype: "post",
354
+ },
355
+ ];
356
+ }
357
+
358
+ /**
359
+ * Mock deletePost
360
+ */
361
+ async deletePost(id: number, force = false): Promise<{ deleted: boolean; previous?: WordPressPost }> {
362
+ return {
363
+ deleted: true,
364
+ previous: {
365
+ id,
366
+ date: "2024-01-15T10:00:00",
367
+ date_gmt: "2024-01-15T10:00:00",
368
+ guid: { rendered: `https://demo.wordpress.com/?p=${id}` },
369
+ modified: "2024-01-15T10:00:00",
370
+ modified_gmt: "2024-01-15T10:00:00",
371
+ slug: `deleted-post-${id}`,
372
+ status: "trash",
373
+ type: "post",
374
+ link: `https://demo.wordpress.com/deleted-post-${id}/`,
375
+ title: { rendered: `Deleted Post ${id}` },
376
+ content: { rendered: `<p>This post was deleted.</p>` },
377
+ excerpt: { rendered: `<p>This post was deleted.</p>` },
378
+ author: 1,
379
+ featured_media: 0,
380
+ comment_status: "open",
381
+ ping_status: "open",
382
+ sticky: false,
383
+ template: "",
384
+ format: "standard",
385
+ meta: [],
386
+ categories: [1],
387
+ tags: [],
388
+ },
389
+ };
390
+ }
391
+
392
+ /**
393
+ * Override getSiteUrl to return mock URL
394
+ */
395
+ getSiteUrl(): string {
396
+ return "https://demo.wordpress.com";
397
+ }
398
+ }