@elementor/editor-canvas 4.3.0-1002 → 4.3.0-1004

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/dist/index.js CHANGED
@@ -116,13 +116,13 @@ var initWidgetsSchemaResource = (reg) => {
116
116
  if (!widgetType) {
117
117
  throw new Error("No widget type provided.");
118
118
  }
119
- const schema2 = await fetchWidgetSchema(widgetType);
119
+ const schema = await fetchWidgetSchema(widgetType);
120
120
  return {
121
121
  contents: [
122
122
  {
123
123
  uri: uri.toString(),
124
124
  mimeType: "application/json",
125
- text: JSON.stringify(schema2)
125
+ text: JSON.stringify(schema)
126
126
  }
127
127
  ]
128
128
  };
@@ -1310,10 +1310,10 @@ var getMultiPropsValue = (multiProps) => {
1310
1310
  // src/renderers/create-props-resolver.ts
1311
1311
  var TRANSFORM_DEPTH_LIMIT = 3;
1312
1312
  function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }) {
1313
- async function resolve({ props, schema: schema2, signal, renderContext }) {
1314
- schema2 = schema2 ?? initialSchema;
1313
+ async function resolve({ props, schema, signal, renderContext }) {
1314
+ schema = schema ?? initialSchema;
1315
1315
  const promises = Promise.all(
1316
- Object.entries(schema2).map(async ([key, type]) => {
1316
+ Object.entries(schema).map(async ([key, type]) => {
1317
1317
  const value = props[key] ?? type.default;
1318
1318
  const transformed = await transform({ value, key, type, signal, renderContext });
1319
1319
  onPropResolve?.({ key, value: transformed, propValue: value, propType: type });
@@ -3961,7 +3961,7 @@ function initTabsModelExtensions() {
3961
3961
  }
3962
3962
 
3963
3963
  // src/mcp/canvas-mcp.ts
3964
- var import_editor_props9 = require("@elementor/editor-props");
3964
+ var import_editor_props8 = require("@elementor/editor-props");
3965
3965
 
3966
3966
  // src/mcp/resources/available-widgets-resource.ts
3967
3967
  var import_http_client3 = require("@elementor/http-client");
@@ -4482,8 +4482,25 @@ function getElementDisplayName(container) {
4482
4482
  // src/mcp/tools/build-composition/tool.ts
4483
4483
  var import_editor_documents2 = require("@elementor/editor-documents");
4484
4484
  var import_editor_elements11 = require("@elementor/editor-elements");
4485
- var import_http_client6 = require("@elementor/http-client");
4485
+ var import_http_client7 = require("@elementor/http-client");
4486
4486
  var import_schema = require("@elementor/schema");
4487
+
4488
+ // src/mcp/utils/get-mcp-error-message.ts
4489
+ var import_http_client6 = require("@elementor/http-client");
4490
+ function getMcpErrorMessage(error, toolName) {
4491
+ if (error instanceof import_http_client6.AxiosError) {
4492
+ const data = error.response?.data;
4493
+ if (data?.message) {
4494
+ return data.code ? `${data.code}: ${data.message}` : data.message;
4495
+ }
4496
+ }
4497
+ if (error instanceof Error) {
4498
+ return error.message;
4499
+ }
4500
+ return `${toolName} failed with an unknown error.`;
4501
+ }
4502
+
4503
+ // src/mcp/tools/build-composition/tool.ts
4487
4504
  var MCP_PROXY_URL5 = "elementor/v1/mcp-proxy";
4488
4505
  var initBuildCompositionTool = (reg) => {
4489
4506
  const { addTool } = reg;
@@ -4505,6 +4522,9 @@ var initBuildCompositionTool = (reg) => {
4505
4522
  "Map configuration-id \u2192 raw CSS declarations (property \u2192 value strings; no selectors). Server converts to native styles; unconvertible declarations become the element custom CSS."
4506
4523
  ),
4507
4524
  parentId: import_schema.z.string().optional().describe("ID of the parent container. Omit or pass 'document' to insert at document root."),
4525
+ mode: import_schema.z.enum(["append", "replace_children"]).optional().describe(
4526
+ "'append' (default) inserts under parentId; 'replace_children' removes existing direct children of parentId first, then inserts."
4527
+ ),
4508
4528
  dryRun: import_schema.z.boolean().optional().describe("If true, validate and return the resolved tree without persisting.")
4509
4529
  },
4510
4530
  outputSchema: {
@@ -4513,15 +4533,16 @@ var initBuildCompositionTool = (reg) => {
4513
4533
  version: import_schema.z.string(),
4514
4534
  resolvedXml: import_schema.z.string(),
4515
4535
  llmInstructions: import_schema.z.string(),
4516
- warnings: import_schema.z.array(import_schema.z.string()).optional()
4536
+ warnings: import_schema.z.array(import_schema.z.string()).optional(),
4537
+ removedElementIds: import_schema.z.array(import_schema.z.string()).optional()
4517
4538
  },
4518
- handler: async ({ xmlStructure, elementConfig, style, parentId, dryRun }) => {
4539
+ handler: async ({ xmlStructure, elementConfig, style, parentId, mode, dryRun }) => {
4519
4540
  const document2 = (0, import_editor_documents2.getCurrentDocument)();
4520
4541
  if (!document2?.id) {
4521
4542
  throw new Error("No active document found.");
4522
4543
  }
4523
4544
  try {
4524
- const { data } = await (0, import_http_client6.httpService)().post(MCP_PROXY_URL5, {
4545
+ const { data } = await (0, import_http_client7.httpService)().post(MCP_PROXY_URL5, {
4525
4546
  tool: "build-composition",
4526
4547
  input: {
4527
4548
  post_id: document2.id,
@@ -4529,6 +4550,7 @@ var initBuildCompositionTool = (reg) => {
4529
4550
  element_config: elementConfig ?? {},
4530
4551
  style: style ?? {},
4531
4552
  parent_id: parentId ?? "document",
4553
+ mode: mode ?? "append",
4532
4554
  dry_run: dryRun ?? false
4533
4555
  }
4534
4556
  });
@@ -4549,26 +4571,15 @@ var initBuildCompositionTool = (reg) => {
4549
4571
  version: data.data.version,
4550
4572
  resolvedXml: data.data.resolved_xml,
4551
4573
  llmInstructions: data.data.llm_instructions,
4552
- warnings: data.data.warnings
4574
+ warnings: data.data.warnings,
4575
+ removedElementIds: data.data.removed_element_ids
4553
4576
  };
4554
4577
  } catch (error) {
4555
- throw new Error(getErrorMessage(error));
4578
+ throw new Error(getMcpErrorMessage(error, "build-composition"));
4556
4579
  }
4557
4580
  }
4558
4581
  });
4559
4582
  };
4560
- function getErrorMessage(error) {
4561
- if (error instanceof import_http_client6.AxiosError) {
4562
- const data = error.response?.data;
4563
- if (data?.message) {
4564
- return data.code ? `${data.code}: ${data.message}` : data.message;
4565
- }
4566
- }
4567
- if (error instanceof Error) {
4568
- return error.message;
4569
- }
4570
- return "build-composition failed with an unknown error.";
4571
- }
4572
4583
 
4573
4584
  // src/mcp/tools/configure-element/tool.ts
4574
4585
  var import_editor_elements14 = require("@elementor/editor-elements");
@@ -4597,9 +4608,9 @@ var readStoredCustomCssText = (raw) => {
4597
4608
 
4598
4609
  // src/mcp/utils/resolve-canonical-prop-name.ts
4599
4610
  var import_editor_elements12 = require("@elementor/editor-elements");
4600
- function buildAliasToCanonicalMap(schema2) {
4611
+ function buildAliasToCanonicalMap(schema) {
4601
4612
  const aliasToCanonical = {};
4602
- for (const [canonical, propType] of Object.entries(schema2)) {
4613
+ for (const [canonical, propType] of Object.entries(schema)) {
4603
4614
  const aliases = propType.meta?.aliases;
4604
4615
  if (!Array.isArray(aliases)) {
4605
4616
  continue;
@@ -4613,26 +4624,26 @@ function buildAliasToCanonicalMap(schema2) {
4613
4624
  return aliasToCanonical;
4614
4625
  }
4615
4626
  function resolveCanonicalPropName(elementType, propertyName) {
4616
- const schema2 = (0, import_editor_elements12.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4617
- if (!schema2 || schema2[propertyName]) {
4627
+ const schema = (0, import_editor_elements12.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4628
+ if (!schema || schema[propertyName]) {
4618
4629
  return propertyName;
4619
4630
  }
4620
- return buildAliasToCanonicalMap(schema2)[propertyName] ?? propertyName;
4631
+ return buildAliasToCanonicalMap(schema)[propertyName] ?? propertyName;
4621
4632
  }
4622
4633
  function resolveCanonicalPropKeys(elementType, props) {
4623
- const schema2 = (0, import_editor_elements12.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4624
- if (!schema2) {
4634
+ const schema = (0, import_editor_elements12.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
4635
+ if (!schema) {
4625
4636
  return { ...props };
4626
4637
  }
4627
- const aliasToCanonical = buildAliasToCanonicalMap(schema2);
4638
+ const aliasToCanonical = buildAliasToCanonicalMap(schema);
4628
4639
  const resolved = {};
4629
4640
  for (const [key, value] of Object.entries(props)) {
4630
- if (schema2[key]) {
4641
+ if (schema[key]) {
4631
4642
  resolved[key] = value;
4632
4643
  }
4633
4644
  }
4634
4645
  for (const [key, value] of Object.entries(props)) {
4635
- if (schema2[key]) {
4646
+ if (schema[key]) {
4636
4647
  continue;
4637
4648
  }
4638
4649
  const canonical = aliasToCanonical[key];
@@ -4680,9 +4691,9 @@ var dynamicTagLLMResolver = (value) => {
4680
4691
  }
4681
4692
  };
4682
4693
  };
4683
- var buildStrictSettings = (schema2, provided) => {
4694
+ var buildStrictSettings = (schema, provided) => {
4684
4695
  const settings = {};
4685
- for (const [key, propType] of Object.entries(schema2)) {
4696
+ for (const [key, propType] of Object.entries(schema)) {
4686
4697
  if (OMITTED_DYNAMIC_SETTING_KEYS.includes(key)) {
4687
4698
  continue;
4688
4699
  }
@@ -5109,102 +5120,49 @@ Provide styling as raw CSS via the "style" parameter (a flat map of CSS property
5109
5120
  }`;
5110
5121
  }
5111
5122
 
5112
- // src/mcp/tools/get-element-config/tool.ts
5113
- var import_editor_elements15 = require("@elementor/editor-elements");
5114
- var import_editor_props8 = require("@elementor/editor-props");
5123
+ // src/mcp/tools/get-page-structure/tool.ts
5124
+ var import_editor_documents3 = require("@elementor/editor-documents");
5125
+ var import_http_client8 = require("@elementor/http-client");
5115
5126
  var import_schema4 = require("@elementor/schema");
5116
- var schema = {
5117
- elementId: import_schema4.z.string()
5118
- };
5119
- var outputSchema2 = {
5120
- properties: import_schema4.z.record(import_schema4.z.string(), import_schema4.z.any()).describe("A record mapping PropTypes to their corresponding PropValues"),
5121
- style: import_schema4.z.record(import_schema4.z.string(), import_schema4.z.any()).describe("A record mapping StyleSchema properties to their corresponding PropValues"),
5122
- childElements: import_schema4.z.array(
5123
- import_schema4.z.object({
5124
- id: import_schema4.z.string(),
5125
- elementType: import_schema4.z.string(),
5126
- childElements: import_schema4.z.array(import_schema4.z.any()).describe("An array of child element IDs, when applicable, same structure recursively")
5127
- })
5128
- ).describe("An array of child element IDs, when applicable, with recursive structure")
5129
- };
5130
- var structuredElements = (element) => {
5131
- const children = element.children || [];
5132
- return children.map((child) => {
5133
- return {
5134
- id: child.id,
5135
- elementType: child.model.get("elType") || child.model.get("widgetType") || "unknown",
5136
- childElements: structuredElements(child)
5137
- };
5138
- });
5139
- };
5140
- var initGetElementConfigTool = (reg) => {
5127
+ var MCP_PROXY_URL6 = "elementor/v1/mcp-proxy";
5128
+ var initGetPageStructureTool = (reg) => {
5141
5129
  const { addTool } = reg;
5142
5130
  addTool({
5143
- name: "get-element-configuration-values",
5144
- description: "Retrieve the element's configuration PropValues for a specific element by unique ID.",
5145
- schema,
5146
- outputSchema: outputSchema2,
5147
- handler: async ({ elementId }) => {
5148
- const element = (0, import_editor_elements15.getContainer)(elementId);
5149
- if (!element) {
5150
- throw new Error(`Element with ID ${elementId} not found.`);
5151
- }
5152
- const elementType = element.model.get("widgetType") || element.model.get("elType") || "";
5153
- const widgetData = (0, import_editor_elements15.getWidgetsCache)()?.[elementType];
5154
- if (!widgetData) {
5155
- throw new Error(
5156
- `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
5157
- );
5158
- }
5159
- if (!widgetData.atomic_props_schema) {
5160
- throw new Error(
5161
- `This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${elementType}`
5162
- );
5163
- }
5164
- const elementRawSettings = element.settings;
5165
- const propSchema = (0, import_editor_elements15.getWidgetsCache)()?.[elementType]?.atomic_props_schema;
5166
- if (!elementRawSettings || !propSchema) {
5167
- throw new Error(`No settings or prop schema found for element ID: ${elementId}`);
5131
+ name: "get-page-structure",
5132
+ description: "Returns the Elementor element tree (widgets, containers, and nested content) for a post or page. If no postId is provided, uses the currently open document. Only works for posts saved with Elementor.",
5133
+ schema: {
5134
+ postId: import_schema4.z.number().optional().describe(
5135
+ "WordPress post ID of the Elementor document. If omitted, uses the currently open document."
5136
+ )
5137
+ },
5138
+ outputSchema: {
5139
+ elements: import_schema4.z.array(import_schema4.z.any()).describe("Root-level Elementor elements for the document.")
5140
+ },
5141
+ handler: async ({ postId }) => {
5142
+ const resolvedPostId = postId ?? (0, import_editor_documents3.getCurrentDocument)()?.id;
5143
+ if (!resolvedPostId) {
5144
+ throw new Error("No post ID provided and no active document found.");
5168
5145
  }
5169
- const propValues = {};
5170
- const stylePropValues = {};
5171
- import_editor_props8.Schema.configurableKeys(propSchema).forEach((key) => {
5172
- propValues[key] = structuredClone(elementRawSettings.get(key));
5173
- });
5174
- const elementStyles = (0, import_editor_elements15.getElementStyles)(elementId) || {};
5175
- const localStyle = Object.values(elementStyles).find((style) => style.label === "local");
5176
- if (localStyle) {
5177
- const defaultVariant = localStyle.variants.find(
5178
- (variant) => variant.meta.breakpoint === "desktop" && !variant.meta.state
5179
- );
5180
- if (defaultVariant) {
5181
- const styleProps = defaultVariant.props || {};
5182
- Object.keys(styleProps).forEach((stylePropName) => {
5183
- if (typeof styleProps[stylePropName] !== "undefined") {
5184
- stylePropValues[stylePropName] = structuredClone(styleProps[stylePropName]);
5185
- }
5186
- });
5187
- if (defaultVariant.custom_css) {
5188
- stylePropValues.custom_css = atob(defaultVariant.custom_css.raw);
5146
+ try {
5147
+ const { data } = await (0, import_http_client8.httpService)().post(MCP_PROXY_URL6, {
5148
+ tool: "get-page-structure",
5149
+ input: {
5150
+ post_id: resolvedPostId
5189
5151
  }
5190
- }
5152
+ });
5153
+ return {
5154
+ elements: data.data.elements
5155
+ };
5156
+ } catch (error) {
5157
+ throw new Error(getMcpErrorMessage(error, "get-page-structure"));
5191
5158
  }
5192
- return {
5193
- properties: {
5194
- ...propValues
5195
- },
5196
- style: {
5197
- ...stylePropValues
5198
- },
5199
- childElements: structuredElements(element)
5200
- };
5201
5159
  }
5202
5160
  });
5203
5161
  };
5204
5162
 
5205
5163
  // src/mcp/canvas-mcp.ts
5206
5164
  var initCanvasMcp = (reg) => {
5207
- import_editor_props9.Schema.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5165
+ import_editor_props8.Schema.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5208
5166
  initWidgetsSchemaResource(reg);
5209
5167
  initAvailableWidgetsResource(reg);
5210
5168
  initDocumentStructureResource(reg);
@@ -5213,9 +5171,9 @@ var initCanvasMcp = (reg) => {
5213
5171
  initEditorStateResource(reg);
5214
5172
  initGeneralContextResource(reg);
5215
5173
  initBestPracticesResource(reg);
5216
- initGetElementConfigTool(reg);
5217
5174
  initConfigureElementTool(reg);
5218
5175
  initBuildCompositionTool(reg);
5176
+ initGetPageStructureTool(reg);
5219
5177
  initBreakpointsResource(reg);
5220
5178
  };
5221
5179
 
@@ -5328,7 +5286,7 @@ Note: The "size" property controls image resolution/loading, not visual size. Se
5328
5286
  `;
5329
5287
 
5330
5288
  // src/prevent-link-in-link-commands.ts
5331
- var import_editor_elements16 = require("@elementor/editor-elements");
5289
+ var import_editor_elements15 = require("@elementor/editor-elements");
5332
5290
  var import_editor_notifications3 = require("@elementor/editor-notifications");
5333
5291
  var import_editor_v1_adapters21 = require("@elementor/editor-v1-adapters");
5334
5292
  var import_i18n4 = require("@wordpress/i18n");
@@ -5399,25 +5357,25 @@ function shouldBlock(sourceElements, targetElements) {
5399
5357
  return false;
5400
5358
  }
5401
5359
  const isSourceContainsAnAnchor = sourceElements.some((src) => {
5402
- return src?.id ? (0, import_editor_elements16.isElementAnchored)(src.id) || !!(0, import_editor_elements16.getAnchoredDescendantId)(src.id) : false;
5360
+ return src?.id ? (0, import_editor_elements15.isElementAnchored)(src.id) || !!(0, import_editor_elements15.getAnchoredDescendantId)(src.id) : false;
5403
5361
  });
5404
5362
  if (!isSourceContainsAnAnchor) {
5405
5363
  return false;
5406
5364
  }
5407
5365
  const isTargetContainsAnAnchor = targetElements.some((target) => {
5408
- return target?.id ? (0, import_editor_elements16.isElementAnchored)(target.id) || !!(0, import_editor_elements16.getAnchoredAncestorId)(target.id) : false;
5366
+ return target?.id ? (0, import_editor_elements15.isElementAnchored)(target.id) || !!(0, import_editor_elements15.getAnchoredAncestorId)(target.id) : false;
5409
5367
  });
5410
5368
  return isTargetContainsAnAnchor;
5411
5369
  }
5412
5370
 
5413
5371
  // src/style-commands/paste-style.ts
5414
- var import_editor_elements19 = require("@elementor/editor-elements");
5415
- var import_editor_props11 = require("@elementor/editor-props");
5372
+ var import_editor_elements18 = require("@elementor/editor-elements");
5373
+ var import_editor_props10 = require("@elementor/editor-props");
5416
5374
  var import_editor_v1_adapters23 = require("@elementor/editor-v1-adapters");
5417
5375
 
5418
5376
  // src/utils/command-utils.ts
5419
- var import_editor_elements17 = require("@elementor/editor-elements");
5420
- var import_editor_props10 = require("@elementor/editor-props");
5377
+ var import_editor_elements16 = require("@elementor/editor-elements");
5378
+ var import_editor_props9 = require("@elementor/editor-props");
5421
5379
  var import_i18n5 = require("@wordpress/i18n");
5422
5380
  function hasAtomicWidgets(args) {
5423
5381
  const { containers = [args.container] } = args;
@@ -5435,13 +5393,13 @@ function getClassesProp(container) {
5435
5393
  return null;
5436
5394
  }
5437
5395
  const [propKey] = Object.entries(propsSchema).find(
5438
- ([, propType]) => propType.kind === "plain" && propType.key === import_editor_props10.CLASSES_PROP_KEY
5396
+ ([, propType]) => propType.kind === "plain" && propType.key === import_editor_props9.CLASSES_PROP_KEY
5439
5397
  ) ?? [];
5440
5398
  return propKey ?? null;
5441
5399
  }
5442
5400
  function getContainerSchema(container) {
5443
5401
  const type = container?.model.get("widgetType") || container?.model.get("elType");
5444
- const widgetsCache = (0, import_editor_elements17.getWidgetsCache)();
5402
+ const widgetsCache = (0, import_editor_elements16.getWidgetsCache)();
5445
5403
  const elementType = widgetsCache?.[type];
5446
5404
  return elementType?.atomic_props_schema ?? null;
5447
5405
  }
@@ -5454,11 +5412,11 @@ function getClipboardElements(storageKey = "clipboard") {
5454
5412
  }
5455
5413
  }
5456
5414
  function getTitleForContainers(containers) {
5457
- return containers.length > 1 ? (0, import_i18n5.__)("Elements", "elementor") : (0, import_editor_elements17.getElementLabel)(containers[0].id);
5415
+ return containers.length > 1 ? (0, import_i18n5.__)("Elements", "elementor") : (0, import_editor_elements16.getElementLabel)(containers[0].id);
5458
5416
  }
5459
5417
 
5460
5418
  // src/style-commands/undoable-actions/paste-element-style.ts
5461
- var import_editor_elements18 = require("@elementor/editor-elements");
5419
+ var import_editor_elements17 = require("@elementor/editor-elements");
5462
5420
  var import_editor_styles_repository4 = require("@elementor/editor-styles-repository");
5463
5421
  var import_editor_v1_adapters22 = require("@elementor/editor-v1-adapters");
5464
5422
  var import_i18n6 = require("@wordpress/i18n");
@@ -5471,7 +5429,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters22.undoable)(
5471
5429
  if (!classesProp) {
5472
5430
  return null;
5473
5431
  }
5474
- const originalStyles = (0, import_editor_elements18.getElementStyles)(container.id);
5432
+ const originalStyles = (0, import_editor_elements17.getElementStyles)(container.id);
5475
5433
  const [styleId, styleDef] = Object.entries(originalStyles ?? {})[0] ?? [];
5476
5434
  const originalStyle = Object.keys(styleDef ?? {}).length ? styleDef : null;
5477
5435
  const revertData = {
@@ -5480,7 +5438,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters22.undoable)(
5480
5438
  };
5481
5439
  if (styleId) {
5482
5440
  newStyle.variants.forEach(({ meta, props, custom_css: customCss }) => {
5483
- (0, import_editor_elements18.updateElementStyle)({
5441
+ (0, import_editor_elements17.updateElementStyle)({
5484
5442
  elementId,
5485
5443
  styleId,
5486
5444
  meta,
@@ -5491,7 +5449,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters22.undoable)(
5491
5449
  } else {
5492
5450
  const [firstVariant] = newStyle.variants;
5493
5451
  const additionalVariants = newStyle.variants.slice(1);
5494
- revertData.styleId = (0, import_editor_elements18.createElementStyle)({
5452
+ revertData.styleId = (0, import_editor_elements17.createElementStyle)({
5495
5453
  elementId,
5496
5454
  classesProp,
5497
5455
  label: import_editor_styles_repository4.ELEMENTS_STYLES_RESERVED_LABEL,
@@ -5509,7 +5467,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters22.undoable)(
5509
5467
  return;
5510
5468
  }
5511
5469
  if (!revertData.originalStyle) {
5512
- (0, import_editor_elements18.deleteElementStyle)(container.id, revertData.styleId);
5470
+ (0, import_editor_elements17.deleteElementStyle)(container.id, revertData.styleId);
5513
5471
  return;
5514
5472
  }
5515
5473
  const classesProp = getClassesProp(container);
@@ -5518,7 +5476,7 @@ var undoablePasteElementStyle = () => (0, import_editor_v1_adapters22.undoable)(
5518
5476
  }
5519
5477
  const [firstVariant] = revertData.originalStyle.variants;
5520
5478
  const additionalVariants = revertData.originalStyle.variants.slice(1);
5521
- (0, import_editor_elements18.createElementStyle)({
5479
+ (0, import_editor_elements17.createElementStyle)({
5522
5480
  elementId: container.id,
5523
5481
  classesProp,
5524
5482
  label: import_editor_styles_repository4.ELEMENTS_STYLES_RESERVED_LABEL,
@@ -5555,7 +5513,7 @@ function pasteStyles(args, pasteLocalStyle) {
5555
5513
  }
5556
5514
  const clipboardElements = getClipboardElements(storageKey);
5557
5515
  const [clipboardElement] = clipboardElements ?? [];
5558
- const clipboardContainer = (0, import_editor_elements19.getContainer)(clipboardElement.id);
5516
+ const clipboardContainer = (0, import_editor_elements18.getContainer)(clipboardElement.id);
5559
5517
  if (!clipboardElement || !clipboardContainer || !isAtomicWidget(clipboardContainer)) {
5560
5518
  return;
5561
5519
  }
@@ -5574,7 +5532,7 @@ function getClassesWithoutLocalStyle(clipboardContainer, style) {
5574
5532
  if (!classesProp) {
5575
5533
  return [];
5576
5534
  }
5577
- const classesSetting = (0, import_editor_elements19.getElementSetting)(clipboardContainer.id, classesProp);
5535
+ const classesSetting = (0, import_editor_elements18.getElementSetting)(clipboardContainer.id, classesProp);
5578
5536
  return classesSetting?.value.filter((styleId) => styleId !== style?.id) ?? [];
5579
5537
  }
5580
5538
  function pasteClasses(containers, classes) {
@@ -5583,10 +5541,10 @@ function pasteClasses(containers, classes) {
5583
5541
  if (!classesProp) {
5584
5542
  return;
5585
5543
  }
5586
- const classesSetting = (0, import_editor_elements19.getElementSetting)(container.id, classesProp);
5587
- const currentClasses = import_editor_props11.classesPropTypeUtil.extract(classesSetting) ?? [];
5588
- const newClasses = import_editor_props11.classesPropTypeUtil.create(Array.from(/* @__PURE__ */ new Set([...classes, ...currentClasses])));
5589
- (0, import_editor_elements19.updateElementSettings)({
5544
+ const classesSetting = (0, import_editor_elements18.getElementSetting)(container.id, classesProp);
5545
+ const currentClasses = import_editor_props10.classesPropTypeUtil.extract(classesSetting) ?? [];
5546
+ const newClasses = import_editor_props10.classesPropTypeUtil.create(Array.from(/* @__PURE__ */ new Set([...classes, ...currentClasses])));
5547
+ (0, import_editor_elements18.updateElementSettings)({
5590
5548
  id: container.id,
5591
5549
  props: { [classesProp]: newClasses }
5592
5550
  });
@@ -5597,7 +5555,7 @@ function pasteClasses(containers, classes) {
5597
5555
  var import_editor_v1_adapters25 = require("@elementor/editor-v1-adapters");
5598
5556
 
5599
5557
  // src/style-commands/undoable-actions/reset-element-style.ts
5600
- var import_editor_elements20 = require("@elementor/editor-elements");
5558
+ var import_editor_elements19 = require("@elementor/editor-elements");
5601
5559
  var import_editor_styles_repository5 = require("@elementor/editor-styles-repository");
5602
5560
  var import_editor_v1_adapters24 = require("@elementor/editor-v1-adapters");
5603
5561
  var import_i18n7 = require("@wordpress/i18n");
@@ -5606,9 +5564,9 @@ var undoableResetElementStyle = () => (0, import_editor_v1_adapters24.undoable)(
5606
5564
  do: ({ containers }) => {
5607
5565
  return containers.map((container) => {
5608
5566
  const elementId = container.model.get("id");
5609
- const containerStyles = (0, import_editor_elements20.getElementStyles)(elementId);
5567
+ const containerStyles = (0, import_editor_elements19.getElementStyles)(elementId);
5610
5568
  Object.keys(containerStyles ?? {}).forEach(
5611
- (styleId) => (0, import_editor_elements20.deleteElementStyle)(elementId, styleId)
5569
+ (styleId) => (0, import_editor_elements19.deleteElementStyle)(elementId, styleId)
5612
5570
  );
5613
5571
  return containerStyles;
5614
5572
  });
@@ -5624,7 +5582,7 @@ var undoableResetElementStyle = () => (0, import_editor_v1_adapters24.undoable)(
5624
5582
  Object.entries(containerStyles ?? {}).forEach(([styleId, style]) => {
5625
5583
  const [firstVariant] = style.variants;
5626
5584
  const additionalVariants = style.variants.slice(1);
5627
- (0, import_editor_elements20.createElementStyle)({
5585
+ (0, import_editor_elements19.createElementStyle)({
5628
5586
  elementId,
5629
5587
  classesProp,
5630
5588
  styleId,
@@ -5824,10 +5782,10 @@ function useEscapeOnCanvas(canvasDocument, onEscape) {
5824
5782
  }
5825
5783
 
5826
5784
  // src/utils/after-render.ts
5827
- var import_editor_elements21 = require("@elementor/editor-elements");
5785
+ var import_editor_elements20 = require("@elementor/editor-elements");
5828
5786
  function doAfterRender(elementIds, callback) {
5829
5787
  const pending = elementIds.map((elementId) => {
5830
- const view = (0, import_editor_elements21.getContainer)(elementId)?.view;
5788
+ const view = (0, import_editor_elements20.getContainer)(elementId)?.view;
5831
5789
  if (!view || !hasDoAfterRender(view)) {
5832
5790
  return void 0;
5833
5791
  }
package/dist/index.mjs CHANGED
@@ -47,13 +47,13 @@ var initWidgetsSchemaResource = (reg) => {
47
47
  if (!widgetType) {
48
48
  throw new Error("No widget type provided.");
49
49
  }
50
- const schema2 = await fetchWidgetSchema(widgetType);
50
+ const schema = await fetchWidgetSchema(widgetType);
51
51
  return {
52
52
  contents: [
53
53
  {
54
54
  uri: uri.toString(),
55
55
  mimeType: "application/json",
56
- text: JSON.stringify(schema2)
56
+ text: JSON.stringify(schema)
57
57
  }
58
58
  ]
59
59
  };
@@ -1260,10 +1260,10 @@ var getMultiPropsValue = (multiProps) => {
1260
1260
  // src/renderers/create-props-resolver.ts
1261
1261
  var TRANSFORM_DEPTH_LIMIT = 3;
1262
1262
  function createPropsResolver({ transformers, schema: initialSchema, onPropResolve }) {
1263
- async function resolve({ props, schema: schema2, signal, renderContext }) {
1264
- schema2 = schema2 ?? initialSchema;
1263
+ async function resolve({ props, schema, signal, renderContext }) {
1264
+ schema = schema ?? initialSchema;
1265
1265
  const promises = Promise.all(
1266
- Object.entries(schema2).map(async ([key, type]) => {
1266
+ Object.entries(schema).map(async ([key, type]) => {
1267
1267
  const value = props[key] ?? type.default;
1268
1268
  const transformed = await transform({ value, key, type, signal, renderContext });
1269
1269
  onPropResolve?.({ key, value: transformed, propValue: value, propType: type });
@@ -3922,7 +3922,7 @@ function initTabsModelExtensions() {
3922
3922
  }
3923
3923
 
3924
3924
  // src/mcp/canvas-mcp.ts
3925
- import { Schema as Schema4 } from "@elementor/editor-props";
3925
+ import { Schema as Schema3 } from "@elementor/editor-props";
3926
3926
 
3927
3927
  // src/mcp/resources/available-widgets-resource.ts
3928
3928
  import { httpService as httpService3 } from "@elementor/http-client";
@@ -4448,8 +4448,25 @@ function getElementDisplayName(container) {
4448
4448
  // src/mcp/tools/build-composition/tool.ts
4449
4449
  import { getCurrentDocument, reloadCurrentDocument } from "@elementor/editor-documents";
4450
4450
  import { getContainer as getContainer4, selectElement } from "@elementor/editor-elements";
4451
- import { AxiosError, httpService as httpService6 } from "@elementor/http-client";
4451
+ import { httpService as httpService6 } from "@elementor/http-client";
4452
4452
  import { z } from "@elementor/schema";
4453
+
4454
+ // src/mcp/utils/get-mcp-error-message.ts
4455
+ import { AxiosError } from "@elementor/http-client";
4456
+ function getMcpErrorMessage(error, toolName) {
4457
+ if (error instanceof AxiosError) {
4458
+ const data = error.response?.data;
4459
+ if (data?.message) {
4460
+ return data.code ? `${data.code}: ${data.message}` : data.message;
4461
+ }
4462
+ }
4463
+ if (error instanceof Error) {
4464
+ return error.message;
4465
+ }
4466
+ return `${toolName} failed with an unknown error.`;
4467
+ }
4468
+
4469
+ // src/mcp/tools/build-composition/tool.ts
4453
4470
  var MCP_PROXY_URL5 = "elementor/v1/mcp-proxy";
4454
4471
  var initBuildCompositionTool = (reg) => {
4455
4472
  const { addTool } = reg;
@@ -4471,6 +4488,9 @@ var initBuildCompositionTool = (reg) => {
4471
4488
  "Map configuration-id \u2192 raw CSS declarations (property \u2192 value strings; no selectors). Server converts to native styles; unconvertible declarations become the element custom CSS."
4472
4489
  ),
4473
4490
  parentId: z.string().optional().describe("ID of the parent container. Omit or pass 'document' to insert at document root."),
4491
+ mode: z.enum(["append", "replace_children"]).optional().describe(
4492
+ "'append' (default) inserts under parentId; 'replace_children' removes existing direct children of parentId first, then inserts."
4493
+ ),
4474
4494
  dryRun: z.boolean().optional().describe("If true, validate and return the resolved tree without persisting.")
4475
4495
  },
4476
4496
  outputSchema: {
@@ -4479,9 +4499,10 @@ var initBuildCompositionTool = (reg) => {
4479
4499
  version: z.string(),
4480
4500
  resolvedXml: z.string(),
4481
4501
  llmInstructions: z.string(),
4482
- warnings: z.array(z.string()).optional()
4502
+ warnings: z.array(z.string()).optional(),
4503
+ removedElementIds: z.array(z.string()).optional()
4483
4504
  },
4484
- handler: async ({ xmlStructure, elementConfig, style, parentId, dryRun }) => {
4505
+ handler: async ({ xmlStructure, elementConfig, style, parentId, mode, dryRun }) => {
4485
4506
  const document2 = getCurrentDocument();
4486
4507
  if (!document2?.id) {
4487
4508
  throw new Error("No active document found.");
@@ -4495,6 +4516,7 @@ var initBuildCompositionTool = (reg) => {
4495
4516
  element_config: elementConfig ?? {},
4496
4517
  style: style ?? {},
4497
4518
  parent_id: parentId ?? "document",
4519
+ mode: mode ?? "append",
4498
4520
  dry_run: dryRun ?? false
4499
4521
  }
4500
4522
  });
@@ -4515,26 +4537,15 @@ var initBuildCompositionTool = (reg) => {
4515
4537
  version: data.data.version,
4516
4538
  resolvedXml: data.data.resolved_xml,
4517
4539
  llmInstructions: data.data.llm_instructions,
4518
- warnings: data.data.warnings
4540
+ warnings: data.data.warnings,
4541
+ removedElementIds: data.data.removed_element_ids
4519
4542
  };
4520
4543
  } catch (error) {
4521
- throw new Error(getErrorMessage(error));
4544
+ throw new Error(getMcpErrorMessage(error, "build-composition"));
4522
4545
  }
4523
4546
  }
4524
4547
  });
4525
4548
  };
4526
- function getErrorMessage(error) {
4527
- if (error instanceof AxiosError) {
4528
- const data = error.response?.data;
4529
- if (data?.message) {
4530
- return data.code ? `${data.code}: ${data.message}` : data.message;
4531
- }
4532
- }
4533
- if (error instanceof Error) {
4534
- return error.message;
4535
- }
4536
- return "build-composition failed with an unknown error.";
4537
- }
4538
4549
 
4539
4550
  // src/mcp/tools/configure-element/tool.ts
4540
4551
  import { getContainer as getContainer5, getWidgetsCache as getWidgetsCache6 } from "@elementor/editor-elements";
@@ -4569,9 +4580,9 @@ var readStoredCustomCssText = (raw) => {
4569
4580
 
4570
4581
  // src/mcp/utils/resolve-canonical-prop-name.ts
4571
4582
  import { getWidgetsCache as getWidgetsCache4 } from "@elementor/editor-elements";
4572
- function buildAliasToCanonicalMap(schema2) {
4583
+ function buildAliasToCanonicalMap(schema) {
4573
4584
  const aliasToCanonical = {};
4574
- for (const [canonical, propType] of Object.entries(schema2)) {
4585
+ for (const [canonical, propType] of Object.entries(schema)) {
4575
4586
  const aliases = propType.meta?.aliases;
4576
4587
  if (!Array.isArray(aliases)) {
4577
4588
  continue;
@@ -4585,26 +4596,26 @@ function buildAliasToCanonicalMap(schema2) {
4585
4596
  return aliasToCanonical;
4586
4597
  }
4587
4598
  function resolveCanonicalPropName(elementType, propertyName) {
4588
- const schema2 = getWidgetsCache4()?.[elementType]?.atomic_props_schema;
4589
- if (!schema2 || schema2[propertyName]) {
4599
+ const schema = getWidgetsCache4()?.[elementType]?.atomic_props_schema;
4600
+ if (!schema || schema[propertyName]) {
4590
4601
  return propertyName;
4591
4602
  }
4592
- return buildAliasToCanonicalMap(schema2)[propertyName] ?? propertyName;
4603
+ return buildAliasToCanonicalMap(schema)[propertyName] ?? propertyName;
4593
4604
  }
4594
4605
  function resolveCanonicalPropKeys(elementType, props) {
4595
- const schema2 = getWidgetsCache4()?.[elementType]?.atomic_props_schema;
4596
- if (!schema2) {
4606
+ const schema = getWidgetsCache4()?.[elementType]?.atomic_props_schema;
4607
+ if (!schema) {
4597
4608
  return { ...props };
4598
4609
  }
4599
- const aliasToCanonical = buildAliasToCanonicalMap(schema2);
4610
+ const aliasToCanonical = buildAliasToCanonicalMap(schema);
4600
4611
  const resolved = {};
4601
4612
  for (const [key, value] of Object.entries(props)) {
4602
- if (schema2[key]) {
4613
+ if (schema[key]) {
4603
4614
  resolved[key] = value;
4604
4615
  }
4605
4616
  }
4606
4617
  for (const [key, value] of Object.entries(props)) {
4607
- if (schema2[key]) {
4618
+ if (schema[key]) {
4608
4619
  continue;
4609
4620
  }
4610
4621
  const canonical = aliasToCanonical[key];
@@ -4652,9 +4663,9 @@ var dynamicTagLLMResolver = (value) => {
4652
4663
  }
4653
4664
  };
4654
4665
  };
4655
- var buildStrictSettings = (schema2, provided) => {
4666
+ var buildStrictSettings = (schema, provided) => {
4656
4667
  const settings = {};
4657
- for (const [key, propType] of Object.entries(schema2)) {
4668
+ for (const [key, propType] of Object.entries(schema)) {
4658
4669
  if (OMITTED_DYNAMIC_SETTING_KEYS.includes(key)) {
4659
4670
  continue;
4660
4671
  }
@@ -5081,102 +5092,49 @@ Provide styling as raw CSS via the "style" parameter (a flat map of CSS property
5081
5092
  }`;
5082
5093
  }
5083
5094
 
5084
- // src/mcp/tools/get-element-config/tool.ts
5085
- import { getContainer as getContainer6, getElementStyles as getElementStyles2, getWidgetsCache as getWidgetsCache7 } from "@elementor/editor-elements";
5086
- import { Schema as Schema3 } from "@elementor/editor-props";
5095
+ // src/mcp/tools/get-page-structure/tool.ts
5096
+ import { getCurrentDocument as getCurrentDocument2 } from "@elementor/editor-documents";
5097
+ import { httpService as httpService7 } from "@elementor/http-client";
5087
5098
  import { z as z3 } from "@elementor/schema";
5088
- var schema = {
5089
- elementId: z3.string()
5090
- };
5091
- var outputSchema2 = {
5092
- properties: z3.record(z3.string(), z3.any()).describe("A record mapping PropTypes to their corresponding PropValues"),
5093
- style: z3.record(z3.string(), z3.any()).describe("A record mapping StyleSchema properties to their corresponding PropValues"),
5094
- childElements: z3.array(
5095
- z3.object({
5096
- id: z3.string(),
5097
- elementType: z3.string(),
5098
- childElements: z3.array(z3.any()).describe("An array of child element IDs, when applicable, same structure recursively")
5099
- })
5100
- ).describe("An array of child element IDs, when applicable, with recursive structure")
5101
- };
5102
- var structuredElements = (element) => {
5103
- const children = element.children || [];
5104
- return children.map((child) => {
5105
- return {
5106
- id: child.id,
5107
- elementType: child.model.get("elType") || child.model.get("widgetType") || "unknown",
5108
- childElements: structuredElements(child)
5109
- };
5110
- });
5111
- };
5112
- var initGetElementConfigTool = (reg) => {
5099
+ var MCP_PROXY_URL6 = "elementor/v1/mcp-proxy";
5100
+ var initGetPageStructureTool = (reg) => {
5113
5101
  const { addTool } = reg;
5114
5102
  addTool({
5115
- name: "get-element-configuration-values",
5116
- description: "Retrieve the element's configuration PropValues for a specific element by unique ID.",
5117
- schema,
5118
- outputSchema: outputSchema2,
5119
- handler: async ({ elementId }) => {
5120
- const element = getContainer6(elementId);
5121
- if (!element) {
5122
- throw new Error(`Element with ID ${elementId} not found.`);
5123
- }
5124
- const elementType = element.model.get("widgetType") || element.model.get("elType") || "";
5125
- const widgetData = getWidgetsCache7()?.[elementType];
5126
- if (!widgetData) {
5127
- throw new Error(
5128
- `Unknown element type: ${elementType}. Check the available-widgets resource for valid types.`
5129
- );
5130
- }
5131
- if (!widgetData.atomic_props_schema) {
5132
- throw new Error(
5133
- `This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${elementType}`
5134
- );
5135
- }
5136
- const elementRawSettings = element.settings;
5137
- const propSchema = getWidgetsCache7()?.[elementType]?.atomic_props_schema;
5138
- if (!elementRawSettings || !propSchema) {
5139
- throw new Error(`No settings or prop schema found for element ID: ${elementId}`);
5103
+ name: "get-page-structure",
5104
+ description: "Returns the Elementor element tree (widgets, containers, and nested content) for a post or page. If no postId is provided, uses the currently open document. Only works for posts saved with Elementor.",
5105
+ schema: {
5106
+ postId: z3.number().optional().describe(
5107
+ "WordPress post ID of the Elementor document. If omitted, uses the currently open document."
5108
+ )
5109
+ },
5110
+ outputSchema: {
5111
+ elements: z3.array(z3.any()).describe("Root-level Elementor elements for the document.")
5112
+ },
5113
+ handler: async ({ postId }) => {
5114
+ const resolvedPostId = postId ?? getCurrentDocument2()?.id;
5115
+ if (!resolvedPostId) {
5116
+ throw new Error("No post ID provided and no active document found.");
5140
5117
  }
5141
- const propValues = {};
5142
- const stylePropValues = {};
5143
- Schema3.configurableKeys(propSchema).forEach((key) => {
5144
- propValues[key] = structuredClone(elementRawSettings.get(key));
5145
- });
5146
- const elementStyles = getElementStyles2(elementId) || {};
5147
- const localStyle = Object.values(elementStyles).find((style) => style.label === "local");
5148
- if (localStyle) {
5149
- const defaultVariant = localStyle.variants.find(
5150
- (variant) => variant.meta.breakpoint === "desktop" && !variant.meta.state
5151
- );
5152
- if (defaultVariant) {
5153
- const styleProps = defaultVariant.props || {};
5154
- Object.keys(styleProps).forEach((stylePropName) => {
5155
- if (typeof styleProps[stylePropName] !== "undefined") {
5156
- stylePropValues[stylePropName] = structuredClone(styleProps[stylePropName]);
5157
- }
5158
- });
5159
- if (defaultVariant.custom_css) {
5160
- stylePropValues.custom_css = atob(defaultVariant.custom_css.raw);
5118
+ try {
5119
+ const { data } = await httpService7().post(MCP_PROXY_URL6, {
5120
+ tool: "get-page-structure",
5121
+ input: {
5122
+ post_id: resolvedPostId
5161
5123
  }
5162
- }
5124
+ });
5125
+ return {
5126
+ elements: data.data.elements
5127
+ };
5128
+ } catch (error) {
5129
+ throw new Error(getMcpErrorMessage(error, "get-page-structure"));
5163
5130
  }
5164
- return {
5165
- properties: {
5166
- ...propValues
5167
- },
5168
- style: {
5169
- ...stylePropValues
5170
- },
5171
- childElements: structuredElements(element)
5172
- };
5173
5131
  }
5174
5132
  });
5175
5133
  };
5176
5134
 
5177
5135
  // src/mcp/canvas-mcp.ts
5178
5136
  var initCanvasMcp = (reg) => {
5179
- Schema4.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5137
+ Schema3.setDynamicTagNamesResolver(getDynamicTagNamesByCategories);
5180
5138
  initWidgetsSchemaResource(reg);
5181
5139
  initAvailableWidgetsResource(reg);
5182
5140
  initDocumentStructureResource(reg);
@@ -5185,9 +5143,9 @@ var initCanvasMcp = (reg) => {
5185
5143
  initEditorStateResource(reg);
5186
5144
  initGeneralContextResource(reg);
5187
5145
  initBestPracticesResource(reg);
5188
- initGetElementConfigTool(reg);
5189
5146
  initConfigureElementTool(reg);
5190
5147
  initBuildCompositionTool(reg);
5148
+ initGetPageStructureTool(reg);
5191
5149
  initBreakpointsResource(reg);
5192
5150
  };
5193
5151
 
@@ -5387,7 +5345,7 @@ function shouldBlock(sourceElements, targetElements) {
5387
5345
  }
5388
5346
 
5389
5347
  // src/style-commands/paste-style.ts
5390
- import { getContainer as getContainer7, getElementSetting, updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
5348
+ import { getContainer as getContainer6, getElementSetting, updateElementSettings as updateElementSettings2 } from "@elementor/editor-elements";
5391
5349
  import { classesPropTypeUtil } from "@elementor/editor-props";
5392
5350
  import {
5393
5351
  __privateListenTo as listenTo5,
@@ -5396,7 +5354,7 @@ import {
5396
5354
  } from "@elementor/editor-v1-adapters";
5397
5355
 
5398
5356
  // src/utils/command-utils.ts
5399
- import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache8 } from "@elementor/editor-elements";
5357
+ import { getElementLabel as getElementLabel2, getWidgetsCache as getWidgetsCache7 } from "@elementor/editor-elements";
5400
5358
  import { CLASSES_PROP_KEY } from "@elementor/editor-props";
5401
5359
  import { __ as __5 } from "@wordpress/i18n";
5402
5360
  function hasAtomicWidgets(args) {
@@ -5421,7 +5379,7 @@ function getClassesProp(container) {
5421
5379
  }
5422
5380
  function getContainerSchema(container) {
5423
5381
  const type = container?.model.get("widgetType") || container?.model.get("elType");
5424
- const widgetsCache = getWidgetsCache8();
5382
+ const widgetsCache = getWidgetsCache7();
5425
5383
  const elementType = widgetsCache?.[type];
5426
5384
  return elementType?.atomic_props_schema ?? null;
5427
5385
  }
@@ -5441,7 +5399,7 @@ function getTitleForContainers(containers) {
5441
5399
  import {
5442
5400
  createElementStyle as createElementStyle2,
5443
5401
  deleteElementStyle,
5444
- getElementStyles as getElementStyles3,
5402
+ getElementStyles as getElementStyles2,
5445
5403
  updateElementStyle as updateElementStyle2
5446
5404
  } from "@elementor/editor-elements";
5447
5405
  import { ELEMENTS_STYLES_RESERVED_LABEL } from "@elementor/editor-styles-repository";
@@ -5456,7 +5414,7 @@ var undoablePasteElementStyle = () => undoable2(
5456
5414
  if (!classesProp) {
5457
5415
  return null;
5458
5416
  }
5459
- const originalStyles = getElementStyles3(container.id);
5417
+ const originalStyles = getElementStyles2(container.id);
5460
5418
  const [styleId, styleDef] = Object.entries(originalStyles ?? {})[0] ?? [];
5461
5419
  const originalStyle = Object.keys(styleDef ?? {}).length ? styleDef : null;
5462
5420
  const revertData = {
@@ -5540,7 +5498,7 @@ function pasteStyles(args, pasteLocalStyle) {
5540
5498
  }
5541
5499
  const clipboardElements = getClipboardElements(storageKey);
5542
5500
  const [clipboardElement] = clipboardElements ?? [];
5543
- const clipboardContainer = getContainer7(clipboardElement.id);
5501
+ const clipboardContainer = getContainer6(clipboardElement.id);
5544
5502
  if (!clipboardElement || !clipboardContainer || !isAtomicWidget(clipboardContainer)) {
5545
5503
  return;
5546
5504
  }
@@ -5586,7 +5544,7 @@ import {
5586
5544
  } from "@elementor/editor-v1-adapters";
5587
5545
 
5588
5546
  // src/style-commands/undoable-actions/reset-element-style.ts
5589
- import { createElementStyle as createElementStyle3, deleteElementStyle as deleteElementStyle2, getElementStyles as getElementStyles4 } from "@elementor/editor-elements";
5547
+ import { createElementStyle as createElementStyle3, deleteElementStyle as deleteElementStyle2, getElementStyles as getElementStyles3 } from "@elementor/editor-elements";
5590
5548
  import { ELEMENTS_STYLES_RESERVED_LABEL as ELEMENTS_STYLES_RESERVED_LABEL2 } from "@elementor/editor-styles-repository";
5591
5549
  import { undoable as undoable3 } from "@elementor/editor-v1-adapters";
5592
5550
  import { __ as __7 } from "@wordpress/i18n";
@@ -5595,7 +5553,7 @@ var undoableResetElementStyle = () => undoable3(
5595
5553
  do: ({ containers }) => {
5596
5554
  return containers.map((container) => {
5597
5555
  const elementId = container.model.get("id");
5598
- const containerStyles = getElementStyles4(elementId);
5556
+ const containerStyles = getElementStyles3(elementId);
5599
5557
  Object.keys(containerStyles ?? {}).forEach(
5600
5558
  (styleId) => deleteElementStyle2(elementId, styleId)
5601
5559
  );
@@ -5817,10 +5775,10 @@ function useEscapeOnCanvas(canvasDocument, onEscape) {
5817
5775
  }
5818
5776
 
5819
5777
  // src/utils/after-render.ts
5820
- import { getContainer as getContainer8 } from "@elementor/editor-elements";
5778
+ import { getContainer as getContainer7 } from "@elementor/editor-elements";
5821
5779
  function doAfterRender(elementIds, callback) {
5822
5780
  const pending = elementIds.map((elementId) => {
5823
- const view = getContainer8(elementId)?.view;
5781
+ const view = getContainer7(elementId)?.view;
5824
5782
  if (!view || !hasDoAfterRender(view)) {
5825
5783
  return void 0;
5826
5784
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elementor/editor-canvas",
3
3
  "description": "Elementor Editor Canvas",
4
- "version": "4.3.0-1002",
4
+ "version": "4.3.0-1004",
5
5
  "private": false,
6
6
  "author": "Elementor Team",
7
7
  "homepage": "https://elementor.com/",
@@ -37,26 +37,26 @@
37
37
  "react-dom": "^18.3.1"
38
38
  },
39
39
  "dependencies": {
40
- "@elementor/editor": "4.3.0-1002",
41
- "@elementor/editor-controls": "4.3.0-1002",
42
- "@elementor/editor-documents": "4.3.0-1002",
43
- "@elementor/editor-elements": "4.3.0-1002",
44
- "@elementor/editor-interactions": "4.3.0-1002",
45
- "@elementor/editor-mcp": "4.3.0-1002",
46
- "@elementor/editor-notifications": "4.3.0-1002",
47
- "@elementor/editor-props": "4.3.0-1002",
48
- "@elementor/editor-responsive": "4.3.0-1002",
49
- "@elementor/editor-styles": "4.3.0-1002",
50
- "@elementor/editor-styles-repository": "4.3.0-1002",
51
- "@elementor/editor-ui": "4.3.0-1002",
52
- "@elementor/editor-v1-adapters": "4.3.0-1002",
53
- "@elementor/events": "4.3.0-1002",
54
- "@elementor/http-client": "4.3.0-1002",
55
- "@elementor/schema": "4.3.0-1002",
56
- "@elementor/twing": "4.3.0-1002",
40
+ "@elementor/editor": "4.3.0-1004",
41
+ "@elementor/editor-controls": "4.3.0-1004",
42
+ "@elementor/editor-documents": "4.3.0-1004",
43
+ "@elementor/editor-elements": "4.3.0-1004",
44
+ "@elementor/editor-interactions": "4.3.0-1004",
45
+ "@elementor/editor-mcp": "4.3.0-1004",
46
+ "@elementor/editor-notifications": "4.3.0-1004",
47
+ "@elementor/editor-props": "4.3.0-1004",
48
+ "@elementor/editor-responsive": "4.3.0-1004",
49
+ "@elementor/editor-styles": "4.3.0-1004",
50
+ "@elementor/editor-styles-repository": "4.3.0-1004",
51
+ "@elementor/editor-ui": "4.3.0-1004",
52
+ "@elementor/editor-v1-adapters": "4.3.0-1004",
53
+ "@elementor/events": "4.3.0-1004",
54
+ "@elementor/http-client": "4.3.0-1004",
55
+ "@elementor/schema": "4.3.0-1004",
56
+ "@elementor/twing": "4.3.0-1004",
57
57
  "@elementor/ui": "1.37.5",
58
- "@elementor/utils": "4.3.0-1002",
59
- "@elementor/wp-media": "4.3.0-1002",
58
+ "@elementor/utils": "4.3.0-1004",
59
+ "@elementor/wp-media": "4.3.0-1004",
60
60
  "@floating-ui/react": "^0.27.5",
61
61
  "@wordpress/i18n": "^5.13.0",
62
62
  "dompurify": "^3.2.6"
@@ -12,7 +12,7 @@ import { initSelectedElementResource } from './resources/selected-element-resour
12
12
  import { initWidgetsSchemaResource } from './resources/widgets-schema-resource';
13
13
  import { initBuildCompositionTool } from './tools/build-composition/tool';
14
14
  import { initConfigureElementTool } from './tools/configure-element/tool';
15
- import { initGetElementConfigTool } from './tools/get-element-config/tool';
15
+ import { initGetPageStructureTool } from './tools/get-page-structure/tool';
16
16
  import { getDynamicTagNamesByCategories } from './utils/resolve-dynamic-tag';
17
17
 
18
18
  export const initCanvasMcp = ( reg: MCPRegistryEntry ) => {
@@ -28,8 +28,8 @@ export const initCanvasMcp = ( reg: MCPRegistryEntry ) => {
28
28
  initEditorStateResource( reg );
29
29
  initGeneralContextResource( reg );
30
30
  initBestPracticesResource( reg );
31
- initGetElementConfigTool( reg );
32
31
  initConfigureElementTool( reg );
33
32
  initBuildCompositionTool( reg );
33
+ initGetPageStructureTool( reg );
34
34
  initBreakpointsResource( reg );
35
35
  };
@@ -1,9 +1,11 @@
1
1
  import { getCurrentDocument, reloadCurrentDocument } from '@elementor/editor-documents';
2
2
  import { getContainer, selectElement } from '@elementor/editor-elements';
3
3
  import { type MCPRegistryEntry } from '@elementor/editor-mcp';
4
- import { AxiosError, type HttpResponse, httpService } from '@elementor/http-client';
4
+ import { type HttpResponse, httpService } from '@elementor/http-client';
5
5
  import { z } from '@elementor/schema';
6
6
 
7
+ import { getMcpErrorMessage } from '../../utils/get-mcp-error-message';
8
+
7
9
  const MCP_PROXY_URL = 'elementor/v1/mcp-proxy';
8
10
 
9
11
  type BuildCompositionResponse = {
@@ -15,6 +17,7 @@ type BuildCompositionResponse = {
15
17
  resolved_xml: string;
16
18
  llm_instructions: string;
17
19
  warnings?: string[];
20
+ removed_element_ids?: string[];
18
21
  };
19
22
 
20
23
  export const initBuildCompositionTool = ( reg: MCPRegistryEntry ) => {
@@ -56,6 +59,12 @@ export const initBuildCompositionTool = ( reg: MCPRegistryEntry ) => {
56
59
  .string()
57
60
  .optional()
58
61
  .describe( "ID of the parent container. Omit or pass 'document' to insert at document root." ),
62
+ mode: z
63
+ .enum( [ 'append', 'replace_children' ] )
64
+ .optional()
65
+ .describe(
66
+ "'append' (default) inserts under parentId; 'replace_children' removes existing direct children of parentId first, then inserts."
67
+ ),
59
68
  dryRun: z
60
69
  .boolean()
61
70
  .optional()
@@ -68,8 +77,9 @@ export const initBuildCompositionTool = ( reg: MCPRegistryEntry ) => {
68
77
  resolvedXml: z.string(),
69
78
  llmInstructions: z.string(),
70
79
  warnings: z.array( z.string() ).optional(),
80
+ removedElementIds: z.array( z.string() ).optional(),
71
81
  },
72
- handler: async ( { xmlStructure, elementConfig, style, parentId, dryRun } ) => {
82
+ handler: async ( { xmlStructure, elementConfig, style, parentId, mode, dryRun } ) => {
73
83
  const document = getCurrentDocument();
74
84
 
75
85
  if ( ! document?.id ) {
@@ -85,6 +95,7 @@ export const initBuildCompositionTool = ( reg: MCPRegistryEntry ) => {
85
95
  element_config: elementConfig ?? {},
86
96
  style: style ?? {},
87
97
  parent_id: parentId ?? 'document',
98
+ mode: mode ?? 'append',
88
99
  dry_run: dryRun ?? false,
89
100
  },
90
101
  } );
@@ -109,25 +120,11 @@ export const initBuildCompositionTool = ( reg: MCPRegistryEntry ) => {
109
120
  resolvedXml: data.data.resolved_xml,
110
121
  llmInstructions: data.data.llm_instructions,
111
122
  warnings: data.data.warnings,
123
+ removedElementIds: data.data.removed_element_ids,
112
124
  };
113
125
  } catch ( error ) {
114
- throw new Error( getErrorMessage( error ) );
126
+ throw new Error( getMcpErrorMessage( error, 'build-composition' ) );
115
127
  }
116
128
  },
117
129
  } );
118
130
  };
119
-
120
- function getErrorMessage( error: unknown ): string {
121
- if ( error instanceof AxiosError ) {
122
- const data = error.response?.data as { message?: string; code?: string } | undefined;
123
- if ( data?.message ) {
124
- return data.code ? `${ data.code }: ${ data.message }` : data.message;
125
- }
126
- }
127
-
128
- if ( error instanceof Error ) {
129
- return error.message;
130
- }
131
-
132
- return 'build-composition failed with an unknown error.';
133
- }
@@ -0,0 +1,56 @@
1
+ import { getCurrentDocument } from '@elementor/editor-documents';
2
+ import { type MCPRegistryEntry } from '@elementor/editor-mcp';
3
+ import { type HttpResponse, httpService } from '@elementor/http-client';
4
+ import { z } from '@elementor/schema';
5
+
6
+ import { getMcpErrorMessage } from '../../utils/get-mcp-error-message';
7
+
8
+ const MCP_PROXY_URL = 'elementor/v1/mcp-proxy';
9
+
10
+ type GetPageStructureResponse = {
11
+ elements: Array< Record< string, unknown > >;
12
+ };
13
+
14
+ export const initGetPageStructureTool = ( reg: MCPRegistryEntry ) => {
15
+ const { addTool } = reg;
16
+
17
+ addTool( {
18
+ name: 'get-page-structure',
19
+ description:
20
+ 'Returns the Elementor element tree (widgets, containers, and nested content) for a post or page. ' +
21
+ 'If no postId is provided, uses the currently open document. Only works for posts saved with Elementor.',
22
+ schema: {
23
+ postId: z
24
+ .number()
25
+ .optional()
26
+ .describe(
27
+ 'WordPress post ID of the Elementor document. If omitted, uses the currently open document.'
28
+ ),
29
+ },
30
+ outputSchema: {
31
+ elements: z.array( z.any() ).describe( 'Root-level Elementor elements for the document.' ),
32
+ },
33
+ handler: async ( { postId } ) => {
34
+ const resolvedPostId = postId ?? getCurrentDocument()?.id;
35
+
36
+ if ( ! resolvedPostId ) {
37
+ throw new Error( 'No post ID provided and no active document found.' );
38
+ }
39
+
40
+ try {
41
+ const { data } = await httpService().post< HttpResponse< GetPageStructureResponse > >( MCP_PROXY_URL, {
42
+ tool: 'get-page-structure',
43
+ input: {
44
+ post_id: resolvedPostId,
45
+ },
46
+ } );
47
+
48
+ return {
49
+ elements: data.data.elements,
50
+ };
51
+ } catch ( error ) {
52
+ throw new Error( getMcpErrorMessage( error, 'get-page-structure' ) );
53
+ }
54
+ },
55
+ } );
56
+ };
@@ -0,0 +1,16 @@
1
+ import { AxiosError } from '@elementor/http-client';
2
+
3
+ export function getMcpErrorMessage( error: unknown, toolName: string ): string {
4
+ if ( error instanceof AxiosError ) {
5
+ const data = error.response?.data as { message?: string; code?: string } | undefined;
6
+ if ( data?.message ) {
7
+ return data.code ? `${ data.code }: ${ data.message }` : data.message;
8
+ }
9
+ }
10
+
11
+ if ( error instanceof Error ) {
12
+ return error.message;
13
+ }
14
+
15
+ return `${ toolName } failed with an unknown error.`;
16
+ }
@@ -1,114 +0,0 @@
1
- import { getContainer, getElementStyles, getWidgetsCache, type V1Element } from '@elementor/editor-elements';
2
- import { type MCPRegistryEntry } from '@elementor/editor-mcp';
3
- import { type PropValue, Schema } from '@elementor/editor-props';
4
- import { z } from '@elementor/schema';
5
-
6
- const schema = {
7
- elementId: z.string(),
8
- };
9
-
10
- const outputSchema = {
11
- properties: z
12
- .record( z.string(), z.any() )
13
- .describe( 'A record mapping PropTypes to their corresponding PropValues' ),
14
- style: z
15
- .record( z.string(), z.any() )
16
- .describe( 'A record mapping StyleSchema properties to their corresponding PropValues' ),
17
- childElements: z
18
- .array(
19
- z.object( {
20
- id: z.string(),
21
- elementType: z.string(),
22
- childElements: z
23
- .array( z.any() )
24
- .describe( 'An array of child element IDs, when applicable, same structure recursively' ),
25
- } )
26
- )
27
- .describe( 'An array of child element IDs, when applicable, with recursive structure' ),
28
- };
29
- type ElementStructure = {
30
- id: string;
31
- elementType: string;
32
- childElements: ElementStructure[];
33
- };
34
- const structuredElements = ( element: V1Element ): ElementStructure[] => {
35
- const children = element.children || [];
36
- return children.map( ( child ) => {
37
- return {
38
- id: child.id,
39
- elementType: child.model.get( 'elType' ) || child.model.get( 'widgetType' ) || 'unknown',
40
- childElements: structuredElements( child ),
41
- };
42
- } );
43
- };
44
-
45
- export const initGetElementConfigTool = ( reg: MCPRegistryEntry ) => {
46
- const { addTool } = reg;
47
-
48
- addTool( {
49
- name: 'get-element-configuration-values',
50
- description: "Retrieve the element's configuration PropValues for a specific element by unique ID.",
51
- schema,
52
- outputSchema,
53
- handler: async ( { elementId } ) => {
54
- const element = getContainer( elementId );
55
- if ( ! element ) {
56
- throw new Error( `Element with ID ${ elementId } not found.` );
57
- }
58
- const elementType = element.model.get( 'widgetType' ) || element.model.get( 'elType' ) || '';
59
- const widgetData = getWidgetsCache()?.[ elementType ];
60
- if ( ! widgetData ) {
61
- throw new Error(
62
- `Unknown element type: ${ elementType }. Check the available-widgets resource for valid types.`
63
- );
64
- }
65
- if ( ! widgetData.atomic_props_schema ) {
66
- throw new Error(
67
- `This tool does not support V3 elements. Please use the elementor-v3-mcp tools instead for element type: ${ elementType }`
68
- );
69
- }
70
- const elementRawSettings = element.settings;
71
- const propSchema = getWidgetsCache()?.[ elementType ]?.atomic_props_schema;
72
-
73
- if ( ! elementRawSettings || ! propSchema ) {
74
- throw new Error( `No settings or prop schema found for element ID: ${ elementId }` );
75
- }
76
-
77
- const propValues: Record< string, PropValue > = {};
78
- const stylePropValues: Record< string, PropValue > = {};
79
-
80
- Schema.configurableKeys( propSchema ).forEach( ( key ) => {
81
- propValues[ key ] = structuredClone( elementRawSettings.get( key ) );
82
- } );
83
- const elementStyles = getElementStyles( elementId ) || {};
84
- const localStyle = Object.values( elementStyles ).find( ( style ) => style.label === 'local' );
85
-
86
- if ( localStyle ) {
87
- const defaultVariant = localStyle.variants.find(
88
- ( variant ) => variant.meta.breakpoint === 'desktop' && ! variant.meta.state
89
- );
90
- if ( defaultVariant ) {
91
- const styleProps = defaultVariant.props || {};
92
- Object.keys( styleProps ).forEach( ( stylePropName ) => {
93
- if ( typeof styleProps[ stylePropName ] !== 'undefined' ) {
94
- stylePropValues[ stylePropName ] = structuredClone( styleProps[ stylePropName ] );
95
- }
96
- } );
97
- if ( defaultVariant.custom_css ) {
98
- stylePropValues.custom_css = atob( defaultVariant.custom_css.raw );
99
- }
100
- }
101
- }
102
-
103
- return {
104
- properties: {
105
- ...propValues,
106
- },
107
- style: {
108
- ...stylePropValues,
109
- },
110
- childElements: structuredElements( element ),
111
- };
112
- },
113
- } );
114
- };