How to create a simple WordPress plugin that saves a single custom field with the Settings API
There are numerous ways to add custom settings to WordPress. One way would be to pay for Advanced Custom Fields Pro, or to create a plugin with a custom database table. But there is a better solution: using the Settings API.
The WordPress Settings API is definitely not the most clear or most fun API to work with, but if all you need are some simple custom settings, it's a great way to do it with just a few lines of code.
The Challenge
A client needs a custom button on his website that will be shown at the top of every post. This button will contain a link to the current offer of his company (there's a new offer every month). So the client wants an easy way to update the link behind the button.
I could use a plugin like Advanced Custom Fields Pro to do this, but I'd have to pay for it (yearly). Plus, I don't want to use a plugin that comes with so many options while I'll just use a simple text field. I like to keep it clean and minimal.
The Solution
Creating a plugin
First the easy part. Let's create a plugin! Just create a folder on your desktop with the name of your plug-in and create an empty PHP file in the directory. The name doesn't really matter, but let's use the same name as the directory.

The only thing we need to define this as a plugin, is the following header:
<?php
/*
Plugin Name: Change link of custom CTA button
*/
However, feel free to add additional headers like 'Description', 'Version', 'Author' and 'Description'.
Now, you can just compress the directory into a zip and upload it to WordPress as a plugin. Congratulations, you are now the author of a plugin!
Creating the admin menu item and page
Let's make our plugin do something. We'll create an additional item in the admin menu.
add_action( 'admin_menu', 'teebow_options_page' );
function teebow_options_page() {
add_menu_page(
'CTA button',
'CTA button',
'manage_options',
'teebow-custom-cta',
'teebow_options_page_html',
'dashicons-admin-tools',
20
);
}
Alright so what is happening here. We're creating a new function that will define the menu item through the add_menu_page function. We provide the following parameters:
- Page title: The title that will be shown in the title tags
- Menu title: The title that will be used for the menu item
- Capability: The capability that is needed for users to see this menu item
- Menu slug: This is how you'll refer to this menu. It should be unique.
- Callback: The name of the function that will include the contents of this settings page.
- Icon: The location of the icon for the menu item. The easiest thing is to pick a dashicon.
This will define the menu item, but we still need to create the function to add content to the settings page.
function teebow_options_page_html() {
?>
<div class="wrap">
<h1>Change CTA button</h1>
<p>Welcome to my custom settings screen!</p>
</div>
<?php
}

Register custom setting
Now let's get started with the Settings API. First we'll use the register_setting to register the custom setting. Then we'll create a settings section. And finally, we'll add a settings field to the section.
function teebow_register_settings() {
register_setting( 'teebow_options', 'teebow_options' );
}
add_action( 'admin_init', 'teebow_register_settings' );
The register_setting function needs two parameters:
- Option Group: The name of the group that will combine all the settings.
- Option Name: How it will be stored in the database.
These names are usually the same but don't have to be.
Create a settings section
The next step is to create a settings section. This function needs the following parameters:
- ID: Slug to identify the section.
- Title: This will be shown as the title of the section.
- Callback: A reference to a function that will output content at the top of the section (above the fields).
- Page: A slug that will be used by add_settings_field and do_settings_sections.
We will add this function right after the register_setting function.
function teebow_register_settings() {
register_setting( 'teebow_options', 'teebow_options' );
add_settings_section( 'cta_settings', 'Change CTA button link', 'teebow_section_text', 'teebow_options_page' );
}
add_action( 'admin_init', 'teebow_register_settings' );
Since we reference the function teebow_section_text, we need to create this function as well. Use this function to echo any output you want to show between the title of the section and the setting fields.
function teebow_section_text() {
echo '<p>Welcome to my settings section</p>';
}
Adding the settings section to your settings page
It's time to change the static HTML output of our settings page to a more dynamic approach.
We'll go back to our callback function that defines the content of our admin menu page (in my case that's the function teebow_options_page_html. Here, we'll add a form that calls options.php. Do not change this.
In the form, we start with calling a function called settings_fields. As a parameter, we pass the name of the option group (which we defined in register_setting). This is an important function that will make the form work and make it secure.
Next, we'll use the do_settings_sections function to output the section we created.
We'll finish up by adding a button to submit the form. By using esc_attr_e the value of the button will be dynamically changed based on the site language.
The function now looks like this:
function teebow_options_page_html() {
?>
<div class="wrap">
<form action="options.php" method="post">
<?php
settings_fields( 'teebow_options' );
do_settings_sections( 'teebow_options_page' ); ?>
<input name="submit" class="button button-primary" type="submit" value="<?php esc_attr_e( 'Save' ); ?>" />
</form>
</div>
<?php
}
In WordPress, the result looks like this:

Adding a text field and saving its value
Alright, we're almost there. Now we just need to add the input fields to receive the values from the user and store it as a setting.
We'll do this by using the add_settings_field, which requires the following parameters:
- ID: Slug to identify the field
- Title: Title that will be shown next to the field
- Callback: Reference to a function that will include the input field
- Page: The slug name of the settings page on which to show the section (this is a very confusing parameter)
- Section: The name of the section that will contain the settings field
The function teebow_register_settings is now complete and looks like this:
function teebow_register_settings() {
register_setting( 'teebow_options', 'teebow_options' );
add_settings_section( 'cta_settings', 'Change CTA button link', 'teebow_section_text', 'teebow_options_page' );
add_settings_field( 'teebow_button_link', 'Button link', 'teebow_button_link', 'teebow_options_page', 'cta_settings' );
}
add_action( 'admin_init', 'teebow_register_settings' );
Since we reference the function ts_button_link, we should now create this function. The function will output (echo) an input field for the setting.
We'll introduce a new concept here: get_option. This function will allow us to get the value of a setting from the WordPress database. By using this as the value of the input field, we're able to show the current value of the value in the text field. To get the value of a setting, you'll use the name of the registered setting as a parameter. The second parameter is the default value which will be used if a custom value hasn't been saved yet.
function teebow_button_link()
{
$option = get_option('teebow_options','default');
echo "<input id='teebow_button_link' name='teebow_options' type='text' value='".esc_attr($option)."' />";
}
Done!
There you go! You now have a custom setting that's being store in the WordPress database. You can now simply use the get_option function to get the value of the setting whenever you need it!

The complete code looks like this:
<?php
/*
* Plugin Name: Change link of CTA button
*/
add_action( 'admin_menu', 'teebow_options_page' );
function teebow_options_page() {
add_menu_page(
'CTA button',
'CTA button',
'manage_options',
'teebow-custom-cta',
'teebow_options_page_html',
'dashicons-admin-tools',
20
);
}
function teebow_options_page_html() {
?>
<div class="wrap">
<form action="options.php" method="post">
<?php
settings_fields( 'teebow_options' );
do_settings_sections( 'teebow_options_page' ); ?>
<input name="submit" class="button button-primary" type="submit" value="<?php esc_attr_e( 'Save' ); ?>" />
</form>
</div>
<?php
}
function teebow_register_settings() {
register_setting( 'teebow_options', 'teebow_options' );
add_settings_section( 'cta_settings', 'Change CTA button link', 'teebow_section_text', 'teebow_options_page' );
add_settings_field( 'teebow_button_link', 'Button link', 'teebow_button_link', 'teebow_options_page', 'cta_settings' );
}
add_action( 'admin_init', 'teebow_register_settings' );
function teebow_section_text() {
echo '<p>Welcome to my settings section</p>';
}
function teebow_button_link()
{
$option = get_option('teebow_options','default');
echo "<input id='teebow_button_link' name='teebow_options' type='text' value='".esc_attr($option)."' />";
}