Blog
Drupal + XSPF
Having worked on many Drupal sites with music players I have used a number of solutions but never quite found something that worked perfectly for me. Recently I have done a number of sites that required the ability to have a play list that is easily managed by the client without messing around with xml files and ftp uploads. There are a couple solutions for this but i am going to focus on one solution which is using the XSPF Playlist module.
Step 1: Enable the modules.
- XSPF Player - http://prdownloads.sourceforge.net/musicplayer/xspf_player-0.2.3.zip?dow...
- XSPF Playlist Module - http://drupal.org/project/xspf_playlist
- Views 2 - http://drupal.org/project/views
- CCK - http://drupal.org/project/cck
- Upload - Comes in Drupal core.
Step 2: Create your content type.
next you'll want to create a custom content type to upload the mp3 files to(admin/content/types/add) , I named mine playlist items.
You can get rid of the body since you won't need it unless you want to use the node in another page. All you are going to need is a title and the file attachment field.
Also note that the file size is going to be constrained by what your server settings will let you upload so if you want to add large size mp3's that will need to be tweaked. Your ability to do this will depend on your hosting situation.
Step 3: Configure XSPF Playlist.
After you have created your content type you will need to enable it in XSPF to allow the module to create playlists from the nodes (admin/settings/xspf_playlist).
Here you can title the playlist that will be created as well. In content settings you select your CCK and click save. Now there's a little bit of a trick i found, if you are using the admin menu module you will need to flush your cache on it for the playlist settings to show in the menu. You can then go to this link through admin menu or /admin/settings/xspf_playlist/name-of_your_content_type. Here you will select the field that contains the mp3 and thumbnail to show in the player. (Please note that currently there seems to be a problem in the D6 version with correctly pulling the thumbnail. You can, however, set a default cover to show for all tracks.
Step 4: Create your view.
Once you have your content type and your XSPF settings done you will need to create a view to generate the xml for the player to read. Start by creating a new view, the main display you will need is the FEED display.
here's a list of the basic settings to get it going.
- items to display:Unlimited
- Style:XSPF Playlist
- Row Style: Node XSPF
You'll need to give it a path i just used /playlist for mine and then as always you'll need some filters so select node type and as a rule i always add node published: Yes
you can then sort the view however you choose and save your work.
Step 5: Embed the player in a block/page.
The last thing to do is set up the actual player. To do that you will need to place the downloaded swf somewhere in your drupal install's file structure. I like to place all my swf's in my themes directory to keep things clean. Once you have done that you will need to either create a page or a block, set the input format to full HTML and enter the following embed code in in the body:
<object type="application/x-shockwave-flash" width="400" height="170"
data="location-of-the-player-swf?playlist_url=feed-url">
<param name="movie"
value="location-of-the-player-swf?playlist_url=feed-url" />
</object>Set the location for the swf to the path from the root of your install and enter the path to the feed you set up for the playlist_url and that's it. You have an audio player that requires no xml knowledge to maintain.
This will get you started with a basic set up from there you can use views sorting, filters and arguments to control your playlists however you want. Depending on your ability there are many players out there to skin and use on your site that accept XSPF playlists.
Drupal + SlideShowPro
If you aren't yet aware of this, we here at Fuse absolutely love challenges. Building highly interactive websites around the jQuery and jQuery UI libraries allows us to create a great experience while eliminating our reliance on flash.
Now, as good as Javascript libraries are at replicating flash features, there are instances where it is hard to look past a good flash component. While there are hundreds of Javascript based slideshow and gallery components with varying feature sets, we have become real fans of SlideShowPro for its adaptable slideshow capabilities. A large feature set and excellent handling of images (and video) makes SlideShowPro a very versatile tool.
When we finally decided SSP was the way to go we took a look at the Drupal modules available to make our lives easier. The SlideShowPro module looked like the obvious choice, but with theme overrides for cck fields and filters and what not, we figured there had to be a more straightforward way. SSP normally takes a custom XML file as an argument to display a list of images, but it also has the ability to read MediaRSS files. Something that views handily has a module to provide support for. It's as simple as creating any kind of view and outputting the file names of the images, choosing a MediaRSS display type and you're in business. This means you can use one node with multiple file attachments, multiple nodes with a cck file upload field, run the images through imagecache, etc....
So let's show you how to make you're own. The variations on how you can get images to SSP are so great that we're just going to show you one implementation using a content type with a single cck file upload field. We're assuming you're comfortable with downloading, installing and enabling modules and building basic views on your own.
Before you get started you'll need: CCK, Views, MediaRSS, a copy of SlideShowPro standalone, and finally a copy of swfobject.
Step 1:
Create your content type and the required filefield with the image widget.
Step 2:
Create a handful of nodes of the content type you setup in step 1 and upload a different image for each one.
Step 3:
Create your slideshow view as a typical node view. Set your filters to only pull the new content type you created and add your image upload field from the 'Content' group using the format pull down to select the 'path to file' option.
Step 4:
Add a new display to your view of type 'Feed' and change the row style to 'Media RSS'. Give your new display a path (this is the path that SSP will use to get the image list) and hit save.
Step 5:
Depending on where you want the slideshow to show up, (block or page) create the appropriate content and in the body add the follwing:
<script type="text/javascript" src="/sites/all/themes/themename/js/swfobject.js"></script>
<script type="text/javascript">
// swf finder
function thisMovie(movieName) {
if (navigator.appName.indexOf("Microsoft") != -1) {
return window[movieName]
} else {
return document[movieName]
}
}
// SWFObject embed
var flashvars = {
xmlFilePath: "/path-to-your-media-rss-view",
paramXMLPath: "param.xml",
initialURL: escape(document.location),
useExternalInterface: "true"
}
var params = {
base: ".",
bgcolor: "#000000",
allowfullscreen: "true",
height: "400",
width: "300",
wmode: "opaque",
quality: "best"
}
var attributes = {
id: "ssp"
}
swfobject.embedSWF("sites/all/themes/themename/swf/slideshowpro.swf", "page", "400", "300", "9.0.115.0", false, flashvars, params, attributes);
</script>Step 6:
Put your swfobject somewhere in your themes folder. We usually put ours in a 'js' subfolder of our theme.
Step 7:
Put the slideshowpro.swf and the params.xml files into your themes directory. Again, we usually put ours in a 'swf' subfolder.
Remember to change the paths to the appropriate locations of your files and edit the xmlFilePath to the path you gave your view in step 4.
That's it! Load up the page or block you just created and you should have a brand spankin' new fancy slideshow that you can easily add and remove images from.
While this guide will certainly open up some options for you, its far from "That's it!" in terms of possibilities.
An example of more advanced ingegration can be seen on Talula Babaton, which we recently launched. It takes what we have outlined here, and adds external navigation and descriptions, which are both managed from the same view! Keep your eyes open for a follow up post where we get a little deeper into customizing SSP.
How to create a custom Drupal AJAX module
Ajax is becoming a standard, oft asked for feature in our Drupal sites. Clients like it because it makes their sites look 'slick'. We don't like it because it causes a few PITA's especially when it came time for us to integrate with Drupal's FAPI (Form API). Not so anymore. After needing to dig in and make a couple custom AJAX modules for a clients site, we got pretty familiar with the ins and outs of what is appropriately called AHAH. Now we're sharing it with you.
In this tutorial we'll show you a simple example of the anatomy of an AJAX module. Hopefully it will help you get started on your own AJAX fueled custom module(s). We'll assume you're somewhat comfortable with getting your hands dirty with a Drupal site
What is AHAH?
AHAH (Asynchronous HTML And HTTP) let you update web pages dynamically without refreshing the whole page. The advantage of it is that it decreases wait time for the user and requires less server resources.
You can download the example module used in this tutorial. To try it out, un-zip it to your /sites/all/modules folder and enable the module. Then go to Site Building -> Blocks and place the "AHAH Example" to the desired region of your site.
Step 1 - Create your .info file
name = AHAH Example
description = A module for demonstrating how to implement AHAH in Drupal.
version = "6.x-1.0"
core = "6.x"
project = "ahah_example"Step 2 - Create your .module file
i.e. ahah_example.module
Step 3 - Define your menu callback function
<?php
/**
* Implementation of hook_menu().
*/
function ahah_example_menu() {
$items = array();
$items['ahah_example/add'] = array(
'page callback' => 'ahah_example_add',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
return $items;
}
?>In the above code we're doing two things. The first is to tell Drupal what URL is going to handle the AHAH request. In the example it's the $item arrays key (ahah_example/add). The second is to tell Drupal what function within our module is going to process the incoming request. In this case it's ahah_example_add.
Step 4 - Create a block
<?php
/**
* Implementation of hook_block().
*/
function ahah_example_block($op = 'list', $delta = 0, $edit = array()) {
global $user;
switch ($op) {
case 'list':
$blocks[0] = array(
'info' => t('AHAH Example'),
);
return $blocks;
case 'view': default:
switch ($delta) {
case 0:
$block['subject'] = t('AHAH Example - My Recent Pages');
$block['content'] = drupal_get_form('ahah_example_form');
break;
}
return $block;
}
}
?>Step 5 - Create your form
This is where you use Drupal's form API to define which form elements you'd like on your page.
<?php
/**
* Implementation of hook_form().
* A form to allow the user to create a new page node and show the 5 most recent pages created by the currently logged in user.
*/
function ahah_example_form($form_state) {
global $user;
// create a DIV to show the output of the AHAH request
$form['new_row_wrapper'] = array(
'#type' => 'markup',
'#value' => '<br><div id="ahah-example-new-row-wrapper" style="clear: both;"></div>',
);
// show links to the latest 5 page nodes
$sql = "SELECT n.nid, n.title
FROM {node} AS n
WHERE n.uid = '%d'
AND n.type = 'page'
ORDER BY n.nid DESC
LIMIT 5";
$db_result = db_query($sql, $user->uid);
while ($row = db_fetch_object($db_result)) {
$form['node_'.$row->nid] = array(
'#type' => 'markup',
'#value' => '<div><a href="'.url('node/'.$row->nid).'">Node '.$row->nid.' - '.$row->title.'</a></div>',
);
}
// create a form to allow the user to enter the new node's title and body
$form['new_title'] = array(
'#type' => 'textfield',
'#title' => "Title",
'#size' => 40,
'#required' => TRUE,
);
$form['new_body'] = array(
'#type' => 'textarea',
'#title' => "Body",
'#required' => TRUE,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Add Node'),
'#submit' => array(),
'#ahah' => array(
'path' => 'ahah_example/add',
'wrapper' => 'ahah-example-new-row-wrapper',
'method' => 'prepend',
'effect' => 'fade',
'progress' => array('type' => 'bar', 'message' => t('Please wait...')),
),
);
return $form;
}
?>The most important part of the above code is:
<?php
'#ahah' => array(
'path' => 'ahah_example/add',
'wrapper' => 'ahah-example-new-row-wrapper',
'method' => 'prepend',
'effect' => 'fade',
'progress' => array('type' => 'bar', 'message' => t('Please wait...')),
),
?>The path tells Drupal where to send this form post. In this case it's the menu item we setup in Step 1 of this tutorial. When the user clicks "Add Node" the form values will be passed to our menu item, then onto the function we specified (ahah_example_add).
Wrapper is used to define the HTML element that we want the returned AJAX data to show up in. In our example it points to a <div> with an id of "ahah-example-new-row-wrapper".
Method defines the behavior of the returned HTML. In our case we chose 'prepend' which will add the data at the beginning of the <div>'s contents. Other possible values include: 'replace' (default), 'after', 'append', 'before', 'prepend'.
Effect defines the jquery effect the new data will be brought into view with. Possible values: 'none' (default), 'fade', 'slide'.
The progress option let's you choose from one of two default Drupal progress indicators. The typical throbber or if you're expecting your AJAX call to take a bit longer (e.g. file uploads) you can choose a progress bar instead.
You can read more about the Drupal FAPI and the AHAH features at Drupal Form API - AHAH property documentation.
Step 6 - Create your function to handle the AHAH request
Depending on what values you're expecting from the form post, you'll need to change the error checking logic and the logic that handles the submitted data, but if you're just following along these should sufficiently cover the basics.
<?php
function ahah_example_add() {
global $user;
$output = '';
//error checking
if (!$user->uid) {
$output .= '<div class="messages error ahah-example-msg">Access denied.</div>';
}
if ($_REQUEST['new_title'] == '') {
$output .= '<div class="messages error ahah-example-msg">Please enter a title</div>';
}
if ($_REQUEST['new_body'] == '') {
$output .= '<div class="messages error ahah-example-msg">Body field is required.</div>';
}
//no error, save node
if (!$output) {
$node = new StdClass();
$node->type = 'page';
$node->status = 1;
$node->uid = $user->uid;
$node->title = $_REQUEST['new_title'];
$node->body = $_REQUEST['new_body'];
node_save($node);
if ($node->nid) {
$output = '
<div class="messages status ahah-example-msg">Successfully saved your page.</div>
<script type="text/javascript">
$("#edit-new-title").val("");
$("#edit-new-body").val("");
</script>
<div><a href="'.url('node/'.$node->nid).'">Node '.$node->nid.' - '.$node->title.'</a></div>';
} else {
$output = '<div class="messages error ahah-example-msg">An error occurred, we cannot add your page at this time.</div>';
}
}
//remove status message after 10 seconds
$output .= '
<script type="text/javascript">
$("#edit-new-title").val("");
$("#edit-new-body").val("");
setTimeout("$(\'.ahah-example-msg\').remove();", 10000);
</script>';
//send output back to browser
drupal_json(array('status' => TRUE, 'data' => $output));
}
?>More useful reading:
The Drupal 6 Form API
Another excellent tutorial on AHAH and Drupal 6
Project Management with Open Atrium
We’ve just recently made the switch from Active Collab to Open Atrium in the office for our project management and ticketing system. We made the decision to switch based on our needs and the fact that we know Drupal so if we need something that OA doesn’t have, we can build it.
One of those things is time tracking. We first took a look at what was out there for time tracking in Drupal. Of the few modules that seemed to be in development, none really hit the target for what we needed or how we really felt time tracking should work. We felt that time should always be contextual and it should fit into the flow we already have setup.
So... introducing time_tracker!. We've just started work on this module so functionality is sparse at the moment, but we'll be working hard on it until it's done. It's built with the case_tracker module and OA in mind, but will work with any nodes that have commenting enabled and have the time_tracker bit set.
On top of tracking your time, you can also report on it. We've included one all encompassing view to filter all time data, but have plans to build out more specific views for reporting. Graphing anyone?
Our long term goal for both time tracking and OA is a desktop Air app for handling some basic functionality of OA. Notifications of new tickets and a time built in for adding time entries. Beautiful.
If anyone has any ideas for this module head to http://drupal.org/project/time_tracker and add a feature request.
Shiny new Drupal solution for Canada's X-Weighted!
On Jan. 1st, working with Anaid Productions, Slice Network & Mod7 Communications, Fuse launched phase 2 of xweighted.com. The popular Canadian weight loss reality show airing on Slice Network had a mandate to bring X Weighted to the masses through the web. The result is a 26 week online National Challenge that leverages social networking, weight loss tools, professional guidance & let's not forget the sweet sweet prizes all in an effort to help Canadians lose weight.
On opening weekend of the National Challenge, the site had nearly 4000 participants sign up with a combined total weight loss goal of 113229 pounds! While the National Challenge is now closed to new sign-ups, anyone is welcome to join and start their own 26 week weight loss challenge. The site continues to grow with hundreds of new participants signing up each week.
Drupal was chosen as the platform because of it's strong social networking and content management features out of the box. As one of Vancouver's Drupal Specialty shops, Fuse was brought on to provide Drupal consulting, configuration, custom module development and theming. With stunning interaction design by Mod7, it was a pleasure for us to build. Some of the bigger challenges we faced with this project included Drupal driven Flash components, Drupal iPhone application interfacing, and custom modules using Drupal's Ajax handlers. Using the services module we managed to get most of the data the Flash components and iPhone apps needed while a custom module took care of a few of things that Drupal didn't have access to on it's own. The last piece of the puzzle was working with Drupal's Ajax implementation. Fuse created several unique modules that gave users the ability to create and edit content seamlessly and in a way they have become accustomed to in the most successful social networking sites.
About The Show
"For three seasons, X-Weighted has followed unique and courageous individuals on their precarious weight-loss journeys. The brave participants exposed all in their daily war on fat and their brutal honesty, openness and perseverance made for compelling and inspiring viewing. Now, moving into its fourth season, X-Weighted turns its focus on a Canadian epidemic - obese families."
Drupal Module of the Week: IE Unlimited CSS Loader
During a recent build, we ran into an issue that left us scratching our heads. IE refused to load the main stylesheet. Normally, something like this would be caused by a faulty configuration file, but seeing how all other browsers worked fine, it came down to IE being IE.
As it turns out, IE has an undocumented limit of 32 individual stylesheets. Now, this isn't a huge concern for production sites since we compress all stylesheets to keep the load time to the minimum. It is however a problem in a development environment, where IE debugging needs to take place.
This is where IE Unlimited CSS Loader steps in. It will use the @import method to load an infinite amount of CSS files allowing for smooth theme debugging. There are some concerns with using this module in production sites, as there is a potential performace hit and possible conflicts with other modules, but it is a lifesaver in a development environment. Once development is done, simply turn off the module and those concerns go out the window.
Fuse launches new site for Kentwood Floors
Kentwood Floors, one of Canada's premier flooring manufacturers, has experienced substantial international growth over the past few years and as part of a rebranding and launch of several new product lines Kentwood required a revamped web presence that would serve to propel and better manage their international expansion. They required a site that more accurately represented their products and brands, while providing region specific information in multiple languages.
Fuse teamed up with Chemistry Marketing and Design to produce the new kentwoodfloors.com. Drupal was a perfect fit for this project as it allowed us to rapidly deploy a site that served both the regionalization and multilingual requirements for the site. Among the advanced features of this site are:
- Full regional support allowing Kentwood marketing staff the ability to target products and information to specific regions and in multiple languages
- Multiple theme support for each brand
- Ability to add and update product data, images, files and sitewide content
- Custom AJAX 'where to buy' search tool
- Custom product and dealer information import – automating the process of adding hundreds of products and dealers to the website
Some of the Drupal Modules we utilized on this project:
Anatomy of a Drupal Project
The Fuse project management team has been meeting lately with the purpose of refining our project execution process. Now, we had a fairly good general process in place for executing a standard web project, but we found we were shoe-horning Drupal projects into this process. Drupal, as some of you may know, has it's own unique set of development requirements and since 75% of our projects are Drupal based these days, we wanted to optimize that process for Drupal.
We've come up with a what I think is a good start on refining our process for Drupal projects and would like to share this document with the Drupal Community. We view this as a work in progress and welcome your feedback. What are we doing that you aren't? Are we missing something that you include in your process? We'd love to hear from our fellow Drupalists.
Have a look: Anatomy of a Drupal Project
We've also been refining our Drupal development and deployment workflow which we will be touching on in an upcoming post.
Drupal Module of the Week: Prepoulate
Prepopulate is a handy module for auto filling fields on a node creation page with values from the url. This way you can provide 'content creation' links on your Drupal site, prepopulated with things like taxonomy terms, profile data, etc...
In our case we have a client that wanted a user to be able to submit a preformatted letter to a third party outside of the site with selected profile information attached. Within the users profile we've provided a link to the create node and have passed a bunch of the users data along in the url. All the user then has to do is make edits where needed and hit send. A pretty painless way of getting Drupal to do what we want. Don't forget you're limited to the maximum size of the URL so it's great for text fields and options, not so much for passing around blog posts and definately not for files.
It works on the title and body fields of nodes as well as any text/numeric fields in CCK. There is some talk of incorporating POST support so if you're handy with that sort of thing head to the issue queue and help them out.
Drupal Module of the Week
Our first installment of "Drupal Module of the Week". A weekly post about a new module that we like around the office, currently using in a project, or some that we're even incorporating into our Fuse Drupal Base Install.
So right off the bat, we're going to cheat just to get up to speed and cover all the obvious basics. These are the ones that we blindly download for every new Drupal install. Most of us black out and let our auto-pilot click in. The next installment will be a lot more in depth.
- CCK - The Content Creation Kit allows you to create and add custom fields to nodes. On a fresh install of Drupal, you get a few content types and you can create a few more, but they're all stuck with only having a title and a body. With CCK you can add any number of fields, with any type of content within them. Turn on the filefield and you can upload pdf's, grab the imagefield and your content type can handle images like a pro. Numbers, maps, audio files, etc... On top of all that, it integrates so awesomely with our next favourite module. CCK is working it's way into Drupal core for version 7, but for now it's one of our favourite contrib modules.
- Views - Views gives you almost SQL level control over your data. If you want to combine a couple different content types, remove a few fields, display the number of comments and only show 6 results with a pager, you can do it with Views.
- Token - Token is basically a dynamic search and replace for data on your site. You can use it with a ton of modules to mark a placeholder and have the token replaced with a title, username, node id, etc... Pathauto takes advantage of the token API quite extensively.
- Pathauto - Pathauto helps us out with our clean urls. On sites that publish a lot of content, pathauto takes the title, strips out penny words and non-alphanumeric characters and replaces spaces with dashes to give you a nice looking SERF. There are a bunch of options included as well that allow for even more flexibility and customisation including different rewrite rules depending on content type and taxonomy term used.
- Administration Menu - Once you start themeing up a storm and remove that side menu that used to give you such quick access to the admin section, you'll end up having to type in /admin an awful lot. Which can make you feel like you're a little more badass, but it does get tedious. Enter Administration menu. Really nice, simple, and gives you quick access to everything you need. It can also be stripped down with permissions to give a nice content creation menu for your site without impacting your site design at all.
- Devel - Devel is a handy module when you're developing a custom module or when you're developing a custom theme. It's a sort of Firebug and debugger all in one for Drupal. One of the handiest features is it's ability to "walk up" the theme stack to find out exactly what template file is controlling the output of any dynamic data on the screen. Also, stop using print_r and var_dump. Use dpr() for print_r() and dvr() for var_dump().