I have a custom post with a lot of meta boxes. I recently tried to add some dynamic metaboxes, using this question: Create more Meta Boxes as needed
I managed to get the metaboxes to add nicely, the jquery works, everything works except the save_post action – the “Reviews” save nicely, but the “Screenings” don’t. What have I done wrong in my code? I’m sure it must be something very simple that I’m overlooking, perhaps with the nonces?
Edit: I know I can do all of this with one save_post
, and that works if I only have 1 of these dynamic metaboxes, but if I add a second (or more) dynamic metabox section, that data doesn’t save.
Edit: If necessary, I can post my entire custom-posts.php function file to pastebin or something, but I have just included what I think is the relevant snippet here for brevity
Edit: Updated code…
<?php
add_action('save_post', 'save_postdata'); // saves post data from another function earlier on
add_action('save_post', 'save_postdata_dynamic_reviews_metabox' );
add_meta_box("film-reviews", "Reviews", "print_dynamic_reviews_metabox", "film", "normal", "low");
add_action('save_post', 'save_postdata_dynamic_screenings_metabox' );
add_meta_box("film-screenings", "Screenings", "print_dynamic_screenings_metabox", "film", "normal", "low");
/* Prints the box content */
function print_dynamic_reviews_metabox() {
global $post;
// Use nonce for verification
echo '<input type="hidden" name="reviews_noncename" id="reviews_noncename" value="' . wp_create_nonce( 'reviews-nonce' ) . '" />';
echo '<div id="meta_inner-reviews">';
echo '<ol id="reviews-meta">';
$reviews = get_post_meta($post->ID,'reviews',true); //get any previously saved meta as an array so we can display it
// print_r($reviews);
$c = 0;
if( is_array($reviews) ) {
foreach($reviews as $review ) {
if (isset($review['review-name']) || isset($review['review-link']) ) {
echo '
<li><span class="remove-review" title="Delete">Remove</span>
<label><strong>Review Name/Title:</strong> <input type="text" class="meta-review-name saveddata" name="reviews['.$c.'][review-name]" value="'.$review['review-name'].'" /></label>
<label><strong>Review URL:</strong> (don't forget the http://) <input type="text" class="meta-review-url saveddata" name="reviews['.$c.'][review-url]" value="'.$review['review-url'].'" /></label>';
echo '<span class="remove-review" title="Delete">Remove</span></li>';
$c = $c +1;
} // ends if isset $award[album]
} // ends foreach
} // ends if (is_array)
echo '</ol>';
echo '<span class="add-review">Add New Review</span>';
?>
<script>
var $ =jQuery.noConflict();
$(document).ready(function() {
var count = <?php echo $c; ?>;
$(".add-review").click(function() {
count = count + 1;
$('#reviews-meta').append('<li><span class="remove-review" title="Delete">Remove</span> <label><strong>Review Name/Title:</strong> <input type="text" class="meta-review-name" name="reviews['+count+'][review-name]" value="" /></label> <label><strong>Review URL:</strong> (don't forget the http://) <input type="text" class="meta-review-url" name="reviews['+count+'][review-url]" value="" /></label></li> <span class="remove-review" title="Delete">Remove</span>');
return false;
});
$(".remove-review").live('click', function() {
$(this).parent().remove();
});
});
</script>
<?php
echo '</div>'; // ends div#meta_inner
} // ends function print_dynamic_reviews_metabox()
function save_postdata_dynamic_reviews_metabox( $post_id ) {
// 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 $post_id; }}
elseif ( !current_user_can( 'edit_post', $post_id )) { return $post_id;}
// verify this came from the our screen and with proper authorization,
// because save_post can be triggered at other times
if (isset($_POST['reviews_noncename'])){
if ( !wp_verify_nonce( $_POST['reviews_noncename'], 'reviews-nonce' ) )
return;
}else{return;}
// OK, we're authenticated: we need to find and save the data
$reviews = $_POST['reviews'];
update_post_meta($post_id,'reviews',$reviews);
} // ends function save_postdata_dynamic_reviews_metabox
/* Prints the box content */
function print_dynamic_screenings_metabox() {
global $post;
// Use nonce for verification
echo '<input type="hidden" name="screenings_noncename" id="screenings_noncename" value="' . wp_create_nonce( 'screenings-nonce' ) . '" />';
echo '<div id="meta_inner-screenings">';
echo '<ol id="screenings-meta">';
$screenings= get_post_meta($post->ID,'screenings',true); //get any previously saved meta as an array so we can display it
// print_r($screenings);
$c = 0;
if( is_array($screenings) ) {
foreach($screenings as $screening ) {
if (isset($screening['screening-festival-name']) || isset($screening['screening-festival-date']) ) {
echo '
<li><span class="remove-screening" title="Delete">Remove</span>
<label><strong>Festival Name:</strong> <input type="text" class="meta-screening-festival-name saveddata" name="screenings['.$c.'][screening-festival-name]" value="'.$screening['screening-festival-name'].'" /></label>
<label><strong>Festival Date:</strong> <input type="text" class="meta-screening-festival-date saveddata" name="screenings['.$c.'][screening-festival-date]" value="'.$screening['screening-festival-date'].'" /></label>';
echo '<span class="remove-screening" title="Delete">Remove</span></li>';
$c = $c +1;
} // ends if isset $award[album]
} // ends foreach
} // ends if (is_array)
echo '</ol>';
echo '<span class="add-screening">Add New Screening</span>';
?>
<script>
var $ =jQuery.noConflict();
$(document).ready(function() {
var count = <?php echo $c; ?>;
$(".add-screening").click(function() {
count = count + 1;
$('#screenings-meta').append('<li><span class="remove-screening" title="Delete">Remove</span> <label><strong>Festival Name:</strong> <input type="text" class="meta-screening-festival-name" name="screenings['+count+'][screening-festival-name]" value="" /></label> <label><strong>Festival Date:</strong> <input type="text" class="meta-screening-festival-date" name="screenings['+count+'][screening-festival-date]" value="" /></label> <span class="remove-screening" title="Delete">Remove</span>');
return false;
});
$(".remove-screening").live('click', function() {
$(this).parent().remove();
});
});
</script>
<?php
echo '</div>'; // ends div#meta_inner
} // ends function print_dynamic_screenings_metabox()
function save_postdata_dynamic_screenings_metabox( $post_id ) {
// 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 $post_id; }}
elseif ( !current_user_can( 'edit_post', $post_id )) { return $post_id;}
// verify this came from the our screen and with proper authorization,
// because save_post can be triggered at other times
if (isset($_POST['screenings_noncename'])){
if ( !wp_verify_nonce( $_POST['screenings_noncename'], 'screenings-nonce' ) )
return;
}else{return;}
// OK, we're authenticated: we need to find and save the data
$screenings= $_POST['screenings'];
update_post_meta($post_id,'screenings',$screenings);
} // ends function save_postdata_dynamic_screenings_metabox
?>
Following are the issues that were preventing from the meta values to be saved in both of your save functions.
1. Incorrect post_type checking.
You are checking post type to be of ‘page’ in your save function where as your meta boxes are being displayed on your custom post type of ‘film’.
Your code:
It should be:
2. Incorrect nonce field name.
As @tollmanz pointed out you are checking incorrect field names when checking nonces. The field name in save functions should match the input field name in print meta box functions.
Your code:
It should be:
For screening nonce your code:
It should be:
3. Incorrectly saving the meta values.
You were using update_post_meta to store the meta values.
4. Inoccrectly getting meta values.
You were using third parameter in your get_post_meta calls which is to specify to only fetch single meta value, were in your case you need to fetch all meta values.
Your code:
It should be:
Your code for screenings:
It should be:
Below is the correct code. The code below should work for you as I have tested it and it worked fine. If it doesn’t work for some reason I will need to look at your complete code.
I believe the problem lies in the following code:
Good job checking for the nonce; however, the nonce name is incorrect. In the HTML form, you specify:
The name of the nonce field is
reviews_noncename
notreviews-nonce
. So, I believe you can correct the code within the save function to:I think this will fix your problem.