EDIT: This post has been deprecated by the recently released WordPress 2.9. Please update your WordPress installation to get this functionality in your blog.
If you don’t wish to update your blog software, then please continue reading.
I was writing a post on my personal blog recently and wanted to show a gallery of pictures, but I also wanted to show one of those pictures near the top of the post, but not in the gallery, and if you’ve ever tried to do this with [gallery], you know it can’t be done.
Well, now it can, and I’ll show you how.
First we take a look at the original WP function that creates the gallery. The function is called gallery_shortcode( ) and it’s located in the /wp-includes/media.php file. Make a copy of this function and paste it in your /wp-content/themes/[your_theme]/functions.php file, or create a plugin and paste it there.
Now that that’s pasted, lets take a look at it.
Near the top of the function, you’ll find the hook we’ll be using to modify the gallery function and output. It looks like the following:
// Allow plugins/themes to override the default gallery template.
$output = apply_filters('post_gallery', '', $attr);
if ( $output != '' )
return $output;
So the first thing we need to do is remove that portion from our function, because it doesn’t make any sense to hook a callback to itself.
The next thing we need to do is edit the function attributes to match the attributes in the hook. Here is the new function definition:
function my_gallery_shortcode($null, $attr = array( )) {
The $null attribute takes the empty string that gets passed and then just ignores it, we don’t need it here. The $args attribute takes the $attr variable that gets passed. you’ll also note that we renamed the function so we don’t get naming conflicts. Just under the function, right after the closing brace ( } ), add the following:
add_filter('post_gallery', 'my_gallery_shortcode', 10, 2);
This hooks the function we’re creating into the original function and overrides it.
Now that we have that, we take a look at where the function is pulling it’s data from, so we can edit that data and filter the output to exclude certain images from the gallery. Just under where the shortcode attributes are extracted, you’ll see a call to get_children( ). This is the function that pulls the gallery image data from the database. After looking through the source, I noticed there was an exclude attribute that was available to this function, but it wasn’t being used here. This will be the key to fixing this function.
Add the exclude attribute to the get_children( ) function call, and add it to the shortcode attribute extract portion of our function as well, so we get what we need out of the shortcode and don’t discard it along the way. Here is the new portion of the function, with a little bit of code before and after for orientation:
// 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',
'exclude' => '' // $id, 'post_status' => 'inherit',
'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order,
'orderby' => $orderby, 'exclude' => $exclude) );
// the 'exclude' portion at the end was added
if ( empty($attachments) )
return '';
Now we have a function that pulls only the gallery images we want, excluding the ones we don’t want. To use, switch your editor to HTML mode and insert the image you wish to exclude from the gallery (I apologize, but there is no other quick way that I know of to get the post id of the image besides inserting it into the post and reading from there, but I want to exclude images from the gallery because I’ve used them elsewhere in the post, so it wasn’t a big deal for me), in the image tag class attribute, you’ll see something like “wp-image-1822″, where the number is different for every image, this is the post id and that’s what you need to insert in your gallery shortcode to exclude as follows (remove the leading dot):
[.gallery exclude="1822,1845,1236"]
And there you have it, images excluded from your gallery.
Here is my complete function and hook. Note I also made some CSS changes to fit the gallery in with my floated right sidebar, which was breaking due to the floated gallery images and the clears that were on them. You can use this as is, or edit to suit your needs.
/**
* The Gallery shortcode.
*
* This alters the functionality of the Gallery Shortcode for displaying
* WordPress images on a post.
* This function also adds an aditional option to the gallery shortcode:
* exclude = excludes the list of post (image) ids from the gallery
*
* @since 2.5.0
*
* @param mixed $null space filler to take up empty string argument passed by WP
* @param array $attr Attributes attributed to the shortcode.
* @return string HTML content to display gallery.
*/
function my_gallery_shortcode($null, $attr = array( )) {
global $post;
// 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',
'exclude' => ''
), $attr));
$id = intval($id);
$attachments = get_children( array('post_parent' => $id, 'post_status' => 'inherit',
'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order,
'orderby' => $orderby, 'exclude' => $exclude) );
if ( empty($attachments) )
return '';
if ( is_feed( ) ) {
$output = "\n";
foreach ( $attachments as $id => $attachment )
$output .= wp_get_attachment_link($id, $size, true) . "\n";
return $output;
}
$itemtag = tag_escape($itemtag);
$captiontag = tag_escape($captiontag);
$columns = intval($columns);
$itemwidth = $columns > 0 ? floor(100/$columns) : 100;
$output = apply_filters('gallery_style', "
.gallery {
margin: auto;
}
.gallery:after {
content: '.';
display: block;
height: 0;
clear: left;
visibility: hidden;
}
.gallery-item {
float: left;
margin-top: 10px;
text-align: center;
width: {$itemwidth}%;
}
.gallery-caption {
margin-left: 0;
}
<!-- see my_gallery_shortcode( ) in {theme_dir}/functions.php -->
<div class='gallery'>");
$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 .= "";
$output .= "
$link
";
if ( $captiontag && trim($attachment->post_excerpt) ) {
$output .= "
{$attachment->post_excerpt}
";
}
$output .= "";
}
$output .= "
</div>\n";
return $output;
}
add_filter('post_gallery', 'my_gallery_shortcode', 10, 2);
I hope this helps somebody, and please leave any questions or comments below.
Tags: gallery

















this worked. awesome, thanks!
BTW, WP seemed to have a problem with the comma at the end of line 34:
‘exclude’ => ”,
so I removed it.
Hi there,
it seems that the script works fine. I also had a problem with comma at ‘exclude’ => ”,.
There’s one thing I can’t get, where [.gallery exclude="1822,1845,1236"] should be pasted in the gallery short code?
Thanks in advance for your reply.
Thanks for the info on the comma, I have fixed the original post.
@Brand Relations - the [.gallery exclude="1822,1845,1236"] (sans the period after the open brace) shouldn’t be pasted anywhere in the gallery short code, it is just an example of how the gallery short code can now be used to filter out certain images.
That portion of code gets pasted in the post, and then WP creates the gallery at that point in the post.
Ahh right, it’s working very well now. Thanks again for your help :)
Here you can see how it is working
http://www.sprowadzanieaut.pl/06/sztuczki-sprzedawcow-samochodow-uzywanych/
Nice work !
For a faster exclude, you should try this :
Instead of that, I’ve changed the wp-include/media.php this way :
–look for the gallery_shortcode() fonction and change —
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);
if (!strstr($link,’$o$’)) {
$output .= “”;
$output .= ”
$link
“;
if ( $captiontag && trim($attachment->post_excerpt) ) {
$output .= ”
” . wptexturize($attachment->post_excerpt) . ”
“;
}
$output .= “”;
if ( $columns > 0 && ++$i % $columns == 0 )
$output .= ”;
}
}
$output .= ”
\n”;
return $output;
To sum up, I’ve only added a test on the $link string, looking for a ‘$o$’ substring. If the link contains this substring, it does not include the picture in the gallery.
All you need to do is to update the code, browse your gallery, and add $o$ for example at the end of the title of the picture(s) you want to exclude !
Johann
Thanks, worked like a charm :)
Thanks, this works perfectly. It’d be great if we could have a plugin with intuitive gui to achieve this.
It looks very tricky and me as a PHP novice - I do not understand much. ;-P
I am searching for a smart solution to edit the output of the gallery shortcode. Do I get it right, that with the right function in the functions.php I can manipulate every content related output of wordpress?
Can you give me a hint, how to change the output of the shortcode [gallery].
The shortcode output now looks like this:
Life is good!
but I would like to have something like this:
Life is good!
Any ideas?
haha … it’s so funny what your comment form made out of my code. *lol*
Life is good! was the plain text between a lot of HTML-code.
[...] and came up with a lot of suggestions. First, I tried to hack my functions.php according to this awesome post from the development team at Code Greene. Yes, it worked out quite well but I didn’t like all [...]
get_children() has a certain lack in usage. I guess this code is well written and quite helpful but remember that get_children() will pull only attachments which ‘bear’ parent Post ID. What if someone wants to insert an image from Media Library whose ID is different than current Post? I guess this image will be out of the scope.
Cheers!
I understand that get_children only grabs attachments that have a parent ID but this code is specifically editing the (gallery) shortcode, which, by definition, only grabs children of the post that the shortcode is used in.
If you wish to insert an image from the media library, this code does nothing to stop you from doing that, although that is outside the scope of this post.
Works a treat! You rock sir. Thanks for improving the wordpress gallery function. You made my day easier.
Minor admin issue:
This might be an issue with FF/win but when I clicked to copy your complete code to my clipboard it changed guillemets and ampersands to entities. WP flagged it and I made everything right again.
Nice tutorial ! Thanks
Please review your code and change “>” etc.
Then take a look… the “We’re trusting author input…” code are different with finaly code… :)
I apologize for the code, but every time I try to edit the code to fix it, WordPress messes it all up again. So I have given up. To fix it yourself, just edit all the html entities to the actual character.
@Benjam
maybe try another syntax highlighting plugin for WP. I’m currently using a customized version of Syntaxhighlighter Plus which does its work nicely and doesn’t mess up any characters when posting source code. The plugin has undergone further development and is now called Syntaxhighlighter Evolved. You can find it here: http://wordpress.org/extend/plugins/syntaxhighlighter/. Another nice SH plugin is CodeColorer.
hth,
Mathias
Hi,
first of all great solution :)
Just one thing…do you have an idea how should i get list of all images in gallery, so i can use them in my way ;)?
thanks,
Z
Great post! I’d been wondering how to do this — when I upgraded to 2.9 the exclude parameter worked perfectly. :)