Blog

Stellar WordPress Portfolio Control with Custom Post / Meta Types

PHP, Tutorials, Wordpress, WordPress Tutorials53 comments

Wordpress 3.0 has introduced a lot of very powerful new features into the theme developer’s toolbox. The most exciting of these is probably the addition of custom post / meta types.

Intro and Prerequisites

We are going to use these features to create a custom “portfolio” post type and add additional options to it using custom metas that will correspond to things like “project URL”, “Client name”, etc.

To define a custom post type, use

register_post_type();

in your functions.php and then customize the post type with a whole slew of options.

Custom metas can be defined with

add_meta_box();

This function also has options.

#1 – Create Custom Post Type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
add_action('init', 'create_portfolio');
function create_portfolio() {
 	$portfolio_args = array(
     	'label' => __('Portfolio'),
     	'singular_label' => __('Portfolio'),
     	'public' => true,
     	'show_ui' => true,
     	'capability_type' => 'post',
     	'hierarchical' => false,
     	'rewrite' => true,
     	'supports' => array('title', 'editor', 'thumbnail')
     );
 	register_post_type('portfolio',$portfolio_args);
}
 
add_action("admin_init", "add_portfolio");
add_action('save_post', 'update_website_url');
add_action('save_post', 'update_client');

This will create our post and tell WordPress to update our custom metas “Website URL” and “Client” when we save the post.

#2 – Add Meta Box

This will add a new write box below your post editor:

1
2
3
function add_portfolio(){
	add_meta_box("portfolio_details", "Item Details", "portfolio_options", "portfolio", "normal", "low");
}

#3 – Create Options for Meta Box

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function portfolio_options(){
	global $post;
	$custom = get_post_custom($post->ID);
	$website_url = $custom["website_url"][0];
	$client = $custom["client"][0];
?>
	<div class="detail">
		<label>Website URL (don't forget <strong>http://</strong>):</label><input name="website_url" value="<?php echo $website_url; ?>" />
	</div>
	<div class="detail">
		<label>client:</label><input name="client" value="<?php echo $client; ?>" />
	</div>
<?php
	}
	function update_website_url(){
		global $post;
		update_post_meta($post->ID, "website_url", $_POST["website_url"]);
	}
	function update_client(){
		global $post;
		update_post_meta($post->ID, "client", $_POST["client"]);
	}
add_filter("manage_edit-portfolio_columns", "portfolio_edit_columns");
add_action("manage_posts_custom_column",  "portfolio_columns_display");

This will add an input box for “Website URL” and “Client”.

#4 – Create Custom Taxonomy

This custom taxonomy is going to function as a “Services Rendered” section that allows the user to select which services were performed for each portfolio item.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
add_action( 'init', 'services_rendered', 0 );
function services_rendered()	{
	register_taxonomy(
		'services_rendered',
		'portfolio',
			array(
				'hierarchical' => true,
				'label' => 'Services Rendered',
				'query_var' => true,
				'rewrite' => true
			)
	);
 
}

#5 – Create Custom Info Columns

The functions below will allow us to customize the data that is displayed in the WordPress admin when browsing the “Portfolio” custom post type items, and also how that data is displayed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function portfolio_edit_columns($portfolio_columns){
	$portfolio_columns = array(
		"cb" => "<input type=\"checkbox\" />",
		"title" => "Project Title",
		"description" => "Description",
		"url" => "Item URL",
		"client" => "client",
		"services" => "services",
	);
	return $portfolio_columns;
}
 
function portfolio_columns_display($portfolio_columns){
	switch ($portfolio_columns)
	{
		case "description":
			the_excerpt();
			break;
		case "client":
  			$meta = get_post_custom();
  			echo $meta["client"][0];
  			break;
		case "url":
  			$meta = get_post_custom();
  			echo $meta["website_url"][0];
  			break;
  		case "services":
  			echo get_the_term_list( $post->ID, 'services_rendered', '<ul><li>','</li><li>','</li></ul>');
  			break;
	}
}

#6 – Display Portfolio Items on Portfolio Page

Use this as your loop in your portfolio page template:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
   $loop = new WP_Query(array('post_type' => 'portfolio', 'posts_per_page' => 10));
?>
<?php while ( $loop->have_posts() ) : $loop->the_post(); ?>
   <div class="portfolio-item">
     <h2><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
 
     <div class="thumbnail">
	<?php the_post_thumbnail(); ?>
     </div>
 
     <div class="excerpt">
	<?php the_excerpt(); ?>
     </div>
 
</div>
 
<?php endwhile(); ?>

# 7 – Display All Data on Single Post Page

Create a new single.php page called single-portfolio.php and add this to it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php if (have_posts()) : ?>
 
<?php while (have_posts()) : the_post(); ?>
 
    <h2><?php the_title(); ?></h2>
 
    <?php the_content('Read the rest of this entry &raquo;'); ?>
 
    <?php
        $custom = get_post_custom($post->ID);
        $customer = $custom["client"][0];
        $website_url = $custom["website_url"][0];
    ?>
 
    <div class="details">
        <h3>Details</h3>
        <div>Client: <span><?=$customer?></span></div>
        <div>URL: <span><a href="<?=$website_url?>"><?=$website_url?></a></span></div>
        <div class="services"><?php echo get_the_term_list( $post->ID, 'servicesRendered', 'Services Rendered: <ul><li>','</li><li>','</li></ul>' ); ?></div>
    </div>

# 8 -Style to Your Heart’s Content

Simple sample:

53 Comments
← Older Comments
  1. rickj says:

    I actually get the same…a blank white page, any help would be great!

  2. rickj says:

    I actually get the same, a blank white page, sorry for the dupe but I wanted to get notified of comments…

  3. rickj says:

    nevermind, I got it. You’re missing the endwhile in your last one

  4. @rickj – Thanks for noticing that.

  5. Shane says:

    I’m surprised no one has pointed this out.
    There is an autosave issue with your custom meta boxes.
    May want to add that statement in.

  6. @Shane – I need to update all of the code in this tutorial as it is rather out of date now. I will see if I can make the update soon.

  7. Kim Smith says:

    Hi Pippin,

    You helped me a while back set up my portfolio site using this tutorial. I have a question about what you helped Henry with (Feb. 2011). He was asking you what statement to use to keep the “Launch Website” link from displaying if there was no url in the field. You gave him the code below, however, I can’t figure out where this code goes.

    if (!empty($website_url) { echo ‘Launch Website‘; }

    In my single-portfolio.php file I have this to display a button to visit the site:
    <a href="” target=”blank”>Visit the Site

    How do I make this conditional. Currently, even if there is no url in the field, the button will still display. You can visit my site to see how I have the page set up. http://www.blueturtlegraphics.com/portfolio_type/web-design-2/

    Any help is much appreciated.
    Kim

  8. @Kim – The anchor link tag needs to go in between the {} of the if statement, where is says echo ‘Launch Website’. Paste your anchor link code into the single quotes after the echo and it should work.

  9. Ingrid says:

    Great tutorial! This is exactly what I was looking for. I’ve followed it but I’m getting a weird error in my dashboard that says: “Warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, ‘admin_portfolio’ was given in /…/wp-includes/plugin.php on line 405″
    I’m trying to figure out how to solve it and I think it has to do with the admin_init function but I’m not much of a developer so I can’t seem to figure out what it needs. Also, when I go to add an entry I’m missing the URL field etc. Could this be because I had previously used the same function name? Any advice would be appreciated and thanks for your hard work, I’m sure you’re tired of answering support questions by now. :)

  10. @Ingrid – the “admin_portfolio” is the name of the function that is used to display the meta box. Make sure that if you changed the function name elsewhere, you change it everywhere. There should be two places the function name is used.

  11. soulmenj says:

    is this applicable in wordpress 3.2.1 version?

    thank you.

  12. @soulmenji – Yes. There are a few areas that could be updated a bit, but overall everything still works perfectly fine.

  13. soulmenj says:

    @pippin: thank you so much! i will try this one. :) I will wait for more updates to this tutorial.

    by the way i subscribed to this tutorial but i haven’t received any notification if someone replied to this thread any remedy?

  14. @soulmenj – check your spam folder

  15. soulmenj says:

    @pippin: thank you … now its working :)

  16. soulmenj says:

    @pippin: do i need to copy the first set of codes and paste it in my function.php file and the rest of the code?

    ‘coz i ended with white page after saving the first snip of codes. “register_post_type();”

  17. @soulmenj – All of the code needs to be pasted. I’ll help you get the issue worked on via email.

  18. Alessio says:

    Please help, I cannot save my custom field… may I post the code here?

  19. @Alessio – yes, you can post it here.

  20. soulmenj says:

    is there any update for this tutorials? :)

  21. No, not at this time. Sorry.

  22. soulmenj says:

    no worries :) thanks

  23. Hello, Pippins i think you miss the end of while and if statement of no 7

← Older Comments
Leave a Reply