Closeup picture of a mix table

If you’re creating a WordPress plugin, you might be wondering how to create a settings page for it. Does WordPress offer some kind of “standard” mechanism for this? Are there any new tools or frameworks with which to create modern settings pages? Is it a good idea to create a settings page? Well, today we’re going to talk about all of this and I am going to answer your questions.

Decisions, not Options

WordPress is a platform that aims to democratize the web. This statement, which sounds very nice but at the same time is very abstract, is a way of saying “we want anyone to be able to use WordPress.” And, believe it or not, settings pages can be, and in fact in many cases are, a barrier for that. Don’t believe me? Well, WordPress itself says it:

When making decisions these are the users we consider first. A great example of this consideration is software options. Every time you give a user an option, you are asking them to make a decision. When a user doesn’t care or understand the option this ultimately leads to frustration. As developers we sometimes feel that providing options for everything is a good thing, you can never have too many choices, right? Ultimately these choices end up being technical ones, choices that the average end user has no interest in. It’s our duty as developers to make smart design decisions and avoid putting the weight of technical choices on our end users.

WordPress philosophy

So before creating a settings page, think carefully about the options you want to give your users, why you want them to have access to those options, and whether it’s necessary or useful to do so.

Filters as an Alternative

Even if I know I’m not supposed to offer too many options to my users, I have to confess that, as a developer, it’s not always easy for me to make a decision instead of offering an option. There are times when I want my users to have the ability to choose, although I’m aware that the options I’m exposing are complex. So what do I do in these cases? Do I follow WordPress’recommendation and limit my advanced users?

Fortunately, WordPress offers a perfect solution to this dilemma: filters. When you design a plugin and want your (advanced) users to be able to tune its behavior, don’t create a settings page or anything like that. Instead, make your plugin customizable through WordPress’ filtering mechanism.

If you use filters, most of your users will enjoy a default behavior (“decisions,” remember?), because they’ll be using the plugin with the default values set in your filters, while advanced users will have the ability to modify these decisions through hooks (and so you also have “options”). The best of both worlds!

WordPress Settings

Ok, now that we’re aware of the importance of making decisions for our users and have seen how to bypass this limitation (if necessary) through filters, it’s time to see how we can create a settings page in WordPress. Cuz, yup: there are times when we really need to give our users the option to make decisions according to their preferences.

Settings API in WordPress

The Settings API was added in WordPress version 2.7. This is a set of functions that standardize the creation of settings pages, allowing you to define which options are available, what the user interface will be for editing each of those options (essentially, fields on a form), and how to validate, save, and retrieve their values.

I think the best way to learn is through examples, so let’s create our first settings page using the settings API step by step.

Creating a new Settings Page

The first thing you need to do to create a settings page is (surprise, surprise!) to create a page to display the settings. To do this, simply use the add_options_page function during the admin_menu action and register the page:

function nelio_add_settings_page() {
  add_options_page(
    'Nelio Plugin Settings',
    'Nelio',
    'manage_options',
    'nelio-example-plugin',
    'nelio_render_settings_page'
  );
}
add_action( 'admin_menu', 'nelio_add_settings_page' );

As you can see, the only thing we do with this function is register a new page that will appear under the WordPress Settings menu, with its title, the name in the menu, the permissions that the user must have to be able to access it, and os on. The last argument, nelio_render_settings_page, is the name of the function that will be in charge of rendering said page:

<?php
function nelio_render_settings_page() {
?>
  <h2>Nelio Plugin Settings</h2>
  <form action="options.php" method="post">
    <?php 
    settings_fields( 'nelio_example_plugin_settings' );
    do_settings_sections( 'nelio_example_plugin' );
    ?>
    <input
      type="submit"
      name="submit"
      class="button button-primary"
      value="<?php esc_attr_e( 'Save' ); ?>"
    />
  </form>
<?php
}

The settings page itself is relatively easy to create. We simply need to add a form whose content will be semi-automatically generated by WordPress. On the one hand, we invoke the settings_fields function, which basically adds a nonce in the form to make it “safe.” Next, we ask WordPress to render all the settings we’ve created for our plugin using the do_settings_sections function. And, finally, we simply add the button to Submit the form.

Actual Settings in our Settings Page

Next, we must register each of the options that will be part of our settings page. To do this, we’ll use two functions: register_setting, which allows us to indicate the name with which we will save the settings in the database, and add_settings_field, which adds each individual option:

function nelio_register_settings() {
  register_setting(
    'nelio_example_plugin_settings',
    'nelio_example_plugin_settings',
    'nelio_validate_example_plugin_settings'
  );
  add_settings_section(
    'section_one',
    'Section One',
    'nelio_section_one_text',
    'nelio_example_plugin'
  );
  add_settings_field(
    'some_text_field',
    'Some Text Field',
    'nelio_render_some_text_field',
    'nelio_example_plugin',
    'section_one'
  );
  add_settings_field(
    'another_number_field',
    'Another Number Field',
    'nelio_render_another_number_field',
    'nelio_example_plugin',
    'section_one'
  );
}
add_action( 'admin_init', 'nelio_register_settings' );

The previous code snippet has a couple of things that deserve special attention. On the one hand, note that the register_setting function has as its third argument: nelio_validate_example_plugin_settings. This is the name of the callback function that will be called to validate the values that the user has selected (remember that you always have to validate and sanitize your form fields). This function is something like this:

function nelio_validate_example_plugin_settings( $input ) {
    $output['some_text_field']      = sanitize_text_field( $input['some_text_field'] );
    $output['another_number_field'] = absint( $input['another_number_field'] );
    // ...
    return $output;
}

where we retrieve each submitted field from $input and we sanitize it into $output so that we know for sure that, whatever it is we end up saving in the database, is valid and correct.

The second thing I wanted to focus you on is the fact that each of the fields we define also includes a function reference that tells WordPress how each field should be rendered. For example, the callbacks of the fields in our example might be something like this:

function nelio_section_one_text() {
  echo '<p>This is the first (and only) section in my settings.</p>';
}
function nelio_render_some_text_field() {
  $options = get_option( 'nelio_example_plugin_settings' );
  printf(
    '<input type="text" name="%s" value="%s" />',
    esc_attr( 'nelio_example_plugin_settings[some_text_field]' ),
    esc_attr( $options['some_text_field'] )
  );
}
function nelio_render_another_number_field() {
  $options = get_option( 'nelio_example_plugin_settings' );
  printf(
    '<input type="number" name="%s" value="%s" />',
    esc_attr( 'nelio_example_plugin_settings[another_number_field]' ),
    esc_attr( $options['another_number_field'] )
  );
}

In essence, all these callbacks do is retrieve the current value of the field they’re supposed to render (with get_option) and render the HTML that will allow the user to set one value or the other (in this example, an input field of type text or number).

What’s the final result, you asking? This:

Example of a simple settings page.
Example of a simple settings page.

Final Thoughts

As you can see, creating a settings page is relatively simple. I’m personally not very fond of the whole process, as it’s quite repetitive and we have to write over and over again the same boilerplate code… but it’s easy nonetheless.

WP Settings API
WP Settings API code generator allows you to easily create the skeleton of your settings page.

To further simplify this process, though, there are some online code generators with which, through a simple user interface, you can define the different fields you want on your settings page. A couple of examples are:

And, of course, there is always the possibility of creating a settings page using technologies like React… but this is a story for a different time, don’t you think?

Featured image by Rima Kruciene on Unsplash.

8 responses to “How to Create a Settings Page in WordPress”

  1. Aliji Emmanuel Avatar
    Aliji Emmanuel

    Thank you for this amazing tutorial. I really learnt a lot in a short period of time.

    1. David Aguilera Avatar

      You’re welcome! And thank you for reading us 🙂

  2. Kelvin Mwinuka Avatar
    Kelvin Mwinuka

    Awesome article David, this came in handy.

    1. David Aguilera Avatar

      Thanks, Kelvin! Glad you liked it 🙂

  3. Led Avatar
    Led

    I’m completely new to WP and there’s no mention of where we are meant to up the code?

    1. David Aguilera Avatar

      Hi! You’re right – I assumed that bit was obvious, sorry. You only need to create a settings page if you plan to create a plugin or theme. Here’s a post on how to create a (basic) plugin to keep track of all the customizations you applied to your site – that’s probably a good candidate to include a settings page, if you need one.

  4. Randy Abidin Avatar
    Randy Abidin

    David,
    Excellent tutorial. Meets my application requirements almost perfectly!

    I would like to increase the rows of a textarea based on the number of lines entered by an admin.
    In the code below I would like to change the number of rows (from the fixed value of ’10’ )to the value in the variable $url_array_count.

    Any insight is greatly appreciated!!!
    Randy

    function url_textarea_field() {
    $options = get_option( ‘aa_site_status_settings’ );

    $my_urls_array = explode(“\r\n”, $options[‘url_text’]);
    $url_array_count = count( $my_urls_array );

    printf(
    “%s”,
    esc_attr( ‘aa_site_status_settings[url_text]’ ),
    esc_attr( $options[‘url_text’] )
    );
    }

    1. David Aguilera Avatar

      Hi, Randy. Thanks! I’m glad to know you liked it 🙂

      Regarding your question, I must say your solution looks quite good (as far as I can tell). There are a couple of things that are bugging me. On the one hand, you used “\r\n” to split lines. That’s how new lines work in Windows, but Linux and Mac only use “\n”. If you just use the “\n” character, the split will work on all systems.

      The other thing is the actual printf: it’s missing the textarea component, but that’s probably because you didn’t escape it when you posted the comment and WordPress stripped it away. Anyway, if you want to add the number of lines there, you simply need a third placeholder in your printf:

      print( '<textarea name="%s" rows="%d">%s</textarea>', esc_attr($name), $count, esc_html($value) )

      Just make sure you use the appropriate escaping function!

Leave a Reply

Your email address will not be published. Required fields are marked *

I have read and agree to the Nelio Software Privacy Policy

Your personal data will be located on SiteGround and will be treated by Nelio Software with the sole purpose of publishing this comment here. The legitimation is carried out through your express consent. Contact us to access, rectify, limit, or delete your data.