I'v re-worked your code. I'll try to explain some of the changes after the code block
add_action("admin_menu", "tf_book_deets_create");
function tf_book_deets_create(){
add_meta_box('tf_book_details', 'Book Details', 'tf_book_details', 'books');
}
function tf_book_details () {
global $post;
$tf_book_media = get_post_meta($post->ID, "tf_book_media", true);
$tf_book_review = get_post_meta($post->ID, "tf_book_review", true);
echo $tf_book_review;
echo $tf_book_media;
?>
<div class="admin_meta">
<ul>
<li><label>Reviews:</label><textarea rows="5" cols="70" name="tf_book_review"><?php echo esc_textarea($tf_book_review); ?></textarea></li>
<li><label>Media:</label><textarea rows="5" cols="70" name="tf_book_media"><?php echo esc_textarea($tf_book_media); ?></textarea></li>
</ul>
<?php wp_nonce_field( 'book-nonce', 'book_nonce_name', false ); ?>
</div>
<?php
}
add_action ('save_post', 'save_tf_book_details');
function save_tf_book_details( $post_id ) {
// make sure we're on a supported post type
if ( $_POST['post_type'] != 'books' ) return;
// verify this came from our screen and with proper authorization.
if ( !wp_verify_nonce( $_POST['book_nonce_name'], 'book-nonce' )) return;
// verify if this is an auto save routine. If it is our form has not been submitted, so we dont want to do anything
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;
// Check permissions
if ( 'page' == $_POST['post_type'] ) {
if ( !current_user_can( 'edit_page', $post_id ) ) return;
} else {
if ( !current_user_can( 'edit_post', $post_id ) ) return;
}
// OK, we're authenticated: we need to find and save the data
if ( isset( $_POST["tf_book_media"] ) ) update_post_meta( $post_id, "tf_book_media", wp_kses_post( $_POST["tf_book_media"] ) );
if ( isset( $_POST["tf_book_review"] ) ) update_post_meta( $post_id, "tf_book_review", wp_kses_post( $_POST["tf_book_review"] ) );
}
Textarea markup
First I switched the textarea markup. The value of a textarea is set in between the opening and closing textarea tags. The textarea's value is also escaped with esc_textarea()
Basic sanitization and nonce security
I added some basic validation and nonce security to the save_tf_book_details()
function. First the nonce
that I added to the metabox callback function is verified here, so we're sure the data is coming from the right place.
I also ran the text area inputs through the wp_kses_post()
function, which filters out any scripts or other tags that are not allowed in regular posts.