A complete, versatile options page class for any WordPress plugin

Building an options page for a plugin can be a daunting prospect – you want to build it in a way that works for your plugin, but also so that it works well within the WordPress UI. Many plugin authors get this painfully wrong and build incredibly unfriendly options pages that look terrible and really don’t fit into the WordPress dashboard design at all.

After putting loads of work into refactoring Seriously Simple Podcasting for the v2.0 release, I’ve developed a single class that will help you to create a versatile and user-friendly options page for your plugin that fits neatly into the WordPress dashboard. All you need to do is add this class to your plugin and modify the array of settings to handle the data that your plugin needs.

This isn’t a tutorial post, so I’m not going to walk you through this step by step, but if you use the class below you can create a WordPress options page with every type of field possible with almost no effort on your part. The field types that this class can create are:

  • Text field
  • Password field
  • Secret text field (where the saved data is not displayed on the page)
  • Text area
  • Single checkbox
  • Multiple checkboxes
  • Select box
  • Multiple select box
  • Radio buttons
  • Number field
  • Colour picker (using WordPress’ built-in colour picker script)
  • Image upload (that saves the image to your site’s media library)

I have included demo fields in the class so you can see how each field type works and what parameters you need to define for each field type – all you need to do is delete these fields and create your own.

The class uses all the WordPress Settings API functions, so it does things in the “correct” way. It also includes a mini-navigation that uses Javascript to show & hide the relevant sections.

You will find the class, along with its associated Javascript file below, but if you want to see it all in action in the context of a full plugin you can check out my WordPress Plugin Template that includes this same code. For a quick overview of what the resulting options page will look like, here’s a handy screenshot (click to enlarge):

Options page

The options page that is generated by this class

Here is the class in its entirety:

<?php

if ( ! defined( 'ABSPATH' ) ) exit;

class WordPress_Plugin_Template_Settings {
    private $dir;
	private $file;
	private $assets_dir;
	private $assets_url;
	private $settings_base;
	private $settings;

	public function __construct( $file ) {
		$this->file = $file;
		$this->dir = dirname( $this->file );
		$this->assets_dir = trailingslashit( $this->dir ) . 'assets';
		$this->assets_url = esc_url( trailingslashit( plugins_url( '/assets/', $this->file ) ) );
		$this->settings_base = 'wpt_';

		// Initialise settings
		add_action( 'admin_init', array( $this, 'init' ) );

		// Register plugin settings
		add_action( 'admin_init' , array( $this, 'register_settings' ) );

		// Add settings page to menu
		add_action( 'admin_menu' , array( $this, 'add_menu_item' ) );

		// Add settings link to plugins page
		add_filter( 'plugin_action_links_' . plugin_basename( $this->file ) , array( $this, 'add_settings_link' ) );
	}

	/**
	 * Initialise settings
	 * @return void
	 */
	public function init() {
		$this->settings = $this->settings_fields();
	}

	/**
	 * Add settings page to admin menu
	 * @return void
	 */
	public function add_menu_item() {
		$page = add_options_page( __( 'Plugin Settings', 'plugin_textdomain' ) , __( 'Plugin Settings', 'plugin_textdomain' ) , 'manage_options' , 'plugin_settings' ,  array( $this, 'settings_page' ) );
		add_action( 'admin_print_styles-' . $page, array( $this, 'settings_assets' ) );
	}

	/**
	 * Load settings JS & CSS
	 * @return void
	 */
	public function settings_assets() {

        // We're including the farbtastic script & styles here because they're needed for the colour picker
        // If you're not including a colour picker field then you can leave these calls out as well as the farbtastic dependency for the wpt-admin-js script below
        wp_enqueue_style( 'farbtastic' );
        wp_enqueue_script( 'farbtastic' );

        // We're including the WP media scripts here because they're needed for the image upload field
        // If you're not including an image upload then you can leave this function call out
        wp_enqueue_media();

        wp_register_script( 'wpt-admin-js', $this->assets_url . 'js/admin.js', array( 'farbtastic', 'jquery' ), '1.0.0' );
        wp_enqueue_script( 'wpt-admin-js' );
	}

	/**
	 * Add settings link to plugin list table
	 * @param  array $links Existing links
	 * @return array 		Modified links
	 */
	public function add_settings_link( $links ) {
		$settings_link = '<a href="options-general.php?page=plugin_settings">' . __( 'Settings', 'plugin_textdomain' ) . '</a>';
  		array_push( $links, $settings_link );
  		return $links;
	}

	/**
	 * Build settings fields
	 * @return array Fields to be displayed on settings page
	 */
	private function settings_fields() {

		$settings['standard'] = array(
			'title'					=> __( 'Standard', 'plugin_textdomain' ),
			'description'			=> __( 'These are fairly standard form input fields.', 'plugin_textdomain' ),
			'fields'				=> array(
				array(
					'id' 			=> 'text_field',
					'label'			=> __( 'Some Text' , 'plugin_textdomain' ),
					'description'	=> __( 'This is a standard text field.', 'plugin_textdomain' ),
					'type'			=> 'text',
					'default'		=> '',
					'placeholder'	=> __( 'Placeholder text', 'plugin_textdomain' )
				),
				array(
					'id' 			=> 'password_field',
					'label'			=> __( 'A Password' , 'plugin_textdomain' ),
					'description'	=> __( 'This is a standard password field.', 'plugin_textdomain' ),
					'type'			=> 'password',
					'default'		=> '',
					'placeholder'	=> __( 'Placeholder text', 'plugin_textdomain' )
				),
				array(
					'id' 			=> 'secret_text_field',
					'label'			=> __( 'Some Secret Text' , 'plugin_textdomain' ),
					'description'	=> __( 'This is a secret text field - any data saved here will not be displayed after the page has reloaded, but it will be saved.', 'plugin_textdomain' ),
					'type'			=> 'text_secret',
					'default'		=> '',
					'placeholder'	=> __( 'Placeholder text', 'plugin_textdomain' )
				),
				array(
					'id' 			=> 'text_block',
					'label'			=> __( 'A Text Block' , 'plugin_textdomain' ),
					'description'	=> __( 'This is a standard text area.', 'plugin_textdomain' ),
					'type'			=> 'textarea',
					'default'		=> '',
					'placeholder'	=> __( 'Placeholder text for this textarea', 'plugin_textdomain' )
				),
				array(
					'id' 			=> 'single_checkbox',
					'label'			=> __( 'An Option', 'plugin_textdomain' ),
					'description'	=> __( 'A standard checkbox - if you save this option as checked then it will store the option as \'on\', otherwise it will be an empty string.', 'plugin_textdomain' ),
					'type'			=> 'checkbox',
					'default'		=> ''
				),
				array(
					'id' 			=> 'select_box',
					'label'			=> __( 'A Select Box', 'plugin_textdomain' ),
					'description'	=> __( 'A standard select box.', 'plugin_textdomain' ),
					'type'			=> 'select',
					'options'		=> array( 'drupal' => 'Drupal', 'joomla' => 'Joomla', 'wordpress' => 'WordPress' ),
					'default'		=> 'wordpress'
				),
				array(
					'id' 			=> 'radio_buttons',
					'label'			=> __( 'Some Options', 'plugin_textdomain' ),
					'description'	=> __( 'A standard set of radio buttons.', 'plugin_textdomain' ),
					'type'			=> 'radio',
					'options'		=> array( 'superman' => 'Superman', 'batman' => 'Batman', 'ironman' => 'Iron Man' ),
					'default'		=> 'batman'
				),
				array(
					'id' 			=> 'multiple_checkboxes',
					'label'			=> __( 'Some Items', 'plugin_textdomain' ),
					'description'	=> __( 'You can select multiple items and they will be stored as an array.', 'plugin_textdomain' ),
					'type'			=> 'checkbox_multi',
					'options'		=> array( 'square' => 'Square', 'circle' => 'Circle', 'rectangle' => 'Rectangle', 'triangle' => 'Triangle' ),
					'default'		=> array( 'circle', 'triangle' )
				)
			)
		);

		$settings['extra'] = array(
			'title'					=> __( 'Extra', 'plugin_textdomain' ),
			'description'			=> __( 'These are some extra input fields that maybe aren\'t as common as the others.', 'plugin_textdomain' ),
			'fields'				=> array(
				array(
					'id' 			=> 'number_field',
					'label'			=> __( 'A Number' , 'plugin_textdomain' ),
					'description'	=> __( 'This is a standard number field - if this field contains anything other than numbers then the form will not be submitted.', 'plugin_textdomain' ),
					'type'			=> 'number',
					'default'		=> '',
					'placeholder'	=> __( '42', 'plugin_textdomain' )
				),
				array(
					'id' 			=> 'colour_picker',
					'label'			=> __( 'Pick a colour', 'plugin_textdomain' ),
					'description'	=> __( 'This uses WordPress\' built-in colour picker - the option is stored as the colour\'s hex code.', 'plugin_textdomain' ),
					'type'			=> 'color',
					'default'		=> '#21759B'
				),
				array(
					'id' 			=> 'an_image',
					'label'			=> __( 'An Image' , 'plugin_textdomain' ),
					'description'	=> __( 'This will upload an image to your media library and store the attachment ID in the option field. Once you have uploaded an imge the thumbnail will display above these buttons.', 'plugin_textdomain' ),
					'type'			=> 'image',
					'default'		=> '',
					'placeholder'	=> ''
				),
				array(
					'id' 			=> 'multi_select_box',
					'label'			=> __( 'A Multi-Select Box', 'plugin_textdomain' ),
					'description'	=> __( 'A standard multi-select box - the saved data is stored as an array.', 'plugin_textdomain' ),
					'type'			=> 'select_multi',
					'options'		=> array( 'linux' => 'Linux', 'mac' => 'Mac', 'windows' => 'Windows' ),
					'default'		=> array( 'linux' )
				)
			)
		);

		$settings = apply_filters( 'plugin_settings_fields', $settings );

		return $settings;
	}

	/**
	 * Register plugin settings
	 * @return void
	 */
	public function register_settings() {
		if( is_array( $this->settings ) ) {
			foreach( $this->settings as $section => $data ) {

				// Add section to page
				add_settings_section( $section, $data['title'], array( $this, 'settings_section' ), 'plugin_settings' );

				foreach( $data['fields'] as $field ) {

					// Validation callback for field
					$validation = '';
					if( isset( $field['callback'] ) ) {
						$validation = $field['callback'];
					}

					// Register field
					$option_name = $this->settings_base . $field['id'];
					register_setting( 'plugin_settings', $option_name, $validation );

					// Add field to page
					add_settings_field( $field['id'], $field['label'], array( $this, 'display_field' ), 'plugin_settings', $section, array( 'field' => $field ) );
				}
			}
		}
	}

	public function settings_section( $section ) {
		$html = '<p> ' . $this->settings[ $section['id'] ]['description'] . '</p>' . "\n";
		echo $html;
	}

	/**
	 * Generate HTML for displaying fields
	 * @param  array $args Field data
	 * @return void
	 */
	public function display_field( $args ) {

		$field = $args['field'];

		$html = '';

		$option_name = $this->settings_base . $field['id'];
		$option = get_option( $option_name );

		$data = '';
		if( isset( $field['default'] ) ) {
			$data = $field['default'];
			if( $option ) {
				$data = $option;
			}
		}

		switch( $field['type'] ) {

			case 'text':
			case 'password':
			case 'number':
				$html .= '<input id="' . esc_attr( $field['id'] ) . '" type="' . $field['type'] . '" name="' . esc_attr( $option_name ) . '" placeholder="' . esc_attr( $field['placeholder'] ) . '" value="' . $data . '"/>' . "\n";
			break;

			case 'text_secret':
				$html .= '<input id="' . esc_attr( $field['id'] ) . '" type="text" name="' . esc_attr( $option_name ) . '" placeholder="' . esc_attr( $field['placeholder'] ) . '" value=""/>' . "\n";
			break;

			case 'textarea':
				$html .= '<textarea id="' . esc_attr( $field['id'] ) . '" rows="5" cols="50" name="' . esc_attr( $option_name ) . '" placeholder="' . esc_attr( $field['placeholder'] ) . '">' . $data . '</textarea><br/>'. "\n";
			break;

			case 'checkbox':
				$checked = '';
				if( $option && 'on' == $option ){
					$checked = 'checked="checked"';
				}
				$html .= '<input id="' . esc_attr( $field['id'] ) . '" type="' . $field['type'] . '" name="' . esc_attr( $option_name ) . '" ' . $checked . '/>' . "\n";
			break;

			case 'checkbox_multi':
				foreach( $field['options'] as $k => $v ) {
					$checked = false;
					if( in_array( $k, $data ) ) {
						$checked = true;
					}
					$html .= '<label for="' . esc_attr( $field['id'] . '_' . $k ) . '"><input type="checkbox" ' . checked( $checked, true, false ) . ' name="' . esc_attr( $option_name ) . '[]" value="' . esc_attr( $k ) . '" id="' . esc_attr( $field['id'] . '_' . $k ) . '" /> ' . $v . '</label> ';
				}
			break;

			case 'radio':
				foreach( $field['options'] as $k => $v ) {
					$checked = false;
					if( $k == $data ) {
						$checked = true;
					}
					$html .= '<label for="' . esc_attr( $field['id'] . '_' . $k ) . '"><input type="radio" ' . checked( $checked, true, false ) . ' name="' . esc_attr( $option_name ) . '" value="' . esc_attr( $k ) . '" id="' . esc_attr( $field['id'] . '_' . $k ) . '" /> ' . $v . '</label> ';
				}
			break;

			case 'select':
				$html .= '<select name="' . esc_attr( $option_name ) . '" id="' . esc_attr( $field['id'] ) . '">';
				foreach( $field['options'] as $k => $v ) {
					$selected = false;
					if( $k == $data ) {
						$selected = true;
					}
					$html .= '<option ' . selected( $selected, true, false ) . ' value="' . esc_attr( $k ) . '">' . $v . '</option>';
				}
				$html .= '</select> ';
			break;

			case 'select_multi':
				$html .= '<select name="' . esc_attr( $option_name ) . '[]" id="' . esc_attr( $field['id'] ) . '" multiple="multiple">';
				foreach( $field['options'] as $k => $v ) {
					$selected = false;
					if( in_array( $k, $data ) ) {
						$selected = true;
					}
					$html .= '<option ' . selected( $selected, true, false ) . ' value="' . esc_attr( $k ) . '" />' . $v . '</label> ';
				}
				$html .= '</select> ';
			break;

			case 'image':
				$image_thumb = '';
				if( $data ) {
					$image_thumb = wp_get_attachment_thumb_url( $data );
				}
				$html .= '<img id="' . $option_name . '_preview" class="image_preview" src="' . $image_thumb . '" /><br/>' . "\n";
				$html .= '<input id="' . $option_name . '_button" type="button" data-uploader_title="' . __( 'Upload an image' , 'plugin_textdomain' ) . '" data-uploader_button_text="' . __( 'Use image' , 'plugin_textdomain' ) . '" class="image_upload_button button" value="'. __( 'Upload new image' , 'plugin_textdomain' ) . '" />' . "\n";
				$html .= '<input id="' . $option_name . '_delete" type="button" class="image_delete_button button" value="'. __( 'Remove image' , 'plugin_textdomain' ) . '" />' . "\n";
				$html .= '<input id="' . $option_name . '" class="image_data_field" type="hidden" name="' . $option_name . '" value="' . $data . '"/><br/>' . "\n";
			break;

			case 'color':
				?><div class="color-picker" style="position:relative;">
			        <input type="text" name="<?php esc_attr_e( $option_name ); ?>" class="color" value="<?php esc_attr_e( $data ); ?>" />
			        <div style="position:absolute;background:#FFF;z-index:99;border-radius:100%;" class="colorpicker"></div>
			    </div>
			    <?php
			break;

		}

		switch( $field['type'] ) {

			case 'checkbox_multi':
			case 'radio':
			case 'select_multi':
				$html .= '<br/><span class="description">' . $field['description'] . '</span>';
			break;

			default:
				$html .= '<label for="' . esc_attr( $field['id'] ) . '"><span class="description">' . $field['description'] . '</span></label>' . "\n";
			break;
		}

		echo $html;
	}

	/**
	 * Validate individual settings field
	 * @param  string $data Inputted value
	 * @return string       Validated value
	 */
	public function validate_field( $data ) {
		if( $data && strlen( $data ) > 0 && $data != '' ) {
			$data = urlencode( strtolower( str_replace( ' ' , '-' , $data ) ) );
		}
		return $data;
	}

	/**
	 * Load settings page content
	 * @return void
	 */
	public function settings_page() {

		// Build page HTML
		$html = '<div class="wrap" id="plugin_settings">' . "\n";
			$html .= '<h2>' . __( 'Plugin Settings' , 'plugin_textdomain' ) . '</h2>' . "\n";
			$html .= '<form method="post" action="options.php" enctype="multipart/form-data">' . "\n";

				// Setup navigation
				$html .= '<ul id="settings-sections" class="subsubsub hide-if-no-js">' . "\n";
					$html .= '<li><a class="tab all current" href="#all">' . __( 'All' , 'plugin_textdomain' ) . '</a></li>' . "\n";

					foreach( $this->settings as $section => $data ) {
						$html .= '<li>| <a class="tab" href="#' . $section . '">' . $data['title'] . '</a></li>' . "\n";
					}

				$html .= '</ul>' . "\n";

				$html .= '<div class="clear"></div>' . "\n";

				// Get settings fields
				ob_start();
				settings_fields( 'plugin_settings' );
				do_settings_sections( 'plugin_settings' );
				$html .= ob_get_clean();

				$html .= '<p class="submit">' . "\n";
					$html .= '<input name="Submit" type="submit" class="button-primary" value="' . esc_attr( __( 'Save Settings' , 'plugin_textdomain' ) ) . '" />' . "\n";
				$html .= '</p>' . "\n";
			$html .= '</form>' . "\n";
		$html .= '</div>' . "\n";

		echo $html;
	}

}

And here is the Javascript file that you will need to manage everything. You will need to save this inside your plugin in this folder: /assets/js/admin.js

jQuery(document).ready(function($) {

    /***** Colour picker *****/

    $('.colorpicker').hide();
    $('.colorpicker').each( function() {
        $(this).farbtastic( $(this).closest('.color-picker').find('.color') );
    });

    $('.color').click(function() {
        $(this).closest('.color-picker').find('.colorpicker').fadeIn();
    });

    $(document).mousedown(function() {
        $('.colorpicker').each(function() {
            var display = $(this).css('display');
            if ( display == 'block' )
                $(this).fadeOut();
        });
    });


    /***** Uploading images *****/

    var file_frame;

    jQuery.fn.uploadMediaFile = function( button, preview_media ) {
        var button_id = button.attr('id');
        var field_id = button_id.replace( '_button', '' );
        var preview_id = button_id.replace( '_button', '_preview' );

        // If the media frame already exists, reopen it.
        if ( file_frame ) {
          file_frame.open();
          return;
        }

        // Create the media frame.
        file_frame = wp.media.frames.file_frame = wp.media({
          title: jQuery( this ).data( 'uploader_title' ),
          button: {
            text: jQuery( this ).data( 'uploader_button_text' ),
          },
          multiple: false
        });

        // When an image is selected, run a callback.
        file_frame.on( 'select', function() {
          attachment = file_frame.state().get('selection').first().toJSON();
          jQuery("#"+field_id).val(attachment.id);
          if( preview_media ) {
            jQuery("#"+preview_id).attr('src',attachment.sizes.thumbnail.url);
          }
        });

        // Finally, open the modal
        file_frame.open();
    }

    jQuery('.image_upload_button').click(function() {
        jQuery.fn.uploadMediaFile( jQuery(this), true );
    });

    jQuery('.image_delete_button').click(function() {
        jQuery(this).closest('td').find( '.image_data_field' ).val( '' );
        jQuery( '.image_preview' ).remove();
        return false;
    });


    /***** Navigation for settings page *****/

    // Make sure each heading has a unique ID.
    jQuery( 'ul#settings-sections.subsubsub' ).find( 'a' ).each( function ( i ) {
        var id_value = jQuery( this ).attr( 'href' ).replace( '#', '' );
        jQuery( 'h3:contains("' + jQuery( this ).text() + '")' ).attr( 'id', id_value ).addClass( 'section-heading' );
    });

    // Create nav links for settings page
    jQuery( '#plugin_settings .subsubsub a.tab' ).click( function ( e ) {
        // Move the "current" CSS class.
        jQuery( this ).parents( '.subsubsub' ).find( '.current' ).removeClass( 'current' );
        jQuery( this ).addClass( 'current' );

        // If "All" is clicked, show all.
        if ( jQuery( this ).hasClass( 'all' ) ) {
            jQuery( '#plugin_settings h3, #plugin_settings form p, #plugin_settings table.form-table, p.submit' ).show();

            return false;
        }

        // If the link is a tab, show only the specified tab.
        var toShow = jQuery( this ).attr( 'href' );

        // Remove the first occurance of # from the selected string (will be added manually below).
        toShow = toShow.replace( '#', '', toShow );

        jQuery( '#plugin_settings h3, #plugin_settings form > p:not(".submit"), #plugin_settings table' ).hide();
        jQuery( 'h3#' + toShow ).show().nextUntil( 'h3.section-heading', 'p, table, table p' ).show();

        return false;
    });
});

To add this options page to your plugin, simply add this line to your plugin’s index file after you have added an include for the class file:

$settings = new WordPress_Plugin_Template_Settings( __FILE__ );

Once you have added all this code you will find the new options page in the dashboard menu by going to Settings > Plugin Settings.

The options that are saved from this page use the $settings_base variable in the class (in this case, ‘wpt_‘)followed by the id field of each setting for their name. So the option name for the first field would be ‘wpt_text_field‘, which you can fetch using get_option( 'wpt_text_field' );.

If you can think of any other field types that you think should be included in this class then let me know in the comments.

Tags: , , , , , , , ,

9 Responses to “A complete, versatile options page class for any WordPress plugin”

  1. André March 10, 2014 at 9:11 pm #

    Great work, just came in handy for my very first plugin. I learned a lot about WP from friendly people like you who are willing to share their knowledge. As for your question about enhancements: how about having some sort of repeater? This would give us the ability for having “sets of settings”. Example: a playlist for an mp3 player, where each entry could for example have a title, a cover picture, etc.

    Another thought: how about storing all settings in an array into the db, instead of having multiple db calls?

    Grettings from germany

    • André March 10, 2014 at 9:43 pm #

      In addition to the above: just found your fantastic wordpress plugin template on Github and came up with another idea on this: why not separate the field output logic? So we could use the different field types for the custom post type metaboxes as well.

      • Hugh Lashbrooke March 11, 2014 at 7:21 am #

        Thanks for the great feedback Andre! I’ll look into the idea of a ‘set’ of settings like you mention – might be a nice little enhancement. As for storing the options in a single array instead of multiple DB calls, I chose not to do that because when you are calling the options on the frontend it’s not always beneficial to call every single option when all you need is a single option. I’m not sure of the numbers with regards to performance, but I generally favour multiple options instead of one global array.

        I really like the idea of separating out the field logic so it’s usable for custom post types as well – I’ll look into enhancing the template to handle that as I think it would be a very valuable upgrade :)

        • André March 11, 2014 at 10:52 am #

          Glad you like my ideas. I think your template is a valuable foundation for every plugin coder, especially for beginners like me. I definitive stick with this post and will refractor my mp3 player plugin with your template as a base, especially after your next update ;-)

          For the database calls: I just was a bit concerned about the amount of database calls for each plugin. Since I love the progress in my WP coding skills, i am quite sure that there will be a lot more plugin stuff from me in the future. Right now I am working on a versatile solution to play mp3 files in a WP site, comes with different flavors like single player, footer player ith playlist, etc. Complete with custom post type. I am damn proud about my first plugin. At the moment I am struggling with a single bit: I somehow need to hook into the file upload process. First for ensuring that there are only mp3 files ready, second because I want to create preview files of the uploaded mp3 files. I have a fantastic class for hat in my arsenal, that I have allready used for another project.

          Thanks for your effort, can’t wait to see the progress in your template. Keep me informed please ;-)

  2. Thom Stark March 19, 2014 at 5:29 am #

    Hi. Thanks for this. I have a question about multi-select options.

    I need to generate the options dynamically according to the given site’s user roles. So:

    array(
    ‘id’ => ‘multi_select_box’,
    ‘label’ => __( ‘A Multi-Select Box’, ‘plugin_textdomain’ ),
    ‘description’ => __( ‘A standard multi-select box – the saved data is stored as an array.’, ‘plugin_textdomain’ ),
    ‘type’ => ‘select_multi’,
    ‘options’ => array( ‘linux’ => ‘Linux’, ‘mac’ => ‘Mac’, ‘windows’ => ‘Windows’ ),
    ‘default’ => array( ‘linux’ )
    )

    … the options array would need to be built from another foreach and stored in a variable I guess. Here’s the foreach to generate the user roles:

    global $wp_roles;
    $all_roles = $wp_roles->roles;
    $editable_roles = apply_filters(‘editable_roles’, $all_roles);
    foreach($editable_roles as $role=>$theroles){
    echo ”.$wp_roles->role_names[$role].”;
    }

    How could I do this and plug it into the options array? Thanks for your time.

  3. Thom Stark March 19, 2014 at 5:30 am #

    Ah, the comment box stripped out the html, but you should get the idea.

    • Hugh Lashbrooke March 19, 2014 at 8:33 am #

      Hi Thom,

      All you need to do is save the array of user roles as a variable in this format array( 'role' => 'Role Name' ). If you’re not sure how to do that then Google should be able to help you out :)

  4. ibhi June 3, 2014 at 2:57 pm #

    Hi,
    Thanks for this great plugin template. I am starting my first plugin with your template. I have a question though. What the “validation callback for field” is doing? Can you explain it for me?

    public function register_settings () {
    if( is_array( $this->settings ) ) {
    foreach( $this->settings as $section => $data ) {

    // Add section to page
    add_settings_section( $section, $data['title'], array( $this, ‘settings_section’ ), ‘html_data_table_settings’ );

    foreach( $data['fields'] as $field ) {

    // Validation callback for field
    $validation = ”;
    if( isset( $field['callback'] ) ) {
    $validation = $field['callback'];
    }

    // Register field
    $option_name = $this->base . $field['id'];
    register_setting( ‘html_data_table_settings’, $option_name, $validation );

    // Add field to page
    add_settings_field( $field['id'], $field['label'], array( $this, ‘display_field’ ), ‘html_data_table_settings’, $section, array( ‘field’ => $field ) );
    }
    }
    }
    }

    • Hugh Lashbrooke June 4, 2014 at 12:31 pm #

      The validation callback is a way of validating the submitted form data before saving it. You can create a function that checks the content of the submitted field and performs any action you like on that content before saving it to the database. A good example of this would be if you are asking people to save a URL in one of the fields – using the validation callback you can run the esc_url() function on the submitted text to make sure that it is saved as a properly formatted URL.

Leave a Reply

css.php
Post
Comments