Using a WordPress loop to pull images directly from the WordPress Media Library and displaying them with a shortcode.
A crucial part of filtering the images you want to show from the rest of what is in your media library is done by attaching a taxonomy to the media library items. This has the added benefit of creating the foundation needed to allow for filtering of the gallery on the front end as well.
Everything in the Media Library WordPress considers an attachment and for the sake of taxonomies and the loop, attachments are simply a post type. A post type with some peculiarities but a post type nonetheless.
I like using CPT UI for creating taxonomies and once you do, they have nice little checkboxes next to all the post types you can associate your taxonomy with and “Media” is one of them. So this part is easy. Of course, if you prefer to add a taxonomy a different way, go for it.
The next step is to assign a term from your new taxonomy to any of the images in your library you want to show in the gallery. If an image has no term assigned it won’t show up. If it has a term assigned from another taxonomy, it also won’t show up.
Your images are ready, now the rest. I made a shortcode that is ready to use. You just have to stick all the code that is in that file somewhere in your install. You can add it to the functions.php file if you’re using a child theme, or you can install a plugin like Code Snippets and stick it in a snippet. Either way you can then use the shortcode in a page or post for example.
But if you want to make your own loop, here are the basics of what I did.
Get all the terms from the taxonomy that’s assigned to Media.
$oAllTerms = get_terms( array( 'taxonomy' => 'your_media_tax' ) );
get_terms()
by default only returns the terms that aren’t empty which is exactly what I want. This now allows me to do two things 1) set up a button group with a button for each term, which will allow for filtering of the gallery 2) set up a query to get all the images I want from the media library.
1) Filtering buttons
<?php $aTermIds = array(); ?>
<div class="button-group gallery-filter">
<button class="filter button active" value="fgimage">All</button>
<?php foreach( $oAllTerms as $oAterm ){ ?>
<button class="filter button" value="<?php echo $oAterm->slug; ?>">
<?php echo $oAterm->name; ?>
</button>
<?php $aTermIds[] = $oAterm->term_id;
} ?>
</div>
2) Setting up a query
The array $aTermIds
is in preparation for the query that’s following now, because if I only specify the taxonomy and not the terms I want attachments from, there will be no attachments to show at all. So while I’m looping through all the terms with attachments anyway, I might as well put all of the term IDs in an array for use later.
//WP_Query Arguments
$args = array(
'post_status' => 'any',
'post_type' => 'attachment',
'post_mime_type' => 'image',
'posts_per_page' => -1,
'tax_query' => array(
array(
'taxonomy' => 'your_media_tax',
'terms' => $aTermIds
)
)
);
//The Query
$bw_query = new WP_Query( $args );
Three things I want to comment on in the above:
- Attachments do not get a post status of ‘published’ (which is the default in WP_Query), their post status is ‘inherit’. You can use either ‘inherit’ or ‘any’.
- Since you have a lot of control over what is being pulled out of your media library, adding the post mime type is perhaps unnecessary, but I like being cautious. Of course, if you’re doing your own thing with it, you might not want to limit the loop to that mime type, or you might want to narrow it even more and specify what type of images, image/jpg for example.
- Setting posts per page to -1 means that all your images with a taxonomy term assigned will be shown; be careful to not have that be too many images…
Displaying the images
<?php //The Loop
if( $bw_query->have_posts() ){ ?>
<ul class="filterable-gallery">
<?php while( $bw_query->have_posts() ){
$bw_query->the_post();
$oPostTerms = get_the_terms( null, 'your_media_tax' );
$aTermlist = array();
foreach( $oPostTerms as $oPostTerm ){
$aTermlist[] = $oPostTerm ->slug;
}
$sTermlist = implode( " ", $aTermlist); ?>
<li class="fgimage <?php echo $sTermlist; ?>">
<?php echo wp_get_attachment_link( null, 'medium', false ); ?>
</li><?php
} ?>
</ul><?php
} else { ?>
<p>There are no images to show.</p><?php
}
//Restore original Post Data
wp_reset_postdata();
Even though we’re treating the attachments as posts in a way, the_content()
won’t output anything. If we want the image we still have to use wp_get_attachment_link()
. Since we’re in the loop, we don’t need to set the post id and null
will work fine for that. I’m using the medium size, but any of the public names available for any of the image sizes in your WP install will work as will an array of width and height values in pixels (in that order).
get_the_terms()
in the code above is used to convert the terms attached to the image to a list of classes used in the li
that wraps around the image, also needed to allow for filtering.
Making the filtering work
I’m using a bit of jQuery, but you do you.
<script id="filterable-gallery-js">
jQuery(document).ready(function(){
jQuery(".filter.button").on('click', function(){
var btnValue = jQuery(this).prop("value");
jQuery(".filterable-gallery").fadeTo("fast", 0.01);
jQuery(".fgimage").not("." + btnValue).fadeOut();
setTimeout(function(){
jQuery("." + btnValue).fadeIn();
jQuery(".filterable-gallery").fadeTo("fast", 1);
}, 400);
jQuery(this).addClass("active").siblings().removeClass("active");
});
});
</script>
First we fade the whole gallery almost to invisible, then we fade everything out that doesn’t have the right term / class, which means that all those images get a display: none
. Since that makes all of the items in the gallery jump around, I wait a beat before first fading in the images with the correct term / class and then I fade the whole gallery back to full opacity.
And last but not least, I give the active button a class of “active”, so I can target it with some CSS and make it visually stand out.
That’s it. How you style your gallery is up to you. If you have any comments or questions, let me know!