Creating Custom Options Pages

  1. Create an Admin Page
  2. Add Fields
  3. Easy Example

First of all please check the screenshot, it is what we are going to create in this tutorial:

WordPress settings page with input field

1. Create an Admin Page

The first step for us is to decide where exactly in admin menu we are going to create an option page.

WordPress admin menu
The good news – you can create it anywhere, whether it is in the Settings section, Dashboard section or a new custom section with an icon.

There are primarily two functions for that:

To simplify the process, instead of add_submenu_page() you can use add_dashboard_page(), add_posts_page(), add_pages_page(), add_comments_page(), add_theme_page(), add_plugins_page(), add_users_page(), add_management_page() or add_options_page() depending on where you’re going to add your submenu page.

Okay, let’s dive into the examples.

Create a custom top-level menu page

Take a look at this code:

add_action( 'admin_menu', 'misha_menu_page' );
 
function misha_menu_page() {
 
	add_menu_page(
		'My Page Title', // page <title>Title</title>
		'My Page', // menu link text
		'manage_options', // capability to access the page
		'misha-slug', // page URL slug
		'misha_page_content', // callback function /w content
		'dashicons-star-half', // menu icon
		5 // priority
	);
 
}
 
function misha_page_content(){
 
	echo 'What is up?';
 
}

It is super simple, but if you insert it to your functions.php file, a new admin page will appear.

Custom menu page in WordPress admin area

If you don’t understand how I have added an icon there, just check the Dashicons icon set.

Create a custom options page

Creating a new menu item with an icon is cool but the truth is when you create a plugin settings page, it is always better to add it as a submenu page under Settings.

It is the best practice and in most cases I recommend you to do it that way.

add_action( 'admin_menu', 'misha_options_page' );
 
function misha_options_page() {
 
	add_options_page(
		'My Page Title', // page <title>Title</title>
		'My Page', // menu link text
		'manage_options', // capability to access the page
		'misha-slug', // page URL slug
		'misha_page_content', // callback function with content
		2 // priority
	);
 
}
 
function misha_page_content(){
 
	echo 'What is up?';
 
}

Very similar to the previous example, isn’t it? We only don’t have an icon parameter anymore.

How to create an options page in WordPress

Now you already know how to add any custom HTML to your options pages, but in the next chapter I will show you how to properly create settings fields there.

2. Add Fields with Settings API

First of all let’s populate our misha_page_content() function which we created in the previous step.

function misha_page_content(){
 
	echo '<div class="wrap">
	<h1>My Page Settings</h1>
	<form method="post" action="options.php">';
 
		settings_fields( 'misha_settings' ); // settings group name
		do_settings_sections( 'misha-slug' ); // just a page slug
		submit_button();
 
	echo '</form></div>';
 
}

We are not going to make any changes in this functions anymore. All you have to know is that we use two functions settings_fields() and do_settings_sections() to print all the settings fields and to populate them with data.

If you did everything correctly until this moment, you will have this:

WordPress options page without fields

2.1 Register a setting and create a field

add_action( 'admin_init',  'misha_register_setting' );
 
function misha_register_setting(){
 
	register_setting(
		'misha_settings', // settings group name
		'homepage_text', // option name
		'sanitize_text_field' // sanitization function
	);
 
	add_settings_section(
		'some_settings_section_id', // section ID
		'', // title (if needed)
		'', // callback function (if needed)
		'misha-slug' // page slug
	);
 
	add_settings_field(
		'homepage_text',
		'Homepage text',
		'misha_text_field_html', // function which prints the field
		'misha-slug', // page slug
		'some_settings_section_id', // section ID
		array( 
			'label_for' => 'homepage_text',
			'class' => 'misha-class', // for <tr> element
		)
	);
 
}
 
function misha_text_field_html(){
 
	$text = get_option( 'homepage_text' );
 
	printf(
		'<input type="text" id="homepage_text" name="homepage_text" value="%s" />',
		esc_attr( $text )
	);
 
}

What is esc_attr() function and why it is here? There is a separate tutorial on my blog about escaping outputs where I said that database is not a trusted source of data and that’s why we must use escaping functions before we output anything into the page content.

And now we have a working options page:

WordPress settings page with input field

2.2 Sanitization

Let’s come back for a moment to a register_setting() function from the previous piece of code.

register_setting(
	'misha_settings',
	'homepage_text',
	'sanitize_text_field' // sanitization function
);

The third parameter is the function name which is intended to sanitize (clean) the field data before saving into the database. For example sanitize_text_field() is the default WordPress function that removes all the characters that are not allowed in use in an input text field. If you would like to to pass an integer, you can use intval() or absint() function names instead. Or create a custom sanitization function for your purpose.

Example for positive integers:

register_setting( 'misha_settings', 'number_of_slides', 'absint' );

3. Easy example

We have some code above. Actually a lot of code. And it is all about to create a single input field.

I want to be honest with you – I never do all that manually on my projects. Because it is so time consuming. What is the solutions then? I also don’t like plugins, especially ACF-like ones. Because I’d better spend a couple more hours and create a fast website instead of using slow bloated plugins.

Finally I came to a solution – I created my own option pages plugin with the bare minimum of the functionality. It is lightning fast just like you code everything in functions.php, but at the same time it saves hours of development.

Just compare this code to everything we did above:

add_filter( 'simple_register_option_pages', 'misha_option_page' );
 
function misha_option_page( $option_pages ) {
 
	$option_pages[] = array(
		'id'	=> 'misha_slug',
		'title' => 'My Page Settings',
		'menu_name' => 'My page',
		'fields' => array(
			array(
				'id' => 'homepage_text',
				'label' => 'Homepage text',
				'type' => 'text',
			),
 		),
	);
 
	return $option_pages;
 
}

And we have absolutely the same result as we have creating an option page from scratch in the first part of the tutorial.

WordPress settings page with input field

Related tutorials

Misha Rudrastyh

Misha Rudrastyh

I love WordPress, WooCommerce and Gutenberg so much. 11 yrs of experience.

Need some custom developer help? Get in touch