November 13, 2010
This last week's development on Drupal Commerce has been a flurry of exciting commits for me. Ever since the first demos I've been talking about how the Add to Cart form will be able to use field data to let customers choose products by their field values instead of their titles. Similarly, I've talked about dynamically updating field data on the page so images, prices, and other fields are re-rendered to reflect the currently selected product.
Until now these features have been relatively low priority, as we focused on the other major core systems. However, with the release of 7.x-1.0-alpha3, they have finally moved from the hypothetical realm into code awaiting your testing.
Inherited product fields, dynamic options, and dependent attributes... oh my!
The screenshot shows three features of Drupal Commerce product displays:
- Product fields from the default product are pulled into the node display via the Product Reference field. The pictured display actually references 12 separate products representing different color / size combinations.
- The Add to Cart form display formatter turns product reference fields into forms. It creates attribute select lists using field data from the referenced products, only including options that actually exist on products referenced by the field.
- As options are selected on the form, the product fields displayed on the page are updated to reflect the currently selected product. The options on the form also update to show newly available options, allowing for attribute dependencies to any depth in their order of appearance on the form.
In other words, as I choose a color option, the size select list updates to only list sizes of the shirt available in that color and the image can change to show me wearing a different shirt. If the size is changed to a more expensive option, the price on the page updates accordingly. I'm sure this description hardly does the features justice, so I'll get a screencast and live demo up next week for you to play with.
(On a side note, if you need to do full form replacement yourself, be sure not to target the form using its id. Each time it is rebuilt, the HTML id is incremented by drupal_html_id(), so the replacement will only work the first time. Instead, either target a container within the form or some other selector that won't change each refresh. This cost me a few hours. )
Other features of note in this release include:
- The order edit form has taken shape with vertical tabs, revision logging, and working customer profile reference fields.
- All currencies have been defined with updates to the Price field accommodating multi-currency stores. Currency rounding now accommodates currencies like Swiss Francs, which rounds to the nearest twentieth (thanks to das-peter). Only known currency formats are implemented, so you may need to open an issue for yours to have proper formatting (i.e. $100.00 vs. 100.00 USD).
- The Payment module received more work since the last release to support credit card payment methods. I've created Commerce Authorize.Net as a proof-of-concept and example implementation for other developers to follow. (Some code specific to that module right now will be abstracted to Payment, like a general handler for prior authorization captures.)
More information and a full commit log are available in the release notes. I'm very grateful for the efforts of community contributors, especially das-peter for his help on the currency issues and our Entity API and Rules integration.
There's still plenty of work to be done, so feel free to join is in the issue queue.
October 9, 2010
Blog's been a bit sleepy as of late... so sleepy it managed to miss out on two trips to Europe for DrupalCon Copenhagen and E-commerce Paris 2010, the first Drupal Commerce alpha release, and my daughter's first steps and first birthday.
"What gives, dad?"
Does it work to just say they were all awesome and move on? My wife can testify that many things in my life back up to a point where a dearth of activity stymies said activity's resumption... or simply put, when I stop doing something I want to do for an extended period of time, I find it hard to start again.
Ok, </introspection>. I'm breaking the ice with a happy announcement - I managed to package up Drupal Commerce 1.0-alpha2 in the wee hours of the night.
The release notes provide an overview of changes with a full commit log since the alpha 1 at DrupalCon CPH. The new alpha and my development installation profile have been updated for Drupal 7.0-beta1, though I still need to update our Fields to take advantage of display formatter settings.
The highlights of the release are:
- Functioning Payment module with integration points for on-site methods (demonstrated by the core Null payment module) and redirected payment services (demonstrated by PayPal WPS integration in Commerce PayPal). Payment service integrators would do well to jump on board so we can take care of any workflow issues, especially for redirected payment services.
- SimpleTest base class for Commerce testing provided by Jeremy Blanchard, complete with documentation and related issues. It's just begging for you to start using it...
- Updates to the price object to allow Rules based transformation of prices prior to purchase and/or display; still requires some implementation as outlined in a rambling Google Doc.
- The Specification handbook at DrupalCommerce.org has received some love to get it up to speed. A major goal for the project was to not have undocumented major releases, so I've begun documenting the various system components and will then move onto the system overviews. For now only the sections on our info hooks and core API utilization have meaningful content. Feedback on the structure is most welcome.
- A host of bugfixes and API / variable naming standardization. The documentation effort really helped here, so I expect similar results as I catalog the Commerce Entities and Fields.
The release is also accompanied by an alpha release of Address Field, a dependency the Customer module uses to collect name and address information during checkout according to the xNAL standard. This module took some massaging to get working, because it defines a Field that uses #ajax to update address form elements based on the country chosen. It now works no matter where I embed the widget, even if I'm doing something crazy like embedding the customer profile entity's field widgets in the checkout form... but that's a topic for a follow-up blog post.
That's all to report for now. There's plenty more activity and good contributions coming through the issue tracker. As this alpha's release was dependent on a fully functioning Payment module, the next alpha release will be dependent on the full implementation of dynamic pricing as outlined in the doc above. We'll also push to get as far as we can on the order administration UI and show some love to product and line item display in the meantime. We'll stay busy!
July 16, 2010
Developing Ubercart was a wonderful experience. I learned a lot about software development, Drupal, web technologies, and worldwide communities. At the end of my time leading the project, I could also see that thousands of people were using the software to sell products for profit, bring people together at events, and raise money for many worthy causes and organizations. Seeing now a book written to help even more people do these things is an added treat.
I was asked to review Drupal E-commerce with Ubercart 2.x published by Packt and received an e-book and three physical copies to give away at DrupalCon San Francisco. I started reading the e-book on that trip and finally finished on the plane home from DrupalCamp Colorado.
What follows is my review with a chapter by chapter analysis of the content. What I saw was very encouraging, and I applaud the authors, George Papadongonas and Yiannis Doxaras, for their effort in delivering this work to the community. My review picks up on what's great about the book, what could use some work, and who I think would benefit most from owning it.
Before the in-depth analysis, here's a quick summary:
- This book provides a very comprehensive look at Ubercart's major core and contributed features, modules, and themes (free and commercial). It's the most expansive summary of all that Ubercart offers I've seen. The value in this exposure can't be overstated, and it's for this aspect of the book alone that I'd recommend it to anyone diving into building e-commerce sites with Ubercart.
- The book includes chapters and content introducing the user to Drupal itself. I suppose this was to make it a standalone resource for building e-commerce sites on Drupal, but I think the book would have benefited from a sharper focus on Ubercart itself. Referencing one of the many general Drupal books, even titles published by Packt itself, would have been sufficient for topics such as installation, search engine optimization, and theming.
- The book introduces all of Ubercart's features but doesn't often address the reasons for a particular feature's existence or the best practices for implementing it. For example, chapter four could have provided a lengthier introduction to product attributes so readers have a fuller understanding of the reasoning behind the system, when and how to use them, and what to look out for (like losing adjusted SKUs when attributes are modified on a product). If the book were made shorter by removing the general Drupal instruction, the content could easily be made up in those sorts of discussions.
- In other areas, the discussion is particularly well thought out and helpful. I thought the payment discussion was great.
Read on for the chapter by chapter summary and review. As I said in the first point, I'd recommend this book to any newcomer to Ubercart. Experienced users might not find much new here but could still employ the book as a desk reference. Anyone looking to write modules and customizations for Ubercart won't find much here - but that wasn't really the point of the book.
For more information, resources, and errata, you should refer to the book's own website, http://www.drupalubercartbook.com/.
Chapter One: Getting Started
The first chapter provides a quick introduction to both Drupal and Ubercart that hits all the high points of using the software to build your store. It then takes the approach of showing the end product first - there are screenshots and a feature walkthrough demonstrating the store that the reader will build by the end of the book. Good idea!
Chapter Two: Installation of Drupal and Ubercart
The second chapter covers installation of both Drupal and Ubercart and should successfully guide a newcomer with some technical experience through the installation process. If anything, it might be a little too thorough. Because the book isn't really a Drupal primer, many of the details and "gotchas" for general Drupal installation could have been left out entirely. Furthermore, instructing readers to download Ubercart from Ubercart.org instead of http://drupal.org/project/ubercart seems risky, as the Ubercart downloads page has a history of lagging behind releases.
I was impressed that the book included a section on the UberDrupal installation profile, and in the first update of the text it would be good to mention that drupal.org now automatically packages distributions based on installation profiles that include all the necessary modules. To install Drupal and Ubercart now, one would simply have to grab the latest distribution from http://drupal.org/project/uberdrupal ... but now I'll need to go make sure all the modules in that package are up to date!
Chapter Three: Basic Configuration
The third chapter runs through various administration pages and configuration forms describing what a lot of the forms and settings do. As with the previous chapter, I would've left the general Drupal information out, but the chapter doesn't suffer from having it in there. The main problem with the approach as I see it is the chapter introduces all the various Ubercart settings, but at this stage in the book they're divorced from any greater context. Descriptions of some of the settings aren't helpful without greater knowledge of how Ubercart works in general, so the discussion would have fit better in a chapter specifically introducing the topic (e.g. introducing order panes, invoices, and settings in a chapter on Ubercart orders).
Chapter Four: Managing Categories, Products, and Attributes
Chapter four is spot on when it begins by emphasizing planning. Ubercart offers multiple ways to simplify product catalog creation and administration, and the authors provide a good overview of how to get it done. I was pleased to see a description of product classes, but it would have been greatly improved by a discussion of how to take advantage of their default attribute settings. Those sorts of tips should save store administrators plenty of time.
I did feel like the introduction of Tagadelic was a little distracting and might recommend placing all the contributed module discussions in the later chapters on customizing / optimizing the store. I also think it would be helpful for the order of the information to be adjusted, so that readers are instructed on how to make attributes and product classes before bothering with information on product kits and especially product importing (as that will often require classes and such to be configured in advance). In fact, given the poor support for product importing in general, I'd almost want to just punt that whole section off into an Appendix or at least a separate chapter where the pitfalls and strategies for the topic can be addressed.
Chapter Five: Managing Shipping and Packaging
Chapter five introduces the configuration of shipping quotes and Ubercart's limited product packaging functionality. It includes a brief description of the Conditional Actions system, but in my experience with training, there is not near enough material here. You could really include an entire chapter on navigating the CA interface, explaining the concepts, and walking through screenshots of setting up predicates. Most people won't understand how to add conditions and actions, especially when it comes to grouping, logical operators, and argument selection. While I wouldn't expect an introductory book to be a full manual on the system, the instructions and few screenshots scattered through the chapters seem insufficient for getting started.
Chapter Six: Managing Taxes and Payments
Chapter six covers taxes and payment, two essential parts of any online store. Figuring out taxes is one of the trickiest things for any online store, especially stores selling physical goods across multiple tax jurisdictions. The chapter provides a sound overview of Ubercart's tax features, but this is one of the rare places in the book where appropriate contributed modules aren't mentioned. Users should be aware of tax modules providing out of the box support for specific tax jurisdictions (like some countries / states) and VAT.
The payment discussion shines in this chapter as one of the most thorough and helpful of the entire book. It includes a lot of the background information and best practices instruction that I felt would've benefited other discussions in the book. Many readers, especially those new to e-commerce in general, will find the payment section extremely helpful.
Chapter Seven: Managing Customers and Orders
Chapter seven begins with a helpful introduction to the order management features of Ubercart, including a nice explanation and graphic explaining the difference between order states and statuses. The chapter is full of screenshots and instruction for administering orders and reminds me that in spite of Ubercart's limitations, there's still quite a lot you can do with it.
The chapter does mostly gloss over the packaging and shipping features on order screens, but those are seldom used features and the mention seems sufficient. Readers should get a firm grasp on how to create and administer orders from this thorough chapter. There are some minor errors in the chapter, like saying that Ubercart's reports depend on Views (they're actually stand alone and worse off for it), but nothing that should confuse newcomers to Ubercart. Also, the chapter helpfully introduces readers to CiviCRM but fails to mention how to setup an ongoing integration between it and Ubercart using the contributed integration modules.
Chapter Eight: Customizing the Frontend
Chapter eight is something of an enigma. It's full of useful information, but it feels more like a brain dump of the many ways to theme a Drupal site (from free and commercial themes to rolling your own using Zen or from scratch) than actually customizing a frontend for an Ubercart store. I'd expect to find information on theming product pages, the shopping cart, the checkout form, and order invoice templates. Instead, the chapter offers many different ways to prepare a custom Drupal theme without really going deep into any particular topic. This is one of those more general Drupal introductions where recommending a reference book on Drupal theming at the beginning and then explaining how to specifically customize the Ubercart frontend would've been more helpful.
Chapter Nine: User Interface Enhancements and Techniques
Chapter nine takes a look at using contributed modules to improve the user experience of your store for the purpose of increasing sells. I didn't find the cross-selling section useful beyond finding out that the Recommender module has an Ubercart integration module. It never went beyond introducing a couple methods without really applying them, and I didn't see mention of the UC Upsell module which was written specifically for thus purpose. However, the chapter moves from there to a much more useful section introducing using Panels, Views, and the Ubercart Views module to merchandise products.
The rest of the chapter introduces some key contributed modules that enhance the shopping cart / checkout form and others for offering discounts and coupons to your customers. The AJAX cart block module mentioned is a great way to get around the limitations of Ubercart's static cart block when page caching is enabled. The UC Discount Framework module doesn't get mentioned (likely due to its development status), but it provides an additional way to provide discounts using the Conditional Actions system. You might never use all the modules mentioned in this chapter (though you're bound to use some), but simply knowing they exist will help you greatly as you build out different types of sites.
Chapter Ten: Optimizing and Promoting Your Store
Chapter ten walks through various optimization topics regarding search engine optimization, marketing your site, improving performance, and enhancing security. It starts by walking through configuration of various modules recommended by the SEO Checklist module. Following the chapter on cross-selling products, I expected Packt to mention the Drupal SEO Book here.
There are certainly more ways to market your site and improve performance than are mentioned, but the chapter should provide a good start for new store owners to get a leg up. In what seems to be an oversight, the Ubercart Google Analytics module isn't mentioned in the discussion on Google Analytics, but enabling that module will cause actual sales data to be reported to Google Analytics for review in addition to goal completion.
The appendices offer some nice extra information, like how to take advantage of the UC Hotel module to sell hotel reservations using Ubercart in Appendix A. It won't be useful for many people, but for those who need it I'm sure it will be helpful. That's why it's an appendix I guess! The remaining appendices list all the modules referenced in the book (there's a lot!) and a host of free and commercial Drupal themes that are ready for e-commerce use and/or specifically designed with Ubercart in mind.
June 8, 2010
UPDATE: Over two years later, this post is still one of the most highly trafficked on my blog. Since then I've learned a lot and shared many other tips and modules. This past year I was honored to be a contributor to The Definitive Guide to Drupal 7, which includes many other great tutorials like this. I highly recommend it if you want to get the latest and greatest information on developing for Drupal.
On two separate sites I've recently had to implement a rotating image banner that could optionally be linked to paths within the site or to external URLs. Originally I tried a (mostly) self-contained module that matched the feature set called Rotor with some success but really needed greater flexibility. Undaunted, I rebuilt the functionality using a custom content type, a few CCK fields, ImageCache, and Views with the Views Slideshow plugin.
This tutorial is for Drupal 6 and walks through the exact steps I took to build the slideshow for the relaunch of Biblical Training, including enabling the right modules, creating the content type, defining the ImageCache presets, and building the View.
Hope it helps!
1. Enable the dependent modules.
To get started, you'll need to download and install the modules listed below. It takes quite a few modules to reproduce the feature set of a single module, but building a complex feature from scratch has advantages in flexibility and reusability. Most of these modules are standard "utility" modules on many Drupal sites that can be used for a variety of purposes on your site.
Enable the following modules through the /admin/build/modules form. In the CCK fieldset enable Content, FileField, ImageField, Number, Option Widgets, and Text. In the ImageCache fieldset enable ImageAPI, ImageAPI GD2 (or ImageAPI ImageMagick if your server supports it), ImageCache, and ImageCache UI. In the Other fieldset enable Advanced Help. In the Views fieldset enable Views, Views Slideshow, Views Slideshow: SingleFrame, and Views UI.
2. Create the Banner content type.
Browse to /admin/content/types/add on your site and create a new custom content type with the name set to Banner, the type set to banner, and a meaningful description for your site's administrators. A body field for the banner is unnecessary, so you can expand the Submission form settings fieldset and disable the field by clearing the Body field label textfield. I leave the Workflow settings defaulted as Published and Promote to front page, but you might adjust these depending on the editorial needs for your banner content. Finally, because comments are unnecessary for banners, I set the Default comment setting in the Comment settings fieldset to Disabled.
3. Add the necessary CCK fields.
I use three CCK fields: an image field, a textfield used to collect the link path, and an integer select list used to provide a sort order for banners in the Views. At this point, I'll mention that an alternate method of ordering banners would be to use the NodeQueue module, but it was unnecessary for my use cases.
To add the fields, browse to your Banner content type's Manage fields tab using the operations link from the content type list page:
First, add a new field positioned under the title labeled Image with banner_image in the name textfield. The field type should be File and the widget type should be Image. I like to store my banner images in a specific files directory, so I provide a file path in the Path settings fieldset (like banners). I didn't enable ALT text (i.e. what appears if an image does not load), but I did enable Title text (i.e. what appears when you hover the mouse over an image). Last, in the Global settings fieldset I mark this field as required.
Second, add a new field positioned under the image labeled Link path with banner_link in the name textfield. The field type should be Text and the widget type should be Text field. I don't adjust the default settings for the field at all, but you can feel free to require a link path for every banner image or include a help text informing your users to enter a Drupal path or a full URL.
Third, add a new field positioned under the link path labeled Sort order with sort_order in the name textfield. (I don't use a banner specific name for this field because I reuse the sort order field on multiple content types.) The field type should be Integer and the widget type should be Select list. In the Global settings fieldset I mark this field as required. The other settings are tricky. Even though it's more than most sites will reasonably require, I tend to allow a sort order of 1 to 50. So, in the Minimum textfield put 1, in the Maximum textfield put 50, and in the PHP code textarea for the Allowed values setting put the following snippet:
return drupal_map_assoc(range(1, 50));
When you view the fields screen for the content type, it should now look like this:
4. Define a couple of ImageCache presets.
While your site will likely require your banner images to have uniform dimensions, it's not necessary to enforce them on the file upload. Using the ImageCache module, we can define presets that are collections of actions performed to transform an image on display to your desired specifications. These transformed images will be cached in your site's files directory so they don't have to be regenerated each time they're viewed. On my sites, I use one preset for the image as it should appear in my rotating banner and a smaller preset for use in lists. I still recommend to my administrators to attach files to the proper size for the full banner to avoid any scaling or cropping issues.
Browse to /admin/build/imagecache/add, enter banner_full as the Preset Namespace, and submit the form. Next click the Add Scale and Crop link and enter the precise pixel width and height the image should be in your rotating banner. For this example, I'm using a pixel width of 690 and height of 230. When you click the Create Action button, you will be returned to the preset's configuration page where you can preview the transformed Druplicon image beneath the form to make sure ImageCache is transforming images properly.
Repeat this process using banner_small as the Preset Namespace and a smaller set of dimensions. I divided by 3 to use a pixel width of 230 and height of 77.
With the ImageCache presets defined, we need to go back and edit the Banner content type to use these for image display. From its edit form, click its Display fields tab. On this form, set the Image field's label to be hidden, its teaser to be banner_small image linked to node, and its full node to be banner_full image linked to image.
5. Create the rotating banner View.
Now that we have a Banner content type defined and the ability to resize its images on display, it's time to create the heart of the rotating banner. Creating Views isn't for the faint of heart, but it's an essential skill for a Drupal site builder or developer. Without explaining Views in too much detail here, I'll simply list the steps to recreate the precise View I use.
- Browse to /admin/build/views/add and create a new Node View (the default type) with the name rotating_banner.
- Change the style to Slideshow by clicking the Unformatted link next to the Style label in the View's Basic settings. When you do this, it will bring up a second settings form with several options you can adjust dealing with the animation and behavior of the slideshow. For now, it's enough to leave them all to their defaults by just clicking the Update button.
- I don't make any assumptions about how many images the rotating banner should have, even if 10 or more is overkill. Stil, I click the 10 link next to the Items to display label and set it to 0 for unlimited.
- Click the + link by the Fields area to add a new field to the View. Scroll down the checkboxes list an check Content: Link path. This field won't actually be displayed, but we need it to be present in the View for use as the link path for the image banner. Simply check the Exclude from display checkbox and click the Update button.
- Click the + to add another field, this time selecting Content: Image. In the settings for the field, check the Output this field as a link checkbox to expand some link settings. In the Link path textfield, put the token [field_banner_link_value]. Further down in the field settings form select the None option in the Label radio buttons. Last, in the Format select list, choose banner_full image and click the Update button.
- Click the + link by the Sort criteria and add Content: Sort order. Leave the settings for the sort order to the default and click the Update button.
- Click the + link by the Filters area and add the following filters all at once: Node: Promoted to front page, Node: Published, and Node: Type. For the promoted and published filters, choose the Yes option. For the node type filter, choose Banner in the Node type select list.
- Last, we just need to add a page display to the View. In the top left of the View edit form locate and click the Add display button beneath the select list with Page already selected. The only thing to adjust on the new display is the path, so click the None link by the Path label in the Page settings area. Enter banner in the textfield and click the Update button.
- Click the Save button beneath the View's settings area. Your View's settings should now look like the following image:
6. Display the View on the front page.
There are several ways to display this View now. The way I've implemented it for my sites, I set the default front page in my Site information settings form at /admin/settings/site-information to the rotating banner page's path, banner. I then added additional content to the front page using blocks.
Depending on the regions in your theme, you might alternately set the front page to something else and use a block display on the View instead of a page display. That's really up to you and how your site is architected.
Whatever you do, once you've set it up, start adding banner images to the site and they should appear. The way the View was setup, only banner images marked as Promoted to the front page will appear. If you're using a rotating banner in multiple places, you might only include that filter on a specific display of the View. Really, what we've done is just a beginning, and there's almost nothing you can't do to customize this for your site.