# elementor/4.3.2/modules/mcp/abilities/build-composition/subtree-builder.php

Elementor Website Builder – more than just a page builder, version 4.3.2. 114 lines.

- Page: https://pluginprobe.com/plugins/elementor/4.3.2/code/modules/mcp/abilities/build-composition/subtree-builder.php
- Raw: https://pluginprobe.com/plugins/elementor/4.3.2/raw/modules/mcp/abilities/build-composition/subtree-builder.php
- Modified: 2026-09-01T11:47:36+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/elementor/4.3.2/code/modules/mcp/abilities/build-composition/subtree-builder.php#L10-L20`.

```php
<?php

namespace Elementor\Modules\Mcp\Abilities\Build_Composition;

use Elementor\Modules\Mcp\Abilities\Appliers\V3_Node_Bridge;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class Subtree_Builder {

	private Xml_Parser $xml_parser;

	public function __construct( Xml_Parser $xml_parser ) {
		$this->xml_parser = $xml_parser;
	}

	/**
	 * @param \DOMDocument         $dom            XML document.
	 * @param array<string, array> $widget_configs Resolved type configs indexed by tag.
	 * @return array[]
	 */
	public function build( \DOMDocument $dom, array $widget_configs ): array {
		$root = $this->xml_parser->get_root( $dom );
		if ( ! $root ) {
			return [];
		}

		$subtrees = [];
		foreach ( $this->xml_parser->get_child_elements( $root ) as $child ) {
			$subtrees[] = $this->build_subtree( $child, $widget_configs );
		}

		return $subtrees;
	}

	/**
	 * Build an index of configuration-id -> reference to subtree node.
	 *
	 * @param array[]      $subtrees Built subtrees (mutated by reference downstream).
	 * @param \DOMDocument $dom      Source DOM.
	 * @return array<string, array&>
	 */
	public function index_by_config_id( array &$subtrees, \DOMDocument $dom ): array {
		$root = $this->xml_parser->get_root( $dom );
		if ( ! $root ) {
			return [];
		}

		$dom_roots = $this->xml_parser->get_child_elements( $root );
		$index = [];

		foreach ( $subtrees as $i => &$subtree ) {
			if ( isset( $dom_roots[ $i ] ) ) {
				$this->index_recursive( $subtree, $dom_roots[ $i ], $index );
			}
		}
		unset( $subtree );

		return $index;
	}

	private function build_subtree( \DOMElement $node, array $widget_configs ): array {
		$config = $widget_configs[ $this->xml_parser->get_tag_name( $node ) ];

		$children = [];
		foreach ( $this->xml_parser->get_child_elements( $node ) as $child ) {
			$children[] = $this->build_subtree( $child, $widget_configs );
		}

		$element = [
			'elType' => $config['elType'],
			'settings' => [],
			'elements' => $children,
			'editor_settings' => [],
		];

		if ( ! empty( $config['widgetType'] ) ) {
			$element['widgetType'] = $config['widgetType'];
		}

		$configuration_id = $this->xml_parser->get_configuration_id( $node );
		if ( null !== $configuration_id ) {
			$element['editor_settings']['title'] = $configuration_id;
		}

		if ( ! empty( $config['controls'] ) && V3_Node_Bridge::is_v3_node( $element ) ) {
			V3_Node_Bridge::seed_dynamic_defaults( $element, $config['controls'] );
		}

		return $element;
	}

	private function index_recursive( array &$subtree, \DOMElement $node, array &$index ): void {
		$configuration_id = $this->xml_parser->get_configuration_id( $node );
		if ( null !== $configuration_id ) {
			$index[ $configuration_id ] = &$subtree;
		}

		if ( ! isset( $subtree['elements'] ) || ! is_array( $subtree['elements'] ) ) {
			return;
		}

		$child_elements = $this->xml_parser->get_child_elements( $node );
		foreach ( $subtree['elements'] as $i => &$child_subtree ) {
			if ( isset( $child_elements[ $i ] ) ) {
				$this->index_recursive( $child_subtree, $child_elements[ $i ], $index );
			}
		}
		unset( $child_subtree );
	}
}

```
