6

I've created a custom post type with 2 custom fields attached to it... When I create a post of this type and fill in the custom fields, the data is, in fact, saved to the db... However, if I trash one of them, then that post's custom fields data is deleted from the database.

I thought trashing was just supposed to basically change the post_status to "trash" so it's out of view unless you actually delete it permanently?

If that's the case, why am I losing my custom fields data when I trash an item?

Here's all the relevant code for the above question:

<?php
add_action('admin_init', 'wpg_add_testimonial_author');
function wpg_add_testimonial_author() {
  add_meta_box('wpg_testimonial_author', __('Author Information', 'quotable'), 'wpg_testimonial_author', 'testimonials', 'side', 'low');
}

function wpg_testimonial_author() {
  global $post;
  $custom = get_post_custom($post->ID);
  $testimonial_author_name = $custom['testimonial_author_name'][0];
  $testimonial_author_link = $custom['testimonial_author_link'][0];
  ?>
  <p>
    <label><?php _e("Author's Name:", 'quotable'); ?></label>
    <input name="testimonial_author_name" value="<?php echo $testimonial_author_name; ?>" />
  </p>
  <p>
    <label><?php _e('Attribution Link:', 'quotable'); ?></label>
    <input name="testimonial_author_link" value="<?php echo $testimonial_author_link; ?>" />
  </p>
  <?php
}

function wpg_save_testimonial_author() {
  global $post;
  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
    return $post_id;
  }
  if (defined('DOING_AJAX')) {
    return;
  }
  update_post_meta($post->ID, 'testimonial_author_name', $_POST['testimonial_author_name']);
  update_post_meta($post->ID, 'testimonial_author_link', $_POST['testimonial_author_link']);
}
add_action('save_post', 'wpg_save_testimonial_author');

function wpg_row_actions() {
  global $post;
  if($post->post_type == 'page') {
    if(!current_user_can('edit_page')) {
      return;
    }
  }
  else {
    if(!current_user_can('edit_post')) {
      return;
    }
  }
  if($post->post_status == 'trash') {
    $actionLinks  = '<div class="row-actions"><span class="untrash"><a title="'.__('Restore this item', 'quotable').'" href="'.wp_nonce_url(get_admin_url().'post.php?post='.$post->ID.'&action=untrash', 'untrash-'.$post->post_type.'_'.$post->ID).'">'.__('Restore', 'quotable').'</a> | </span>';
    $actionLinks .= '<span class="trash"><a href="'.wp_nonce_url(get_admin_url().'post.php?post='.$post->ID.'&action=delete', 'delete-'.$post->post_type.'_'.$post->ID).'" title="'.__('Delete this item permanently', 'quotable').'" class="submitdelete">'.__('Delete Permanently', 'quotable').'</a></span>';
  }
  else {
    $actionLinks  = '<div class="row-actions"><span class="edit"><a title="'.__('Edit this item', 'quotable').'" href="'.get_admin_url().'post.php?post='.$post->ID.'&action=edit">'.__('Edit', 'quotable').'</a> | </span>';
    $actionLinks .= '<span class="inline hide-if-no-js"><a title="'.__('Edit this item inline', 'quotable').'" class="editinline" href="#">'.__('Quick Edit', 'quotable').'</a> | </span>';
    $actionLinks .= '<span class="trash"><a href="'.wp_nonce_url(get_admin_url().'post.php?post='.$post->ID.'&action=trash', 'trash-'.$post->post_type.'_'.$post->ID).'" title="'.__('Move this item to the Trash', 'quotable').'" class="submitdelete">'._x('Trash', 'verb (ie. trash this post)', 'quotable').'</a></span>';
  }
  return $actionLinks;
}

function wpg_edit_testimonials_columns($columns) {
  $columns = array(
    'cb' => '<input type="checkbox" />',
    'testimonial_author' => __('Author', 'quotable'),
    'testimonial_text' => __('Testimonial', 'quotable'),
    'attribution_link' => __('Attribution Link', 'quotable'),
    'date' => __('Date Added', 'quotable')
  );
  return $columns;
}

function wpg_manage_testimonials_columns($column, $post_id) {
  global $post;
  $custom = get_post_custom($post->ID);
  $testimonial_author_name = $custom['testimonial_author_name'][0];
  $testimonial_author_link = $custom['testimonial_author_link'][0];

  $wpg_row_actions  = wpg_row_actions();

  switch($column) {
    case 'testimonial_author':
      echo $testimonial_author_name.$wpg_row_actions;
    break;

    case 'testimonial_text':
      echo $post->post_content;
    break;

    case 'attribution_link':
      echo $testimonial_author_link;
    break;

    default :
      break;
    }
  }
  add_filter('manage_edit-testimonials_columns', 'wpg_edit_testimonials_columns');
  add_action('manage_testimonials_posts_custom_column', 'wpg_manage_testimonials_columns', 10, 2);

The custom post type doesn't support the "title" portion of posts, so it's not included as one of the columns in the edit posts page. Therefore, I had to hack my own version of the row_actions() function to enable the edit/quick edit/trash links when each post is hovered.

All of the functionality works as it should... Except that the "testimonial author" and "attribution link" values are deleted from the database when moving a post to the trash. No idea why...

1
  • I've narrowed it down... I added yet ANOTHER post type with all the exact same attributes as this one, but I didn't include the custom function for adding the "trash" link. Instead I added the "title" as one of the array keys when setting up the custom columns... However, it still deletes the custom field data even when I trash the post using the original trash link. So this leads me to believe it's got to be something to do with my save method for the custom field data. I read somewhere that "save_post" is fired when trashing a post... Any way around this? Oct 25, 2011 at 3:30

3 Answers 3

4

It seems that the action save_post gets fired when sending a post to the trash... Therefore, my custom metadata save function was being activated with no $_POST data to send thru it.

To circumvent this, I wound up adding a nonce to the save function.

function wpg_testimonial_author() {
  global $post;
  $custom = get_post_custom($post->ID);
  $testimonial_author_name = $custom['testimonial_author_name'][0];
  $testimonial_author_link = $custom['testimonial_author_link'][0];
  ?>
  <p>
    <label><?php _e("Author's Name:", 'quotable'); ?></label>
    <input name="testimonial_author_name" value="<?php echo $testimonial_author_name; ?>" />
  </p>
  <p>
    <label><?php _e('Attribution Link:', 'quotable'); ?></label>
    <input name="testimonial_author_link" value="<?php echo $testimonial_author_link; ?>" />
    <input type="hidden" name="testimonial_author_noncename" id="testimonial_author_noncename" value="<?php echo wp_create_nonce(plugin_basename(__FILE__).$post->ID); ?>" />
  </p>
  <?php
}

function wpg_save_testimonial_author($post_id) {
  global $post;
  if (!wp_verify_nonce($_POST['testimonial_author_noncename'], plugin_basename(__FILE__).$post->ID)) {
    return $post->ID;
  }
  if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
    return $post_id;
  }
  if(defined('DOING_AJAX')) {
    return;
  }
  if(!current_user_can('edit_post')) {
    return $post->ID;
  }
  if($post->post_type == 'revision') {
    return;
  }
  update_post_meta($post->ID, 'testimonial_author_name', $_POST['testimonial_author_name']);
  update_post_meta($post->ID, 'testimonial_author_link', $_POST['testimonial_author_link']);
}
add_action('save_post', 'wpg_save_testimonial_author');

Hopefully this might help someone else later...

2
  • Ah, you've just helped me with a bizarre problem that cost me a few pointless hours..! Much appreciated.
    – turbonerd
    Dec 25, 2011 at 14:57
  • kudos for "It seems that the action save_post gets fired" would have never guess it!
    – Benn
    Feb 12, 2018 at 22:09
3

I have run into the same problem and found even shorter solution (in terms of writing).

if (isset($_POST['action']) && $_POST['action'] == 'editpost') {
// do your update_post_meta, delete_post_meta, etc.
}

I tried to test it now on 5+ WP version and seems to fire only on editing or saving a new post.

2

Wow, thank you Nero_DCLXVI. Very helpful. For future people looking to implement this, here's simplified instructions of his solution:

  1. Add this hidden input along with your other custom meta inputs:
<input 
    type="hidden" \
    name="prevent_delete_meta_movetotrash" 
    id="prevent_delete_meta_movetotrash" 
    value="<?php 
        echo wp_create_nonce( plugin_basename(__FILE__) . $post->ID ); 
    ?>" />
  1. Add this right before your update_post_meta() functions.
if ( ! wp_verify_nonce( 
        $_POST['prevent_delete_meta_movetotrash'], 
        plugin_basename(__FILE__) . $post->ID ) 
    ) { 
    return $post_id; 
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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