WordPress 3 Custom Post Types : Create a simple Portfolio Page
March 2nd, 2011 | Php , Tips and Tricks , Tutorials , Wordpress
I am working on a Wordpress theme lately and just finished coding the Portfolio page. I would like to share my experience with Custom Post Types with you. (Thanks to Joe Casabona, his post is a great start guide.)
Ok, less talk, more code....
We want to...
- Add "Client" and "Short Text" fields to our work
- Add "Types" so our work can be filtered
- Add Sorting Function to Portfolio List (by Date, Project name and Client)
- Add Filtering function to theme
- Have Pagination on the page
Screenshots
Create Custom Post Type
<?php
//////REGISTER A CUSTOM POST TYPE
add_action('init', 'gs_portfolio_register');//Always use a shortname like "gs_" not to see any 404 errors
function gs_portfolio_register(){
$args = array(
'label' => __('Portfolio List'),
'singular_label' => __('Portfolio'),
'public' => true,
'show_ui' => true,
'capability_type' => 'post',
'hierarchical' => false,
'rewrite' => array('slug' => 'project'),//Use a slug like "work" or "project" that shouldnt be same with your page name
'supports' => array('title', 'editor', 'thumbnail')//Boxes will be showed in the panel
);
register_post_type( 'gs_portfolio' , $args );
}
//////ADD CUSTOM INPUTS (Client & Short_text)
add_action("admin_init", "admin_init");
add_action('save_post', 'save_options');
function admin_init(){
add_meta_box("gs_portfolioInfo-meta", "Portfolio Options", "meta_options", "gs_portfolio", "side", "low");
}
function meta_options(){
global $post;
$custom = get_post_custom($post->ID);
$client = $custom["client"][0];
$short_text = $custom["short_text"][0];
?>
<p><label>Client:</label><br /><input name="client" value="<?php echo $client; ?>" /></p>
<p><label>Short Text:</label><br /><textarea name="short_text"><?php echo $short_text; ?></textarea></p>
<?php
}
function save_options(){
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return $post_id;
global $post;
update_post_meta($post->ID, "client", $_POST["client"]);
update_post_meta($post->ID, "short_text", $_POST["short_text"]);
}
//////ADD TAXONOMY FOR FILTERING (Taxonomy name: types)
register_taxonomy("types", array("gs_portfolio"), array("hierarchical" => true, "label" => "Types", "singular_label" => "Types", "rewrite" => true));
//////ADD HOOKS FOR PANEL VIEW
add_filter("manage_edit-gs_portfolio_columns", "gs_portfolio_edit_columns");
add_action("manage_posts_custom_column", "gs_portfolio_custom_columns");
function gs_portfolio_edit_columns($columns){
$columns = array(
"cb" => "<input type=\"checkbox\" />",
"title" => "Portfolio Title",
"short_text" => "Short Text",
"client" => "Client",
"types" => "Types",
);
return $columns;
}
function gs_portfolio_custom_columns($column){
global $post;
$custom = get_post_custom();
switch ($column)
{
case "short_text":
echo $custom["short_text"][0];
break;
case "client":
echo $custom["client"][0];
break;
case "types":
echo get_the_term_list($post->ID, 'types', '', ', ','');
break;
}
}
?>
Create a Portfolio Template
<?php
/*
Template Name: Portfolio
*/
?>
<?php get_header(); ?>
<div class="sidebar grid_3 alpha">
<div id="sort">
<h5>SORT BY : </h5>
<ul>
<li><a href="<?php echo add_query_arg(array ('paged' => '1', 'orderby' => 'date', 'order' => 'DESC'));?>">Date</a></li>
<li><a href="<?php echo add_query_arg(array ('paged' => '1', 'orderby' => 'title', 'order' => 'ASC'));?>">Project (A to Z)</a></li>
<li><a href="<?php echo add_query_arg(array ('paged' => '1', 'orderby' => 'meta_value', 'order' => 'ASC', 'meta_key' => 'client'));?>">Client (A to Z)</a></li>
</ul>
</div>
<div id="filter">
<h5>FILTER BY : </h5>
<ul>
<?php
$categories= get_categories('taxonomy=types&title_li=');
foreach ($categories as $category){ ?>
<li><a href="<?php echo add_query_arg(array ('paged' => '1', 'filter' => $category->category_nicename));?>" title="Filter by <?php echo $category->name;?>"><?php echo $category->name;?></a></li>
<?php }?>
</ul>
</div>
<div id="reset-filters">
<a href="<?php echo add_query_arg(array ('paged' => '1', 'filter' => ''));?>">reset filters</a>
</div>
</div>
<div id="content" class="grid_9 omega">
<ul id="work-list">
<?php
$query = 'post_type=gs_portfolio&types='.$_GET['filter'].'&orderby='.$_GET['orderby'].'&order='.$_GET['order'].'&meta_key='.$_GET['meta_key'].'&posts_per_page=3&paged='.$paged;
query_posts($query);
if (have_posts()) : while (have_posts()) : the_post();
$custom = get_post_custom(get_the_ID());
?>
<li class="clearfix">
<div class="work-thumb">
<a title="<?php echo get_the_title(); ?>" href="<?php the_permalink(); ?>"><?php the_post_thumbnail('portfolio-img-440');?></a>
</div>
<div class="work-details">
<h6 class="project">Project :</h6>
<p><a href="<?php the_permalink(); ?>" rel="bookmark" title="<?php echo get_the_title(); ?>"><?php the_title(); ?></a></p>
<h6 class="client">Client :</h6>
<h4><?php echo $custom["client"][0];?></h4>
<p class="short"><?php echo $custom["short_text"][0];?></p>
<p><a href="<?php the_permalink(); ?>">View Project →</a></p>
</div>
</li>
<?php endwhile; ?>
<?php endif;?>
</ul>
<div class="posts-nav">
<div class="prev"><?php next_posts_link(__('← Older Projects')) ?></div>
<div class="next"><?php previous_posts_link(__('Newer Projects →')) ?></div>
</div>
</div>
<?php get_footer(); ?>
View Single Project
You can duplicate and rename your single.php as single-portfolio.php if you want to have a custom single page for your projects.


Hi,
Thanks for sharing your experience. It was very helpful.
is it possible to add the CSS file?
Thanks again.
Thanks. May be this helps you : http://geryit.com/lib/custom-post-types.css
Thanks! It helped me a lot. I was confused as to where to place the “floats” and “clear” (I don’t know how they are called in english…).
In your CSS file I saw that you have added all the styling for the landing page after clicking “view project”. Is it a custom page that you have created? Do you know how can I tell WordPress to go to a specific/custom page instead of the single.php?
Thanks again for your tutorial.
Just duplicate the single.php and rename it as “single-gs_portfolio.php” (or whatever Post Type Name you registered ). Hope it helps
Btw, you can take a look at live example beta template : http://grattis.geryit.com .
Hi,
The thing is that I’m using Thesis Framework. So I have to adapt everything the Thesis way. I have to figure out how I can tell my portfolio page (where all my work is listed) to open in a custom-single.php (with it’s own layout). I’m sure it’s very easy but I have spent so much time on it, I probably need to get fresh air, get my mind out of it for a while…
Thanks for your time and everything.
Hi there,
great tutorial, thanks for posting! I have a question though; I’ve implemented this on my website for my portfolio, and would like to copy the effect for my workshops.
I am able to register the new custom post type, but I’m having trouble adding the custom input fields. When I copy and paste the code I get a server error, presumably because of the repeating functions. When I copy the functions I change the title from jp_portfolio… to jp_workshops…
any suggestions?
Thanks!
Thanks Josh. Can you send me the code to hi@geryit.com?
Can you port the code as a twenty ten child theme and release it.
That’s will be great.
Thanks
Mat
I dont have time for that right, working on 2 projects, but can do that later.
Great tutorial and out of the hours (yes hours) of finding something, yours works…however, a couple things: First, in WordPress, it shows portfolio categories for the menu manager, so I decided to make a menu link to each portfolio catergory. But, I get 404′s. It appears depsite the portfolio category meta box showing up for menu creation, adding them to a menu doesn’t work, is there a solution? Second, when debugging my website (wordpress debug turned on, your filter shows this:
Notice: Undefined index: filter in ….”path here and line it’s on”. It shows this for each of the filter, orderby, order, and meta key. Any idea how to solve this?
Thanks in advance.
Hey Andre, thanks. Thats a very common problem. Just go to permalinks page and hit the save changes button. Your permalink settings will be refreshed. For other issue, use isset for vars. Like if (isset($filter)){}.
Hi. Thank you for this.
I would like to incorporate your ‘sort’ solution by putting the code in a php-widget.
The custom post type = literature.
I would like to give my users the opportunity to sort the literature by:
- date posted
- title descending
- publicationyear (which is a custom taxonomy)
Do you know how I can do this?
I tried using and customising your piece of code, but did not succeed.
Thanks!
Hi Abe,
so your problem is you cant make this work in a widget but you successfully made it work as a single project page?
I discovered an problem…I always have 5 portfolio items showing. Doesn’t matter if I have 10 or 20 items in one category, it’s always 5 showing. Any idea why it’s always 5 instead of all or any specified number?
Probably you didnt set post_per_page value so it show 5 posts (default wp post per page value) . Can you change “Blog pages show at most” value from the admin panel. Its under Settings>Reading Settings
Actually, I had customized the portfolio page and something about my changes is affecting it (still not sure why everything works but it always stays at 5 and don’t know what the significance of 5 is. I’ve added a thumbnail resizer, and also did a 3 column layout but I did set the post per page at -1, then tried 9, etc, still 5 shows. So when I put your code as-is back in, it works. I just need to add my own additions one at a time and remake what I did beore and see what is causing it to do 5 posts. A challenge considering I’m not a programmer.
ah..just realized what you said about the 5 posts is default. So it means whatever I did with my own coding modifications that the posts per page is being ignored in this page and it reverts to the WP default 5.
Wish I could help you dude :/
Amazing what going for coffee does…I solved the problem and also got my own modifications working 100% in conjunction with your portfolio type. Looks good and now I can do 1, 2, 3, or 4 column layouts. Cheers!
Hi,
First of all, thanks for sharing your experience.
It cleared a lot of doubts on filtering the content by category.
What I didn’t manage to get is if I have a subcategory. I would like the subcategory to appear only when the category is selected.
Who to get this? I tried to check if category has a subcategory, an if statemente on the Page template but nothing.
Any idea on how to get this?
Thanks in advance!
Bye
Hey Madgy,
can you send me your code to hello@geryit.com?
Hi,
Thanks for answering.
Actually the code I’m using is pretty much the same as yours. Changes I made were only in the name of cutsom post-type.
What a tried to do, was in functions.php: I tried to check if there are subcategories, using this code:
function category_has_children() {
global $wpdb;
$term = get_queried_object();
$category_children_check = $wpdb->get_results(” SELECT * FROM wp_term_taxonomy WHERE parent = ‘$term->term_id’ “);
if ($category_children_check) {
return true;
} else {
return false;
}
}
Then I added parent=0 to this line (to hide the subcategories):
$categories= get_categories(‘taxonomy=types&title_li=’);
plus this if statement after the foreach loop on template-portfolio.php:
<?php
if (!category_has_children()) {
echo 'Sorry'!
} else {
<a href=" ’1′, ‘filter’ => $category->category_nicename));?>” title=”Filter by name;?>”>name;?>
}
?>
I’m pretty sure I’m missing something…
Also I’m not an wordpress expert…
Well this is the code I’m using + your code.
Hope you can help or give some light on this.
Thanks, and Happy 2012.
Bye
Hi!
Something on these? Anything…
Thanks man.
bye
Guess who! lol…quick question, I’m still getting used to this custom post type thing with WordPress. The portfolio I put together works great, but when I click on a portfolio item to view it in a single-portfolio.php page, I noticed the menu link to the portfolio page is no longer active, the Blog menu link at the top is now active, but the breadcrumbs navigation shows the correct path. What would cause my blog menu item to suddently become active?
Hey Andre, do you have on online sample for this exercise?
First up, not sure if this is a WordPress issue but it appears a ton of people have 404′s with custom post types and the method to go to the permalinks settings, save, still does not work for me here. In my demo site, under Images, is a menu for the portfolio and a submenu for that going to a category of the portfolio “Happiness”. I get 404′s. But also the issue of the blog link being active when viewing a portfolio item is what is confusing me. I also (testing) added a submenu link on the Portfolio one as “Sleeping is Great” which is a portfolio item. Watch what happens to the top main menu active links.
Site: http://wordpress-themes.gradientpixels.ca/incantation-pro/?page_id=17
So the hard part is to try and determine what the Portfolio type and Portfolio_Category (taxonomy) does and what part is related to WP core.
Well it was 4 days of nightmare hell, but it looks like the issues I posted are actually common with many in relation to custom post types, viewing an item from one, and the active blog menu item (when doing a static front page method), where the blog menu goes active. This points to a WordPress bug and is still existing even with WP 3.3. I would imagine it’s also a WP bug that gives the 404′s on the portfolio category menu links. Long story short, the portfolio works well but the WordPress core has bugs.
Thanks a lot for your sharing !
I spend 3 days to fight with 404 error but it was my fault : I didn’t see that I have to change the custom_post_id AND the taxonomy_id on line 39 in the template file… I realise a bit late that ‘types=’ was your taxonomy id and not an argument
Anyway, I wonder now :
What code can I add to your $query to assign a “current” class to the active filter/order by value ?
Cheers,
Henry from Belgium (Europe)