This tutorial is designed for intermediate developers. It will get you started, but you’ll need to tweak the template files to your own needs.
A few of the StudioPress child themes include a portfolio page, like Modern Portfolio and Jane. But what if you’ve found a theme you want and it doesn’t include this feature?
It’s actually not that difficult to add to any theme. And even if your theme already includes it, this plugin-based approach will ensure your portfolio will keep working when it comes time to change themes.
An Integrated Approach
Just like Event Calendar Integration, this is a feature that should be built using a plugin and your theme.
The plugin contains the functionality: registering a “portfolio” post type, a “portfolio categories” taxonomy, any necessary metaboxes…all of the backend features that should be theme-independent and stay with you when you change themes in the future.
The theme is responsible for styling how the portfolio looks. If you don’t make any changes to your theme, the portfolio will look like another blog (because it will inherit the styling from that section). In the future if you change themes, you’ll want to update the design of that theme with regards to your portfolio.
Set up the backend
Install the Portfolio Post Type plugin. This will add a “Portfolio” post type below your “Posts”.
Add your portfolio items, making sure to add images for each one so the layout looks good in the next step.
If you go to yoursite.com/portfolio, you’ll see all your portfolio items showing up but it looks like a blog – just title and post content.
Styling your Portfolio
Create a theme file called archive-portfolio.php
and place it in your child theme. Place this code in it:
<?php | |
/** | |
* Portfolio Archive | |
* | |
*/ | |
/** | |
* Display as Columns | |
* | |
*/ | |
function be_portfolio_post_class( $classes ) { | |
global $wp_query; | |
if( !$wp_query->is_main_query() ) | |
return $classes; | |
$columns = 3; | |
$column_classes = array( '', '', 'one-half', 'one-third', 'one-fourth', 'one-fifth', 'one-sixth' ); | |
$classes[] = $column_classes[$columns]; | |
if( 0 == $wp_query->current_post % $columns ) | |
$classes[] = 'first'; | |
return $classes; | |
} | |
add_filter( 'post_class', 'be_portfolio_post_class' ); | |
// Remove items from loop | |
remove_action( 'genesis_entry_header', 'genesis_post_info', 12 ); | |
remove_action( 'genesis_entry_content', 'genesis_do_post_content' ); | |
remove_action( 'genesis_entry_footer', 'genesis_entry_footer_markup_open', 5 ); | |
remove_action( 'genesis_entry_footer', 'genesis_post_meta' ); | |
remove_action( 'genesis_entry_footer', 'genesis_entry_footer_markup_close', 15 ); | |
/** | |
* Add Portfolio Image | |
* | |
*/ | |
function be_portfolio_image() { | |
echo wpautop( '<a href="' . get_permalink() . '">' . genesis_get_image( array( 'size' => 'medium' ) ). '</a>' ); | |
} | |
add_action( 'genesis_entry_content', 'be_portfolio_image' ); | |
add_filter( 'genesis_pre_get_option_content_archive_thumbnail', '__return_false' ); | |
// Move Title below Image | |
remove_action( 'genesis_entry_header', 'genesis_entry_header_markup_open', 5 ); | |
remove_action( 'genesis_entry_header', 'genesis_entry_header_markup_close', 15 ); | |
remove_action( 'genesis_entry_header', 'genesis_do_post_title' ); | |
add_action( 'genesis_entry_footer', 'genesis_entry_header_markup_open', 5 ); | |
add_action( 'genesis_entry_footer', 'genesis_entry_header_markup_close', 15 ); | |
add_action( 'genesis_entry_footer', 'genesis_do_post_title' ); | |
genesis(); |
The first secton of code is breaking the portfolio into columns. Change the
$columns = 3
to however many columns you want (2-6). If your portfolio is not showing up in multiple columns, your theme might be missing the Column Classes CSS. Go to that link and copy/paste the CSS to your style.css
file.
The second section is removing items we don’t want showing up in the loop. I’m removing the post info (date and author at top), post content, and post meta (categories at bottom). I’m also removing the markup for the entry’s footer since we no longer have a footer.
The third section is adding an image to replace the post content. I’m using the medium image size, which you can manage in Settings > Media. You might also consider creating your own image size in functions.php
.
The fourth section moves the post title below the featured image.
With that in place, you should have a pretty good portfolio set up. You might want to do some additional styling or changes to the template file, but now you have a starting point. Here’s what it looks like on my demo site:
Use same template for taxonomies
The plugin includes Portfolio Categories and Portfolio Tags taxonomies. You could duplicate the template file into taxonomy-portfolio_category.php
and taxonomy-portfolio_tag.php
, but that means if you make changes in the future you’ll need to update 3 files.
A cleaner approach is to put this in functions.php
:
<?php | |
/** | |
* Portfolio Template for Taxonomies | |
* | |
*/ | |
function be_portfolio_template( $template ) { | |
if( is_tax( array( 'portfolio_category', 'portfolio_tag' ) ) ) | |
$template = get_query_template( 'archive-portfolio' ); | |
return $template; | |
} | |
add_filter( 'template_include', 'be_portfolio_template' ); |
That tells WordPress “if we’re on either the portfolio category or portfolio tag taxonomies, use the portfolio archive template file”.
Ordering projects
Right now the projects are showing up in reverse chronological order – the most recently published are at the top. But since this is a portfolio, you might want to put your most impressive projects at the top, regardless of post date.
Add this to your functions.php
file:
<?php | |
/** | |
* Add 'page-attributes' to Portfolio Post Type | |
* | |
* @param array $args, arguments passed to register_post_type | |
* @return array $args | |
*/ | |
function be_portfolio_post_type_args( $args ) { | |
$args['supports'][] = 'page-attributes'; | |
return $args; | |
} | |
add_filter( 'portfolioposttype_args', 'be_portfolio_post_type_args' ); | |
/** | |
* Sort projects by menu order | |
* | |
*/ | |
function be_portfolio_query( $query ) { | |
if( $query->is_main_query() && !is_admin() && ( is_post_type_archive( 'portfolio' ) || is_tax( array( 'portfolio_category', 'portfolio_tag' ) ) ) ) { | |
$query->set( 'orderby', 'menu_order' ); | |
$query->set( 'order', 'ASC' ); | |
} | |
} | |
add_action( 'pre_get_posts', 'be_portfolio_query' ); |
You can now use the “Page Attributes” box in the right column when editing a portfolio item to set the order, or install a plugin like Simple Page Ordering which will let you drag them around from the main portfolio edit screen.
Paul Oaten says
Hi Bill,
thank you for this brilliantly useful post. I have it up and running on a localhost install. I only have one question: is there an easy way to center align the portfolio post image and heading on the archive grid view?
Bill Erickson says
You can use this tutorial to modify the classes applied to the featured image: https://www.billerickson.net/genesis-featured-image-alignment/
Noman says
Hi Bill,
Thanks for your useful tutorial.working fine on my blog.I will install your plugin asap! thanks again
Hugh Anderson says
Hi Bill,
thanks for the excellent tutorial – I have been trying to apply it’s methods. (beginner)
I wanted to ask, can I turn off the sidebar in the Portfolio page? I can turn it off globally, but then I can’t get it to be present in my blog. And since there isn’t a “Portfolio” page, I can’t target the sidebar. Wee, “I” can’t. 🙂
Any pointers would be welcome.
Thanks!
Hugh
Bill Erickson says
In your archive-portfolio.php file, add this:
add_filter( 'genesis_pre_get_option_site_layout', '__genesis_return_full_width_content' );
Hugh Anderson says
Bill,
that’s awesome! Thank you so much for your speedy and most helpful reply, it did exactly what I wanted. I really appreciate it.
Hugh
Pixelloop says
Hi Bill,
Cool tutorial, I would love to see a way you could setup this template in a way so it could be used by any custom post type. I guess that would involve some child theme settings to allow you to activate the template or specify the name of the post type you are using that you want to have the grid active for?
I know from the past you were a proponent of Thesis also, and then moved. There are a few things I still believe Thesis handles better.
1) It would be cool if on the edit taxonomy term screen you could specify what template you wanted to use there like you can on the edit page screen. You can do this in Thesis and is one loose end of Genesis.
2) Genesis over reliance on widgetized areas for custom content areas. I like your approach using advanced custom fields but have a few ideas which I think would improve the ecosystem. WordPress Spots plugin is a good idea, albeit with some modifications to allow shortcode insertion or template insertion etc.
Would love to hear your feedback.
Bill Erickson says
You can use the
template_include
filter to specify which templates are used where on your site. For instance, if you had ‘portfolio’ and ‘product’ post types and wanted this template used on the archive page for the product one, you could do this: https://gist.github.com/billerickson/89e813e4e1bd3abe61bdAlternatively you could just create an archive-product.php template and put the same code in there, but that would require duplicating the code.
I’m sure you could build your #1 request with the above code and a metabox on the Edit Term screen
For #2, Genesis does not rely on widgetized areas at all. You’re describing StudioPress’ child themes. I can’t stand widgetized areas being used for page content, like 5 widget areas for the front page. It belongs in a metabox when you edit the front page, not in widgets. But StudioPress chooses to do it that way since it takes less code (don’t have to create custom metaboxes, leverage built-in WP functionality instead) and it’s easier for their support to help customers if every theme works in a very similar way.
Tony says
I’m going to try that for my product pages,thanks for the explanation Bill.
Rani says
Hi
I’m trying to pull the tags for each portfolio item, but I get none.
get_the_tags is not working as well.
Thanks
Rani
Bill Erickson says
It’s probably because you’re using a custom taxonomy. get_the_tags() only works with the ‘post_tag’ taxonomy. You’ll want to use get_the_terms( get_the_ID(), ‘my_taxonomy_name’ );
Rani says
Thanks. Works great,
MarK Hemmingson says
Thanks for this Bill. Is it possible to use this so that the grid only displays for the category called “Gallery”? I have a site where all the artisans are added to the “Gallery”. The link in the navigation is a category, so the posts display according to the Genesis Theme settings. I would like them to display as a grid for the “Gallery” category only.
Bill Erickson says
Instead of naming the file
archive-portfolio.php
which would apply to a ‘portfolio’ post type, name itcategory-gallery.php
which will apply to the category with a slug of ‘gallery’.Mark Hemmingson says
Thank you Bill. Much appreciated.
Jessica says
I’ve got this mostly working, but I’m running to an issue with how many items are returned per page. It’s stopping at pulling 10 portfolio items and then going to next page. Since I’m 4 columns, this is awkward. Is there a way to change it to pull 12 per page? http://www.glowweddingsandevents.com/portfolio/
Thanks!
Bill Erickson says
Yes, in functions.php you have the function that orders the posts (hooked to ‘pre_get_posts’). Use this function to customize your query, including changing the number of posts per page. So in the be_portfolio_query() function above, add this:
$query->set( 'posts_per_page', 12 );
More information on customizing queries: https://www.billerickson.net/customize-the-wordpress-query/
Jessica says
Thanks so much! I got it working.
Carissa Magras says
Thank you so much for this!!! Quick question: Is there a way to add “next” and “previous” buttons? I love the display of the portfolio on my page, but would really like to be able to just click “next” when viewing (instead of going back to main page every time).
Bill Erickson says
Yes, you can use the previous_post_link() and next_post_link() functions. Click them for more information on the WordPress Codex.
Carissa says
Thank you Bill!!! I’m a little confused though… Do I add to the archive-portfolio.php file or functions.php?
Bill Erickson says
It would go in single-portfolio.php since you want it to only apply to the single posts in the ‘portfolio’ post type. Or you could put it in functions.php and wrap it in a conditional (
if( is_singular( 'portfolio' ) ...
)Tim says
Hi, I am just curious as to actions like this: remove_action( ‘genesis_entry_header’, ‘genesis_entry_header_markup_open’, 5 );
Why do you need to add the number at the end? Isn’t this a number specifying priority? If so, is it needed when you are removing an item?
Thanks.
Bill Erickson says
Yes, the priority is needed if you are removing a function that was added at a certain priority.
In the example above, if you left off the 5 it would use the default priority (10). But
genesis_entry_header_markup_open()
uses the priority of 5, so it wouldn’t get removed.