Update (10th July 2010): Pippin has now converted this into a premium plugin which can be purchased from Code Canyon. If you’re not afraid to mess with your code a little though, read on for the DIY method!

WordPress theme option panels were a tremendous stride in the world of theme development; they gave site owner’s the ability to modify various aspects of their site, without ever having to touch the code. Every great theme either has or should have an extensive options panel.

In this tutorial, I’m going to demonstrate how to add a custom font uploader to your options panel. This will allow site owners to upload any number of font files and apply them to different sections of the site.

As a designer, I cringe a little at the thought of clients possibly screwing up my carefully selected fonts with their own haphazard selection, but, in the end, it’s what the client wants.

Before Starting

To begin, you first need to create your options panel. For this task, I recommend you follow Rohan Mehta‘s tutorial over on Net Tuts. It’s the best tutorial I’ve found on this topic and will provide you with almost everything you need for this tutorial.

#1 – The Essentials

The first thing we need to do is create a folder called fonts in our theme directory. Your Structure should look like this:

  • wp-content
    • themes
      • your_theme_folder
        • fonts

For security reasons, set the permissions of this folder to 774. This will allow the server to read, execute and write, while disallowing any public write / execute privileges.

You will also need to ensure you have a functions.php file, which, of course, you do because you’ve already followed the Net Tuts tutorial, or created an options page of your own ;-)

#2 – The Upload Script

In order to actually upload files, such as custom fonts, we need to create a php upload script.

Save this as upload.php in your theme folder (the same place we created the uploads folder):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?php
//include internal wordpress functions
require($_SERVER['DOCUMENT_ROOT'].'/wp-blog-header.php');
 
//define a maxim size for the uploaded files
define ("MAX_SIZE","20000000"); 
 
//This function reads the extension of the file. It is used to determine if the file  is an font by checking the extension.
function getExtension($str)
{
   $parts = explode('.', $str);
   return end($parts);
}
 
//This variable is used as a flag. The value is initialized with 0 (meaning no error  found)  
//and it will be changed to 1 if an errro occures.  
//If the error occures the file will not be uploaded.
 $errors=0;
//checks if the form has been submitted
 if(isset($_POST['Submit'])) 
 {
 	//reads the name of the file the user submitted for uploading
 	$font=$_FILES['font']['name'];
 	//if it is not empty
 	if ($font) 
 	{
	 	//get the original name of the file from the clients machine
	 		$filename = stripslashes($_FILES['font']['name']);
	 	//get the extension of the file in a lower case format
	  		$extension = getExtension($filename);
	 		$extension = strtolower($extension);
	 	//if it is not a known extension, we will suppose it is an error and will not upload the file,
	 	//we will only allow .ttf and .otf file extensions  
		//otherwise we will do more tests
		if (($extension != "ttf") && ($extension != "otf")) 
	 	{
			//print error message
	 		echo '<h1>Unknown extension!</h1>';
	 		$errors=1;
	 	}
	 	else
	 	{ 		
			//check the mimetypes against an allowed list
			$mime = array ("application/x-font-ttf", "application/vnd.oasis.opendocument.forumla-template", "application/octet-stream");
 
			if (!in_array($_FILES['font']['type'],$mime))
			{
		 		echo '<h1>Unknown mimetype!</h1>';
				$errors=1;
			}
			//get the size of the file in bytes
			//$_FILES['image']['tmp_name'] is the temporary filename of the file
			//in which the uploaded file was stored on the server
			$size=filesize($_FILES['font']['tmp_name']);
			//compare the size with the maxim size we defined and print error if bigger
			if ($size > MAX_SIZE)
			{
				echo '<h1>You have exceeded the size limit!</h1>';
				$errors=1;
			}
			//keep the original file name
			$font_name=$filename;
 
			if (!$errors)
			{
				//the new name will be containing the full path where fonts will be stored (fonts folder)
				$newname="fonts/".$font_name;
				//we verify if the image has been uploaded, and print error instead
				$copied = copy($_FILES['font']['tmp_name'], $newname);
				if (!$copied) 
				{
					echo '<h1>Copy unsuccessfull!</h1>';
					$errors=1;
				}
			}
		}
	}		
	//If no errors registred, redirect back to the theme options panel
	if(isset($_POST['Submit']) && !$errors) 
	{
	$url = get_bloginfo('url') . '/wp-admin/admin.php?page=functions.php';
 
	header ("Location: $url");
	}
 }
 ?>

For explanations of how this script works, read the embedded comments.

#3 – Embed the Upload Script

We now need to create the upload form in our options panel that will allow us to actually upload font files to the server.

Place this in your functions.php:

1
2
3
4
5
6
7
8
9
10
11
	<h2>Upload Fonts</h2>
	<p><em>Filetypes accepted: <strong>.ttf</strong> and <strong>.otf</strong></em></p>
	<p>Uploaded fonts will appear in the <strong>FONTS</strong> menu below</p>
	<form name="newad" method="post" enctype="multipart/form-data"  action="<?php bloginfo('template_directory');?>/upload.php">
	 <table>
	 	<tr>
	 		<td><input type="file" name="font"></td>
	 		<td><input name="Submit" type="submit" value="Upload"></td>
	 	</tr>
	 </table>	
	</form>

This code provides an interface to the upload.php that we created earlier, and it looks like this:

upload form

Important! In the Net Tuts tutorial, you created a section in functions.php that displays the theme options in a table based layout. The above code should be placed like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<div class="wrap rm_wrap">
    <h2><?php echo $themename; ?> Settings</h2>
    <div class="rm_opts">
 
        //upload form begins here
 
	<h2>Upload Fonts</h2>
	<p><em>Filetypes accepted: <strong>.ttf</strong> and <strong>.otf</strong></em></p>
	<p>Uploaded fonts will appear in the <strong>FONTS</strong> menu below</p>
	<form name="newad" method="post" enctype="multipart/form-data"  action="<?php bloginfo('template_directory');?>/upload.php">
	 <table>
	 	<tr>
	 		<td><input type="file" name="font"></td>
	 		<td><input name="Submit" type="submit" value="Upload"></td>
	 	</tr>
	 </table>	
	</form>
 
       //upload form ends here
 
 <form method="post">
 
<?php 
                foreach ($options as $value):
                    switch ( $value['type'] ):
                        case "open":
                            break;
 
                        case "close":
?>
. . .

If you do not place the upload form in the correct area, it will not show up in your theme options panel.

#4 – List the Available Fonts

We have created the ability to upload fonts and store them in a folder called fonts. Now we are going to create a function to list all of the available fonts inside our theme options panel.

Place this code in your functions.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$fontsList = array();
$fontDirectoryURL = $_SERVER['DOCUMENT_ROOT'] . get_bloginfo('template_directory') . '/fonts';
$removeSiteURL = get_bloginfo('url');
$fontDirectoryPath = str_replace($removeSiteURL, "", $fontDirectoryURL);
$fontURL = get_bloginfo('template_directory') . '/fonts';
$fontDir = opendir($fontDirectoryPath);
while(($font = readdir($fontDir)) !== false)
	{
		if($font != '.' && $font != '..' && !is_file($font) && $font != '.htaccess' && $font != 'resource.frk' && !eregi('^Icon',$font))
			{
				$fontList[] = $fontURL."/".$font;
			}
	}
closedir($fontDir);
array_unshift($fontList, "Choose a font");

just after

1
2
$themename = "Theme-Name";  
$shortname = "sn";

These two lines are created in the Net Tuts article.

This is a function that works like this:

  • create a url that will be used to access the font files in the CSS
  • open the font directory
  • read all files contained in the directory
  • exclude certain file names and directories
  • place all fonts found inside a list

#5 – Create the Font Options

Anywhere among the rest of your theme options created in the Net Tuts article, place this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    array( "name" => "Fonts",
        "type" => "section"),
    array( "type" => "open"),
 
	 array( "name" => "Headers",
		"desc" => "Choose a font",
		"id" => $shortname."_header_font",
		"type" => "select",
		"options" => $fontList),
 
	 array( "name" => "Navigation",
		"desc" => "Choose a font",
		"id" => $shortname."_nav_font",
		"type" => "select",
		"options" => $fontList),
 
	 array( "name" => "Main Body",
		"desc" => "Choose a font",
		"id" => $shortname."_body_font",
		"type" => "select",
		"options" => $fontList),
 
	 array( "name" => "Footer",
		"desc" => "Choose a font",
		"id" => $shortname."_footer_font",
		"type" => "select",
		"options" => $fontList),
 
    array( "type" => "close"),

#6 – The CSS Part One

We’re going to include the fonts in our header.php file so that we can apply them to the web elements.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<style type="text/css" media="screen">
@font-face {
  font-family: "header-font";
  src: url("<?php echo get_option('sn_header_font'); ?>");
}
@font-face {
  font-family: "nav-font";
  src: url("<?php echo get_option('sn_nav_font'); ?>");
}
@font-face {
  font-family: "body-font";
  src: url("<?php echo get_option('sn_body_font'); ?>");
}
@font-face {
  font-family: "footer-font";
  src: url("<?php echo get_option('sn_footer_font'); ?>");
}
</style>

Important! Do not forget to replace sn with your own theme’s short name.

#6 – The CSS Part Two

In your style.css file:

1
2
3
4
5
6
7
8
9
10
11
12
h1,h2,h3,h4,h5,h6,h7  {
  font-family: "header-font";
}
p  {
  font-family: "body-font";
}
.navigation  {
  font-family: "nav-font";
}
#footer p  {
  font-family: "footer-font";
}

That’s it! Your final outcome should look similar to this (unless you used your own theme options page rather than following Net Tuts’):

font uploader

#7 – Going Further

The system we’ve created works very well and is significantly better than any wordpress font plugin I’ve been able to find. Here are some suggestions for going a little further and making it even better:

  • Add jQuery and or Ajax to the upload form to prevent reloading of the page and to create cleaner error / success messages
  • Create options for more specific site elements, such as p tags with a class of “antique”, rather than just generic elements as I’ve done above.
  • Allow more font file types by adding their mime types and extensions to upload.php

Enjoy this post? You should follow me on Twitter!