I’m not entirely sure this is WordPress’ fault, but I figure I’d ask anyway and see if anyone else has experienced any problems like this before.
I’m trying to save an array to a wp_options table row. The data is coming from a custom metabox and is being saved when the save_post hook is triggered. I assumed this should do the trick:
update_option("myOptionName", $myArray);
I started getting 4(?!) of each value I saved. For instance:
$myArray = array("option1");
update_option("myOptionName", $myArray);
get_option("myOptionName");
// array([0]=>"option1", [1]=>"option1", [2]=>"option1", [3]=>"option1");
Needless to say, this behavior is extremely annoying. It works perfectly well with strings, but never arrays. I’ve tried to get around this by trying json_encode to store it as a string-y entity, but even that isn’t working. The problem could very well be the legacy code I’ve inherited by taking on this project, but I see nothing pointing to save_post.
Has anyone ever seen a situation like this before?
EDIT: As requested … the save function:
# SAVE BRICK DATA
function brick_update() {
// Verify if this is an auto save routine.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// Check permissions
if ( !current_user_can( 'publish_posts' ) ) { // Check for capabilities
wp_die( 'Sorry, you do not have the capabilities access to this page. :(' );
}
if (!wp_verify_nonce($_REQUEST['brickupdate'], 'brickupdate')) {
return;
}
$newView = array();
$currentView = get_option('ci_guidesbrick_posts');
if (!is_array($currentView)) {
$currentView = (array)$currentView;
}
for (var i = 0, i < count($currentView), i++) {
$newView[i] = $currentView[i];
}
$newView[] = $_REQUEST['postID'];
update_option('ci_guidesbrick_posts', $newView );
}
4 Answers
I had something similar going on when I tried to use the wp_editor()
function while inside a custom metabox. It was wanting to save multiple times.
Take a look at this.
// SAVE Metabox for admin response
add_action('post_updated', 'display_jwl_wp_etickets_response_meta_box_save');
function display_jwl_wp_etickets_response_meta_box_save( $post_id ){
if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
if( !isset( $_POST['jwl_wp_etickets_editor_box_nonce_check'] ) || !wp_verify_nonce( $_POST['jwl_wp_etickets_editor_box_nonce_check'], 'jwl_wp_etickets_editor_box_nonce' ) )
return;
global $post;
$post_type_object = get_post_type_object( $post->post_type );
if ( !current_user_can( $post_type_object->cap->edit_post, $post->ID ) ) {
return;
}
//$values = get_post_custom( $post_id );
$editor_id = 'jwl_wp_etickets_response_editor';
$meta_key = 'jwl_wp_etickets_response_box_select';
$content_post = get_post($post_id);
$old_content = $content_post->post_content;
if(isset($_POST[$editor_id]) && !empty($_POST[$editor_id])) {
if ( !wp_is_post_revision( $post_id ) ){ //IMPORTANT - Can cause infinite loop otherwise : codex - wp_update_post (see note a few lines down)
$new_content="<div class="eMember_admin_div"><p class="eMember_adminname_response"><strong>Admin</strong> on <strong>".date('F j, Y @ g:i a').'</strong> said:</p>'.$_POST[$editor_id].'</div>';
$update_content = array(
'ID' => $post_id,
'post_content' => $new_content.$old_content
);
// IMPORTANT!!!!
//*****
//***** Apparently the 'post_updated' action likes to fire on every WP process while saving the content.
//***** Since we are also firing on 'wp_update_post'; we are getting stuck in a loop.
//***** To get around, unhook the function before sending the revised content with 'wp_update_post'.
//***** This will prevent clashes between 'post_updated' and 'wp_update_post" firing at the same time.
//***** DAMN YOU WORDPRESS!!
//*****
// Unhook this function so it doesn't loop infinitely
remove_action('post_updated', 'display_jwl_wp_etickets_response_meta_box_save');
// Update the post, which calls save_post again
wp_update_post( $update_content );
// Let's check the 'ticket state', and if queued... let's update it to 'in progress'
$terms_types = wp_get_post_terms( $post->ID, 'jwl_wp_etickets_states');
foreach ($terms_types as $term_type) {
if ($term_type == 'Queued' || !empty($term_type)) {
wp_set_post_terms( $post_id, __('In Progress','wp_etickets_lang'), 'jwl_wp_etickets_states' );
}
}
// Do the same for post meta for cool admin filtering
update_post_meta( $post_id, 'jwl_wp_etickets_states_box_select', __('In Progress','wp_etickets_lang'), __('Queued','wp_etickets_lang') );
// Re-hook this function
add_action('post_updated', 'display_jwl_wp_etickets_response_meta_box_save');
}
}
}
Look at line #43. See how I had to remove_action
the original function… run the update… and then add_action
back again?
That may be what you need to do as well.
Here is a quick “example” code:
add_action('post_updated', 'my_metabox_save');
function my_metabox_save() {
// Run checks
// Unhook this function so it doesn't loop infinitely
remove_action('post_updated', 'my_metabox_save');
// Run your update stuff
// Re-hook this function
add_action('post_updated', 'my_metabox_save');
}