In Portfolio+ I use a custom post type for portfolio items and a custom taxonomy for portfolio categories. When someone views a portfolio archive page all of the portfolio featured images are displayed, and when someone goes to a portfolio category all the featured images of posts in that category are displayed.
But a common request I’ve had is for a template that displays all the portfolio categories with thumbnail images for each of the categories. This would allow someone to easily link to different sections of their overall portfolio (for instance, “Photography”, “Water Color”, “Sculpture”) rather than having them all show up in one jumble of the main portfolio archive template.
This gets a bit tricky because there is no easy way to associate an image with a taxonomy term (though Michael Field’s Taxonomy Images Plugin has made it work).
I decided the best route would be to just display all of the categories, and use the featured image from the most recent post in each category. This obviously won’t be the perfect solution for everyone (some may want to use a completely different image for the category thumbnail), but for most users I think it works well and is a dynamic way to show off new work.
You can tweak all the code below to also work for regular posts and categories (or even other custom posts and taxonomies), but all the code below is for the use case I mentioned above.
Get all the Taxonomy Terms
First we need to get all the unique custom terms for the taxonomy, in this case “portfolio_category”:
/* Retrieves all the terms from the taxonomy portfolio_category * http://codex.wordpress.org/Function_Reference/get_categories */ $args = array( 'type' => 'portfolio', 'orderby' => 'name', 'order' => 'ASC', 'taxonomy' => 'portfolio_category'); $categories = get_categories( $args );
Get the Most Recent Post for Each Term
Now we need to loop over each of the terms that was returned, and get the most recent post in that term:
/* Pulls the first post from each of the individual portfolio categories */ foreach( $categories as $category ) { $args = array( 'posts_per_page' => 1, 'post_type' => 'portfolio', 'portfolio_category' => $category->slug, 'no_found_rows' => true, 'update_post_meta_cache' => false, 'update_post_term_cache' => false ); $the_query = new WP_Query( $args ); // The Loop while ( $the_query->have_posts() ) : $the_query->the_post(); echo '<h3>' . $category->name . '</h3>'; // Display category name the_post_thumbnail(); // Display the image of the first post in category endwhile; } // Reset Post Data wp_reset_postdata();
Caching Results
Running WP_Query for each term in the taxonomy involves a ton of database calls, so it’s a smart idea to cache the results of these looped calls to reduce load on your server. The only time you really need to update that cached value is when a portfolio post is updated with a new category or image.
So, instead of running the above loops and outputting the values directly, we’ll save only the data we need to into an array (which I call $portoliopress_category_query) and save that as a transient. Then the template will use this cached value to output the contents.
Also, to keep the code a bit cleaner, I put this cache function in a separate file (portfolio-category-functions.php) than my regular page template code. Here’s what that function file looks like:
<?php /** * @package WordPress * @subpackage Portfolio Press * * Loops over each of the terms in the custom taxonomy "portfolio_categories" * and retrieves the first post from each. Since this is an expensive * request the result is built into an array and saved as a transient. */ function portfoliopress_category_cache() { /* Retrieves all the terms from the taxonomy portfolio_category * http://codex.wordpress.org/Function_Reference/get_categories */ $args = array( 'type' => 'portfolio', 'orderby' => 'name', 'order' => 'ASC', 'taxonomy' => 'portfolio_category'); $categories = get_categories( $args ); $portoliopress_category_query = array(); /* Pulls the first post from each of the individual portfolio categories */ foreach( $categories as $category ) { $args = array( 'posts_per_page' => 1, 'post_type' => 'portfolio', 'portfolio_category' => $category->slug, 'no_found_rows' => true, 'update_post_meta_cache' => false, 'update_post_term_cache' => false ); $the_query = new WP_Query( $args ); // The Loop while ( $the_query->have_posts() ) : $the_query->the_post(); $portfolio_thumbnail = null; $portfolio_thumbnail_fullwidth = null; $portfolio_thumbnail = wp_get_attachment_image_src( get_post_thumbnail_id(), 'portfolio-thumbnail'); $portfolio_thumbnail_fullwidth = wp_get_attachment_image_src( get_post_thumbnail_id(), 'portfolio-thumbnail-fullwidth'); /* All the data pulled is saved into an array which we'll save later */ $portoliopress_category_query[$category->slug] = array( 'name' => $category->name, 'term_link' => esc_attr( get_term_link( $category->slug, 'portfolio_category' ) ), 'portfolio-thumbnail' => $portfolio_thumbnail[0], 'portfolio-thumbnail-fullwidth' => $portfolio_thumbnail_fullwidth[0] ); endwhile; } // Reset Post Data wp_reset_postdata(); set_transient( 'portoliopress_category_query', $portoliopress_category_query ); return $portoliopress_category_query; }
Displaying Categories and Thumbnails in the Template
In the page template, I include the portfolio-category-functions.php file at the top. This code will only be used on this particular template, so it doesn’t make sense to load it from functions.php where it would always be loaded.
Then we check to see if the transitent has been set. If so, it’s used. If not, the portfoliopress_category_cache function is run (which will set the transitent), and its results are returned to be used:
<?php /* * Template Name: Portfolio Categories * Description: Displays all the portfolio categories * * @package WordPress * @subpackage Portfolio Press */ // This template requires some additional functions to work properly require_once( get_template_directory() . '/extensions/portfolio-category-functions.php' ); get_header(); $portoliopress_category_query = get_transient('portoliopress_category_query'); if ( !$portoliopress_category_query ) { $portoliopress_category_query = portfoliopress_category_cache(); } $thumbnail = 'portfolio-thumbnail'; ?> <div id="portfolio"> <?php foreach ( $portoliopress_category_query as $portfolio_cat ) { ?> <?php if ( $portfolio_cat[$thumbnail] ) { ?> <h3><a href="<?php echo $portfolio_cat['term_link']; ?>" class="title-overlay"><?php echo $portfolio_cat['name']; ?></a></h3> <a href="<?php echo $portfolio_cat['term_link']; ?>" class="thumb"><img src="<?php echo $portfolio_cat[$thumbnail]; ?>"></a> <?php } ?> <?php } ?> </div><!-- #portfolio --> <?php get_footer();
Updating the Transitent
Everything should now be displaying out fine, but there’s one last piece. Unless we delete the transitent when a portfolio post is updated, it will always display out the same results. So, we need to add a bit of code to functions.php that will hook in when a portfolio post is updated, and delete our saved transitent. Here’s how it works:
/** * Deletes the portoliopress_category_query transient if a portfolio post is updated */ function portfoliopress_save_portfolio( $post_id, $post ) { // If this is an auto save routine don't do anyting if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return; if ( $post->post_type == 'portfolio' ) { delete_transient( 'portoliopress_category_query' ); } } add_action( 'save_post', 'portfoliopress_save_portfolio', 10, 2 );
Conclusion
If someone has a lot of categories, it might also be useful to add custom pagination. I haven’t explored that functionality yet.
Does anyone use a template like this? Ideas, comments, suggestions?
This functionality is also now in Portfolio+ (see template). If anyone wants to view the actual source code you can purchase the theme and adapt it however you like.
Question – and maybe I am doing it wrong BUT –
trashing, untrashing a post throws an error saying that post_type is NOT defined. and doing an isset() will not delete the transient if you just trash the post or untrash it.
What would you suggest in this case?
Hi Adam. Thanks, you found a bug I hadn’t noticed. I updated the portfoliopress_save_portfolio function. Give it a try now.
Hi, I am using Portfolio+, and appreciate the addition of the portfolio category template since I am upgrading from Portfolio Press. There is one thing that I haven’t been able to figure out:
In the options panel I can set portfolio categories to display either full-width, or with sidebar. This is great, except that I would my portfolio category pages to display full width, and my portfolio tag pages to display with sidebar.
How do I do this?
I’m really happy of this post. Thanks Devin! People like you deserve kudos!
Devin,
Thanks so much for making a great theme (that also comes in a free version!)
I’m using Portfolio Press and I was wondering if there was a way to display the portfolio category at the top of the page?
Like if someone wanted to view my illustrations. Was there a way to put “Illustration” at the top of the thumbnail page? Is this what is actually being covered in this tutorial?
If so, should I go ahead and invest in Portfolio+?
Thanks for your help.
Hi Ro. Portfolio+ does have an option to display titles on taxonomy pages. No one has really asked for it, but it seems like a smart thing to also put into Portfolio Press at some point.
Thanks for getting back to me. If that’s something you end up doing, I look forward to using it.
I’m just starting to set up a WP multisite and going to use Portfolio Press for each member artist. I’m concerned that either Portfolio Press or the portfolio-post-plugin are not multisite compatible.
At the top of the Portfolio posts page I see the message about “portfolio-post-type” being required in future versions. If I Network Activate the plugin it’s not available in the individual sites in their plugins list. If I leave it deactivated in the Network admin, then it shows up in individual sites, but even though I activate it, I continue to get the message at the top saying that it is required and install it etc. … Even scarier is that I tried to Network Activate it after adding some Portfolio posts to a site, and when I went back to the site to add more the posts were scrambled and displayed an error message that portfolio-post-type was missing. I went back and Network deactivated the plugin so that it showed up in the site’s plugin list again, but the posts were still scrambled and displayed an error message. Am I doing something wrong, or should I not use either of these in a multisite install?
The nag message will only show if the theme is activated and the plugin is not.
If you network activate, that should be fine.
My demo theme is on multisite (along with several other demos), and seems to work fine: http://themes.wptheming.com/portfolioplus/
Hello,
Is version 1.4.1 of P+ compatible with WordPress 3.5? Would like to update my WP install.
thanks!
Yes.
I’ve found a simpler solution which uses the portfolio categories to classify the portfolios. Then on each portfolio page I have a gallery.
I nest the portfolio categories. I.e. Works is at top, under that is several types like painting, mural, photography, ilustration…
Using the portfolio categories in the menu section on WP allows me to present the user with a nested series of choices. If they choose Work they see everything.
If the choose a submenu item such as Illustration then they only see portfolio pages marked as portfolio category illustration.
As I said a gallery on the page allows me to show several vies of the piece.
The feature image for illustration is the one I choose.
Is there a way to add the description of the taxonomy as well?
I tried adding “‘description’ => $category->description,” to the “$portoliopress_category_query[$category->slug]” array, but it doesn’t seem to be adding the description field when placing “” in the template file.
Thanks for this. It’s saving my life right now!
You wouldn’t want to add it to the array. Just output $category->description in the loop, like $category->name.
Thanks! I actually got it to work properly late last night. Much appreciated!
Hi,
I use your code and it works great. However, I am trying to sort the posts so that the category/taxonomy with the newest post is shown first. Is that possible? It now just sorts by taxonomy name.
You could probably re-sort $the_query object by date before outputting it.
Thanks! I
What is a good place to start? I am now reading up on the ‘pre_get_posts’ hook.
Was looking in the wrong place but I think I got it now!
In the cache function, when running the query, I save the date in the ‘$portoliopress_category_query’ array. Before displaying results I sort the array by date.
Thanks for this, I thought this might be a good idea for ‘expensive’ queries.
I have a magazine site with four multiple loops on the homepage and I would like to do something similar. Run the loops, save the array and only update when a new post is added.
Question: does a plugin like W3 cache make this sort of thing unnecessary?
Hi Steven. Yes, a cache plugin will also save expensive queries so that you don’t have the hard database hit every load. Depending on how often your caches clear a long term transient might help a little, but I doubt it be worth the effort to implement.
Hi, with this code, i alway get the same image, i tested and added the title and i alway get the same title.
Hello – I would like to display only one category on the homepage, and thought perhaps the Portfolio+ might accomplish this with the custom portfolio template, but I can’t seem to get it to work or understand what that template does. Please advise!
Portfolio+ does not offer that option. You would need to copy one of the portfolio templates and customize the template to query for the category you want to display.