No Edit / Delete Links for Custom Post Type?

All we need is an easy explanation of the problem, so here it is.

I’ve created a custom post type for “testimonials” as well as rearranged the edit post display with custom columns for that post type… Everything works as expected EXCEPT for the fact that when I hover over one of these custom posts, the list of “action links” that normally appears beneath it enabling you to edit/delete that post aren’t there…

Here’s a screenshot of what I mean:
enter image description here

Here’s all the related code:

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];

  switch($column) {

    case 'testimonial_author':
      echo $testimonial_author_name;
    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);

My only guess is that maybe it has something to do with the fact that the “title” column isn’t being used? I didn’t see any need in using the title column since the post type doesn’t even support the use of “titles”, as it’s just a testimonial.

EDIT:

Ok, I’ve confirmed that it is, in fact, due to the fact that the title column isn’t being used… I added “title” to the list of columns in the array and the links appeared… However, since titles aren’t supported in this post type, the title is being listed as “Auto Draft” for all of the testimonials.

EDIT AGAIN:

Taking the advice of @helenhousandi, I’ve rolled my own set of links… but now I’m running into an entirely new problem. The delete/trash link uses a nonce, which I’ve added… but I’m apparently missing a step somewhere, because it’s not actually completing the action when clicked.

Instead I’m getting a WordPress failure notice:
enter image description here

Here’s the edited portion of my code:

$wpg_row_actions  = '<div class="row-actions"><span class="edit"><a title="'.__('Edit this item', 'quotable').'" href="'.get_admin_url().'post.php?post='.$post->ID.'&amp;action=edit" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">Edit</a> | </span>';
$wpg_row_actions .= '<span class="inline hide-if-no-js"><a title="'.__('Edit this item inline', 'quotable').'" class="editinline" href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">Quick&nbsp;Edit</a> | </span>';
$wpg_row_actions .= '<span class="trash"><a href="'.wp_nonce_url(get_admin_url().'post.php?post='.$post->ID.'&amp;action=trash', 'delete-post_'.$post->ID).'" rel="nofollow noreferrer noopener" title="'.__('Move this item to the Trash', 'quotable').'" class="submitdelete">Trash</a></span>';


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

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Correct, without the title column, the row actions don’t have a place to show. I haven’t tried doing this before, but take a look at the row_actions() method in the WP_List_Table class. You may not be able to call it directly, but it should show you how those links are built so you can roll them yourself if you need to.

Method 2

Ok, so it may not be the most efficient method… but I’ve found a solution. In the end, I wound up having to write a custom function to handle the addition of the row actions for each post. Here’s how it turned out:

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.'&amp;action=untrash', 'untrash-'.$post->post_type.'_'.$post->ID).'" rel="nofollow noreferrer noopener">'.__('Restore', 'quotable').'</a> | </span>';
    $actionLinks .= '<span class="trash"><a href="'.wp_nonce_url(get_admin_url().'post.php?post='.$post->ID.'&amp;action=delete', 'delete-'.$post->post_type.'_'.$post->ID).'" rel="nofollow noreferrer noopener" 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.'&amp;action=edit" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">'.__('Edit', 'quotable').'</a> | </span>';
    $actionLinks .= '<span class="inline hide-if-no-js"><a title="'.__('Edit this item inline', 'quotable').'" class="editinline" href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">'.__('Quick Edit', 'quotable').'</a> | </span>';
    $actionLinks .= '<span class="trash"><a href="'.wp_nonce_url(get_admin_url().'post.php?post='.$post->ID.'&amp;action=trash', 'trash-'.$post->post_type.'_'.$post->ID).'" rel="nofollow noreferrer noopener" 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 function handles checking to see which version of the row actions needs to be added based on whether you’re viewing the trashed posts or regular ones. Hopefully this will save someone else hours of frustration later on down the road.

It seems now, however, that I’ve stumbled onto an entirely new problem. The custom fields data for each post in this custom post type gets deleted when I “trash” one of them… but that’s a new question entirely.

Method 3

I only wanted the edit button back because alot of the other things can be accomplished either using the bulk actions or inside the actual post so I just retrieved the url of the wordpress site and the post ID and created my own edit link.

$postid = get_the_ID();
$weburl = get_bloginfo('url');
$_cmb_ = get_post_custom($post->ID);
$linktext = $_cmb_["_cmb_link_text"][0];
$linkurl = $_cmb_["_cmb_link_url"][0];

And then in the column output

case "link_text":
echo '<b>'.$linktext.'</b><br> <a href="'.$weburl.'/wp-admin/post.php?post='.$postid.'&action=edit" rel="nofollow noreferrer noopener" title="Edit">Edit</a><br/>';
break;

Hope this helps people who are after a simple answer and just for the edit link.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply