fix(elementor): v1.9.0 sync — addContainer factory defaults, by-ref update/remove/move/duplicate, batchUpdate, reorderElements, addLine, addBlock tools
This commit is contained in:
@@ -28,51 +28,55 @@ class ElementorTools {
|
|||||||
$this->def('elementor_delete_page_content','Clear all Elementor content from a page, resetting it to blank.',['post_id'=>['type'=>'integer']],['post_id'],'write','deletePageContent'),
|
$this->def('elementor_delete_page_content','Clear all Elementor content from a page, resetting it to blank.',['post_id'=>['type'=>'integer']],['post_id'],'write','deletePageContent'),
|
||||||
$this->def('elementor_import_template','Import a JSON element structure into a page at an optional position.',['post_id'=>['type'=>'integer'],'template_json'=>['type'=>'array','items'=>['type'=>'object']],'position'=>['type'=>'integer']],['post_id','template_json'],'write','importTemplate'),
|
$this->def('elementor_import_template','Import a JSON element structure into a page at an optional position.',['post_id'=>['type'=>'integer'],'template_json'=>['type'=>'array','items'=>['type'=>'object']],'position'=>['type'=>'integer']],['post_id','template_json'],'write','importTemplate'),
|
||||||
$this->def('elementor_export_page','Export a page\'s full Elementor data as JSON.',['post_id'=>['type'=>'integer']],['post_id'],'read','exportPage'),
|
$this->def('elementor_export_page','Export a page\'s full Elementor data as JSON.',['post_id'=>['type'=>'integer']],['post_id'],'read','exportPage'),
|
||||||
$this->def('elementor_add_container','Add a flex or grid container to an Elementor page. Use parent_id for nesting, position for insertion index (-1 = append). Settings: flex_direction, flex_wrap, flex_justify_content (or justify_content), flex_align_items (or align_items), gap, padding, background_color, border_border, etc. Shorthand justify_content/align_items/align_content are auto-remapped to flex_justify_content/flex_align_items/flex_align_content.',['post_id'=>['type'=>'integer'],'parent_id'=>['type'=>'string'],'position'=>['type'=>'integer'],'settings'=>['type'=>'object']],['post_id'],'write','addContainer'),
|
$this->def('elementor_add_container','Add a flex or grid container. Omit parent_id for top-level. Settings: flex_direction, flex_wrap, flex_justify_content (or justify_content), flex_align_items (or align_items), gap, padding, background_color, border_border. Shorthand justify_content/align_items/align_content auto-remapped to flex_ prefixed keys.',['post_id'=>['type'=>'integer'],'parent_id'=>['type'=>'string'],'position'=>['type'=>'integer'],'settings'=>['type'=>'object']],['post_id'],'write','addContainer'),
|
||||||
$this->def('elementor_update_container','Update settings on an existing container element. Accepts flex shorthand justify_content/align_items/align_content and remaps to prefixed keys automatically.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string'],'settings'=>['type'=>'object']],['post_id','element_id'],'write','updateContainer'),
|
$this->def('elementor_update_container','Update settings on an existing container. Flex shorthand keys auto-normalised.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string'],'settings'=>['type'=>'object']],['post_id','element_id'],'write','updateContainer'),
|
||||||
$this->def('elementor_update_element','Update settings on any Elementor element by ID. For containers, flex shorthand keys are auto-normalised.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string'],'settings'=>['type'=>'object'],'merge'=>['type'=>'boolean','default'=>true]],['post_id','element_id','settings'],'write','updateElement'),
|
$this->def('elementor_update_element','Update settings on any element by ID. For containers, flex shorthand keys are auto-normalised.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string'],'settings'=>['type'=>'object'],'merge'=>['type'=>'boolean','default'=>true]],['post_id','element_id','settings'],'write','updateElement'),
|
||||||
$this->def('elementor_remove_element','Remove any element (container or widget) from a page by element ID.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string']],['post_id','element_id'],'write','removeElement'),
|
$this->def('elementor_remove_element','Remove any element (container or widget) from a page by element ID.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string']],['post_id','element_id'],'write','removeElement'),
|
||||||
$this->def('elementor_duplicate_element','Duplicate an element (and its children) within the same page. Clone is placed immediately after the original.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','element_id'],'write','duplicateElement'),
|
$this->def('elementor_duplicate_element','Duplicate an element (and its children). Clone is placed immediately after the original.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','element_id'],'write','duplicateElement'),
|
||||||
$this->def('elementor_move_element','Move an element to a different parent or position within the page.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string'],'target_parent_id'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','element_id'],'write','moveElement'),
|
$this->def('elementor_move_element','Move an element to a different parent or position.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string'],'target_parent_id'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','element_id'],'write','moveElement'),
|
||||||
$this->def('elementor_add_widget','Add any Elementor widget to a container. widget_type: heading, text-editor, image, button, video, icon, divider, spacer, google_maps, html, shortcode, accordion, tabs, toggle, icon-list, counter, progress, testimonial, alert, social-icons, star-rating, image-box, icon-box, basic-gallery, image-carousel, reviews, posts, nav-menu, search-form, woocommerce-product-images, etc.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'widget_type'=>['type'=>'string'],'settings'=>['type'=>'object'],'position'=>['type'=>'integer']],['post_id','container_id','widget_type'],'write','addWidget'),
|
$this->def('elementor_add_widget','Add any Elementor widget to a container. widget_type: heading, text-editor, image, button, video, icon, divider, spacer, google_maps, html, shortcode, accordion, tabs, toggle, icon-list, counter, progress, testimonial, alert, social-icons, star-rating, image-box, icon-box, basic-gallery, image-carousel, etc.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'widget_type'=>['type'=>'string'],'settings'=>['type'=>'object'],'position'=>['type'=>'integer']],['post_id','container_id','widget_type'],'write','addWidget'),
|
||||||
$this->def('elementor_update_widget','Update an existing widget\'s settings.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string'],'settings'=>['type'=>'object'],'merge'=>['type'=>'boolean','default'=>true]],['post_id','element_id','settings'],'write','updateWidget'),
|
$this->def('elementor_update_widget','Update an existing widget\'s settings.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string'],'settings'=>['type'=>'object'],'merge'=>['type'=>'boolean','default'=>true]],['post_id','element_id','settings'],'write','updateWidget'),
|
||||||
$this->def('elementor_add_heading','Add a heading widget. Accepts title or text param.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'title'=>['type'=>'string'],'text'=>['type'=>'string'],'tag'=>['type'=>'string','default'=>'h2'],'align'=>['type'=>'string'],'color'=>['type'=>'string'],'size'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','container_id'],'write','addHeading'),
|
$this->def('elementor_add_heading','Add a heading widget.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'title'=>['type'=>'string'],'text'=>['type'=>'string'],'tag'=>['type'=>'string','default'=>'h2'],'align'=>['type'=>'string'],'color'=>['type'=>'string'],'size'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','container_id'],'write','addHeading'),
|
||||||
$this->def('elementor_add_text','Add a text editor widget.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'content'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','container_id','content'],'write','addText'),
|
$this->def('elementor_add_text','Add a text editor widget.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'content'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','container_id','content'],'write','addText'),
|
||||||
$this->def('elementor_add_image','Add an image widget.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'url'=>['type'=>'string'],'alt'=>['type'=>'string'],'link'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','container_id','url'],'write','addImage'),
|
$this->def('elementor_add_image','Add an image widget.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'url'=>['type'=>'string'],'alt'=>['type'=>'string'],'link'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','container_id','url'],'write','addImage'),
|
||||||
$this->def('elementor_add_button','Add a button widget.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'text'=>['type'=>'string'],'url'=>['type'=>'string'],'type'=>['type'=>'string','default'=>'default'],'align'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','container_id','text','url'],'write','addButton'),
|
$this->def('elementor_add_button','Add a button widget.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'text'=>['type'=>'string'],'url'=>['type'=>'string'],'type'=>['type'=>'string','default'=>'default'],'align'=>['type'=>'string'],'position'=>['type'=>'integer']],['post_id','container_id','text','url'],'write','addButton'),
|
||||||
|
$this->def('elementor_add_line','Add a line/divider widget.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'settings'=>['type'=>'object'],'position'=>['type'=>'integer']],['post_id','container_id'],'write','addLine'),
|
||||||
|
$this->def('elementor_add_block','Add an HTML block widget.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'html'=>['type'=>'string'],'content'=>['type'=>'string'],'settings'=>['type'=>'object'],'position'=>['type'=>'integer']],['post_id','container_id'],'write','addBlock'),
|
||||||
|
$this->def('elementor_batch_update','Update multiple elements in a single save. Provide operations array with element_id and settings per item. Far more efficient than calling update_element multiple times.',['post_id'=>['type'=>'integer'],'operations'=>['type'=>'array','items'=>['type'=>'object']]],['post_id','operations'],'write','batchUpdate'),
|
||||||
|
$this->def('elementor_reorder_elements','Reorder direct children of a container. Provide container_id and element_ids in the desired order.',['post_id'=>['type'=>'integer'],'container_id'=>['type'=>'string'],'element_ids'=>['type'=>'array','items'=>['type'=>'string']]],['post_id','container_id','element_ids'],'write','reorderElements'),
|
||||||
$this->def('elementor_save_as_template','Save the current page content as a reusable Elementor template.',['post_id'=>['type'=>'integer'],'template_name'=>['type'=>'string'],'type'=>['type'=>'string','default'=>'page']],['post_id','template_name'],'write','saveAsTemplate'),
|
$this->def('elementor_save_as_template','Save the current page content as a reusable Elementor template.',['post_id'=>['type'=>'integer'],'template_name'=>['type'=>'string'],'type'=>['type'=>'string','default'=>'page']],['post_id','template_name'],'write','saveAsTemplate'),
|
||||||
$this->def('elementor_apply_template','Apply a saved template to a page (replaces existing content).',['post_id'=>['type'=>'integer'],'template_id'=>['type'=>'integer']],['post_id','template_id'],'write','applyTemplate'),
|
$this->def('elementor_apply_template','Apply a saved template to a page (replaces existing content).',['post_id'=>['type'=>'integer'],'template_id'=>['type'=>'integer']],['post_id','template_id'],'write','applyTemplate'),
|
||||||
$this->def('elementor_list_templates','List saved Elementor templates.',['type'=>['type'=>'string'],'per_page'=>['type'=>'integer','default'=>50]],[],'read','listTemplates'),
|
$this->def('elementor_list_templates','List saved Elementor templates.',['type'=>['type'=>'string'],'per_page'=>['type'=>'integer','default'=>50]],[],'read','listTemplates'),
|
||||||
$this->def('elementor_get_global_colors','Get Elementor global color palette.',[],[],'read','getGlobalColors'),
|
$this->def('elementor_get_global_colors','Get Elementor global color palette.',[],[],'read','getGlobalColors'),
|
||||||
$this->def('elementor_set_global_color','Add or update a color in the Elementor global palette.',['id'=>['type'=>'string'],'title'=>['type'=>'string'],'value'=>['type'=>'string']],['title','value'],'write','setGlobalColor'),
|
$this->def('elementor_set_global_color','Add or update a color in the Elementor global palette.',['id'=>['type'=>'string'],'title'=>['type'=>'string'],'value'=>['type'=>'string']],['title','value'],'write','setGlobalColor'),
|
||||||
$this->def('elementor_get_global_fonts','Get Elementor global font groups.',[],[],'read','getGlobalFonts'),
|
$this->def('elementor_get_global_fonts','Get Elementor global font groups.',[],[],'read','getGlobalFonts'),
|
||||||
$this->def('elementor_get_kit_settings','Get Elementor Site Kit settings (colors, fonts, button styles, form styles, etc.).',[],[],'read','getKitSettings'),
|
$this->def('elementor_get_kit_settings','Get Elementor Site Kit settings.',[],[],'read','getKitSettings'),
|
||||||
$this->def('elementor_update_kit_settings','Update Elementor Site Kit settings.',['settings'=>['type'=>'object']],['settings'],'write','updateKitSettings'),
|
$this->def('elementor_update_kit_settings','Update Elementor Site Kit settings.',['settings'=>['type'=>'object']],['settings'],'write','updateKitSettings'),
|
||||||
$this->def('elementor_list_widgets','List all registered Elementor widget types.',[],[],'read','listWidgets'),
|
$this->def('elementor_list_widgets','List all registered Elementor widget types.',[],[],'read','listWidgets'),
|
||||||
$this->def('elementor_get_element','Get a single element by ID from a page\'s element tree.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string']],['post_id','element_id'],'read','getElement'),
|
$this->def('elementor_get_element','Get a single element by ID from a page\'s element tree.',['post_id'=>['type'=>'integer'],'element_id'=>['type'=>'string']],['post_id','element_id'],'read','getElement'),
|
||||||
$this->def('elementor_clone_page','Duplicate an existing Elementor page as a new draft.',['post_id'=>['type'=>'integer'],'title'=>['type'=>'string']],['post_id'],'write','clonePage'),
|
$this->def('elementor_clone_page','Duplicate an existing Elementor page as a new draft.',['post_id'=>['type'=>'integer'],'title'=>['type'=>'string']],['post_id'],'write','clonePage'),
|
||||||
$this->def('elementor_replace_text','Replace all occurrences of a text string across all widgets in a page.',['post_id'=>['type'=>'integer'],'search'=>['type'=>'string'],'replace'=>['type'=>'string'],'case_sensitive'=>['type'=>'boolean','default'=>false]],['post_id','search','replace'],'write','replaceText'),
|
$this->def('elementor_replace_text','Replace all occurrences of a text string across all widgets in a page.',['post_id'=>['type'=>'integer'],'search'=>['type'=>'string'],'replace'=>['type'=>'string'],'case_sensitive'=>['type'=>'boolean','default'=>false]],['post_id','search','replace'],'write','replaceText'),
|
||||||
$this->def('elementor_get_page_outline','Get a simplified structural outline of an Elementor page (containers + widget types).',['post_id'=>['type'=>'integer']],['post_id'],'read','getPageOutline'),
|
$this->def('elementor_get_page_outline','Get a simplified structural outline of an Elementor page.',['post_id'=>['type'=>'integer']],['post_id'],'read','getPageOutline'),
|
||||||
$this->def('elementor_delete_items','Delete one or more elements (containers or widgets) from a page by element_id. Use element_ids array.',['post_id'=>['type'=>'integer'],'element_ids'=>['type'=>'array','items'=>['type'=>'string']],'element_id'=>['type'=>'string']],['post_id'],'write','deleteItems'),
|
$this->def('elementor_delete_items','Delete one or more elements from a page.',['post_id'=>['type'=>'integer'],'element_ids'=>['type'=>'array','items'=>['type'=>'string']],'element_id'=>['type'=>'string']],['post_id'],'write','deleteItems'),
|
||||||
$this->def('elementor_flush_css','Flush and regenerate all Elementor CSS files across the entire site. Call after bulk design changes.',[],[],'write','flushCss'),
|
$this->def('elementor_flush_css','Flush and regenerate all Elementor CSS files across the entire site.',[],[],'write','flushCss'),
|
||||||
$this->def('elementor_regenerate_css','Regenerate the Elementor CSS file for a single post/page.',['post_id'=>['type'=>'integer']],['post_id'],'write','regenerateCss'),
|
$this->def('elementor_regenerate_css','Regenerate the Elementor CSS file for a single post/page.',['post_id'=>['type'=>'integer']],['post_id'],'write','regenerateCss'),
|
||||||
$this->def('elementor_replace_urls','Find and replace a URL string across ALL Elementor data in the database. Essential for domain migrations and staging to production pushes.',['old_url'=>['type'=>'string'],'new_url'=>['type'=>'string']],['old_url','new_url'],'admin','replaceUrls'),
|
$this->def('elementor_replace_urls','Find and replace a URL string across ALL Elementor data in the database.',['old_url'=>['type'=>'string'],'new_url'=>['type'=>'string']],['old_url','new_url'],'admin','replaceUrls'),
|
||||||
$this->def('elementor_get_kit_custom_css','Get the global custom CSS stored in the Elementor Site Kit.',[],[],'read','getKitCustomCss'),
|
$this->def('elementor_get_kit_custom_css','Get the global custom CSS stored in the Elementor Site Kit.',[],[],'read','getKitCustomCss'),
|
||||||
$this->def('elementor_update_kit_custom_css','Set the global custom CSS in the Elementor Site Kit. Replaces existing kit-level CSS.',['css'=>['type'=>'string']],['css'],'write','updateKitCustomCss'),
|
$this->def('elementor_update_kit_custom_css','Set the global custom CSS in the Elementor Site Kit.',['css'=>['type'=>'string']],['css'],'write','updateKitCustomCss'),
|
||||||
$this->def('elementor_get_page_custom_css','Get the custom CSS set for a specific Elementor page (page-level, not kit-level).',['post_id'=>['type'=>'integer']],['post_id'],'read','getPageCustomCss'),
|
$this->def('elementor_get_page_custom_css','Get the custom CSS set for a specific Elementor page.',['post_id'=>['type'=>'integer']],['post_id'],'read','getPageCustomCss'),
|
||||||
$this->def('elementor_update_page_custom_css','Set the custom CSS for a specific Elementor page.',['post_id'=>['type'=>'integer'],'css'=>['type'=>'string']],['post_id','css'],'write','updatePageCustomCss'),
|
$this->def('elementor_update_page_custom_css','Set the custom CSS for a specific Elementor page.',['post_id'=>['type'=>'integer'],'css'=>['type'=>'string']],['post_id','css'],'write','updatePageCustomCss'),
|
||||||
$this->def('elementor_list_experiments','List all Elementor feature flags (experiments) with their current state.',[],[],'read','listExperiments'),
|
$this->def('elementor_list_experiments','List all Elementor feature flags with their current state.',[],[],'read','listExperiments'),
|
||||||
$this->def('elementor_set_experiment','Activate or deactivate an Elementor feature flag by name.',['name'=>['type'=>'string'],'state'=>['type'=>'string','enum'=>['active','inactive','default']]],['name','state'],'admin','setExperiment'),
|
$this->def('elementor_set_experiment','Activate or deactivate an Elementor feature flag.',['name'=>['type'=>'string'],'state'=>['type'=>'string','enum'=>['active','inactive','default']]],['name','state'],'admin','setExperiment'),
|
||||||
$this->def('elementor_set_page_template','Set the WordPress page template for a post (e.g. elementor_canvas, elementor-full-width, default).',['post_id'=>['type'=>'integer'],'template'=>['type'=>'string']],['post_id','template'],'write','setPageTemplate'),
|
$this->def('elementor_set_page_template','Set the WordPress page template for a post (e.g. elementor_canvas, elementor-full-width, default).',['post_id'=>['type'=>'integer'],'template'=>['type'=>'string']],['post_id','template'],'write','setPageTemplate'),
|
||||||
$this->def('elementor_get_revisions','List all saved revisions for an Elementor post. Returns id, type, author, timestamp.',['post_id'=>['type'=>'integer']],['post_id'],'read','getRevisions'),
|
$this->def('elementor_get_revisions','List all saved revisions for an Elementor post.',['post_id'=>['type'=>'integer']],['post_id'],'read','getRevisions'),
|
||||||
$this->def('elementor_restore_revision','Restore an Elementor post to a specific revision by revision ID.',['post_id'=>['type'=>'integer'],'revision_id'=>['type'=>'integer']],['post_id','revision_id'],'write','restoreRevision'),
|
$this->def('elementor_restore_revision','Restore an Elementor post to a specific revision.',['post_id'=>['type'=>'integer'],'revision_id'=>['type'=>'integer']],['post_id','revision_id'],'write','restoreRevision'),
|
||||||
$this->def('elementor_get_performance_settings','Get all Elementor performance settings (CSS print method, font display, lazy load, FA4 shim, caching, etc.).',[],[],'read','getPerformanceSettings'),
|
$this->def('elementor_get_performance_settings','Get all Elementor performance settings.',[],[],'read','getPerformanceSettings'),
|
||||||
$this->def('elementor_update_performance_settings','Update one or more Elementor performance settings.',['settings'=>['type'=>'object']],['settings'],'admin','updatePerformanceSettings'),
|
$this->def('elementor_update_performance_settings','Update one or more Elementor performance settings.',['settings'=>['type'=>'object']],['settings'],'admin','updatePerformanceSettings'),
|
||||||
$this->def('elementor_get_cpt_support','Get the list of post types where Elementor editor is enabled.',[],[],'read','getCptSupport'),
|
$this->def('elementor_get_cpt_support','Get the list of post types where Elementor editor is enabled.',[],[],'read','getCptSupport'),
|
||||||
$this->def('elementor_set_cpt_support','Set which post types Elementor editor is enabled for. Pass post_types as array of slugs.',['post_types'=>['type'=>'array','items'=>['type'=>'string']]],['post_types'],'admin','setCptSupport'),
|
$this->def('elementor_set_cpt_support','Set which post types Elementor editor is enabled for.',['post_types'=>['type'=>'array','items'=>['type'=>'string']]],['post_types'],'admin','setCptSupport'),
|
||||||
$this->def('elementor_get_maintenance_mode','Get current Elementor maintenance/coming-soon mode state.',[],[],'read','getMaintenanceMode'),
|
$this->def('elementor_get_maintenance_mode','Get current Elementor maintenance/coming-soon mode state.',[],[],'read','getMaintenanceMode'),
|
||||||
$this->def('elementor_set_maintenance_mode','Enable or disable Elementor maintenance or coming-soon mode.',['mode'=>['type'=>'string','enum'=>['maintenance','coming_soon','']],'page_id'=>['type'=>'integer'],'exclude_mode'=>['type'=>'string','enum'=>['logged_in','exclude_admins','']]],['mode'],'admin','setMaintenanceMode'),
|
$this->def('elementor_set_maintenance_mode','Enable or disable Elementor maintenance or coming-soon mode.',['mode'=>['type'=>'string','enum'=>['maintenance','coming_soon','']],'page_id'=>['type'=>'integer'],'exclude_mode'=>['type'=>'string','enum'=>['logged_in','exclude_admins','']]],['mode'],'admin','setMaintenanceMode'),
|
||||||
$this->def('elementor_get_site_settings','Get Elementor site-level settings: Google Maps API key, meta generator tag, font settings, and other global options.',[],[],'read','getSiteSettings'),
|
$this->def('elementor_get_site_settings','Get Elementor site-level settings.',[],[],'read','getSiteSettings'),
|
||||||
$this->def('elementor_update_site_settings','Update Elementor site-level settings.',['settings'=>['type'=>'object']],['settings'],'admin','updateSiteSettings'),
|
$this->def('elementor_update_site_settings','Update Elementor site-level settings.',['settings'=>['type'=>'object']],['settings'],'admin','updateSiteSettings'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -83,17 +87,36 @@ class ElementorTools {
|
|||||||
return ['name'=>$name,'description'=>$desc,'scope'=>$scope,'handler'=>[$this,$method],'inputSchema'=>$schema];
|
return ['name'=>$name,'description'=>$desc,'scope'=>$scope,'handler'=>[$this,$method],'inputSchema'=>$schema];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// PAGE METHODS
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function createPage(array $args): array {
|
public function createPage(array $args): array {
|
||||||
$title = sanitize_text_field($args['title'] ?? '');
|
$title = sanitize_text_field($args['title'] ?? '');
|
||||||
$status = sanitize_key($args['status'] ?? 'draft');
|
$status = sanitize_key($args['status'] ?? 'draft');
|
||||||
$post_type = sanitize_key($args['post_type'] ?? 'page');
|
$post_type = sanitize_key($args['post_type'] ?? 'page');
|
||||||
if (empty($title)) throw new \RuntimeException('title is required.');
|
if (empty($title)) throw new \RuntimeException('title is required.');
|
||||||
$post_id = wp_insert_post(['post_title'=>$title,'post_status'=>$status,'post_type'=>$post_type,'meta_input'=>['_elementor_edit_mode'=>'builder','_elementor_template_type'=>'wp-'.$post_type]], true);
|
$post_id = wp_insert_post([
|
||||||
|
'post_title' => $title,
|
||||||
|
'post_status' => $status,
|
||||||
|
'post_type' => $post_type,
|
||||||
|
'meta_input' => [
|
||||||
|
'_elementor_edit_mode' => 'builder',
|
||||||
|
'_elementor_template_type' => 'wp-' . $post_type,
|
||||||
|
],
|
||||||
|
], true);
|
||||||
if (is_wp_error($post_id)) throw new \RuntimeException($post_id->get_error_message());
|
if (is_wp_error($post_id)) throw new \RuntimeException($post_id->get_error_message());
|
||||||
if (!empty($args['template'])) update_post_meta($post_id, '_wp_page_template', sanitize_text_field($args['template']));
|
if (!empty($args['template'])) {
|
||||||
|
update_post_meta($post_id, '_wp_page_template', sanitize_text_field($args['template']));
|
||||||
|
}
|
||||||
$content = !empty($args['content']) && is_array($args['content']) ? $args['content'] : [];
|
$content = !empty($args['content']) && is_array($args['content']) ? $args['content'] : [];
|
||||||
$this->data->save_page_data($post_id, $content);
|
$this->data->save_page_data($post_id, $content);
|
||||||
return ['post_id'=>$post_id,'title'=>$title,'edit_url'=>admin_url("post.php?post={$post_id}&action=elementor"),'preview_url'=>get_permalink($post_id)?:''];
|
return [
|
||||||
|
'post_id' => $post_id,
|
||||||
|
'title' => $title,
|
||||||
|
'edit_url' => admin_url("post.php?post={$post_id}&action=elementor"),
|
||||||
|
'preview_url' => get_permalink($post_id) ?: '',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPage(array $args): array {
|
public function getPage(array $args): array {
|
||||||
@@ -126,8 +149,11 @@ class ElementorTools {
|
|||||||
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
||||||
$template_json = $this->data->reassign_ids($template_json);
|
$template_json = $this->data->reassign_ids($template_json);
|
||||||
$count = $this->data->count_elements($template_json);
|
$count = $this->data->count_elements($template_json);
|
||||||
if ($position < 0 || $position >= count($data)) $data = array_merge($data, $template_json);
|
if ($position < 0 || $position >= count($data)) {
|
||||||
else array_splice($data, $position, 0, $template_json);
|
$data = array_merge($data, $template_json);
|
||||||
|
} else {
|
||||||
|
array_splice($data, $position, 0, $template_json);
|
||||||
|
}
|
||||||
$result = $this->data->save_page_data($post_id, $data);
|
$result = $this->data->save_page_data($post_id, $data);
|
||||||
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
||||||
return ['success' => true, 'elements_count' => $count];
|
return ['success' => true, 'elements_count' => $count];
|
||||||
@@ -140,47 +166,73 @@ class ElementorTools {
|
|||||||
return ['json' => $data, 'count' => $this->data->count_elements($data)];
|
return ['json' => $data, 'count' => $this->data->count_elements($data)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// CONTAINER & ELEMENT METHODS
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a container. Uses insert_element() (by-reference) from the data layer.
|
* Add a container.
|
||||||
* Flex shorthand keys normalised before building the element.
|
* - Normalises flex shorthand keys via data layer (upstream v1.5.1 fix)
|
||||||
* Auto-sets flex_align_items=center for column containers (mirrors v1.9.0 factory defaults).
|
* - Auto-sets flex_align_items=center for column containers (upstream v1.9.0 factory)
|
||||||
|
* - Uses insert_element() by-reference
|
||||||
*/
|
*/
|
||||||
public function addContainer(array $args): array {
|
public function addContainer(array $args): array {
|
||||||
$post_id = (int)($args['post_id'] ?? 0);
|
$post_id = (int)($args['post_id'] ?? 0);
|
||||||
$parent_id = $args['parent_id'] ?? '';
|
$parent_id = $args['parent_id'] ?? null;
|
||||||
$position = (int)($args['position'] ?? -1);
|
$position = (int)($args['position'] ?? -1);
|
||||||
$settings = $args['settings'] ?? [];
|
$settings = $args['settings'] ?? [];
|
||||||
|
|
||||||
$settings = \AskTamMCP\Elementor\Data\ElementorData::normalize_container_settings($settings);
|
// Normalise flex shorthand aliases (upstream v1.9.0 / v1.5.1).
|
||||||
|
$settings = $this->data->normalize_container_settings($settings);
|
||||||
|
|
||||||
|
// Upstream v1.9.0 factory defaults.
|
||||||
|
$merged = array_merge(['container_type' => 'flex', 'content_width' => 'boxed'], $settings);
|
||||||
|
$is_grid = ('grid' === ($merged['container_type'] ?? 'flex'));
|
||||||
|
$direction = $merged['flex_direction'] ?? '';
|
||||||
|
$is_row = ('row' === $direction || 'row-reverse' === $direction);
|
||||||
|
|
||||||
|
// Auto-center flex_align_items for column containers (not grid, not row).
|
||||||
|
if (!$is_grid && !$is_row && !isset($settings['flex_align_items'])) {
|
||||||
|
$merged['flex_align_items'] = 'center';
|
||||||
|
}
|
||||||
|
|
||||||
$data = $this->data->get_page_data($post_id);
|
$data = $this->data->get_page_data($post_id);
|
||||||
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
||||||
|
|
||||||
$element_id = $this->data->generate_id();
|
$element_id = $this->data->generate_id();
|
||||||
$defaults = ['container_type'=>'flex','content_width'=>'boxed'];
|
$container = [
|
||||||
|
'id' => $element_id,
|
||||||
|
'elType' => 'container',
|
||||||
|
'widgetType' => null,
|
||||||
|
'isInner' => !empty($parent_id),
|
||||||
|
'settings' => $merged,
|
||||||
|
'elements' => [],
|
||||||
|
];
|
||||||
|
|
||||||
$direction = $settings['flex_direction'] ?? '';
|
// insert_element() is by-reference (upstream v1.9.0).
|
||||||
$is_row = in_array($direction, ['row','row-reverse'], true);
|
$inserted = $this->data->insert_element($data, $parent_id ?? '', $container, $position);
|
||||||
$is_grid = ($settings['container_type'] ?? 'flex') === 'grid';
|
if (!$inserted) {
|
||||||
if (!$is_grid && !$is_row && !isset($settings['flex_align_items'])) {
|
if (!empty($parent_id)) {
|
||||||
$defaults['flex_align_items'] = 'center';
|
$data = $this->insertIntoParent($data, $parent_id, $container, $position);
|
||||||
|
} else {
|
||||||
|
if ($position < 0 || $position >= count($data)) $data[] = $container;
|
||||||
|
else array_splice($data, $position, 0, [$container]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$container = ['id'=>$element_id,'elType'=>'container','widgetType'=>null,'isInner'=>!empty($parent_id),'settings'=>array_merge($defaults,$settings),'elements'=>[]];
|
|
||||||
|
|
||||||
$inserted = $this->data->insert_element($data, $parent_id, $container, $position);
|
|
||||||
if (!$inserted) throw new \RuntimeException("Parent element '{$parent_id}' not found.");
|
|
||||||
|
|
||||||
$result = $this->data->save_page_data($post_id, $data);
|
$result = $this->data->save_page_data($post_id, $data);
|
||||||
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
||||||
|
|
||||||
return ['element_id' => $element_id, 'post_id' => $post_id];
|
return ['element_id' => $element_id, 'post_id' => $post_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateContainer(array $args): array { return $this->updateElement($args); }
|
public function updateContainer(array $args): array {
|
||||||
|
return $this->updateElement($args);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update any element. For containers the data layer auto-normalises flex shorthand keys.
|
* Update any element's settings (by-reference data layer, returns bool).
|
||||||
* update_element_settings() is by-reference and returns bool.
|
* For containers, flex shorthand keys are auto-normalised inside the data layer.
|
||||||
*/
|
*/
|
||||||
public function updateElement(array $args): array {
|
public function updateElement(array $args): array {
|
||||||
$post_id = (int)($args['post_id'] ?? 0);
|
$post_id = (int)($args['post_id'] ?? 0);
|
||||||
@@ -191,16 +243,18 @@ class ElementorTools {
|
|||||||
$data = $this->data->get_page_data($post_id);
|
$data = $this->data->get_page_data($post_id);
|
||||||
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
||||||
|
|
||||||
|
// update_element_settings is by-reference in v1.9.0 — returns bool.
|
||||||
$updated = $this->data->update_element_settings($data, $element_id, $settings, $merge);
|
$updated = $this->data->update_element_settings($data, $element_id, $settings, $merge);
|
||||||
if (!$updated) throw new \RuntimeException("Element not found: {$element_id}");
|
if (!$updated) throw new \RuntimeException("Element not found: {$element_id}");
|
||||||
|
|
||||||
$result = $this->data->save_page_data($post_id, $data);
|
$result = $this->data->save_page_data($post_id, $data);
|
||||||
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
||||||
|
|
||||||
return ['success' => true, 'post_id' => $post_id, 'element_id' => $element_id];
|
return ['success' => true, 'post_id' => $post_id, 'element_id' => $element_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an element. remove_element() is by-reference and returns bool.
|
* Remove an element. remove_element() is by-reference, returns bool.
|
||||||
*/
|
*/
|
||||||
public function removeElement(array $args): array {
|
public function removeElement(array $args): array {
|
||||||
$post_id = (int)($args['post_id'] ?? 0);
|
$post_id = (int)($args['post_id'] ?? 0);
|
||||||
@@ -209,16 +263,19 @@ class ElementorTools {
|
|||||||
$data = $this->data->get_page_data($post_id);
|
$data = $this->data->get_page_data($post_id);
|
||||||
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
||||||
|
|
||||||
|
// remove_element is by-reference in v1.9.0 — returns bool.
|
||||||
$removed = $this->data->remove_element($data, $element_id);
|
$removed = $this->data->remove_element($data, $element_id);
|
||||||
if (!$removed) throw new \RuntimeException("Element not found: {$element_id}");
|
if (!$removed) throw new \RuntimeException("Element not found: {$element_id}");
|
||||||
|
|
||||||
$result = $this->data->save_page_data($post_id, $data);
|
$result = $this->data->save_page_data($post_id, $data);
|
||||||
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
||||||
|
|
||||||
return ['success' => true, 'removed_id' => $element_id];
|
return ['success' => true, 'removed_id' => $element_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Duplicate element — clone placed immediately after original (mirrors v1.9.0 insert_after).
|
* Duplicate an element (with all children). Clone gets fresh IDs and is
|
||||||
|
* inserted immediately after the original (upstream v1.9.0 pattern).
|
||||||
*/
|
*/
|
||||||
public function duplicateElement(array $args): array {
|
public function duplicateElement(array $args): array {
|
||||||
$post_id = (int)($args['post_id'] ?? 0);
|
$post_id = (int)($args['post_id'] ?? 0);
|
||||||
@@ -230,17 +287,20 @@ class ElementorTools {
|
|||||||
$element = $this->data->find_element($data, $element_id);
|
$element = $this->data->find_element($data, $element_id);
|
||||||
if (!$element) throw new \RuntimeException("Element not found: {$element_id}");
|
if (!$element) throw new \RuntimeException("Element not found: {$element_id}");
|
||||||
|
|
||||||
$clone = $this->data->reassign_element_ids($element);
|
// reassign_ids on single-element array = upstream reassign_element_ids.
|
||||||
|
$clone = $this->data->reassign_ids([$element])[0];
|
||||||
|
|
||||||
$inserted = $this->insertAfter($data, $element_id, $clone);
|
$inserted = $this->insertAfter($data, $element_id, $clone);
|
||||||
if (!$inserted) throw new \RuntimeException("Failed to insert duplicate after {$element_id}.");
|
if (!$inserted) throw new \RuntimeException("Failed to insert duplicate after {$element_id}.");
|
||||||
|
|
||||||
$result = $this->data->save_page_data($post_id, $data);
|
$result = $this->data->save_page_data($post_id, $data);
|
||||||
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
||||||
|
|
||||||
return ['success' => true, 'new_element_id' => $clone['id']];
|
return ['success' => true, 'new_element_id' => $clone['id']];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move element — by-reference remove then insert.
|
* Move element to new parent/position using by-reference remove+insert.
|
||||||
*/
|
*/
|
||||||
public function moveElement(array $args): array {
|
public function moveElement(array $args): array {
|
||||||
$post_id = (int)($args['post_id'] ?? 0);
|
$post_id = (int)($args['post_id'] ?? 0);
|
||||||
@@ -262,25 +322,142 @@ class ElementorTools {
|
|||||||
|
|
||||||
$result = $this->data->save_page_data($post_id, $data);
|
$result = $this->data->save_page_data($post_id, $data);
|
||||||
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
||||||
|
|
||||||
return ['success' => true, 'element_id' => $element_id];
|
return ['success' => true, 'element_id' => $element_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// BATCH UPDATE (upstream v1.9.0)
|
||||||
|
// Updates multiple elements in a single save operation.
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
|
public function batchUpdate(array $args): array {
|
||||||
|
$post_id = (int)($args['post_id'] ?? 0);
|
||||||
|
$operations = $args['operations'] ?? [];
|
||||||
|
|
||||||
|
if (!$post_id || empty($operations)) {
|
||||||
|
throw new \RuntimeException('post_id and operations are required.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->data->get_page_data($post_id);
|
||||||
|
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
||||||
|
|
||||||
|
$updated_count = 0;
|
||||||
|
$failed = [];
|
||||||
|
|
||||||
|
foreach ($operations as $op) {
|
||||||
|
$eid = $op['element_id'] ?? '';
|
||||||
|
$settings = $op['settings'] ?? [];
|
||||||
|
|
||||||
|
if (empty($eid) || empty($settings)) {
|
||||||
|
$failed[] = ['element_id' => $eid, 'reason' => 'missing element_id or settings'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$element = $this->data->find_element($data, $eid);
|
||||||
|
if (null === $element) {
|
||||||
|
$failed[] = ['element_id' => $eid, 'reason' => 'element not found'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ok = $this->data->update_element_settings($data, $eid, $settings);
|
||||||
|
if ($ok) {
|
||||||
|
$updated_count++;
|
||||||
|
} else {
|
||||||
|
$failed[] = ['element_id' => $eid, 'reason' => 'update failed'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->data->save_page_data($post_id, $data);
|
||||||
|
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => empty($failed),
|
||||||
|
'updated' => $updated_count,
|
||||||
|
'failed' => $failed,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// REORDER ELEMENTS (upstream v1.9.0)
|
||||||
|
// Reorders direct children of a container in one save.
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
|
public function reorderElements(array $args): array {
|
||||||
|
$post_id = (int)($args['post_id'] ?? 0);
|
||||||
|
$container_id = $args['container_id'] ?? '';
|
||||||
|
$element_ids = $args['element_ids'] ?? [];
|
||||||
|
|
||||||
|
if (!$post_id || empty($container_id) || empty($element_ids)) {
|
||||||
|
throw new \RuntimeException('post_id, container_id, and element_ids are required.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->data->get_page_data($post_id);
|
||||||
|
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
||||||
|
|
||||||
|
$container = $this->data->find_element($data, $container_id);
|
||||||
|
if (!$container) throw new \RuntimeException("Container not found: {$container_id}");
|
||||||
|
if ('container' !== ($container['elType'] ?? '')) throw new \RuntimeException('Element is not a container.');
|
||||||
|
|
||||||
|
$children = $container['elements'] ?? [];
|
||||||
|
$by_id = [];
|
||||||
|
foreach ($children as $child) {
|
||||||
|
$by_id[$child['id']] = $child;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($element_ids as $eid) {
|
||||||
|
if (!isset($by_id[$eid])) {
|
||||||
|
throw new \RuntimeException("Element \"{$eid}\" is not a direct child of \"{$container_id}\".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$reordered = [];
|
||||||
|
foreach ($element_ids as $eid) {
|
||||||
|
$reordered[] = $by_id[$eid];
|
||||||
|
unset($by_id[$eid]);
|
||||||
|
}
|
||||||
|
foreach ($by_id as $remaining) {
|
||||||
|
$reordered[] = $remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
$applied = $this->applyChildReorder($data, $container_id, $reordered);
|
||||||
|
if (!$applied) throw new \RuntimeException('Failed to reorder elements.');
|
||||||
|
|
||||||
|
$result = $this->data->save_page_data($post_id, $data);
|
||||||
|
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
||||||
|
|
||||||
|
return ['success' => true];
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// WIDGET METHODS
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function addWidget(array $args): array {
|
public function addWidget(array $args): array {
|
||||||
$post_id = (int)($args['post_id'] ?? 0);
|
$post_id = (int)($args['post_id'] ?? 0);
|
||||||
$container_id = $args['container_id'] ?? '';
|
$container_id = $args['container_id'] ?? '';
|
||||||
$widget_type = $args['widget_type'] ?? '';
|
$widget_type = $args['widget_type'] ?? '';
|
||||||
$settings = $args['settings'] ?? [];
|
$settings = $args['settings'] ?? [];
|
||||||
$position = (int)($args['position'] ?? -1);
|
$position = (int)($args['position'] ?? -1);
|
||||||
|
|
||||||
if (empty($widget_type)) throw new \RuntimeException('widget_type is required.');
|
if (empty($widget_type)) throw new \RuntimeException('widget_type is required.');
|
||||||
|
|
||||||
$data = $this->data->get_page_data($post_id);
|
$data = $this->data->get_page_data($post_id);
|
||||||
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
||||||
|
|
||||||
$element_id = $this->data->generate_id();
|
$element_id = $this->data->generate_id();
|
||||||
$widget = ['id'=>$element_id,'elType'=>'widget','widgetType'=>$widget_type,'isInner'=>false,'settings'=>$settings,'elements'=>[]];
|
$widget = [
|
||||||
|
'id' => $element_id,
|
||||||
|
'elType' => 'widget',
|
||||||
|
'widgetType' => $widget_type,
|
||||||
|
'isInner' => false,
|
||||||
|
'settings' => $settings,
|
||||||
|
'elements' => [],
|
||||||
|
];
|
||||||
|
|
||||||
$inserted = $this->data->insert_element($data, $container_id, $widget, $position);
|
$inserted = $this->data->insert_element($data, $container_id, $widget, $position);
|
||||||
if (!$inserted && !empty($container_id)) {
|
if (!$inserted && !empty($container_id)) {
|
||||||
|
// Fallback for edge cases.
|
||||||
$data = $this->data->get_page_data($post_id);
|
$data = $this->data->get_page_data($post_id);
|
||||||
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
||||||
$data = $this->insertIntoParent($data, $container_id, $widget, $position);
|
$data = $this->insertIntoParent($data, $container_id, $widget, $position);
|
||||||
@@ -288,10 +465,13 @@ class ElementorTools {
|
|||||||
|
|
||||||
$result = $this->data->save_page_data($post_id, $data);
|
$result = $this->data->save_page_data($post_id, $data);
|
||||||
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
if (is_wp_error($result)) throw new \RuntimeException($result->get_error_message());
|
||||||
|
|
||||||
return ['element_id' => $element_id, 'post_id' => $post_id, 'widget_type' => $widget_type];
|
return ['element_id' => $element_id, 'post_id' => $post_id, 'widget_type' => $widget_type];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateWidget(array $args): array { return $this->updateElement($args); }
|
public function updateWidget(array $args): array {
|
||||||
|
return $this->updateElement($args);
|
||||||
|
}
|
||||||
|
|
||||||
public function addHeading(array $args): array {
|
public function addHeading(array $args): array {
|
||||||
$text = $args['title'] ?? $args['text'] ?? '';
|
$text = $args['title'] ?? $args['text'] ?? '';
|
||||||
@@ -304,7 +484,10 @@ class ElementorTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function addText(array $args): array {
|
public function addText(array $args): array {
|
||||||
return $this->addWidget(array_merge($args,['widget_type'=>'text-editor','settings'=>['editor'=>$args['content']??'']]));
|
return $this->addWidget(array_merge($args, [
|
||||||
|
'widget_type' => 'text-editor',
|
||||||
|
'settings' => ['editor' => $args['content'] ?? ''],
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addImage(array $args): array {
|
public function addImage(array $args): array {
|
||||||
@@ -314,18 +497,51 @@ class ElementorTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function addButton(array $args): array {
|
public function addButton(array $args): array {
|
||||||
$settings = ['text'=>$args['text']??'','link'=>['url'=>$args['url']??''],'button_type'=>$args['type']??'default'];
|
$settings = [
|
||||||
|
'text' => $args['text'] ?? '',
|
||||||
|
'link' => ['url' => $args['url'] ?? ''],
|
||||||
|
'button_type' => $args['type'] ?? 'default',
|
||||||
|
];
|
||||||
if (!empty($args['align'])) $settings['align'] = $args['align'];
|
if (!empty($args['align'])) $settings['align'] = $args['align'];
|
||||||
return $this->addWidget(array_merge($args, ['widget_type' => 'button', 'settings' => $settings]));
|
return $this->addWidget(array_merge($args, ['widget_type' => 'button', 'settings' => $settings]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Add a line/divider widget (upstream v1.9.0 alias). */
|
||||||
|
public function addLine(array $args): array {
|
||||||
|
return $this->addWidget(array_merge($args, [
|
||||||
|
'widget_type' => 'divider',
|
||||||
|
'settings' => $args['settings'] ?? [],
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add an HTML block widget (upstream v1.9.0 alias). */
|
||||||
|
public function addBlock(array $args): array {
|
||||||
|
return $this->addWidget(array_merge($args, [
|
||||||
|
'widget_type' => 'html',
|
||||||
|
'settings' => ['html' => $args['html'] ?? $args['content'] ?? ''],
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// TEMPLATE METHODS
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function saveAsTemplate(array $args): array {
|
public function saveAsTemplate(array $args): array {
|
||||||
$post_id = (int)($args['post_id'] ?? 0);
|
$post_id = (int)($args['post_id'] ?? 0);
|
||||||
$name = sanitize_text_field($args['template_name'] ?? '');
|
$name = sanitize_text_field($args['template_name'] ?? '');
|
||||||
$type = sanitize_key($args['type'] ?? 'page');
|
$type = sanitize_key($args['type'] ?? 'page');
|
||||||
$data = $this->data->get_page_data($post_id);
|
$data = $this->data->get_page_data($post_id);
|
||||||
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
||||||
$template_id = wp_insert_post(['post_title'=>$name,'post_type'=>'elementor_library','post_status'=>'publish','meta_input'=>['_elementor_data'=>wp_json_encode($data),'_elementor_template_type'=>$type,'_elementor_edit_mode'=>'builder']],true);
|
$template_id = wp_insert_post([
|
||||||
|
'post_title' => $name,
|
||||||
|
'post_type' => 'elementor_library',
|
||||||
|
'post_status' => 'publish',
|
||||||
|
'meta_input' => [
|
||||||
|
'_elementor_data' => wp_json_encode($data),
|
||||||
|
'_elementor_template_type' => $type,
|
||||||
|
'_elementor_edit_mode' => 'builder',
|
||||||
|
],
|
||||||
|
], true);
|
||||||
if (is_wp_error($template_id)) throw new \RuntimeException($template_id->get_error_message());
|
if (is_wp_error($template_id)) throw new \RuntimeException($template_id->get_error_message());
|
||||||
wp_set_object_terms($template_id, $type, 'elementor_library_type');
|
wp_set_object_terms($template_id, $type, 'elementor_library_type');
|
||||||
return ['success' => true, 'template_id' => $template_id, 'name' => $name];
|
return ['success' => true, 'template_id' => $template_id, 'name' => $name];
|
||||||
@@ -343,11 +559,31 @@ class ElementorTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function listTemplates(array $args): array {
|
public function listTemplates(array $args): array {
|
||||||
$query_args = ['post_type'=>'elementor_library','post_status'=>'publish','posts_per_page'=>(int)($args['per_page']??50),'orderby'=>'title','order'=>'ASC'];
|
$query_args = [
|
||||||
if (!empty($args['type'])) $query_args['tax_query'] = [['taxonomy'=>'elementor_library_type','field'=>'slug','terms'=>[$args['type']]]];
|
'post_type' => 'elementor_library',
|
||||||
$templates = get_posts($query_args);
|
'post_status' => 'publish',
|
||||||
return ['templates'=>array_map(fn($t)=>['id'=>$t->ID,'title'=>$t->post_title,'type'=>get_post_meta($t->ID,'_elementor_template_type',true),'date'=>$t->post_date],$templates),'total'=>count($templates)];
|
'posts_per_page' => (int)($args['per_page'] ?? 50),
|
||||||
|
'orderby' => 'title',
|
||||||
|
'order' => 'ASC',
|
||||||
|
];
|
||||||
|
if (!empty($args['type'])) {
|
||||||
|
$query_args['tax_query'] = [['taxonomy' => 'elementor_library_type', 'field' => 'slug', 'terms' => [$args['type']]]];
|
||||||
}
|
}
|
||||||
|
$templates = get_posts($query_args);
|
||||||
|
return [
|
||||||
|
'templates' => array_map(fn($t) => [
|
||||||
|
'id' => $t->ID,
|
||||||
|
'title' => $t->post_title,
|
||||||
|
'type' => get_post_meta($t->ID, '_elementor_template_type', true),
|
||||||
|
'date' => $t->post_date,
|
||||||
|
], $templates),
|
||||||
|
'total' => count($templates),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// GLOBAL / KIT METHODS
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function getGlobalColors(array $args): array {
|
public function getGlobalColors(array $args): array {
|
||||||
$kit = $this->getActiveKit();
|
$kit = $this->getActiveKit();
|
||||||
@@ -370,7 +606,12 @@ class ElementorTools {
|
|||||||
$id = $args['id'] ?? ('color_' . substr(md5($args['title'] ?? uniqid()), 0, 6));
|
$id = $args['id'] ?? ('color_' . substr(md5($args['title'] ?? uniqid()), 0, 6));
|
||||||
$found = false;
|
$found = false;
|
||||||
foreach ($colors as &$color) {
|
foreach ($colors as &$color) {
|
||||||
if (($color['_id']??'') === $id) { $color['title']=$args['title']??$color['title']; $color['color']=$args['value']??$color['color']; $found=true; break; }
|
if (($color['_id'] ?? '') === $id) {
|
||||||
|
$color['title'] = $args['title'] ?? $color['title'];
|
||||||
|
$color['color'] = $args['value'] ?? $color['color'];
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!$found) $colors[] = ['_id' => $id, 'title' => $args['title'] ?? $id, 'color' => $args['value'] ?? ''];
|
if (!$found) $colors[] = ['_id' => $id, 'title' => $args['title'] ?? $id, 'color' => $args['value'] ?? ''];
|
||||||
$settings['system_colors'] = $colors;
|
$settings['system_colors'] = $colors;
|
||||||
@@ -425,7 +666,15 @@ class ElementorTools {
|
|||||||
$orig = get_post($post_id);
|
$orig = get_post($post_id);
|
||||||
if (!$orig) throw new \RuntimeException("Post not found: {$post_id}");
|
if (!$orig) throw new \RuntimeException("Post not found: {$post_id}");
|
||||||
$title = $args['title'] ?? ('Copy of ' . $orig->post_title);
|
$title = $args['title'] ?? ('Copy of ' . $orig->post_title);
|
||||||
$new_id = wp_insert_post(['post_title'=>$title,'post_type'=>$orig->post_type,'post_status'=>'draft','meta_input'=>['_elementor_edit_mode'=>'builder','_elementor_template_type'=>get_post_meta($post_id,'_elementor_template_type',true)]],true);
|
$new_id = wp_insert_post([
|
||||||
|
'post_title' => $title,
|
||||||
|
'post_type' => $orig->post_type,
|
||||||
|
'post_status' => 'draft',
|
||||||
|
'meta_input' => [
|
||||||
|
'_elementor_edit_mode' => 'builder',
|
||||||
|
'_elementor_template_type' => get_post_meta($post_id, '_elementor_template_type', true),
|
||||||
|
],
|
||||||
|
], true);
|
||||||
if (is_wp_error($new_id)) throw new \RuntimeException($new_id->get_error_message());
|
if (is_wp_error($new_id)) throw new \RuntimeException($new_id->get_error_message());
|
||||||
$data = $this->data->get_page_data($post_id);
|
$data = $this->data->get_page_data($post_id);
|
||||||
if (!is_wp_error($data)) $this->data->save_page_data($new_id, $this->data->reassign_ids($data));
|
if (!is_wp_error($data)) $this->data->save_page_data($new_id, $this->data->reassign_ids($data));
|
||||||
@@ -441,7 +690,9 @@ class ElementorTools {
|
|||||||
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
if (is_wp_error($data)) throw new \RuntimeException($data->get_error_message());
|
||||||
$encoded = wp_json_encode($data);
|
$encoded = wp_json_encode($data);
|
||||||
$count = 0;
|
$count = 0;
|
||||||
$new = $case_sensitive ? str_replace($search,$replace,$encoded,$count) : str_ireplace($search,$replace,$encoded,$count);
|
$new = $case_sensitive
|
||||||
|
? str_replace($search, $replace, $encoded, $count)
|
||||||
|
: str_ireplace($search, $replace, $encoded, $count);
|
||||||
$new_data = json_decode($new, true);
|
$new_data = json_decode($new, true);
|
||||||
if (!is_array($new_data)) throw new \RuntimeException('Failed to re-encode data after replacement.');
|
if (!is_array($new_data)) throw new \RuntimeException('Failed to re-encode data after replacement.');
|
||||||
$result = $this->data->save_page_data($post_id, $new_data);
|
$result = $this->data->save_page_data($post_id, $new_data);
|
||||||
@@ -467,10 +718,14 @@ class ElementorTools {
|
|||||||
return ['post_id' => $args['post_id'], 'deleted' => $deleted, 'count' => count($deleted)];
|
return ['post_id' => $args['post_id'], 'deleted' => $deleted, 'count' => count($deleted)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// CSS / REGENERATION
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function flushCss(array $args): array {
|
public function flushCss(array $args): array {
|
||||||
if (!class_exists('\Elementor\Plugin')) throw new \RuntimeException('Elementor not active.');
|
if (!class_exists('\Elementor\Plugin')) throw new \RuntimeException('Elementor not active.');
|
||||||
\Elementor\Plugin::instance()->files_manager->clear_cache();
|
\Elementor\Plugin::instance()->files_manager->clear_cache();
|
||||||
return ['success'=>true,'message'=>'All Elementor CSS files flushed and queued for regeneration.'];
|
return ['success' => true, 'message' => 'All Elementor CSS files flushed.'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function regenerateCss(array $args): array {
|
public function regenerateCss(array $args): array {
|
||||||
@@ -478,20 +733,28 @@ class ElementorTools {
|
|||||||
if (!$post_id) throw new \RuntimeException('post_id is required.');
|
if (!$post_id) throw new \RuntimeException('post_id is required.');
|
||||||
if (!class_exists('\Elementor\Core\Files\CSS\Post')) throw new \RuntimeException('Elementor CSS class not found.');
|
if (!class_exists('\Elementor\Core\Files\CSS\Post')) throw new \RuntimeException('Elementor CSS class not found.');
|
||||||
(new \Elementor\Core\Files\CSS\Post($post_id))->update();
|
(new \Elementor\Core\Files\CSS\Post($post_id))->update();
|
||||||
return ['success'=>true,'post_id'=>$post_id,'message'=>"CSS regenerated for post {$post_id}."];
|
return ['success' => true, 'post_id' => $post_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// REPLACE URLS
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function replaceUrls(array $args): array {
|
public function replaceUrls(array $args): array {
|
||||||
$old = trim($args['old_url'] ?? '');
|
$old = trim($args['old_url'] ?? '');
|
||||||
$new = trim($args['new_url'] ?? '');
|
$new = trim($args['new_url'] ?? '');
|
||||||
if (empty($old) || empty($new)) throw new \RuntimeException('old_url and new_url are required.');
|
if (empty($old) || empty($new)) throw new \RuntimeException('old_url and new_url are required.');
|
||||||
if ($old === $new) return ['success'=>true,'updated'=>0,'message'=>'old_url and new_url are identical.'];
|
if ($old === $new) return ['success' => true, 'updated' => 0, 'message' => 'URLs are identical.'];
|
||||||
|
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
$posts = $wpdb->get_col($wpdb->prepare(
|
$posts = $wpdb->get_col($wpdb->prepare(
|
||||||
"SELECT pm.post_id FROM {$wpdb->postmeta} pm WHERE pm.meta_key='_elementor_data' AND pm.meta_value LIKE %s",
|
"SELECT pm.post_id FROM {$wpdb->postmeta} pm WHERE pm.meta_key='_elementor_data' AND pm.meta_value LIKE %s",
|
||||||
'%' . $wpdb->esc_like($old) . '%'
|
'%' . $wpdb->esc_like($old) . '%'
|
||||||
));
|
));
|
||||||
$updated = 0; $errors = [];
|
|
||||||
|
$updated = 0;
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
foreach ($posts as $pid) {
|
foreach ($posts as $pid) {
|
||||||
$raw = get_post_meta((int)$pid, '_elementor_data', true);
|
$raw = get_post_meta((int)$pid, '_elementor_data', true);
|
||||||
if (empty($raw)) continue;
|
if (empty($raw)) continue;
|
||||||
@@ -500,13 +763,22 @@ class ElementorTools {
|
|||||||
if ($new_raw === $raw) continue;
|
if ($new_raw === $raw) continue;
|
||||||
$r = update_post_meta((int)$pid, '_elementor_data', wp_slash($new_raw));
|
$r = update_post_meta((int)$pid, '_elementor_data', wp_slash($new_raw));
|
||||||
if ($r !== false) {
|
if ($r !== false) {
|
||||||
if (class_exists('\Elementor\Core\Files\CSS\Post')) (new \Elementor\Core\Files\CSS\Post((int)$pid))->update();
|
if (class_exists('\Elementor\Core\Files\CSS\Post')) {
|
||||||
$updated++;
|
(new \Elementor\Core\Files\CSS\Post((int)$pid))->update();
|
||||||
} else { $errors[] = (int)$pid; }
|
|
||||||
}
|
}
|
||||||
|
$updated++;
|
||||||
|
} else {
|
||||||
|
$errors[] = (int)$pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ['success' => true, 'old_url' => $old, 'new_url' => $new, 'posts_found' => count($posts), 'updated' => $updated, 'errors' => $errors];
|
return ['success' => true, 'old_url' => $old, 'new_url' => $new, 'posts_found' => count($posts), 'updated' => $updated, 'errors' => $errors];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// KIT & PAGE-LEVEL CUSTOM CSS
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function getKitCustomCss(array $args): array {
|
public function getKitCustomCss(array $args): array {
|
||||||
$kit = $this->getActiveKit();
|
$kit = $this->getActiveKit();
|
||||||
if (!$kit) return ['css' => '', 'note' => 'No active Elementor kit.'];
|
if (!$kit) return ['css' => '', 'note' => 'No active Elementor kit.'];
|
||||||
@@ -520,7 +792,9 @@ class ElementorTools {
|
|||||||
$settings = get_post_meta($kit->ID, '_elementor_page_settings', true) ?: [];
|
$settings = get_post_meta($kit->ID, '_elementor_page_settings', true) ?: [];
|
||||||
$settings['custom_css'] = $args['css'] ?? '';
|
$settings['custom_css'] = $args['css'] ?? '';
|
||||||
update_post_meta($kit->ID, '_elementor_page_settings', $settings);
|
update_post_meta($kit->ID, '_elementor_page_settings', $settings);
|
||||||
if (class_exists('\Elementor\Core\Files\CSS\Post')) (new \Elementor\Core\Files\CSS\Post($kit->ID))->update();
|
if (class_exists('\Elementor\Core\Files\CSS\Post')) {
|
||||||
|
(new \Elementor\Core\Files\CSS\Post($kit->ID))->update();
|
||||||
|
}
|
||||||
return ['success' => true, 'kit_id' => $kit->ID, 'bytes' => strlen($settings['custom_css'])];
|
return ['success' => true, 'kit_id' => $kit->ID, 'bytes' => strlen($settings['custom_css'])];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,16 +811,29 @@ class ElementorTools {
|
|||||||
$settings = get_post_meta($post_id, '_elementor_page_settings', true) ?: [];
|
$settings = get_post_meta($post_id, '_elementor_page_settings', true) ?: [];
|
||||||
$settings['custom_css'] = $args['css'] ?? '';
|
$settings['custom_css'] = $args['css'] ?? '';
|
||||||
update_post_meta($post_id, '_elementor_page_settings', $settings);
|
update_post_meta($post_id, '_elementor_page_settings', $settings);
|
||||||
if (class_exists('\Elementor\Core\Files\CSS\Post')) (new \Elementor\Core\Files\CSS\Post($post_id))->update();
|
if (class_exists('\Elementor\Core\Files\CSS\Post')) {
|
||||||
|
(new \Elementor\Core\Files\CSS\Post($post_id))->update();
|
||||||
|
}
|
||||||
return ['success' => true, 'post_id' => $post_id, 'bytes' => strlen($settings['custom_css'])];
|
return ['success' => true, 'post_id' => $post_id, 'bytes' => strlen($settings['custom_css'])];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// EXPERIMENTS / FEATURE FLAGS
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function listExperiments(array $args): array {
|
public function listExperiments(array $args): array {
|
||||||
if (!class_exists('\Elementor\Plugin')) throw new \RuntimeException('Elementor not active.');
|
if (!class_exists('\Elementor\Plugin')) throw new \RuntimeException('Elementor not active.');
|
||||||
$features = \Elementor\Plugin::instance()->experiments->get_features();
|
$features = \Elementor\Plugin::instance()->experiments->get_features();
|
||||||
$list = [];
|
$list = [];
|
||||||
foreach ($features as $name => $feature) {
|
foreach ($features as $name => $feature) {
|
||||||
$list[] = ['name'=>$name,'title'=>$feature['title']??$name,'description'=>$feature['description']??'','state'=>$feature['state']??'default','default'=>$feature['default']??'inactive','is_active'=>\Elementor\Plugin::instance()->experiments->is_feature_active($name)];
|
$list[] = [
|
||||||
|
'name' => $name,
|
||||||
|
'title' => $feature['title'] ?? $name,
|
||||||
|
'description' => $feature['description'] ?? '',
|
||||||
|
'state' => $feature['state'] ?? 'default',
|
||||||
|
'default' => $feature['default'] ?? 'inactive',
|
||||||
|
'is_active' => \Elementor\Plugin::instance()->experiments->is_feature_active($name),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
return ['experiments' => $list, 'total' => count($list)];
|
return ['experiments' => $list, 'total' => count($list)];
|
||||||
}
|
}
|
||||||
@@ -561,31 +848,44 @@ class ElementorTools {
|
|||||||
$feature = $experiments->get_features($name);
|
$feature = $experiments->get_features($name);
|
||||||
if (!$feature) throw new \RuntimeException("Experiment '{$name}' not found.");
|
if (!$feature) throw new \RuntimeException("Experiment '{$name}' not found.");
|
||||||
$option_key = $experiments->get_feature_option_key($name);
|
$option_key = $experiments->get_feature_option_key($name);
|
||||||
if ($state === 'default') delete_option($option_key); else update_option($option_key, $state);
|
if ($state === 'default') delete_option($option_key);
|
||||||
|
else update_option($option_key, $state);
|
||||||
return ['success' => true, 'name' => $name, 'state' => $state, 'is_active' => $experiments->is_feature_active($name)];
|
return ['success' => true, 'name' => $name, 'state' => $state, 'is_active' => $experiments->is_feature_active($name)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// =========================================================
|
||||||
* Set page template — always uses update_post_meta directly.
|
// PAGE TEMPLATE
|
||||||
* wp_update_post template validation fails in CLI context (no registered templates).
|
// =========================================================
|
||||||
* See 05-KNOWN-ISSUES.md.
|
|
||||||
*/
|
|
||||||
public function setPageTemplate(array $args): array {
|
public function setPageTemplate(array $args): array {
|
||||||
$post_id = (int)($args['post_id'] ?? 0);
|
$post_id = (int)($args['post_id'] ?? 0);
|
||||||
$template = $args['template'] ?? '';
|
$template = $args['template'] ?? '';
|
||||||
if (!$post_id) throw new \RuntimeException('post_id is required.');
|
if (!$post_id) throw new \RuntimeException('post_id is required.');
|
||||||
if ($template === 'default') $template = '';
|
if ($template === 'default') $template = '';
|
||||||
|
// Always use update_post_meta — wp_update_post template validation fails
|
||||||
|
// in CLI context. See 05-KNOWN-ISSUES.md.
|
||||||
update_post_meta($post_id, '_wp_page_template', $template);
|
update_post_meta($post_id, '_wp_page_template', $template);
|
||||||
if ($template && class_exists('\Elementor\Core\Files\CSS\Post')) (new \Elementor\Core\Files\CSS\Post($post_id))->update();
|
if ($template && class_exists('\Elementor\Core\Files\CSS\Post')) {
|
||||||
|
(new \Elementor\Core\Files\CSS\Post($post_id))->update();
|
||||||
|
}
|
||||||
return ['success' => true, 'post_id' => $post_id, 'template' => $template ?: 'default'];
|
return ['success' => true, 'post_id' => $post_id, 'template' => $template ?: 'default'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// REVISIONS
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function getRevisions(array $args): array {
|
public function getRevisions(array $args): array {
|
||||||
$post_id = (int)($args['post_id'] ?? 0);
|
$post_id = (int)($args['post_id'] ?? 0);
|
||||||
if (!$post_id) throw new \RuntimeException('post_id is required.');
|
if (!$post_id) throw new \RuntimeException('post_id is required.');
|
||||||
if (!class_exists('\Elementor\Plugin')) throw new \RuntimeException('Elementor not active.');
|
if (!class_exists('\Elementor\Plugin')) throw new \RuntimeException('Elementor not active.');
|
||||||
$revisions = \Elementor\Plugin::instance()->revisions_manager->get_revisions($post_id);
|
$revisions = \Elementor\Plugin::instance()->revisions_manager->get_revisions($post_id);
|
||||||
$clean = array_map(fn($r)=>['id'=>$r['id'],'type'=>$r['type'],'author'=>$r['author']??'','timestamp'=>$r['timestamp']??0], $revisions??[]);
|
$clean = array_map(fn($r) => [
|
||||||
|
'id' => $r['id'],
|
||||||
|
'type' => $r['type'],
|
||||||
|
'author' => $r['author'] ?? '',
|
||||||
|
'timestamp' => $r['timestamp'] ?? 0,
|
||||||
|
], $revisions ?? []);
|
||||||
return ['post_id' => $post_id, 'revisions' => $clean, 'total' => count($clean)];
|
return ['post_id' => $post_id, 'revisions' => $clean, 'total' => count($clean)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,23 +895,55 @@ class ElementorTools {
|
|||||||
if (!$post_id || !$revision_id) throw new \RuntimeException('post_id and revision_id are required.');
|
if (!$post_id || !$revision_id) throw new \RuntimeException('post_id and revision_id are required.');
|
||||||
if (!class_exists('\Elementor\Plugin')) throw new \RuntimeException('Elementor not active.');
|
if (!class_exists('\Elementor\Plugin')) throw new \RuntimeException('Elementor not active.');
|
||||||
\Elementor\Plugin::instance()->revisions_manager->restore_revision($post_id, $revision_id);
|
\Elementor\Plugin::instance()->revisions_manager->restore_revision($post_id, $revision_id);
|
||||||
if (class_exists('\Elementor\Core\Files\CSS\Post')) (new \Elementor\Core\Files\CSS\Post($post_id))->update();
|
if (class_exists('\Elementor\Core\Files\CSS\Post')) {
|
||||||
|
(new \Elementor\Core\Files\CSS\Post($post_id))->update();
|
||||||
|
}
|
||||||
return ['success' => true, 'post_id' => $post_id, 'restored_revision_id' => $revision_id];
|
return ['success' => true, 'post_id' => $post_id, 'restored_revision_id' => $revision_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// PERFORMANCE SETTINGS
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function getPerformanceSettings(array $args): array {
|
public function getPerformanceSettings(array $args): array {
|
||||||
return ['css_print_method'=>get_option('elementor_css_print_method','external'),'google_font'=>get_option('elementor_google_font','1'),'load_fa4_shim'=>get_option('elementor_load_fa4_shim',''),'lazy_load_background_images'=>get_option('elementor_lazy_load_background_images','1'),'meta_generator_tag'=>get_option('elementor_meta_generator_tag',''),'unfiltered_files_upload'=>get_option('elementor_unfiltered_files_upload',''),'font_display'=>get_option('elementor_font_display','auto'),'google_maps_api_key'=>get_option('elementor_google_maps_api_key',''),'element_cache_ttl'=>(int)get_option('elementor_element_cache_ttl',24),'optimized_gutenberg_loading'=>get_option('elementor_optimized_gutenberg_loading','1')];
|
return [
|
||||||
|
'css_print_method' => get_option('elementor_css_print_method', 'external'),
|
||||||
|
'google_font' => get_option('elementor_google_font', '1'),
|
||||||
|
'load_fa4_shim' => get_option('elementor_load_fa4_shim', ''),
|
||||||
|
'lazy_load_background_images' => get_option('elementor_lazy_load_background_images', '1'),
|
||||||
|
'meta_generator_tag' => get_option('elementor_meta_generator_tag', ''),
|
||||||
|
'unfiltered_files_upload' => get_option('elementor_unfiltered_files_upload', ''),
|
||||||
|
'font_display' => get_option('elementor_font_display', 'auto'),
|
||||||
|
'google_maps_api_key' => get_option('elementor_google_maps_api_key', ''),
|
||||||
|
'element_cache_ttl' => (int)get_option('elementor_element_cache_ttl', 24),
|
||||||
|
'optimized_gutenberg_loading' => get_option('elementor_optimized_gutenberg_loading', '1'),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatePerformanceSettings(array $args): array {
|
public function updatePerformanceSettings(array $args): array {
|
||||||
$settings = $args['settings'] ?? [];
|
$settings = $args['settings'] ?? [];
|
||||||
if (empty($settings)) throw new \RuntimeException('settings object is required.');
|
if (empty($settings)) throw new \RuntimeException('settings object is required.');
|
||||||
$map = ['css_print_method'=>['key'=>'elementor_css_print_method','allowed'=>['external','internal']],'google_font'=>['key'=>'elementor_google_font','allowed'=>['1','']],'load_fa4_shim'=>['key'=>'elementor_load_fa4_shim','allowed'=>['1','']],'lazy_load_background_images'=>['key'=>'elementor_lazy_load_background_images','allowed'=>['1','']],'meta_generator_tag'=>['key'=>'elementor_meta_generator_tag','allowed'=>['1','']],'unfiltered_files_upload'=>['key'=>'elementor_unfiltered_files_upload','allowed'=>['1','']],'font_display'=>['key'=>'elementor_font_display','allowed'=>['auto','block','swap','fallback','optional']],'google_maps_api_key'=>['key'=>'elementor_google_maps_api_key','allowed'=>null],'element_cache_ttl'=>['key'=>'elementor_element_cache_ttl','allowed'=>null,'type'=>'int'],'optimized_gutenberg_loading'=>['key'=>'elementor_optimized_gutenberg_loading','allowed'=>['1','']]];
|
$map = [
|
||||||
$updated = []; $errors = [];
|
'css_print_method' => ['key' => 'elementor_css_print_method', 'allowed' => ['external', 'internal']],
|
||||||
|
'google_font' => ['key' => 'elementor_google_font', 'allowed' => ['1', '']],
|
||||||
|
'load_fa4_shim' => ['key' => 'elementor_load_fa4_shim', 'allowed' => ['1', '']],
|
||||||
|
'lazy_load_background_images' => ['key' => 'elementor_lazy_load_background_images', 'allowed' => ['1', '']],
|
||||||
|
'meta_generator_tag' => ['key' => 'elementor_meta_generator_tag', 'allowed' => ['1', '']],
|
||||||
|
'unfiltered_files_upload' => ['key' => 'elementor_unfiltered_files_upload', 'allowed' => ['1', '']],
|
||||||
|
'font_display' => ['key' => 'elementor_font_display', 'allowed' => ['auto', 'block', 'swap', 'fallback', 'optional']],
|
||||||
|
'google_maps_api_key' => ['key' => 'elementor_google_maps_api_key', 'allowed' => null],
|
||||||
|
'element_cache_ttl' => ['key' => 'elementor_element_cache_ttl', 'allowed' => null, 'type' => 'int'],
|
||||||
|
'optimized_gutenberg_loading' => ['key' => 'elementor_optimized_gutenberg_loading', 'allowed' => ['1', '']],
|
||||||
|
];
|
||||||
|
$updated = [];
|
||||||
|
$errors = [];
|
||||||
foreach ($settings as $field => $value) {
|
foreach ($settings as $field => $value) {
|
||||||
if (!isset($map[$field])) { $errors[] = "Unknown field: {$field}"; continue; }
|
if (!isset($map[$field])) { $errors[] = "Unknown field: {$field}"; continue; }
|
||||||
$def = $map[$field];
|
$def = $map[$field];
|
||||||
if (!empty($def['allowed']) && !in_array((string)$value,$def['allowed'],true)) { $errors[] = "Invalid value for {$field}: {$value}."; continue; }
|
if (!empty($def['allowed']) && !in_array((string)$value, $def['allowed'], true)) {
|
||||||
|
$errors[] = "Invalid value for {$field}: {$value}.";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$write_val = isset($def['type']) && $def['type'] === 'int' ? (int)$value : (string)$value;
|
$write_val = isset($def['type']) && $def['type'] === 'int' ? (int)$value : (string)$value;
|
||||||
update_option($def['key'], $write_val);
|
update_option($def['key'], $write_val);
|
||||||
$updated[$field] = $write_val;
|
$updated[$field] = $write_val;
|
||||||
@@ -619,8 +951,14 @@ class ElementorTools {
|
|||||||
return ['success' => empty($errors), 'updated' => $updated, 'errors' => $errors];
|
return ['success' => empty($errors), 'updated' => $updated, 'errors' => $errors];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// CPT SUPPORT
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function getCptSupport(array $args): array {
|
public function getCptSupport(array $args): array {
|
||||||
return ['supported_post_types'=>(array)(get_option('elementor_cpt_support')?:['post','page']),'available_post_types'=>array_keys(get_post_types(['public'=>true],'names'))];
|
$supported = (array)(get_option('elementor_cpt_support') ?: ['post', 'page']);
|
||||||
|
$all_types = array_keys(get_post_types(['public' => true], 'names'));
|
||||||
|
return ['supported_post_types' => $supported, 'available_post_types' => $all_types];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setCptSupport(array $args): array {
|
public function setCptSupport(array $args): array {
|
||||||
@@ -633,10 +971,21 @@ class ElementorTools {
|
|||||||
return ['success' => true, 'supported_post_types' => $post_types];
|
return ['success' => true, 'supported_post_types' => $post_types];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// MAINTENANCE MODE
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function getMaintenanceMode(array $args): array {
|
public function getMaintenanceMode(array $args): array {
|
||||||
$mode = get_option('elementor_maintenance_mode_mode', '');
|
$mode = get_option('elementor_maintenance_mode_mode', '');
|
||||||
$page_id = (int)get_option('elementor_maintenance_mode_page_id', 0);
|
$page_id = (int)get_option('elementor_maintenance_mode_page_id', 0);
|
||||||
return ['mode'=>$mode?:'disabled','page_id'=>$page_id,'page_url'=>$page_id?get_permalink($page_id):'','exclude_mode'=>get_option('elementor_maintenance_mode_exclude_mode',''),'is_active'=>!empty($mode)];
|
$exclude_mode = get_option('elementor_maintenance_mode_exclude_mode', '');
|
||||||
|
return [
|
||||||
|
'mode' => $mode ?: 'disabled',
|
||||||
|
'page_id' => $page_id,
|
||||||
|
'page_url' => $page_id ? get_permalink($page_id) : '',
|
||||||
|
'exclude_mode' => $exclude_mode,
|
||||||
|
'is_active' => !empty($mode),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setMaintenanceMode(array $args): array {
|
public function setMaintenanceMode(array $args): array {
|
||||||
@@ -647,21 +996,49 @@ class ElementorTools {
|
|||||||
update_option('elementor_maintenance_mode_mode', $mode);
|
update_option('elementor_maintenance_mode_mode', $mode);
|
||||||
if ($page_id) update_option('elementor_maintenance_mode_page_id', $page_id);
|
if ($page_id) update_option('elementor_maintenance_mode_page_id', $page_id);
|
||||||
if ($exclude_mode !== '') update_option('elementor_maintenance_mode_exclude_mode', $exclude_mode);
|
if ($exclude_mode !== '') update_option('elementor_maintenance_mode_exclude_mode', $exclude_mode);
|
||||||
return ['success'=>true,'mode'=>$mode?:'disabled','page_id'=>$page_id?:(int)get_option('elementor_maintenance_mode_page_id',0),'exclude_mode'=>$exclude_mode?:get_option('elementor_maintenance_mode_exclude_mode','')];
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'mode' => $mode ?: 'disabled',
|
||||||
|
'page_id' => $page_id ?: (int)get_option('elementor_maintenance_mode_page_id', 0),
|
||||||
|
'exclude_mode' => $exclude_mode ?: get_option('elementor_maintenance_mode_exclude_mode', ''),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================
|
||||||
|
// SITE SETTINGS
|
||||||
|
// =========================================================
|
||||||
|
|
||||||
public function getSiteSettings(array $args): array {
|
public function getSiteSettings(array $args): array {
|
||||||
return ['google_maps_api_key'=>get_option('elementor_google_maps_api_key',''),'meta_generator_tag'=>get_option('elementor_meta_generator_tag',''),'google_font'=>get_option('elementor_google_font','1'),'font_display'=>get_option('elementor_font_display','auto'),'load_fa4_shim'=>get_option('elementor_load_fa4_shim',''),'unfiltered_files_upload'=>get_option('elementor_unfiltered_files_upload',''),'css_print_method'=>get_option('elementor_css_print_method','external'),'elementor_version'=>get_option('elementor_version',''),'pro_version'=>get_option('elementor_pro_version','')];
|
return [
|
||||||
|
'google_maps_api_key' => get_option('elementor_google_maps_api_key', ''),
|
||||||
|
'meta_generator_tag' => get_option('elementor_meta_generator_tag', ''),
|
||||||
|
'google_font' => get_option('elementor_google_font', '1'),
|
||||||
|
'font_display' => get_option('elementor_font_display', 'auto'),
|
||||||
|
'load_fa4_shim' => get_option('elementor_load_fa4_shim', ''),
|
||||||
|
'unfiltered_files_upload' => get_option('elementor_unfiltered_files_upload', ''),
|
||||||
|
'css_print_method' => get_option('elementor_css_print_method', 'external'),
|
||||||
|
'elementor_version' => get_option('elementor_version', ''),
|
||||||
|
'pro_version' => get_option('elementor_pro_version', ''),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateSiteSettings(array $args): array {
|
public function updateSiteSettings(array $args): array {
|
||||||
$settings = $args['settings'] ?? [];
|
$settings = $args['settings'] ?? [];
|
||||||
if (empty($settings)) throw new \RuntimeException('settings object is required.');
|
if (empty($settings)) throw new \RuntimeException('settings object is required.');
|
||||||
$allowed = ['google_maps_api_key'=>'elementor_google_maps_api_key','meta_generator_tag'=>'elementor_meta_generator_tag','google_font'=>'elementor_google_font','font_display'=>'elementor_font_display','load_fa4_shim'=>'elementor_load_fa4_shim','unfiltered_files_upload'=>'elementor_unfiltered_files_upload','css_print_method'=>'elementor_css_print_method'];
|
$allowed_fields = [
|
||||||
$updated = []; $errors = [];
|
'google_maps_api_key' => 'elementor_google_maps_api_key',
|
||||||
|
'meta_generator_tag' => 'elementor_meta_generator_tag',
|
||||||
|
'google_font' => 'elementor_google_font',
|
||||||
|
'font_display' => 'elementor_font_display',
|
||||||
|
'load_fa4_shim' => 'elementor_load_fa4_shim',
|
||||||
|
'unfiltered_files_upload' => 'elementor_unfiltered_files_upload',
|
||||||
|
'css_print_method' => 'elementor_css_print_method',
|
||||||
|
];
|
||||||
|
$updated = [];
|
||||||
|
$errors = [];
|
||||||
foreach ($settings as $field => $value) {
|
foreach ($settings as $field => $value) {
|
||||||
if (!isset($allowed[$field])) { $errors[] = "Unknown or read-only field: {$field}"; continue; }
|
if (!isset($allowed_fields[$field])) { $errors[] = "Unknown or read-only field: {$field}"; continue; }
|
||||||
update_option($allowed[$field], (string)$value);
|
update_option($allowed_fields[$field], (string)$value);
|
||||||
$updated[$field] = (string)$value;
|
$updated[$field] = (string)$value;
|
||||||
}
|
}
|
||||||
return ['success' => empty($errors), 'updated' => $updated, 'errors' => $errors];
|
return ['success' => empty($errors), 'updated' => $updated, 'errors' => $errors];
|
||||||
@@ -671,10 +1048,7 @@ class ElementorTools {
|
|||||||
// PRIVATE HELPERS
|
// PRIVATE HELPERS
|
||||||
// =========================================================
|
// =========================================================
|
||||||
|
|
||||||
/**
|
/** Inserts $element immediately after $target_id (by-reference). */
|
||||||
* Inserts $element immediately after $target_id in the tree (by-reference).
|
|
||||||
* Mirrors insert_after() from Elementor_MCP_Layout_Abilities v1.9.0.
|
|
||||||
*/
|
|
||||||
private function insertAfter(array &$data, string $target_id, array $element): bool {
|
private function insertAfter(array &$data, string $target_id, array $element): bool {
|
||||||
foreach ($data as $index => &$item) {
|
foreach ($data as $index => &$item) {
|
||||||
if (isset($item['id']) && $item['id'] === $target_id) {
|
if (isset($item['id']) && $item['id'] === $target_id) {
|
||||||
@@ -688,6 +1062,23 @@ class ElementorTools {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Walks $data (by-reference), finds $container_id, replaces its children. */
|
||||||
|
private function applyChildReorder(array &$data, string $container_id, array $new_children): bool {
|
||||||
|
foreach ($data as &$item) {
|
||||||
|
if (isset($item['id']) && $item['id'] === $container_id) {
|
||||||
|
$item['elements'] = $new_children;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!empty($item['elements']) && is_array($item['elements'])) {
|
||||||
|
if ($this->applyChildReorder($item['elements'], $container_id, $new_children)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Legacy helper used by addWidget fallback path (by-value). */
|
||||||
private function insertIntoParent(array $elements, string $parent_id, array $element, int $position): array {
|
private function insertIntoParent(array $elements, string $parent_id, array $element, int $position): array {
|
||||||
foreach ($elements as &$el) {
|
foreach ($elements as &$el) {
|
||||||
if (($el['id'] ?? '') === $parent_id) {
|
if (($el['id'] ?? '') === $parent_id) {
|
||||||
|
|||||||
Reference in New Issue
Block a user