Reputation: 913
Here is my block of html
$html = '<div class="importantnoticediv">
<p class="important-notice-title important-notice-title-1">
NOTICE:
</p>
<p class="important-notice-title important-notice-title-2">
PROFESSIONAL INSTALLATION IS RECOMMENDED!
</p>
</div>';
I'm able to initiate a new DOMDocument
and target this specific DIV class using DOMXpath
$dom = new DOMDocument;
$dom->loadHTML($post_content);
$xpath = new DOMXpath($dom);
$importantnotice = $xpath->query('//div[contains(@class, "importantnoticediv")]');
$indiv = $importantnotice->item(0);
I'm having a very hard time figuring out how to append the HTML I want to this class, though.
Here's what I'm trying to transform my block of html into:
<div class="importantnoticediv">
<div class="note-icon note-icon-important">
<span><i class="fa fa-exclamation" aria-hidden="true"></i>
</span>
</div>
<div class="note-text note-text-important">
<p class="important-notice-title important-notice-title-1">
NOTICE:
</p>
<p class="important-notice-title important-notice-title-2">
PROFESSIONAL INSTALLATION IS RECOMMENDED!
</p>
</div>
</div>
So, in other words,
<div class="note-icon note-icon-important">
<span><i class="fa fa-exclamation" aria-hidden="true"></i>
</span>
</div>
<div class="note-text note-text-important">
Immediately after my <div class="importantnoticediv">
as well as add a closing </div>
at the very end of this div class.
Is this even possible with DOMDocument
and DOMXpath
? Given that what I am trying to add isn't "valid" html (even though it is, once I do the two steps..)
I understand I can create new elements, but how do I insert just a custom html string immediately after the start and end of my chosen DOMDocument
/DOMXpath
?
Upvotes: 3
Views: 2384
Reputation: 22783
Here's one way to do it. It makes use of DOMDocumentFragment
. Admittedly, it's all a bit convoluted.
Furthermore, one problem with DOMDocumentFragment
is that, besides appendXML()
, it does not have a counterpart method appendHTML()
, which means you can only append HTML to it if it validates as XML.
$html = '<div class="importantnoticediv">
<p class="important-notice-title important-notice-title-1">
NOTICE:
</p>
<p class="important-notice-title important-notice-title-2">
PROFESSIONAL INSTALLATION IS RECOMMENDED!
</p>
</div>';
$dom = new DOMDocument;
// format our output to make it a tad bit easier on the eyes (doesn't help all that much, though)
$dom->formatOutput = true;
// this implicitly adds <html> and <body> tags
$dom->loadHTML( $html );
$xpath = new DOMXpath( $dom );
// notice I appended /p to your original query, so that we get the list of <p> elements inside the "importantnoticediv"
$nodes = $xpath->query('//div[contains(@class, "importantnoticediv")]/p');
// the first <p>
$p1 = $nodes->item( 0 );
// the second <p>
$p2 = $nodes->item( 1 );
// we create a DOMDocumentFragment that is associated with our DOMDocument
$frag = $dom->createDocumentFragment();
// I append your first HTML fragment (must be valid XML)
$frag->appendXML( '<div class="note-icon note-icon-important">
<span><i class="fa fa-exclamation" aria-hidden="true"></i>
</span>
</div>' );
// ... and insert it before our first <p> (parentNode is the "importantnoticediv")
$p1->parentNode->insertBefore( $frag, $p1 );
// frag is now empty again, because we just inserted it(s contents) into the DOMDocument
// we create our second fragment
$frag->appendXML( '<div class="note-text note-text-important"></div>' );
// this time we append it to "importantnoticediv" (i.e. as last child)
// and get the reference to this newly inserted <div>
$insertedNode = $p1->parentNode->appendChild( $frag );
// now we can append (i.e. move) the <p> elements to the newly inserted <div>
$insertedNode->appendChild( $p1 );
$insertedNode->appendChild( $p2 );
// the HTML should now be as desired
echo $dom->saveHTML();
Upvotes: 5