I am developing a payments gateway, and wanted to have a page with a form to save authentication credentials for reaching out to an external API used for payment. I made a settings page using WordPress's Settings API for my plugin, which has been great, except for some odd behavior I haven't seen anybody else have. Whenever I am on the page created by my code, input the settings into my fields, and click "save", the fields completely empty themselves. I have also checked to see whether or not my settings have saved to the database by echoing them to the display of that page, which you can see in the function elv_render_forms_description near the bottom of my code, and found that, at first, entering ONE field functioned properly, but after trying to save more than one, none of the fields saved. I have not been able to recreate this behavior. To my understanding, only using the "register_setting()" function ONCE, and then putting multiple settings within it via "add_settings_group()", and "add_settings_field()", makes it such that everything may be retrieved in ONE database query as an array, and since the settings shown here will all be used at once when reaching out to an external API, I figured this was best for my use case. My "$default_values" also seemed to function for the display, but did not show themselves in my display of the data from elv_render_forms_description, and do not seem to function after trying to input data into the fields and save them.
I have looked around here on the Wordpress Stack Exchange, at the WordPress documentation of Settings API, at what the functions I'm using actually mean and require on the WordPress Developer resources page, at Stack Overflow, and over many sites found via Google, but have not been able to figure out what my problem is. I am totally stuck. I would appreciate any discussion or help.
// If this file is accessed directly, abort it defined ('ABSPATH' ) or die( 'Unauthorized Access' ); //-------------------------------------------------------------------------------------------------------------------------------------- // 1.) Hooks settings page onto wordpress dashboard under "Settings" menu // 2.) Hooks elv_register_settings() into Settings API to maintain plugin options in the database. //-------------------------------------------------------------------------------------------------------------------------------------- add_action( 'admin_menu', 'elv_add_settings_page' ); add_action( 'admin_init', 'elv_register_settings' ); //This function adds the submenu page which contains the settings for the test and for the plugin in general. function elv_add_settings_page() { add_submenu_page( 'elavon-post-api-test', // Slug of parent, aka the function just above this one 'Settings API Form Fields', // Name displayed on title tags of page when menu is selected 'Elavon Converge Settings', // Name displayed as title of submenu page on admin menu 'manage_options', // Permissions of user who may use this, in this case, administrators only 'elv_settings_page', // Slug of the submenu page 'elv_render_settings_page' // Callback function that renders the submenu page ); } // Important note; the SECOND field of register_setting(), option name, is what the other functions use, NOT the group. function elv_register_settings() { // This should be the option name used in the second field of "register_setting()". $option_name = 'elv_settings_fields'; // Fetch existing option values $option_current_values = get_option( $option_name ); $default_values = array( 'elv_setting_merchant_id' => '0123456', 'elv_setting_api_user_id' => 'apiusername', 'elv_setting_api_key' => 'K38qxPvFQhZneeIuygOaqwFuP0vg3DHKN93qfwynyQGMMAtXvb03Ms0ytLeQ1hKL' ); // Parse option current values into predefined keys, throw the rest away $data = shortcode_atts( $default_values, $option_current_values ); register_setting( 'elv_settings_fields', // $option_group. Defines settings group name. Used for settings_fields() 'elv_settings_fields', // $option_name. Name of option to sanitize and save to database. Used by get_option() 'elv_validate_settings_fields' // Validation callback function. ); add_settings_section( 'api_settings', // $id, slug name to identify section. Used in 'id' attribute of tags. 'API Settings', // $title, Formatted title of the section. Shown as the heading for the section. 'elv_render_forms_description', // $callback, echoes out any content at top of section between heading and fields. 'elv_settings_page' // $page, Page slug on which you want to show the section (used by settings fields) ); add_settings_field( 'elv_setting_merchant_id', // $id, slug name to identify field. Used in 'id' attribute of tags 'Merchant ID', // $title, shown as label for field during output 'elv_render_settings_field1', // Callback function that fills the form with the desired inputs 'elv_settings_page', // Slug name of settings page on which to show the section (eg; general, reading, writing) 'api_settings', // SLUG NAME of settings section in which field resides array( // Array contains actual values used by the field. 'label_for' => 'label1', // HTML <label> for Attribute 'name' => 'elv_setting_merchant_id', // HTML "name" used for submitting form, and submitting to database 'value' => esc_textarea( $data['elv_setting_merchant_id'] ), // Actual value of row, hence $data 'option_name' => $option_name // Option name stored as variable ) ); add_settings_field( 'elv_setting_api_user_id', 'API User ID', 'elv_render_settings_field2', 'elv_settings_page', 'api_settings', array( 'label_for' => 'label2', 'name' => 'elv_setting_api_user_id', 'value' => esc_textarea( $data['elv_setting_api_user_id'] ), 'option_name' => $option_name ) ); add_settings_field( 'elv_setting_api_key', 'API Key', 'elv_render_settings_field3', 'elv_settings_page', 'api_settings', array( 'label_for' => 'label3', 'name' => 'elv_setting_api_key', 'value' => esc_textarea( $data['elv_setting_api_key'] ), 'option_name' => $option_name ) ); } function elv_render_settings_page() { ?> <h2> Elavon Converge WooCommerce Payment Gateway Settings </h2> <form action="options.php" method="post"> <?php settings_fields( 'elv_settings_fields' ); // Outputs nonce, action, and options page fields for a settings page. String inside is name of settings group. do_settings_sections( 'elv_settings_page' ); // Prints out all settings sections. String inside is the slug name of the page whose settings you want to output. ?> <input name="submit" class="button button-primary" type="submit" value="<?php esc_attr_e( 'Save' ); ?>" /> </form> <?php } //---------------------------------------------------------------------------------------------------------------- // Validating data entered when saving the options to the database. //---------------------------------------------------------------------------------------------------------------- function elv_validate_settings_fields( $input ) { // Strips any non a-z, A-Z, or 0-9 characters out of submitted data via sanitization. $output['elv_setting_merchant_id'] = sanitize_text_field( $input['elv_setting_merchant_id'] ); $output['elv_setting_api_user_id'] = sanitize_text_field( $input['elv_setting_api_user_id'] ); $output['elv_setting_api_key'] = sanitize_text_field( $input['elv_setting_api_key'] ); return $output; } //------------------------------------------------------------------------------------------------------------------------------------------------ // Callback functions that display the description of what the form fields do at the top of the admin settings page. For the Noobs! :) // // HERE'S SOME EXPLANATIONS AS TO VARIOUS BITS OF WORDPRESS AND PHP SPECIFIC CODE FOR LATER READABILITY AND REFERENCE: // 1.) Function "get_option()" uses the name of the option group to retrieve the settings fields from the register settings function. // 2.) "$options" is predefined using get_option, which retrieves the option value based on an option name // 3.) The "name" attribute for the input field of the settings needs to match the $option_name that was set in the register_setting function (I think?) //------------------------------------------------------------------------------------------------------------------------------------------------ function elv_render_forms_description() { //------------------------------------------------------------------------------------ // Attempt at checking database for existing variables by echoing them to the display foreach( get_option('elv_settings_fields') as $value) { echo "$value <br>"; } //------------------------------------------------------------------------------------ echo '<p>Here is where you define the settings to make the gateway function. You MUST input your Merchant ID, API Terminal User, and your API Key, so that Elavon can speak with your website.</p>'; } function elv_render_settings_field1( $args ) { printf( '<textarea name="%1$s[$2$s]" id="%3$s" rows="1" cols="30" class="code">%4$s</textarea>', $args['option_name'], $args['name'], $args['label_for'], $args['value'] ); } function elv_render_settings_field2( $args ) { printf( '<textarea name="%1$s[$2$s]" id="%3$s" rows="1" cols="30" class="code">%4$s</textarea>', $args['option_name'], $args['name'], $args['label_for'], $args['value'] ); } function elv_render_settings_field3( $args) { printf( '<textarea name="%1$s[$2$s]" id="%3$s" rows="1" cols="64" class="code">%4$s</textarea>', $args['option_name'], $args['name'], $args['label_for'], $args['value'] ); }