Throughout this six-part beginner-to-master series, we'll be using the advanced features of WordPress to create our own portfolio & blog, complete with an options page, multiple styles and support for the new WordPress 2.7 features.
In day one, we're handling the preparation and admin sections by creating our Options page.
Also available in this series:
- WordPress: Beginner to Master, Part 1
- WordPress: Beginner to Master, Part 2
- WordPress: Beginner to Master, Part 3
- WordPress: Beginner to Master, Part 4
- WordPress: Beginner to Master, Part 5
- WordPress: Beginner to Master, Part 6
Overview
By the end of this series, we will have created Innovation – a premium-quality WordPress template perfect for showcasing a portfolio and hosting a blog; complete with the following features:
- Options page for handling the advanced nature of the template, without having to edit any files manually.
- 3 built-in colour schemes – with easy switching between them.
- Homepage and Portfolio page templates, with a widget-ready footer and sidebar.
- Compatibility with WordPress 2.5+.
- Threaded & paged comments support for WordPress 2.7.
- A custom widget for displaying your latest posts, with a preview image, on your homepage.
The theme will come with three styles built-in, DeepBlue, RedSpace and SoftLight, but you will be able to easily add your own colour schemes:









The plan for each day:
- Preparation & Admin Options page.
- Homepage layout. Creating a custom WordPress loop. Using widget areas. Footer.
- Blog posts loop. Sidebar. Single blog layout.
- Portfolio page. Seperating 'single' pages dependant on category. Single portfolio page.
- Comments layout. Archives. Search.
- Face lift – the 'RedSpace' alternative colour scheme. Creating a custom widget.
What previous experience do I need?
Experience with xHTML & CSS is a must (as I won't go over much of this code in detail).
It would also be very useful to have some basic understanding of PHP (such as using variables, arrays, conditional statements and 'foreach' and 'while' loops. Check out Jeffrey's excellent "Diving into PHP" screencast series.
Having some knowledge of WordPress (even just knowing your way around the Dashboard!) would definitely improve your experience. Check out Drew's "WordPress for Designers" screencast series.
Jump to a Section
- Getting Started
- — Preparing Files
- — Categories & Pages
- — Make WordPress a CMS
- Options Page
- — Categories Drop-down
- — Pages Drop-down
- — Stylesheet Drop-down
- — The Options Array
- — Options Back-end
- Retrieving the Options
- Summary
Getting Started
Today, we will be handling the core back-end code which the rest of theme will rely upon. You will first need a fresh install of WordPress, preferably the latest version (2.7 at time of writing); however the template will work with any version above 2.5. Inside the /wp-content/themes/
folder, create new folders and files with the following structure:
-
/innovation/
-
/styles/
/deepblue/
deepblue.css
functions.php
index.php
page.php
page-home.php
page-portfolio.php
style.css
var.php
-
functions.php
will contain code for our options page and widgets amongst other things.
index.php
is used for displaying latest posts.
page.php
will the template used for most single pages.
page-home.php
will be our frontpage template.
page-portfolio.php
will be our portfolio page.
var.php
will be used to retrieve our options from the database.
style.css
will contain most of our styling.
/styles/deepblue.css
will contain the styling for our first colour-scheme.
These aren't all the files we will need. We'll create the others as we go along so that you can understand what each is for.
Preparing Files
The two page-
files are custom page templates, so that we can lay content out differently on pages assigned these templates. For WordPress to recognize them, inside page-home.php
enter the following:
1 |
|
2 |
<?php
|
3 |
/*
|
4 |
Template Name: Homepage
|
5 |
*/
|
6 |
|
7 |
get_header(); ?> |
Similarly, inside page-portfolio.php
enter:
1 |
|
2 |
<?php
|
3 |
/*
|
4 |
Template Name: Portfolio
|
5 |
*/
|
6 |
|
7 |
get_header(); ?> |
The Template Name is the name used by WordPress when selecting a page template. get_header();
is a WordPress function to load the header.php
file (which we'll create later).
And add the following to page.php
. We don't need to give this file a template name, as it is the default template.
1 |
|
2 |
<?php
|
3 |
get_header(); ?> |
We also need to assign some details such as name, description and author for our theme. This is done in a comment block at the top of style.css
:
1 |
|
2 |
/*
|
3 |
Theme Name: Innovation
|
4 |
Theme URI: https://www.danharper.me/innovation
|
5 |
Description: An advanced portfolio & blog theme built by Dan Harper as part of a tutorial series for NETTUTS.com
|
6 |
Version: 1.0
|
7 |
Author: Dan Harper
|
8 |
Author URI: http://www.danharper.me
|
9 |
*/
|
Categories & Pages
To save time later, we will create the relevant categories & pages we will need now. In your WordPress dashboard, activate the theme (it will be using the name we defined in the CSS previously) - don't worry that the theme is empty, we're moving to that later.



Now create three new Pages. One named 'Home', and the other 'Portfolio'. Select the Page Template for each of them as 'Homepage' and 'Portfolio' respectively. Name the final page 'Blog' and use the default page template.



Also create a new category named 'Portfolio'. This is what we will use to post portfolio items in.



Make WordPress a CMS
From your Dashboard, go to Settings -> Reading. For 'Front Page Display' set Front page to the 'Home' page you created, and Posts page to 'Blog':



Options Page
This is probably going to seem a little backwards, but we are going to create an options page for our theme before we do any work on the actual front-end. This is because the entire theme depends upon the options on the page, and it wouldn't make sense to do those other parts first.
For those who don't know, the options page is an extra page in the WordPress Dashboard we are adding which holds a number of options for our theme. These are:
- Colour Scheme
- Portfolio Category
- Blog Page
- Google Analytics code



Inside functions.php
start with the following. The $themename
variable defines the name of the theme which will be used for the page's title in the Dashboard (Innovation). And $shortname
is used to make our options unique - if you change this, you will have to change several instances throughout the code (so don't change it ;)).
1 |
|
2 |
<?php
|
3 |
$themename = "Innovation"; |
4 |
$shortname = "ts"; |
Categories Drop-Down
Next we will create the code which gets all the categories for us to use in the 'Portfolio' drop-down option:
1 |
|
2 |
/* Get Categories into a drop-down list */
|
3 |
$categories_list = get_categories('hide_empty=0&orderby=name'); |
4 |
$getcat = array(); |
5 |
foreach($categories_list as $acategory) { |
6 |
$getcat[$acategory->cat_ID] = $acategory->cat_name; |
7 |
}
|
8 |
$category_dropdown = array_unshift($getcat, "Choose a category:"); |
This code uses WordPress' get_categories();
function to retrieve a list of all the category names, and using a foreach();
loop to add each name & ID into an array named $getcat
for use later in the code. Finally, we use array_unshift
to insert "Choose a category:" at the top of the array.
Pages Drop-Down
Next is another similar drop-down option which selects a page name. The code for this is very similar to the previous one:
1 |
|
2 |
/* Get Pages into a drop-down list */
|
3 |
$pages_list = get_pages(); |
4 |
$getpag = array(); |
5 |
foreach($pages_list as $apage) { |
6 |
$getpag[$apage->ID] = $apage->post_title; |
7 |
}
|
8 |
$page_dropdown = array_unshift($getpag, "Select a page:"); |
Like getting the categories, we are using WordPress' get_pages();
function to get a list of all the page names, and the result is placed into the $getpag
array for use later.
Stylesheet Drop-Down
There is also a drop-down option for selecting a stylesheet. This code is a little more complicated:
1 |
|
2 |
/* Get Stylesheets into a drop-down list */
|
3 |
$styles = array(); |
4 |
if(is_dir(TEMPLATEPATH . "/styles/")) { |
5 |
if($open_dirs = opendir(TEMPLATEPATH . "/styles/")) { |
6 |
while(($style = readdir($open_dirs)) !== false) { |
7 |
if(stristr($style, ".css") !== false) { |
8 |
$styles[] = $style; |
9 |
}
|
10 |
}
|
11 |
}
|
12 |
}
|
13 |
$style_dropdown = array_unshift($styles, "Choose a colour scheme:"); |
The above code uses the PHP opendir();
function, followed by readdir();
to open our /styles/
folder and get a list of all the files in there.
We then use stristr();
to limit the list to only the .css
files (to stop the folders from being outputted aswell), and the results are passed into the $styles
array.
The Options Array
All our options will be stored in their own arrays so that we can mass-process them later in the code:
1 |
|
2 |
/* The Options*/
|
3 |
$options = array ( |
4 |
|
5 |
array( "name" => "General", |
6 |
"type" => "title"), |
7 |
|
8 |
array( "type" => "open"), |
9 |
|
10 |
array( "name" => "Colour Scheme", |
11 |
"desc" => "Which colour scheme would you like?", |
12 |
"id" => $shortname."_colourscheme", |
13 |
"type" => "select", |
14 |
"std" => "Choose a colour scheme:", |
15 |
"options" => $styles), |
16 |
|
17 |
array( "name" => "Portfolio Category", |
18 |
"desc" => "Select the category portfolio items are being posted in.", |
19 |
"id" => $shortname."_portfolio_cat", |
20 |
"type" => "select", |
21 |
"std" => "Choose a category:", |
22 |
"options" => $getcat), |
23 |
|
24 |
array( "name" => "Blog page", |
25 |
"desc" => "Select the page used as a blog (posts) page.", |
26 |
"id" => $shortname."_blogpage", |
27 |
"type" => "select", |
28 |
"std" => "Select a page:", |
29 |
"options" => $getpag), |
30 |
|
31 |
array( "name" => "Google Analytics", |
32 |
"desc" => "Insert your Google Analytics (or other) code here.", |
33 |
"id" => $shortname."_analytics_code", |
34 |
"type" => "textarea"), |
35 |
|
36 |
array( "type" => "close") |
37 |
|
38 |
);
|
Each array is one option, and contains name
, desc
, id
and type
parameters. The ID is very important, and is what we'll be using to reference the option later in the code. For example, to get the Portfolio Category, we would check the $ts_portfolio_cat
(ts is the shortname we referenced at the top of the document.)
Options Back-end
The following code makes our options page appear in the Dashboard (it's under "Design" in WordPress 2.6 or below), and saves the options into the database.



1 |
|
2 |
function mytheme_add_admin() { |
3 |
global $themename, $shortname, $options; |
4 |
if ( $_GET['page'] == basename(__FILE__) ) { |
5 |
if ( 'save' == $_REQUEST['action'] ) { |
6 |
foreach ($options as $value) { |
7 |
update_option( $value['id'], $_REQUEST[ $value['id'] ] ); } |
8 |
foreach ($options as $value) { |
9 |
if( isset( $_REQUEST[ $value['id'] ] ) ) { update_option( $value['id'], $_REQUEST[ $value['id'] ] ); } else { delete_option( $value['id'] ); } } |
10 |
header("Location: themes.php?page=functions.php&saved=true"); |
11 |
die; |
12 |
} else if( 'reset' == $_REQUEST['action'] ) { |
13 |
foreach ($options as $value) { |
14 |
delete_option( $value['id'] ); } |
15 |
header("Location: themes.php?page=functions.php&reset=true"); |
16 |
die; |
17 |
}
|
18 |
}
|
19 |
if(!function_exists('wp_list_comments')) { |
20 |
add_theme_page($themename." Options", $themename, 'edit_themes', basename(__FILE__), 'mytheme_admin'); |
21 |
} else { |
22 |
add_menu_page($themename." Options", $themename, 'edit_themes', basename(__FILE__), 'mytheme_admin'); |
23 |
}
|
24 |
}
|
25 |
function mytheme_admin() { |
26 |
global $themename, $shortname, $options; |
27 |
if ( $_REQUEST['saved'] ) echo '<div id="message" class="updated fade"><p><strong>'.$themename.' settings saved.</strong></p></div>'; |
28 |
if ( $_REQUEST['reset'] ) echo '<div id="message" class="updated fade"><p><strong>'.$themename.' settings reset.</strong></p></div>'; |
29 |
?>
|
30 |
<div class="wrap"> |
31 |
<hr /> |
32 |
<h2><?php echo $themename; ?> settings</h2> |
33 |
<form method="post"> |
We're not going to go through the code as it would take this tutorial off-track too much. Just copy & paste it and think of it as some magic code from the WordPress Gods which makes your theme work.
This next code checks each of our options for their type
attribute, and styles them into a table. So options with "type" => "select"
would output as a drop-down box, or "type" => "textarea"
would output as a textarea.
1 |
|
2 |
<?php foreach ($options as $value) { |
3 |
switch ( $value['type'] ) { |
4 |
|
5 |
case "open": ?> |
6 |
<table width="100%" border="0" style="background-color:#F1F1F1; border:1px solid #E3E3E3; border-top:none; padding:10px;"><?php |
7 |
|
8 |
break; |
9 |
case "close": |
10 |
?>
|
11 |
</table><br /><?php |
12 |
|
13 |
break; |
14 |
case "title": |
15 |
?>
|
16 |
<table width="100%" border="0" style="background-color:#6D6D6D; border: 1px solid #E3E3E3; padding:5px 10px;"> |
17 |
<tr>
|
18 |
<td colspan="2"> |
19 |
<h3 style="color:#fff; font-family:Georgia,'Times New Roman',Times,serif; font-weight: bold;"><?php echo $value['name']; ?></h3> |
20 |
</td>
|
21 |
</tr>
|
22 |
</table><?php |
23 |
|
24 |
break; |
25 |
case 'text': |
26 |
?>
|
27 |
<tr>
|
28 |
<td width="20%" rowspan="2" valign="middle"><strong><?php echo $value['name']; ?></strong></td> |
29 |
<td width="80%"><input style="width:400px;" name="<?php echo $value['id']; ?>" id="<?php echo $value['id']; ?>" type="<?php echo $value['type']; ?>" value="<?php if ( get_settings( $value['id'] ) != "") { echo get_settings( $value['id'] ); } else { echo $value['std']; } ?>" /></td> |
30 |
</tr>
|
31 |
<tr>
|
32 |
<td><small><?php echo $value['desc']; ?></small></td> |
33 |
</tr><tr><td colspan="2" style="margin-bottom:5px;border-bottom:1px dotted #C8C8C8;"> </td></tr><tr><td colspan="2"> </td></tr> |
34 |
<?php
|
35 |
|
36 |
break; |
37 |
case 'textarea': |
38 |
?>
|
39 |
<tr>
|
40 |
<td width="20%" rowspan="2" valign="middle"><strong><?php echo $value['name']; ?></strong></td> |
41 |
<td width="80%"><textarea name="<?php echo $value['id']; ?>" style="width:400px; height:200px;" type="<?php echo $value['type']; ?>" cols="" rows=""><?php if ( get_settings( $value['id'] ) != "") { echo stripslashes(get_settings( $value['id'] )); } else { echo $value['std']; } ?></textarea></td> |
42 |
</tr>
|
43 |
<tr>
|
44 |
<td><small><?php echo $value['desc']; ?></small></td> |
45 |
</tr><tr><td colspan="2" style="margin-bottom:5px;border-bottom:1px dotted #C8C8C8;"> </td></tr><tr><td colspan="2"> </td></tr> |
46 |
<?php
|
47 |
|
48 |
break; |
49 |
case 'select': |
50 |
?>
|
51 |
<tr>
|
52 |
<td width="20%" rowspan="2" valign="middle"><strong><?php echo $value['name']; ?></strong></td> |
53 |
<td width="80%"><select style="width:240px;" name="<?php echo $value['id']; ?>" id="<?php echo $value['id']; ?>"><?php foreach ($value['options'] as $option) { ?><option<?php if ( get_settings( $value['id'] ) == $option) { echo ' selected="selected"'; } elseif ($option == $value['std']) { echo ' selected="selected"'; } ?>><?php echo $option; ?></option><?php } ?></select></td> |
54 |
</tr>
|
55 |
<tr>
|
56 |
<td><small><?php echo $value['desc']; ?></small></td> |
57 |
</tr><tr><td colspan="2" style="margin-bottom:5px;border-bottom:1px dotted #C8C8C8;"> </td></tr><tr><td colspan="2"> </td></tr> |
58 |
<?php
|
59 |
|
60 |
break; |
61 |
case "checkbox": |
62 |
?>
|
63 |
<tr>
|
64 |
<td width="20%" rowspan="2" valign="middle"><strong><?php echo $value['name']; ?></strong></td> |
65 |
<td width="80%"><? if(get_settings($value['id'])){ $checked = "checked=\"checked\""; }else{ $checked = ""; } ?> |
66 |
<input type="checkbox" name="<?php echo $value['id']; ?>" id="<?php echo $value['id']; ?>" value="true" <?php echo $checked; ?> /> |
67 |
</td>
|
68 |
</tr>
|
69 |
<tr>
|
70 |
<td><small><?php echo $value['desc']; ?></small></td> |
71 |
</tr><tr><td colspan="2" style="margin-bottom:5px;border-bottom:1px dotted #C8C8C8;"> </td></tr><tr><td colspan="2"> </td></tr> |
72 |
<?php
|
73 |
|
74 |
break; |
75 |
}
|
76 |
}
|
77 |
?>
|
78 |
<p class="submit"> |
79 |
<input name="save" type="submit" value="Save changes" /> |
80 |
<input type="hidden" name="action" value="save" /> |
81 |
</p>
|
82 |
</form>
|
83 |
<form method="post"> |
84 |
<p class="submit"> |
85 |
<input name="reset" type="submit" value="Reset" /> |
86 |
<input type="hidden" name="action" value="reset" /> |
87 |
</p>
|
88 |
</form>
|
89 |
<?php
|
90 |
}
|
91 |
add_action('admin_menu', 'mytheme_add_admin'); |
Finally, at the end of the file, insert:
1 |
|
2 |
require(TEMPLATEPATH . "/var.php"); |
We require()
our var.php
file which will contain code for retrieving our options.
Note that we have to use TEMPLATEPATH
in require()
or include()
tags so that it is browsing to our theme directory, and not the root WordPress directory.
Retrieving These Options
Now those options are in the Dashboard, we need to be able to use them in our theme. Insert the following code into var.php
:
1 |
|
2 |
<?php
|
3 |
|
4 |
/* Get all our options from the database */
|
5 |
global $options; |
6 |
foreach ($options as $value) { |
7 |
if (get_settings( $value['id'] ) === FALSE) { $$value['id'] = $value['std']; |
8 |
} else { $$value['id'] = get_settings( $value['id'] ); } |
9 |
}
|
10 |
|
11 |
/* Get Portfolio category ID from the name */
|
12 |
$ts_portfolio_cat = $wpdb->get_var("SELECT term_id FROM $wpdb->terms " |
13 |
."WHERE name='$ts_portfolio_cat'"); |
14 |
|
15 |
/* Get Blog page ID from the name */
|
16 |
$ts_blogpage = $wpdb->get_var("SELECT `ID` FROM $wpdb->posts " |
17 |
."WHERE post_title='$ts_blogpage' AND post_type='page' LIMIT 1"); |
18 |
|
19 |
?>
|
The first section of the code retrieves all our options from the database. However we have a problem: our Category & Page options send back the name of the category or page - but we'd prefer the ID as it's easier to use in WordPress functions.
The next two parts of the code do exactly that. We run a SQL query to get the appropriate ID. These options are now stored in the $ts_portfolio_cat
and $ts_blogpage
variables.
Now we have the admin side finished, login to your Dashboard, and set the appropriate settings for each of the options. Choose deepblue.css
for the colour-scheme for now.



Summary
That concludes Day 1 of WordPress Week. Tomorrow, we'll be creating our homepage layout, making a custom 'WordPress Loop' and handeling widget areas.