ERROR: Options page not found – saving settings page with tabs

First Thing

The fields are registered only when the proper tab is selected to
avoid resetting values in other tabs to defaults on save.

And because of that, you should pass the proper tab name/slug to the wp-admin/options.php page which is where the form is being submitted to.

  1. You can simply pass it as a query string in the form action attribute value:

    <form method="post" action="<?php echo esc_url( add_query_arg( // wrapped for clarity
      'tab', $active_tab, admin_url( 'options.php' )
    ) ); ?>">
    
  2. Or in create_settings_page(), add a hidden input field having the tab slug as the value:

    echo '<input type="hidden" name="tab" value="' . esc_attr( $active_tab ) . '" />';
    submit_button();
    

    And then in the display_options(), retrieve the tab slug using $_REQUEST:

    $active_tab = isset( $_REQUEST['tab'] ) ? $_REQUEST['tab'] : 'general';
    

Either way, the point is so that the register_setting() calls in the display_options() are invoked. Because otherwise, WordPress would throw the “options page not found” error because the option page is not registered.

You could use the whitelist_options filter, but I’d rather want the register_setting() calls be invoked, so I removed this and the associated callback (whitelist_custom_options_page()):

add_action( 'whitelist_options', array( $this, 'whitelist_custom_options_page' ),11 );

Second Thing

Since you’re using the same database option name (eswc_settingz) for all tabs/fields, you should then merge the saved data with the one being submitted:

public function sanitize_general( $input ) {
    $new_input = (array) get_option( 'eswc_settingz' ); // get saved data
    ... add/update new data
    return $new_input;
}

public function sanitize_account( $input ) {
    $new_input = (array) get_option( 'eswc_settingz' ); // get saved data
    ... add/update new data
    return $new_input;
}

Or you could use different database option names:

register_setting( 'general_section', 'eswc_general_settingz', array( $this, 'sanitize_general' ) );
register_setting( 'account_section', 'eswc_account_settingz', array( $this, 'sanitize_account' ) );

Btw, is that “z” in the settingz a typo? Maybe it was meant to be settings?…

Leave a Comment