Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I just set up a custom post type, mostly following this tutorial.

I'm setting up things on my site now, doing a lot of CSS modifications and such, and every few minutes the post just forgets everything that's in the custom meta boxes.

I'm sure I've done something wrong in the add_action/update_post_meta section, but I don't know what it is, because I don't really understand the entirety of what the code does.

In any case, here's the entire thing:

add_action('init', 'portfolio_register');

function portfolio_register() {

    $labels = array(
        'name' => _x('My Portfolio', 'post type general name'),
        'singular_name' => _x('Portfolio Item', 'post type singular name'),
        'add_new' => _x('Add New', 'portfolio item'),
        'add_new_item' => __('Add New Portfolio Item'),
        'edit_item' => __('Edit Portfolio Item'),
        'new_item' => __('New Portfolio Item'),
        'view_item' => __('View Portfolio Item'),
        'search_items' => __('Search Portfolio'),
        'not_found' =>  __('Nothing found'),
        'not_found_in_trash' => __('Nothing found in Trash'),
        'parent_item_colon' => ''
    );

    $args = array(
        'labels' => $labels,
        'public' => true,
        'publicly_queryable' => true,
        'show_ui' => true,
        'query_var' => true,
        'menu_icon' => get_stylesheet_directory_uri() . '/article16.png',
        'rewrite' => true,
        'capability_type' => 'post',
        'hierarchical' => false,
        'menu_position' => null,
        'supports' => array('title','editor','thumbnail')
      ); 

    register_post_type( 'portfolio' , $args );
}

register_taxonomy("portfolio_cat", array("portfolio"), array("hierarchical" => true, "label" => "Categories", "singular_label" => "Category", "rewrite" => true));

add_action("admin_init", "admin_init");

function admin_init(){
  add_meta_box("media_meta", "Media", "media_meta", "portfolio", "normal", "low");
  add_meta_box("highlights_meta", "Highlights", "highlights_meta", "portfolio", "normal", "low");
  add_meta_box("main_meta", "Main", "main_meta", "portfolio", "normal", "low");
  add_meta_box("tabbed_meta", "Tabbed", "tabbed_meta", "portfolio", "normal", "low");
}


function media_meta(){
  global $post;
  $custom = get_post_custom($post->ID);
  $media_meta = $custom["media_meta"][0];
  ?>
  <p><label>Media:</label><br />
  <textarea cols="110" rows="5" name="media_meta"><?php echo $media_meta; ?></textarea></p>
  <?php
}

function highlights_meta(){
  global $post;
  $custom = get_post_custom($post->ID);
  $highlights_meta = $custom["highlights_meta"][0];
  ?>
  <p><label>Highlights:</label><br />
  <textarea cols="110" rows="5" name="highlights_meta"><?php echo $highlights_meta; ?></textarea></p>
  <?php
}

function main_meta(){
  global $post;
  $custom = get_post_custom($post->ID);
  $main_meta = $custom["main_meta"][0];
  ?>
  <p><label>Main:</label><br />
  <textarea cols="110" rows="5" name="main_meta"><?php echo $main_meta; ?></textarea></p>
  <?php
}

function tabbed_meta(){
  global $post;
  $custom = get_post_custom($post->ID);
  $tabbed_meta = $custom["tabbed_meta"][0];
  ?>
  <p><label>Tabbed:</label><br />
  <textarea cols="110" rows="5" name="tabbed_meta"><?php echo $tabbed_meta; ?></textarea></p>
  <?php
}

add_action('save_post', 'save_details');

function save_details(){
  global $post;

  update_post_meta($post->ID, "media_meta", $_POST["media_meta"]);
  update_post_meta($post->ID, "highlights_meta", $_POST["highlights_meta"]);
  update_post_meta($post->ID, "main_meta", $_POST["main_meta"]);
  update_post_meta($post->ID, "tabbed_meta", $_POST["tabbed_meta"]);
}

add_action("manage_posts_custom_column",  "portfolio_custom_columns");
add_filter("manage_edit-portfolio_columns", "portfolio_edit_columns");

function portfolio_edit_columns($columns){
  $columns = array(
    "cb" => "<input type=\"checkbox\" />",
    "title" => "Portfolio Title",
    "description" => "Description",
    "media_meta" => "Media",
    "highlights_meta" => "Highlights",
    "main_meta" => "Main",
    "tabbed_meta" => "Tabbed",
    "portfolio_cat" => "Portfolio Categories"
  );

  return $columns;
}
function portfolio_custom_columns($column){
  global $post;

  switch ($column) {
    case "description":
      the_excerpt();
      break;
    case "media_meta":
      $custom = get_post_custom();
      echo $custom["media_meta"][0];
      break;
    case "highlights_meta":
      $custom = get_post_custom();
      echo $custom["highlights_meta"][0];
      break;
    case "main_meta":
      $custom = get_post_custom();
      echo $custom["main_meta"][0];
      break;
    case "tabbed_meta":
      $custom = get_post_custom();
      echo $custom["tabbed_meta"][0];
      break;
    case "portfolio_cat":
      echo get_the_term_list($post->ID, 'portfolio_cat', '', ', ','');
      break;
  }
}
share|improve this question
1  
I don't have time to sift through your code for an answer (sorry), but I'd like to point out that you really should consider using a better naming scheme, functions like admin_init() have a REALLY high possibility of conflicting with other core or plugin functions. –  m0r7if3r Feb 14 '12 at 2:05
    
Oh, that’s a really terrible tutorial. So many errors. –  toscho Feb 14 '12 at 3:25
    
Yeah, agreed on both counts. It's a bad tutorial. –  amphibious Feb 14 '12 at 4:19

2 Answers 2

up vote 4 down vote accepted

In the function hooked onto save_posts you should make sure that you check that the action wasn't triggered by an auto-save routine. I suspect that the reason why the post 'forgets' the data is that the post auto-saves, and updates the post-meta with blank data.

To do this:

function save_details($post_id){
    //Make sure you check this isn't an autosave.
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
         return;

    update_post_meta($post_id, "media_meta", $_POST["media_meta"]);
    update_post_meta($post_id, "highlights_meta", $_POST["highlights_meta"]);
    update_post_meta($post_id, "main_meta", $_POST["main_meta"]);
    update_post_meta($post_id, "tabbed_meta", $_POST["tabbed_meta"]);
}

I've had a quick glance at the tutorial. It seems to ignore best practice and security checks such as the following:

  1. The function hooked on save_posts is given the argument $post_id (the post ID). You should use this rather than global $post.
  2. Prefix your functions. save_details is very generic, and if the WordPress core or another plug-in uses that function name, it'll crash your blog. This is particularly important for plugin developers. Prefix it with something unique: my_name_save_details. Same goes for the other functions.
  3. Check user permissions. Use current_user_can to verify that a user is allowed to be editing the post.
  4. Uses nonces. In your metabox, add a nonce and verify it in my_name_save_details. This checks the data you're adding to your database really came from your metabox.(See Codex)
  5. Perform other checks. save_posts fires every time a post or page is saved/updated, but you only really want to be altering posts of your custom post type. It's not essential, but removes the possibility of upsets further down the line. You can use get_post_type to help with this.
share|improve this answer
    
A side note: you can include multiple fields inside a metabox. I'd recommend taking a look at this Codex page for a 'best practise' example (it's not a tutorial though...). Hope this helps :D –  Stephen Harris Feb 14 '12 at 2:37
    
For a minimal example see my basic meta box. –  toscho Feb 14 '12 at 3:22

The answer from Stephen Harris is excellent, but shows that rolling your own friendly custom fields can be a real pain. To do things securely and robustly you have to hold WordPress' hand quite a bit. I'll save my rant about how WordPress should do many of these things by default. Instead, I'll point you to the Advanced Custom Fields plugin which will help with everything in the above question.

The plugin has nice documentation for each of the different types of fields provided, and handy code snippets for getting the data out and into your templates.

Best of all, it's free for everything you're trying to use it for.

This plugin isn't perfect for every site, but it's great for when you just want to add a few extra fields to a custom post type.

If you're interested in continuing with rolling your own friendly custom fields, I highly recommend this article from .net magazine. It walks through the issues you're experiencing, and has helped me in the past.

share|improve this answer
    
Excellent suggestions. Thanks. –  amphibious Feb 14 '12 at 15:04

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.