I am creating a metabox that loops through all the posts of another CPT: 'product'. The metabox lists all the published products in that CPT, puts them in a table row along with an input box. Each input box has a unique ID based off of the CPT product id.
Most of this code I have added based on other posts, but I am having a problem saving the data. I know that it has to do with my value="", my nonce, and $meta_value, but I am not sure where to go next. Below is the code I have so far:
<?php
add_action('admin_init', 'my_theme_on_admin_init');
function my_theme_on_admin_init() {
add_meta_box('my_metabox',
__('Daily Inventory Levels', 'textdomain'),
'my_metabox_render',
'location_inventory', 'normal', 'high'
);
}
function my_metabox_render($post) {
// using an underscore, prevents the meta variable
// from showing up in the custom fields section
global $woocommerce, $post;
$productsList = new WP_Query( 'post_type=product&post_status=publish');
?>
<div class="inside">
<table class="form-table">
<input type="hidden" name="inventory_noncename" id="inventory_noncename" value="<?php wp_create_nonce( 'inventory-nonce' ); ?>" />
<?php
while ( $productsList->have_posts() ) {
$productsList->the_post();
?>
<tr><td><label for="location_inventory_product-<?php the_ID(); ?>"><?php the_title(); ?></label></td><td><input id="location_inventory_product-<?php the_ID(); ?>" name="location_inventory_product-<?php the_ID(); ?>" cols="40" rows="5" value="<?php echo $meta_key; ?>" /></td></tr>
<?php }
wp_reset_postdata();
?>
</table>
</div>
<?php
}
/*update on save*/
add_action('save_post', 'save_postdata_dynamic_inventory_metabox' );
function save_postdata_dynamic_inventory_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 ( 'location_inventory' == $_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['inventory_noncename'])){
if ( !wp_verify_nonce( $_POST['inventory_noncename'], 'inventory-nonce' ) )
return;
} else {
return;
}
// Get the posted data and sanitize it for use as an HTML class.
$new_meta_value = ( isset( $_POST['location_inventory_product-'.the_ID().''] ) ? sanitize_html_class( $_POST['location_inventory_product-'.the_ID().''] ) : '' );
// Get the meta key.
$meta_key = 'location_inventory_product-'.the_ID().'';
// Get the meta value of the custom field key.
$meta_value = get_post_meta( $post_id, $meta_key, true );
// If a new meta value was added and there was no previous value, add it.
if ( $new_meta_value && '' == $meta_value )
add_post_meta( $post_id, $meta_key, $new_meta_value, true );
// If the new meta value does not match the old value, update it.
elseif ( $new_meta_value && $new_meta_value != $meta_value )
update_post_meta( $post_id, $meta_key, $new_meta_value );
// If there is no new meta value but an old value exists, delete it.
elseif ( '' == $new_meta_value && $meta_value )
delete_post_meta( $post_id, $meta_key, $meta_value );
} // ends function save_postdata_dynamic_reviews_metabox
Some observations:
1) The hook save_post takes 2 arguments:
add_action( 'save_post', 'save_postdata_dynamic_inventory_metabox', 10, 2 );
function save_postdata_dynamic_inventory_metabox( $post_id, $post_object ) { }
2) I don't think checking for permissions is necessary (at least, never seen it). Just in case, this is an example of the post_object use:
if ( 'location_inventory' == $post_object->post_type )
3) Short this check:
if ( !isset($_POST['inventory_noncename']) || !wp_verify_nonce( $_POST['inventory_noncename'], 'inventory-nonce' ) )
return;
4) The use of the_ID() inside the function save_postdata_dynamic_inventory_metabox is wrong. This is only available inside a Loop and you already have $post_id at hand.
5) Finally, and the most important, the way you're handling the $meta_key is wrong. For one, it's not defined inside the function my_metabox_render. Check this Answer for a working example.
Research in this search query to find more examples.
Related
I have a problem with updating my custom meta box in wordpress for a custom post news. I have made a meta box checkbox so I could decide if the post is featured or not. If the checkbox is checked then isFeatured = 1. Until this part it works, the problem is when after sometime I wan't to edit the post and deselect the checkbox. After updating the post the checkbox is checked all the time.
The database: meta_key | meta_value ---- > news_details | a:1:{s:10:"isFeatured";s:1:"1";}
This is how my code looks:
function add_news_details_meta_box() {
add_meta_box(
'news_details_meta_box', // $id
'Checkbox', // $title
'show_news_details_meta_box', // $callback
'news', // $screen
'normal', // $context
'high' // $priority
);
}
add_action( 'add_meta_boxes', 'add_news_details_meta_box' );
function show_news_details_meta_box() {
global $post;
$meta = get_post_meta( $post->ID, 'news_details', true ); ?>
<input type="hidden" name="news_details_meta_box_nonce" value="<?php echo wp_create_nonce( basename(__FILE__) ); ?>">
<p>
<label for="news_details[isFeatured]">Is this post featured?
<input type="checkbox" name="news_details[isFeatured]" value="1" <?php if (is_array($meta) && $meta['isFeatured'] === '1' ) { echo 'checked';} else { echo 'Unchecked';}?>>
</label>
</p>
<?php
}
function save_news_details_meta( $post_id ) {
// verify nonce
if ( !wp_verify_nonce( $_POST['news_details_meta_box_nonce'], basename(__FILE__) ) ) {
return $post_id;
}
// check autosave
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
// 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;
}
}
$old = get_post_meta( $post_id, 'news_details', true );
$new = $_POST['news_details'];
if ( $new && $new !== $old ) {
update_post_meta( $post_id, 'news_details', $new );
} elseif ( '' === $new && $old ) {
delete_post_meta( $post_id, 'news_details', $old );
}
}
add_action( 'save_post', 'save_news_details_meta' );
Could you explain to me what's wrong with updating the checkbox after sometime?
I think you should check the if condition. The way I got your description, the $meta['isFeatured'] === '1' always becomes true. You set the value to 1 in the input tag. So on save the value of 1 gets saved to the field I guess. On next load you are checking with an if, if the $meta['isFeatured'] is 1, so this is always true.
You could check if the checkbox in the form is checked with:
isset($_POST['name_of_your_checkbox_input'])
If it is set, you save the value of 1. If not, you stay at the pre defined value of 0.
What worked for me in this case was changing } elseif ( '' === $new && $old ) { to } else ( '' === $new && $old ) {
I have a custom metabox that I created and have been using on my website for a while, but there's a bit of an issue with how it saves. It tends to be rather volatile, meaning that when backing-up with xml or bulk-editing, it will always lose the data.
The following is the code that I use for the checkbox and to save it
function member_page_featured_meta() {
add_meta_box( 'member_page_meta', __( 'Page Template (if default, select none)', 'member_page_textdomain' ), 'member_page_meta_callback', 'page', 'side', 'low' );
}
add_action( 'add_meta_boxes', 'member_page_featured_meta' );
/**
* Outputs the content of the meta box
*/
function member_page_meta_callback( $post ) {
$values = get_post_meta( $post->ID );
$check = isset( $values['member_box_check'] ) ? esc_attr( $values['member_box_check'][0] ) : '';
wp_nonce_field( basename( __FILE__ ), 'member_page_nonce' );
$member_page_stored_meta = get_post_meta( $post->ID );
?>
<p>
<div class="member_page-row-content">
<label for="featured-checkbox">
<input type="checkbox" name="featured-checkbox" id="featured-checkbox" value="yes" <?php if ( isset ( $member_page_stored_meta['featured-checkbox'] ) ) checked( $member_page_stored_meta['featured-checkbox'][0], 'yes' ); ?> />
<?php _e( 'Member Page', 'member_page_textdomain' )?>
</label><br />
<label for="list-checkbox">
<input type="checkbox" name="list-checkbox" id="list-checkbox" value="yes" <?php if ( isset ( $member_page_stored_meta['list-checkbox'] ) ) checked( $member_page_stored_meta['list-checkbox'][0], 'yes' ); ?> />
<?php _e( 'Home List', 'member_page_textdomain' )?>
</label><br />
</div>
</p>
<?php
}
/**
* Saves the custom meta input
*/
function member_page_meta_save( $post_id ) {
// Checks save status - overcome autosave, etc.
$is_autosave = wp_is_post_autosave( $post_id );
$is_revision = wp_is_post_revision( $post_id );
$is_valid_nonce = ( isset( $_POST[ 'member_page_nonce' ] ) && wp_verify_nonce( $_POST[ 'member_page_nonce' ], basename( __FILE__ ) ) ) ? 'true' : 'false';
// Exits script depending on save status
if ( $is_autosave || $is_revision || !$is_valid_nonce ) {
return;
}
// Checks for input and saves - save checked as yes and unchecked at no
//This line of code is my hack (just keeps the boxes from saving pretty much)
//if (!empty($_POST['featured-checkbox']) && !empty($_POST['list-checkbox'])) {
if( isset( $_POST[ 'featured-checkbox' ] ) ) {
update_post_meta( $post_id, 'featured-checkbox', 'yes' );
} else {
update_post_meta( $post_id, 'featured-checkbox', 'no' );
};
if( isset( $_POST[ 'list-checkbox' ] ) ) {
update_post_meta( $post_id, 'list-checkbox', 'yes' );
} else {
update_post_meta( $post_id, 'list-checkbox', 'no' );
};
// (bracket ending the first if statement) }
}
add_action( 'save_post', 'member_page_meta_save' );
Is there any way to prevent this issue from happening or is it just something that has to be dealt with when saving check-boxes?
I've sorted out a bit of a hack that is working for now, but whenever I need to make changes to the check-boxes (which is fairly often by the nature of how they're used), I have to comment out a few lines of code, make the change, then un-comment the lines of code and it's a bit unconventional.
I mostly need to make it work when backing-up and restoring (on my backup/production website).
The save_post action is triggered when a post is created or updated, so quick edits and regular edits and the import of posts will trigger it too.
It is actually your script which clears the post meta when doing a quick edit or import, because the POST array does not contain the previously saved values of the checkboxes.
To solve this, you might want to know the "type of saving" currently happening, and only update the post meta when you are on the post edit screen in the admin area. A way of doing this is to check the action parameter of the POST array like the following, because the action parameter only has the value editpost when saving from a post edit screen:
if (filter_input(INPUT_POST, 'action') != 'editpost') {
return;
}
Putting this code at the beginning of the function hooked to the save_post action (member_page_meta_save in your case) will let the rest of the function run only when saving from the post edit screen.
I've created a Custom Post Type 'media-page-items' that I'm attempting to add meta boxes to. Currently the meta boxes are showing but not saving to the database. I've tried a few different approaches on it and none of them seem to save to database.
Debug is turned on but no errors are being thrown currently that I can see.
Any help is much appreciated!
//add article link to media page item
add_action( 'admin_menu', 'gruman_article_link_create' );
add_action( 'save_post', 'gruman_article_link_save', 10, 2 );
function gruman_article_link_create() {
add_meta_box( 'gruman-article-link', 'Article Link', 'gruman_article_link', 'media-page-items', 'advanced', 'high' );
}
function gruman_article_link( $post ) {
// retrieve the _gruman_article_title current value
$current_article_link = get_post_meta( $post->ID, '_gruman_article_link', true );
?>
<p>
<label>Article Link</label>
<br />
<input name="gruman-article-link" id="article-link" style="width: 97%;"><?php $current_article_link; ?>/>
<input type="hidden" name="gruman_article_link_nonce" value="<?php echo wp_create_nonce( plugin_basename( __FILE__ ) ); ?>" />
</p>
<?php }
function gruman_article_link_save( $post_id ) {
// verify taxonomies meta box nonce
if ( !isset( $_POST['gruman_article_link_nonce'] ) || !wp_verify_nonce( $_POST['gruman_article_link_nonce'], basename( __FILE__ ) ) ){
return $post_id;
}
// return if autosave
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ){
return $post_id;
}
// Check the user's permissions.
if ( !current_user_can( 'edit_post', $post_id ) ){
return $post_id;
}
// store article title value
if ( isset( $_REQUEST['gruman-article-link'] ) ) {
update_post_meta( $post_id, '_gruman_article_link', sanitize_text_field( $_POST['gruman-article-link'] ) );
}
}
In wp_create_nonce you are using plugin_basename( __FILE__ ).
And when you verifying nonce you use basename( __FILE__ ) as action name.
Those values are not the same. First one will return something like my-plugin/my-plugin.php and the second will be my-plugin.php
That is why I believe wp_verify_nonce returns False and your data is not saved.
I want to change the slug of a post with a custom field.
In example, if the custom field is "keyword" my post link will become: mysite.com/keyword.
I wrote this script in fonction.php:
function change_default_slug($id) {
// get part number
$partno = get_post_meta( $id, 'partno', true );
$post_to_update = get_post( $id );
// prevent empty slug, running at every post_type and infinite loop
if ( $partno == '' )
return;
$updated_post = array();
$updated_post['ID'] = $id;
$updated_post['post_name'] = $partno;
wp_update_post( $updated_post ); // update newly created post
}
add_action('save_post', 'change_default_slug');
add_action( 'add_meta_boxes', 'cd_meta_box_add' );
function cd_meta_box_add()
{
add_meta_box( 'my-meta-box-id', 'My First Meta Box', 'cd_meta_box_cb', 'post', 'normal', 'high' );
}
function cd_meta_box_cb( $post )
{
$values = get_post_custom( $post->ID );
$text = isset( $values['my_meta_box_text'] ) ? esc_attr( $values['my_meta_box_text'][0] ) : '';
wp_nonce_field( 'my_meta_box_nonce', 'meta_box_nonce' );
?>
<p>
<label for="my_meta_box_text">Text Label</label>
<input type="text" name="my_meta_box_text" id="my_meta_box_text" value="<?php echo $text; ?>" />
</p>
<?php
}
add_action( 'save_post', 'cd_meta_box_save' );
function cd_meta_box_save( $post_id )
{
// Bail if we're doing an auto save
if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
// if our nonce isn't there, or we can't verify it, bail
if( !isset( $_POST['meta_box_nonce'] ) || !wp_verify_nonce( $_POST['meta_box_nonce'], 'my_meta_box_nonce' ) ) return;
// if our current user can't edit this post, bail
if( !current_user_can( 'edit_post' ) ) return;
// now we can actually save the data
$allowed = array(
'a' => array( // on allow a tags
'href' => array() // and those anchords can only have href attribute
)
);
// Probably a good idea to make sure your data is set
if( isset( $_POST['my_meta_box_text'] ) )
update_post_meta( $post_id, 'my_meta_box_text', wp_kses( $_POST['my_meta_box_text'], $allowed ) );
}
$partno = get_post_meta($post->ID,'my_meta_box_text',true);
echo $partno;
This script return me "Fatal error: Maximum execution time of 30 seconds exceeded". But it seems it work because my slug change. Any idea about this issue?
The 'save_post' action gets called by wp_update_post(), so your change_default_slug() function causes an infinite loop. You need to perform a check within change_default_slug() and bail out if the function has already been called:
function change_default_slug($id) {
static $beentheredonethat = false;
if ($beentheredonethat) return;
$beentheredonethat = true;
//do your stuff and save the post...
}
I'm trying to add a checkbox into my custom meta box in WordPress and I ran into a problem with saving it - whenever I check the checkbox and update the post/page, it comes back unchecked again.
Here's the code I'm using:
add_meta_box(
'sl-meta-box-sidebar', // id
'Sidebar On/Off', // title
'sl_meta_box_sidebar', // callback function
'page', // type of write screen
'side', // context
'low' // priority
);
function sl_meta_box_sidebar() {
global $meta; sl_post_meta( $post->ID ); ?>
<input type="checkbox" name="sl_meta[sidebar]" value="<?php echo htmlspecialchars ($meta['sidebar']); ?>" />Check to turn the sidebar <strong>off</strong> on this page.
}
This creates the checkbox in the sidebar of the "Edit Page" screen, as it should, no problem there. I'm not sure what should I enter in the value of the checkbox, with text fields it obviously returns whatever was saved as meta information... I tried just using "checked" instead cause that would be my first guess (then simply check for the value when using this meta data), but it didn't save the checkbox either.
Here's the function that saves all the meta data, which I assume causes this problem:
function sl_save_meta_box( $post_id, $post ) {
global $post, $type;
$post = get_post( $post_id );
if( !isset( $_POST[ "sl_meta" ] ) )
return;
if( $post->post_type == 'revision' )
return;
if( !current_user_can( 'edit_post', $post_id ))
return;
$meta = apply_filters( 'sl_post_meta', $_POST[ "sl_meta" ] );
foreach( $meta as $key => $meta_box ) {
$key = 'meta_' . $key;
$curdata = $meta_box;
$olddata = get_post_meta( $post_id, $key, true );
if( $olddata == "" && $curdata != "" )
add_post_meta( $post_id, $key, $curdata );
elseif( $curdata != $olddata )
update_post_meta( $post_id, $key, $curdata, $olddata );
elseif( $curdata == "" )
delete_post_meta( $post_id, $key );
}
do_action( 'sl_saved_meta', $post );
}
add_action( 'save_post', 'sl_save_meta_box', 1, 2 );
It works perfectly for text fields, but the checkbox just won't save. I'm not sure if the saving function is wrong, or am I missing something about the value of the checkbox.
Any help appreciated!
I had trouble with this previously and here is how I solved it.
First, creating the Checkbox.
<?php
function sl_meta_box_sidebar(){
global $post;
$custom = get_post_custom($post->ID);
$sl_meta_box_sidebar = $custom["sl-meta-box-sidebar"][0];
?>
<input type="checkbox" name="sl-meta-box-sidebar" <?php if( $sl_meta_box_sidebar == true ) { ?>checked="checked"<?php } ?> /> Check the Box.
<?php } ?>
Next, saving.
<?php
add_action('save_post', 'save_details');
function save_details($post_ID = 0) {
$post_ID = (int) $post_ID;
$post_type = get_post_type( $post_ID );
$post_status = get_post_status( $post_ID );
if ($post_type) {
update_post_meta($post_ID, "sl-meta-box-sidebar", $_POST["sl-meta-box-sidebar"]);
}
return $post_ID;
} ?>