LCDTV.net - New Online Magazine Using Drupal 6
LCDTV.net is an online magazine dedicated to LCD TV information and LCD TV Reviews. It employs several journalists to stay up to date with the latest technology news related to LCD televisions, has a large database of the latest TV specifications, and offers enthusiasts the opportunity to write in-depth TV reviews receiving full byline credit getting paid for their efforts.
PropDrop Web Development and Marketing completed the installation, configuration, and custom theme development for the Drupal site. PropDrop is a Louisville Web Design company that specializes in Drupal for small businesses, and also manages a portfolio of various topical websites. For most sites, PropDrop works almost exclusively in Drupal. For LCDTV.net in particular, where we needed robust user management and permissions, tightly defined and unique content types, and easy ways to group and manage that content, we knew Drupal was up to the task to ensure fast development and ultimate success.
Organization and Content
The site had to accommodate a vast breadth of information and be easy to find. As a result, we ended up making use of Drupal’s core Taxonomy system more than we ever had on a previous site, but still combined it with practical uses of CCK Node Reference fields.
There are three key content types: TV Series, TV Models, and TV Reviews.
A TV Series (like the Samsung 9000 series of televisions) has a "Brand" taxonomy term. TV Models (like the Samsung UN46C9000) have a node reference field that references the correct TV Series. Likewise, the TV Review content type references a specific TV Model node.
We also used taxonomy vocabularies for TV Models for certain specifications that were important for shoppers looking for information, like TV Size, HDMI port numbers, Resolution, Price Range, and Features like Internet connectivity. CCK fields picked up the slack for a majority of the specifications.
To get a handle on the taxonomy display, we overrode the default taxonomy display URLs with a simple view that displayed node teasers. This way we had more control on the ordering of nodes within a term (thanks to the nodeorder module), how many nodes to display per page, whether to use ajax. To dictate what exactly shows up for each node teaser on a taxonomy page, each content type has a customized .tpl.php theme file with only certain fields allowed to display if ($page == 0).
The only part we didn’t have control over were the taxonomy page headings. Because of the robust Page Title module, the actual HTML page title was fully under our control, with each term and vocabulary having a unique title. Because we were using a views override, the term name could be included, but displaying nodes by Brand, TV Size, or News categories each call for significantly different headings, both from user experience and SEO standpoints, and Views doesn’t allow this by default.
The solution was easy, if a little inelegant. Within the custom theme’s page.tpl.php, we checked the URL structure to determine if it was a taxonomy page, and then added the appropriate heading suffix based on the vocabulary.
<span style="color: #000000"><span style="color: #0000BB"><?php </span><span style="color: #007700">if (</span><span style="color: #0000BB">arg</span><span style="color: #007700">(</span><span style="color: #0000BB">0</span><span style="color: #007700">) == </span><span style="color: #DD0000">'taxonomy' </span><span style="color: #007700">&& </span><span style="color: #0000BB">arg</span><span style="color: #007700">(</span><span style="color: #0000BB">1</span><span style="color: #007700">) == </span><span style="color: #DD0000">'term'</span><span style="color: #007700">) {<br> </span><span style="color: #0000BB">$term </span><span style="color: #007700">= </span><span style="color: #0000BB">taxonomy_get_term</span><span style="color: #007700">(</span><span style="color: #0000BB">arg</span><span style="color: #007700">(</span><span style="color: #0000BB">2</span><span style="color: #007700">));<br> if (</span><span style="color: #0000BB">$term</span><span style="color: #007700">-></span><span style="color: #0000BB">vid </span><span style="color: #007700">== </span><span style="color: #0000BB">2</span><span style="color: #007700">) { </span><span style="color: #0000BB">?></span></span><br> LCD TV Listings<br> <span style="color: #000000"><span style="color: #0000BB"><?php </span><span style="color: #007700">} elseif (</span><span style="color: #0000BB">$term</span><span style="color: #007700">-></span><span style="color: #0000BB">vid </span><span style="color: #007700">== </span><span style="color: #0000BB">1</span><span style="color: #007700">) { </span><span style="color: #0000BB">?></span></span><br> Size LCD TV Listings<br> <span style="color: #000000"><span style="color: #0000BB"><?php </span><span style="color: #007700">} elseif (</span><span style="color: #0000BB">$term</span><span style="color: #007700">-></span><span style="color: #0000BB">vid </span><span style="color: #007700">== </span><span style="color: #0000BB">8</span><span style="color: #007700">) { </span><span style="color: #0000BB">?></span></span><br> Questions<br> <span style="color: #000000"><span style="color: #0000BB"><?php </span><span style="color: #007700">} elseif (</span><span style="color: #0000BB">$term</span><span style="color: #007700">-></span><span style="color: #0000BB">vid </span><span style="color: #007700">== </span><span style="color: #0000BB">10</span><span style="color: #007700">) { </span><span style="color: #0000BB">?></span></span><br> LCD TV News<br> <span style="color: #000000"><span style="color: #0000BB"><?php </span><span style="color: #007700">} elseif (</span><span style="color: #0000BB">$term</span><span style="color: #007700">-></span><span style="color: #0000BB">vid </span><span style="color: #007700">== </span><span style="color: #0000BB">11</span><span style="color: #007700">) { </span><span style="color: #0000BB">?></span></span><br> Related LCD TV News<br> <span style="color: #000000"><span style="color: #0000BB"><?php </span><span style="color: #007700">} </span><span style="color: #0000BB">?></span></span><br> <span style="color: #000000"><span style="color: #0000BB"><?php </span><span style="color: #007700">} </span><span style="color: #0000BB">?></span></span>
Archiving
New television models come out every year, and the site will always need to be weighted toward newer releases, while still maintaining all of its old content and model information. The answer was to have a vocabulary for the year the model or series came out. And then we limit the taxonomy view to only this year and the last. This is something that won’t come into play for a while, but we wanted to have the process in place and prevent major changes when the time came. This solution is simple and allows the old content to be hidden easily while still existing in the archive, all by just changing the filter on a single view.
Expert Reviews in a Certain Format
In depth, user-submitted reviews would be one of the critical pieces of the site. But in order to keep quality up and maintain the content in a format we wanted without investing heavy editing hours, a simple solution was required.
We wanted writers to provide their thought on four aspects of the TV model they were reviewing: Picture, Audio, Features, and Value. And then have an Overall section where they can sum up their thoughts. Each section also needed a number score on a scale of 1 to 10. The overall score is calculated with a hook_nodeapi call when the node is saved, creating a number that is the average of the other four ratings, with the picture rating triple-weighted.
Text areas are powered by a rich text editor using the WYSIWYG module, and they can insert and manipulate images with the Insert and Image Resize Filter modules.
To allow a bit more flexibility, we also added 2 optional sections that users can fill out if they so desire. One was an introduction section so they can lead into the review, a text area. The other is a strengths/weaknesses section, where they can list out quick bullet points of highlights of the review. These are CCK text fields that allow for unlimited entries, that are then printed out in the theme as bulleted lists, as you can see in this review.
All of these are then arranged and printed out in the correct order in the review.tpl.php file. Other than punctuation and slight grammar mistakes, no editing is required on our part. No rearranging content, no renaming sections, no emailing the reviewer asking for additional info.
This may seem rigid and laborious, but we have had good feedback from some of our reviewers. Because there is very little ambiguity, they know exactly what is expected, and it saves them time in the long run.
When reviews are saved, they default to unpublished. This is done for editing purposes and screening of basic quality, and to help minimize spam.
For the star ratings displayed on the review, we do some CSS and Javascript transformation based on the numeric rating.
Javascript:
$.fn.stars = function() {<br> $(this).each(function() {<br> // Get the value<br> var val = parseFloat($(this).html());<br> // Make sure that the value is in 0 - 5 range<br> val = val > 10 ? 10 : (val < 0 ? 0 : val);<br> // Calculate physical size<br> var size = 17 * val;<br> // Create stars holder<br> var stars = $('<span class="expert-stars"><span></span></span>');<br> // Adjust stars' width<br> stars.find('span').width(size);<br> // Replace the numerical value with stars<br> $(this).replaceWith(stars);<br> });<br>}<br><br>$(document).ready(function() {<br> $('span.expert-stars').stars();<br>});
CSS:.node span.expert-stars, .node span.expert-stars span {<br> display: block;<br> background: url(img/stars-gray.png) 0 0 repeat-x;<br> width: 170px;<br> height: 16px;<br>}<br><br>.node span.expert-stars span, span.expert-stars span {<br> background-position: 0 -16px;<br>}
Why not use VotingAPI and Fivestar? Well, we d: for the quick reviews on the actual model pages, and it works great as usual. And it was possible to use them, with Fivestar CCK fields and multiple voting axis, but we still felt that the scope we were going for was outside the bounds of the modules. We wanted reviewers to just enter a concrete integer, and have reviews sortable by those integers in Views. But we also wanted control of the styling and color of the stars, making them a different color than the quick reviews. Fivestar’s stylings, by default, effect all instances, and that’s not something we wanted to wrestle with at this time.
To prompt user and make them aware that they can write a review on a particular model, we display text and a link telling the visitor that they can write the expert review if a published review is not found for the model they are viewing. If an expert review has already been written, the overall rating as well as a link to the review is shown. We do this with a quick database call in a custom module, as the Nodereferrer module seemed a bit of an overkill for our situation. However, for those who do not want to write custom code, Nodereferrer would fit the bill for this problem.
To Forum, or Not to Forum
Besides commenting on reviews and news stories, we wanted another way for users to interact. The most obvious choice is using Advanced Forum, and this has served us well on some other sites. However, several active and large forums already exist that cover LCD TVs, and we didn’t want to be seen as their competition, as they could eventually become a great source of cross promotion.
So we decided to do a Yahoo Answers type of functionality. Users can ask questions, receive answers, and vote on those answers.
This was possible with Userpoints, the Vote Up/Down module, and the Userpoints Karma module. Vote Up/Down can add VotingAPI powered forms to comments for certain node types (in this case, Questions), and User Karma ties into Userpoints so every vote for a comment adds a certain number of points to the comment author.
The only thing missing after all of this is sorting comments by vote. Given that core only let’s you sort by comment post date, we again had to override the comment display with a view to get access to the needed sorting. But how to replace the default comments on nodes with this view? Enter the Comments In a View module. All you have to do is enable it to get it working.
Managing a Multi-Writer Team
When you have multiple authors writing about the same topic, and they don’t each have a separate and specific "beat", there is a risk that they will duplicate work on stories that are similar or the same.
To help obviate this, we created an Upcoming News view, that only displays unpublished news items. Writers are instructed to first create the news item with the title of the news story they are working on, so it will show up in this list. Likewise, before they begin working on something extensively, they need to check this list to make sure no one else has already claimed the same thing.
But having unpublished nodes creates a permissions problem. Only roles with the "administer nodes" permission can view unpublished content, and we don’t need news writers to have full access. So we used the view_unpublished module which gives us granular control over what roles can view unpublished nodes of a certain content type.
The Future
Real world users and browsing patterns are needed before adding additional pages, or changing the structure. As traffic rises and we collect more data, we will be able to add additional groups of relevant content and more useful sidebars.
And as users begin adding quick reviews and asking/answering questions, we will be able to add more incentives, like a Featured or Top Users list, and then allow them to use their earned karma to trade in for free stuff. Given Ubercart’s integration with Userpoints, this will be relatively simple.
Conclusion
Yet another success for Drupal and the community. Even with needed functionality that Drupal core lacked, there was usually a module to fill the gap quickly and help manage a site that will have a large amount of content in the future. The power of the Views module, in particular, never ceases to amaze me and continue to reveal additional power on each subsequent use.
Drupal version: Drupal 6.x