I'm creating a WordPress plugin using Settings API. Everything else is working fine except the callback for register_setting() function. Here is the line:

    register_setting( self::ADMIN_PAGE, self::ADMIN_PAGE,
array( $this, 'validate_options' ) );

    public function validate_options($input) {
            error_log(print_r($input, true));
            $data = array('tp-text-field' => 'Default text');
            foreach($data as $k => $v){
                $data[$k] = sanitize_text_field(isset($input[$k]) ? trim($input[$k]) : $v);
            }
            return $data;
        }

The form is displayed on the plugin options page as expected. Default values are saving in the database as a serialized array. Yet, once I fill any field and submit the form, I'm not getting the submitted value in the $input parameter. The debug.log file contains no values for the error_log() function.

As I'm trying to implement the plugin in multiple files and classes, here is my full code.

The main plugin file that contains information for the plugin, test-plugin.php

/**
 *
 * Plugin Name:       Test plugin
 * Description:       This is a test plugin.
 * Version:           1.0.0
 * License:           GPL-2.0+
 * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
 * Text Domain:       test-plugin
 * Domain Path:       /languages
 */

 defined( 'TEST_PLUGIN_FILE' ) || define( 'TEST_PLUGIN_FILE', __FILE__ );

    if ( ! class_exists( 'Test_Main' ) ) {
        include_once dirname( TEST_PLUGIN_FILE ) . '/class-test-main.php';
    }

    function test_main() {
        return Test_Main::instance();
    }

    test_main();

class-test-main.php

defined( 'TEST_PLUGIN_NAME' ) || define( 'TEST_PLUGIN_NAME', 'Test Plugin' );
defined( 'TEST_PLUGIN_DIR' ) || define( 'TEST_PLUGIN_DIR', plugin_dir_path( TEST_PLUGIN_FILE ) );
defined( 'TEST_PLUGIN_BASENAME' ) || define( 'TEST_PLUGIN_BASENAME', plugin_basename( TEST_PLUGIN_FILE ) );

class Test_Main{

    protected $admin;
    private static $instance = null;

    public static function instance() {
        if ( is_null( self::$instance ) ) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    private function __construct() {
        add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
        $this->do_test();
    }

    public function load_textdomain() {
        $domain = dirname( TEST_PLUGIN_BASENAME );
        load_plugin_textdomain($domain, false, $domain.'/languages');
    }

    private function do_test() {
        if ( is_admin() ) {
            include_once TEST_PLUGIN_DIR . 'admin/class-test-admin.php';

            $this->admin = new Test_Admin();
            $this->admin->run();
        } else {
            //Public part
        }       
    }
}

admin/class-test-admin.php

class Test_Admin{

    const ADMIN_DIR = TEST_PLUGIN_DIR . 'admin/';

    // Menu slug.
    const ADMIN_PAGE = 'test_plugin';

    public function run() {
        add_action( 'admin_init', array( $this, 'setup_sections_fields' ) );
        add_action( 'admin_menu', array( $this, 'setup_settings_page' ) );
    }

    public function setup_settings_page() {
        add_submenu_page('options-general.php', TEST_PLUGIN_NAME, TEST_PLUGIN_NAME, 'manage_options', self::ADMIN_PAGE, array( $this, 'setup_settings_form' )
        );
    }

    public function setup_settings_form() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'You do not have sufficient permissions to access this page.' );
        }

        include_once self::ADMIN_DIR . 'parts/options-form.php';
    }

    public function setup_sections_fields() {
        register_setting( self::ADMIN_PAGE, self::ADMIN_PAGE, array( $this, 'validate_options' ) );
        add_settings_section( 'general', esc_html__('General', 'test-plugin'), array( $this, 'section_callback' ), self::ADMIN_PAGE );
        add_settings_field( 'tp-text-field', esc_html__('Text field', 'test-plugin'), array( $this, 'setup_text_fields' ), self::ADMIN_PAGE, 'general', array('id' => 'tp-text-field', 'placeholder' => 'Input text', 'default' => 'Default text') );
    }

    public function validate_options($input) {
        error_log(print_r($input, true));
        $data = array('tp-text-field' => 'Default text');
        foreach($data as $k => $v){
            $data[$k] = sanitize_text_field(isset($input[$k]) ? trim($input[$k]) : $v);
        }
        return $data;
    }

    public function setup_text_fields($atts) {
        $opts = get_option( self::ADMIN_PAGE );
        printf('<input id="%1$s" name="%2$s" type="%3$s" placeholder="%4$s" value="%5$s" />',
            esc_attr( $atts['id'] ),
            esc_attr( $atts['id'] ),
            esc_attr( 'text' ),
            esc_attr( $atts['placeholder'] ),
            esc_attr( isset($opts[ $atts['id'] ]) ? $opts[ $atts['id'] ] :  $atts['default'] )
        );
    }

    public function section_callback($atts) {

    }
}

admin/parts/options-form.php

<div class="wrap">
    <h2><?php echo esc_html( get_admin_page_title() ); ?></h2>
    <form method="post" action="options.php">
    <?php
        settings_fields( Test_Admin::ADMIN_PAGE );
        do_settings_sections( Test_Admin::ADMIN_PAGE );
        submit_button();
    ?>
    </form>
</div>

There are definitely more sections and fields. However, I'm just skipping them to keep the code simpler. I have no issue in displaying the form or load it with default values.

But once the form is submitted, the $input variable in the validate_options() callback still remains empty. However, The submitted data is present in the POST request parameters as I did get it in the debug.log.

Can anybody inform me what am I doing wrong?

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Browse other questions tagged or ask your own question.