I am making use of PHP's DOMDocument to carry out two DOM operations on the post content, by filtering the_content:

The trouble is, it seems like DOMDocument is destroying embedded WordPress content like tweets. As seen in this example, the embedded tweet is not rendered as an <iframe> as it should be, it is just rendered using <p>.

Is there a way to stop DOMDocument from doing this?

My code is below.

Wrap element in another element.
Contributed by @XzKto, https://stackoverflow.com/a/8428323/1375163
function wrap_element($dom, $wrapped_element, $new_element) {
    // Initialise the new wrapper
    $wrapper = $dom->createElement($new_element);
    //Clone our created element
    $wrapper_clone = $wrapper->cloneNode();
    //Replace image with this wrapper div
    //Append the element to wrapper div

add_filter( 'the_content', 'bootstrap_blockquote' );
function bootstrap_blockquote( $content ) {
    // Load DOM of post content
    $dom = new DOMDocument();

    foreach($dom->getElementsByTagName('blockquote') as $blockquote){
        // Add blockquote class
        // Class addition contributed by @Gillu13, https://stackoverflow.com/a/63088684/1375163
        $class_to_add = 'blockquote';
        $blockquote->setAttribute('class', $class_to_add);
        // Wrap blockquote in <figure>
        wrap_element($dom, $blockquote, 'figure');

    $content = utf8_decode($dom->saveHTML($dom->documentElement)); // formatting correction contributed by @Greeso, https://stackoverflow.com/a/20675396/1375163
    return $content;


Original contributed by @jack,
add_filter( 'the_content', 'segment_post' );
function segment_post( $content ) {

    $d = new DOMDocument;

    $segments = array(); $card = null;

    foreach ($d->getElementsByTagName('h3') as $h3) {
        // first collect all nodes
        $card_nodes = array($h3);
        // iterate until another h3 or no more siblings
        for ($next = $h3->nextSibling; $next && $next->nodeName != 'h3'; $next = $next->nextSibling) {
            $card_nodes[] = $next;

        // create the wrapper node
        $card = $d->createElement('div');
        $card->setAttribute('class', 'card p-4 mb-3');

        // replace the h3 with the new card
        $h3->parentNode->replaceChild($card, $h3);
        // and move all nodes into the newly created card
        foreach ($card_nodes as $node) {
        // keep title of the original h3
        $segments[] = $h3->nodeValue;

    //  make sure we have segments (card is the last inserted card in the dom)
    if ($segments && $card) {
        $ul = $d->createElement('ul');
        foreach ($segments as $title) {
            $li = $d->createElement('li');

            $a = $d->createElement('a', $title);
            $a->setAttribute('href', '#');


        // add as sibling of last card added

    // TODO: examine https://stackoverflow.com/questions/10703057/wrap-all-html-tags-between-h3-tag-sets-with-domdocument-in-php

    $content = utf8_decode($d->saveHTML($d->documentElement)); // formatting correction contributed by @Greeso, https://stackoverflow.com/a/20675396/1375163    
    return $content;

enter image description here enter image description here


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.