9

When creating an image gallery in WordPress using the default Media Uploader, WordPress wraps the images in a bunch of HTML markup.

How can I overwrite this before it's generated so that I can output the desired markup and change the way the gallery layout is created?

Currently, WordPress is generating the code like this:

<div id="container">
   <div src="<?php bloginfo('template_directory'); ?>/images/small.jpg">
   <div src="<?php bloginfo('template_directory'); ?>/images/medium.jpg" data-media="(min-width: 400px)"></div>
   <div src="<?php bloginfo('template_directory'); ?>/images/large.jpg" data-media="(min-width: 950px)"></div>
   <div src="<?php bloginfo('template_directory'); ?>/images/extralarge.jpg" data-media="(min-width: 1200px)"></div>
</div>
Kirk Beard
  • 9,569
  • 12
  • 43
  • 47
Romain
  • 407
  • 2
  • 9
  • 20

5 Answers5

33

Instead of overwriting the gallery shortcode function, a better way is to use the post_gallery filter that is included within that function.

Add this in functions.php

add_filter('post_gallery','customFormatGallery',10,2);

function customFormatGallery($string,$attr){

    $output = "<div id=\"container\">";
    $posts = get_posts(array('include' => $attr['ids'],'post_type' => 'attachment'));

    foreach($posts as $imagePost){
        $output .= "<div src='".wp_get_attachment_image_src($imagePost->ID, 'small')[0]."'>";
        $output .= "<div src='".wp_get_attachment_image_src($imagePost->ID, 'medium')[0]."' data-media=\"(min-width: 400px)\">";
        $output .= "<div src='".wp_get_attachment_image_src($imagePost->ID, 'large')[0]."' data-media=\"(min-width: 950px)\">";
        $output .= "<div src='".wp_get_attachment_image_src($imagePost->ID, 'extralarge')[0]."' data-media=\"(min-width: 1200px)\">";
    }

    $output .= "</div>";

    return $output;
}

This is assuming you've set up image sizes for the different sizes you need using https://codex.wordpress.org/Function_Reference/add_image_size

Tim
  • 6,281
  • 3
  • 39
  • 49
DaveF
  • 356
  • 3
  • 3
  • The filter and the get_posts work great, although i had to change the foreach loop as the wp_get_attachment_image did not retrieve anything even though i had the correct thumb sizes. But i could easily change it to get the data i needed. Very helpful the post_gallery filter tip, thanks! – Larzan Jul 16 '15 at 13:27
  • Although, `div` would be the nicer solution, IMHO, using CSS background ;) – Julian F. Weinert Apr 19 '17 at 21:35
  • This works, although the order argument cannot be passed through `get_posts()` since the IDs are simply ordered in the shortcode itself. Does anyone have a method of keeping the order of the gallery this way? – RCNeil Sep 01 '17 at 17:28
  • 2
    @RCNeil `post_gallery` has 3 arguments: `$output, $atts, $instance`. `$atts['ids']` contains the ids (of the gallery items) and `$atts['orderby']` contains the order.. – honk31 Oct 12 '18 at 11:29
  • This doesn't seem to work for the new Gutenberg one :( – jave.web Aug 19 '22 at 15:23
18

I missed the post_gallery filter mentioned in the Answer just below this one. You should really consider using that filter instead of copying over the whole function.

Add this code to your template's functions.php and modify the HTML inside function. This function is copy of WP35's default gallery shortcode function. Accordiong to Codex, each shortcode can have only one function assigned to it, and because of that, your function will override WordPress default one:

add_shortcode('gallery', 'my_gallery_shortcode');    
function my_gallery_shortcode($attr) {
    $post = get_post();

static $instance = 0;
$instance++;

if ( ! empty( $attr['ids'] ) ) {
    // 'ids' is explicitly ordered, unless you specify otherwise.
    if ( empty( $attr['orderby'] ) )
        $attr['orderby'] = 'post__in';
    $attr['include'] = $attr['ids'];
}

// Allow plugins/themes to override the default gallery template.
$output = apply_filters('post_gallery', '', $attr);
if ( $output != '' )
    return $output;

// We're trusting author input, so let's at least make sure it looks like a valid orderby statement
if ( isset( $attr['orderby'] ) ) {
    $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
    if ( !$attr['orderby'] )
        unset( $attr['orderby'] );
}

extract(shortcode_atts(array(
    'order'      => 'ASC',
    'orderby'    => 'menu_order ID',
    'id'         => $post->ID,
    'itemtag'    => 'dl',
    'icontag'    => 'dt',
    'captiontag' => 'dd',
    'columns'    => 3,
    'size'       => 'thumbnail',
    'include'    => '',
    'exclude'    => ''
), $attr));

$id = intval($id);
if ( 'RAND' == $order )
    $orderby = 'none';

if ( !empty($include) ) {
    $_attachments = get_posts( array('include' => $include, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );

    $attachments = array();
    foreach ( $_attachments as $key => $val ) {
        $attachments[$val->ID] = $_attachments[$key];
    }
} elseif ( !empty($exclude) ) {
    $attachments = get_children( array('post_parent' => $id, 'exclude' => $exclude, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
} else {
    $attachments = get_children( array('post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
}

if ( empty($attachments) )
    return '';

if ( is_feed() ) {
    $output = "\n";
    foreach ( $attachments as $att_id => $attachment )
        $output .= wp_get_attachment_link($att_id, $size, true) . "\n";
    return $output;
}

$itemtag = tag_escape($itemtag);
$captiontag = tag_escape($captiontag);
$icontag = tag_escape($icontag);
$valid_tags = wp_kses_allowed_html( 'post' );
if ( ! isset( $valid_tags[ $itemtag ] ) )
    $itemtag = 'dl';
if ( ! isset( $valid_tags[ $captiontag ] ) )
    $captiontag = 'dd';
if ( ! isset( $valid_tags[ $icontag ] ) )
    $icontag = 'dt';

$columns = intval($columns);
$itemwidth = $columns > 0 ? floor(100/$columns) : 100;
$float = is_rtl() ? 'right' : 'left';

$selector = "gallery-{$instance}";

$gallery_style = $gallery_div = '';
if ( apply_filters( 'use_default_gallery_style', true ) )
    $gallery_style = "
    <style type='text/css'>
        #{$selector} {
            margin: auto;
        }
        #{$selector} .gallery-item {
            float: {$float};
            margin-top: 10px;
            text-align: center;
            width: {$itemwidth}%;
        }
        #{$selector} img {
            border: 2px solid #cfcfcf;
        }
        #{$selector} .gallery-caption {
            margin-left: 0;
        }
    </style>
    <!-- see gallery_shortcode() in wp-includes/media.php -->";
$size_class = sanitize_html_class( $size );
$gallery_div = "<div id='$selector' class='gallery galleryid-{$id} gallery-columns-{$columns} gallery-size-{$size_class}'>";
$output = apply_filters( 'gallery_style', $gallery_style . "\n\t\t" . $gallery_div );

$i = 0;
foreach ( $attachments as $id => $attachment ) {
    $link = isset($attr['link']) && 'file' == $attr['link'] ? wp_get_attachment_link($id, $size, false, false) : wp_get_attachment_link($id, $size, true, false);

    $output .= "<{$itemtag} class='gallery-item'>";
    $output .= "
        <{$icontag} class='gallery-icon'>
            $link
        </{$icontag}>";
    if ( $captiontag && trim($attachment->post_excerpt) ) {
        $output .= "
            <{$captiontag} class='wp-caption-text gallery-caption'>
            " . wptexturize($attachment->post_excerpt) . "
            </{$captiontag}>";
    }
    $output .= "</{$itemtag}>";
    if ( $columns > 0 && ++$i % $columns == 0 )
        $output .= '<br style="clear: both" />';
}

$output .= "
        <br style='clear: both;' />
    </div>\n";

return $output;
}
Community
  • 1
  • 1
david.binda
  • 1,058
  • 9
  • 15
  • Hi guys, this looks great. I can see what it's doing but when I include it in my functions.php, it has no effect. I've made it the last function in the file in an effort to have it load last. Any ideas what might be the issue? – tadywankenobi Jul 23 '13 at 10:03
  • I can't get this working either. I tried to past into functions.php - with no change. @tadywankenobi - how did you get it work? – avexdesigns Dec 05 '13 at 17:20
  • Actually, I got it. It won't take effect until you add a NEW gallery. For some reason it does not apply to already existing galleries – avexdesigns Dec 05 '13 at 17:22
  • 1
    Actually, this is incorrect. You have to first unhook the default function and then add a new function to handle it. Unhook using remove_shortcode('gallery'), then add_shortcode('gallery', 'your function'). Furthermore, there is no need to copy the whole function. You only need to use the filter 'post_gallery' to return your own markup, and the default function wont be used. – chesscov77 Jun 04 '15 at 22:55
  • You're right - that was already mentioned in the answer below this one: http://stackoverflow.com/a/23410472/1259882 – david.binda Jun 05 '15 at 12:28
4

Building off of @DaveF's answer, here is a gallery function that maintains the gallery order and also randomizes if it is selected in the WP editor -

add_filter('post_gallery','customFormatGallery',10,2);

function customFormatGallery($string,$attr){

    $posts_order_string = $attr['ids'];
    $posts_order = explode(',', $posts_order_string);

    $output = "<div class=\"gallery-container\">";
    $posts = get_posts(array(
          'include' => $posts_order,
          'post_type' => 'attachment', 
          'orderby' => 'post__in'
    ));

    if($attr['orderby'] == 'rand') {
        shuffle($posts); 
    } 

    foreach($posts as $imagePost){
        $output .= '<img src="' . wp_get_attachment_image_src($imagePost->ID, 'full')[0] . '" alt="" />';
    }

    $output .= "</div>";

    return $output;
}
RCNeil
  • 8,581
  • 12
  • 43
  • 61
  • Late comment: I get a syntax error on the $output line in the foreach. Appears to be the wp_get_attachment_image_src arguments.... – Rick Hellewell Aug 23 '18 at 21:55
2

Just addition to accepted answer To make it work you need first to remove default gallery short code like this:

add_action( 'after_setup_theme', 'my_override_of_default_gallery' );

function my_override_of_default_gallery() {
    remove_shortcode( 'gallery' );
    add_shortcode('gallery', 'my_gallery_shortcode');  
}

//add_shortcode('gallery', 'my_gallery_shortcode'); 

function my_gallery_shortcode($attr) {
    $post = get_post();
    ...
}
jere_hr
  • 284
  • 3
  • 11
  • +1 for mentioning "removing" the other function. But note that the best aproach is to use the provided filter (see filter "post gallery" around line 981). – chesscov77 Jun 04 '15 at 22:57
1

Here is the code that I change to obtain the layout that I was looking for:

/******    REWRITE THE GALLERIE FUNCTION FROM WORDPRESS   **********/

add_shortcode('gallery', 'my_gallery_shortcode');  

function my_gallery_shortcode($attr) {
  $counter=0;
//var_dump("Rewrite the shortcode gallery");

    $post = get_post();

static $instance = 0;
$instance++;


if ( ! empty( $attr['ids'] ) ) {
    // 'ids' is explicitly ordered, unless you specify otherwise.
    if ( empty( $attr['orderby'] ) )
        $attr['orderby'] = 'post__in';
    $attr['include'] = $attr['ids'];
}



// Allow plugins/themes to override the default gallery template.
$output = apply_filters('post_gallery', '', $attr);
if ( $output != '' )
    return $output;

// We're trusting author input, so let's at least make sure it looks like a valid orderby statement
if ( isset( $attr['orderby'] ) ) {
    $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
    if ( !$attr['orderby'] )
        unset( $attr['orderby'] );
}

extract(shortcode_atts(array(

/******    CHANGE TO FULL SIZE TO GET THE CORRECT INFORMATION **********/
    'order'      => 'ASC',
    'orderby'    => 'menu_order ID',
    'id'         => $post->ID,
    'itemtag'    => 'dl',
    'icontag'    => 'dt',
    'captiontag' => 'dd',
    'columns'    => 3,
    'size'       => 'Full size',
    'include'    => '',
    'exclude'    => ''    
), $attr));

/***********************************************************************/

$id = intval($id);
if ( 'RAND' == $order )
    $orderby = 'none';

if ( !empty($include) ) {
    $_attachments = get_posts( array('include' => $include, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );

    $attachments = array();
    foreach ( $_attachments as $key => $val ) {
        $attachments[$val->ID] = $_attachments[$key];
    }
} elseif ( !empty($exclude) ) {
    $attachments = get_children( array('post_parent' => $id, 'exclude' => $exclude, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
} else {
    $attachments = get_children( array('post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
}

if ( empty($attachments) )
    return '';

if ( is_feed() ) {
    $output = "\n";
    foreach ( $attachments as $att_id => $attachment )
        $output .= wp_get_attachment_link($att_id, $size, true) . "\n";
    return $output;
}

$itemtag = tag_escape($itemtag);
$captiontag = tag_escape($captiontag);
$icontag = tag_escape($icontag);
$valid_tags = wp_kses_allowed_html( 'post' );
if ( ! isset( $valid_tags[ $itemtag ] ) )
    $itemtag = 'dl';
if ( ! isset( $valid_tags[ $captiontag ] ) )
    $captiontag = 'dd';
if ( ! isset( $valid_tags[ $icontag ] ) )
    $icontag = 'dt';

$columns = intval($columns);
$itemwidth = $columns > 0 ? floor(100/$columns) : 100;
$float = is_rtl() ? 'right' : 'left';

$selector = "gallery-{$instance}";
$gallery_div ="<div pictures-content>";
$gallery_style ="";

$output = apply_filters( 'gallery_style', "\n\t\t" . $gallery_div );

$i = 0;
$count=0;
foreach ( $attachments as $id => $attachment ) {

$test = $attachments[$id];
$link=$test->guid;
    $nocsript="";
    if ($count==0){$nocsript ="<noscript><img src='$link'</noscript>";$sentence ="<div data-src='$link'></div>";}
    if ($count==1){$sentence ="<div data-src='$link' data-media='(min-width: 400px)'></div>";}
    if ($count==2){$sentence ="<div data-src='$link' data-media='(min-width: 800px)'></div>";}
    if ($count==3){$sentence ="<div data-src='$link' data-media='(min-width: 1000px)'></div>";}
    if($nocsript==""){ $output .= "$sentence";} else { $output .= $nocsript."$sentence";}
    $count++;
}
$output .= "</div>\n";
return $output;
}
Romain
  • 407
  • 2
  • 9
  • 20