register( 'elementor_widgets_list', array( 'description' => 'List available Elementor widgets.', 'domain' => 'elementor', 'capability' => 'edit_pages', 'inputSchema' => array( 'type' => 'object', 'properties' => array() ), ), function () { $widgets = array(); if ( class_exists( '\Elementor\Plugin' ) ) { $manager = \Elementor\Plugin::$instance->widgets_manager; foreach ( $manager->get_widget_types() as $name => $widget ) { $widgets[] = array( 'name' => $name, 'title' => $widget->get_title(), 'categories' => $widget->get_categories(), ); } } return array( 'widgets' => $widgets ); } ); $registry->register( 'elementor_page_create', array( 'description' => 'Create a new Elementor page with optional initial structure.', 'domain' => 'elementor', 'capability' => 'edit_pages', 'inputSchema' => array( 'type' => 'object', 'properties' => array( 'title' => array( 'type' => 'string' ), 'status' => array( 'type' => 'string', 'default' => 'draft' ), 'structure' => array( 'type' => 'array', 'description' => 'Optional Elementor element tree' ), 'canvas' => array( 'type' => 'boolean', 'description' => 'Use Elementor Canvas template (no theme header/footer)' ), ), 'required' => array( 'title' ), ), ), function ( $args ) { $status = isset( $args['status'] ) ? sanitize_key( $args['status'] ) : 'draft'; $allowed = Agentdesk_Security::can_create_post( 'page', $status ); if ( is_wp_error( $allowed ) ) { return $allowed; } $post_id = wp_insert_post( array( 'post_title' => sanitize_text_field( $args['title'] ), 'post_type' => 'page', 'post_status' => $status, ), true ); if ( is_wp_error( $post_id ) ) { return $post_id; } $structure = isset( $args['structure'] ) && is_array( $args['structure'] ) ? $args['structure'] : agentdesk_elementor_default_structure(); $structure = Agentdesk_Security::sanitize_elementor_tree( $structure ); if ( is_wp_error( $structure ) ) { return $structure; } update_post_meta( $post_id, '_elementor_data', wp_slash( wp_json_encode( $structure ) ) ); update_post_meta( $post_id, '_elementor_edit_mode', 'builder' ); update_post_meta( $post_id, '_elementor_version', ELEMENTOR_VERSION ); if ( ! empty( $args['canvas'] ) ) { update_post_meta( $post_id, '_wp_page_template', 'elementor_canvas' ); update_post_meta( $post_id, '_elementor_page_settings', array( 'hide_title' => 'yes', ) ); } return array( 'post_id' => $post_id, 'link' => get_permalink( $post_id ) ); } ); $registry->register( 'elementor_widget_add', array( 'description' => 'Add a widget to an Elementor document at a container path.', 'domain' => 'elementor', 'capability' => 'edit_pages', 'power_mode' => true, 'inputSchema' => array( 'type' => 'object', 'properties' => array( 'post_id' => array( 'type' => 'integer' ), 'container_id' => array( 'type' => 'string', 'description' => 'Element ID of parent container' ), 'widget_type' => array( 'type' => 'string' ), 'settings' => array( 'type' => 'object' ), ), 'required' => array( 'post_id', 'widget_type' ), ), ), function ( $args ) { $post_id = absint( $args['post_id'] ); $data = agentdesk_elementor_get_data( $post_id ); if ( is_wp_error( $data ) ) { return $data; } $widget = agentdesk_elementor_create_element( 'widget', sanitize_key( $args['widget_type'] ), isset( $args['settings'] ) && is_array( $args['settings'] ) ? $args['settings'] : array() ); $container_id = isset( $args['container_id'] ) ? sanitize_text_field( $args['container_id'] ) : ''; if ( $container_id ) { $updated = agentdesk_elementor_append_to_container( $data, $container_id, $widget ); if ( is_wp_error( $updated ) ) { return $updated; } $data = $updated; } else { $data[] = $widget; } $saved = agentdesk_elementor_save_data( $post_id, $data ); if ( is_wp_error( $saved ) ) { return $saved; } return array( 'post_id' => $post_id, 'widget_id' => $widget['id'] ); } ); $registry->register( 'elementor_container_add', array( 'description' => 'Add a container/section to an Elementor document.', 'domain' => 'elementor', 'capability' => 'edit_pages', 'power_mode' => true, 'inputSchema' => array( 'type' => 'object', 'properties' => array( 'post_id' => array( 'type' => 'integer' ), 'settings'=> array( 'type' => 'object' ), ), 'required' => array( 'post_id' ), ), ), function ( $args ) { $post_id = absint( $args['post_id'] ); $data = agentdesk_elementor_get_data( $post_id ); if ( is_wp_error( $data ) ) { return $data; } $el_type = version_compare( ELEMENTOR_VERSION, '3.0', '>=' ) ? 'container' : 'section'; $container = agentdesk_elementor_create_element( $el_type, $el_type, isset( $args['settings'] ) && is_array( $args['settings'] ) ? $args['settings'] : array() ); $data[] = $container; $saved = agentdesk_elementor_save_data( $post_id, $data ); if ( is_wp_error( $saved ) ) { return $saved; } return array( 'post_id' => $post_id, 'container_id' => $container['id'] ); } ); $registry->register( 'elementor_structure_get', array( 'description' => 'Get simplified Elementor page structure tree (IDs, types, widget types).', 'domain' => 'elementor', 'capability' => 'edit_pages', 'inputSchema' => array( 'type' => 'object', 'properties' => array( 'post_id' => array( 'type' => 'integer' ) ), 'required' => array( 'post_id' ), ), ), function ( $args ) { $data = agentdesk_elementor_get_data( absint( $args['post_id'] ) ); if ( is_wp_error( $data ) ) { return $data; } return array( 'structure' => agentdesk_elementor_simplify_tree( $data ) ); } ); $registry->register( 'elementor_template_import', array( 'description' => 'Import Elementor template JSON into a post.', 'domain' => 'elementor', 'capability' => 'edit_pages', 'power_mode' => true, 'inputSchema' => array( 'type' => 'object', 'properties' => array( 'post_id' => array( 'type' => 'integer' ), 'template' => array( 'type' => 'array' ), ), 'required' => array( 'post_id', 'template' ), ), ), function ( $args ) { $post_id = absint( $args['post_id'] ); $template = $args['template']; $content = isset( $template['content'] ) ? $template['content'] : $template; $saved = agentdesk_elementor_save_data( $post_id, $content ); if ( is_wp_error( $saved ) ) { return $saved; } return array( 'imported' => true, 'post_id' => $post_id ); } ); $registry->register( 'elementor_template_export', array( 'description' => 'Export Elementor document as template JSON.', 'domain' => 'elementor', 'capability' => 'edit_pages', 'inputSchema' => array( 'type' => 'object', 'properties' => array( 'post_id' => array( 'type' => 'integer' ) ), 'required' => array( 'post_id' ), ), ), function ( $args ) { $data = agentdesk_elementor_get_data( absint( $args['post_id'] ) ); if ( is_wp_error( $data ) ) { return $data; } return array( 'title' => get_the_title( absint( $args['post_id'] ) ), 'content' => $data, 'version' => ELEMENTOR_VERSION, ); } ); $registry->register( 'elementor_build_from_brief', array( 'description' => 'Composite workflow: create Elementor page with hero heading + text + button from a brief.', 'domain' => 'elementor', 'capability' => 'edit_pages', 'inputSchema' => array( 'type' => 'object', 'properties' => array( 'title' => array( 'type' => 'string' ), 'headline' => array( 'type' => 'string' ), 'subtext' => array( 'type' => 'string' ), 'cta_text' => array( 'type' => 'string' ), 'cta_url' => array( 'type' => 'string' ), 'status' => array( 'type' => 'string', 'default' => 'draft' ), ), 'required' => array( 'title', 'headline' ), ), ), function ( $args ) { $status = isset( $args['status'] ) ? sanitize_key( $args['status'] ) : 'draft'; $allowed = Agentdesk_Security::can_create_post( 'page', $status ); if ( is_wp_error( $allowed ) ) { return $allowed; } $structure = agentdesk_elementor_build_hero_structure( sanitize_text_field( $args['headline'] ), isset( $args['subtext'] ) ? sanitize_textarea_field( $args['subtext'] ) : '', isset( $args['cta_text'] ) ? sanitize_text_field( $args['cta_text'] ) : '', isset( $args['cta_url'] ) ? esc_url_raw( $args['cta_url'] ) : '' ); $post_id = wp_insert_post( array( 'post_title' => sanitize_text_field( $args['title'] ), 'post_type' => 'page', 'post_status' => $status, ), true ); if ( is_wp_error( $post_id ) ) { return $post_id; } $saved = agentdesk_elementor_save_data( $post_id, $structure ); if ( is_wp_error( $saved ) ) { return $saved; } return array( 'post_id' => $post_id, 'link' => get_permalink( $post_id ), 'message' => 'Hero page created from brief', ); } ); } ); /** * Get Elementor data array. * * @param int $post_id Post ID. * @return array|WP_Error */ function agentdesk_elementor_get_data( $post_id ) { $allowed = Agentdesk_Security::can_read_post( $post_id ); if ( is_wp_error( $allowed ) ) { return $allowed; } $raw = get_post_meta( $post_id, '_elementor_data', true ); if ( empty( $raw ) ) { return array(); } return is_string( $raw ) ? json_decode( $raw, true ) : $raw; } /** * Save Elementor data. * * @param int $post_id Post ID. * @param array $data Data. */ function agentdesk_elementor_save_data( $post_id, $data ) { $allowed = Agentdesk_Security::can_edit_post( $post_id ); if ( is_wp_error( $allowed ) ) { return $allowed; } $data = Agentdesk_Security::sanitize_elementor_tree( $data ); if ( is_wp_error( $data ) ) { return $data; } update_post_meta( $post_id, '_elementor_data', wp_slash( wp_json_encode( $data ) ) ); update_post_meta( $post_id, '_elementor_edit_mode', 'builder' ); update_post_meta( $post_id, '_elementor_version', ELEMENTOR_VERSION ); agentdesk_elementor_clear_cache( $post_id ); return true; } /** * Create Elementor element node. * * @param string $el_type Element type. * @param string $widget_type Widget type. * @param array $settings Settings. * @return array */ function agentdesk_elementor_create_element( $el_type, $widget_type, $settings = array() ) { return array( 'id' => agentdesk_elementor_generate_id(), 'elType' => $el_type, 'widgetType' => 'widget' === $el_type ? $widget_type : null, 'settings' => $settings, 'elements' => array(), 'isInner' => false, ); } /** * Generate Elementor-style element ID. * * @return string */ function agentdesk_elementor_generate_id() { return dechex( wp_rand( 0, 0xFFFFFFF ) ); } /** * Default empty container structure. * * @return array */ function agentdesk_elementor_default_structure() { $el_type = defined( 'ELEMENTOR_VERSION' ) && version_compare( ELEMENTOR_VERSION, '3.0', '>=' ) ? 'container' : 'section'; return array( agentdesk_elementor_create_element( $el_type, $el_type, array() ) ); } /** * Append element to container by ID. * * @param array $tree Element tree. * @param string $container_id Container ID. * @param array $element Element to add. * @return array|WP_Error */ function agentdesk_elementor_append_to_container( $tree, $container_id, $element ) { $found = agentdesk_elementor_walk_tree( $tree, $container_id, function ( &$node ) use ( $element ) { if ( ! isset( $node['elements'] ) ) { $node['elements'] = array(); } $node['elements'][] = $element; return true; } ); if ( ! $found ) { return new WP_Error( 'agentdesk_container_not_found', 'Container not found in document' ); } return $tree; } /** * Walk element tree. * * @param array $tree Tree. * @param string $target_id Target ID. * @param callable $callback Callback. * @return bool */ function agentdesk_elementor_walk_tree( &$tree, $target_id, $callback ) { foreach ( $tree as &$node ) { if ( isset( $node['id'] ) && $node['id'] === $target_id ) { return (bool) $callback( $node ); } if ( ! empty( $node['elements'] ) ) { if ( agentdesk_elementor_walk_tree( $node['elements'], $target_id, $callback ) ) { return true; } } } return false; } /** * Simplify tree for overview. * * @param array $tree Tree. * @return array */ function agentdesk_elementor_simplify_tree( $tree ) { $out = array(); foreach ( $tree as $node ) { $item = array( 'id' => $node['id'] ?? '', 'elType' => $node['elType'] ?? '', ); if ( ! empty( $node['widgetType'] ) ) { $item['widgetType'] = $node['widgetType']; } if ( ! empty( $node['elements'] ) ) { $item['children'] = agentdesk_elementor_simplify_tree( $node['elements'] ); } $out[] = $item; } return $out; } /** * Build hero section structure. * * @param string $headline Headline. * @param string $subtext Subtext. * @param string $cta_text CTA text. * @param string $cta_url CTA URL. * @return array */ function agentdesk_elementor_build_hero_structure( $headline, $subtext, $cta_text, $cta_url ) { $el_type = version_compare( ELEMENTOR_VERSION, '3.0', '>=' ) ? 'container' : 'section'; $container = agentdesk_elementor_create_element( $el_type, $el_type, array( 'content_width' => 'full' ) ); $heading = agentdesk_elementor_create_element( 'widget', 'heading', array( 'title' => $headline, 'header_size' => 'h1' ) ); $container['elements'][] = $heading; if ( $subtext ) { $text = agentdesk_elementor_create_element( 'widget', 'text-editor', array( 'editor' => $subtext ) ); $container['elements'][] = $text; } if ( $cta_text && $cta_url ) { $button = agentdesk_elementor_create_element( 'widget', 'button', array( 'text' => $cta_text, 'link' => array( 'url' => $cta_url ) ) ); $container['elements'][] = $button; } return array( $container ); }