scarhand
scarhand

Reputation: 4337

Using DOM to insert a DIV after an IMG with a specific class

So this is for WordPress. What I'm trying to do is create a little modification within the functions.php file of my theme. All I want to do is get the ID of the WordPress image and then add a <div> after the image itself IF the image contains the class dd-star-rating.

Notes:

Heres an example of what is stored in the $content variable:

<p>Nunc et neque risus. Nam a nisl eu magna rutrum euismod ac in lorem. Aenean varius accumsan ligula tincidunt malesuada. In diam lectus, pharetra quis cursus in, egestas vitae tellus. In neque arcu, aliquet ut egestas in, ultrices id ligula. Suspendisse ut dolor ligula, sit amet placerat ligula. Ut viverra nisi id ante facilisis pharetra. Aenean scelerisque, leo eget accumsan condimentum, odio libero ultrices enim, pretium placerat sapien purus nec odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur bibendum viverra pellentesque. Pellentesque eu diam non eros consectetur semper nec sed nisl.</p>

<p style="text-align: center;"><img class="size-full wp-image-44 aligncenter concept dd-star-rating" alt="concept" src="http://www.mysite.com/wp-content/uploads/2012/12/concept.png" width="720" height="540" /></p>

<p style="text-align: center;"><img class="size-full wp-image-45 aligncenter concept dd-star-rating" alt="concept" src="http://www.mysite.com/wp-content/uploads/2012/12/concept2.png" width="720" height="540" /></p>

<p>Nulla eros ante, lobortis in convallis eget, dignissim ut quam. Proin nisi nunc, iaculis ac auctor eu, tincidunt ac augue. Nunc purus nisi, sollicitudin nec luctus ullamcorper, dictum id magna. Sed quis nisi sagittis sapien placerat semper vitae tempus leo. Suspendisse sem diam, eleifend in blandit sed, pellentesque ac nisl. Morbi tincidunt adipiscing augue in pharetra. Duis dapibus bibendum egestas. Phasellus dictum dapibus quam id fermentum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>

So for those 2 images, since they contain the dd-star-rating class, I want the value of the $content variable to change to this:

<p>Nunc et neque risus. Nam a nisl eu magna rutrum euismod ac in lorem. Aenean varius accumsan ligula tincidunt malesuada. In diam lectus, pharetra quis cursus in, egestas vitae tellus. In neque arcu, aliquet ut egestas in, ultrices id ligula. Suspendisse ut dolor ligula, sit amet placerat ligula. Ut viverra nisi id ante facilisis pharetra. Aenean scelerisque, leo eget accumsan condimentum, odio libero ultrices enim, pretium placerat sapien purus nec odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur bibendum viverra pellentesque. Pellentesque eu diam non eros consectetur semper nec sed nisl.</p>

<p style="text-align: center;"><img class="size-full wp-image-44 aligncenter concept dd-star-rating" alt="concept" src="http://www.mysite.com/wp-content/uploads/2012/12/concept.png" width="720" height="540" /></p>
<div>Star Rating ID = 44</div>

<p style="text-align: center;"><img class="size-full wp-image-45 aligncenter concept dd-star-rating" alt="concept" src="http://www.mysite.com/wp-content/uploads/2012/12/concept2.png" width="720" height="540" /></p>
<div>Star Rating ID = 45</div>

<p>Nulla eros ante, lobortis in convallis eget, dignissim ut quam. Proin nisi nunc, iaculis ac auctor eu, tincidunt ac augue. Nunc purus nisi, sollicitudin nec luctus ullamcorper, dictum id magna. Sed quis nisi sagittis sapien placerat semper vitae tempus leo. Suspendisse sem diam, eleifend in blandit sed, pellentesque ac nisl. Morbi tincidunt adipiscing augue in pharetra. Duis dapibus bibendum egestas. Phasellus dictum dapibus quam id fermentum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>

Now here is my code so far, in my themes functions.php file:

add_filter( 'the_content' , 'dd_wrap_image' );

function dd_wrap_image ( $content )
{    
    $dom = new DOMDocument;
    $dom->loadHTML($content);
    $imgs = $dom->getElementsByTagName('img');

    foreach($imgs as $img)
    {
        if ($img->hasAttribute('class') && strstr($img->getAttribute('class'), 'dd-star-rating'))
        {                
            // get the "wp-image-X" ID and store into $id variable
            // add "<div>Star Rating ID = $id</div>" after image

            $class_array = explode(' ', $img->getAttribute('class'));

            foreach ($class_array as $k => $v)
            {
                if (strstr($v, 'wp-image'))
                {
                    $id = end(explode('-', $v));
                }
            }

            if (!empty($id))
            {
                $img->appendChild("<div>Star Rating ID = $id</div>");
            }            
        }
    }

    $dom->saveHTML();
    return $content;
}

As you can see, I need some help inside of the conditional statement. Is a regular expression match best for figuring out the ID with a preg_match()? What is the best way to add the <div> after each image? Use str_replace()?

EDIT:

Updated my code. But now getting error Argument 1 passed to DOMNode::appendChild() must be an instance of DOMNode, string given

EDIT AGAIN:

Thanks alot hakre! However, what if I wanted to add some larger code like the following after each image?

Lets say the following code is stored in a variable called $star_code, how would I insert this after the image using DOM?

<div class="dd-star-poll" id="img-$id">

    <ul class="dd-star-poll-options">
    <li><a href='#' title='1 star out of 5' class='one-star'>1</a></li>
    <li><a href='#' title='2 stars out of 5' class='two-stars'>2</a></li>
    <li><a href='#' title='3 stars out of 5' class='three-stars'>3</a></li>
    <li><a href='#' title='4 stars out of 5' class='four-stars'>4</a></li>
    <li><a href='#' title='5 stars out of 5' class='five-stars'>5</a></li>    
    </ul>

    <div class="dd-star-poll-results">
    Currently 3.5/5 Stars.
    </div>

</div>

Upvotes: 1

Views: 118

Answers (1)

hakre
hakre

Reputation: 197692

The final problem you got is because you do not add the new <div> element by string but by an object. For example:

$class->appendChild(new DOMElement('div', "Star Rating ID = $id"));

However I would also suggest you to make use of XPath in your case. It does allow you to select only those img elements that have the classes as strings you're looking for. At least at the same level as you wrote in your PHP code. So you can spare some code.

An Example selecting all attributes that do match, then parsing them (with a regular expression) to obtain the ID:

$doc = new DOMDocument;
$doc->loadHTML("<body>$html</body>");

$xp = new DOMXPath($doc);
$images = $xp->query(
    '//img[@class
           and contains(@class, "dd-star-rating") 
           and contains(@class, "wp-image-")
       ]/@class'
);

foreach ($images as $class) {
    $id = preg_match('/(?:^|\s)wp-image-(\d+)(?:$|\s)/', $class->nodeValue, $matches) ? $matches[1] : NULL;
    $class->appendChild(new DOMElement('div', "Star Rating ID = $id"));
}

Result:

<p>Nunc et neque risus. Nam a nisl eu magna rutrum euismod ac in lorem. Aenean varius accumsan ligula tincidunt malesuada. In diam lectus, pharetra quis cursus in, egestas vitae tellus. In neque arcu, aliquet ut egestas in, ultrices id ligula. Suspendisse ut dolor ligula, sit amet placerat ligula. Ut viverra nisi id ante facilisis pharetra. Aenean scelerisque, leo eget accumsan condimentum, odio libero ultrices enim, pretium placerat sapien purus nec odio. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur bibendum viverra pellentesque. Pellentesque eu diam non eros consectetur semper nec sed nisl.</p>

<p style="text-align: center;"><img class="size-full wp-image-44 aligncenter concept dd-star-rating" alt="concept" src="http://www.mysite.com/wp-content/uploads/2012/12/concept.png" width="720" height="540"></p>
<div>Star Rating ID = 44</div>

<p style="text-align: center;"><img class="size-full wp-image-45 aligncenter concept dd-star-rating" alt="concept" src="http://www.mysite.com/wp-content/uploads/2012/12/concept2.png" width="720" height="540"></p>
<div>Star Rating ID = 45</div>

<p>Nulla eros ante, lobortis in convallis eget, dignissim ut quam. Proin nisi nunc, iaculis ac auctor eu, tincidunt ac augue. Nunc purus nisi, sollicitudin nec luctus ullamcorper, dictum id magna. Sed quis nisi sagittis sapien placerat semper vitae tempus leo. Suspendisse sem diam, eleifend in blandit sed, pellentesque ac nisl. Morbi tincidunt adipiscing augue in pharetra. Duis dapibus bibendum egestas. Phasellus dictum dapibus quam id fermentum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p>

Adding more elements works by working with the return value of DOMElelemnt::appendChild. Example:

$prefix = 'dd-star-poll';

$divOuter = $node->appendChild(new DOMElement('div'));
$divOuter->setAttribute('class', $prefix);
$divOuter->setAttribute('id', "img-$id");

$ul = $divOuter->appendChild(new DOMElement('ul'));
$ul->setAttribute('class', "$prefix-options");

...

You just continue to add the elements.

Upvotes: 3

Related Questions