1

Intro

I have a settings page which includes a setting with a more complicated callback function to save.

Save data

To save the data I use the register_setting() function with a custom sanitize callback. I implemented it exactly as the WordPress settings API explains so this works fine.

Remove data from option

To remove data from this option array I use jQuery in combination with an AJAX callback function.

The problem

The problem is that I cannot use update_option() (in my AJAX callback) when the register_setting() is also active. I know this because when I comment out the register_setting() function, the update_option() suddenly works well, where it with the register_setting() uncommented deletes the option.

Does anyone have experience with this problem and knows what I can do to use both functions to update the option?

Setup and register setting

function gtp_init_theme_options() { 

    $page = 'services-settings-page';

    /**
     * Services settings sections and fields
     */
    $section = 'installing_settings_section';

    // Add installation settings section
    add_settings_section( $section, _x( 'Installing', 'Measure and installing', 'gtp_translate' ), 'gtp_display_installing_settings_section', $page );

    // Add and register installation areas
    $id = 'installing_data';
    add_settings_field( $id, __( 'Installing data', 'gtp_translate' ), 'gtp_settings_installing_data_fields', $page, $section, array( 'id' => $id, 'label_for' => $id ) );
    register_setting( 'services-theme-settings', $id, 'gtp_register_installing_data_setting' ); 

}
add_action( 'admin_init', 'gtp_init_theme_options' );

The sanitize callback called by the register_setting()

/**
 * Sanatizes callback for saving installation areas
 */
function gtp_register_installing_data_setting() {

    // Initialize object
    $installing     = new Installing();

    $error = false;

    // Check if country isset
    if ( ! empty( $_POST['existing_country'] ) ) {
        $country = strtolower( $_POST['existing_country'] );
    } elseif ( ! empty( $_POST['country'] ) ) {
        $country = strtolower( $_POST['country'] );
    } else {
        $error = true;  
    }

    // Check if zipcode isset
    if ( ! empty( $_POST['existing_zipcode_area'] ) ) {
        $range = $_POST['existing_zipcode_area'];
    } elseif ( ! empty( $_POST['zipcode_from'] ) && ! empty( $_POST['zipcode_to'] ) ) {
        $range = $_POST['zipcode_from'] . '-' . $_POST['zipcode_to'];
    } else {
        $error = true;  
    }

    // Check if product isset
    if ( ! empty( $_POST['existing_product'] ) ) {
        $product = strtolower( $_POST['existing_product'] );    
    } elseif ( ! empty( $_POST['product'] ) ) {
        $product = strtolower( $_POST['product'] );
    } else {
        $error = true;  
    }

    // Check if price isset
    if ( ! empty( $_POST['price'] ) ) {
        $price = str_replace( ',', '.', $_POST['price'] );
    } else {
        $error = true;  
    }

    // No errors
    if ( ! $error ) {

        // Add row to data array
        $installing->addRow( $country, $range, $product, $price );

        // Return data array
        return $installing->getData();

    }

}

AJAX callback function

/**
 * Remove installing data in admin AJAX handle
 */
function gtp_remove_installing_data() {

    // Initialize object
    $installing     = new Installing();

    // Remove product
    if ( ! empty( $_POST['country'] ) && ! empty( $_POST['zipcode_area'] ) && ! empty( $_POST['product'] ) ) {
        $installing->removeRow( $_POST['country'], $_POST['zipcode_area'], $_POST['product'] );
    } 
    // Remove zipcode area
    elseif ( ! empty( $_POST['country'] ) && ! empty( $_POST['zipcode_area'] ) ) {
        $installing->removeRow( $_POST['country'], $_POST['zipcode_area'] );
    }
    // Remove country
    elseif ( ! empty( $_POST['country'] ) ) {
        $installing->removeRow( $_POST['country'] );
    }

    // Update 
    $installing->update();

    die;        
}
add_action( 'wp_ajax_remove_installing_data', 'gtp_remove_installing_data' );
add_action( 'wp_ajax_nopriv_remove_installing_data', 'gtp_remove_installing_data' );

I have attached an image of the settings screen for your imagination what kind of project I am working on.

enter image description here

  • 1
    Well it will be better if you share your code? – Sumit Jun 3 '16 at 14:14
  • @Sumit I have added the code now. – Robbert Jun 3 '16 at 15:32
0

Note what happens when you provide sanitize callback in register_setting(). It register a filter to sanitize your options

add_filter( "sanitize_option_{$option_name}", $sanitize_callback );

Now when you do update_option() then trigger your own function to prevent saving :D

Because update_option() calls $value = sanitize_option( $option, $value );

Solution: Remove register_settings() callback before you call update_option().

function gtp_remove_installing_data() {

    //Your code 

    //Remove sanitizing for adding
    remove_filter( "sanitize_option_installing_data", 'gtp_register_installing_data_setting' );

    // Update 
    $installing->update();

    die;        
}
0

This is just a hunch, but it seems to me that this problem has something to do with the order in which the operations are called.

If you have defined your hooks wp_ajax_remove_installing_data and wp_ajax_nopriv_remove_installing_data in your plugin and hooked that plugin in the usual way into WP with the init hook, it means this code is executed before register_setting, which you hook into admin_init, which is later in the queue.

Now, you are updating the option directly, not through the Options API. As you can read at the bottom of the codex page on update_option, this means the cache is not updated. So, you are deleting the option, but when register_setting is called further on, it gets the value from the cache and sets it again.

The solution would be to clear the cache after updating the option, or to hook register_setting in init as well and make sure it has a higher priority than your update function, so the latter is executed after the call to register_setting. Disclaimer: I haven't tried this.

  • it means this code is executed before register_setting, which you hook into admin_init. Completely wrong! every Ajax callback is called after admin_init is done. Take a look here – Sumit Jun 3 '16 at 17:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.