a:2:{i:0;a:1:{s:4:"data";a:2:{s:7:"entries";a:10:{i:0;a:6:{s:5:"title";s:24:"Weekly Link Round-Up #41";s:4:"slug";s:23:"weekly-link-round-up-41";s:2:"id";s:3:"198";s:10:"typeHandle";s:4:"blog";s:4:"body";s:1656:"

Well, another week and weekend flew by. I’m finally starting to work on my redesign/realign, and I hope that I can get it launched in not too long. Here is what I found interesting this week:

";s:10:"bodyBlocks";a:0:{}}i:1;a:6:{s:5:"title";s:48:"Flexible and Semantic Forms with a Little jQuery";s:4:"slug";s:48:"flexible-and-semantic-forms-with-a-little-jquery";s:2:"id";s:3:"199";s:10:"typeHandle";s:4:"blog";s:4:"body";s:18471:"

While they may not be that pretty, forms are one of the most important parts of a web site. I have already written an article on CSS Forms, that was over a year ago, and I have developed much better techniques.

There are other great resources for information about form design, and I will take this information into account when I am showing the flexibility of my method of marking up and styling forms.

The Markup

After previously using a definition list to mark up my forms, I have switched to using an ordered list now. I switched for two main reasons:

I have decided to create just a simple un-styled form to use as an example. Here is what the markup of the page is:

<ol class="forms">
 <li><label for="name">Name</label><input type="text"name="name" id="name" /></li>
 <li><label for="email">Email</label><input type="text" name="email" id="email" /></li>
 <li><label for="city">City</label><input type="text" name="city" id="city" /></li>
 <li><label for="state">State</label><input type="text" name="state" id="state" /></li>
 <li><label for="zip">Zip</label><input type="text" name="zip" id="zip" /></li>
 <li class="grouping"><label>Sign Up for the Following</label>
  <ul>
   <li><input type="checkbox" name="info1" id="info1" /><label for="info1">Information 1</label></li>
   <li><input type="checkbox" name="info2" id="info2" /><label for="info2">Information 2</label></li>
   <li><input type="checkbox" name="info3" id="info3" /><label for="info3">Information 3</label></li>
  </ul>
 </li>
 <li><label for="message">Message</label><textarea name="message" id="message"></textarea></li>
 <li class="buttons"><button type="submit" name="submit" id="submit">Submit</button></li>
</ol> 

Even without any style applied, the form is still completely usable.

Styling the Forms

There are really 3 main styles of laying out forms:

Again, like I said, I am not going to go through the pros and cons of each method, I am going to show how easy it is to switch between the methods using my markup.

Labels Above the Form Field

This is by far the easiest method. Here is the CSS used to style my example form:

ol.forms { float: left; list-style: none; width: 100%; }
ol.forms li { 
 clear: both; 
 float: left; 
 margin: 0 0 10px; 
 width: 100%; 
}
ol.forms label { cursor: pointer; display: block; font-weight: bold; }
ol.forms input, ol.forms textarea { 
 font: inherit;
 padding: 2px;
 width: 300px;
}
ol.forms textarea { height: 250px; }
ol.forms li.grouping { margin-bottom: 0; }
ol.forms li.grouping ul { list-style: none; }
ol.forms li.grouping ul label { 
 display: inline;
 font-weight: normal;
 margin: 0 0 0 10px;
}
ol.forms li.grouping ul input { width: auto; } 

Really nothing too complicated. In my opinion, I don’t like stacking the label over the form field; I think it just makes the form too long.

Labels to the Side of the Form Field, Jagged Right

I like this layout of forms the best. I think it presents the form in a clear way so that you can just scan right through the form fields. With just a few changes to the CSS, you can float the labels to the left of the form fields. The changes are marked in bold:

ol.forms { float: left; list-style: none; width: 100%; }
ol.forms li { 
 clear: both;
 float: left;
 margin: 0 0 10px;
 width: 100%;
}
ol.forms label { 
 cursor: pointer;
 display: block;
 <strong>float: left;</strong>
 font-weight: bold;
 <strong>margin: 0 10px 0 0;
 width: 90px;</strong>
}
ol.forms input, ol.forms textarea { 
 font: inherit;
 padding: 2px;
 width: 300px;
}
ol.forms textarea { height: 250px; }
<strong>ol.forms li.grouping label { margin: 0; width: auto; }</strong>
ol.forms li.grouping { margin-bottom: 0; }
ol.forms li.grouping ul { list-style: none; <strong>margin-left: 100px;</strong> }
ol.forms li.grouping ul label { 
 display: inline;
 <strong>float: none;</strong>
 font-weight: normal;
 margin: 0 0 0 10px;
 <strong>width: auto;</strong>
}
ol.forms li.grouping ul input { width: auto; }
<strong>ol.forms li.buttons { float: none; margin-left: 100px; width: auto; }</strong> 

Take a look at the example with the fields on the left. Depending upon your label length, you may need to increase the width of the labels so that it does not span more than one line, but that is an easy enough change.

Labels to the Side of the Form Field, Jagged Left

Now with two changes to the CSS, you can easily switch to having the labels jagged left, which puts them closer to the form input. The changes needed are highlighted in bold:

ol.forms label { 
 cursor: pointer;
 display: block;
 float: left;
 font-weight: bold;
 margin: 0 10px 0 0;
 <strong>text-align: right;</strong>
 width: 90px;
}
ol.forms li.grouping label { margin: 0; <strong>text-align: left;</strong> width: auto; } 

Here is the example of the form with the labels jagged left.

Taking it a Step Further with More CSS and a Little jQuery

Since I like the form layout with labels to the side and jagged right, I am going to use this one to customize the display a little, and then add in some jQuery functionality.

Improving the Display

When looking at the form, it may be confusing to have all form fields be the same width. It is helpful to the user to modify the width to suit the data that will be entered.

For example, there is no reason that the zip code, city, and state fields should be so long, so let’s add a class to each one to shorten it to the length of the data that will probably be entered. Here is the modified markup:

<li>
 <label for="city">City</label>
 <input type="text" name="city" id="city" class="medium" />
</li>
<li>
 <label for="state">State</label>
 <input type="text" name="state" id="state" class="small" />
</li>
<li>
 <label for="zip">Zip</label>
 <input type="text" name="zip" id="zip" class="extraSmall" />
</li> 

Then we just have to add those 3 classes to the CSS:

ol.forms .extraSmall { width: 50px; }
ol.forms .small { width: 100px; }
ol.forms .medium { width: 150px; } 

Here is what the form looks like with that little bit of extra style. I also added in some help text, a notation for required fields, and the associated CSS; so take a look at the code to see that.

Adding a Little jQuery

Obviously you have read my article about AJAX forms with jQuery, which discusses how to add AJAX functionality to a form in a degradable way. So the following code assumes that you are going to be doing server side validation of the form as well.

Since there are required fields in this form, I add a class of required to the form and to each parent list item of required input fields.

First, we want our JavaScript to execute when the form with a class of required is submitted:

$(document).ready(function() {
 $('form.required').submit(function() {
  &hellip;
 });
}); 

If there are any error messages still displaying from before, we want to hide them. Also, let’s disable the submit button so just in case, the form cannot be submitted twice. I am also creating a variable that I will be using later to determine if there is an error or not:

$(document).ready(function() {
 $('form.required').submit(function() {
  <strong>$('form.required span.error').remove();
  $('form.required li.buttons button').attr('disabled','disabled');
  var hasError = false;</strong>
 });
}); 

Now, we want to check each form field that has a parent list item with a class of required:

$(document).ready(function() {
 $('form.required').submit(function() {
  $('form.required span.error').remove();
  $('form.required li.buttons button').attr('disabled','disabled');
  var hasError = false;

  <strong>jQuery.each($('form.required ol.forms li.required'),function() {
   &hellip;
  });</strong>
 });
}); 

There are a lot of other jQuery plugins that validate forms, but most of the time, it will just alert the user that the field is required. Instead of doing that, I am going to grab the text from the label element and display that in the error message:

$(document).ready(function() {
 $('form.required').submit(function() {
  $('form.required span.error').remove();
  $('form.required li.buttons button').attr('disabled','disabled');
  var hasError = false;

  jQuery.each($('form.required ol.forms li.required'),function() {
   <strong>var labelText = $(this).children('label').text();
   labelText = labelText.replace(' *','');</strong>
  });
 });
}); 

Now, we have two different structures of form fields for each list item: a single form field and a grouping of checkboxes or radio buttons. We have to do things a little bit different for each one:

$(document).ready(function() {
 $('form.required').submit(function() {
  $('form.required span.error').remove();
  $('form.required li.buttons button').attr('disabled','disabled');
  var hasError = false;

  jQuery.each($('form.required ol.forms li.required'),function() {
   var labelText = $(this).children('label').text();
   labelText = labelText.replace(' *','');

   <strong>if($(this).hasClass('grouping')) {
    &hellip; 
   } else {
    &hellip;
   }</strong>
  });
 });
}); 

First, let’s focus on the case when there is a grouping. We want to loop through each input and see if it is checked. If it is, we just increment a counter. Then, if the counter equals zero, meaning we have no fields checked, we display an error message:

$(document).ready(function() {
 $('form.required').submit(function() {
  $('form.required span.error').remove();
  $('form.required li.buttons button').attr('disabled','disabled');
  var hasError = false;

  jQuery.each($('form.required ol.forms li.required'),function() {
   var labelText = $(this).children('label').text();
   labelText = labelText.replace(' *','');

   if($(this).hasClass('grouping')) {
    <strong>var numSelected = 0;
    jQuery.each($(this).find('input'),function() {
     if($(this).attr('checked') == true) {
      numSelected++;
     }
    });
    
    if(numSelected == 0) {
     $(this).append('<span class="error">You must select from '+labelText+'.</span>');
     hasError = true;
    }</strong>
   } else {
    &hellip;
   }
  });
 });
}); 

That seems easy enough, and it’s even easier for the single input fields. We just check to see if the value is empty, and if it is, display the error message:

$(document).ready(function() {
 $('form.required').submit(function() {
  $('form.required span.error').remove();
  $('form.required li.buttons button').attr('disabled','disabled');
  var hasError = false;

  jQuery.each($('form.required ol.forms li.required'),function() {
   var labelText = $(this).children('label').text();
   labelText = labelText.replace(' *','');

   if($(this).hasClass('grouping')) {
    var numSelected = 0;
    jQuery.each($(this).find('input'),function() {
     if($(this).attr('checked') == true) {
      numSelected++;
     }
    });
    
    if(numSelected == 0) {
     $(this).append('<span class="error">You must select from '+labelText+'.</span>');
     hasError = true;
    }
   } else {
    <strong>if(jQuery.trim($(this).children('input, textarea').val()) == '') {
     $(this).append('<span class="error">Please enter your '+labelText+'.</span>');
     hasError = true;
    }</strong>
   }
  });
 });
}); 

To finish up, we just check to see if the hasError variable is true. Since this is just a demo form, I just add an alert if the form would submit successfully:

$(document).ready(function() {
 $('form.required').submit(function() {
  $('form.required span.error').remove();
  $('form.required li.buttons button').attr('disabled','disabled');
  var hasError = false;

  jQuery.each($('form.required ol.forms li.required'),function() {
   var labelText = $(this).children('label').text();
   labelText = labelText.replace(' *','');

   if($(this).hasClass('grouping')) {
    var numSelected = 0;
    jQuery.each($(this).find('input'),function() {
     if($(this).attr('checked') == true) {
      numSelected++;
     }
    });
    
    if(numSelected == 0) {
     $(this).append('<span class="error">You must select from '+labelText+'.</span>');
     hasError = true;
    }
   } else {
    if(jQuery.trim($(this).children('input, textarea').val()) == '') {
     $(this).append('<span class="error">Please enter your '+labelText+'.</span>');
     hasError = true;
    }
   }
  });

  <strong>if(hasError) {
   $('form.required li.buttons button').removeAttr('disabled');
   return false;
  } else {
   alert('The form would submit now');
   $('form.required li.buttons button').removeAttr('disabled'); //Remove this line if using for real
   return false; //Change this to true when using it for real
  }</strong>
 });
}); 

Go ahead and take a look at the demo form to see it in action.

Conclusion

With a well structured form, you can easily customize it to your liking with just a little bit of CSS. Then, by using some custom jQuery code, you can easily customize how you would like to have the form validation appear.

With a little more work, you could easily add in validation for things like form elements expecting an email address, zip codes, phone numbers, etc. I will have to save that for another post since this one is quite long.

What do you all think? How do you structure your forms? Which layout of forms do you prefer and why?

";s:10:"bodyBlocks";a:0:{}}i:2;a:6:{s:5:"title";s:24:"Weekly Link Round-Up #40";s:4:"slug";s:23:"weekly-link-round-up-40";s:2:"id";s:3:"200";s:10:"typeHandle";s:4:"blog";s:4:"body";s:1194:"

Well, I finally got a site launched that had been stressing me out, now I only have my company website to stress me out for the next two weeks. Here is what I found interesting this week:

";s:10:"bodyBlocks";a:0:{}}i:3;a:6:{s:5:"title";s:24:"Weekly Link Round-Up #39";s:4:"slug";s:23:"weekly-link-round-up-39";s:2:"id";s:3:"201";s:10:"typeHandle";s:4:"blog";s:4:"body";s:2065:"

Wow, I must say it is hard writing blog posts, doing freelance work, and being crazy busy at my day job. I’ve got one post in the works, and hopefully I will be able to finish it up next week. Here is what I found interesting last week (and the beginning of this week):

";s:10:"bodyBlocks";a:0:{}}i:4;a:6:{s:5:"title";s:24:"Weekly Link Round-Up #38";s:4:"slug";s:23:"weekly-link-round-up-38";s:2:"id";s:3:"202";s:10:"typeHandle";s:4:"blog";s:4:"body";s:957:"

Only found a couple of interesting things to read this past week, must have been the fact that I am working on 2 sites that need to launch next week.

";s:10:"bodyBlocks";a:0:{}}i:5;a:6:{s:5:"title";s:48:"When Planning Your Site Content, Become the User";s:4:"slug";s:47:"when-planning-your-site-content-become-the-user";s:2:"id";s:3:"203";s:10:"typeHandle";s:4:"blog";s:4:"body";s:1519:"

On Friday, I needed to get a small coffee table for my living room, so I decided to head to Ikea. I love Ikea, not only because their website is full of web standards goodness, but also because they make some really nice and affordable furniture.

Since Friday was the 4th of July, I wasn’t sure what the hours would be. I logged onto their website, found the store closest to me, and was getting ready to call and find out the hours.

To my delight, I not only found the normal store hours, but also found the holiday store hours.

Wow, that is quite a rarity. It is rare to even find the normal store hours on their websites, but holiday hours too? Quite impressive.

What the folks at Ikea have done is the simplest (and probably most important) method to having a successful website: put yourself in the users’ shoes. I’m sure at some point during their web site strategy development they thought: if we provide our store hours on the web site, then we will get less phone calls at the store about the hours, thus allowing the employees to focus more on the customers in the store.

So what is the lesson here? With every decision you make about your website, think about the goal of the website, and make sure your decision will help to achieve that goal.

";s:10:"bodyBlocks";a:0:{}}i:6;a:6:{s:5:"title";s:24:"Weekly Link Round-Up #37";s:4:"slug";s:23:"weekly-link-round-up-37";s:2:"id";s:3:"204";s:10:"typeHandle";s:4:"blog";s:4:"body";s:1554:"

So I think I am going to stop doing weekly link round-ups once i launch my redesign/realign. I think I want to have more of like “asides”, where I will just post an interesting link with a little blurb much more frequently. But the redesign is still a little ways off, so here is what I found interesting this past week:

";s:10:"bodyBlocks";a:0:{}}i:7;a:6:{s:5:"title";s:52:"WordPress Tips and Ideas Learned From Implementation";s:4:"slug";s:52:"wordpress-tips-and-ideas-learned-from-implementation";s:2:"id";s:3:"205";s:10:"typeHandle";s:4:"blog";s:4:"body";s:8093:"

Recently, I had to slice and implement a blog for the CEO of my company. I decided to go with WordPress because that is what I have become enamored with recently, when I created a job board using it. I used some features of WordPress that I had never used before, so I figured I would talk about them so that others could learn how to use them as well.

Multiple Loops

The blog contained a main blog section, along with a “Favorites” section in the sidebar, that would be used to list anything: favorite websites, books, etc. I didn’t think that using just the basic WordPress blogroll or a third party bookmarking site would give the CEO enough flexibility to mark whatever she wanted as a favorite. So I decided to just create a separate category for Favorites.

In the footer of the site, there is also information about the last 6 projects that we had worked on. I definitely did not want those to be static. Since we complete projects almost daily, I wanted “non-technical” people to be able to update them. So I decided to create a separate category for those.

So in total, I had 3 categories: Blog, Favorites, and Projects.

I figured I would just end up having the main loop in the content area, a loop in the sidebar, and a loop in the footer. I had never really done a site with multiple loops, but after reading the documentation, it didn’t look too complicated. So the key to having multiple loops is to use the query_posts template tag.

The Main Blog Loop

The Blog category has an id of 1. So all you have to do is call the query_posts template tag before you loop through the entries:

<?php query_posts('cat=1');
 if (have_posts()) : 
  while (have_posts()) : the_post(); ?>
   &hellip;
  <?php endwhile;
 endif; ?> 

Then the Favorites and Project categories are basically the same, you just plug in the correct category id into the query_posts template tag.

Paging with Multiple Loops

So since we are using the query_posts template tag, it messes up the paging of the main loop. So, in the main blog loop, we need to use the ternary operator to add in the paging argument:

<?php
 $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
 query_posts("cat=1&paged=$paged");
?> 

So those two lines would replace the previous call to the query_posts template tag that we used for the main loop.

Read More Links

When I had first implemented the blog, we were using the read more links (whenever they were added into the post) for all posts. Later in the implementation process, I was told that the most recent article should always show the full post.

I wasn’t sure how the heck I could do that, but after some Googling I figured it out. Basically what we need to do is just create a simple counter to see if we are on the first post. If we are, we set a global $more variable equal to 1. So I define the $count variable and set it equal to 1, then I have this at the beginning of the main loop:

<?php
if (is_home()) {
 global $more;
 if($count == 1) $more = 1;
 else $more = 0;
 $count++;
}
?> 

Wait a Minute…

So I was all ready to publish this article, when I found out today that the first article on my CEO’s blog was still showing the read more link. From what I discovered, it looked like both the is_home() and is_front_page() conditional tags were not registering as true when on the homepage. For the life of me, I could not figure out why this was happening.

So this was a little bit of a hacky solution, but it was all that I could think of quickly. I had this code before the loop:

<?php
 if($_SERVER['REQUEST_URI'] == '/') { 
  $isHomepage = true;
 }
?> 

So essentially, I was setting up my own flag to see if it was the homepage. What that is doing is checking the URL to see if it is the root of the site or not. Then I modifed the if statement in my other code to be:

<?php
 if (isset($isHomepage) && $isHomepage = true) {
  global $more;
  if($count == 1) $more = 1;
  else $more = 0;
  $count++;
 }
?> 

I’m not sure if there is a better solution, but I think the reason the is_home() and is_front_page() conditions don’t work is because of calling the query_posts template tag, because they worked before the call.

Custom Fields

I had used custom fields before, and they are amazingly powerful in being able to extend WordPress functionality. For my CEO’s blog, I used 4 custom fields:

Favorites’ Custom Fields

The favorites are supposed to be little blurbs about something that my CEO likes, whether it is a book, website, etc. So the idea is that it is not supposed to be a full blog post, just a little blurb. So instead of linking to the WordPress post, we link to the favoriteUrl custom field. Here is how the favoriteUrl custom field is being used (this is called within The Loop):

<?php 
$favoriteUrl = get_post_meta($post->ID, "favoriteUrl", true);
if($favoriteUrl != '') { ?>
 <a href="<?=$favoriteUrl ?>" class="heading"><strong><?php the_title(); ?></strong></a>
<?php } else { ?>
 <strong class="heading"><?php the_title(); ?></a>
<?php } ?> 

So basically what I am doing there is first calling in the favoriteUrl custom field and assigning it to the $favoriteUrl variable. Then, I check to make sure it is not empty (meaning the custom field was not entered). If it is entered, I output the link to the URL. If not, I still do not link to the WordPress post, I just display the title in bold.

The favoriteThumbnail is pretty self explanatory and is called in the same way as the favoriteUrl. The reason I wanted to use a custom field for the thumbnail instead of just adding the image to the post content is because the design called for the image to be floated next to the title and because I wanted to link the image to the favoriteUrl. This way, when my CEO is adding a favorite, she does not have to worry about floating the image and linking it to the favoriteUrl.

Projects’ Custom Fields

Both of the Projects’ custom fields are used similarly to the Favorities’ custom fields. The projectThumbnail custom field is just used to show the most recent 6 projects in the footer. Nothing complicated, just showing and linking the photo to the WordPress post.

Until our new company website gets launched, we are linking to the short WordPress post which gives a little description about the project. The projectUrl outputs the URL to the project at the end of the post. Once our company website is finished, I will just modify the custom field to link directly from the footer to its respective page in our portfolio.

Conclusion

I really enjoyed doing this implementation. While it was just a simple blog, it is always great to learn a couple of new tricks/techniques. Any other WordPress tips that you have found useful?

";s:10:"bodyBlocks";a:0:{}}i:8;a:6:{s:5:"title";s:24:"Weekly Link Round-Up #36";s:4:"slug";s:23:"weekly-link-round-up-36";s:2:"id";s:3:"206";s:10:"typeHandle";s:4:"blog";s:4:"body";s:2534:"

I actually got started on my redesign/realign this weekend. I think I want to have a larger focus on my portfolio, and not just my blog. But god is it hard to redesign when you aren’t a designer. Hopefully it will all turn out well in the end. Here is what I found interesting this week:

";s:10:"bodyBlocks";a:0:{}}i:9;a:6:{s:5:"title";s:25:"jQuery Table Striping Bug";s:4:"slug";s:25:"jquery-table-striping-bug";s:2:"id";s:3:"207";s:10:"typeHandle";s:4:"blog";s:4:"body";s:2574:"

I have been using jQuery to do table striping, and up until today, I have not had any problems with it.

I had just been using the :even and :odd selectors to add classes to each table row.

Here is the code that I have been using:

$(document).ready(function(){
 $("table.striped tbody tr:odd").addClass("odd");
 $("table.striped tbody tr:even").addClass("even");
}); 

Seems easy enough. Then I just styled the odd table rows like so:

table.striped tr.odd td { background-color: #f0f0f4; } 

One thing to note is that the :even and :odd selectors are zero-indexed, so the first table row will have a class of even, and not odd. Here is an example showing this simple striping.

Multiple Striped Instances

The situation that I had today had two different tables that were being striped. So based on the code, you would think that there wouldn’t be a problem. Here is the example with two striped tables on the same page.

Weird, so it looks like the first table row in the second striped table has a class of even instead of odd. I thought that the client may not like that because the two tables were not consistent, so I tried to think of another way to do the striping.

The nth Child

So based on the documentation, it looks like the nth child selector would be the solution. I just modified my JavaScript like so:

$(document).ready(function(){
 $("table.striped tbody tr:nth-child(odd)").addClass("odd");
 $("table.striped tbody tr:nth-child(even)").addClass("even");
}); 

As a note, the nth child selector is not zero indexed, so the first table row will have a class of odd instead of even. Here is the fixed example.

Conclusion

From what I can tell, this does not appear to be a browser problem, but a bug in jQuery. I have checked this in Firefox, Safari, IE6 and IE7.

";s:10:"bodyBlocks";a:0:{}}}s:5:"total";i:270;}}i:1;O:25:"yii\caching\TagDependency":3:{s:4:"tags";a:4:{i:0;s:7:"element";i:1;s:29:"element::craft\elements\Entry";i:2;s:40:"element::craft\elements\Entry::section:4";i:3;s:7:"graphql";}s:4:"data";a:4:{s:40:"CraftCMSce35088bdfe0816226cd17fd051a4803";s:21:"0.46162700 1707493692";s:40:"CraftCMS2743a789e8993267a348eee1ee7e4450";s:21:"0.34758900 1706282441";s:40:"CraftCMS2ac34726f299f7e18e449d8e536c67f8";s:21:"0.22771600 1711953912";s:40:"CraftCMS3817d4a648fcfac939af46605323feb0";s:21:"0.44505500 1681499442";}s:8:"reusable";b:0;}}