16 January 2010 ~ 1 Comment

PSD template to Wordpress Theme from Scratch

Clean & Detailed PSD template to Wordpress Theme from Scratch

In this tutorial I’ll guide you in the process to transform a PhotoshopTM PSD template to a complete XHTML and CSS site build. In the process you will learn how to slice the PSD, how to reproduce some photoshop layer styles using CSS3 and how to easily implement CSS sprites. You will not find any cross browser hacks or tricks because, this topic would require a complete tutorial by itself and this is not the purpose of this tutorial.

Final image result

Final Image Result

Wordpress Setup

In order to have a complete preview of what can go into a Wordpress blog I use a resource from wpcandy.com: Easier Theme Development with Sample Wordpress Content this archive contains a complete dummy content like blockquotes, lists, and floating images that are common to blogs and that need to be supported in every theme you release.

Simply download and extract the archive then go to the Wordpress Dashboard and Tools > Import choose «Wordpress» and upload the extracted «posts.xml» file.

We now have a solid content base that will prevent us to omit something in our CSS/XHTML design process so we can now focus on slicing and theming our new Wordpress blog!

Starting from default Wordpress theme

A common usage if you do not already made a subsequent amount of Wordpress themes is to start from the default one, Kubrick. First thing to do is to clear the style.css and insert the well known CSS reset by Eric Meyer.

You should obtain something very similar to this as a result:
CSS Reset

Do you notice the background image still visible in our reseted layout ? The Kubrick theme inserts this CSS at runtime after a sidebar detection. Let’s remove it. Open the file «/wordpress/wp-content/themes/default/header.php» and remove the inline style block mentioning the #page id.
It should looks like this :

<style type="text/css" media="screen">

<?php
// Checks to see whether it needs a sidebar or not
if ( empty($withcomments) &amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp; !is_single() ) {
?>
#page { background: url("<?php bloginfo('stylesheet_directory'); ?>/images/kubrickbg-<?php bloginfo('text_direction'); ?>.jpg") repeat-y top; border: none; }
<?php } else { // No sidebar ?>
#page { background: url("<?php bloginfo('stylesheet_directory'); ?>/images/kubrickbgwide.jpg") repeat-y top; border: none; }
<?php } ?>

</style>

Remove this block and as well as the «rtl.css» and «screenshot.png» files and everything in «images/», I will not cover the Right To Left implementation in this tutorial and we will replace the screenshot at the very end.

Main zones analysis

Here are the top level zones identified in our Photoshop template :
Identified zones

To build a theme we need to first define the zones we will implement, starting by large containers, slowly focusing on smaller elements. Here are the first elements I identified.

Our theme features by default the following top level elements: #header, #content, #sidebar and #footer all contained in the main wrapper: #page

That’s almost complete, but our layout features a navigation bar. We will have to add a CSS hook for this one, open up «/wordpress/wp-content/themes/default/header.php» in your favorite editor if you closed it and add the following code a the end of file.

<div id="wrapper">

<div id="navigation">
<ul class="left">
<li<?php if(is_home() &amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp; !is_paged()) echo ' class="current_item"'; ?>>
<a href="<?php bloginfo('url'); ?>"><?php _e('Home'); ?></a>
</li>
<?php wp_list_pages('title_li=&amp;amp;amp;amp;amp;amp;depth=2'); ?>
</ul>
</div>

Then in «/wordpress/wp-content/themes/default/footer.php», just after the hr tag, close the wrapper div:

<?php
/**
* @package Wordpress
* @subpackage Default_Theme
*/
?>

<hr />
</div>

Basically, we added the list of the top level pages in an unordered list and wrapped our everything except the header and footer in a div.

The first conditional block just displays a «Home» link and optionally apply it a class if we are on the frontpage or in a paged navigation.
Our Wordpress template should now looks like this in a browser:
Adding Navigation Hook

PSD Slicing

Start by isolating the top header background image.

Header Background Isolation

Save the slice for web & device as «/wordpress/wp-content/themes/default/images/header-bg.png»
using png-24 (lesser size in this case) then start Firebug (F12).
Using the DOM Inspector tool (Firebug DOM Inspector tool),
select the header zone (id=header).

Header Selection

Once the node selected, right click (ctrl+click on Macintosh) in the «Style» tab on the right
firebug panel and choose «Edit Element Style …».

Header Edition

You can now preview all CSS changes you make in live.

Enter the following directives :

background: transparent url(images/header-bg.png) repeat-x scroll 0 0;
height:116px;

Once done and satisfied with the result, save the generated CSS into our theme main stylesheets document: «/wordpress/wp-content/themes/default/style.css»

#header {
background: transparent url(images/header-bg.png) repeat-x scroll 0 0;
height:116px;
}

Back to Photoshop, hide all groups except for the background and create a new horizontal guide at 116px
(if not already exists) and grab a selection from this guide to just under the background gradient

Background Selection

Enter the following directives in your «style.css» file:

body {
background: #663300 url(images/bg.jpg) no-repeat scroll center 116px;
font-family:"Myriad Pro", helvetica, arial, sans-serif;
line-height:1.7em;
}

Then build the footer like you did for the header :

Footer Selection

Then, style it :

#footer {
background: transparent url(images/footer-bg.png) repeat-x scroll 0 0;
height:295px;
clear:both;
}

And style the wrapper div and the common elements while you’re at it:

#wrapper {
margin: 0 auto;
width:970px;
}

a {
color:#FFFFFF;
text-decoration:none;
}

Navigation

The default Wordpress content we used to seed our favorite blogging engine features hierarchized pages. This is an unique occasion for us to style and add some fancy drop down menu with jQuery.

For a start the styling is not rocket science :


/* Prevents blocks to hang side by side */
#content {
clear:both;
}

#navigation li
{
display:block;
float:left;
line-height:35px;
min-width:100px;
text-align:center;
position:relative;
padding-left:5px;
padding-right:5px;
height:33px;
background:transparent url(images/navigation-separator.png) no-repeat scroll 0 0;
}

/* Hiding sub menu items */
#navigation li ul {
display:none;
}

To slice our navigation background images we must, hide all groups except for Navigation one. Start with the left part of the navigation bar:

Navigation Slicing

Once saved, transform the selection in order to make a narrow selection, that will be the main navigation background.

Navigation Slicing

That done you can now slice the tab separator then style the navigation elements:

#navigation {
background: transparent url(images/nav-left.png) no-repeat scroll 0 0;
padding-left:11px;
}

#navigation ul {
background: transparent url(images/nav-middle.png) repeat-x scroll 0 0;
height:44px;
}

#navigation li:hover, #navigation li ul li:hover {
background:transparent url(images/navigation-hover.png) no-repeat scroll 0 0;
}

You may need to adjust your padding and height if necessary, it only depends on your sliced images sizes.

For example, I added a left padding of 11 pixels to my navigation div because I don’t want the background of the element inside it to hide it’s content.

Take a look at the difference:

CSS Padding Difference

It speaks by itself.

Well, you may have noticed that I included a rule to handle the CSS :hover pseudo-class.

The code is not relevant, it just displays another image as the background of the tab. If there’s something you must pay attention to, is the hover image size. It must be at least longer than you longer tab, itself being conditioned by the longest title of your pages.

Here is a quick preview of what you will face if the hover image is too short:

Too short hover image

This is one if not the only the counter part of using CSS sliding doors.

Displaying submenus using jQuery

First create a new folder named «/wordpress/wp-content/themes/default/js/» and install a fresh copy of jQuery inside along with a new file named «shiny-theme.js».
Open «/wordpress/wp-content/themes/default/footer.php» and just before the closing body tag, add the references to jQuery and shiny-theme.js:

<script src="<?php bloginfo('stylesheet_directory'); ?>/js/jquery-1.3.js" type="text/javascript"></script>
<script src="<?php bloginfo('stylesheet_directory'); ?>/js/shiny-theme.js" type="text/javascript"></script>

You might want to take advantage of Google’s Ajax CDN to save bandwidth. In this case replace the jQuery reference by this one :

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>

«Why in the footer?» You might ask. The answer is based on the assumption that any javascript that affects the DOM won’t be triggered until the DOM is fully parsed by the browser, generating errors otherwise. More important, having the javascripts in the footer avoid browsers stalling while rendering a page. Because it doesn’t have to download and parse huge files prior DOM rendering.

Styling submenus:

#navigation li ul {
display:none;
left:0;
position:absolute;
top:33px;
height:auto;
}

#navigation li ul li {
background:transparent url(images/navigation-hover.png) repeat scroll 0 0;
}

Open «/wordpress/wp-content/themes/default/js/shiny-theme.js» and paste the following snippet:

$(document).ready(function(){

$('#navigation li').hover(
function() {$(this).find('ul:first').show();},
function() {$(this).find('ul:first').hide();}
);

})

Refresh your page and take a look at the result :

jQuery Menu

It’s nice, but it could be nicer using some CSS3 rules.

In the previous screenshot the li are not clearly diferenciated from the post content. It’s too flat, there’s no deepness. Let’s add some deepness using a couple CSS3 rules edit the ul selector to add two new browser specific rules :

#navigation li ul {
display:none;
left:0;
position:absolute;
top:33px;
height:auto;
<strong>
-moz-box-shadow:0 2px 5px #000000;
-webkit-box-shadow:0 2px 5px #000000;
</strong>
}

Then take a look at the result:

jQuery Menu Shaded

Voilà! Our design just took another dimension. With just only those two lines you are covering Firefox 3.1+, Safari 3+ and Chrome browsers. I don’t know about you but on my sites it’s a more than significant part of my audience.

The content and sidebar areas

Kubrick does not shows the sidebar while on a post or page and it displays the navigations links above the content element. Let’s change these behaviors by adding the following code just before the get_footer() call in «/wordpress/wp-content/themes/default/single.php»:

<?php get_sidebar(); ?>
<?php get_footer(); ?>

… And by removing the navigation snippet.

Let’s quickly lay some CSS rules to style our main content and sidebar.

/*
The left margin of the #content element must be the same
as the #navigation left padding
*/
#content {
clear:both;
float:left;
margin:0 0 0 11px;
width:625px;
background-color:#ccc;
border: 1px solid #fff;
margin-bottom:20px;
padding:10px;
}

#content a {
color:#663300;
text-decoration:underline;
}

#sidebar  {
background-color:#ccc;
border: 1px solid #fff;
margin-bottom:20px;
padding:10px;
float:left;
width:270px;
color:#666;
font-size:0.9em;
}

.post {
margin-bottom:20px;
}

You should now have something very similar to the following screenshot when you browse a specific post:

Content and Sidebar Areas

Once formated properly, we should add the basic typography and formating rules.

.post h2, .post h3, .post h4, .post h5, .post h6 {
color:#333333;
font-family:Georgia, "Times New Roman" ,serif;
font-style:italic;
margin-bottom:10px;
height:32px;
}

h2 {font-size:28px;}
h3 {font-size:24px;}
h4 {font-size:20px;}
h5 {font-size:16px;}
h6 {font-size:12px;}

.post {
margin-bottom:20px;
}

.post img {
background-color:#CCCCCC;
border:3px solid #AAAAAA;
margin-bottom:10px;
margin-top:10px;
padding:4px;
}

.alignright {
margin-left:10px;
}

.alignleft {
margin-right:10px;
}

.entry p {
text-align:justify;
}

.post blockquote {
border-bottom:3px solid #663300;
border-top:3px solid #663300;
font-style:oblique;
margin:1em;
}

.post ul, .post ol {
list-style-type:disc;
margin-left:1em;
}

.post ol {
list-style-type:decimal;
}

.post cite {
margin-left:1em;
}

textarea {
width:100%;
}

You must now have something more readable:

Basic Post Formating

Meta data

To stick to our PSD layout, we must move and edit the meta data informations, mainly the publication date and categories, to the top of the post area, just below the post title.

Open «/wordpress/wp-content/themes/default/single.php» and add the following code just after the_title() call

<h2><?php the_title(); ?></h2>
<div class="post-meta">
Posted in
<span><?php the_category(', ') ?></span> on
<span><?php the_time('l, F jS, Y') ?></span> at
<span><?php the_time() ?></span> by
<span><?php the_author_link(); ?></span>
</div>

Also remove the similar content in the .postmetadata block then style the newly created publication information in «/wordpress/wp-content/themes/default/style.css».


.post-meta {
font-family:Georgia, "Times New Roman" ,serif;
font-style:italic;
font-size:14px;
margin-bottom:2em;
color: #888;
font-weight:bold;
}

.post-meta span {
font-style:normal;
font-weight:normal;
}

Let’s refresh our browser to see our style publication informations:

Publication information Formating

Comments Bubble

Comments Bubble Preview

The comment bubble will be as easy to slice and code, hide everything that is not the bubble itself then make a tight selection around it and make a merged copy (shift+ctrl+c) of it.

Comments Bubble Selection

Create a new Photoshop document (ctrl+N) (it should be at the good size) then paste the bubble and Save for the web & devices.

Open «/wordpress/wp-content/themes/default/single.php» and add the following code just after our previous edition:

<h2><?php the_title(); ?></h2>
<div class="post-meta">
Posted in
<span><?php the_category(', ') ?></span> on
<span><?php the_time('l, F jS, Y') ?></span> at
<span><?php the_time() ?></span> by
<span><?php the_author_link(); ?></span>
</div>

&lt;div class="comments-count"&gt;
&lt;?php comments_number('No Comments', 'One Comment', '% Comments' );?&gt;
&lt;/div&gt;

Finally apply relevant CSS rules to this new div.comments-count element :


.entry {
position: relative;

}
.entry .comments-count {
background:transparent url(images/comments-bubble.png) no-repeat scroll 0 0;
color:#FFFFFF;
height:37px;
position:absolute;
right:0;
font-size:12px;
text-align:center;
top:-32px;
width:110px;
}

Post image

To finish the content area, we need to add two elements, the post image and the attached ribbon graphical element. To do so we will make use of Wordpress custom fields. Slice the illustrative image from the PSD layout and save it in «/wordpress/wp-content/themes/default/default-post-image.jpg». Needless to say that making use of such feature generate a little bit more work when writing new posts.

Edit the post you are currently using as master then add the following informations in the Custom Fields area and update the post, or whatever is relevant to your installation path.

Custom fields settings

To get benefit from this new information, we will make use of the get_post_meta() function. Slice & save the illustrative image’s ribbon and shadow then open «/wordpress/wp-content/themes/default/single.php».

Add the following snippet just above the_content() call:

<?php if (get_post_meta(get_the_ID(), 'post_image', true) != '') {?>
<p class="post-image">
<span class="ribbon">&amp;amp;amp;amp;amp;amp;nbsp;</span>
<img src="<?php echo get_post_meta(get_the_ID(), 'post_image', true); ?>" alt="<?php the_title(); ?>" width="630" />

</p>
<div class="post-image-shadow">&amp;amp;amp;amp;amp;amp;nbsp;</div>
<?php } ?>

This is some additional markup conditioned by the presence of a post_image custom field in the post currently displayed. Basically, if there is no image associated with the post then do not display this part. As an exercise, you could also try an implement a default image to display in place of the post_image custom field.

Add the corresponding CSS formating and positioning in the stylesheets file :


.post-image {
position: relative;
}

.post-image img {
border:1px solid #FFFFFF;
padding:0;
margin-bottom:0;
}

.ribbon {
background:transparent url(images/vertical-ribbon.png) no-repeat scroll center center;
height:100%;
left:-28px;
position:absolute;
width:44px;
}

.post-image-shadow {
background:transparent url(images/post-image-shadow.png) no-repeat scroll center top;
height:44px;
width:100%;
}

The completed post design should now looks like this in your browser:

Completed post design

Author box

Author box

Open «/wordpress/wp-content/themes/default/single.php» in your favorite editor and place your cursor just before the comments_template() call. Paste the following code:

<div class="hr">&amp;amp;amp;amp;amp;amp;nbsp;</div>
<div id="author-bio-container">
<h3><?php _e('About the Author');?></h3>
<div class="author vcard">
<div class="user-avatar"><?php
echo get_avatar(get_the_author_meta('ID'), $size='64', $default = get_option('home') . '/wp-content/themes/default/images/avatar.png'); ?>
</div>
</div>
<p id="author-bio">
<?php
the_author_meta('description');
?>
</p>

</div>
<div class="clear"></div>

This is straight forward, display an horizontal line, display the header then display the author’s avatar and description. Edit the existing headers rule :

.post h2, .post h3, .post h4, .post h5, .post h6,
h3#comments, #comments-description, #respond h3,
<strong>#author-bio, #author-bio-container h3</strong> {
color:#333333;
font-family:Georgia, "Times New Roman" ,serif;
font-style:italic;
margin-bottom:10px;
height:32px;
}

Then add the following rules to format the newly created markup:

.author {
float:left;
}

.author .user-avatar {
margin-right:42px;
}

#author-bio {
font-size:12px;
font-style:italic;
line-height:1.5em;
}

And we are done for this simple element.

Comments area

The slicing and coding will become a little it heavier in this step, we will adapt the existing «/wordpress/wp-content/themes/default/comments.php» to fit our needs.

Add a couple new selectors to the HTML Headers rules:

.post h2, .post h3, .post h4, .post h5, .post h6, <strong>h3#comments, #comments-description</strong> {
color:#333333;
font-family:Georgia, "Times New Roman" ,serif;
font-style:italic;
margin-bottom:10px;
height:32px;
}

Edit the text to fit the PSD layout by replacing the following code

<h3 id="comments"><?php comments_number('No Responses', 'One Response', '% Responses' );?> to “<?php the_title(); ?>”</h3>

by

<h3 id="comments">Comments (<?php comments_number('0', '1', '%' );?>) <span><a href="#respond">Participate!</a></span></h3>

Then add the description line

<span id="comments-description">Take a look at the responses we've had to this article.</span>

Apply some CSS rules to the newly introduced elements.


#comments-description {
font-weight:bold;
color:#666;
font-size:14px;
}

h3#comments {
margin-bottom:0;
}

h3#comments span {
float:right;
font-size:14px;
}

Comments boxes

Let’s analyze our comment box, there’s a custom default avatar that is larger (64 x 64px) than the Wordpress default one and the user name and comment are framed in a comic like bubble. Nothing to be scared of.

At this point you should know how to slice a PSD layout, I’ll not explain further how to slice the parts (default avatar, left arrow and horizontal line) we will need in this step, let’s instead focus on code. Open «/wordpress/wp-content/themes/default/functions.php» and delete everything under the register_sidebar conditional test and add the following function :

function shinytheme_comment($comment, $args, $depth) {
$GLOBALS['comment'] = $comment;
$urlHome = get_option('home') . '/wp-content/themes/default/images/';
?>
<li <?php comment_class(); ?> id="li-comment-<?php comment_ID() ?>">
<div id="comment-<?php comment_ID(); ?>">
<div class="comment-author vcard">
<div class="user-avatar"><?php echo get_avatar($comment, $size='64', $default = $urlHome . 'avatar.png'); ?></div>
<div class="reply">
<?php comment_reply_link(array_merge( $args, array('depth' => $depth, 'max_depth' => $args['max_depth']))) ?>
</div>
</div>

<div class="comment-text">

<div class="left-arrow">&amp;amp;amp;amp;amp;amp;nbsp;</div>
<div class="comment-meta commentmetadata">
<?php comment_author_link() ?><?php _e('&amp;amp;amp;amp;amp;amp;nbsp;said:&amp;amp;amp;amp;amp;amp;nbsp;');?>
</div>
<?php comment_text() ?>
<span><?php comment_date(__('l, F jS, Y')) ?>&amp;amp;amp;amp;amp;amp;nbsp;<?php comment_time(__('H:i')) ?></span>
<?php if ($comment->comment_approved == '0') : ?>
<br />
<em><?php _e('Your comment is awaiting approval.'); ?></em>
<br />
<?php endif; ?>
</div>
<div class="clear"></div>
</div>
<?php }

This function will be used as a replacement of the Wordpress default comment display handling. Let’s register it. Open «/wordpress/wp-content/themes/default/comments.php» then replace the wp_list_comments call by this one :

<ol class="commentlist">
<?php
wp_list_comments('type=all&amp;amp;amp;amp;amp;amp;callback=shinytheme_comment');
?>
</ol>

This instruction simply overrides the default Wordpress comments display by a custom callback function.

All what is left concerning the comment boxes is the CSS. In «/wordpress/wp-content/themes/default/style.css», add the following rules:

.comment-author {
float:left;
margin-right:10px;
}

.comment-text {
background-color:#E9E9E9;
border:1px solid #FFFFFF;
margin-bottom:30px;
margin-left:100px;
padding:10px;
position:relative;
}

.comment-text span {
font-size:12px;
color: #666;

}
.clear {
clear:both;
}

.left-arrow {
background:transparent url(images/left-arrow.png) no-repeat scroll center top;
height:26px;
left:-15px;
position:absolute;
top:3px;
width:19px;
}

.user-avatar {
border: 1px solid #aaa;
}

.hr {
background:transparent url(images/hr.png) no-repeat scroll center top;
height:2px;
margin:20px;
width:100%;
}

And we are done, let’s take a quick look at the result:

Finished Comment Boxes

Comment form

We will now style the comment form to match as closely as possible our PSD layout.

Open «/wordpress/wp-content/themes/default/style.css» and move the textarea line above the is_user_logged_in() call:

<p><textarea name="comment" id="comment" cols="100%" rows="10" tabindex="4"></textarea></p>

<?php if ( is_user_logged_in() ) : ?>

Add the user (or default if not logged) avatar just inside the form#commentform element:

<div class="comment-author vcard">
<div class="user-avatar"><?php
global $current_user;
get_currentuserinfo();
echo get_avatar($current_user->ID, $size='64', $default = get_option('home') . '/wp-content/themes/default/images/avatar.png'); ?>
</div>
</div>

Wrap the rest in a div#comment-fields element:

<div id="comment-fields">
<p>
<span class="left-arrow-white">&amp;amp;amp;amp;amp;amp;nbsp;</span>
<textarea name="comment" id="comment" rows="10" tabindex="4"></textarea>
</p>

<?php if ( is_user_logged_in() ) : ?>

<p>Logged in as <a href="<?php echo get_option('siteurl'); ?>/wp-admin/profile.php"><?php echo $user_identity; ?></a>. <a href="<?php echo wp_logout_url(get_permalink()); ?>" title="Log out of this account">Log out &amp;amp;amp;amp;amp;amp;raquo;</a></p>

<?php else : ?>

<p><input type="text" name="author" id="author" value="<?php echo esc_attr($comment_author); ?>" size="22" tabindex="1" <?php if ($req) echo "aria-required='true'"; ?> />
<label for="author"><small>Name <?php if ($req) echo "(required)"; ?></small></label></p>

<p><input type="text" name="email" id="email" value="<?php echo esc_attr($comment_author_email); ?>" size="22" tabindex="2" <?php if ($req) echo "aria-required='true'"; ?> />
<label for="email"><small>Mail (will not be published) <?php if ($req) echo "(required)"; ?></small></label></p>

<p><input type="text" name="url" id="url" value="<?php echo esc_attr($comment_author_url); ?>" size="22" tabindex="3" />
<label for="url"><small>Website</small></label></p>

<?php endif; ?>

<p id="submit-container"><input name="submit" type="submit" id="submit" tabindex="5" value="Submit Comment" />
<?php comment_id_fields(); ?>
</p>
<?php do_action('comment_form', $post->ID); ?>
</div>

And format the elements using CSS:

#comment-fields {
float:left;
margin-left:22px;
width:522px;
}

#comment-fields p {
position:relative;
}

#comment, #author, #email, #url{
border:1px solid #999999;
margin-bottom:20px;
width:505px;
padding:10px;
}

.left-arrow-white {
background:transparent url(images/left-arrow-white.png) no-repeat scroll center top;
height:26px;
left:-14px;
position:absolute;
top:6px;
width:19px;
}

You should get something very similar to the following screenshot:

Comments Form Early Formating

Some work’s left in this area. Labels should appear inside the inputs and the submit button needs a background image.

Here is the content of the div#comments-fields element after a bit editing and Javascript magic:

<div id="comment-fields">
<p>
<span class="left-arrow-white">&amp;amp;amp;amp;amp;amp;nbsp;</span>
<textarea name="comment" id="comment" rows="10" tabindex="4"
onfocus="javascript:if(this.value == 'What\\'s on your mind ?'){this.value=''};"
onblur="javascript:if(this.value==''){this.value='What\\'s on your mind ?'}"
>What's on your mind ?</textarea>
</p>

<?php if ( is_user_logged_in() ) : ?>

<p>Logged in as <a href="<?php echo get_option('siteurl'); ?>/wp-admin/profile.php"><?php echo $user_identity; ?></a>. <a href="<?php echo wp_logout_url(get_permalink()); ?>" title="Log out of this account">Log out &amp;amp;amp;amp;amp;amp;raquo;</a></p>

<?php else : ?>

<p><input type="text" name="author" id="author"
onfocus="javascript:if(this.value == 'Your name <?php if ($req) echo "(required)"; ?>'){this.value=''};"
onblur="javascript:if(this.value==''){this.value='Your name <?php if ($req) echo "(required)"; ?>'}"
value="<?php echo (esc_attr($comment_author))==''?'Your name ' . (($req)?"(required)":""):esc_attr($comment_author); ?>"
size="22" tabindex="1" <?php if ($req) echo "aria-required='true'"; ?> />
</p>

<p><input type="text" name="email" id="email"
onfocus="javascript:if(this.value == 'Mail (will not be published) <?php if ($req) echo "(required)"; ?>'){this.value=''};"
onblur="javascript:if(this.value==''){this.value='Mail (will not be published) <?php if ($req) echo "(required)"; ?>'}"
value="<?php echo (esc_attr($comment_author_email))==''?'Mail (will not be published) ' .(($req)?"(required)":""):esc_attr($comment_author_email); ?>"
size="22" tabindex="2" <?php if ($req) echo "aria-required='true'"; ?> />

</p>

<p><input type="text" name="url" id="url"
onfocus="javascript:if(this.value == 'Website'){this.value=''};"
onblur="javascript:if(this.value==''){this.value='Website'}"
value="<?php echo (esc_attr($comment_author_url))==''?'Website':esc_attr($comment_author_url); ?>"
size="22" tabindex="3" />
</p>

<?php endif; ?>

<p id="submit-container"><input name="submit" type="submit" id="submit" tabindex="5" value="Submit Comment" />
<?php comment_id_fields(); ?>
</p>
<?php do_action('comment_form', $post->ID); ?>
</div>

Nothing especially hard to understand here, labels strings have been moved into inputs values and two javascript events have been added, let me explain this a bit further. onFocus & onBlur events are triggered when a user respectively enters or leaves an html field. The actions are rather simple too, it reads like this in pseudo code:

onFocus, we clear the field so the user don't have to:

IF my.value == 'something' THEN
clear my.value
FI

onBlur, we reset the field to a known state so the onFocus event could be triggered again

IF my.value is empty THEN
my.value = 'something'
FI

That’s all for javascript, we could have go for some jQuery event binding too. I love jQuery, but I couldn’t find any good argument for this particular usage apart from being unobtrusive. Anyway here the unobtrusive equivalent to our snippets:

$(document).ready(function(){
$("#author").
bind('focus', function(){
if($(this).val() == "Your name") {
$(this).val('');
}
}).
bind('blur', function(){
if($(this).val() == "") {
$(this).val('Your name');
}
});

/* Rinse, repeat for other fields. */
});

The only tricky part resides in fact, in the values filled using PHP. It might be confusing to beginners because it makes use in some cases of 2 ternary operations. Let’s decompose this:

echo (esc_attr($comment_author))==''?'Your name ' . (($req)?"(required)":""):esc_attr($comment_author);

Is equivalent to :

if (esc_attr($comment_author) == '') {
echo 'Your name ';
if($req != '') {
echo '(required)';
}
}
else {
echo esc_attr($comment_author)
}

Ternary operators are bottled awesomeness when it comes to one liners.

Onto the submit button. You have two choices, going for a full alpha channel PNG24 version of it or a matted version in PNG8.

Each solution have it’s own downside I’ll explain them both and you’ll have to choose by yourself what’s better for your particular situation.

PNG24 is more flexible, let’s say you want to change the background of your main content area, your button will follow the flow and you will not have to slice it again until you completely change your layout. This has a cost, in terms of bytes this button will be about 10kbytes. Which is kind of huge a en element of this size.

PNG8 on the other hand, will produce a smaller image, around 3kbytes, but you’ll have to embed the background color information (Matte option in Photoshop Save for web & devices) thus limiting the uses for this graphical element and forcing you to re-export it each time you change it’s background.

PNG24 vs. PNG8

My choice will go to PNG24 and flexibility. So slice and export your button and style the input#submit element:

#submit-container{
text-align:right;
}

#submit {
background:transparent url(images/add-comment.png) no-repeat scroll center top;
border:none;
height:68px;
text-indent:-100000px;
width:273px;
}

To finish this area off we yet have to change to form title which reads «Leave a reply» to «Participate!»
Once done, your are finished with the comments area and you should have something very similar to the
following screenshot:

Comments Final Formating

And for logged in users :

Comments Final Formating for Logged In Users

Header and Subscriptions

An important part if not the most, of every web design is the header. In our case it’s composed of a logo with a tagline and the common subscriptions options you find on about every blog. We will edit the default header markup to fit our need. But first slice the PSD and save the following parts as files in «/wordpress/wp-content/themes/default/images/»:

  • Logo + tagline as 323 x 70px «logo.png»
  • Header Background gradient as 1 x 115px «inner-orange.png»
  • Separator as 2 x 78px «header-separator.png»
  • Twitter Subscription as 48 x 60px «twitter-sub.png»
  • eMail Subscription as 90 x 60px «email-sub.png»
  • Twitter Subscription as 57 x 60px «rss-sub.png»

Open «/wordpress/wp-content/themes/default/header.php» and replace the div#header element by the following code :

<div id="header" role="banner">
<div id="headerimg">
<h1><a href="<?php echo get_option('home'); ?>/"><img height="70" width="321" src="<?php bloginfo('stylesheet_directory'); ?>/images/logo.png" alt="<?php bloginfo('name'); ?>" title="<?php bloginfo('name'); ?>"</a></h1>
<div id="subscriptions">
<a href="http://twitter.com/ncrovatti"><img src="<?php bloginfo('stylesheet_directory'); ?>/images/twitter-sub.png" alt="Subscribe via Twitter"/></a>
<a href="javascript:void();"><img src="<?php bloginfo('stylesheet_directory'); ?>/images/email-sub.png" alt="Subscribe via Email"/></a>
<a href="<?php bloginfo('rss2_url'); ?>"><img src="<?php bloginfo('stylesheet_directory'); ?>/images/rss-sub.png" alt="Subscribe via RSS"/></a>
</div>
</div>
</div>

Nothing exceptional about the markup, try to keep a clean and as smaller as possible markup is my only advice. All elements layed out we need to style them, the logo must float on the left side of the header and the subscriptions at the exact opposite.

You might have noticed the link for email subscription is a “do_nothing” Javascription function. We will get back to this later in this chapter.

Be sure to check your the dimensions of your sliced images, depending on how you do it, you might not obtain the same size, thus involving a bit CSS editing. Anyway here the CSS for my slices of the headers elements:

#headerimg {
background:transparent url(images/inner-orange.png) repeat-x scroll center center;
height:115px;
margin:0 auto;
width:952px;
}

#headerimg h1 {
float:left;
padding-top:20px;
padding-left:10px;
width:335px;
}

#subscriptions {
background:transparent url(images/header-separator.png) no-repeat scroll center left;
float:right;
margin-top:26px;
text-align:right;
width:600px;
}

Only three elements, #headerimg is our container, it must be centered.
#headerimg h1 is the logo, it belong to the left side of #headerimg and must have a width setup in order to avoid overlapping over the #subscriptions elements, finally, the #subscriptions element belonging to the right of the header section.

All finished you should have a header section very similar to the following screenshot:

Header Formating

ShinyTheme Options Page

Having a subscription for your twitter feed is great, it’s a no brainer on any blog. But you do not want the people using your theme have to hack into the code just to add their Twitter account.

We will now build the options page for our theme. The explained process will help you produce a clean, Wordpress look & feel settings page for your theme. The only field I will explain is how to customize the blog’s Twitter account for the corresponding subscription option.

Everything starts in «/wordpress/wp-content/themes/default/function.php», at the top of the file, before the sidebar registering, add the following php code :

$themename = "ShinyTheme";
$shortname = "wpst";
$options = array (

array(
"name" => "Subscription Settings",
"type" => "title"
),

array(
"type" => "open"
),

array(
"name" => "Twitter account",
"desc" => "Enter the twitter account related to your blog.",
"id"   => $shortname."_twitter_account",
"std"  => "",
"type" => "text"
),

array(
"type" => "close"
)

);
  • $themename variable is the display name of our theme accross the whole Wordpress installation.
  • $shortname is the prefix for all our custom options fields.
  • $options The options array’s arrays can be read as template blocks
    • Index 0: The Title of the option page
    • Index 1: The options opening. In our case it will correspond to a table tag opening.
    • Index 2: An (or more) option field.
    • Index 3: The options closing. This is where we will close the table tag opened
      at opening stage.

Add the generic options handling function :


function shinytheme_add_admin() {
global
$themename,
$shortname,
$options;

if ($_GET['page'] == basename(__FILE__)) {
if ('save' == $_REQUEST['action']) {
foreach ($options as $value) {
update_option($value['id'], $_REQUEST[ $value['id']]);
}

foreach ($options as $value) {
if(isset($_REQUEST[$value['id']])) {
update_option($value['id'], $_REQUEST[ $value['id']]);
}
else {
delete_option($value['id']);
}
}

header("Location: themes.php?page=functions.php&amp;amp;amp;amp;amp;amp;saved=true");
die();

}
}

add_theme_page($themename." Settings", "".$themename." Settings", 'edit_themes', basename(__FILE__), 'shinytheme_admin');

}

This function saves the parameters filled in the options form of our theme settings admin page. If you want to add different action handling it’s the function you have to hack into.

Here comes the Beast.

If there’s a thing I dislike concerning Wordpress admin pages, it’s how the markup is handled. I mean, if I learned one thing in more than ten years of web working, it’s to separate content from logic.
This is clearly not the case when you glance at the following admin settings function:

function shinytheme_admin() {
global
$themename,
$shortname,
$options;

if ($_REQUEST['saved']) {
echo '<div id="message" class="updated fade"><p><strong>'.$themename.' settings saved.</strong></p></div>';
}

?>
<div class="wrap">
<div class="icon32" id="icon-options-general"><br/></div>
<h2><?php echo $themename; ?> settings</h2>

<form method="post">

<?php foreach ($options as $value) {

switch ( $value['type'] ) {
case "open":
?>
<table class="form-table">

<?php
break;
case "close":
?>

</table><br />

<?php
break;
case "title":
?>

<h3><?php echo $value['name']; ?></h3>

<?php
break;
case 'text':
?>

<tr>
<th>
<label for="<?php echo $value['id']; ?>"><?php echo $value['name']; ?></label>
</th>
<td>
<input class="regular-text" 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']; } ?>" />
<span class="description"><?php echo $value['desc']; ?></span>
</td>
</tr>
<?php
break;

}
}
?>
<p class="submit">
<input type="submit" value="Save Changes" class="button-primary" name="Submit"/>
<input type="hidden" name="action" value="save" />
</p>
</form>
<?php

}

Anyway, it’s how Wordpress does things. As a side note, I’ve been greatly inspired from this blog post concerning the whole theme admin page building, I just simplified the code, stripped out the inline CSS and applied the core Wordpress stylesheets in order to keep unity accross the administration panels.

One last thing to do is to actually register the admin function with Wordpress itself:

add_action('admin_menu', 'shinytheme_add_admin');

And we are (almost) done! The appearance box should now displays the link to our settings page:

Appearance Box

The settings page itself:

Settings Page

It’s clean, it blends nicely with the whole Wordpress administration panels and it’s simple. Yet we only have one option but I’m sure you got the picture.

Now the time as come to make use of these specific informations in the ShinyTheme. Open «/wordpress/wp-content/themes/default/header.php» and add the following php code snippet just below the wp_head() call:

<?
// Making options available in the current function
global $options;

foreach ($options as $value) {
/*
Stores the result of get_settings() into a variable
to avoid multiple calls to the function
*/
$current_option = get_settings($value['id']);

$$value['id'] = ($current_option === false) ? $value['std'] : $current_option;
}
?>

The last line worth a little bit more explanation. It creates a new variable named after $value['id'] content (See Variable variables in PHP documentation). e.g: if $value['id'] value is «hello», this will create a new variable named $hello with either $current_option or $value['std'] as value. Providing by this mean, a convenient way to handle default values by setting «std» in the $options array.

With that in mind it’s not difficult to guess what variable will be assigned: $wpst_twitter_account wich is the id parameter of the $options array: 'id' => $shortname."_twitter_account".

All you have to do now is to add a conditional verification to display or not the Twitter subscription image and link. Open «/wordpress/wp-content/themes/default/header.php» and edit the div#header block:

<div id="header" role="banner">
<div id="headerimg">
<h1><a href="<?php echo get_option('home'); ?>/"><img height="70" width="321" src="<?php bloginfo('stylesheet_directory'); ?>/images/logo.png" alt="<?php bloginfo('name'); ?>" title="<?php bloginfo('name'); ?>"</a></h1>
<div id="subscriptions">
<?php if ($wpst_twitter_account != "") { ?>
<a href="http://twitter.com/<?php echo $wpst_twitter_account;?>"><img src="<?php bloginfo('stylesheet_directory'); ?>/images/twitter-sub.png" alt="Subscribe via Twitter"/></a>
<?php }?>
<a href="javascript:void;"><img src="<?php bloginfo('stylesheet_directory'); ?>/images/email-sub.png" alt="Subscribe via Email"/></a>
<a href="<?php bloginfo('rss2_url'); ?>"><img src="<?php bloginfo('stylesheet_directory'); ?>/images/rss-sub.png" alt="Subscribe via RSS"/></a>
</div>
</div>
</div>

And we are done for the theme options part. Let’s look at the result:

Twitter Account: Set vs Unset

The Sidebar

Here is the preview of what we are going to build in this section:

Sidebar headings preview

But first, we need to setup our widgetizable sidebar accordingly to the PSD layout:

Sidebar widgets and options

To achieve the dotted effect on the sidebar headings we will not slice and export each heading separatly, nor we won’t use any text replacement technique. Instead, we will use a pattern overlay applied over the headings, using CSS.

Created a new Photoshop document 2 x 2px transparent background and using the background color of the sidebar, reproduce the following pattern :

Pattern overlay

And save it for the web as «pattern.png».

Edit the register_sidebar() function in «/wordpress/wp-content/themes/default/functions.php» to add a bit of markup (bolded in the following snippet) to the headings wrappers so we can hook in CSS.

register_sidebar(array(
'before_widget' => '<li id="%1$s" class="widget %2$s">',
'after_widget' => '</li>',
'before_title' => '<h2 class="widgettitle">',
'after_title' => '<strong><span class="overlay"></span></strong></h2>',
));

CSS formating and positioning

.widget {
margin-bottom:20px;
}

.widgettitle {
background:transparent url(images/sidebar-separator.png) no-repeat scroll center bottom;
color:#333;
margin-bottom:10px;
padding-bottom:5px;
position:relative;
}

.overlay {
background:transparent url(images/pattern.png) repeat scroll 0 0;
position:absolute;
height:1em;
left:0;
top:0;
width:100%;
}

Here we are giving some breath to the widgets, and setting the newly created span elements on
top of the heading text. The effect is complete. You might want to try different patterns and colors in your
own designs.

Here are some examples:

Pattern experiment

Ok, nothing tricky anymore, let’s style the rest of the sidebar:

#s {
border:1px solid #999;
padding:10px;
}

#searchsubmit {
display:none;
}

#sidebar a {
color: #630;
text-decoration: underline;
}

#sidebar ul li ul li	{
list-style-image:url(images/bullet.png);

}

#sidebar ul li ul	{
margin-left: 20px;
}

Let’s keep the CSS at minimal styling. Here’s the result:

Sidebar final preview

The Footer

As is, wordpress comes with a default footer. Our PSD layout features rich content in this area. Let’s completly rewrite the markup. Open «/wordpress/wp-content/themes/default/footer.php» and replace everything in div#footer element by the following HTML markup:

<div id="footer_container">
<div class="footer_block separator">
<h3>About<span class="overlay"></span></h3>
</div>

<div class="footer_block separator">
<h3>Last Tweet<span class="overlay"></span></h3>
</div>

<div class="footer_block">
<h3>Elsewhere<span class="overlay"></span></h3>
</div>
</div>

Apply the basic CSS for formating and positioning the floating boxes:

#footer_container {
width:960px;
margin: 0 auto;
}

.footer_block {
float:left;
margin-top:10px;
min-height:230px;
width:320px;
}

.footer_block.separator {
background:transparent url(images/footer-separator.png) no-repeat scroll right top;
}

.footer_block h3 {
font-size:32px;
margin:10px;
padding:2px;
position:relative;
}

Glance at the result:

Footer preview

See this Last Tweet box ? We will make use of a third party library provided by Twitter itself to display our lastest Twitter activity, however, we will need to get the Twitter Account setting from ou theme in order to query Twitter.

Due to variable scope, the newly created variables in the header won’t be available in the footer, because it’s two diferent functions and localy instancied variables stays local.

To resolve this issue, I could have copy/pasted the corresponding snippet from the header to the footer, thus repeating a complete portion of the code, and almost doubling it’s maintenance time. Needless to says that this is a very bad pratice. Instead we have the option to either register those variables in the global namespace or to register them in the wrapping php object.

The cleaner way is always to not polute the global namespace. In our case we will add those variables in the $wp object, wich is the Wordpress main object. Yet this is polution of Wordpress object, but, it’s a small price to pay compared to the time saved.

On to the code, open «/wordpress/wp-content/themes/default/header.php» and change the code that gets the custom options to this one:

// Making options available in the current function
global $options;

foreach ($options as $value) {
if($value['id'] == '') {continue;}
/*
Stores the result of get_settings() into a variable
to avoid multiple calls to the function
*/
$current_option = get_settings($value['id']);
/* Save it in the Worpress oject to have this
information later in the script */
$wp->shinytheme[$value['id']] = ($current_option === false) ? $value['std'] : $current_option;
}

We must also change the manner we display this information to reflect the changes:

$wpst_twitter_account becomes : $wp->shinytheme['wpst_twitter_account']

Back to the footer, add the following code in the “Last Tweet” column:

<div class="author vcard">
<a href="http://twitter.com/<?php echo $wp->shinytheme[\'wpst_twitter_account\']; ?>"><img alt="Subscribe via Twitter" src="http://localhost:83/wp-content/themes/default/images/twitter-sub.png"/></a>
</div>
<div id="tweet-box">
<div id="twitter_update_list" ><li><em>And all is quiet ...</em></li></div>
</div>

<script type="text/javascript" src="http://twitter.com/javascripts/blogger.js"></script>
<script type="text/javascript" src="http://twitter.com/statuses/user_timeline/<?php echo $wpst_twitter_account; ?>.json?callback=twitterCallback2&amp;amp;amp;amp;amp;count=1"></script>
<?php }?>

Everything is now setup. The Last Tweet box will display a small informative text in case of failwhale or it will make a call to Twitter’s server and display your last tweet.

Afterword

Worpress is such a great tool that I could go on talking about it for days. So I’ll bring a consious ending to this tutorial. All I hope is that it helped you in some way. You may notice some mistakes I could have made. IF this is the case please contact me at nicolas dot crovatti at gmail dot com.

Spread the word:
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • Twitter
  • DZone
  • Facebook
  • FriendFeed
  • HackerNews

One Response to “PSD template to Wordpress Theme from Scratch”

  1. Zejulio 16 January 2010 at 8:36 pm Permalink

    Great post Nicolas!


Additional comments powered by BackType