I would like to preface this by saying a couple things about myself to provide some context for this article. I was able to develop Dreamsocket.com over the course of about four months with a little development and testing over another month while development on our first product was wrapping up. This is truly a testament to Drupal and Ubercart and the great community that exists around both. I say this because this project encompassed many firsts for me personally. It was the first big project I had worked on after college and my first experience with Drupal and web programming in general. Previously, I had tried to stay as far away from HTML and website development as possible, so the four months of time I spent on the site included a month or so devoted to research. It has been a great experience though, and I would (and will) recommend Drupal to anyone looking to build a professional website no matter their level of expertise in the field.
Dreamsocket
Dreamsocket is an Atlanta, GA based software company. We develop web applications for some very well-know companies in the entertainment industry. Our work has been featured in the New York Times, has been cited across the web, and has won numerous awards. With this project, we set out to build a website that would establish a presence for Dreamsocket on the web, provide a place to sell our products, provide support for those products, and enable us to interact with our customers. I will cover a couple custom modules and techniques we used to reach these goals.
Company Image
Although we have developed web apps that have been seen by millions of people, we have never had a company website. Being our company's first visible presence on the web, we wanted the entire site to reflect Dreamsocket's image. Every section needed to seamlessly mesh together in style as well as function. This is why we gravitated towards Drupal in the beginning. We have seen many websites that feel pasted together, they grab a blog from one place then use a forum module from somewhere else and eventually combine all the parts to come up with a functional website, albeit not the best looking. Drupal gave us a way to maintain a common look and feel across every section from submitting forum posts to purchasing products which was invaluable to us.
Initially, we were a little frightened upon glancing at the urls of pages on our Drupal test site. Since look and feel is important to us we wanted the urls to appear logical to the average person and to clearly indicate where the content on screen is located in relation to previously viewed pages. We wanted neither the word "node" nor numbers to appear in any of our urls if at all possible. Fortunately, with clean urls, Pathauto, and a little trickery we were able to get logical and hackable urls across the entire site.
For example, by default Drupal displays user ids rather than usernames in users' accounts i.e. user/5/view. We added a couple lines of code to hook_user() to create aliases for each user when their account is created. So, that same url could be user/jsmith/view, for example. Here is a snippet of that code:
function ds_accountpath_user($op, &$edit, &$user, $category = FALSE) {
switch ($op) {
case 'insert':
// Generate aliases
if ($user->name) {
$name = check_plain($user->name);
path_set_alias('user/'. $user->uid . '/profile', 'user/' . $name . '/profile');
...
}
case 'delete':
// Delete aliases
The added benefit of cleaning up the urls so much was that we were able to essentially copy the url onto the breadcrumb. In my opinion, this is considerably more logical than letting modules use drupal_set_breadcrumb() and most likely setting the breadcrumb to something that matches neither the url nor the page titles. The breadcrumb and url match exactly and both are hackable across the site.
Store
Since our main reason for building the site was to sell software, the first thing we did after choosing Drupal was to pick a cart module. We ended up going with Ubercart after looking over all the other options and we are very happy with the choice. It had every feature we were looking for and their support and documentation were robust and very similar to Drupal's. The several times I ran into an issue that I could not solve with their documentation, my forum posts were answered by someone on their dev team (usually Ryan) within the hour.
Our current and future products will be distributed via downloads. Immediately after a customer makes a purchase all the files for their product are added to a tab in their account pages where they can access them it at any time. Ubercart's File Downloads module provided this functionality although we modified it to fit a couple specific needs.
We needed to support products with several "sub products" and multiple versions per sub product. For example, when a customer buys our Media Framework, it comes with an Actionscript 2, Actionscript 3, and Flex version. Additionally, we will release upgrades for each version and will allow the customer to download back versions as well as each new upgrade. As a result, we modified Ubercart's File Downloads module to get a layout that is logical and will not become cluttered at some point in the future when there are many downloads for each sub product. Here is an image of a download pod in the finished Files section.
Product Support
The heart of our product support lies in our Documentation section which contains language references as well as instructional articles related to our products. The Documentation section was constructed with Drupal's built in Book module. To create the language reference sections we developed a little script to run against the output of ASDoc and AS2API for Actionscript 3 and Actionscript 2, respectively. Both are tools for generating HTML documentation from source code. Although they are great for standalone documentation, they don't work very well if imported directly into Drupal.
The script we developed cleans up the HTML files and processes the links so that, using a slightly modified version of the Import HTML module, the links work after the files are imported. Our Media Framework has over a hundred classes, so it was not realistic to create and submit each page by hand. Also, we will be updating our language references regularly as we add comments to our code so being able to update the documentation in place and maintain user comments was important, and thankfully the Import HTML module supports this.
Community
We believe establishing a dialogue with customers is key to developing relevant applications. We don't want to isolate our development process from the people we are developing for. Creating areas of the site to gather input was very important. One of these sections is our Issue Tracker. When browsing the Drupal contrib modules, I was very impressed with how all the projects and associated issue queues were managed. We decided to develop a similar system in the spirit of the Project and Project Issue modules but slimmed down a lot to fit our minimal needs.
We didn't need any of the functionality of Drupal's Project module for several reasons but mainly because our "projects" are products that we are selling and we intended to have whole sections of the site devoted to providing information about them; we didn't need any extra pages for each project. Our distilled version of the Project module is essentially just a content type and a couple other fields that we use to organize them. Then we have a Project Release content type built on top of the Project module which is what feeds the version numbers for our Issue Tracker and Release notes pages.
A couple issues arose with this approach mainly since all content in Drupal is considered a node. Several of our content types, Project, Product, FAQ and Release Notes, are never intended to be browsed to directly. Our products are only displayed in the Store section using a view from the Views module, our FAQ's are only displayed in views as well, and Release Notes are displayed with a custom module. We did not want these content types to show up in the search or have any content at the address of their urls. Our solution veered from the "Drupal way," perhaps, but it has worked so far. We simply used the Content Template module to hide all content at their urls, providing a link to their actual View, and wrote a SQL query that runs after Drupal's cron to remove these content types from the search index:
db_query("DELETE FROM search_index WHERE sid IN (SELECT nid FROM node WHERE type IN ('product', 'project', 'project_release', 'release_notes', 'faq'));");
The Future
We plan on making many improvements over the coming months and have already started working on a couple. Perhaps the largest looming improvement is to move everything over to Drupal 6. The site was built on Drupal 5 because Ubercart wasn't stable for Drupal 6 throughout most of our development phase. Most of all though, we look forward to hearing ideas from our customers and will make improvements based on that input.
Comments
Awesome, awesome job. Your
Awesome, awesome job. Your site looks very sharp, and I'm impressed by the customizations you've put into the various cart components, esp. the file downloads fulfillment. Hope the store sells well!
----------------------
Drupal by Wombats | Current Drupal project: http://www.ubercart.org
Very nice looking site. I can
Very nice looking site. I can tell you spent much time on it. I am interested to know how you built the pages with two levels of navigation. Your products/actionscript-media-framework/in-action page and products/actionscript-media-framework/faq pages appear to have the same navigation but the FAQ one is javascript unlike the others. Are they built with views and static html? Are they just page content types?
Question about Media Player
Site looks great. Congrats. Great tip about user paths and path manipulation in general.
For the free media player page, did you use swfobject API to make it easier to embed? Just curious as I need to do some tests with dreamsocket player embedded in a Drupal content type.
Anyway, great job on the site!
Yes, I did use swfobject API
Yes, I did use swfobject API for all the flash content and I definitely recommend it. It should work great to embed the Media Player in any content type.
Thanks for the comments!