Skip to main content
Glama
elementor-tools.ts29.2 kB
// Elementor MCP Tools import { ElementorService } from '../services/elementor/elementor-service.js'; import { logger } from '../utils/logger.js'; export function createElementorTools(elementorService: ElementorService) { const tools: any[] = []; // ========== BASIC ELEMENTOR OPERATIONS ========== tools.push({ name: 'get_elementor_data', description: 'Get complete Elementor data for a page', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' } }, required: ['post_id'] }, handler: async (args: any) => { const result = await elementorService.data.getElementorData(args.post_id); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } }); tools.push({ name: 'update_elementor_data', description: 'Update complete Elementor data for a page', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, elementor_data: { type: 'string', description: 'Elementor data as JSON string' } }, required: ['post_id', 'elementor_data'] }, handler: async (args: any) => { const data = JSON.parse(args.elementor_data); await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Elementor data updated successfully for post ${args.post_id}` }] }; } }); tools.push({ name: 'get_elementor_data_chunked', description: 'Get Elementor data in manageable chunks for large pages', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, chunk_size: { type: 'number', description: 'Number of elements per chunk (default: 50)', default: 50 } }, required: ['post_id'] }, handler: async (args: any) => { const result = await elementorService.data.getElementorDataChunked( args.post_id, args.chunk_size || 50 ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } }); tools.push({ name: 'backup_elementor_data', description: 'Create backup of Elementor data before making changes', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' } }, required: ['post_id'] }, handler: async (args: any) => { const result = await elementorService.data.backupElementorData(args.post_id); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } }); tools.push({ name: 'clear_elementor_cache', description: 'Clear Elementor cache for better performance', inputSchema: { type: 'object', properties: {} }, handler: async (args: any) => { await elementorService.data.clearElementorCache(); return { content: [{ type: 'text', text: 'Elementor cache cleared successfully' }] }; } }); tools.push({ name: 'get_page_structure', description: 'Get the hierarchical structure of a page', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, include_settings: { type: 'boolean', description: 'Include element settings (default: false)', default: false } }, required: ['post_id'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const structure = elementorService.manipulation.getPageStructure( data.elements, args.include_settings || false ); return { content: [{ type: 'text', text: JSON.stringify(structure, null, 2) }] }; } }); // ========== SECTION & CONTAINER CREATION ========== tools.push({ name: 'create_elementor_section', description: 'Create a new Elementor section with specified columns', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, columns: { type: 'number', description: 'Number of columns (default: 1)', default: 1 }, position: { type: 'number', description: 'Position to insert section (optional)' }, section_settings: { type: 'object', description: 'Section settings (background, layout, etc.)' } }, required: ['post_id'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const newSection = elementorService.builder.createSection( args.columns || 1, args.section_settings || {} ); if (args.position !== undefined) { data.elements.splice(args.position, 0, newSection); } else { data.elements.push(newSection); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Section created successfully with ID: ${newSection.id}` }] }; } }); tools.push({ name: 'create_elementor_container', description: 'Create a new Elementor container (Flexbox)', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, position: { type: 'number', description: 'Position to insert container (optional)' }, container_settings: { type: 'object', description: 'Container settings' } }, required: ['post_id'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const newContainer = elementorService.builder.createContainer( args.container_settings || {} ); if (args.position !== undefined) { data.elements.splice(args.position, 0, newContainer); } else { data.elements.push(newContainer); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Container created successfully with ID: ${newContainer.id}` }] }; } }); // ========== WIDGET MANAGEMENT ========== tools.push({ name: 'add_widget_to_section', description: 'Add a widget to an Elementor section or column', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, parent_id: { type: 'string', description: 'Section or column ID to add widget to' }, widget_type: { type: 'string', description: 'Widget type (heading, text-editor, button, image, etc.)' }, widget_settings: { type: 'object', description: 'Widget settings' }, position: { type: 'number', description: 'Position within parent (optional)' } }, required: ['post_id', 'parent_id', 'widget_type'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const widget = elementorService.builder.createWidget( args.widget_type, args.widget_settings || {} ); const { element: parent } = elementorService.manipulation.findElementById( data.elements, args.parent_id ); if (!parent || !parent.elements) { throw new Error(`Parent element ${args.parent_id} not found or cannot contain widgets`); } if (args.position !== undefined) { parent.elements.splice(args.position, 0, widget); } else { parent.elements.push(widget); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Widget ${args.widget_type} added successfully with ID: ${widget.id}` }] }; } }); tools.push({ name: 'clone_widget', description: 'Clone an existing widget', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, widget_id: { type: 'string', description: 'Widget ID to clone' }, target_parent_id: { type: 'string', description: 'Target parent ID (optional, uses same parent if not specified)' }, position: { type: 'number', description: 'Position in target parent (optional)' } }, required: ['post_id', 'widget_id'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const { element: widget, parent } = elementorService.manipulation.findElementById( data.elements, args.widget_id ); if (!widget) { throw new Error(`Widget ${args.widget_id} not found`); } const clonedWidget = elementorService.manipulation.cloneElement(widget); const targetParentId = args.target_parent_id || parent?.id; if (targetParentId) { const { element: targetParent } = elementorService.manipulation.findElementById( data.elements, targetParentId ); if (targetParent && targetParent.elements) { if (args.position !== undefined) { targetParent.elements.splice(args.position, 0, clonedWidget); } else { targetParent.elements.push(clonedWidget); } } } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Widget cloned successfully. New ID: ${clonedWidget.id}` }] }; } }); // ========== ELEMENT MANAGEMENT ========== tools.push({ name: 'update_element_settings', description: 'Update settings for any Elementor element', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, element_id: { type: 'string', description: 'Element ID' }, settings: { type: 'object', description: 'Settings to update' } }, required: ['post_id', 'element_id', 'settings'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const updated = elementorService.manipulation.updateElement( data.elements, args.element_id, args.settings ); if (!updated) { throw new Error(`Element ${args.element_id} not found`); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Element ${args.element_id} updated successfully` }] }; } }); tools.push({ name: 'delete_elementor_element', description: 'Delete an Elementor element (section, column, or widget)', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, element_id: { type: 'string', description: 'Element ID to delete' } }, required: ['post_id', 'element_id'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const deleted = elementorService.manipulation.deleteElement( data.elements, args.element_id ); if (!deleted) { throw new Error(`Element ${args.element_id} not found`); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Element ${args.element_id} deleted successfully` }] }; } }); tools.push({ name: 'move_element', description: 'Move an element to a new position', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, element_id: { type: 'string', description: 'Element ID to move' }, target_parent_id: { type: 'string', description: 'Target parent ID (null for root level)' }, position: { type: 'number', description: 'Position in target parent' } }, required: ['post_id', 'element_id', 'position'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const moved = elementorService.manipulation.moveElement( data.elements, args.element_id, args.target_parent_id || null, args.position ); if (!moved) { throw new Error(`Failed to move element ${args.element_id}`); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Element ${args.element_id} moved successfully` }] }; } }); tools.push({ name: 'reorder_elements', description: 'Change the order of elements within a parent', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, parent_id: { type: 'string', description: 'Parent element ID (null for root level)' }, new_order: { type: 'array', items: { type: 'string' }, description: 'Array of element IDs in new order' } }, required: ['post_id', 'new_order'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const reordered = elementorService.manipulation.reorderElements( data.elements, args.parent_id || null, args.new_order ); if (!reordered) { throw new Error('Failed to reorder elements'); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Elements reordered successfully` }] }; } }); // ========== TEMPLATE MANAGEMENT ========== tools.push({ name: 'get_elementor_templates', description: 'Get Elementor templates', inputSchema: { type: 'object', properties: { per_page: { type: 'number', description: 'Number of templates to retrieve (default: 10)', default: 10 }, type: { type: 'string', description: 'Template type (page, section, widget)' } } }, handler: async (args: any) => { const result = await elementorService.templates.getTemplates( args.per_page || 10, args.type ); return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }; } }); tools.push({ name: 'create_elementor_template', description: 'Create a new Elementor template', inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'Template title' }, type: { type: 'string', description: 'Template type (page, section, widget)' }, content: { type: 'string', description: 'Template content as JSON string' } }, required: ['title', 'type', 'content'] }, handler: async (args: any) => { const result = await elementorService.templates.createTemplate( args.title, args.type, args.content, {} ); return { content: [{ type: 'text', text: `Template created successfully with ID: ${result.id}` }] }; } }); tools.push({ name: 'apply_template_to_page', description: 'Apply an Elementor template to a page', inputSchema: { type: 'object', properties: { page_id: { type: 'number', description: 'Page ID to apply template to' }, template_id: { type: 'number', description: 'Template ID to apply' } }, required: ['page_id', 'template_id'] }, handler: async (args: any) => { await elementorService.templates.applyTemplateToPage( args.page_id, args.template_id ); return { content: [{ type: 'text', text: `Template ${args.template_id} applied successfully to page ${args.page_id}` }] }; } }); // ========== PRE-BUILT WIDGET CREATORS ========== tools.push({ name: 'add_heading_widget', description: 'Add a heading widget to a section or column', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, parent_id: { type: 'string', description: 'Parent element ID (section or column)' }, text: { type: 'string', description: 'Heading text' }, tag: { type: 'string', description: 'HTML tag (h1, h2, h3, h4, h5, h6)', default: 'h2' }, position: { type: 'number', description: 'Position within parent (optional)' } }, required: ['post_id', 'parent_id', 'text'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const widget = elementorService.builder.createHeadingWidget(args.text, args.tag || 'h2'); const { element: parent } = elementorService.manipulation.findElementById( data.elements, args.parent_id ); if (!parent || !parent.elements) { throw new Error(`Parent ${args.parent_id} not found`); } if (args.position !== undefined) { parent.elements.splice(args.position, 0, widget); } else { parent.elements.push(widget); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Heading widget added successfully with ID: ${widget.id}` }] }; } }); tools.push({ name: 'add_text_widget', description: 'Add a text editor widget', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, parent_id: { type: 'string', description: 'Parent element ID' }, content: { type: 'string', description: 'Text content (HTML supported)' }, position: { type: 'number', description: 'Position within parent (optional)' } }, required: ['post_id', 'parent_id', 'content'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const widget = elementorService.builder.createTextWidget(args.content); const { element: parent } = elementorService.manipulation.findElementById( data.elements, args.parent_id ); if (!parent || !parent.elements) { throw new Error(`Parent ${args.parent_id} not found`); } if (args.position !== undefined) { parent.elements.splice(args.position, 0, widget); } else { parent.elements.push(widget); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Text widget added successfully with ID: ${widget.id}` }] }; } }); tools.push({ name: 'add_button_widget', description: 'Add a button widget', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, parent_id: { type: 'string', description: 'Parent element ID' }, text: { type: 'string', description: 'Button text' }, link: { type: 'string', description: 'Button link URL', default: '#' }, position: { type: 'number', description: 'Position within parent (optional)' } }, required: ['post_id', 'parent_id', 'text'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const widget = elementorService.builder.createButtonWidget(args.text, args.link || '#'); const { element: parent } = elementorService.manipulation.findElementById( data.elements, args.parent_id ); if (!parent || !parent.elements) { throw new Error(`Parent ${args.parent_id} not found`); } if (args.position !== undefined) { parent.elements.splice(args.position, 0, widget); } else { parent.elements.push(widget); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Button widget added successfully with ID: ${widget.id}` }] }; } }); tools.push({ name: 'add_image_widget', description: 'Add an image widget', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, parent_id: { type: 'string', description: 'Parent element ID' }, image_url: { type: 'string', description: 'Image URL' }, image_id: { type: 'number', description: 'WordPress media ID (optional)' }, position: { type: 'number', description: 'Position within parent (optional)' } }, required: ['post_id', 'parent_id', 'image_url'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const widget = elementorService.builder.createImageWidget(args.image_url, args.image_id); const { element: parent } = elementorService.manipulation.findElementById( data.elements, args.parent_id ); if (!parent || !parent.elements) { throw new Error(`Parent ${args.parent_id} not found`); } if (args.position !== undefined) { parent.elements.splice(args.position, 0, widget); } else { parent.elements.push(widget); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Image widget added successfully with ID: ${widget.id}` }] }; } }); // ========== ELEMENT SEARCH ========== tools.push({ name: 'find_elements_by_type', description: 'Find all elements of a specific type in a page', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, element_type: { type: 'string', description: 'Element type (section, column, widget, container)' } }, required: ['post_id', 'element_type'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const elements = elementorService.manipulation.findElementsByType( data.elements, args.element_type ); return { content: [{ type: 'text', text: JSON.stringify(elements.map(el => ({ id: el.id, type: el.elType, widgetType: el.widgetType })), null, 2) }] }; } }); tools.push({ name: 'find_widgets_by_type', description: 'Find all widgets of a specific type', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, widget_type: { type: 'string', description: 'Widget type (heading, text-editor, button, etc.)' } }, required: ['post_id', 'widget_type'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const widgets = elementorService.manipulation.findWidgetsByType( data.elements, args.widget_type ); return { content: [{ type: 'text', text: JSON.stringify(widgets.map(w => ({ id: w.id, widgetType: w.widgetType, settings: w.settings })), null, 2) }] }; } }); // ========== COPY & DUPLICATE ========== tools.push({ name: 'copy_element_settings', description: 'Copy settings from one element to another', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, source_element_id: { type: 'string', description: 'Source element ID' }, target_element_id: { type: 'string', description: 'Target element ID' }, settings_keys: { type: 'array', items: { type: 'string' }, description: 'Specific settings to copy (optional, copies all if not specified)' } }, required: ['post_id', 'source_element_id', 'target_element_id'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const copied = elementorService.manipulation.copyElementSettings( data.elements, args.source_element_id, args.target_element_id, args.settings_keys ); if (!copied) { throw new Error('Failed to copy element settings'); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: 'Element settings copied successfully' }] }; } }); tools.push({ name: 'duplicate_section', description: 'Duplicate an existing section', inputSchema: { type: 'object', properties: { post_id: { type: 'number', description: 'Post/Page ID' }, section_id: { type: 'string', description: 'Section ID to duplicate' }, position: { type: 'number', description: 'Position to insert duplicated section (optional)' } }, required: ['post_id', 'section_id'] }, handler: async (args: any) => { const data = await elementorService.data.getElementorData(args.post_id); const { element: section } = elementorService.manipulation.findElementById( data.elements, args.section_id ); if (!section) { throw new Error(`Section ${args.section_id} not found`); } const duplicated = elementorService.manipulation.cloneElement(section) as any; if (args.position !== undefined) { data.elements.splice(args.position, 0, duplicated); } else { data.elements.push(duplicated); } await elementorService.data.updateElementorData(args.post_id, data); return { content: [{ type: 'text', text: `Section duplicated successfully. New ID: ${duplicated.id}` }] }; } }); return tools; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mbrown1837/Ultimate-Elementor-MCP'

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