How to get Page/Post Gallery attachment images in order they are set in backend using WP_Query()?

When you create a gallery via the 3.5 media manager, menu_order is no longer used to save the order of the images, the order only exists in the shortcode you insert when you click the Insert Gallery button, via the ids= attribute. This is to accommodate the fact that you can now add multiple galleries to a single post- ordering via menu_order wouldn’t work for this case. To extract these IDs, we’ll have to use a bit of regex to search post content for gallery shortcodes, then use those IDs in a post__in query, which can now be conveniently ordered by those IDs via the new-in-3.5 orderby value post__in.

If I were better at regex, this probably wouldn’t be so complicated, but alas, I’m terrible at it, so we’ll use some native WP functions and do a few backflips to extract these id attributes. This will work for a single or multiple galleries in post content. I just tested this by dropping it into the loop of a post, you’ll want to change $post->post_content to whatever/wherever you’re getting the post/page content from.

$pattern = get_shortcode_regex();

if( preg_match_all( "https://wordpress.stackexchange.com/". $pattern .'/s', $post->post_content, $matches )
    && array_key_exists( 2, $matches )
    && in_array( 'gallery', $matches[2] ) ):

        $keys = array_keys( $matches[2], 'gallery' );

        foreach( $keys as $key ):
            $atts = shortcode_parse_atts( $matches[3][$key] );
                if( array_key_exists( 'ids', $atts ) ):

                    $images = new WP_Query(
                        array(
                            'post_type' => 'attachment',
                            'post_status' => 'inherit',
                            'post__in' => explode( ',', $atts['ids'] ),
                            'orderby' => 'post__in'
                        )
                    );

                    if( $images->have_posts() ):
                        // loop over returned images
                    endif;

                    wp_reset_query();

                endif;
        endforeach;

endif;

Leave a Comment