Building my Portfolio

I received the following email from a developer yesterday.

As a newcomer to the web world and genesis included, I’m attempting to learn from others and looking at great designs that inspire me. This brings me to my question. Would you be willing to share your experience or even go as far as sharing your code for your custom designed portfolio page here?

After writing out my response, I figured others might be interested as well. Here’s the code, followed by a description of what each function does below.

First, the functions.php file:

<?php
/**
* Functions
*
* @package BE_Genesis_Child
* @since 1.0.0
* @link https://github.com/billerickson/BE-Genesis-Child
* @author Bill Erickson <[email protected]>
* @copyright Copyright (c) 2011, Bill Erickson
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
*
*/
/**
* Portfolio Query
*
* @param object $query
* @return null
*/
function be_portfolio_query( $query ) {
if( $query->is_main_query() && !is_admin() && ( is_post_type_archive( 'projects' ) || is_tax( 'type' ) ) ) {
$query->set( 'posts_per_page', 18 );
$query->set( 'orderby', 'menu_order' );
$query->set( 'order', 'ASC' );
$query->set( 'post_type', 'projects' );
}
}
add_action( 'pre_get_posts', 'be_portfolio_query' );
view raw functions.php hosted with ❤ by GitHub
  • be_portfolio_query() customizes the query on the portfolio pages. This must go in functions.php since it needs to run before main query, which happens before the template is determined. More information on customizing the query.

I specify the post type so the projects show up on the taxonomy archive pages AND so that the archive-projects.php file is used for the taxonomy archive pages. I could’ve also done this second part using the template_include filter.

<?php
/**
* Portfolio Archive
*
* @package BE_Genesis_Child
* @since 1.0.0
* @link https://github.com/billerickson/BE-Genesis-Child
* @author Bill Erickson <[email protected]>
* @copyright Copyright (c) 2011, Bill Erickson
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
*
*/
/**
* Portfolio Body Class
*
* @param array $classes
* @return array
*/
function be_portfolio_body_class( $classes ) {
$classes[] = 'portfolio-section';
return $classes;
}
add_filter( 'body_class', 'be_portfolio_body_class' );
/**
* Collect Testimonials
*
*/
function be_collect_testimonials() {
if( have_posts() ): while( have_posts() ): the_post();
global $post, $be_testimonials;
$testimonial = get_post_meta( $post->ID, 'be_project_testimonial', true );
if( $testimonial ) {
$testimonial = '<div class="clearfix"></div><div class="testimonial">' . wpautop( $testimonial );
$name = get_post_meta( $post->ID, 'be_project_testimonial_name', true );
if( !empty( $name ) )
$testimonial .= '<p class="name">-- ' . $name . '</p>';
$testimonial .= '</div><div class="clearfix"></div>';
$be_testimonials[] = $testimonial;
}
endwhile; endif;
}
add_action( 'genesis_before_loop', 'be_collect_testimonials' );
/**
* Sort Projects
*
*/
function be_sort_projects() {
echo '<div class="sort-projects">';
echo '<h3><span>Sort by project type:</span></h3>';
echo '<ul>';
// All Projects
$class = is_post_type_archive( 'projects' ) ? 'all-projects active' : 'all-projects';
echo '<li class="' . $class . '"><a href="' . get_post_type_archive_link( 'projects' ) . '">All<br />Projects</a></li>';
// Project Types
$types = get_terms( 'type', array( 'orderby' => 'menu_order' ) );
foreach ( $types as $type ) {
$class = is_tax( 'type', $type->slug ) ? $type->slug . ' active' : $type->slug;
echo '<li class="' . $class . '"><a href="' . get_term_link( $type, 'type' ) . '">' . $type->name . '</a></li>';
}
echo '</ul></div>';
}
add_action( 'genesis_before_loop', 'be_sort_projects' );
// No Post Info
remove_action( 'genesis_before_post_title', 'genesis_post_info' );
/**
* Project Post Classes
*
* @param array $classes
* @return array
*/
function be_project_post_classes( $classes ) {
global $wp_query;
$classes[] = 'one-third';
if( 0 == $wp_query->current_post || 0 == $wp_query->current_post % 3 )
$classes[] = 'first';
return $classes;
}
add_filter( 'post_class', 'be_project_post_classes' );
/**
* Outer Wrap
*
*/
function be_outer_wrap() {
echo '<div class="outer-wrap">';
}
add_action( 'genesis_before_loop', 'be_outer_wrap', 80 );
/**
* Outer Wrap Close
*
*/
function be_outer_wrap_close() {
echo '</div>';
}
add_action( 'genesis_after_loop', 'be_outer_wrap_close', 1 );
/**
* Project Archive Content
*
*/
function be_project_archive_content() {
global $post;
echo '<div class="image"><a href="' . get_permalink() . '">' . get_the_post_thumbnail( $post->ID, 'be_project_thumbnail' ) . '</a></div>';
$terms_output = '';
$terms = get_the_terms( $post->ID, 'type' );
foreach( $terms as $term )
$terms_output .= '<a class="icon-type ' . $term->slug . '" href="' . get_term_link( $term, 'type' ) . '">' . $term->name . '</a> ';
if( !empty( $terms_output ) )
echo wpautop( $terms_output );
}
add_action( 'genesis_post_content', 'be_project_archive_content' );
/**
* Project Divider
*
*/
function be_project_divider() {
global $wp_query;
$count = $wp_query->current_post + 1;
if( 0 == $count % 3 && $count !== 6 && $count !== $wp_query->post_count )
echo '<div class="divider"></div>';
}
add_action( 'genesis_after_post', 'be_project_divider' );
/**
* Project Quote
*
*/
function be_project_quote() {
global $wp_query, $be_testimonials;
if( !( ( 5 < $wp_query->found_posts && 5 == $wp_query->current_post ) || ( $wp_query->current_post == ( $wp_query->found_posts - 1 ) && 5 > $wp_query->found_posts ) ) )
return;
if( isset( $be_testimonials ) && !empty( $be_testimonials ) ) {
$testimonial = $be_testimonials[0];
if( is_tax( 'type', 'mobile-design' ) )
$testimonial = $be_testimonials[2];
if( is_tax( 'type', 'design-to-website' ) )
$testimonial = $be_testimonials[1];
echo $testimonial;
} else {
echo '<div class="divider"></div>';
}
}
add_action( 'genesis_after_post', 'be_project_quote' );
genesis();
  • be_portfolio_body_class() adds a consistent body class to all the pages using this template, for styling (if I didn’t use this, I’d have to write styles with body.post-type-archive-projects and body.tax-type )
  • be_collect_testimonials(), I wanted to display a testimonial between certain projects, and wanted that testimonial to be from one of the projects featured on this page. So before the projects are listed, I loop through them all and pull out all the testimonials. I can then use this in a function lower down in the page
  • be_sort_projects() adds the links before the project listing that lets you go from the main portfolio (all projects) to one of the taxonomy archives
  • be_project_post_classes() – This looks at the loop counter and adds column classes to the posts, breaking it into multiple columns. See this tutorial for more information.
  • be_outer_wrap() and be_outer_wrap_close() add a wrapping div around all the posts and testimonials so they can be cleared with CSS
  • be_project_archive_content() is the content of each project. It has the image and then displays the taxonomy terms (Project Type) below it
  • be_project_divider() adds a dividing line after every 3 posts, except after the 6th one (where a testimonial is the divider)
  • be_project_quote() adds a testimonial after the 6th project (it’s #5 since it starts counting at 0) OR after the last project if there are less than 6. I also have it choosing different testimonials for different taxonomies so the same testimonial isn’t used on every page

Bill Erickson

Bill Erickson is the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments are closed. Continue the conversation with me on Twitter: @billerickson

Comments

  1. Joshua says

    Bill,

    This is great stuff, thanks for posting it!

    It looks like this code works for inserting one testimonial after the 6th project, but not any further than that. Do you have an updated version that you are using on your portfolio that displays more than one testimonial? Just curious, since it looks like your portfolio page is a single page instead of multiple with 18 projects per page as outlined above. I imagine you would use the $count and pull the testimonial based on the $count divided by 6?

    I had to add similar !empty checks for each if( is_tax() ) statement in the portfolio_quote function, similar to the parent if statement, to avoid errors on the taxonomy pages: https://gist.github.com/joshuadavidnelson/7327303#file-project_quote-php. This is probably just because I was playing around with it an didn’t have enough projects in the portfolio.

    Thanks again!
    Joshua