
Creating themes to give away or sell is great, but not everyone who uses your theme will have a solid understanding of HTML/CSS. Providing your theme with an options page makes it easier for non-technical users to make theme changes without getting their hands dirty with code. I'll show you how to make one from scratch!
What We're Going to Achieve
Before we begin, what are we actually striving for? What are we going to make customizable about our theme? Well, this tutorial will focus mostly on the programmatic side, but in order to change something about the layout, we'll need to have a few design ideas up our sleeves, as well. Here's what we have:
- Change a theme's color scheme
- Add 2x advertising spots
- Optional sidebar
- Optional recent tweets panel
- Optional search box
There are plenty of editable elements we could add to a theme, but after today's tutorial which illustrates how to implement the five features listed above, you should have a good feel for how to create your own options page.
1. Creating the Required Files
We're going to concentrate entirely on the options page first before we start making the theme change. First, we need a place to put all of our code that's going to manage the options page. All this code is going to resides in a file called functions.php, which will go inside of our themes folder. So, if our theme is called 'example,' then the path to our functions file would be wp-content/themes/example/functions.php.
We don't need to tell WordPress to include our functions.php file, it's automatically called during the WordPress execution cycle.
2. Creating the Options Page
So first we need to actually create the blank options page - the canvas for our work. To do so, we must inform WordPress about the new options page that we wish to create. We accomplish this task by using actions. Actions are called at a specific time in WordPress' execution; so, for example, when the menu in the dashboard is being created, the action admin_menu is called. We can tie functions to these actions; so we can execute our functions at specific times. Here's the basic functions we need to create our options page.
1 |
|
2 |
<?php
|
3 |
// Options Page Functions
|
4 |
|
5 |
function themeoptions_admin_menu() |
6 |
{
|
7 |
// here's where we add our theme options page link to the dashboard sidebar
|
8 |
add_theme_page("Theme Options", "Theme Options", 'edit_themes', basename(__FILE__), 'themeoptions_page'); |
9 |
}
|
10 |
|
11 |
function themeoptions_page() |
12 |
{
|
13 |
// here is the main function that will generate our options page
|
14 |
}
|
15 |
|
16 |
add_action('admin_menu', 'themeoptions_admin_menu'); |
17 |
|
18 |
?>
|
Our first function, themeoptions_admin_menu is simply there to add a link to our page in the admin sidebar, it also tells WordPress what function to call to display the page which, in our case, is themeoptions_page().
The parameters for the add_theme_page() function are as follows:
- Page Title - Theme Options
- Menu Title - Theme Options
- Capability - edit_themes
- Handle - The current file
- Function - themeoptions_page()
If you have the theme activated, then, in the Themes drop down menu, you should see your new link to an options page which is currently blank. We now have the canvas for our options page, and we can begin implementing the forms, fields and back end of our options functionality.

3. Adding Options and Fields
Ok, so that page is looking a bit lonely; let's add the form and fields that the user will interact with to make changes to the theme. It's important to note you can style this page however you wish, even adding tabbed dialogs if you want; but for our tutorial, we're going to make use of the default classes used by WordPress. This way it saves us the time of reinventing the wheel, and makes our options page blend in with the rest of the dashboard.
The code for our page should reside in our themeoptions_page() function, so we're going to add our code in like this;
1 |
function themeoptions_page() |
2 |
{ |
3 |
// here's the main function that will generate our options page |
4 |
?> |
5 |
<div class="wrap"> |
6 |
<div id="icon-themes" class="icon32"><br /></div> |
7 |
<h2>Theme Options</h2> |
8 |
|
9 |
<form method="POST" action=""> |
10 |
<input type="hidden" name="update_themeoptions" value="true" /> |
11 |
|
12 |
<p><input type="submit" name="search" value="Update Options" class="button" /></p> |
13 |
</form>
|
14 |
|
15 |
</div>
|
16 |
<?php
|
17 |
}
|
First we create the predefined wrap class for the page. Then, we add a quick header with a default icon. Finally, our form; we need a hidden value so that we can check if it has been submitted. We also need a button that's going to submit the form, and, again, we use a predefined class for this. Here's what we have so far:

Now we have our basic structure. So if we check back to the beginning of this tutorial, we planned to implement five options.
- First of all, we're going to allow the theme users to change the color scheme. For this, we'll require a drop down list of color schemes available.
- Secondly, we'll have two advertising spots. We'll need two input fields for the image URLs, and two input fields for the links.
- Third is the optional sidebar: a simple check box.
- Fourth is the optional Twitter stream in the sidebar. We'll need a checkbox and an input field for the username.
- Finally we'll need an optional search box: another check box.
1 |
function themeoptions_page() |
2 |
{ |
3 |
// here's the main function that will generate our options page |
4 |
?> |
5 |
<div class="wrap"> |
6 |
<div id="icon-themes" class="icon32"><br /></div> |
7 |
<h2>Theme Options</h2> |
8 |
|
9 |
<form method="POST" action=""> |
10 |
<input type="hidden" name="update_themeoptions" value="true" /> |
11 |
|
12 |
<h4>Colour Stylesheet To Use</h4> |
13 |
<select name ="colour"> |
14 |
<option value="red">Red Stylesheet</option> |
15 |
<option value="green">Green Stylesheet</option> |
16 |
<option value="blue">Blue Stylesheet</option> |
17 |
</select>
|
18 |
|
19 |
<h4>Advertising Spot #1</h4> |
20 |
<p><input type="text" name="ad1image" id="ad1image" size="32" value=""/> Advert Image</p> |
21 |
<p><input type="text" name="ad1url" id="ad1url" size="32" value=""/> Advert Link</p> |
22 |
|
23 |
<h4>Advertising Spot #2</h4> |
24 |
<p><input type="text" name="ad2image" id="ad2image" size="32" value=""/> Advert Image</p> |
25 |
<p><input type="text" name="ad2url" id="ad2url" size="32" value=""/> Advert Link</p> |
26 |
|
27 |
<h4><input type="checkbox" name="display_sidebar" id="display_sidebar" /> Display Sidebar</h4> |
28 |
|
29 |
<h4><input type="checkbox" name="display_search" id="display_search" /> Display Search Box</h4> |
30 |
|
31 |
<h4><input type="checkbox" name="display_twitter" id="display_twitter" /> Display Twitter Stream</h4> |
32 |
<p><input type="text" name="twitter_username" id="twitter_username" size="32" value="" /> Twitter Username</p> |
33 |
|
34 |
<p><input type="submit" name="search" value="Update Options" class="button" /></p> |
35 |
</form>
|
36 |
|
37 |
</div>
|
38 |
<?php
|
39 |
}
|

4. Updating The Database
So far, we have an options page with a form that submits data to itself, via POST. The next logical step is to take the data submitted, and insert it into the WordPress database. To do so, we're going to create a new function called themeoptions_update(). This function will be called by themeoptions_page(); so add this code to the very top of themeoptions_page();
1 |
if ( $_POST['update_themeoptions'] == 'true' ) { themeoptions_update(); } |
Of course, the next step is to create the update function. Remember, for the sake of this tutorial, I'm not adding validation or sanitization to my code. When creating a plugin, you should always check the input from your users. However it's beyond the scope of this tutorial. Now you could rely on WordPress to validate your input, but it's best to do so yourself, to make sure.
Anywhere in the functions.php file, add this block of code:
1 |
function themeoptions_update() |
2 |
{
|
3 |
// this is where validation would go
|
4 |
update_option('mytheme_colour', $_POST['colour']); |
5 |
|
6 |
update_option('mytheme_ad1image', $_POST['ad1image']); |
7 |
update_option('mytheme_ad1url', $_POST['ad1url']); |
8 |
|
9 |
update_option('mytheme_ad2image', $_POST['ad2image']); |
10 |
update_option('mytheme_ad2url', $_POST['ad2url']); |
11 |
|
12 |
if ($_POST['display_sidebar']=='on') { $display = 'checked'; } else { $display = ''; } |
13 |
update_option('mytheme_display_sidebar', $display); |
14 |
|
15 |
if ($_POST['display_search']=='on') { $display = 'checked'; } else { $display = ''; } |
16 |
update_option('mytheme_display_search', $display); |
17 |
|
18 |
if ($_POST['display_twitter']=='on') { $display = 'checked'; } else { $display = ''; } |
19 |
update_option('mytheme_display_twitter', $display); |
20 |
|
21 |
update_option('mytheme_twitter_username', $_POST['twitter_username']); |
22 |
}
|
The update function, as the name suggests, updates an option you can store in the database. If the option doesn't exist, then WordPress creates it. We've prepended all our options with mytheme_, just to make sure we don't overwrite options that another plugin/theme might be using.
So far, we have a settings page that can save our options, however, when we hit submit, and our options are stored, our form is blank when we re-visit it. This is because we need to load our values back from the database.
5. Fetching Options
We now need to fetch our options so that we can populate the settings form. This is an easy one, and we'll do it by using the get_option() function. We could use variables, but for this example, we'll simply echo the output of the function where it should go in the form. Our new code looks like this;
1 |
function themeoptions_page() |
2 |
{
|
3 |
// here's the main function that will generate our options page
|
4 |
|
5 |
if ( $_POST['update_themeoptions'] == 'true' ) { themeoptions_update(); } |
6 |
|
7 |
//if ( get_option() == "checked"
|
8 |
|
9 |
?>
|
10 |
<div class="wrap"> |
11 |
<div id="icon-themes" class="icon32"><br /></div> |
12 |
<h2>Theme Options</h2> |
13 |
|
14 |
<form method="POST" action=""> |
15 |
<input type="hidden" name="update_themeoptions" value="true" /> |
16 |
|
17 |
<h4>Colour Stylesheet To Use</h4> |
18 |
<select name ="colour"> |
19 |
<?php $colour = get_option('mytheme_colour'); ?> |
20 |
<option value="red" <?php if ($colour=='red') { echo 'selected'; } ?> >Red Stylesheet</option> |
21 |
<option value="green" <?php if ($colour=='green') { echo 'selected'; } ?>>Green Stylesheet</option> |
22 |
<option value="blue" <?php if ($colour=='blue') { echo 'selected'; } ?>>Blue Stylesheet</option> |
23 |
</select>
|
24 |
|
25 |
<h4>Advertising Spot #1</h4> |
26 |
<p><input type="text" name="ad1image" id="ad1image" size="32" value="<?php echo get_option('mytheme_ad1image'); ?>"/> Advert Image</p> |
27 |
<p><input type="text" name="ad1url" id="ad1url" size="32" value="<?php echo get_option('mytheme_ad1url'); ?>"/> Advert Link</p> |
28 |
|
29 |
<h4>Advertising Spot #2</h4> |
30 |
<p><input type="text" name="ad2image" id="ad2image" size="32" value="<?php echo get_option('mytheme_ad2image'); ?>"/> Advert Image</p> |
31 |
<p><input type="text" name="ad2url" id="ad2url" size="32" value="<?php echo get_option('mytheme_ad2url'); ?>"/> Advert Link</p> |
32 |
|
33 |
<h4><input type="checkbox" name="display_sidebar" id="display_sidebar" <?php echo get_option('mytheme_display_sidebar'); ?> /> Display Sidebar</h4> |
34 |
|
35 |
<h4><input type="checkbox" name="display_search" id="display_search" <?php echo get_option('mytheme_display_search'); ?> /> Display Search Box</h4> |
36 |
|
37 |
<h4><input type="checkbox" name="display_twitter" id="display_twitter" <?php echo get_option('mytheme_display_twitter'); ?> /> Display Twitter Stream</h4> |
38 |
<p><input type="text" name="twitter_username" id="twitter_username" size="32" value="<?php echo get_option('mytheme_twitter_username'); ?>" /> Twitter Username</p> |
39 |
|
40 |
<p><input type="submit" name="search" value="Update Options" class="button" /></p> |
41 |
</form>
|
42 |
|
43 |
</div>
|
44 |
<?php
|
45 |
}
|
So there you have it. The back end has now been completed. We're able to update our options in the database, so all that's left to do is make the theme react to these changes in the options page. This works similarly to how we updated the options fields: we fetch the option and then either display it or use it as a conditional to do something else. Let's get started with the front end.
6. Changing the Theme
Changing the Colour Scheme
This is going to deal with CSS and such, which isn't what this tutorial is about. So we'll skim over how you'd approach this. One of the best ways to go about this is to have a default stylesheet that uses a colour scheme such as black, then a series of alternative colour schemes. For example style.css could style your layout black, but including red.css AFTER including style.css.
A helpful CSS tip is to use the !important tag. Use this tag in the stylesheets that change colours of the layout to ensure that those properties will, in fact, be used. In order to actually switch the stylesheets, add this code to the header.php file of your layout where the stylesheet would be included:
1 |
<link rel="stylesheet" href="<?php bloginfo('stylesheet_directory'); ?>/default.css" type="text/css"> |
2 |
<link rel="stylesheet" href="<?php bloginfo('stylesheet_directory'); ?>/<?php echo get_option('mytheme_colour'); ?>.css" type="text/css"> |
Adding advertising spots
This section is meant to show you the theory. In real life, you'd probably use a plugin or something like "Buy Sell Ads." So say we've got two spots for our adverts to go in. Similar to above, we simply output the option where it needs to go, like so:
1 |
<a href="<?php echo get_option('mytheme_ad1url'); ?>"><img src="<?php echo get_option('mytheme_ad1image'); ?>" height="125" width="125" /></a> |
2 |
<a href="<?php echo get_option('mytheme_ad2url'); ?>"><img src="<?php echo get_option('mytheme_ad2image'); ?>" height="125" width="125" /></a> |
Optional Sidebar
This time, we'll use the option as a conditional to decide whether or not we should output a block of code, that in this case would display a sidebar. Of course, your layout should be able to still display properly if a sidebar is not visible; so that one is up to you. The following code will be added wherever you'd usually call your sidebar, usually mine is called from header.php.
1 |
if ( get_option('mytheme_display_sidebar') == 'checked') { get_sidebar(); } |
2 |
|
3 |
// or alternatively...
|
4 |
if ( get_option('mytheme_display_sidebar') == 'checked') { get_sidebar(); } else { /* display something else */ } |
Optional Recent Tweets
For this little option, we'll need to do two things. If tweets are enabled we'll first need to display the area where the tweets should appear, we'll also need to insert a block of JavaScript before the </body> tag to get the tweets from a specific user.
We need to place the following where we actually want the tweets to appear:
1 |
<?php if (get_option('mytheme_display_twitter') ) { ?> |
2 |
<div id="twitter_div"> |
3 |
<ul id="twitter_update_list"></ul> |
4 |
</div>
|
5 |
<?php } ?> |
Next we need to place this code before the </body> tag, which most probably resides in footer.php;
1 |
<script src="https://twitter.com/javascripts/blogger.js"></script> |
2 |
<script src="http://twitter.com/statuses/user_timeline/<?php echo get_option('mytheme_twitter_username'); ?>.json?callback=twitterCallback2&count=5"></script> |
Tip: why not try and add your own option to change how many tweets are fetched above?
Optional Search Box
Finally, we come to our optional search box, which functions just as our sidebar did. We use the option as a conditional and display code dependent on the user's choice.
1 |
if ( get_option('mytheme_display_search') == 'checked') { ?> |
2 |
<form role="search" method="get" id="searchform" action="" > |
3 |
<input type="text" value="" name="s" id="s" /> |
4 |
</form>
|
5 |
<?php } |
Wrapping Up
I hope you've learned the basics of how to create an options page for your theme, and make it function properly. I've tried to skip a few of the tedious bits, like the actual CSS and the validation that should be in place, primarily because it was outside of the scope of this tutorial.
As usual, if you have any questions at all, leave a comment below! Thanks for reading!