Close and Go BackBack to Viget

Building Viget.com In EE (Part 2)

Doug Avery
Doug Avery, ON THE TOPIC OF Development
Jun23 7

In my last EE post, I covered some ExpressionEngine tricks we used for managing multiple sites, removing the /comments URL segment, and setting up a simple “Preview” function.

This time, we’re going to use URL segments to create some dynamic user profiles, sort a portfolio page, and make a flexible upcoming event list.

Team Pages

The team pages had to be two things: Full of info (Twitter updates, posts, photos, links) and easy for team members to update themselves. A lot of this could probably be accomplished using custom user profile fields, but we opted for creating separate weblog entries about each user instead, making listing and maintaining these pages a little easier.

So we had three separate objects: A user, a weblog entry about a user, and the "page" itself that needed to display all this stuff. The easiest way to thread these all together was with a constant string: in our case, the user's username, which we set up as a lowercase string (in my case: 'davery'). This string was my username, my weblog entry's URL Title, and the actual URL of my profile page.

One immediate question was how to pull back a weblog of recent entries when the whole page is already an entry (and remember, you can't nest weblogs). The solution: cut the page into three weblogs.

{exp:weblog:entries weblog="profiles" 
    url_title="{segment_3}" limit="1" }
    ...
{/exp:weblog:entries}
{exp:weblog:entries username="{segment_3}" 
    weblog="fourlabs| ... |advance" limit="5"}
    ...
{/exp:weblog:entries}
{exp:weblog:entries weblog="profiles" 
    url_title="{segment_3}" limit="1" }
    ...
{/exp:weblog:entries}

So, we're pulling back entries with the URL Title of "davery" for the first and last third of the page, and pulling back entries with the username of "davery" for the middle third. This way, we're using the URL segment to steer EE towards the data we want. You could take this idea further: use the "davery" string to pull from a weblog called "davery," pull entries with the term "davery" in the text, or even use URL segments like "month=12" or "Monday" to pass specific start dates and ranges into the weblog tag. It's an quick way to use pre-existing, human-readable strings both as URLs and as parameters for retrieving data.

The Work Page

The idea for "Work" was to tag entries with the type of work done (SEO, design, branding) and allow users to sort the page based on these tags. This was already a little tricky, but we threw in an additional requirement: The tags had to be easy for project managers to create and edit. We naturally decided to use categories as the tags, which can work in a many-to-one relationship with each EE entry. The first step was to generate the lists at the top of the page, with two tags like this:

{exp:weblog:categories weblog="work" category_group="9"
    backspace="1" style="linear" }
    <a href="#" rel="{category_url_title}"> 
    {category_name}</a>
    <span class="hide" id="{category_url_title}">
    {category_description}</span>,
{/exp:weblog:categories}

The two Category Groups house the different "things" and "clients" category types, and help us divide them visually. The "category_url_title" outputs a lowercase string for each category, making it perfect for re-use in CSS or javascript. The hidden "category_description" appears in the top right corner (in the yellow sticky note) when a user selects a category.

Now for the work pieces themselves:

{exp:weblog:entries weblog="work"}
    <li><a href="/work/{url_title}/"  class="{categories}
    {category_url_title} {/categories} {url_title}">
    ...
{/exp:weblog:entries}    

Here, we're spitting out a list of category_url_titles as classes for each item of work. So now, we have multiple classes on each work link that match the rel tags of the links we already made. Time to link them up with some jQuery (courtesy of Rob Soulé):

$('#work_wrap a').click(function() {
    
    if($(this).hasClass('selected')) {} else {
    
      $('.selected').removeClass('selected');
      $(this).addClass('selected');
    
      $('#work_groups li a.'+$(this).attr('rel')).parent().each(function() {
         $(this).addClass('remove');
         $('#work_groups ul').prepend('');     
      });
      
      $('.remove').remove();
      $('#work_groups ul li.selected').fadeIn(450);
      $('#work_paper').html('<p>' + $(this).next().html()
         + '</p>');

    }//if
    return false;
  });

So, when a user clicks one of our tags, we:

  • Remove the "selected" state from anything currently selected
  • Add a "selected" state to the tag link
  • Get the parent li of any link with class matching the clicked rel tag
  • Add the "remove" class to those parent list items
  • Prepend new list items with the same HTML (and the "selected" class) to the list, and hide them
  • Remove all list items with the "remove" class from the DOM
  • Fade the new hidden list items in form their hidden state.

This is a pretty cool reusable answer to sorting, and can be used for any list that needs to be shuffled based on user interaction. With a little more work, you could find a way to slide open the space for the prepended items, which would look awesome on a more traditional list.

Events

We attend (and even host) a lot of events here at Viget, and needed an easy, flexible way to post them. Stuff on the wishlist:

  • The dates listed in a readable, standard format (July 10-15, September 10, August 29-September 2)
  • The ability to give events a span of days
  • The ability to add times, if necessary
  • The ability to completely buck the format and write up an event in a unique way
  • The ability to link to a blog entry or related website from an event's title
  • The ability for an event to automatically expire after it occurs

The dates were by far the trickiest bit. Sometimes events had start times, sometimes they had end times, sometimes they spanned two months, sometimes they were a single day, and the formatting needed to read correctly in all cases. The solution was a sort of IF statement spaghetti:

{exp:weblog:entries weblog="events" ... show_future_entries="yes"}    

{if full_override == ""}
      {if event_url}<a href="{event_url}">
      {title}</a>{if:else}{title}{/if} - 
   {if start_time}{start_time}
      {if end_time != "" AND expiration_date == 
      ""}-{end_time}{/if}, 
   {/if}
   {entry_date format="%F %j"} 
   {if "{entry_date format="%m"}" == 
   "{expiration_date format="%m"}"}
      {if expiration_date AND expiration_date != 
      entry_date}- {expiration_date format="%j"}
         {if end_time}, {end_time}{/if}
      {/if}
   {if:else}
      {if expiration_date  AND expiration_date  != 
      entry_date}to 
         {if end_time}{end_time}, {/if}
         {expiration_date format="%F %j"}
      {/if}
   {/if}
   {description}
{if:else}
   {full_override}
{/if}

{/exp:weblog:entries}

Eesh. Here's an easier way to read it, with the IF statements nested and indented:

Are we totally overriding the entry format?
   Yes: Output the HTML the user entered instead of the normal stuff.
   No: Output the standard event layout.
      Is there an event URL?
         Yes: Link the title to it.
         No: Just show the title without a link.
      Was a "start time" (a custom field in the entry) specified?
         Yes: Show it.
            Was an "end time" specified, and did the user set
            an expiration date?

               Yes: Show the end time, so the start+end will read "7 PM-8 PM"
      Show the events's month and date
      Do the beginning and end dates occur in the
      same month (set with a custom field)?

         Yes: Is there an expiration date set, and is it
         later than the start date?

            Yes: Show just the numerical date
            (so the final event might read "June 10-11")
               Is an end time set?
                  Yes: Show it
         No: Is there an expiration date set,
         and is it later than the start date?

            Yes: Show the month and numerical date (June 30-August 1)
               Is an end time set?
                  Yes: Show it

It's a pretty complex way to handle the date, but given the goals and restrictions, it was the best solution we found at the time.

That about covers our favorite EE pieces of Viget.com for now, but we're going to keep working with EE and posting any new ideas we find. If you have any suggestions on how to reuse, tighten up, or totally redo some of these ideas, we'd love to hear them in the comments.

Matt Crest said on 06/23 at 08:25 PM

Wow. That’s some nifty IF statement work.

The long-form written out version is nice too. Thanks for posting. As an EE noob, these specific tutorials are great because they show the true potential of what can be done.

Eli Van Zoeren said on 06/23 at 08:45 PM

Thanks for the tips, I have a project coming up where I will need a profile page for each user and have been trying to decide how best to do that. It’s good to have an outside opinion.

In you last example, you could also save yourself a custom field and add to the iffy goodness by replacing {if same_month == “yes"} with {if {entry_date format="%m"} == {expiration_date format="%m"}}. I always figure it is better to have complexity in the code rather than the front-end, when possible. (Better not to have complexity at all...but in this case I don’t see how to avoid it.)

Doug Avery said on 06/24 at 05:09 AM

@matt glad it was helpful! I definitely had problems getting ramped up in EE without specific tutorials, I think they help a lot more than the official documentation does at times.

@Eli I actually never thought that kind of conditional was possible, but I tried it out and it works! Looks like quotes are actually needed around the compared values, like so:

{if “{entry_date format="%m"}" == “{expiration_date format="%m"}"}

I’ve updated the post to include this change. Thanks for the tip!

Eli Van Zoeren said on 06/24 at 08:13 AM

I’ve been enjoying this blog for a while now...glad I could give something back!

I am currently running that exact conditional on one of my sites without the quotes, I don’t know why it insisted on them for you. Weird.

Doug Avery said on 06/24 at 08:56 AM

We’re not running the most up-to-date version at the moment, which might be the issue. I should finish the upgrade process and then see what changes.

Adam said on 06/29 at 10:36 AM

Another great behind-the-scenes EE post. I love your clever full_override solution for custom layouts. I’m sure I’ll be using that at some point in the future. You also helped me look at categories differently.

It probably wouldn’t make sense for just your employee profiles, but there’s always Solspace’s User Module for when you want to use a regular template for user profiles.

Doug Avery said on 06/30 at 07:50 AM

@Adam, I think you’re right in that the Solspace module wouldn’t help us much, but it looks fascinating nonetheless. Thanks for the link!

Trackback URL: http://www.viget.com/trackback/1170/

Comments for this entry were closed after 60 days.

Name:

Email:

URL:

Not a robot? Prove it by entering the word below.


Remember my personal information

Notify me of follow-up comments?