Create WordPress Plugin Settings Page

Before we get down to business, it’s important to understand the difference between WordPress options and WordPress postmeta. Check out our post on this topic:

A very important note, we’re using the WordPress Plugin Boilerplate ( when we build out WordPress plugins. It makes the whole process super easy and well structured.

Step 1: Add Admin Menu Action to your construct method in the class-plugin-name-admin.php file

add_action('admin_menu', array( $this, 'addPluginAdminMenu' ), 9);    

STEP 2: Add the addPluginAdminMenu Method to your class-plugin-name-admin.php file

Copy and paste the following function into your class-plugin-name-admin.php file.

public function addPluginAdminMenu() {
//add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position );
//add_menu_page(  $this->plugin_name, 'Plugin Name', 'administrator', $this->plugin_name, array( $this, 'displayPluginAdminDashboard' ), plugin_dir_url( FILE ) . 'img/logo2.png', 26 );

//add_submenu_page( '$parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function );
add_submenu_page( $this->plugin_name, 'Plugin Name Settings', 'Settings', 'administrator', $this->plugin_name.'-settings', array( $this, 'displayPluginAdminSettings' ));

You’ll notice that in the addPluginAdminMenu method there’s a reference to the displayPluginAdminSettings function. So, we need to add that to the admin php file as well.

STEP 3: Add the displayPluginAdminSettings Method to your class-plugin-name-admin.php file

public function displayPluginAdminSettings() {
         // set this var to be used in the settings-display view
         $active_tab = isset( $_GET[ 'tab' ] ) ? $_GET[ 'tab' ] : 'general';
             add_action('admin_notices', array($this,'pluginNameSettingsMessages'));
             do_action( 'admin_notices', $_GET['error_message'] );
         require_once 'partials/'.$this->plugin_name.'-admin-settings-display.php';

There’s also a reference to the displayPluginAdminDashboard function in the addPluginAdminMenu method. So, we need to add the displayPluginAdminDashboard method to the admin class file as well.

STEP 4: Add the pluginNameSettingsMessages Method to your class-plugin-name-admin.php file

In the displayPluginAdminDashboard function, there’s a reference to another function called pluginNameSettingsMessages.

public function pluginNameSettingsMessages($error_message){
         switch ($error_message) {
             case '1':
                 $message = ( 'There was an error adding this setting. Please try again.  If this persists, shoot us an email.', 'my-text-domain' );                 $err_code = esc_attr( 'plugin_name_example_setting' );                 $setting_field = 'plugin_name_example_setting';                 break;
         $type = 'error';

STEP 5: Add the plugin-name-admin-settings-display.php to partials directory

In the displayPluginAdminDashboard function, there’s a reference to a template file called plugin-name-admin-settings-display.php, so we need to add that to the partials directory.


 * Provide a admin area view for the plugin
 * This file is used to markup the admin-facing aspects of the plugin.
 * @link
 * @since      1.0.0
 * @package    PluginName
 * @subpackage PluginName/admin/partials
<!-- This file should primarily consist of HTML with a little bit of PHP. -->
<div class="wrap">
		        <div id="icon-themes" class="icon32"></div>  
		        <h2>Plugin Name Settings</h2>  
		         <!--NEED THE settings_errors below so that the errors/success messages are shown after submission - wasn't working once we started using add_menu_page and stopped using add_options_page so needed this-->
				<?php settings_errors(); ?>  
		        <form method="POST" action="options.php">  
		                settings_fields( 'plugin_name_general_settings' );
		                do_settings_sections( 'plugin_name_general_settings' ); 
		            <?php submit_button(); ?>  

STEP 6: Build the fields on the settings page by adding the following to the construct method:

add_action('admin_init', array( $this, 'registerAndBuildFields' ));

Step 7: Add registerAndBuildFields method to your construct method of admin.php file

Because you’re referencing the registerAndBuildFields function in the admin_action hook above, you need to add that to your admin.php file.

public function registerAndBuildFields() {
        * First, we add_settings_section. This is necessary since all future settings must belong to one.
        * Second, add_settings_field
        * Third, register_setting
      // ID used to identify this section and with which to register options
      // Title to be displayed on the administration page
      // Callback used to render the description of the section
       array( $this, 'plugin_name_display_general_account' ),    
      // Page on which to add this section of options
    $args = array (
              'type'      => 'input',
              'subtype'   => 'text',
              'id'    => 'plugin_name_example_setting',
              'name'      => 'plugin_name_example_setting',
              'required' => 'true',
              'get_options_list' => '',
              'wp_data' => 'option'
      'Example Setting',
      array( $this, 'plugin_name_render_settings_field' ),



Step 8: Add plugin_name_display_general_account in admin.php file

The plugin_name_display_general_account method is referenced in the registerAndBuildFields function so you need to add it to the file.

public function plugin_name_display_general_account() {
	  echo '<p>These settings apply to all Plugin Name functionality.</p>';

Step 9: Add plugin_name_render_settings_field in admin.php file

This method is referenced in the registerAndBuildFields function so you need to add it to the file. This function is super powerful. We added it to reduce the number of lines of code that we have in our plugins and to automatically populate inputs based on the specified option name or postmeta key associated with that setting. It will also handle saving serialized or normal values. It will save you a ton of time. The registerAndBuildFields function is much smaller as a result of this function.

Since this post, we have added to this function so that it adds the ability to use select boxes in your plugin settings page. Shoot us an email if you would like us to send it to you

public function plugin_name_render_settings_field($args) {
         /* EXAMPLE INPUT
                   'type'      => 'input',
                   'subtype'   => '',
                   'id'    => $this->plugin_name.'_example_setting',
                   'name'      => $this->plugin_name.'_example_setting',
                   'required' => 'required="required"',
                   'get_option_list' => "",
                     'value_type' = serialized OR normal,
         'wp_data'=>(option or post_meta),
         'post_id' =>
   if($args['wp_data'] == 'option'){
        $wp_data_value = get_option($args['name']);
    } elseif($args['wp_data'] == 'post_meta'){
        $wp_data_value = get_post_meta($args['post_id'], $args['name'], true );

    switch ($args['type']) {

        case 'input':
            $value = ($args['value_type'] == 'serialized') ? serialize($wp_data_value) : $wp_data_value;
            if($args['subtype'] != 'checkbox'){
                $prependStart = (isset($args['prepend_value'])) ? '<div class="input-prepend"> <span class="add-on">'.$args['prepend_value'].'</span>' : '';
                $prependEnd = (isset($args['prepend_value'])) ? '</div>' : '';
                $step = (isset($args['step'])) ? 'step="'.$args['step'].'"' : '';
                $min = (isset($args['min'])) ? 'min="'.$args['min'].'"' : '';
                $max = (isset($args['max'])) ? 'max="'.$args['max'].'"' : '';
                    // hide the actual input bc if it was just a disabled input the informaiton saved in the database would be wrong - bc it would pass empty values and wipe the actual information
                    echo $prependStart.'<input type="'.$args['subtype'].'" id="'.$args['id'].'_disabled" '.$step.' '.$max.' '.$min.' name="'.$args['name'].'_disabled" size="40" disabled value="' . esc_attr($value) . '" /><input type="hidden" id="'.$args['id'].'" '.$step.' '.$max.' '.$min.' name="'.$args['name'].'" size="40" value="' . esc_attr($value) . '" />'.$prependEnd;
                } else {
                    echo $prependStart.'<input type="'.$args['subtype'].'" id="'.$args['id'].'" "'.$args['required'].'" '.$step.' '.$max.' '.$min.' name="'.$args['name'].'" size="40" value="' . esc_attr($value) . '" />'.$prependEnd;
                /*<input required="required" '.$disabled.' type="number" step="any" id="'.$this->plugin_name.'_cost2" name="'.$this->plugin_name.'_cost2" value="' . esc_attr( $cost ) . '" size="25" /><input type="hidden" id="'.$this->plugin_name.'_cost" step="any" name="'.$this->plugin_name.'_cost" value="' . esc_attr( $cost ) . '" />*/

            } else {
                $checked = ($value) ? 'checked' : '';
                echo '<input type="'.$args['subtype'].'" id="'.$args['id'].'" "'.$args['required'].'" name="'.$args['name'].'" size="40" value="1" '.$checked.' />';
            # code...

You can adjust the styling on the admin settings page to match your plugin’s styling if you don’t like what shows up but that’s all there is to it!

Leave a Reply

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