Pages

Friday, August 30, 2013

Implementing a donation system with Drupal Commerce

The Drupal Commerce module is a great solution for anyone who wants to have a shop implemented with Drupal. It doesn't matter if you configure the shop from scratch or if you use an installation profile, you can have a shop in a very short time. Most of the time is just configuration, almost no coding required.
By default, you can create your products, set the prices for them, categorize them, create rules for tax handling, use different payment gateways (also with the help of some contributed modules) and many many other things. Unfortunately there is one thing you cannot do just with configuration: a donation system. The main problem in the donation system is that the amount of each donation can be different. If your donation system has only fixed amounts, then there is no problem, all you have to do is to create one product for each donation amount. But when the amount is variable, then implementing this using only configuration may not be so trivial (if not possible at all).
I will explain next how we deal with this case, when we have to build such platforms.

The concept

If we go a bit deeper and check how the Drupal commerce system is built and how the price of the order is calculated, we can see that each line item from the order has a unit price field, that usually is populated with the price of the product to which it is associated. So the user clicks on the button to add the product to the cart, and this triggers the creation of a line item in the order that will have the unit price of that product. But in our case, the price of the product is variable, because it is about a custom amount that the user wants to donate, so we cannot really use that price to populate the line item. We will have to handle this by ourselves, to implement some logic that will populate the unit price of the line item with the amount of the donation. The solution involves site configuration, as well as some coding.
The main idea is to have a new field on the line items (a price field) that will be populated with the value the user wants to donate, and then using a rule that will be triggered on the event “Calculating the sell price of a product” to put the value from our custom field into the price field of the line item. The reason why we do not just put the value directly in the line item price field, when we create the line item, is that the price of the line item can actually be updated later. For examplecommerce_cart_order_refresh() would update the price of the line items. In this case, our code that populates the unit price will not be executed, and we will not be able to maintain the correct price of the line item. That's why we use that rule that fires on the “Calculating the sell price of a product” and we store the amount that is being donated in a separate field that will not be altered by any other code.

The setup

And this is how it works:
add a price field on the line item type (admin/commerce/config/line-items/product/fields), with the name: field_variable_price
create a product with the SKU “donation” that has the price set to 0
add a rule that updates the price of the line item

 
For the coding part, an example can be found in a sandbox project. An important remark for the coding part is that we actually have to create the order and add the donation product to the order by ourselves, because we have to populate the field_variable_price with the amount that the user want to donate.
The code also has a page: /donate and a configuration form /admin/commerce/config/donation_amounts where some predefined amounts can be configured. For more details about the coding part, you can just check out the sandbox project.
While finalizing this blog post I discovered that, since starting to implement this feature on a recent project, a new module called Commerce Donate surfaced on Drupal.org which might be interesting for you too.

The new face of Omega 4, Part II

Omega 4 looks very different than Omega 3. When we first wrote about some of their differences back in January, we reported on four major themes:
  1. Zones & Regions
  2. SASS
  3. Pluggable Layouts
  4. Polyfills
After getting our hands dirty for the first time with the new theme, these were the most obvious changes. And while these topics are still important to note for those still looking to make the transition from 3 to 4, there are other improvements to the theme which also deserve attention.
In general, Omega 4 is a vastly more flexible version of its predecessor. As a follow-up post to our original findings, here are even more reasons why:

Extensions

Essentially, Omega 4’s theme extensions have been improved in four areas: layout, development, asset management, and compatibility improvements. We’ve touched on the new layouts before, but there’s more to them you should know:

Total L​ay​out Control

With Omega 4 Layouts, you can define how pages are laid out through code. There are no predefined breakpoints which makes for a completely fluid (truly responsive) site.
Layouts can be added via the “layouts” folder of an Omega 4 sub-theme.
Given the file structure in the example above, you could even switch your layout contextually with a hook_omega_layout_alter function:
This feature completely removes the need for the Delta module commonly used with Omega 3.

Devel​opment, made easier

Some cool new features have also been added to assist in the theme development process. In a nutshell (and taken from a great resource, Omega 3.x vs. Omega 4.x - Comparing Apples and Oranges), Omega 4 provides the following development additions:
  • Rebuild theme registry on page load
  • Rebuild CSS and JS aggregates on page load
  • Browser width indicator
  • LiveReload
  • Region demo mode
(Some pretty spiffy improvements if you ask us...)

Asset Management

As in the Magic module, Omega 4 now makes use of Frontend best practices like moving JavaScript files to the footer, and excluding certain Javascript & CSS. Polyfill libraries (as discussed in our first Omega 3 post) are also readily available through the theme’s settings.
These features make for better site performance and happier Frontend lives.

Browser & Viewport Compatibility

Conditional HTML classes are now added, for example “lte-ie9” in Internet Explorer versions 8 and below. This is a big win when optimizing sites for cross-browser consistency.
There’s also Cleartype support for Windows, customizable Viewport metatags, and ChromeFrame & IE Edge support.

Drush Integration

Next — the powers of Drush! If you navigate (via the command line) to a Drupal site with Omega 4 & Drush installed, there’s a slew of new Omega-specific commands, with two notable ones being omega-wizard (owiz) and omega-guard (ogrd).
Omega-wizard is a guide through the process of setting up and enabling a subtheme, and omega-guard enables the use of Omega 4‘s LiveReload built-in support.
Have a look at the others as well. Omega-export and omega-revert can greatly assist during site-deployments.

Preprocess, Process, and Theme Files

And if you’re a developer fed up with the days of having cluttered, unorganized template.php files, this one’s for you. :)
Omega 4 allows the themer to provide separate preprocess, process and theme functions to their Drupal site via organized, structured theme files. These files are autoloaded and are no longer to blame for overloaded template.php files, especially in the case of themes requiring a heavy load of PHP.
Also, according to fubhy, the Omega 4 developer, “this feature has been improved tremendously since 3.x and performs much better now.”

SMACSS

Finally, and if you didn’t know already, SMACSS is where it’s at. Omega 4 has adopted the “Scalable and Modular Architecture for CSS” principals and applied them directly to both of its available subtheme starterkits.
If you’re not familiar with SMACSS however, it’s basically just a guiding set of methodolgies to write maintainable CSS. Due to CSS’s flexible nature, it’s easy to make a mess of it. SMACSS helps with that.
And if you’re going to use the omega-wizard Drush feature, go ahead and choose the “extended” starterkit. It has a fuller SASS structure included with more modular components, making it easier to understand and organize your project and different Drupal components.
So that's it for now! We're still loving Omega 4. Are you?

The new face of Omega 4

We've been big cheerleaders for Omega as a responsive base-theme for Drupal for a while now… since around the time of DrupalCon London. And although the community has HUGELY embraced Omega… making it the second-most-installed Drupal theme after Zen, there has always been a bit of controversy surrounding Omega 3 in terms of how it approached responsive web design.
Some of those critiques included:
  • Omega 3 was more "adaptive" than truly responsive (due to the definition of set breakpoints based on device widths).
  • Configuring Zones and Regions was confusing and laborious.
  • Omega 3 did not take a mobile-first approach.
The good news is that Omega 4 has addressed these issues of its predecessor head-on. In fact, Omega 4 looks quite a bit different than Omega 3.
If you're more of a skimmer, here's a quick overview (in list-form) of how Omega 4's changed:
  • Zones & regions: GONE
  • SASS out of the box
  • A new (pluggable!) layout & grid system
  • Optional polyfills for CSS3 & HTML5 support in older browsers

Zones & Regions

For starters, zones and regions have been totally abandoned. There have been many folks who have tried to explain how to wrap your head around how to configure these things. Remember this screen?
Well, no more. Omega 4 has gone back to the tried and true page.tpl.php file which is a) standardized for Drupal and b) better for markup control. Themer purists will undoubtedly appreciate this reversion.
Edit: For those that want the old UI we are working on it to make that an option and will allow you the same power that to control things as was in 3.x but now we're not forcing it on everyone. This is largely what's holding back the RC release but we're working quick to fix that! (See excerpt from Cellar Door's comment below.)

SASS

Omega 4 ships with SASS out of the box. This addition will be hugely important for keeping Omega a cutting-edge contender as a popular Drupal base-theme.
And for those looking to improve their SASS skills, the media queries, variables, and mixins that ship with Omega 4 are a great learning tool for novice or intermediate SASS-ers:
Just look at all that SASSY goodness!

Pluggable Layouts

In the Omega 4 theme settings, you can now choose to enable layouts. Layouts are a new feature that provide functionality much like what theDelta and the Context modules achieved together. Essentially, you can have completely unique layouts for different sections or pages of your site.
There is currently only one available layout, Epiqo, to use as a starting point, but it's chock-full of more SASS techniques.
If you'd like to employ this built-in feature in an upcoming Omega 4 project, simply copy the Epiqo layout into your sub-theme, and rename it and its contents much in the same way you would when manually creating a sub-theme. From there, you should add only layout-specific code, and nothing relating to styles (colors, typography, etc...).

Polyfills

For anyone responsible for browser testing or device testing, polyfills are becoming essential scripts to include on your site. Polyfills provide themers the ability to quickly enable CSS3 and HTML5 technologies in legacy browsers, saving hours of testing and work-arounds.
In Omega 4, there are already 5 optional scripts available to enable across your site:
While this certainly doesn't mark every improvement, these are the changes we felt most during the development of our first and second Omega 4 projects.

How To: Loading ads in a Drupal AJAX call asynchronously

While working on LikeMag, one of our most recent releases, we were confronted with a challenge: loading ads during a Drupal AJAX (Asynchronous JavaScript and XML) call. This is how we solved it.

The issue

By definition synchronously loaded JavaScript can only add objects like files, content or ads to a page's structure until it is entirely rendered. An additional complexity that can occur while working with third-party advertising providers is that you can not control the performance of their infrastructure. Which means either you accept this risk or try finding a way to mitigate it. We went for the latter.
At this point it is important to stress that it is common practice for third party ads to use the document.write method which only works for the synchronous loading approach. To learn more about the synchronous and asynchronous loading of remote tags I suggest you read the article "synchronous vs. asynchronous tags - what’s the big deal?" on the krux blog. In our case however it became apparent that our solution had to include the asynchronous approach.
While researching possible solutions I found the following tools:
The issue with the the majority of them were, that active development or support wasn't visible, except for PostScribe. This solution offers the following features:
"Krux PostScribe enables the type of tag execution required by most ad formats in an easy-to-use-and-deploy format. It leverages innerHTML to ensure reliable, fast ad delivery."
"Unlike other innerHTML-based solutions (e.g., writeCapture, ControlJS, and OpenTag), Krux PostScribe seamlessly enables the “immediate writes” upon which most ad formats depend."
Which in plain English enables the quick rendering of the page to the user and allowing the ads to respond in their own time without reducing the user's experience.

How to use PostScribe

Download PostScribe directly from its github repository.
Include these files in your project:
/htmlParser/htmlParser.js /postscribe.js
Here is a small example:
<div id="myAd"></div> <script type="text/javascript"> $(function() { postscribe('#myAd', '<script src="remote.js"><\script>'); }); </script>

Our use case

As mentioned in the introduction this solution stems from LikeMag which, besides utilizing PostScribe, is a responsive website and uses the Isotope library to arrange items over the screen automatically depending on the viewport.
Since there are no free lunches on the web, LikeMag has to monetize too and one of their models is built around ads. So in order to deliver the perfect balance between content and ads for every viewport, we had to find a way to render the perfect amount after the identification. And that is moment the where PostScribe comes into play.
Instead of injecting the ads right into the Drupal view and slowing down the loading of the rest of the page, we just print the standard items. In a next step the system iterates over the items and adds the appropriate amount of ad containers to the content with jQuery. (These containers can be addressed with PostScribe, because PostScribe works best when the DOM is ready.)
LikeMag.com Ad
"But where is the AJAX you mentioned in the title?", I hear you cry. So let's talk about it right now. When we scroll down on LikeMag, which besides being responsive is a smart infinite scroll site too, new items will be loaded through an AJAX call. So here we can use PostScribe as we did before. The only thing that we have to check, is that we do not add ads to already "adified" content. In our case we can check if the view-item was already processed by Isotope.
Code from View, partially modified by isotope and postscribe
See the code as an example:
Drupal.behaviors.ViewsLoadMore = { attach: function(context, settings){ if ($(context).hasClass('view')) { $isotope = $('.view-id-articles .view-content'); $isotope.isotope('insert', $('.view-id-articles .view-content .views-row:not(.isotope-item)'), function(){ isotop_load_more_init(settings); Drupal.behaviors.advertisment.loadads() }); } else if ($(context).find("html").length == 1){ // If it contains html, it is the first behavior call. isotop_load_more_init(settings) } } } 
loadads: function(){ $('.view-articles .views-row.views-row-ad').once('postscribe',function(){ if(typeof(cachebuster) == "undefined"){var cachebuster = Math.floor(Math.random()*10000000000)} if(typeof(dcopt) == "undefined"){var dcopt = "dcopt=ist;"} else {var dcopt = ""} if(typeof(tile) == "undefined"){var tile = 1} else {tile++} var string = '<scr'+'ipt src="http://ad-emea.doubleclick.net/adj/likemag.ch/;' + dcopt + ';tile=' + tile + ';sz=300x250;ord=' + cachebuster + '?"></scr'+'ipt>'; postscribe($(this), string); }); } 
As you can see we process only the newly loaded items from the Drupal view and exclude the already processed items.
With this solution we are very flexible to deliver the page content as fast as we can while not depending on the speed of an ad-provider.