builder_slug; } /** * Get section tag name. * * @return string */ public function get_section_name(): string { return $this->section_name; } /** * Extract builder section from full XML document. * * @param string $xml_string * @return string */ public function extract_section( string $xml_string ): string { if ( empty( trim( $xml_string ) ) ) { return ''; } libxml_use_internal_errors( true ); if ( false !== stripos( $xml_string, '{$this->section_name} ) ) { libxml_clear_errors(); return ''; } $wrapper = new SimpleXMLElement( '' ); self::simplexml_append_child( $wrapper, $xml->{$this->section_name} ); return self::format_simplexml_to_string( $wrapper ); } /** * Get default XML skeleton for this builder. * * @return string */ abstract public function get_default_skeleton(): string; /** * Extract exact widget/block snippet from an XML document. * * @param SimpleXMLElement $xml * @param string $name * @return string|null */ abstract public function extract_widget_snippet( SimpleXMLElement $xml, string $name ); /** * Build a standalone XML snippet from fields array. * * @param string $name * @param array $field_details * @return string */ abstract public function generate_snippet( string $name, array $field_details ): string; /** * Sync an existing DOM element with a new SimpleXMLElement definition. * Preserves removed keys/fields by setting noTranslate="true". * * @param DOMElement $existing_elem * @param SimpleXMLElement $new_elem * @return void */ abstract public function sync_node( DOMElement $existing_elem, SimpleXMLElement $new_elem ): void; /** * Append or update a rule in the builder XML. * * @param SimpleXMLElement $xml * @param string $name * @param array $field_details * @return void */ abstract public function append_rule( SimpleXMLElement $xml, string $name, array $field_details ): void; /** * Parse rules from SimpleXMLElement into the rules array. * * @param SimpleXMLElement $xml * @param array $rules * @param string $source * @return void */ abstract public function parse_rules( SimpleXMLElement $xml, array &$rules, string $source = 'core' ): void; /** * Helper: Wrap SimpleXMLElement node in .... * * @param SimpleXMLElement $node * @param string $section_name * @return string */ public static function wrap_node_in_config( SimpleXMLElement $node, string $section_name ): string { $wrapper = new SimpleXMLElement( '<' . $section_name . '>' ); self::simplexml_append_child( $wrapper->{$section_name}, $node ); return self::format_simplexml_to_string( $wrapper ); } /** * Helper: Format SimpleXMLElement into pretty printed XML string. * * @param SimpleXMLElement $xml * @return string */ public static function format_simplexml_to_string( SimpleXMLElement $xml ): string { $dom = new DOMDocument( '1.0' ); $dom->preserveWhiteSpace = false; $dom->formatOutput = true; $dom->loadXML( $xml->asXML(), LIBXML_NONET ); return $dom->saveXML(); } /** * Helper: Append SimpleXMLElement child recursively. * * @param SimpleXMLElement $to * @param SimpleXMLElement $from * @return void */ public static function simplexml_append_child( SimpleXMLElement $to, SimpleXMLElement $from ): void { $to_dom = dom_import_simplexml( $to ); $from_dom = dom_import_simplexml( $from ); $to_dom->appendChild( $to_dom->ownerDocument->importNode( $from_dom, true ) ); } }