Can’t get plugin settings page to save data

While you are using Settins API, that’s why you don’t need to use update_option or add_option functions. Settings API would handle that by self.

There were few issues that’s why your code is not working.

1.

add_settings_section(
    'wpa_ad_insert_main',
    'Ad Insertion Settings',
    'wpa_ad_insert_section_text',
    'wpa_ad_insert'
);

3rd parameter is the callback function. Since, you don’t need this function therefore just add __return false as the callback. Then your code for this function would be like:

add_settings_section(
    'wpa_ad_insert_main',
    'Ad Insertion Settings',
    '__return_false',
    'wpa_ad_insert'
);

2.

register_setting(
    'wpa_ad_insert_options',
    'wpa_ad_insert_options',
    'wpa_ad_insert_validate_options'
);

Look at the above code. Since second parameter is the option name, that’s why you have to use this option name when you want to retrieve the option from database. Instead of calling that option name, you called two option names listed below:

$options = get_option('wpa_ad_insert_paragraph');
$options = get_option('wpa_ad_insert_adcode');

Since you used another option name in the register_setting function, that’s why you were failed to retrieve the option into the database. You should have call get_option function with the option name that you registered with the register_setting function. And that would be like:

$options = get_option('wpa_ad_insert_options');

3.
But still the data is not being saved into the database, right? Because, you used plugin_options as the name of your form input and textarea. Since you are using wordpress Settings API, that’s why you should have use the same name that you registered as option_name in the register_setting function.

So, you need to fixed few things to make this code usable. I modified few lines of your code and that works. Replace your register_setting function with this one:

register_setting(
    'wpa_ad_insert_options',
    'plugin_options',
    'wpa_ad_insert_validate_options'
);

Replace your add_settings_section function with this one:

add_settings_section(
    'wpa_ad_insert_main',
    'Ad Insertion Settings',
    '__return_false',
    'wpa_ad_insert'
);

Replace all get_option function with this one:
$options = wpa_options(‘plugin_options’);

And finally add this new code:

function wpa_options() {
    $default = array(
        'wpa_ad_insert_paragraph' => 1,
        'wpa_ad_insert_adcode' => ''
        );
    return get_option('plugin_options', $default);
}

Put it all together:

// Add a menu for our option page
add_action('admin_menu', 'wpa_ad_insert_add_page');
function wpa_ad_insert_add_page() {
    add_options_page( 'Ad Insertion', 'Ad Insertion', 'manage_options', 'wpa_ad_insert', 'wpa_ad_insert_option_page' );
}

// Draw the option page
function wpa_ad_insert_option_page() {
    ?>
    <div class="wrap">
        <?php screen_icon(); ?>
        <h2>Ad Insertion</h2>
        <form action="options.php" method="post">
            <?php settings_fields('wpa_ad_insert_options'); ?>
            <?php do_settings_sections('wpa_ad_insert'); ?>
            <input name="Submit" type="submit" value="Save Changes" />
        </form>
    </div>
    <?php
}

// Register and define the settings
add_action('admin_init', 'wpa_ad_insert_admin_init');
function wpa_ad_insert_admin_init(){
    register_setting(
        'wpa_ad_insert_options',
        'plugin_options',
        'wpa_ad_insert_validate_options'
    );
    add_settings_section(
        'wpa_ad_insert_main',
        'Ad Insertion Settings',
        // 'wpa_ad_insert_section_text',
        '__return_false',
        'wpa_ad_insert'
    );
    add_settings_field(
        'wpa_ad_insert_paragraph',
        'Ad will appear after paragraph number:',
        'wpa_ad_insert_paragraph_setting',
        'wpa_ad_insert',
        'wpa_ad_insert_main'
    );
    add_settings_field(
        'wpa_ad_insert_adcode',
        'Ad code:',
        'wpa_ad_insert_adcode_setting',
        'wpa_ad_insert',
        'wpa_ad_insert_main'
    );
}

register_setting(
    'wpa_ad_insert_options',
    'plugin_options',
    'wpa_ad_insert_validate_options'
);

function wpa_ad_insert_paragraph_setting() {
    $options = wpa_options('plugin_options');
    $items = array("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20");
    echo "<select id='wpa_ad_insert_paragraph' name="plugin_options[wpa_ad_insert_paragraph]">";
    foreach($items as $item) {
        $selected = ($options['wpa_ad_insert_paragraph']==$item) ? 'selected="selected"' : '';
        echo "<option value="$item" $selected>$item</option>";
    }
    echo "</select>";
}

function wpa_ad_insert_adcode_setting() {
    $options = wpa_options('plugin_options');
    echo "<textarea id='wpa_ad_insert_adcode' name="plugin_options[wpa_ad_insert_adcode]" rows="7" cols="50" type="textarea">{$options['wpa_ad_insert_adcode']}</textarea>";
}


function wpa_insert_ad($content) {
    $paragraphAfter = get_option('wpa_ad_insert_paragraph');
    $ad = get_option('wpa_ad_insert_adcode');
    if( is_single() && is_main_query() ) {
        $content = explode("</p>", $content);
        for ($i = 0; $i <count($content); $i++ ) {
            if ($i == $paragraphAfter)   
            echo $content[$i] . "</p>";
        }
    }   
    return $content;
}
add_filter('the_content', 'wpa_insert_ad');

function wpa_options() {
    $default = array(
        'wpa_ad_insert_paragraph' => 1,
        'wpa_ad_insert_adcode' => ''
        );
    return get_option('plugin_options', $default);
}