MJC SEO & Web Development Blog

Drupal views templating tutorial: Outputting the respective image fields of multiple associated taxonomy term references

Using a custom field template to output taxonomy term references as their respective image fields, rather than as text or a link


The ingredient icons are term reference fields formatted to output as their respective image fields, rather than as a link or text

The example situation is where a view displays a list of nodes or fieldable entities, for our example items on a menu, and each of these has one or more taxonomy term references, in this example the main ingredients. While it’s simple to output the term references as plain text or a link, showing an image or other field attached to the term reference instead of this presents problems.

Using views relationships

The obvious solution is to create a relationship to the taxonomy in the view set up, and add the image field via the relationship. However, this currently presents issues with duplicate rows being output. If an item in the view has more than one term reference, it is displayed once for each term reference. Because of how views works, setting “distinct” and “pure distinct” in the query settings does nothing as they are technically distinct results (each has a different term reference).

The views_distinct module should offer a solution to this kind of problem, but currently it does not work in a way that can aggregate the required fields while filtering duplicates in this situation.

Creating the custom field template

In our example view, no relationship is used and the relevant term reference field is included in the field list

If you have never made a views template before, click the link “Information” in the Other section of the view:



This displays a list of possible templates to use in customising your view for each field in the view. The template names shown are ordered from least specific to most specific – the filename of the template determines which situtations it is used. The bolded template is the one currently being used. To make a new custom template, create a file in the theme’s templates directory with the name. Click the link next to it to get the default code which should go into the template. In this case we wish to control output in all situations the field appears, so the first custom template option (highlighted) is that used.



From the helpful comment at the top of the file, it can be seen that the contents of the view item can be found in the $row object. By debugging this object the location of the ingredients term references and their respective image fields can be found.

In this case the term reference field data is at:


and the image field at:


Where INDEX is the array index for multiple items.

The field_view_field() function is useful here to display the image field without needing to worry about URLs and allows control of formatting, e.g. image style presets. We also need to use an isset() condition to prevent warnings being thrown where rows don’t have any term references.

Putting this all together gives the example code:

if(isset($row->field_field_ingredients)) {
        $term = $row->field_field_ingredients;

        foreach($term as $ingredient){
                print render(field_view_field('taxonomy_term', $ingredient['raw']['taxonomy_term'], 'field_image',));

This outputs the image, but at it’s original size and with an ugly label that says “Image:”. To fix this, we need to use the optional fourth parameter of the field_view_field() function to control display and formatting of the field. The line inside the foreach() loop becomes:

print render(field_view_field('taxonomy_term', $ingredient['raw']['taxonomy_term'], 'field_image',
array('label'=>'hidden', 'settings' => array('image_style' => 'thumbnail'))));

This hides the label and sets the image style preset for the output to ‘thumbnail’.

Final code:

if(isset($row->field_field_ingredients)) {
        $term = $row->field_field_ingredients;

        foreach($term as $ingredient){
                print render(field_view_field('taxonomy_term', $ingredient['raw']['taxonomy_term'], 'field_image',
                array('label'=>'hidden', 'settings' => array('image_style' => 'thumbnail'))));

It will be necessary to set the views Query settings to distinct (pure distinct shouldn’t be needed) to avoid multiple rows being output, but in this case it will filter the view as expected.

Entity Reference Fields in Rules – Updating reference fields based on the value of other reference fields

Drupal 7 tutorial: Working with entity reference fields in rules

While there are a couple of modules that can be used to easily set up entity reference field relationships, in particular the corresponding entity references module, it’s also possible to do create these kinds of relationships with rules. While initially more complicated to set up (though not requiring a dedicated module), the result is a more powerful setup that can be easily cloned and extended with additional actions and conditions – for example, sending e-mails, displaying messages on the site, or changing the value of a third field.

Entities and Entity References

Drupal 7 is built around entities and entity bundles. To understand this concept, it’s necessary to look back to how things were in Drupal 6. D6 used a system of nodes, expanded by the CCK module to provide configurable content types. Content types have to be types of node by definition, and come with comments, revisions etc that may not be relevant in many use cases and cause an overhead.

With entities, there is no longer anything special about nodes. In Drupal 7, nodes, comments and users are all examples of entities, configured from the same base entity system. It’s now possible to create new entity types and many Drupal 7 modules take advantage of this to provide enhanced functionality and performance – for example, the Commerce module with its line item entity type and profile2 module’s profile types.

Entity references replace the role of the user and node reference fields from CCK. These field types allow the definition of relationships between two things (e.g. a user and a node). There are two modules commonly used to enable entity references in Drupal 7:


References is a simple module which emulates the node and user reference fields from Drupal 6. It is easy to configure and use.

Entity reference

Entity reference is a powerful module which is not restricted to any predefined entities like the References module. It is possible to create references to any entity type, including custom entities. The module is a little more complicated to set up and use, particularly for anyone previously unfamiliar with reference fields. There is a module to migrate from references to this module should referencing other entity types become a requirement.

Both modules work with rules in the same way, but if you wish to work with more than just user, node and taxonomy term entities you will need entity_reference.

Creating a synced client / manager relationship in rules

In this example, the user entity can have an attached customer profile or a manager profile, containing different fields, using the profile2 module.

The client has a user reference field called “manager”, which can only contain one item, and the manager has a user reference field called “clients” which may contain multiple values.

When a manager is assigned to a client, using the manager field on the client’s profile, the objective is to update the “clients” field on the manager’s profile to match.

We are also going to set up a second rule that fires only when a currently assigned manager is removed or changed, and to make things more fun we have a “past clients” reference field for the managers which former clients should be prepended to.

You will need the Rules and token modules installed and enabled

The basic rule: Add client to the manager’s ‘clients’ entity reference field when a manager is assigned to a client.

Event and conditions

Event: After updating an existing profile

To have access to the relevant fields later on and to be sure the rule only fires if the field is not empty:

  • Condition: Entity has field
  • Parameter: Entity: [profile2]
  • Field: field_current_manager



  1. Add an action “Fetch entity by ID”
    We need to load the entity that will be altered by the other actions. The type of this entity is User – the user who is being assigned as the client’s manager.

    • Entity type = User
    • Data selector= profile2:user:profile-client:field-current-manager:uid
      • Provides variable “manager”
      • note that this is actually accessing data through the entity reference field to get the new manager’s UID – pretty cool!
  2. Add an action “Add an item to a list” – this is needed rather than ‘set value’ as the clients field can hold multiple values. We use the ‘entity fetched’ variable provided by the previous step to achieve this:
    • List to be added to: manager:profile-manager:field-clients
    • Item to be added: profile2:user (the user of the client profile being updated)
    • Check the box “enforce uniqueness” and select “prepend to the list” if you wish to have newest clients at the top.

You could choose to add other actions, such as to display a message on the site such as “Assigned manager is [token value]” or send an e-mail. These may require the addition of a condition that makes the rule only fire if the client did not have a manager before (use a data comparison) – as currently the rule fires every time a profile is updated – but this does not cause any issues if “enforce uniqueness” is checked.

You can also have this rule react to profiles being created if the manager may be delegated when data is first entered into the profile. Otherwise profiles would have to be saved twice in this situation. To do this, add a second event: After saving a new profile. You can also clone this rule and change the event for greater power.

Rule Two: Adding to a manager’s past clients list when a manager is changed or removed

With a second rule we can react in two situations. When a manager is changed or removed from the manager field (the new rule), and when a manager is assigned and the manager field was empty (the first rule – which will need an extra condition)

  1. Clone the first rule. Call it “Sync fields when manager is changed and update old manager’s past clients field”
  2. New condition: NOT Data comparison:

    This makes sure that the rule only fires if the new manager is different to the old one (to prevent the rule firing when the profile is updated, but this field hasn’t been changed)

  3. New condition: NOT Data value is empty:
    So the rule only fires when there was a previous manager assigned. It would otherwise also fire in the same situations as the first rule.
  4. New action “Fetch entity by ID”
    Load the old manager’s user entity

    • Entity type = User
    • Data selector= profile2-unchanged:user:profile-client:field-current-manager:uid
    • Provides variable “old-manager”
  5. New action: Add an item to a list:
    • List to be added to: old-manager:profile-manager:field-past-clients
    • Item to be added: profile2:user
  6. New action: Remove item from a list
    • List: Selected list: old-manager:profile-manager:field-clients
    • Item to remove: profile2:user

Again, there are plenty of avenues for extending this with new actions. For example, “Display a message on the site” – a message helpful for admins might be:

[profile2:user]‘s manager set to [profile2:field-manager] – Old manager was [old-manager:name]

Adjusting the first rule

To prevent the first rule from also firing in situations where the second does, add a new condition to the first rule:

  • Condition: Data value is empty
  • Data to check: profile2-unchanged:field-current-manager

Two way relationships should be set up using another rule with inverse data selectors and if applicable, a different event to react to. Hopefully this article helps illustrate what can be achieved with rules and entity references.

Image free responsive mobile menu buttons using the ≡ character and pure CSS

Pure CSS scalable menu toggle buttons with three, four, five and six lines – tutorial and download

Different pure CSS buttons at 60px, 90px, 115px, 145px and 170px. The top row uses CSS3 styling whereas the bottom row is CSS2
Download the CSS – 4.3KB (full version)
‘lite’ version – 772B (3 line button only, minimal comments)

A lot of responsively designed sites call for menu toggle buttons, so that menus don’t take up a lot of vertical screen space on mobile devices where elements are often stretched to 100% width. This can be to toggle a separate touch enabled menu, or to display the normal menu from a position:fixed header. Rather than creating a lot of button graphics I wondered if there way a way to make such a simple icon using pure CSS, and came up with these. The CSS3 version is fully compatible with IE 9 and the CSS2 version should work with any browser that has proper support of the after property – for example IE8 but not IE7. All smartphone browsers from recent years should be compatible with the basic button and most will support the CSS3 effects.

The buttons render in the box model with the same horiontal and vertical dimensions as the font-size specified, in pixels, with all other values in the code using relative units in order to scale with this value. The buttons themselves can also be sized in ems if preferred.

Instead of an image, an ‘equal sign with three bars’ ≡, meaning ‘identical to’ is used, equivalent to the triple equals operator in programming languages. This is represented as \2261 when escaped in CSS files, with the HTML entity code being ≡.

Basic three line button


<div id="menu-button"></div>

You could use other elements than a div, such as <span> or <button>, but it may require more lines of CSS due to element default styles. The element is ideally output with JavaScript anyway as it has no function if JavaScript is disabled in a typical usage scenario. On a few sites it might be necessary to add a &nsbp; inside the div if the button doesn’t appear, depending on existing CSS rules.

The CSS:

#menu-button {
        font-size:60px; /* Change to alter button size */
        font-family:verdana !important;
        font-weight:normal !important;
        font-style:normal !important;
        position:relative; /* Also works with absolute */
        border:0.05em solid #555;

#menu-button:after {

#menu-button:active {

CSS Notes

Using an :after pseudoclass means the button can be made from a single empty element, not needing a parent container or child element or any text nodes, with the side benefit that the &equiv; character doen’t end up cluttering the source code.

Font-family, weight and style needs to be specified to ensure consistent rendering – characters are displayed very differently in terms of position, scaling and style across different fontfaces, and some fonts may not contain the ≡ character. You could use a different font and adjust the top and left values if looking for a different thickness or spacing of lines, though scaling may present issues.

Simple Button Usage

An easy usage to display a large, black button:

<div id="menu-button" style="background:black; font-size:120px"></div>

Four, Five and Six Line Buttons

Four Bars

Five Bars

Six Bars

<div id="menu-button" class="four"></div>
<div id="menu-button" class="five"></div>
<div id="menu-button" class="six"></div>

Solving scaling issues with CSS3 transforms and reciprocal functions

To get the four, five and six line versions, instead of just one ≡, there are four in the :after content property. Two render on each line, and letter-spacing and line-height are used to superimpose the four characters to make what appears to be one of the required number of lines and width.

Due to the increase in the number of characters, the element needs to be larger to contain them. This means it no longer renders at the same pixel size as specified in font-size, but larger by the ratio of the value in ems the width and height of the element is increased by – for example 1.2ems for the four bar version and 1.8 for the six. Read More »

Add Account Creation to your Webform with only an e-mail required, using the Webform Rules module (regardless of site registration settings)

Create a versatile alternative account registration system for Drupal powered by Webform and Rules, with zero lines of code

The power of the webform module allows sophisticated registration forms to be put together far more quickly than would be possible by modifying the standard system. Webforms and Rules can also easily be cloned, allowing the possibility of simple setup of a multi-faceted registration system as site-wide settings for user registration no longer apply – everything (sending e-mails, assigning roles etc) is handled by Rules.

Restrictions of Drupal’s built-in user registration system

Drupal sites allows one of these three options for user registration:

  • Registration Disabled
  • Registration Approved (with admin approval)
  • Registration Approved (no approval needed)

There is also a checkbox to select whether e-mail verification is required or not.

In my previous post on Drupal Commerce’s powerful integration with Rules, I explained a way to improve the anonymous user experience on completing an order, but it required the user registration settings to be set to the most lenient option “Registration approved, no approval needed, no e-mail verification needed”.

In the past when I have used this setting, sites are likely to be inundated with bot created accounts. To prevent this, I added a rewriterule from /user/registration back to /user and hid the “register” tab on the user page with CSS.

The side effect of this was to effectively lock registration to one of only two methods – via placing an order in the store, or via manual admin creation of accounts.

A need arose on a site configured like this for user registration functionality for a new ‘members only’ section. There are a number of ways I could have tackled this (the most obvious being a ‘subsite’), but I decided to see what was possible using Rules and Webform. I was very pleased with how it turned out and believe it can be useful for any Drupal site looking to make a departure from the standard user registration system.

Adding user registration to your Drupal Webform

You must install the Webform Rules module, which provides relevant events, conditions and data selectors to rules. You must be using version 4+ of Webform (which, though still an alpha release, is worth upgrading to for improved built-in error handling presentation on existing forms and built in ‘conditions’, which are similar to a stripped down version of rules conditions for use internally in the webform module). This guide also assumes you have Drupal Commerce installed, though you only need it in order to clone one if its rules.

Update November 2013
It turns out that the commerce_checkout module must be installed in order to have the “Entity exists by propery” condition used below available in Rules. This is an extremely useful condition and a patch has been made to add it to the Rules module, though at the time of writing it has not been committed to dev. If you wish to use this on a site without commerce_checkout, you’ll need to apply the patch, and make the edit to the patch to change the type to text (I will make a new patch with this done and add it to the issue).

  1. If you don’t have an existing form you wish to use, create your registration form. A password field is not required or accounted for in this guide, it is set by the user on first logging into their account from a link in e-mail sent to them. The only necessary field is ‘e-mail‘. You can set up the Webform with whatever other fields and functionality you like though.
  2. Make a clone of the rule from commerce, “Create a new account for an anonymous order”, calling it “Create a new account on Webform submission“.
  3. The first step is to delete the event “Completing the checkout process” (this will throw a bunch of errors on reloading the page), replacing it with a new event “After a Webform has been submitted“.
  4. Delete all the conditions except “NOT entity exists by property“.
  5. Add a new condition “Webform has name” and select your registration form.
  6. Move “send account e-mail” out of the loop. Select the type of account registration e-mail relevant. If you have already customised the relevant one, as in my case, just use one of the other options and alter the template to fit (in the configuration > people > account settings page).
  7. Delete the other actions in the loop to fetch the created account, and the loop itself (unless you wish to manipulate areas outside the user entity based on its data too).
  8. There will still be errors shown for most of the rules. This is because they are still using tokens from commerce. These need to be replaced with tokens from the Webform submission. These are formed similar to [data:email-value] or [data:email-value-raw], where ‘email’ is the key of your Webform component.
  9. (Optional) Create a new role for the users registering via this form.
  10. Add an action below “Create a new Entity” and above “Save entity”.  Set a data value [acount-created:roles] – select the role to assign user accounts created via this form from list.
  11. Finally, add an action “Show a message on the site“, last in the actions list – The Webform module does not know whether the rule was successful or not, so it goes to the confirmation page even if there was a problem in the rules evaluation. So we show a success message as part of the rule instead. I have not fully looked into the conditions aspect added to Webform 4 to see if there is any provision for integration in this area.
  12. Test your new Webform based registration form

Update November 2013

Stay tuned for a followup article on advanced entity manipulation based on submitted webform data using the rules_data_transforms module – including addressfields, times and dates, integer values and multiple value fields (e.g. checkboxes) – both input and output

Tutorial: Improving the Drupal Commerce user and admin experience – examples with rules and VBO modules

A Compilation of Drupal Commerce modifications and enhancements – user friendly anonymous checkout, efficient store administration, address label printing

About Drupal Commerce

Out of the box, Drupal Commerce is not, as yet, very streamlined in terms of purchaser experience or non-technical store administration. In part, this is due to it’s relative youth in development and especially in wide deployment, but a significant factor is the modularity: A lot of functionality that is provided as part of the default system in Ubercart must be installed as an optional companion module with commerce – for example, there is no shipping or payment without installing the relevant modules. However, even with these modules there is still a lot for the web developer to do for more than a very basic setup, and Commerce may even seem clumsy and limited in what it can do. What may not be realised is the excellent integration with the Rules module gives Commerce a significant amount of power and flexibility under the hood. In this guide I am going to be using this module extensively and will be sharing some ideas on improving the customer experience and ease of non-technical admin on a typical Commerce site.

Update November 2013

Commerce has matured into a stable and well supported platform, however it’s basic out-of-the-box nature and modularity remain.
A significant proportion of commerce developers now use the Commerce Kickstart platform for building typical use case sites, a commercial but open source project.
Although nearly all development work to create a typical online store is already done, configuration of products and the last parts of development have a steep learning curve (and work differently to vanilla Commerce) – to the point that some developers use the ‘example store’ with products, taxonomies etc already set up as a base to build from rather than using the platform installation. It should be stressed that there are many ways to build a feature-rich store with Drupal commerce, the Kickstart platform is not the only way to go. For other non-typical use cases the Kickstart platform carries a large overhead. Everything in this tutorial is likely to still be of use if building from a basic Commerce installation.

Some ideas worth implementing are found here: Express checkout with Drupal Commerce -the main thrust of the article is setting up a ‘buy now’ instead of ‘add to cart’ functionality, but it walks through some aspects of the setup process which are worth doing on all Drupal Commerce sites. This guide assumes you already have a basic Drupal Commerce site set up. In this guide I am going to use the Rules, Views and Views Bulk Operations  to tackle several specific points where the system has current issues or a lack of built in functionality.

Covered in this tutorial

  • Fixing the default order success page for anonymous orders – account creation on purchase, auto log in, redirect to order page
  • Improving the information displayed to purchasers
  • Setting up a decent workflow for handling orders
  • Improved handling of delayed payment options (e.g. cheque, bank transfer)
  • A store admin page showing just orders waiting to be sent out, rather than all orders
  • Bulk operations on order tables
  • Printing Address Labels with VBO


Improved Handling of Anonymous/First Time Orders

new anonymous drupal commerce order page

An improved order success page for anonymous users/first-time customers, made with Rules

By default, in Drupal Commerce when an anonymous user checks out a purchase, they are presented on order completion with a page with very minimal info, only the order number and the below: “Thanks for your order – please click here to view your order when logged in”. Of course, anonymous users by definition aren’t logged in, and clicking the link gives them a generic “access denied” error with no further info, which is very unfriendly:

The link does work for authenticated users, but even then it would be desirable to display the order details on the confirmation page rather than requiring a click. An easy fix would be to edit the message to not have that link – but the page doesn’t show details of their order apart from the order number, and some things (e.g. selected postal method) are as far as I know impossible to output via tokens to this page. Others have tackled the issue by forcing customers to create or log in to an account before ordering, but requiring registration is not going to be optimal for all e-commerce sites. The page that a logged in user is taken to on clicking the link mentioned above link would be to some extent the perfect order confirmation page, apart from not having a success message. So how to get past the access denied error? First, we must make sure that accounts are fully and instantly registered with the site and do not require confirmation or admin approval to be accessed. Second, we set up an automatic redirect to the previously mentioned, previously inaccessible new order page with rules:

System Setup

Go to the configuration > users page, change settings to “anyone can create an account” and untick “e-mail verification needed” – this enables instant account creation and verification. Now a user can see their own order details page on checkout without any errors. Note – this will enable spam signups to your site, so depending on needs you may wish to make your standard user registration page inaccessible. On the site I developed this store for I disabled the registration page, but a need arose for a functional registration system alongside this which I found a fairly simple solution for using Webform, stay tuned for a follow-up article.

Rules Setup

Here we set up a rule that sends a customer straight to their order details page. Add a new rule in workflow > rules – call it “Redirect to order page”. event: on completing checkout action: page redirect [commerce-order:customer-url] The order details page doesn’t have any success message – but we can display our own with the rules action “display a message on the site” – and even improve on the basic setup with different messages for logged in (repeat) and anonymous (first time) purchasers.

Setting new order success messages

To set an order success message for anonymous users:

Add an action to “create a new account for an anonymous useraction: display a message on the site (add your message for first-time purchasers) You can use HTML. The default “status” styling with a green tick is fairly good for a success message.

Set order success message for authenticated users and repeat purchasers

Create a new rule – call it “Show a success message for authenticated purchasers” Event: on completing checkout Condition: NOT entity is new [site:current-user] Action: display a message on the site (add your message for repeat/logged-in purchasers) Give both of these rules a high weight (large number) so they only run after successful evaluation of the rest of the “on completing checkout” rules. I haven’t yet got this to work properly for payments involving an off-site redirect (eg Payapl WPS), so to handle these I would recommend customising the default success page to not have a link to the order details and to just instruct purchasers to log in via their e-mail.

Setting up a good order handling scheme

This is sometimes a stumbling block. The Commerce system has several stages an order can be put through, but how these are used and when is up to the developer. They are:

  • Pending
  • Processing
  • Complete

(There are multiple stages before an order is successfully placed but those are not relevant here). The most sensible way to use these for a good workflow is:

  • Pending – order received, but payment not authenticated
  • Processing – Payment authenticated, items to be readied for dispatch
  • Complete – Order has left on its way to customer.

If further stages are necessary for your enterprise, there is an optional module to achieve this.

Update Order status on payment completion automatically

Building on this idea, a great rule to add that saves work in the store back end, especially with non-instant payments is: Event: When an order is paid in full Condition: None Action: Update Order Status: Processing With payments where authentication comes through some time after the order is placed, this helps ensure your store is up to date without any work.

Improved Delayed Payment Handling

If using modules like cheque or bank transfer, there is currently no inbuilt way to show the relevant details (bank account number to make payment to / address to post cheque to) except on the ‘payment’ page of the checkout process (with an instruction to write it down before placing the order…). The bank_transfer module does not recommend use on production sites because of this issue. Again, this can be solved by adding more rules with actions to display a message on the site, when meeting certain conditions. As set up, it shows the payment details to the user on their order page until the payment is marked as cleared in the system, when it automatically stops showing.

Rule Setup

Event: On viewing order
Condition: payment-method comparison = your payment method (e.g. cheque)
Condition: order-balance > 0 (this will stop showing the message once the payment is cleared in the system)
Condition: data comparison: site:current-page:url = [commerce-order:customer-url] (if this condition is not added, the message will show wherever orders are displayed (multiple times if looking at the ‘orders’ page in admin, for example), instead of just on the customer’s order page.
Action: Display a message on the site Set high (higher number) weight for the rule, so that it is displayed below any success message from checkout completion, and if you wish change the message type to from status (suitable for a success message) to “warning” (suitable for information), which will seperate the two messages into different boxes and give them a different visual context. You can always style the output of the messages just for this page if you wish, though I have found the default presentation to be acceptable (example of first time order):


A page for store admin to ship orders from

The orders page store > orders for order administration is quite lacking in terms of useful information. It’s simple enough to edit which fields are displayed in the View which creates it. For the use of someone who’s job it is to post out orders, the page is not easy to use at all. Create a new view of orders as a table (you can also clone the default orders view and adjust), calling it “Processing Orders”. This will handle just orders that are paid for and ready to be shipped out. The basic view includes these fields:

  • Name
  • Line Items
  • Shipping Address
  • Order Total
  • Order Balance

Use a filter on order status to just show processing orders, and in the centre column of the views admin you can set a URL and menu entry for admins to access this new page by.

Using Bulk Operations to speed up order handling

If you don’t have it already, install the module Views Bulk Operations (VBO). This is a powerful module that lets administrators achieve tasks on multiple items in the database with a checkbox interface.

Excuse the backwards English, one of those 3AM errors that stayed in

To mark orders as shipped/complete en masse

We need to create a component in rules – this is like a segment of a rule that can be used by other rules or modules. Component type: Rule Add a parameter at the bottom (commerce product) Set the action to “change order status” – completed Go back to your view, and add a field “VBO”. Select the component you just created as one of the possible actions. Now you can mark orders as complete (shipped) en masse instead of one at a time via at least three clicks each. It’s also easy to set up an option to delete orders in bulk.

To add a basic Address labels Printing page (for shipping out orders)

This allows a non-technical admin to tick the checkboxes on a batch of orders on the ‘processing orders’ page and then click a button to be taken to a page with those labels formatted for printing. First, add a new display to the previously created processing orders view. The only field needed is shipping address. Give the display a URL. In the views ‘advanced settings’ add a contextual filter, select “order id” In the original processing orders display, edit the VBO field and create a “pass argument to page” operation. Call it “print address labels”. Pass to the URL of the print labels page. Select the “multiple arguments” option. Now, whatever orders are selected with the VBO checkboxes can be displayed for address label printing. You will need to do some CSS styling with print styles.

Semi-Randomized Created and Changed Dates for Nodes in Drupal 7

Fix sort order problems with a run-once script to set dates for existing nodes to fall randomly between two defined dates, e.g ’01-01-2012′ and ‘now’

Let’s say you have a mixed content-type view like an e-commerce site with different product types shown on the homepage, or a general ‘front page’ kind of view, and the client is adding content to the site prior to launch. Typically they will add one type of content to the site at a time. If the feed is ordered in descending date order, this leads to a monotonous display of one type of content followed by another.

There are many ways to get around this issue, with varying degrees of time involvement and success. At one end would be working out new dates and editing nodes one a time. This is easy if you only have half a dozen pieces of content, but it is obviously not going to work for larger numbers.

When, years ago, I first came up against an issue like this, creating photo galleries in Gallery2, I either set the order of photos to manual and readjusted them laboriously or set them to random. You can do the same in Drupal too, making a new “sort order” field and filling it with numbers manually or via a script.

You can also set content to sort by global:random – this is desirable for content that should be rotated when the page reloads, like testimonials, ads, or featured content. But it is very confusing for visitors trying to browse a feed sorted randomly as except for caching, there is no persistence to what they see. I have seen others use the Cache Actions module to partly get around this, forcing the same cached random view result to be used until a new node is added or another similar event.

It was one such particular case where I decided all these inelegant solutions just weren’t going to cut it and worked on a dedicated solution. It would also work well in cases of sites wishing to appear to have been established longer or more regularly active than reality.

The Script:

  • Changes the created and changed dates of nodes to fall with a random distribution between two given dates $date1 and $date2
  • Works on one specified content type at a time but can be set to do all content on the site at once by uncommenting one line


  1. Create a blank file, paste in the script and save as myscript.php. Then upload to a web accessible directory on your webserver.
  2. To run the script, visit myserver.com/myscript.php with your web browser.

Author: Miles Carter http://www.milesjcarter.co.uk/blog/


// 1. Edit your Drupal database details:
$db_drupal = mysqli_connect('localhost', 'db_user', 'db_pass', 'db_name');

// 2. Edit "WHERE node.type='article'" to the content type you wish to randomize

$query = "SELECT node.nid, created, changed, type FROM node
LEFT JOIN node_revision ON 'node.nid'='node_revsion.nid' WHERE node.type='article'"

// - OR: Uncomment below line to update all content rather than just one content type at a time

#$query = "SELECT node.nid, created, changed, type FROM node LEFT JOIN node_revision ON 'node.nid'='node_revsion.nid'";

$results = mysqli_query($db_drupal, $query);
if (!$results) {
echo '<p>Error doing script: ' .
         mysqli_error($db_drupal) . '';
while ($row = mysqli_fetch_assoc($results)) {
$theid = $row['nid'];
$type = $row['type'];

/* 3. Edit below dates to suit, typical usage shown as example
   $date1 = The earliest possible date that content may be set to
   $date2 = The latest possible date */

$date1 = strtotime('2012-01-01');
$date2 = strtotime('now');

$rand_date = mt_rand($date1, $date2);

// Update DB
 $query_insert = "UPDATE node SET created='$rand_date', changed='$rand_date' WHERE nid='$theid'";
if (!mysqli_query($db_drupal, $query_insert)) {

echo '<p>Error doing script: ' .
         mysqli_error($db_drupal) . '';
else {  
echo "Record change attempted: $type $theid $rand_date <br />";  }


Drupal 7 SEO: Custom Page Titles and Meta Elements at the Theme Layer – Now Multilingual

Drupal 7 Development: Multilingual Field Based Page Titles and Meta Descriptions from template.php

This is an update of a previous post on this blog from July 2011 Drupal 7 SEO: Controlling Page Titles and Meta Elements at the Theme Layer. The script allows the setting of custom page titles and Meta descriptions from defined fields in content types with no modules needed and consistent performance

Being able to set custom page titles and Meta descriptions is an important part of SEO for many sites, vital to establishing topical relevancy and therefore rankings in the case of the former, and clickthrough rates from search results in the latter.


Drupal 7 does not support custom page titles or Meta descriptions out of the box and I have found this script to be extremely useful on a number of sites and still find it to be a more robust alternative than using multiple modules. It works with Panel pages which has continued to be an issue with the page_title module. If no custom page title is found, it falls back on a basic “drupal title | site name” scheme. The script could be edited to support other patterns.

At the end of last year I was working on adding multilingual functionality to a Drupal 7 site and needed to get this script to work with multiple languages. It now allows the setting of field-based custom titles and Meta descriptions for different languages, with each node translation being able to have it’s own unique title and Meta description.

It works on single/undefined language sites too so this replaces the old version of the script entirely.


Simply create new fields for your content type(s) called “title” and “meta_desc”, then paste the following code into your THEME_preprocess_html function in template.php:

 * Ver: 1.05
 * By Miles J Carter
 * http://www.milesjcarter.co.uk/blog
 * Tested with Drupal versions 7.3, 7.4, 7.8, 7.9, 7.12, 7.14
 * licensed under the GPL license:
 * http://www.gnu.org/licenses/gpl.html
 * Works with all content types that have
 * text fields created named "title" and "meta_desc".
 * Insert into THEME_preprocess_html function in template.php

// Extract language value for multilingual sites
global  $language;
        $lang = $language->language;

// Find Node ID

$node = $vars['page']['content']['system_main'];

if (isset($node['nodes'])) {  
        $node = $node['nodes'];
        // Extract key value for node ID
  if (list($key, $val) = each($node))  {
    // Node object variable
    $node = ($node[$key]['#node']);            
        // Assign page title field content variable, if set            
        if (isset($node->field_title)) {
          $node_title = $node->field_title;
                if (isset($node_title[$lang]['0']['value'])) {
                  $seo_title = $node_title[$lang]['0']['value'];
                // Fall back on undefined language if nothing set for this language
                        elseif (isset($node_title['und']['0']['value'])) {
                          $seo_title = $node_title['und']['0']['value'];
  // If manual field title for SEO has been set, set the title to [seo-title] | [site-name]
        if (isset($seo_title)) {
          if (strlen($seo_title)<65) {        
  $vars['head_title'] = implode(' | ', array($seo_title, variable_get('site_name', ''),  ));
          else {        
  $vars['head_title'] = $seo_title;
// If SEO title field not set, use an automatic [current-page-title] | [site-name] scheme
        else {  
  $vars['head_title'] = implode(' | ', array(drupal_get_title(), variable_get('site_name', ''), ));  
// Uncomment to set custom pattern for non-node content
#       else {  
#  $vars['head_title'] = implode(' | ', array(drupal_get_title(), variable_get('site_name', ''), ));  
#       }

// ----- Custom Meta Description (uses $node variable from previous code) -----

// Assign meta_desc field content variable, if set
if (isset($node->field_meta_desc)) {
  $node_desc = $node->field_meta_desc;

        if (isset($node_desc[$lang]['0']['value'])) {
            $seo_desc = $node_desc[$lang]['0']['value'];
                 elseif (isset($node_desc['und']['0']['value'])) {
                        $seo_desc = $node_desc['und']['0']['value'];

if (isset($seo_desc)) {
// Create meta description element array for insertion into head
    $element = array(
      '#tag' => 'meta',
      '#attributes' => array(
        'name' => 'description',
        'content' => "$seo_desc",
    // Insert element into <head> (if field has a value)
    drupal_add_html_head($element, 'meta_description');

// ------- END SEO CODE ---------

If nothing changes, flush your caches.

I hope this is useful to other SEOs and Drupal developers – follow me on Twitter to stay tuned for updates (I may see if it’s possible to turn this into a module). Please report any bugs in the comments.


1.03 – 30/5/2012 – Minor tidying of code and comments, fall-back pattern now applies to nodes with no title set rather than non-node content (moved a parenthesis to where it should have been)

1.04 – 31/5/2012 – Addition of optional custom pattern for non-node content (commented out by default)

1.05 – 24/7/2012 – Only shows ” | sitename” on the end of the custom title if the custom title is less than 65 characters in length (to help prevent title overflow in search results) – let me know if you think this is not improved functionality.

Simple JQuery Collapsible Content in Drupal 7 with Ctools

Drupal 7 Development: Collapsing Content with no Extra JavaScript

I stumbled upon a neat solution for collapsible content sections for Drupal 7.

It uses functionality built into the Ctools module, which must be installed with Views so is already installed on most sites.

Edit and add this code to your template.php:

function THEME_collapse_content($c_content, $collapse_heading) {
print theme('ctools_collapsible', array('handle' => $collapse_heading, 'content' => $c_content, 'collapsed' => TRUE));

Then where you want your collapsible content to appear, edit and add this code:


$collapse_heading = 'Heading for the Collapsed Content';
$c_content = <<<'EOD'

[paste the HTML of your content to be collapsed here]


THEME_collapse_content($c_content, $collapse_heading);


I don’t have a demo available right now but if you’ve ever seen a collapsible div where content is hidden with CSS and shown with JavaScript, you know what to expect in terms of functionality.

The resulting elements are very minimal in appearance out of the box but can easily be styled with CSS. It would be great to integrate this with the WYSIWYG editor as a custom button, I’m not sure but my current thinking is this would need to be made into a module first.

I like this kind of presentation as it allows an information rich display in an initially small area. This in particular gives opportunities to include vital-for-SEO topical text content which it can otherwise be hard to find room for with many layouts.

Drupal 7 SEO: Controlling Page Titles and Meta Elements at the Theme Layer

Drupal 7 Development: How to Set Field Based Page Titles and Meta Descriptions in template.php

This script has been updated to work with multilingual sites too! See http://www.milesjcarter.co.uk/blog/web-design-development/drupal-7-seo-page-titles-meta-elements-theme-layer-multilingual/. All further development will be with the new version

Drupal 6 was great for manual control of page titles, either with the page_title module, or with control at the theme layer.

In Drupal 6, I used a small snippet of code like this in the page.tpl.php to set a custom page title, simply because it was simple and sufficient for most sites:


if ( arg(0) == 'node' && is_numeric(arg(1)) ) {
  $node = node_load(arg(1));
  if ( $node->type == 'page' && !empty($node->field_title[0]) ) {
    // Output CCK Title
print content_format('field_title', $node->field_title[0]);
else {
print $head_title;


field_title being a field called “title” I added with CCK to the ‘page’ content type or any other content type that should have hand-written page titles. A similar snippet also did the trick for the Meta description.

However, Drupal 7 makes this a lot trickier – whereas the title and other head elements are declared individually in page.tpl.php in Drupal 6, the replacement for Drupal 7 is:

<?php print render($page['header']); ?>;

In Drupal 7, anything to be inserted into the head at the theme layer (by my understanding) has to be done through preprocess functions in template.php.

As an aside, notice in the previous the use of the render() function to output the header – this is a common source of confusion amongst those new to Drupal 7 theme development, where just print is needed to output regions in Drupal 6.

This is made doubly tricky by node variables not being directly available in template.php as they are in page.tpl.php.

I tried out the page_title module for Drupal 7, and this does work to an extent, but it breaks completely with panel pages. You could, according to a post on drupal.org use panels as a template to display nodes, but for a single page usage (as in a homepage only use) this seems like something not straighforward. It’s also another module to keep maintained, and with field tokens currently broken and not much progress being made the page_title module is a lot less useful than it was in Drupal 6.

A Drupal 7 Solution:

I was inspired by this post by Sivaji Ganesh, containing this line:

$vars['head_title'] = implode(' | ', array(drupal_get_title(), variable_get('site_name', ''), variable_get('site_slogan', '')));

For setting a title at the theme layer as “title (as in the h1 title) | site_name | site_slogan”

This gave me a base to work from. The code I finally came up with (after about 8hr of perserverance) was this:

 * Ver: 0.9c
 * By Miles J Carter
 * http://www.milesjcarter.co.uk/blog
 * Tested with Drupal versions 7.3, 7.4, 7.7
 * licensed under the GPL license:
 * http://www.gnu.org/licenses/gpl.html
 * Works for content types that have text fields created
 * named "title" and "meta_desc".
 * function THEME_preprocess_html(&$vars) {
 * in template.php

// Find Node ID
$node = $vars['page']['content']['system_main'];

if (isset($node['nodes'])) {
        $node = $node['nodes'];
        // Extract key value for node ID
  if (list($key, $val) = each($node))  {
    // Create node object variable
    $node = ($node[$key]['#node']);    
                // Creat page title field content variable, if set             
                if (isset($node->field_title)) {
      $node_title = $node->field_title;
                if (isset($node_title['und']['0']['value'])) {
        $seo_title = $node_title['und']['0']['value'];
  // If manual field title for SEO has been set, set the title to [seo-title] | [site-name]
  if (isset($seo_title)){
                 $vars['head_title'] = implode(' | ', array($seo_title, variable_get('site_name', ''),  ));

/* If SEO title field not set, or content type not page,
use an automatic [current-page-title] | [site-name] scheme */

else { 
  $vars['head_title'] = implode(' | ', array(drupal_get_title(), variable_get('site_name', ''), ));  

// ----- Custom Meta Description -----

// Create meta_desc field content variable, if set
if (isset($node->field_meta_desc)) {
  $node_desc = $node->field_meta_desc;
        if (isset($node_desc['und']['0']['value'])) {
                $seo_desc = $node_desc['und']['0']['value'];

    // Create meta description element array for insertion into head
    $element = array(
      '#tag' => 'meta',
      '#attributes' => array(
        'name' => 'description',
        'content' => "$seo_desc",
    // Insert element into <head> (if field has a value)
    drupal_add_html_head($element, 'meta_description');


// ------- END SEO CODE ---------

This allows a field created called “title” to manually set the page title. If this field is not set, or the page is a view or  any other non-node page, the title will be “get_title() | site_name”, with get_title() the h1 title. Other fields could easily be incorporated into the script by minor modification.

Once the title was figured out, it was pretty easy to set up a field based meta description too.

As this issue had been holding me up from developing with Drupal 7, I hope the above code is useful to other SEOs and developers.

Using Panoramic Photos for Variable Width CSS Backgrounds

Variable Panoramic Header Backgrounds – CSS Development Techniques

Traditionally, websites are made either as a static width – one that doesn’t change depending on other factors – or one that is fluid – that does not have a width set and will expand to fill the width of the screen, whatever that is. For a long time, the established tradition for most sites has been fixed width, to be full screen horizontally on 800px and 1024px width displays. In terms of line lengths for reading text, more than around 1000 pixels and things get harder to read with most font sizes used on the web, which is a drawback of the simplest simple fluid layouts. But with the recent increase in average screen resolution of web users, particularly in professional sectors such as media, design and publishing and in the the higher income home user demographic, it is worth presenting a site that looks good at many resolutions.

I could write a lot on this topic, but in this article I am going to cover the basic nuts and bolts of variable width layouts.

This site at around 1600px horizontal resolution

This site at around 1280px horizontal resolution

Read More »