@noleemits/vision-builder-control-mcp 4.16.1 → 4.18.1

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 (2) hide show
  1. package/index.js +84 -5
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -104,7 +104,7 @@ process.on('SIGINT', () => {
104
104
  // CONFIG
105
105
  // ================================================================
106
106
 
107
- const VERSION = '4.16.1';
107
+ const VERSION = '4.18.1';
108
108
  const MIN_PLUGIN_VERSION = '4.13.0'; // Minimum WP plugin version required by this MCP server
109
109
 
110
110
  // ================================================================
@@ -2003,7 +2003,7 @@ function getToolDefinitions() {
2003
2003
  },
2004
2004
  {
2005
2005
  name: 'fix_trailing_slashes',
2006
- description: 'Add missing trailing slashes to internal URLs across ALL post types (pages, posts, CPTs). Scans both Elementor widget data and Gutenberg/classic post_content. Skips anchors (#), query strings (?), external URLs, and file extensions (.pdf etc). ALWAYS run with dry_run=true first to preview changes.',
2006
+ description: 'Add missing trailing slashes to internal URLs across ALL post types (pages, posts, CPTs). Scans both Elementor widget data and Gutenberg/classic post_content. Skips anchors (#), query strings (?), external URLs, and file extensions (.pdf etc). Never changes post_modified date. ALWAYS run with dry_run=true first to preview changes.',
2007
2007
  inputSchema: {
2008
2008
  type: 'object',
2009
2009
  properties: {
@@ -2051,7 +2051,7 @@ function getToolDefinitions() {
2051
2051
  },
2052
2052
  {
2053
2053
  name: 'find_replace',
2054
- description: 'Global find & replace across all Elementor pages. Searches heading titles, text-editor HTML, button text, image-box titles/descriptions, icon-box titles/descriptions, icon-list items, toggle titles/content, and image alt text. Supports literal text or regex. Always preview with dry_run=true first.',
2054
+ description: 'Global find & replace across all Elementor pages. Searches heading titles, text-editor HTML, button text, image-box titles/descriptions, icon-box titles/descriptions, icon-list items, toggle titles/content, and image alt text. Supports literal text or regex. Never changes post_modified date (Elementor meta only). Always preview with dry_run=true first.',
2055
2055
  inputSchema: {
2056
2056
  type: 'object',
2057
2057
  properties: {
@@ -2155,7 +2155,7 @@ function getToolDefinitions() {
2155
2155
  },
2156
2156
  {
2157
2157
  name: 'update_post',
2158
- description: 'Update any field on a WordPress post/page. Only provided fields are changed. Supports title, content, status, slug, excerpt, taxonomies, featured image, and RankMath SEO.',
2158
+ description: 'Update any field on a WordPress post/page. Only provided fields are changed. Supports title, content, status, slug, excerpt, taxonomies, featured image, and RankMath SEO. Pass preserve_modified_date=true to keep the original last-modified date.',
2159
2159
  inputSchema: {
2160
2160
  type: 'object',
2161
2161
  properties: {
@@ -2231,6 +2231,16 @@ function getToolDefinitions() {
2231
2231
  }
2232
2232
  }
2233
2233
  },
2234
+ {
2235
+ name: 'audit_faq_schema',
2236
+ description: 'Audit all published posts/pages for FAQ schema issues: duplicate FAQPage markup (NVBC meta + RankMath block), orphaned NVBC schemas, unconverted plain FAQs, invalid JSON, empty Q&As, and encoding issues (bare u003c).',
2237
+ inputSchema: {
2238
+ type: 'object',
2239
+ properties: {
2240
+ post_type: { type: 'string', description: 'Optional: filter by post type (e.g., "page" or "post")' }
2241
+ }
2242
+ }
2243
+ },
2234
2244
  {
2235
2245
  name: 'update_term_seo',
2236
2246
  description: 'Update RankMath SEO fields on a taxonomy term (category, tag, custom taxonomy). Accepts any subset: title, description, focus_keyword, canonical_url, noindex (boolean convenience flag).',
@@ -2541,7 +2551,7 @@ function getToolDefinitions() {
2541
2551
  },
2542
2552
  {
2543
2553
  name: 'replace_post_content',
2544
- description: 'Bulk find-replace in WordPress post_content (Gutenberg/classic editor). Use for migrating URLs, fixing domains, replacing shortcodes. Always dry_run=true first to preview. Works on published posts and pages.',
2554
+ description: 'Bulk find-replace in WordPress post_content (Gutenberg/classic editor). Use for migrating URLs, fixing domains, replacing shortcodes. Always dry_run=true first to preview. Works on published posts and pages. Never changes post_modified date (uses direct DB write).',
2545
2555
  inputSchema: {
2546
2556
  type: 'object',
2547
2557
  properties: {
@@ -2580,6 +2590,18 @@ function getToolDefinitions() {
2580
2590
  required: ['posts']
2581
2591
  }
2582
2592
  },
2593
+ {
2594
+ name: 'convert_faq_to_rankmath',
2595
+ description: 'Scan post_content for plain Q/A FAQ sections and convert them to wp:rank-math/faq-block Gutenberg blocks. Detects H2 "FAQs" / "Frequently Asked Questions" headings followed by H3+paragraph Q/A pairs. Strips Q:/A: prefixes and   entities. Never changes post_modified date (direct DB write). ALWAYS dry_run=true first.',
2596
+ inputSchema: {
2597
+ type: 'object',
2598
+ properties: {
2599
+ post_id: { type: 'number', description: 'Convert only this specific post ID. Omit to scan all posts.' },
2600
+ post_type: { type: 'string', description: 'Filter by post type: "post", "page", etc. Omit for all types.' },
2601
+ dry_run: { type: 'boolean', description: 'Preview extracted Q&As without saving (default: true). Set false to apply conversion.' }
2602
+ }
2603
+ }
2604
+ },
2583
2605
  {
2584
2606
  name: 'get_global_styles',
2585
2607
  description: 'Read Elementor global colors and fonts from the active kit. Returns system colors (Primary, Secondary, Text, Accent), custom colors, system typography, and custom typography with all properties.',
@@ -3842,6 +3864,36 @@ async function handleToolCall(name, args) {
3842
3864
  return ok(out);
3843
3865
  }
3844
3866
 
3867
+ case 'audit_faq_schema': {
3868
+ const params = new URLSearchParams();
3869
+ if (args.post_type) params.set('post_type', args.post_type);
3870
+ const qs = params.toString() ? `?${params.toString()}` : '';
3871
+ const r = await apiCall(`/audit-faq-schema${qs}`);
3872
+ if (!r.success) return ok(`Failed: ${r.message || 'Unknown error'}`);
3873
+ const s = r.summary;
3874
+ let out = `=== FAQ SCHEMA AUDIT ===\n`;
3875
+ out += `Total published: ${s.total_posts}\n`;
3876
+ out += `With RankMath FAQ block: ${s.has_rankmath_block}\n`;
3877
+ out += `With NVBC plugin schema: ${s.has_nvbc_schema}\n`;
3878
+ out += `Clean (no issues): ${s.clean}\n\n`;
3879
+ out += `--- Issues ---\n`;
3880
+ out += `Duplicate FAQ (both sources): ${s.duplicate_faq}\n`;
3881
+ out += `Plain FAQ unconverted: ${s.plain_faq_unconverted}\n`;
3882
+ out += `Invalid JSON: ${s.invalid_json}\n`;
3883
+ out += `Empty questions: ${s.empty_questions}\n`;
3884
+ out += `Encoding issues (bare u003c): ${s.encoding_issues}\n`;
3885
+ if (r.issues.length) {
3886
+ out += `\n--- POSTS WITH ISSUES (${r.issues.length}) ---\n`;
3887
+ r.issues.forEach(p => {
3888
+ out += ` [${p.id}] ${p.title} (${p.type}/${p.editor})`;
3889
+ out += `\n Issues: ${p.issues.join(', ')}\n`;
3890
+ });
3891
+ } else {
3892
+ out += '\nNo issues found — all FAQ schemas are clean!';
3893
+ }
3894
+ return ok(out);
3895
+ }
3896
+
3845
3897
  case 'update_term_seo': {
3846
3898
  const { term_id, taxonomy, ...seoFields } = args;
3847
3899
  const body = { ...seoFields };
@@ -4484,6 +4536,33 @@ async function handleToolCall(name, args) {
4484
4536
  return ok(out);
4485
4537
  }
4486
4538
 
4539
+ case 'convert_faq_to_rankmath': {
4540
+ const body = {};
4541
+ if (args.post_id) body.post_id = args.post_id;
4542
+ if (args.post_type) body.post_type = args.post_type;
4543
+ if (args.dry_run !== undefined) body.dry_run = args.dry_run;
4544
+ const r = await apiCall('/convert-faq-to-rankmath', 'POST', body);
4545
+ if (r.code || r.error) return ok(`Failed: ${r.message || r.error}`);
4546
+ let out = r.dry_run ? `=== CONVERT FAQ TO RANKMATH (DRY RUN) ===\n` : `=== CONVERT FAQ TO RANKMATH ===\n`;
4547
+ out += `Posts scanned: ${r.posts_scanned} | Converted: ${r.posts_converted} | Total Q&As: ${r.total_questions}\n`;
4548
+ if (r.results?.length) {
4549
+ r.results.forEach(p => {
4550
+ out += `\nšŸ“„ [${p.post_id}] ${p.title} (${p.post_type}) — ${p.sections} section(s), ${p.questions} Q&A(s)${p.duplicates_removed ? ` [${p.duplicates_removed} duplicate(s) removed]` : ''}\n`;
4551
+ if (p.preview) {
4552
+ p.preview.forEach(sec => {
4553
+ out += ` Section: "${sec.heading}"\n`;
4554
+ sec.qa_pairs.forEach((qa, i) => {
4555
+ out += ` ${i + 1}. Q: ${qa.question}\n`;
4556
+ out += ` A: ${qa.answer}\n`;
4557
+ });
4558
+ });
4559
+ }
4560
+ });
4561
+ }
4562
+ out += `\n${r.note}`;
4563
+ return ok(out);
4564
+ }
4565
+
4487
4566
  case 'get_global_styles': {
4488
4567
  const r = await apiCall('/global-styles');
4489
4568
  if (r.code || r.error) return ok(`Failed: ${r.message || r.error}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noleemits/vision-builder-control-mcp",
3
- "version": "4.16.1",
3
+ "version": "4.18.1",
4
4
  "description": "Vision Builder Control MCP server - design token-driven page builder tools for WordPress/Elementor websites",
5
5
  "type": "module",
6
6
  "main": "index.js",