@noleemits/vision-builder-control-mcp 4.111.0 → 4.114.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.
- package/index.js +116 -18
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -111,7 +111,7 @@ process.on('SIGINT', () => {
|
|
|
111
111
|
// CONFIG
|
|
112
112
|
// ================================================================
|
|
113
113
|
|
|
114
|
-
const VERSION = '4.
|
|
114
|
+
const VERSION = '4.114.1';
|
|
115
115
|
const MIN_PLUGIN_VERSION = '4.13.0'; // Minimum WP plugin version required by this MCP server
|
|
116
116
|
|
|
117
117
|
// v4.110.0: shared styling philosophy appended to every build/style tool so the
|
|
@@ -1742,6 +1742,7 @@ async function apiCall(endpoint, method = 'GET', body = null) {
|
|
|
1742
1742
|
'Content-Type': 'application/json',
|
|
1743
1743
|
'Accept': 'application/json',
|
|
1744
1744
|
'User-Agent': `Vision-Builder-Control/${VERSION}`,
|
|
1745
|
+
'Connection': 'close',
|
|
1745
1746
|
},
|
|
1746
1747
|
signal: controller.signal,
|
|
1747
1748
|
};
|
|
@@ -2464,7 +2465,7 @@ function getToolDefinitions() {
|
|
|
2464
2465
|
},
|
|
2465
2466
|
{
|
|
2466
2467
|
name: 'create_post',
|
|
2467
|
-
description: 'Create a WordPress post, page, or CPT. Supports content, excerpt, taxonomies, featured image, parent linking (by slug or ID), Elementor setup, and initial RankMath SEO data.',
|
|
2468
|
+
description: 'Create a WordPress post, page, or CPT. Supports content, excerpt, taxonomies, featured image, parent linking (by slug or ID), an explicit publish date (for migrations), Elementor setup, and initial RankMath SEO data.',
|
|
2468
2469
|
inputSchema: {
|
|
2469
2470
|
type: 'object',
|
|
2470
2471
|
properties: {
|
|
@@ -2473,6 +2474,8 @@ function getToolDefinitions() {
|
|
|
2473
2474
|
content: { type: 'string', description: 'Post content (block HTML or plain text)' },
|
|
2474
2475
|
excerpt: { type: 'string', description: 'Post excerpt' },
|
|
2475
2476
|
status: { type: 'string', enum: ['draft', 'publish', 'private', 'pending'], description: 'Post status (default: draft)' },
|
|
2477
|
+
date: { type: 'string', description: 'Explicit publish date in site-local time, "YYYY-MM-DD HH:MM:SS" (or any strtotime-parseable string). Use to PRESERVE original dates when migrating posts — omit and the post gets the current date.' },
|
|
2478
|
+
date_gmt: { type: 'string', description: 'Optional explicit UTC date. If omitted, derived from `date` via the site timezone.' },
|
|
2476
2479
|
slug: { type: 'string', description: 'URL slug (auto-generated if omitted)' },
|
|
2477
2480
|
parent: { type: 'number', description: 'Parent post ID (for hierarchical types). Use this OR parent_slug.' },
|
|
2478
2481
|
parent_slug: { type: 'string', description: 'Parent slug — looked up against the same post_type. Saves a follow-up update_post call.' },
|
|
@@ -2777,16 +2780,27 @@ function getToolDefinitions() {
|
|
|
2777
2780
|
},
|
|
2778
2781
|
{
|
|
2779
2782
|
name: 'display_conditions',
|
|
2780
|
-
description: 'Get or set Elementor Theme Builder display conditions on a template (header, footer, single, archive). Common conditions: "include/general" (entire site), "include/singular/page" (all pages), "include/singular/post" (all posts), "include/archive" (all archives).',
|
|
2783
|
+
description: 'Get or set Elementor Theme Builder display conditions on a template (header, footer, single, archive). Common conditions: "include/general" (entire site), "include/singular/page" (all pages), "include/singular/post" (all posts), "include/archive" (all archives), "include/singular/{cpt}", "include/archive/{cpt}_archive". Conditions are VALIDATED against Elementor\'s registered conditions — a typo\'d slug returns condition_warnings (advisory) instead of silently no-op\'ing; pass strict:true to hard-refuse. Run list_display_conditions for the exact valid strings. On set, site caches are purged and a ?nocache verify hint is returned.',
|
|
2781
2784
|
inputSchema: {
|
|
2782
2785
|
type: 'object',
|
|
2783
2786
|
properties: {
|
|
2784
2787
|
template_id: { type: 'number', description: 'Template ID (from list_templates)' },
|
|
2785
|
-
conditions: { type: 'array', items: { type: 'string' }, description: 'Array of condition strings. Omit to read current conditions.' }
|
|
2788
|
+
conditions: { type: 'array', items: { type: 'string' }, description: 'Array of condition strings. Omit to read current conditions.' },
|
|
2789
|
+
strict: { type: 'boolean', description: 'If true, refuse the write when any condition does not match a registered Elementor condition. Default false (persist + warn).' }
|
|
2786
2790
|
},
|
|
2787
2791
|
required: ['template_id']
|
|
2788
2792
|
}
|
|
2789
2793
|
},
|
|
2794
|
+
{
|
|
2795
|
+
name: 'list_display_conditions',
|
|
2796
|
+
description: 'List the EXACT valid Theme Builder display-condition strings registered on this site (Elementor Pro), optionally filtered by post_type substring. Use before display_conditions to avoid silent no-ops — e.g. a CPT archive is "include/archive/{cpt}_archive", not "include/archive/{cpt}". Returns a fallback note when Pro is unavailable.',
|
|
2797
|
+
inputSchema: {
|
|
2798
|
+
type: 'object',
|
|
2799
|
+
properties: {
|
|
2800
|
+
post_type: { type: 'string', description: 'Optional substring filter (e.g. "team_member") to narrow to one type\'s singular + archive conditions.' }
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
},
|
|
2790
2804
|
|
|
2791
2805
|
// ── Nav menus (v4.29.0) ──
|
|
2792
2806
|
{
|
|
@@ -2894,7 +2908,7 @@ function getToolDefinitions() {
|
|
|
2894
2908
|
},
|
|
2895
2909
|
{
|
|
2896
2910
|
name: 'migrate_extracted_md',
|
|
2897
|
-
description: 'One-shot migration: take an extract-format markdown chunk and create or update a CPT post with cleaned HTML body, featured image, parent linking, and RankMath SEO. Idempotent: re-running with the same slug+post_type updates instead of duplicating. Pass md_content (preferred) or md_path. Use hero_basename to look up the featured image by filename instead of attachment ID.',
|
|
2911
|
+
description: 'One-shot migration: take an extract-format OR standard markdown chunk and create or update a CPT post with cleaned HTML body, featured image, parent linking, and RankMath SEO. Idempotent: re-running with the same slug+post_type updates instead of duplicating. md_content MUST be a STRING (markdown/plain text/clean HTML) — passing an array/object is now rejected with an error (it previously produced a silent "<p>Array</p>" corrupt write). Pass md_content (preferred) or md_path (string file path). Use hero_basename to look up the featured image by filename instead of attachment ID. For plain prose, ordinary markdown works; extract-format adds frontmatter blocks (## H1, **Meta description:**, etc.) that are parsed into title/SEO and stripped from the body.',
|
|
2898
2912
|
inputSchema: {
|
|
2899
2913
|
type: 'object',
|
|
2900
2914
|
properties: {
|
|
@@ -3079,7 +3093,7 @@ function getToolDefinitions() {
|
|
|
3079
3093
|
// ── Element Operations (v3.6.0) ──
|
|
3080
3094
|
{
|
|
3081
3095
|
name: 'add_element',
|
|
3082
|
-
description: 'Add a widget or container into a parent container on a page. Pass the full Elementor element JSON (elType, widgetType, settings, etc.). If no ID is provided, one will be auto-generated. Use position to insert at a specific index. NESTED COLUMN PRESET (v4.86.0): instead of element, pass preset="cols-3" (or cols-2, cols-4, sidebar-left, sidebar-right, split, stack) to drop a gap-safe column row AS A CHILD of parent_id. The scaffold ships content_width:full on the row AND every column, so no boxed `.e-con-inner` wrapper is injected and flex-row children never stack — this is the reusable fix for multi-column rows inside an existing section. Columns are empty; fill them with further add_element calls. GUARDRAIL: classic Elementor section/column elType is rejected (use containers); pass legacy:true to override.' + CSS_PHILOSOPHY,
|
|
3096
|
+
description: 'Add a widget or container into a parent container on a page. Pass the full Elementor element JSON (elType, widgetType, settings, etc.). If no ID is provided, one will be auto-generated. Use position to insert at a specific index. NESTED COLUMN PRESET (v4.86.0): instead of element, pass preset="cols-3" (or cols-2, cols-4, sidebar-left, sidebar-right, split, stack) to drop a gap-safe column row AS A CHILD of parent_id. The scaffold ships content_width:full on the row AND every column, so no boxed `.e-con-inner` wrapper is injected and flex-row children never stack — this is the reusable fix for multi-column rows inside an existing section. Columns are empty; fill them with further add_element calls. GUARDRAIL: classic Elementor section/column elType is rejected (use containers); pass legacy:true to override. DYNAMIC CONTAINER LINK: Elementor does NOT render a clickable <a> for a container whose link is a dynamic tag (e.g. post-url) — static container links work, but for a dynamic clickable card put the post-url link on a heading/button widget inside the card (you\'ll get a warning if you set a dynamic container link).' + CSS_PHILOSOPHY,
|
|
3083
3097
|
inputSchema: {
|
|
3084
3098
|
type: 'object',
|
|
3085
3099
|
properties: {
|
|
@@ -3095,6 +3109,24 @@ function getToolDefinitions() {
|
|
|
3095
3109
|
required: ['page_id', 'parent_id']
|
|
3096
3110
|
}
|
|
3097
3111
|
},
|
|
3112
|
+
{
|
|
3113
|
+
name: 'add_dynamic_field',
|
|
3114
|
+
description: 'Add a dynamic-data widget to a loop-item / single / archive template — a STANDARD widget (heading/text-editor/image) carrying the correct Elementor __dynamic__ tag. Use this INSTEAD of the theme-post-* widgets (theme-post-title/-excerpt/-featured-image), which are unreliable when authored via REST (they render placeholders). Types: title→heading+post-title, excerpt→text-editor+post-excerpt, content→text-editor+post-content, featured_image→image+post-featured-image, acf→heading+acf (pass field = the ACF field key/name). The widget renders the current post\'s data inside loop/single context.',
|
|
3115
|
+
inputSchema: {
|
|
3116
|
+
type: 'object',
|
|
3117
|
+
properties: {
|
|
3118
|
+
page_id: { type: 'number', description: 'Template (or page) ID to add into' },
|
|
3119
|
+
parent_id: { type: 'string', description: 'Elementor ID of the parent container' },
|
|
3120
|
+
type: { type: 'string', enum: ['title', 'excerpt', 'content', 'featured_image', 'acf'], description: 'Which post field to bind.' },
|
|
3121
|
+
field: { type: 'string', description: 'For type=acf: the ACF field key or name to bind.' },
|
|
3122
|
+
tag: { type: 'string', description: 'Override the dynamic tag name (advanced — e.g. a custom registered tag).' },
|
|
3123
|
+
settings: { type: 'object', description: 'Extra widget settings to merge (e.g. typography, header_size, link). additionalProperties.', additionalProperties: true },
|
|
3124
|
+
position: { type: 'number', description: 'Optional 0-based insert index. Omit to append.' },
|
|
3125
|
+
force: { type: 'boolean', description: 'Override edit locks.' }
|
|
3126
|
+
},
|
|
3127
|
+
required: ['page_id', 'parent_id', 'type']
|
|
3128
|
+
}
|
|
3129
|
+
},
|
|
3098
3130
|
{
|
|
3099
3131
|
name: 'get_element',
|
|
3100
3132
|
description: 'Get a single element\'s full settings and metadata by its Elementor ID. Returns elType, widgetType, all settings, and a summary of children (for containers). Use this to inspect an element before updating it.',
|
|
@@ -3196,7 +3228,7 @@ function getToolDefinitions() {
|
|
|
3196
3228
|
},
|
|
3197
3229
|
{
|
|
3198
3230
|
name: 'convert_to_gutenberg',
|
|
3199
|
-
description: 'Phase 2 migration tool — convert an
|
|
3231
|
+
description: 'Phase 2 migration tool — convert an ELEMENTOR page/post\'s content to native core Gutenberg blocks. SCOPE: Elementor pages ONLY (reads _elementor_data); a classic/HTML post returns not_elementor — there is no automated classic-HTML → blocks path (store clean semantic HTML in post_content, it renders as a Classic block). NON-DESTRUCTIVE: the source is never modified. mode=preview (default) returns the block markup; mode=ir returns the intermediate representation (node list) for debugging; mode=new_draft creates a fresh draft and returns its edit URL. The new draft mirrors the source post type by default (post→post, page→page); override with target_type. Rich text-editor content that is not a single paragraph falls back to a lossless wp:html block. The output is pure core blocks — converted content does NOT depend on this plugin to render.',
|
|
3200
3232
|
inputSchema: { type: 'object', properties: {
|
|
3201
3233
|
page_id: { type: 'integer', description: 'Source Elementor page/post ID to convert.' },
|
|
3202
3234
|
mode: { type: 'string', enum: ['preview', 'ir', 'new_draft'], description: 'preview (default) | ir | new_draft' },
|
|
@@ -3486,14 +3518,15 @@ function getToolDefinitions() {
|
|
|
3486
3518
|
},
|
|
3487
3519
|
{
|
|
3488
3520
|
name: 'get_widget_schema',
|
|
3489
|
-
description: 'Read the full settings schema for one widget or element type — every accepted control with type, label, default, options, responsive flag, and section grouping. For atomic V4 widgets, returns the serialized props_schema instead (different system). Use to avoid having to read Elementor source. Pass section to scope to one control section, search to filter by control-name substring, or keys_only=true for just the names. v4.44.3+.',
|
|
3521
|
+
description: 'Read the full settings schema for one widget or element type — every accepted control with type, label, default, options, responsive flag, and section grouping. For atomic V4 widgets, returns the serialized props_schema instead (different system). Use to avoid having to read Elementor source. By DEFAULT the universal Advanced-tab control groups (margin/padding/motion-effects/transform/background/border/masking/responsive/custom-css/attributes) are EXCLUDED — they are ~200-300 identical boilerplate controls on every widget; pass include_common=true to include them. Pass section to scope to one control section (overrides the common filter), search to filter by control-name substring, or keys_only=true for just the names. v4.44.3+.',
|
|
3490
3522
|
inputSchema: {
|
|
3491
3523
|
type: 'object',
|
|
3492
3524
|
properties: {
|
|
3493
3525
|
widget_type: { type: 'string', description: 'Widget or element name (e.g. "heading", "e-heading", "container", "image", "button"). Use list_widget_types to enumerate.' },
|
|
3494
|
-
section: { type: 'string', description: 'Restrict to controls inside this control section (e.g. "section_title_style").' },
|
|
3495
|
-
search: { type: 'string', description: 'Substring filter on control name.' },
|
|
3496
|
-
keys_only: { type: 'boolean', description: 'Return only control name + type per entry (slim payload). Default: false.' }
|
|
3526
|
+
section: { type: 'string', description: 'Restrict to controls inside this control section (e.g. "section_title_style"). Overrides the default common-section filter.' },
|
|
3527
|
+
search: { type: 'string', description: 'Substring filter on control name. Overrides the default common-section filter.' },
|
|
3528
|
+
keys_only: { type: 'boolean', description: 'Return only control name + type per entry (slim payload). Default: false.' },
|
|
3529
|
+
include_common: { type: 'boolean', description: 'Include the universal Advanced-tab boilerplate controls (transform/effects/background/responsive/custom-css/etc.). Default: false — they are hidden to save tokens.' }
|
|
3497
3530
|
},
|
|
3498
3531
|
required: ['widget_type']
|
|
3499
3532
|
}
|
|
@@ -5223,12 +5256,13 @@ async function handleToolCall(name, args) {
|
|
|
5223
5256
|
const body = { title: args.title };
|
|
5224
5257
|
const passthrough = ['post_type', 'content', 'excerpt', 'status', 'slug',
|
|
5225
5258
|
'parent', 'parent_slug', 'taxonomies', 'featured_image_id',
|
|
5226
|
-
'featured_image_basename', 'elementor', 'seo', 'dedupe_by_title'
|
|
5259
|
+
'featured_image_basename', 'elementor', 'seo', 'dedupe_by_title',
|
|
5260
|
+
'date', 'date_gmt'];
|
|
5227
5261
|
for (const k of passthrough) if (args[k] !== undefined) body[k] = args[k];
|
|
5228
5262
|
const r = await apiCall('/posts', 'POST', body);
|
|
5229
5263
|
if (!r.success) return ok(`Failed: ${r.message || 'Unknown error'}`);
|
|
5230
5264
|
const prefix = r.was_existing ? 'Post already existed (dedupe hit)' : 'Post created';
|
|
5231
|
-
return ok(`${prefix}!\nID: ${r.id} | Type: ${r.type} | Status: ${r.status}\nTitle: ${r.title}\nSlug: ${r.slug}\nURL: ${r.url}\nEdit: ${r.edit_url}`);
|
|
5265
|
+
return ok(`${prefix}!\nID: ${r.id} | Type: ${r.type} | Status: ${r.status}\nTitle: ${r.title}\nSlug: ${r.slug}${r.date ? ` | Date: ${r.date}` : ''}\nURL: ${r.url}\nEdit: ${r.edit_url}`);
|
|
5232
5266
|
}
|
|
5233
5267
|
|
|
5234
5268
|
case 'get_post_by_slug': {
|
|
@@ -5558,10 +5592,22 @@ async function handleToolCall(name, args) {
|
|
|
5558
5592
|
|
|
5559
5593
|
case 'display_conditions': {
|
|
5560
5594
|
if (args.conditions) {
|
|
5561
|
-
const
|
|
5562
|
-
|
|
5563
|
-
});
|
|
5564
|
-
|
|
5595
|
+
const body = { conditions: args.conditions };
|
|
5596
|
+
if (args.strict !== undefined) body.strict = args.strict;
|
|
5597
|
+
const r = await apiCall(`/templates/${args.template_id}/display-conditions`, 'POST', body);
|
|
5598
|
+
if (r.code || r.error) {
|
|
5599
|
+
let m = `Failed: ${r.message || r.error}`;
|
|
5600
|
+
if (Array.isArray(r.warnings) && r.warnings.length) m += `\n - ${r.warnings.join('\n - ')}`;
|
|
5601
|
+
if (r.hint) m += `\n${r.hint}`;
|
|
5602
|
+
return ok(m);
|
|
5603
|
+
}
|
|
5604
|
+
let msg = `Set ${r.conditions.length} condition(s) on "${r.title}" (ID: ${r.template_id}):\n${r.conditions.join('\n')}`;
|
|
5605
|
+
if (Array.isArray(r.condition_warnings) && r.condition_warnings.length) {
|
|
5606
|
+
msg += `\n⚠️ CONDITION WARNINGS (persisted anyway — these may not match anything):\n - ${r.condition_warnings.join('\n - ')}\n Run list_display_conditions for valid strings.`;
|
|
5607
|
+
}
|
|
5608
|
+
if (r.caches_purged && r.caches_purged.length) msg += `\nCaches purged: ${r.caches_purged.join(', ')}`;
|
|
5609
|
+
if (r.verify_hint) msg += `\n${r.verify_hint}`;
|
|
5610
|
+
return ok(msg);
|
|
5565
5611
|
} else {
|
|
5566
5612
|
const r = await apiCall(`/templates/${args.template_id}/display-conditions`);
|
|
5567
5613
|
const conds = r.conditions && r.conditions.length ? r.conditions.join('\n') : '(none)';
|
|
@@ -5569,6 +5615,18 @@ async function handleToolCall(name, args) {
|
|
|
5569
5615
|
}
|
|
5570
5616
|
}
|
|
5571
5617
|
|
|
5618
|
+
case 'list_display_conditions': {
|
|
5619
|
+
const params = new URLSearchParams();
|
|
5620
|
+
if (args.post_type) params.set('post_type', args.post_type);
|
|
5621
|
+
const r = await apiCall(`/templates/conditions/available?${params.toString()}`);
|
|
5622
|
+
if (r.code || r.error) return ok(`Failed: ${r.message || r.error}`);
|
|
5623
|
+
if (!r.available) return ok(`Condition listing unavailable.\n${r.note}`);
|
|
5624
|
+
let out = `Valid display conditions (${r.count}${r.post_type ? `, filtered: "${r.post_type}"` : ''}):\n`;
|
|
5625
|
+
out += r.conditions.map(c => ` ${c}`).join('\n');
|
|
5626
|
+
out += `\n\n${r.note}`;
|
|
5627
|
+
return ok(out);
|
|
5628
|
+
}
|
|
5629
|
+
|
|
5572
5630
|
case 'list_nav_menus': {
|
|
5573
5631
|
const r = await apiCall('/menus');
|
|
5574
5632
|
if (!r.menus || !r.menus.length) return ok('No nav menus found.');
|
|
@@ -5808,7 +5866,43 @@ async function handleToolCall(name, args) {
|
|
|
5808
5866
|
if (args.force) body.force = true;
|
|
5809
5867
|
const r = await apiCall(`/pages/${args.page_id}/add-element`, 'POST', body);
|
|
5810
5868
|
if (r.code || r.error) return ok(`Failed: ${r.message || r.error || 'Unknown error'}`);
|
|
5811
|
-
|
|
5869
|
+
let addMsg = `Element added!\nPage: ${r.page_id}\nParent: ${r.parent_id}\nNew element ID: ${r.element_id}${r.position !== null && r.position !== undefined ? `\nPosition: ${r.position}` : ' (appended)'}`;
|
|
5870
|
+
if (Array.isArray(r.warnings) && r.warnings.length) addMsg += `\n⚠️ ${r.warnings.join('\n⚠️ ')}`;
|
|
5871
|
+
return ok(addMsg);
|
|
5872
|
+
}
|
|
5873
|
+
|
|
5874
|
+
case 'add_dynamic_field': {
|
|
5875
|
+
// Emit a standard widget + the correct __dynamic__ tag (the proven-rendering
|
|
5876
|
+
// form), instead of the unreliable theme-post-* widgets.
|
|
5877
|
+
const MAP = {
|
|
5878
|
+
title: { widgetType: 'heading', control: 'title', tag: 'post-title', base: { title: '', header_size: 'h2' } },
|
|
5879
|
+
excerpt: { widgetType: 'text-editor', control: 'editor', tag: 'post-excerpt', base: { editor: '' } },
|
|
5880
|
+
content: { widgetType: 'text-editor', control: 'editor', tag: 'post-content', base: { editor: '' } },
|
|
5881
|
+
featured_image: { widgetType: 'image', control: 'image', tag: 'post-featured-image', base: { image: { url: '', id: '' } } },
|
|
5882
|
+
acf: { widgetType: 'heading', control: 'title', tag: 'acf', base: { title: '', header_size: 'h2' } },
|
|
5883
|
+
};
|
|
5884
|
+
const m = MAP[args.type];
|
|
5885
|
+
if (!m) return ok(`Failed: unknown type "${args.type}". Use one of: ${Object.keys(MAP).join(', ')}.`);
|
|
5886
|
+
if (args.type === 'acf' && !args.field) return ok('Failed: type=acf requires a `field` (the ACF field key/name).');
|
|
5887
|
+
|
|
5888
|
+
// Elementor dynamic-tag shortcode: [elementor-tag id="<7-char>" name="<tag>" settings="<urlencoded-json>"]
|
|
5889
|
+
const tagId = Array.from({ length: 7 }, () => 'abcdef0123456789'[Math.floor(Math.random() * 16)]).join('');
|
|
5890
|
+
const tagSettings = {};
|
|
5891
|
+
if (args.type === 'acf') tagSettings.key = args.field;
|
|
5892
|
+
const enc = encodeURIComponent(JSON.stringify(tagSettings));
|
|
5893
|
+
const dynamicValue = `[elementor-tag id="${tagId}" name="${args.tag || m.tag}" settings="${enc}"]`;
|
|
5894
|
+
|
|
5895
|
+
const settings = Object.assign({}, m.base, args.settings || {}, {
|
|
5896
|
+
__dynamic__: Object.assign({}, (args.settings && args.settings.__dynamic__) || {}, { [m.control]: dynamicValue }),
|
|
5897
|
+
});
|
|
5898
|
+
const element = { elType: 'widget', widgetType: m.widgetType, settings };
|
|
5899
|
+
|
|
5900
|
+
const body = { parent_id: args.parent_id, element };
|
|
5901
|
+
if (args.position !== undefined) body.position = args.position;
|
|
5902
|
+
if (args.force) body.force = true;
|
|
5903
|
+
const r = await apiCall(`/pages/${args.page_id}/add-element`, 'POST', body);
|
|
5904
|
+
if (r.code || r.error) return ok(`Failed: ${r.message || r.error || 'Unknown error'}`);
|
|
5905
|
+
return ok(`Dynamic field added!\nType: ${args.type} → ${m.widgetType} widget bound to "${args.tag || m.tag}"${args.field ? ` (field: ${args.field})` : ''}\nElement ID: ${r.element_id} (parent ${r.parent_id})\nIt renders the current post's data in loop/single context.`);
|
|
5812
5906
|
}
|
|
5813
5907
|
|
|
5814
5908
|
case 'get_element': {
|
|
@@ -6720,6 +6814,7 @@ async function handleToolCall(name, args) {
|
|
|
6720
6814
|
if (args.section) params.set('section', args.section);
|
|
6721
6815
|
if (args.search) params.set('search', args.search);
|
|
6722
6816
|
if (args.keys_only) params.set('keys_only', '1');
|
|
6817
|
+
if (args.include_common) params.set('include_common', '1');
|
|
6723
6818
|
const r = await apiCall(`/widget-schema?${params.toString()}`);
|
|
6724
6819
|
if (r.code || r.error) return ok(`Failed: ${r.message || r.error}`);
|
|
6725
6820
|
let out =
|
|
@@ -6746,6 +6841,9 @@ async function handleToolCall(name, args) {
|
|
|
6746
6841
|
out += ` ${name.padEnd(36)} ${meta.join(' | ')}${dflt}\n`;
|
|
6747
6842
|
if (c.label && !args.keys_only) out += `${' '.repeat(38)}label: ${c.label}\n`;
|
|
6748
6843
|
}
|
|
6844
|
+
if (r.excluded_common && r.excluded_common.controls > 0) {
|
|
6845
|
+
out += `\n(${r.excluded_common.controls} universal Advanced-tab controls hidden across ${r.excluded_common.sections.length} sections — pass include_common=true to see them.)`;
|
|
6846
|
+
}
|
|
6749
6847
|
return ok(out);
|
|
6750
6848
|
}
|
|
6751
6849
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noleemits/vision-builder-control-mcp",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.114.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",
|