View Customization - Developer Guide | Spree Commerce

Overview

View customization allows you to extend or replace any view within a
Spree store. This guide explains the options available, including:

Using Deface for view customization

Replacing entire view templates

Using Deface

Deface is a standalone Rails library that enables you to customize Erb
templates without needing to directly edit the underlying view file.
Deface allows you to use standard CSS3 style selectors to target any
element (including Ruby blocks), and perform an action against all the
matching elements.

For example, take the Checkout Registration template, which looks like
this:

This override inserts<p>Registration is the future!</p>before the div with the id of “registration”.

Available actions

Deface applies an action to element(s) matching the supplied CSS selector. These actions are passed when defining a new override are supplied as the key while the CSS selector for the target element(s) is the value, for example:

:insert_after - Inserts after all elements that match the supplied selector

:insert_before - Inserts before all elements that match the supplied selector

:insert_top - Inserts inside all elements that match the supplied selector, as the first child

:insert_bottom - Inserts inside all elements that match the supplied selector, as the last child

:set_attributes - Sets attributes on all elements that match the supplied selector, replacing existing attribute value if present or adding if not. Expects :attributes option to be passed.

:add_to_attributes - Appends value to attributes on all elements that match the supplied selector, adds attribute if not present. Expects :attributes option to be passed.

:remove_from_attributes - Removes value from attributes on all elements that match the supplied selector. Expects :attributes option to be passed.

Not all actions are applicable to all elements. For example, :insert_top and :insert_bottom expects a parent element with children.

Supplying content

Deface supports three options for supplying content to be used by an override:

:text - String containing markup

:partial - Relative path to a partial

:template - Relative path to a template

As Deface operates on the Erb source the content supplied to an override can include Erb, it is not limited to just HTML. You also have access to all variables accessible in the original Erb context.

Targeting elements

While Deface allows you to use a large subset of CSS3 style selectors (as provided by Nokogiri), the majority of Spree’s views have been updated to include a custom HTML attribute (data-hook), which is designed to provide consistent targets for your overrides to use.

As Spree views are changed over coming versions, the original HTML elements maybe edited or be removed. We will endeavour to ensure that data-hook / id combination will remain consistent within any single view file (where possible), thus making your overrides more robust and upgrade proof.

As you can see from the example above the data-hook can be present in
a number of ways:

On elements with noid attribute the data-hook attribute
contains a value similar to what would be included in the id
attribute.

On elements with an id attribute the data-hook attribute does
not normally contain a value.

Occasionally on elements with an id attribute the data-hook will
contain a value different from the elements id. This is generally to
support migration from the old 0.60.x style of hooks, where the old
hook names were converted into data-hook versions.

The suggested way to target an element is to use the data-hook
attribute wherever possible. Here are a few examples based on
products/show.html.erb above:

You can also use a combination of both styles of selectors in a single
override to ensure maximum protection against changes:

:insert_top => "[data-hook='thumbnails'], #thumbnails[data-hook]"

Targeting ruby blocks

Deface evaluates all the selectors passed against the original erb view
contents (and importantly not against the finished / generated HTML). In
order for Deface to make ruby blocks contained in a view parseable they
are converted into a pseudo markup as follows.

Version 1.0 of Deface, used in Spree 2.1, changed the code tag syntax.
Formerly code tags were parsed as <code erb-loud> and <code
erb-silent>. They are now parsed as <erb loud> and <erb silent>.
Deface overrides which used selectors like code[erb-loud] should now
use erb[loud].

View upgrade protection

To ensure upgrading between versions of Spree is as painless as
possible, Deface supports an :original option that can contain a
string of the original content that’s being replaced. When Deface is
applying the override it will ensure that the current source matches the
value supplied and will output to the Rails application log if they are
different.

These warnings are a good indicator that you need to review the source
and ensure your replacement is adequately replacing all the
functionality provided by Spree. This will help reduce unexpected issues
after upgrades.

Once you’ve reviewed the new source you can update the :original value
to new source to clear the warning.

Deface removes all whitespace from both the actual and :original
source values before comparing, to reduce false warnings caused by basic
whitespace differences.

Organizing Overrides

The suggested method for organizing your overrides is to create a
separate file for each override inside the app/overrides directory,
naming each file the same as the :name specified within.

Using this method will ensure your overrides are compatible with
future theming developments (editor).

More information on Deface

For more information and sample overrides please refer to its
README file on GitHub.

You can also see how Deface internals work, and test selectors using the
Deface Test Harness application.

Template Replacements

Sometimes the customization required to a view are so substantial that
using a Deface override seems impractical. Spree also supports the
duplication of views within an application or extension that will
completely replace the file of the same name in Spree.

To override any of Spree’s default views including those for the admin
interface, simply create a file with the same filename in your app/views
directory.

For example, to override the main layout, create the file
YOUR_SITE_OR_EXTENSION/app/views/spree/layouts/spree_application.html.erb

It’s important to ensure you copy the correct version of a view
into your application or extension, as copying a mismatched version
could lead to hard to debug issues. We suggest using bundle show spree
to get the location of the Spree code you’re actually running and then
copying the relevant file from there.

Drawbacks of template replacements

Whenever you copy an entire view into your extension or application you
are adding a significant maintenance overhead to your application when
it comes to upgrading to newer versions of Spree. When upgrading between
versions you need to compare each template that’s been replaced to
ensure to replicate any changes from the newer Spree version in your
locally copied version.

To this end we strongly suggest you use Deface to achieve the desired
customizations wherever possible.