Creating a Custom WordPress Settings Page: A Beginner’s Guide

For developers looking to extend the functionality of WordPress, creating a custom settings page can be a crucial skill. This allows you to offer your users a dedicated area where they can configure options for your theme or plugin. In this guide, we’ll walk through how to create a settings page that includes a select field, text field, and checkbox, explaining how to display these on the page and save the input to the database.

Step 1: Create a new PHP file in your WordPress theme or plugin directory and name it something like “word-count-settings.php“.

Step 2: Define the WordCountAndTimePlugin class. The class name can be anything. For now, we’re defining it WordCountAndTimePlugin.

  • The code defines a class called ‘WordCountAndTimePlugin’ using the ‘class’ keyword.
class WordCountAndTimePlugin
{
    // ... Constructor and methods will go here ...
}

Step 3: Initialize the class

  • Inside the class, a constructor function is defined using the ‘__construct‘ method.
  • The constructor function adds two actions: ‘admin_menu‘ and ‘admin_init‘.
  • The ‘admin_menu‘ action is used to add a new options page to the WordPress admin menu.
  • The ‘admin_init‘ action is used to initialize the plugin settings.
class WordCountAndTimePlugin
{
    function __construct()
    {
        add_action('admin_menu', array($this, 'adminPage'));
        add_action('admin_init', array($this, 'settings'));
    }


}

Step 4: Define the settings function

  • The ‘settings‘ function is defined to handle the plugin settings.
  • Inside this function, several settings fields are added using the ‘add_settings_field‘ function.
  • Each setting field has a unique name, label, and HTML callback function.
  • The ‘register_setting‘ function is used to register each setting field, specifying the sanitize callback function and default value.
class WordCountAndTimePlugin
{
    function __construct()
    {
        add_action('admin_menu', array($this, 'adminPage'));
        add_action('admin_init', array($this, 'settings'));
    }

    function settings()
    {
        add_settings_section('wcp_first_section', null, null, 'word-count-settings-page');

        // Select
        add_settings_field('wcp_location', 'Display Location', array($this, 'locationHtml'), 'word-count-settings-page', 'wcp_first_section');
        register_setting('wordcountplugin', 'wcp_location', array('sanitize_callback' => array($this, 'sanitizeLocation'), 'default' => '0'));
        // Text Field
        add_settings_field('wcp_headline', 'Headline Text', array($this, 'headlineHtml'), 'word-count-settings-page', 'wcp_first_section');
        register_setting('wordcountplugin', 'wcp_headline', array('sanitize_callback' => 'sanitize_text_field', 'default' => 'Post Statistics'));
        // Checkbox
        add_settings_field('wcp_wordcount', 'Word Count', array($this, 'checkboxHtml'), 'word-count-settings-page', 'wcp_first_section', array('theName' => 'wcp_wordcount'));
        register_setting('wordcountplugin', 'wcp_wordcount', array('sanitize_callback' => 'sanitize_text_field', 'default' => '1'));

        add_settings_field('wcp_charactercount', 'Character Count', array($this, 'checkboxHtml'), 'word-count-settings-page', 'wcp_first_section', array('theName' => 'wcp_charactercount'));
        register_setting('wordcountplugin', 'wcp_charactercount', array('sanitize_callback' => 'sanitize_text_field', 'default' => '1'));

        add_settings_field('wcp_readtime', 'Read Time', array($this, 'checkboxHtml'), 'word-count-settings-page', 'wcp_first_section', array('theName' => 'wcp_readtime'));
        register_setting('wordcountplugin', 'wcp_readtime', array('sanitize_callback' => 'sanitize_text_field', 'default' => '1'));
    }

}

In this code, 'theName' => 'wcp_wordcount' is an argument passed to the callback function (checkboxHtml). Inside the checkboxHtml function, we can access this argument as $args['theName']. This is useful when we want to reuse the same callback function for different settings fields but need to differentiate between them. In this case, 'theName' is used to specify the name of the checkbox input field in the HTML.

Step 5: Define the sanitizeLocation function

When we need to deal with custom validation logic for a particular field, we can create a custom sanitization function like this.

  • The ‘sanitizeLocation‘ function is defined to sanitize the select input for the ‘wcp_location‘ setting.
  • It checks if the input value is either 0 or 1.
  • If the input value is invalid, an error message is added and the function returns the current value of ‘wcp_location‘.
// Sanitize the select input i.e. location value validation
    function sanitizeLocation($input)
    {
        if ($input != 0 && $input != 1) {
            add_settings_error('wcp_location', 'wcp_location_error', 'Display location must be beginning or end.');
            return get_option('wcp_location');
        }
        return $input;
    }

Step 6: Define the HTML callback functions

  • Three HTML callback functions are defined: ‘locationHtml‘, ‘headlineHtml‘, and ‘checkboxHtml‘.
  • These functions generate the HTML markup for the select input, text input, and checkbox input fields, respectively.
// Handle the select input HTML
    function locationHtml()
    { ?>
        <select name="wcp_location">
            <option value="0" <?php selected(esc_attr(get_option('wcp_location')), 0); ?>>Beginning of Post</option>
            <option value="1" <?php selected(esc_attr(get_option('wcp_location')), 1); ?>>End of Post</option>
        </select>
    <?php }
    // Handle the text input HTML
    function headlineHtml()
    { ?>
        <input type="text" name="wcp_headline" value="<?php echo esc_attr(get_option('wcp_headline')); ?>">
    <?php }

    // Handle the checkbox input HTML
    function checkboxHtml($args)
    { ?>
        <input type="checkbox" name="<?php echo $args['theName']; ?>" value="1" <?php checked(esc_attr(get_option($args['theName'])), 1); ?>>
    <?php }

Step 7: Define the adminPage function

  • The ‘adminPage‘ function is defined to generate the HTML markup for the options page.
  • It uses the ‘add_options_page‘ function to add a new options page to the WordPress admin menu.
  • The function specifies the page title, menu title, capability required to access the page, and the HTML callback function.
function adminPage()
    {
        add_options_page('Word Count Settings', 'Word Count', 'manage_options', 'word-count-settings-page', array($this, 'ourHtml'));
    }

Step 8: Define the ourHTML function

  • The ‘ourHTML‘ function is defined to generate the HTML markup for the options page content.
  • It includes a form with the ‘action‘ attribute set to ‘options.php‘ and the ‘method‘ attribute set to ‘POST‘.
  • Inside the form, the ‘settings_fields‘ function is used to output the hidden fields required for the settings.
  • The ‘do_settings_sections‘ function is used to output the sections and fields defined in the ‘settings’ function.
  • Finally, the ‘submit_button‘ function is used to output the submit button.
 function ourHTML()
    { ?>
        <div class="wrap">
            <h1>Word Count Settings</h1>
            <form action="options.php" method="POST">
                <?php
                settings_fields('wordcountplugin');
                do_settings_sections('word-count-settings-page');
                submit_button();
                ?>
            </form>
        </div>
    <?php }

Step 9: Create an instance of the WordCountAndTimePlugin class

  • Outside the class definition, an instance of the ‘WordCountAndTimePlugin’ class is created.
  • This will initialize the plugin and execute the constructor function.
$wordCountAndTimePlugin = new WordCountAndTimePlugin();

Now that we’ve explored how to create a settings page within WordPress, here is the complete code snippet you would use for a plugin that adds a settings page with select, text, and checkbox fields. This code is designed to get you started on building your own customized settings for your WordPress plugins.

<?php
/*
Plugin Name: Our First Unique Plugin
Plugin URI: https://www.rajandangi.com.np
Description: This is our first unique plugin
Author: Rajan Dangi
Version: 1.0
Author URI: https://www.rajandangi.com.np
Text Domain: wcdomain
Domain Path: /languages
*/
class WordCountAndTimePlugin
{
    function __construct()
    {
        add_action('admin_menu', array($this, 'adminPage'));
        add_action('admin_init', array($this, 'settings'));
        add_action('init', array($this, 'languages'));
    }

    function languages()
    {
        load_plugin_textdomain('wcdomain', false, dirname(plugin_basename(__FILE__)) . '/languages');
    }

    function settings()
    {
        add_settings_section('wcp_first_section', null, null, 'word-count-settings-page');

        // Select
        add_settings_field('wcp_location', esc_html__('Display Location', 'wcdomain'), array($this, 'locationHtml'), 'word-count-settings-page', 'wcp_first_section');
        register_setting('wordcountplugin', 'wcp_location', array('sanitize_callback' => array($this, 'sanitizeLocation'), 'default' => '0'));

        // Text Field
        add_settings_field('wcp_headline', 'Headline Text', array($this, 'headlineHtml'), 'word-count-settings-page', 'wcp_first_section');
        register_setting('wordcountplugin', 'wcp_headline', array('sanitize_callback' => 'sanitize_text_field', 'default' => 'Post Statistics'));

        // Checkbox
        add_settings_field('wcp_wordcount', 'Word Count', array($this, 'checkboxHtml'), 'word-count-settings-page', 'wcp_first_section', array('theName' => 'wcp_wordcount'));
        register_setting('wordcountplugin', 'wcp_wordcount', array('sanitize_callback' => 'sanitize_text_field', 'default' => '1'));

        add_settings_field('wcp_charactercount', 'Character Count', array($this, 'checkboxHtml'), 'word-count-settings-page', 'wcp_first_section', array('theName' => 'wcp_charactercount'));
        register_setting('wordcountplugin', 'wcp_charactercount', array('sanitize_callback' => 'sanitize_text_field', 'default' => '1'));

        add_settings_field('wcp_readtime', 'Read Time', array($this, 'checkboxHtml'), 'word-count-settings-page', 'wcp_first_section', array('theName' => 'wcp_readtime'));
        register_setting('wordcountplugin', 'wcp_readtime', array('sanitize_callback' => 'sanitize_text_field', 'default' => '1'));
    }

    // Sanitize the select input i.e. location value validation
    function sanitizeLocation($input)
    {
        if ($input != 0 && $input != 1) {
            add_settings_error('wcp_location', 'wcp_location_error', 'Display location must be beginning or end.');
            return get_option('wcp_location');
        }
        return $input;
    }

    // Handle the select input HTML
    function locationHtml()
    { ?>
        <select name="wcp_location">
            <option value="0" <?php selected(esc_attr(get_option('wcp_location')), 0); ?>>Beginning of Post</option>
            <option value="1" <?php selected(esc_attr(get_option('wcp_location')), 1); ?>>End of Post</option>
        </select>
    <?php }
    // Handle the text input HTML
    function headlineHtml()
    { ?>
        <input type="text" name="wcp_headline" value="<?php echo esc_attr(get_option('wcp_headline')); ?>">
    <?php }
    // Handle the checkbox input HTML
    function checkboxHtml($args)
    { ?>
        <input type="checkbox" name="<?php echo $args['theName']; ?>" value="1" <?php checked(esc_attr(get_option($args['theName'])), 1); ?>>
    <?php }

    function adminPage()
    {
        add_options_page('Word Count Settings', __('Word Count', 'wcdomain'), 'manage_options', 'word-count-settings-page', array($this, 'ourHtml'));
    }

    function ourHTML()
    { ?>
        <div class="wrap">
            <h1>Word Count Settings</h1>
            <form action="options.php" method="POST">
                <?php
                settings_fields('wordcountplugin');
                do_settings_sections('word-count-settings-page');
                submit_button();
                ?>
            </form>
        </div>
    <?php }

}
$wordCountAndTimePlugin = new WordCountAndTimePlugin();



// Implement Word Count and Time Plugin on the front end of the website using the_content filter
require_once plugin_dir_path(__FILE__) . 'inc/word-count.php';