Drupal 7 site building case study
Wireframes #
In this post we’ll look at some wireframes, and then build the three pages given using contrib Drupal modules.
We may skip or change some elements from the wireframes to fit our purposes.
Source for these wireframes: Park & Bond on Behance (2011-09-21)
Homepage #
The first page we are going to build is the homepage. The main blocks to be displayed are:
- Header: Includes static information, links, and the shopping cart on the first row (we will treat this as static content); the site logo and search form, and a menu below.
- Slideshow: an arbitrary number of slides, each with a title, subtitle, background image, and optionally a button linking to any page in the site.
- Featured products: A list of products from a single category, the first of which is shown in a bigger format.
- Blog sidebar: Includes a contact form, and a list of the latest blog posts.
- Featured article: A single article teaser.
- Secondary products: From a single category, and with three sort options shown as tabs: new, popular, exclusive.
- Bottom categories: A manually curated list of three categories.
Category page #
The category page mainly shows products for a single category. The blocks are:
- Header top menu with parent category selected.
- Editorial content: Changes with each category, a Q&A block and two articles.
- Featured products: Manually curated list of featured products for the category.
- Category title.
- Products view: Includes sort and filter options, and a way of choosing between two different layouts (grid and table view).
Product detail page #
The product detail page shows a single product, and some related information. The blocks are:
- Breadcrumb: Contains links to the product’s category and its parents.
- Product information: Title, image, and other fields. We will not focus on the shopping cart functionality here, only displaying information from the product.
- Related products: A list of products shown in a single row.
- Bottom categories: The same block as in the homepage.
Setup #
Required modules #
Let’s install a few modules first. Using drush:
$ drush en panels panels_mini views views_ui views_content page_manager ds nodequeue smartqueue entity entityreference link webform hierarchical_term_formatter
Tip: This command is meant to “enable” a few modules, but if they don’t exist in your files, Drush will download them first. Also, a few more modules are enabled if they’re dependencies (ctools, for example).
We will also need these modules to work with Features:
$ drush en features features_uuid
Let’s explain a bit what each module does.
Noteworthy modules #
-
panels_mini
- Allows the creation of “mini-panels”, which can be used as blocks on other panels. -
views_content
- Gives views a “content pane” display option to better integrate with the Panels system. -
smartqueue
- Adds functionality to nodequeues, to be able to define subqueues for each term in a taxonomy, for example. -
webform
- Implements a content type in which nodes are configurable forms. Also provides the ability to use these forms as blocks. -
hierarchical_term_formatter
- Provides a formatter for term reference fields that show the term and its parents. -
featured_uuid
- Allows content (nodes, taxonomy terms, etc.) to be exported into features.
Homepage #
Let’s build the homepage. Go to Structure -> Pages -> Add custom page
, and let’s create a Panel. Make sure you check the “Make this your site home page” checkbox.
Now let’s choose a layout. We could create a new layout in the theme, or we could use the “Flexible” layout from the “Builders” category, which lets us create regions dynamically through the interface, but for now let’s stick with “Two column bricks”, which looks like it has appropriate regions for our purposes.
After a couple of screens, we arrive at the “Content” page. We’ll come back to it later to add the blocks we create in the appropriate places.
Header mini-panel #
To create the header (some static content, title, main menu, search form, and eventually some links for managing the user account and shopping cart functionality), we will use a mini-panel. The reason is reusability: when we need to change it, we will only change it in one place and it will update throughout the site.
The process is very similar to creating a new panel. From Structure -> Mini panels -> Add
:
Let’s choose an appropriate layout:
Let’s add the site logo first. You can find it in the “Page elements” category:
Now, following the same process, let’s add some more blocks:
- Search form (“Widgets” category)
- Main menu (“Menus” category)
And, finally, a “New custom content” block for the “Top” region. For now this is all we’ll do in this region.
Finally, click on Preview to see how it looks like:
It might not be obvious by looking at it, but all elements are there. Finally, click on “Finish” to save our work.
Main slideshow #
For the slideshow we will use a nodequeue to let users edit the displayed content.
The nodes will belong to a specialized content type that we will call “Slide”. Let’s create that first. From Structure -> Content types -> Add content type
, let’s create it and click on “Save and add fields”.
In addition to the fields created by default, we will need an image field, a link (to show a button linking to any page in the site), and a reference field to show the category above the title. We quickly create the Category taxonomy to accommodate the reference field.
And now we go back to the content type and create all the fields. Note that the type for the category field is “Term reference” and not the new “Entity reference”. This is because later we’ll have problems creating nodequeues (there is a new “entity queue” module that might soon replace “nodequeue”).
Next step is creating the nodequeue. From Structure -> Nodequeues -> Add simple queue
:
Now we can create the slideshow view. From Structure -> Views -> Add new view
, we create the view without creating a page nor a block. The display type we will use is “Content pane”, since we will want to place the view in a panel, so we have to manually add the display. After tweaking the view options, this is what we have:
Things to note from the view configuration:
- A “Content pane” display is created with “Homepage” as its name (and “homepage” as its machine name). The view itself is called “Slideshow”. These names are deliberately chosen so that in the future you may create slideshows for other parts of the site by cloning the display and changing its query.
- A “Nodequeue: Queue” relationship is added so that the nodes are retrieved from the nodequeue. The “Nodequeue: Position” sort criteria is used to control the order of the slides.
- There is no pager, we want the nodequeue to control how many items we show here.
- We don’t care yet about the “Format” (eventually we may use a slideshow plugin here that generates the necessary Javascript to make it work), but we do set “Show” to “Rendered entity”, and the view mode to be shown to “Full content”. This disables the “Fields” section, so that the display of each slide is controlled by the configuration in the content type, in the “Manage display” tab. Let’s go in there and adjust the fields that are shown to match the following:
Note that we had to select a layout (bottom of this page, not visible in the screenshot) so that the Title field shows as an option.
We now have a slideshow, ready to be placed in the Homepage panel.
Featured products #
Next is the “featured products” block, which shows a total of 5 products from a single category (chosen by a content editor), the first of which is shown in a bigger, more detailed format than the rest.
For this we’ll create two view modes for the Product content type (which we’ll also need to create), a set of nodequeues (one for each category), and a view to show them. The view will have a contextual filter, so that the results come from a single category, specified in the homepage panel configuration.
Let’s configure the Product content type with these fields:
- Title
- Body - stores full description and summary.
- Brand name
- Image - we use the existing “field_image” field. In general we can re-use fields between different content types if they’re generic enough. Image is a good candidate, it acts as “the main image” of the node, regardless of whether it’s a product, an article, etc. One example of why this is useful is configuring a search page (we might want to show a title and an image for all results). There are drawbacks, however, of sharing too many fields. For example, if a node from an “Employee” content type needs to store his company logo as an image field, it might be a bad idea to use “field_image”. Another problem might be when exporting features (which feature should store the “field_image” field base, if it’s shared between content types from different features?).
- Price - we use the “Decimal” field type, an alternative would be to install the “currency” contrib module and use that.
The result is shown below:
Now let’s create a nodequeue called “Featured products”. Here we will use a “smart queue”, specifically a “taxonomy queue”, which will create separate lists for each term of the Category taxonomy. We restrict the nodequeue to only accept Products.
Now, let’s create the two view modes that will display the products. Here we make a conscious decision to create two new view modes and not reuse any of the existing ones. We decide this because these modes are specific to products, and they will probably not be used in many places in the site. Teaser, for example, sounds like it could be shared between different content types and show nodes in a more standardized way.
Let’s create the two view modes and call them “Product big” and “Product small” (only the first shown here).
Now we can go to the display configuration for the Product content type, and select both view modes so that we can customize the display for them.
Now we can configure them to show the appropriate fields in each case, according to the wireframes.
The final step is, then, to create the view. Here it is, finalized:
Some things to note:
- We created the view named “Products” with the intention for it to contain many displays representing the many lists of products that will be shown throughout the site. The display is called “Featured”, corresponding to the “Featured products” nodequeue we created before.
- A relationship is added to the nodequeue, and a contextual filter to select the specific subqueue according to a taxonomy term ID. The panel will be responsible for passing this value. Here is the “Argument input” configuration, which specifies the type of value expected for this filter (a term ID):
- The pager config is set to show the first 5 items. It works best to put that limit in the view rather than in the nodequeue, because editors might want to keep more elements in the queue than are shown.
- We select “Display suite” in the Format options. This is the settings popup, which contains information about what view mode to use in which view row:
That’s it, the featured products view is all set and ready to be placed in the homepage panel.
Blog sidebar #
The blog sidebar is a form with a view below it. For the form we’ll use the Webform module, which gives us the ability to create arbitrary forms for our site as nodes. For the view we’ll create a Blog Post content type, and create the view to show the latest posts using the Teaser view mode.
After enabling the Webform module, you will see a Webform content type. We can simply create a node from this content type, and set up its fields in the Webform tab. The specifics are outside the scope of this course, but it should look like this:
One thing that needs to be specified in the “Form settings” tab is that the webform should be available as a block. This will allow the form to be placed in the homepage panel configuration.
Next is the blog view. The configuration for the content type, teaser display, and view is shown below.
Featured article #
Drupal provides a “promote to homepage” checkbox for nodes. We can use this property and select the latest promoted article in a view, like so:
Secondary products #
This view will be created as the second display of the Products view we created before. It receives a contextual filter to select the category, and it has some exposed sort options.
Bottom categories #
The last piece of the puzzle is a list of three links to category pages. Content editors need to be able to select any category, so a nodequeue might be the first option that comes to mind. Except nodequeues only work for nodes. A new module, “Entity queue”, promises to solve this issue, but it’s not stable yet, so let’s do this a different way, one that will hopefully illustrate how panel contexts work. We will manually select three taxonomy terms as “contexts”, and then show them in the appropriate region with a new view mode that we’ll call “Block”.
Putting everything together #
Let’s go back to the homepage panel configuration.
First, let’s select the bottom 3 categories as contexts. We will also need two more to pass to the product lists:
Now let’s go to “Content” and add everything!
Some things to note:
- You’ll notice we’re not using the “Middle” region. This is not ideal. We could create a custom layout in code, in the theme folder (we should do that to simplify the HTML too, and have complete control over styles).
- The product list views accept a taxonomy context as the view’s contextual filter. The system knows how to pass the actual term ID to the view, because we configured the expected type in the view. If you have other contexts that are not taxonomy terms, they will not show in the configuration for these particular views.
- You can’t actually see this working until there is some test content and the nodequeues are filled. Still, if you do that, the page will still look pretty horrible. The structure is all there, though, ready for a themer to do their thing. Here is a screenshot of how it all looks when test content is created using the Devel module:
Category page #
In our structure, “Category” is a taxonomy vocabulary, so the Category page is actually the “view taxonomy term” page for that vocabulary.
The Pages configuration interface gives you the option of enabling the term_view
panel, which we will use to customize this page.
Once enabled, go into “Edit” and you’ll see an empty panel. We need to create a variant. Generally when using term_view
(and, later, node_view
) we want to have a variant for each vocabulary (or content type). So we specify “Selection rules” to make this variant work only when the term is from the Category vocabulary.
The layout we will use is the “Single column” one, since our blocks will cover all the page width. We click on “Continue” a couple more times, and we get to this page:
Here we set the title to “%term:name
”. We can do this because we have a context configured automatically in this panel identified by “%term
”, which is the taxonomy term object that the user will see in the final page. So, if we go into the “Clothing” term, “%term:name
” will translate to “Clothing”.
Finally, we click on “Create variant”, and then “Update and save”. We will add the blocks later. A category page now looks completely empty.
Editorial content #
For showing editorial content related to the category, we will add an entity reference field to the vocabulary, with the possibility to add 3 items. For now we will only be able to add articles to it.
We will later add this field directly to the panel, using the “rendered entity” formatter to display the articles with an appropriate view mode.
Featured products #
This works the same as the Editorial Content block: an entity reference field in the taxonomy with a maximum of 3 elements.
Products view #
This is the main view for this page. We will not use the existing “Products” view created for the homepage, because the presentation is very different. This view has a lot more functionality, so it deserves to be promoted to a separate view.
Noteworthy:
- There are some exposed filters. We don’t care for their presentation at this point, so we use standard Views functionality. Same with exposed sort options.
- There are two “layout options” shown in the top-right corner in the wireframe. These are simply two displays with a selector so that the user can switch between them, but for now we will only build the first one and call it “Grid”.
- We have a “Category” contextual filter, which will receive the term ID from the panel. Don’t forget to configure the options in “Argument input”.
- We are re-using the “Product small” view mode created for the homepage.
- Let’s turn the “AJAX” option on just because it’s easy and cool.
Panel config #
We now have everything we need. Let’s put it all in the panel:
The “Featured products” block has a customizable title (in the wireframe example, the category is “Suits” and this title says “Suiting for Spring”). We do this by adding an extra text field to the taxonomy, and simply including it in the panel configuration.
Product detail page #
The detail page works very similar to the Category page, but uses the node_view
panel instead of the term_view
one. This is the simplest of the three, so we’ll keep it short.
The process of enabling the panel and creating a variant is the same as before, but this time we configure the selection rule to filter by content type.
Breadcrumbs #
Each product has a category, and the categories can have parents (e.g. “Apparel -> Suits”). This block shows the product’s category and its parents. A quick Google search returns the Hierarchical Term Formatter module, which seems perfect for our needs. It provides a new formatter, which can be configured right on the panel to show the Category field for the node.
Product information #
This is just fields shown in the panel. We could build a mini-panel, or play around with the layout, but the idea is the same: showing fields from the product node.
Related products #
This is a new display in our “Products” view that receives two contextual filters:
- The current node ID, configured as “Exclude”. This makes the view not show the same product the user is viewing in the whole page, which wouldn’t make sense.
- A term ID to select products from. This could change in the future to a more complicated “related” logic, but for our purposes it’s enough to show products from the same category.
Bottom categories #
We copy the same functionality we have in the homepage. There could be some logic here to select the three categories to be shown (a view with some specific criteria depending on the product node), and once that’s defined it can easily be changed.
Panel configuration #
This is the final panel configuration for the Product detail page. We used the same layout as the homepage.
Features #
In order to do clean deploys we use Features to encapsulate all that we’ve been doing. We will use the “JBS” prefix to separate our features from other modules; this is generally considered good practice.
For this demo we’ll have the following features:
- JBS Model: Will contain content types, taxonomies, and anything else that is necessary to store the content only.
- JBS Pages: This feature will have all the panel config, views, display suite, etc.
- JBS Test content: We will export test data to this feature.
JBS Model #
Let’s create the “model” feature then. We will only show how the “recreate” screen looks like; this shows what’s in the feature. Note that Drupal automatically adds dependencies, so for example when including the “Product” content type, it will add the “field_brand” and the rest of the fields.
Note that this feature includes the “Ask Anything” webform. This is actually a node, and requires the “uuid” and “features_uuid” modules to be enabled, including a configuration (in admin/config/content/uuid_features
) so that webforms are exportable to features.
JBS Pages #
This contains all the panel configuration, views, and display suite settings. This is normally split into different features, so for example a “JBS Blog” feature could contain the “Blog post” content type and related views and other objects.
JBS Test content #
This feature contains nodes and taxonomy terms. These were generated by the “Devel generate” module.
Downloads #
You can download the features used in this exercise here. If you do a clean Drupal 7 install, put these into the modules folder, and enable them using drush
, all dependencies will be downloaded automatically and you should see the same site we’ve been working on.