I need the built-in gallery shortcode to output UL instead of DL. How can I do it? I know I can use the 'post_gallery' filter, but that means almost duplicating the media's gallery_shortcode function. I'd like to find a less 'verbose' solution.

Thank you


You can use the the following attributes for the gallery shortcode:

[gallery itemtag="ul" icontag="li" captiontag="li"]

The problem with this is that the gallery shortcode wraps the image and the caption in different elements(thats why the default solution is using dl-dt-dd), so this will generate one li element for the image, and one for the caption. You can still style it using CSS though, because both of the element has unique classnames.

  • Ok no. Excuse me but I forgot to mention that I want a single list. There's absolutely no point in creating 1 UL for each image. I frankly can't get the reason why wordpress devs made the gallery generate 1 list for each image: it's not semantically correct, harder to style, and also no css framework (ex. bootstrap, foundation) has any sugar for that, since it's just wrong code... Apr 11 '14 at 7:10
  • Also, I think there's really no point in letting you to change the inner tags but not the outer one. well, you CAN do it with the 'gallery_style' filter, but then you loose useful classes because the filter itself doesn't give you access to sensible informations used to build that classes (for example the number of items/columns) Apr 11 '14 at 7:11
  • It will generate 2 list item / image(2 li element), not creating an ul for each image.
    – passatgt
    Apr 11 '14 at 12:42
  • No. The main container is natively hardcoded in the shortcode function, so itemtag refers to the single item/image. I don't want a separate ul for each image, there's no reason at all. See my own answer below. Apr 11 '14 at 14:18

Ok, so I rewrote the gallery shortcode function by copying the original and removing/adding/changing what I needed, and now I share it with you. The major things I added/changed are:

  • One single UL/LI list per gallery instead of a DL for each damned item..
  • Removed 'itemtag' attr, since there's no point in using another tag for items inside an UL
  • 'icontag' now defaults to 'figure', 'captiontag' now defaults to 'p'
  • new 'class' attr for adding a custom class to the container UL
  • new 'first-in-row', 'last-in-row', 'first-row', 'last-row' helper classes for LI items (though I strongly recommend to use nth-child css selectors instead)

Here's the code:

//remove styles: I'll use mine

//remove default shortcode
//add new shortcode
add_shortcode('gallery', 'custom_gallery');

function custom_gallery($attr) {
  $post = get_post();

  static $instance = 0;

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

  $output = '';

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

    'order'      => 'ASC',
    'orderby'    => 'menu_order ID',
    'id'         => $post ? $post->ID : 0,
    'icontag'    => 'figure',
    'captiontag' => 'p',
    'columns'    => 3,
    'size'       => 'thumbnail',
    'include'    => '',
    'exclude'    => '',
    'link'       => '',
    'class'      => ''//now you can add custom class to container UL 
  ), $attr, 'gallery'));

  $id = intval($id);

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

    $_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() ) //removed, see original in media.php

  $itemtag = tag_escape('li');//new tag for item 
  $captiontag = tag_escape($captiontag);
  $icontag = tag_escape($icontag);

  //valid tags check removed, see original in media.php

  $columns = intval($columns);
  $selector = "gallery-{$instance}";

  $size_class = sanitize_html_class( $size );

  //new tag for container 
  $output = "<ul id='$selector' class='gallery galleryid-{$id} gallery-columns-{$columns} gallery-size-{$size_class} {$class}'>";

  $i = 0;
  $c = count($attachments);
  $o = (int)floor($c/$columns)*$columns;

  foreach ( $attachments as $id => $attachment ) {
    if(!empty($link) && 'file' === $link) $image_output = wp_get_attachment_link($id,$size,false,false);
    elseif(!empty($link) && 'none' === $link) $image_output = wp_get_attachment_image($id,$size,false);
    else $image_output = wp_get_attachment_link( $id, $size, true, false );
    $image_meta = wp_get_attachment_metadata($id);
    $orientation = '';
    if(isset($image_meta['height'], $image_meta['width'])) $orientation = ($image_meta['height'] > $image_meta['width']) ? 'portrait' : 'landscape';

    //setup custom aux classes to help style
    $m = ++$i % $columns;
    $item_pos_class = ($m == 1) ? 'first-in-row' : (($m == 0) ? 'last-in-row' : '');
    $row_class = ($i <= $columns) ? 'first-row' : (($i > $o) ? 'last-row' : '');

    //added: custom aux classes
    $output .= "<{$itemtag} class='gallery-item {$item_pos_class} {$row_class}'>";
    $output .= "<{$icontag} class='gallery-icon {$orientation}'>$image_output</{$icontag}>";
    if($captiontag && trim($attachment->post_excerpt)){
      $output .= "<{$captiontag} class='wp-caption-text gallery-caption'>" . wptexturize($attachment->post_excerpt) . "</{$captiontag}>";
    $output .= "</{$itemtag}>";

  //changed BR>clear:both with a more conventional clearfix div
  $output .= "</ul>\n<div class='clearfix'></div>";

  return $output;
}//end custom gallery

And just to complete the gallery shortcode "chapter", here I show you how to eventually programmatically change the default and/or user defined attributes. Say for example I need to change the size attr based on number of items:


function set_gallery_thumbs_size($out, $pairs, $atts) {

  //in this case, if size was defined by the user, keep original and stop here
  if(isset($atts['size'])) return $out;

  //get number of images
  $c = count(explode(',',$atts['ids']));
  //set different sizes based on items count
  //new sizes were created with add_image_size() and image_size_names_choose filter (see wp docs)
  $atts['size'] = ($c > 2) ? 'thumb-3c' : ( ($c > 1) ? 'thumb-2c' : 'thumbnail');
  //merge original array with new one and return it
  return array_merge($out,$atts);

Hope it will help other people searching for a cleaner gallery markup.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.