3

I've got a weird layout to get around and am at a loss, even in the planning stage. Essentially I need to separate out all content that's not a .gallery and put it into an <aside />. I initially considered a plugin using the edit_post hook from the Plugin API, but have since decided against it because this content change is layout specific and I want to maintain a clean database. So...

How can I parse through WP's the_content for content that's not .gallery? Admittedly not a PHP guy, so I doubly appreciate the help!


As per Michael's comment below - here's an example of WP's the_content class output:

HTML

<div class="entry-content">
    <div class="gallery">
        <dl class="gallery-item">
            <dt class="gallery-icon portrait">
                <img src="/imagePath/etc.jpg" class="attachment-thumbnail">
            </dt>
        </dl>
        <dl class="gallery-item">
            <dt class="gallery-icon portrait">
                <img src="/imagePath/etc.jpg" class="attachment-thumbnail">
            </dt>
        </dl>
        <dl class="gallery-item">
            <dt class="gallery-icon portrait">
                <img src="/imagePath/etc.jpg" class="attachment-thumbnail">
            </dt>
        </dl>
    </div>
    <p>Curabitur vulputate, ligula lacinia scelerisque tempor, lacus lacus ornare ante, ac egestas est urna sit amet arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed molestie augue sit amet.</p>
    <ul>
        <li>Item A</li>
        <li>Item B</li>
        <li>Item C</li>
    </ul>
</div>

Desired Output

<div class="entry-content">
    <div class="gallery">
        <dl class="gallery-item">
            <dt class="gallery-icon portrait">
                <img src="/imagePath/etc.jpg" class="attachment-thumbnail">
            </dt>
        </dl>
        <dl class="gallery-item">
            <dt class="gallery-icon portrait">
                <img src="/imagePath/etc.jpg" class="attachment-thumbnail">
            </dt>
        </dl>
        <dl class="gallery-item">
            <dt class="gallery-icon portrait">
                <img src="/imagePath/etc.jpg" class="attachment-thumbnail">
            </dt>
        </dl>
    </div>
    <aside>
        <p>Curabitur vulputate, ligula lacinia scelerisque tempor, lacus lacus ornare ante, ac egestas est urna sit amet arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Sed molestie augue sit amet.</p>
        <ul>
            <li>Item A</li>
            <li>Item B</li>
            <li>Item C</li>
        </ul>
    </aside>
</div>
technopeasant
  • 7,809
  • 31
  • 91
  • 149
  • For those of us not versed in WP's classes and markup layout, can you post a sample of what the markup looks like now, and what you want it to look like? Do you really _need_ to change the markup; can you not achieve what you want via CSS alone? – Michael Berkowski Dec 29 '13 at 00:26
  • Thanks Michael. I've included an example of the output above. Unfortunately I *do* need to change the markup for a variety of reasons. I do wish it was CSS-able though - definitely my forte. – technopeasant Dec 29 '13 at 00:38
  • 1
    A little vulgar but you could do this in jQuery/JavaScript - see http://stackoverflow.com/questions/15430851/jquery-wrapping-groups-of-adjacent-elements – ggdx Dec 29 '13 at 01:13
  • 1
    Yeah, really easy to do in JavaScript, but it'd be less than ideal – technopeasant Dec 29 '13 at 03:11

2 Answers2

6

You'll want to use a Dom Parser for this. Here's an example in how you can go about it using your markup as an example. Testing yielded the desired results, so hopefully this will give you the head start you need:

add_filter( 'the_content', 'wrap_nongallery_aside', 20 );
function wrap_nongallery_aside($content){
    $dom = new DOMDocument();
    $dom->loadHTML($content); // Replace with Edit below if PHP >= 5.4
    $aside = $dom->createElement('aside');
    $xpath = new DOMXPath($dom);
    $not_gallery = $xpath->query('//div[@class="entry-content"]/*[not(contains(@class, "gallery"))]');

    foreach($not_gallery as $ng){
        $aside->appendChild($ng);
    }
    $dom->getElementsByTagName('div')->item(0)->appendChild($aside);
    return $dom->saveHTML();
}

Edit:

If you're using PHP >= 5.4, then you can easily remove any extra <html> and <body> tags from the generated markup by using the following:

$dom->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

maiorano84
  • 11,574
  • 3
  • 35
  • 48
  • Thank you, exactly what I'm looking for and very clearly beyond my understanding. – technopeasant Dec 29 '13 at 05:57
  • Worth noting that this method adds a Doctype String and and tag, you probably don’t want that. – Andreas Riedmüller Nov 17 '21 at 09:35
  • 1
    @AndreasRiedmüller You're correct, however in the 8 years that this answer has been posted, options have also been provided to turn off that behavior. [See this answer](https://stackoverflow.com/questions/4879946/how-to-savehtml-of-domdocument-without-html-wrapper) for additional details. – maiorano84 Nov 18 '21 at 06:50
1

Maiorano84's answer worked beautifully, but prior to his reply I worked out an alternate method that's less specific to my situation, so I figured it'd be good to share.

I had originally written off the plugin approach because it requires changing post content itself - not just the format of the output, but realized that plugins live independent of the theme installation. Below is a very simple, developer targeted plugin that converts a [aside /] shortcodes into HTML elements. It's entirely based on BSD Aside by Sean D Burkin. I'll eventually include a button for the WP text editor and open source it.

<?php
/*
Plugin Name: RW Content Aside
Description: Inserts aside formatting into post content via shortcodes
Author: Daniel Redwood
Version: 0.1
Author URI: http://www.rdwd.fm/

Based on SBD Aside by Sean B. Durkin:
Original Plugin: http://seanbdurkin.id.au/pascaliburnus2/archives/51
Author: http://www.seanbdurkin.id.au
*/

if ( !is_admin() ){
  add_filter('the_content', 'handle_rw_aside');
}

function generate_random_str( $length=10)
{
  return substr(md5(rand()), 0, $length);
}

function generate_place_marker()
{
  return '@' . generate_random_str( 10) . '@';
}

function GetBody( $aside_instruction) {
  return preg_replace( '~^((<p>)?  \S+\s*=\s*.*?(<br \/>|<\/p>)\n?)*~mi', '', $aside_instruction);
}

function handle_rw_aside($the_content)
{
  $begin = generate_place_marker();
  $end   = generate_place_marker();

  $new_content = preg_replace(
    '~^((<p>)?\[aside\](<br />|</p>))(.*?)(^(<p>)?\[\/aside\](<br />|</p>))~ms',
    $begin . '$4' . $end,
    $the_content);

  $new_content = preg_replace_callback(
    '~^(<p>)?(!+\[\/?aside\])~m',
    function ($match) {
      return $match[1] . substr( $match[2], 1);
      },
    $new_content);

  $pattern = '~'.$begin.'(.*?)'.$end.'~s';

  return preg_replace_callback(
    $pattern,
    function ($match) {
      $aside_instruction = $match[1];
      $body = GetBody( $aside_instruction);
      $aside = '<aside class="contentAside">' . $body . '</aside>';
      return $aside;
      },
    $new_content);

}

?>
technopeasant
  • 7,809
  • 31
  • 91
  • 149