How to paginate attachments in a secondary query as gallery?

I’m assuming you want something like this:

|---------------------|   
|       content       |  
|       (static)      |  
|---------------------|  
|       gallery       |  
|       (paged)       |  
|---------------------|  
|   << pagelinks >>   |  
|---------------------|  

In this setup your the post content stays the same, appears to be static, while the gallery is paged. This means you have the main query, showing you the title, content and so on, and a secondary query, which is responsible for showing you the gallery images. The page links on this page are connected to the secondary loop and do the paging there. To achieve this I suggest using WP_Query instead of get_posts(), not only because I don’t have a solution for the latter in mind, but also because I think it’s generally the better approach. In a first step you have to setup a new query variable, which will be used for the pagination. The function add_gallery_query_var() goes into your functions.php.

Code:

    add_filter('init', 'wpse124169_attachment_gallery_add_query_var');
    function wpse124169_attachment_gallery_add_query_var() {
        global $wp;
        $wp->add_query_var('gallery_page');
    }

Additionally, if you want pretty permalinks to work with the new query variable, you have to implement a new rewrite rule. For this add the following to your functions.php, which makes use of add_rewrite_tag and add_rewrite_rule.

Code:

    add_filter('init', 'wpse124169_attachment_gallery_add_rewrite_tag_rule');
    function wpse124169_attachment_gallery_add_rewrite_tag_rule() {
        add_rewrite_tag('%gallery_page%','([^&]+)');
        add_rewrite_rule('([^/]+)/gallery/image//?([0-9]{1,})/?$', 'index.php?name=$matches[1]&gallery_page=$matches[2]', 'top');
    }

The next step is to create the secondary loop for the gallery. WP_Query is used to do so, additionally paginate_links gives us the possibility to create the links for paging through the gallery. I’ve decided to create a function for this, so below code goes into the functions.php.

Code:

function wpse124169_get_attachment_gallery() {
    global $post;
    $gallery_page = (get_query_var('gallery_page')) ? get_query_var('gallery_page') : 1;
    $args = array(
        'posts_per_page' => 1, 
        'orderby' => 'menu_order', 
        'order' => 'ASC', 
        'post_type' => 'attachment',
        'post_status' => 'inherit', 
        'post_mime_type' => 'image', 
        'post_parent' => $post->ID, 
        'paged' => $gallery_page
    ); 
    $gallery = new WP_Query($args);
        if ( $gallery->have_posts() ) :
            echo '<div class="my_cpt_gallery_paged">';
                    while ( $gallery->have_posts() ) : $gallery->the_post();
                        echo wp_get_attachment_image( $post->ID, 'medium' );
                    endwhile;
            echo '</div>';
            echo '<div class="my_cpt_gallery_paginate_links">';
                    if ( get_option('permalink_structure') ) {
                        $format="gallery/image/%#%";
                    } else {
                        $format="&gallery_page=%#%";
                    }
                    $args = array(
                        'base' => get_permalink( $post->post_parent ) . '%_%',
                        'format' => $format,
                        'current' => $gallery_page,
                        'total' => $gallery->max_num_pages
                    );
                    echo paginate_links( $args );
                    wp_reset_postdata();
            echo '</div>';
        endif;
}

As you can see the secondary query uses an extra post object – $gallery – and the query variable defined before – gallery_page – to enable proper pagination. The latter is used to setup the format parameter of paginate_links(). We shouldn’t forget to reset – wp_reset_postdata() – to prevent problems. Of course this is just the secondary loop, not the complete template.

I call the secondary attachment gallery query in my single.php, after the main query/loop, via the function wpse124169_get_attachment_gallery(). Following above steps you have your paginated attachment gallery set up. I’ve tested this and it’s working for me.


Below I list the most important information and sources, if you’re interested in more details this should get you more then just started.

Information:

  1. WP_Query
  2. paginate_links
  3. Class WP/source/add_query_var
  4. Rewrite API
  5. add_rewrite_tag
  6. add_rewrite_rule
  7. Multiple WP_Query loops with Pagination
  8. How to create separate pagination for mutiple loops?


Optional:

What it does is, it changes the default link for the first image. Normally it is http://site.ext/?p=123 or http://site.ext/post-name/, the attachment parents permalink. That’s ok, it shows you the first image by default. But if you want the link for the first image represent the gallery query var in the URL, you have to hook into paginate_links. This leads to the link being condtsructed like this http://site.ext/?p=123&gallery_page=1 or http://site.ext/post-name/gallery/image/1. This only applies to the navigation via the link by paginate_links(), calling the parent post does only show the according parent permalink. The code would also go into the functions.php.

Code:

add_filter( 'paginate_links', 'wpse124169_attachment_gallery_first_image_link' );
function wpse124169_attachment_gallery_first_image_link( $link ) {
    global $post;
    if ( get_option('permalink_structure') ) {
        $gpg_num = substr( strrchr( $link, "https://wordpress.stackexchange.com/" ), 1 );
    } else {
        $gpg_plk = wp_parse_args($link);
        $gpg_num = $gpg_plk['gallery_page'];
    }
    if ( empty( $gpg_num ) ) {
        if ( get_option('permalink_structure') ) {
            $link = get_permalink( $post->post_parent ) . 'gallery/image/1';
        } else {
            $link = get_permalink( $post->post_parent ) . '&gallery_page=1';
        }
    }

    return $link;
}


Update:

This can be used for altering the shortcode, like shown here: How to paginate wordpress shortcode?.

Leave a Comment