There isn’t, by default, a ‘publish’ link because of the way WordPress handles publishing posts. ‘publish‘ is not consider an action in the same way ‘delete‘ is, instead you save the post, with all its data, including its post status.
To get round this you can create your own action handler. In order to avoid potential clashes with WP or other plug-ins, you should probably prefix your custom action, or at the very least your nonce.
The following code should work for this link (note prefixed action and nonce):
$url = add_query_arg(array('action'=>'mypublish', 'post'=>$post->ID),home_url());
echo "<a href="" . wp_nonce_url($url, "my-publish-post_' . $post->ID) . "'>Publish</a>";
The following function performs some checks, publishes the post and then re-directs you to the published post.
//Run the publish function only if the action variable is correct.
if(isset($_REQUEST['action']) && $_REQUEST['action']=='mypublish')
add_action('init','my_publish_draft');
function my_publish_draft(){
//Get the post's ID.
$post_id = (isset($_REQUEST['post']) ? (int) $_REQUEST['post'] : 0);
//No post? Oh well..
if(empty($post_id))
return;
$nonce = $_REQUEST['_wpnonce'];
//Check nonce
if (! wp_verify_nonce($nonce,'my-publish-post_'.$post_id))
wp_die('Are you sure?');
//Check user permissions
if (!current_user_can('publish_posts'))
wp_die("You can't do that");
//Any other checks you may wish to perform..
//Publish post
wp_publish_post( $post_id );
//Redirect to published post
$redirect = get_permalink($post_id);
wp_redirect($redirect);
exit;
}
Edit
As mentioned in the comments, slugs are not set when using this method. WordPress does not automatically give draft posts a slug, but only when you click ‘Publish’. The above does not update the slug, just the status. To get round this you can manually set the slug when you create the draft.
Alternatively, you can replace the wp_publish_post
call with the following (slightly heavier and a bit uglier) code:
$post = get_post($post_id,ARRAY_A);
$post['post_status'] ='publish';
wp_update_post($post);