Wordpress - Split Content and Gallery

Open to anybody who can simplify this but here's what I came up with that worked for me.

First thing's first - get the gallery, using get_post_gallery(), as soon as the loop starts:

<?php if( have_posts() ) : ?>

    <?php while( have_posts() ) :
            the_post();
            $gallery = get_post_gallery();
            $content = strip_shortcode_gallery( get_the_content() );
    ?>

        <div id="content">
            <?php echo $content; ?>
        </div> <!-- id="content" -->

        <div id="gallery">
            <?php echo $gallery; ?>
        </div> <!-- id="gallery" -->

    <?php endwhile; ?>

<?php endif; ?>

strip_shortcode_gallery() Function - functions.php

function strip_shortcode_gallery( $content ) {
    preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER );

    if ( ! empty( $matches ) ) {
        foreach ( $matches as $shortcode ) {
            if ( 'gallery' === $shortcode[2] ) {
                $pos = strpos( $content, $shortcode[0] );
                if( false !== $pos ) {
                    return substr_replace( $content, '', $pos, strlen( $shortcode[0] ) );
                }
            }
        }
    }

    return $content;
}

Resources:

Stackoverflow:

What I was originally going off of, which didn't work as expected:

  • Wordpress remove shortcode from content

Core shortcode Regular Expressions

Basically we can do that with a Regex - actually even with the Regex provided by core by get_shortcode_regex().

First we need to grab the shortcode tags and build a regex. The core function get_shortcode_regex() sadly offers no chance to throw in an argument so we'd be left with a regex that matches each and every shortcode, which is undesired as we only want to target the [gallery] shortcode.

// Get all tags as Array
$tags = $GLOBALS['shortcode_tags'];
// remove the gallery-shortcode; 'gallery' is the key
unset( $tags['gallery'] );
// retrieve all shortcodes (but not 'gallery') separated by a vertical pipe char/the "or" Regex char
$tags = join( '|', array_map(
    'preg_quote',
    array_keys( $GLOBALS['shortcode_tags'] )
) );

Catch all galleries

Next we need a Regex that catches all galleries. Therefore we are calling preg_match_all() as it will return all Matches for the gallery shortcode as array with an 0 index (the rest will be partial matches and can be ignored).

$pattern = get_shortcode_regex();
preg_match_all( "/$pattern/s", get_the_content(), $galleries );

Now $galleries[0] holds an array of gallery shortcode tags.

The content without galleries

The next thing is that we need to do is to remove all [gallery] shortcodes from the content. We will use the same Regex again and run it on get_the_content(). Of course we apply the the_content filter as shortcode could have been added through a callback at render time.

$content = preg_replace_callback(
    "/$pattern/s",
    'strip_shortcode_tag',
    apply_filters( 'the_content', get_the_content() )
);

The $content variable now holds our content.

Example callback to alter the content

or: How you can split up the content into galleries and the rest of the post

We could easily just replace the content with our new content during a callback:

$tags = $GLOBALS['shortcode_tags'];
unset( $tags['gallery'] );

$tags = join( '|', array_map(
    'preg_quote',
    array_keys( $GLOBALS['shortcode_tags'] )
) );
$pattern = get_shortcode_regex();

preg_match_all( "/{$pattern}/s", get_the_content(), $galleries );

echo $galleries;
echo "<hr>";
echo preg_replace_callback(
    "/{$pattern}/s",
    'strip_shortcode_tag',
    apply_filters( 'the_content', get_the_content() )
);

which would first add all galleries, then add our content without galleries, both separated by a horizontal rule. This is just a starting point.


It should not be sooo complicated. The code below can be shortened down to a couple of lines at wish.

Approach 1. Get the clean post content by removing all shortcodes, including the gallery one from the post content.

NB: all the other shortcodes will be removed from the post. If you do not place custom shortcodes there, then the approach is for you.

Assume you are in the WP loop

$ctt = apply_filters('the_content',strip_shortcodes(get_the_content())); // This is your cleaned content
$glry = get_post_gallery(); // and here is the gallery.

Assume you are out

$my_postid = 12;
$my_post = get_post($my_postid);
$ctt = apply_filters('the_content',strip_shortcodes($my_post->post_content));
$glry = get_post_gallery($my_postid);

Approach 2. Remove only [gallery] shortcode, keep all other shortcodes in.

Relies on the internal realisation of the how the [gallery] shortcode looks like, which can be changed by WP team, so maybe not as future proof as the 1st approach:

In the WP loop

$ctt = preg_replace('/\[gallery.*\]/', '', get_the_content());
$ctt = apply_filters('the_content',$ctt); // This is your cleaned content
$glry = get_post_gallery();

Out of it

$my_postid = 12;
$my_post = get_post($my_postid);
$ctt = apply_filters('the_content',preg_replace('/\[gallery.*\]/', '', $my_post->post_content));
$glry = get_post_gallery($my_postid);