Skip to documentation content

Development Practices

Development Practices

Recommendations for building any Marketpath site or component well: code, templates, asset names, quality and accessibility, and the editor's experience.

These practices help on every Marketpath site and component, whether it is a one-off site, a CMS package, or a site assembled and imported from files. They are recommendations, and most give the reason for the advice so you can judge when it does not fit. Marketpath Site Standards 1 (MPSS1) is the one formal standard, and it covers interoperability only; the rules for publishing a CMS package are in Package Development Guidelines.

The sections cover code, templates, asset names and paths, quality, accessibility and rights, and the experience of the editors who will use what you build. The planning decisions that come before them, such as who owns content, how templates read it, and where fields are defined, are in Planning and Strategy.

Code Practices

Keep code you write simple, consistently named, and scoped: vanilla javascript where practical, versioned third-party libraries, and stylesheets in SCSS or LESS with customizable variables.

These practices apply only to code you write yourself. Backporting new standards onto existing third-party code is impractical, improper, and unhelpful.

General
• Do not get fancy unless it is clearly called for. Fancy code takes more time, has more bugs, and needs more maintenance. If you need it, put it in its own component with clear documentation.
• Use full, descriptive names for functions, mixins, filenames, and variables, and use indentation to group code visually.
• Follow one consistent methodology within a site or a group of related components. If one component uses BEM class names, use them everywhere, and do not mix variable naming schemes (for example, $primary-color, $orange, and $color-theme-background).

Javascript
• When writing small amounts of javascript, prefer vanilla javascript over a framework so the code is portable and reusable. Good: document.getElementById("menubtn").addEventListener("click", doSomething); Bad: jQuery("#menubtn").click(doSomething);
• If a framework genuinely helps with a lot of javascript, use it, but keep the framework in its own asset and reference it rather than bundling it into your javascript files.
• Include a version number in the path or filename of every third-party library. First-party code may optionally include one. Usually only the major version is needed, as long as minor updates are backwards compatible.
• Scope functions and variables to a single global object (or a small number of them) with a name unique enough to avoid conflicts. Writing code inside an IIFE helps avoid polluting the global scope. Good: marketpath_maps.init() Bad: init_maps()
• End every javascript asset in .js.

Stylesheets
• When copying stylesheets from a third-party library, keep the library's original type: CSS stays CSS, SCSS stays SCSS.
• For your own stylesheets, use SCSS or LESS, which are easier to customize, with customizable variables wherever possible (most importantly for colors and font styles), and consider splitting them into partial stylesheets imported by a main stylesheet.
• Mark partial stylesheets as not compiled.
• Do not hide visual indicators such as bullets in editable content areas, which makes content hard to edit. Light or white text is also hard to see in a content area; when it is needed, add a CSS override for body.cke_editable so text stays visible in the HTML editor.
• End every stylesheet asset in .css, .less, .scss, or .sass.

Template Practices

Keep templates few, restricted by entity type, DRY, and documented at the top; split components into a base partial and an editor partial; and include CSS and javascript so consumers can bundle or disable it.

Templates should be clean, well organized, and labeled intuitively.

Templates
• Limit the number of page templates and restrict each to the entity types it should be used with. Ideally each page template is restricted to a single entity type, which makes creating new pages easier.
• Where possible, add an image to each page template that shows what a page built with it looks like.
• Break partial templates into logically organized templates for each section of the site, and keep them DRY ("Don't Repeat Yourself") wherever reasonable. Partials for common functionality work almost like reusable functions.
• Open every template with the contract comment described in Template Best Practices. For a reusable component, the comment should also list the CSS and javascript assets the template requires, any CSS or javascript framework it relies on (such as Bootstrap), and any override or customization options.
• Follow Variable Scopes when choosing between var, set, and assign. When a template does write a variable to the root scope with assign, give it a name unique enough to avoid collisions and describe it in the component's documentation.
• End every template asset in .html, .liquid, .txt, or another extension that makes sense for the asset.

Common components
Include common UI components as partial templates so developers can change the site and add new sections easily. Ideally these come from reputable components, though some may be custom to the site. Common components include:
• Menus and navigation
• Banners
• Buckets and cards
• Galleries and carousels
• Form and table elements and filters
• Accordions and tabs
• Related and recent content
• Any other element repeated on the site

Two partials per component
A pattern that works well is to split a component in two. The base partial has no editor fields: it takes raw data as input and does the rendering and logic. The editor partial holds only the editor fields, turns them into clean variables, and passes them to the base partial. A second template can instead fetch the data and include the base partial. Splitting lets you swap fields without touching rendering logic, and reuse the base partial where the data comes from code instead of fields. Prefix names by domain and responsibility (for example nav-bootstrap5, banner-hero, cards-testimonials) and keep one clear entry partial per component.

Including CSS and javascript
Use {% add_javascript %} and {% add_stylesheet %} as described in Template Best Practices; this section covers only what is specific to reusable components. Clearly document how to customize or disable your javascript and stylesheets.

When a template includes javascript or stylesheets, make every reasonable effort to ensure that:
1. You include only the minimum code needed for the component to look and behave correctly: no unnecessary code or placeholders, and no compiling an entire CSS or javascript framework for a few small members.
2. The code works when included more than once on a page. Do not rely on unique ids unless you can reasonably guarantee the id appears once in the DOM.
3. A consumer can easily include your scripts and styles in the site's main javascript and stylesheet instead of from within your component.
Good: {% unless exclude_component_css %}{% add_stylesheet "/developer/v1/component.scss" %}{% endunless %}
Bad: {% add_stylesheet "/developer/v1/component.scss" %}

To make it easy to bundle your styles into the main site stylesheet, create two stylesheets for each component, one compiled and one partial. The compiled stylesheet includes the dependencies (such as variables and frameworks) and the partial. The partial holds only the styles, assumes the variables are declared, and opens with a comment describing what it requires. For example:
• /developer/v1/component.scss (compiled) includes "/_variables.scss" and then "_component.scss"
• /developer/v1/_component.scss (partial) opens with a comment such as "Depends on variables defined in the _variables.scss file", followed by the component's rules

Asset Names and Paths

Name and place templates, javascript, and stylesheets consistently: kebab-case paths, js and css folders, an underscore for assets other assets consume, and no renaming of assets that others rely on.

A site is easier to maintain with a clear organizational structure. Use folders and paths that make sense, are intuitive, and are consistent between assets, components, and sites.

Paths and names
• Use kebab-case for all paths so they stay consistent.
• Put javascript under a "js" path and stylesheets under a "css" path.
• Use other sub-paths only when there are many assets, or when you copy assets from another source and keep its file organization.
• Start the names of assets consumed by other assets (partial templates, SCSS partials, non-compiled javascript) with an underscore, for example _partial.liquid.
• End asset names in an appropriate extension, such as .liquid, .txt, .js, .css, .scss, or .less.
• If javascript or stylesheet assets come from another source (git, a third-party website), keep the original file structure and naming under the relevant root path.

Do not rename assets that others rely on
Do not change template, javascript, or stylesheet names or paths once other templates or sites use them, so other developers can reuse your assets without fear that an update will break their code. If a breaking change is unavoidable, keep the original asset unaltered and put the changed copy under a new version path, for example /marketpath/superbanner/v2/ beside /marketpath/superbanner/v1/.

A reusable package also starts every path with a company name and package identifier; Package Organization describes that convention.

Quality, Accessibility, and Rights

Produce valid, accessible, mobile-friendly output, use only assets you may distribute, and serve third-party resources from the site rather than hot-linking them.

Valid output
All templates and pages should produce valid HTML that passes W3C validation (https://validator.w3.org/). JSON, XML, RSS, and any other output should pass the validation relevant to its format.

Accessibility
Make a good-faith effort to output accessible markup. Before activating a template or component, consider how screen readers and different users and browsers will interpret the output. Simple ways to improve accessibility include:
• Proper heading order (no skipping from H1 to H3), using real heading tags rather than styled paragraphs, divs, or spans
• Alt text on every image. A purely decorative image should have an empty alt="" attribute; aria-label or aria-labelledby are less common alternatives.
• ARIA roles and attributes, plus alt, title, and the other HTML accessibility attributes
• Semantic markup
• Screen reader utilities, such as the visually hidden classes in Bootstrap
• Proper color contrast and clearly visible controls
• No significant navigation or functionality that depends on hover
• Keyboard navigation support, through tabindex attributes, javascript, and other methods
• Distinct, identifiable styles for focused elements, often an outline
• Respect for browser preferences and browser zoom

Mobile friendly
Usually through responsive markup, though other approaches are acceptable. Mobile-first design is preferred but not required. Check every relevant component for mobile responsiveness.

Rights
Only include assets you have the right to use and distribute, such as scripts, fonts, and images, and document that right in the code along with any other requirement set by the owner. Be especially careful with images and documents from other sites. Reusable packages have further rules about licenses and agreements; see Package Rights and Agreements.

External resources
Avoid referencing outside javascript or other resources where possible; serve those assets from the Marketpath CMS site instead.
Fine to use from their original source:
• Fonts (Google Fonts, Adobe Fonts, Font Awesome, and similar)
• Google Tag Manager, Analytics, and similar
• Other proprietary third-party services that instruct you to use their URL (for example, Appcues or LogRocket)
Copy to the Marketpath CMS site:
• Bootstrap
• jQuery
• Angular
• Vue
• Images and documents from other sites or services (no hot-linking)

Any third-party API that requires a key or token should read it from a custom site setting with no default value. Otherwise the key is exposed to everyone who can see the code, including every developer who installs it as part of a package.

Editor Experience

Design templates for the editors who use them: clear fields in page order, repeated content managed in one place, safe defaults, no more options than needed, and text that can be translated.

When building templates, consider how easily a user can create and edit pages. Field names should be obvious, and most fields should have descriptions. Use field conditions and validation where possible. Field values should be easy to edit and, where possible, follow the same order as their position on the page. Designing Editor-Friendly Fields covers each of these in detail.

Repeated content
The main content of each page should be unique, but much of a site's supplemental content repeats across pages. Where possible, manage repeated content (testimonials, projects, featured content) in one location and reference it across the site; Choosing Content Ownership covers where it should live.

It can be useful to customize repeated content on one page while every other page keeps the shared version. In that case, default to the standard values and use custom values only when the user explicitly overrides them. For example:
• A testimonials template may pull random testimonials from a datastore, with an option to select the testimonials for a given page manually.
• A "Core Values" article list may default to the values from another page (such as the home page), with an option to set custom values.
• An "Our Story" section may reference a snippet with a default selected. Changing it means selecting a different snippet, and updating the snippet updates every page that shows it.

Default values
Set a default value on a custom field only when that value makes sense on most websites, because defaults are likely to end up on live sites. Default values must never contain dummy text (Lorem Ipsum or similar) or proprietary intellectual property.

Do not over-engineer
An option that helps a few users is not worth adding for every conceivable scenario. Keep it simple: too many options add confusion.

Multi-lingual friendly
Not every site or component needs to be multi-lingual. If one should be usable on a multi-lingual site, every piece of text must be customizable by language. Some ways to do that:
1. Define separate templates for each language. This produces many extra templates when only a few pieces of text change.
2. Define the text as a dictionary or as individual variables in a template. Switching language then only requires including a configurable language-specific template that loads the alternate text into the dictionary or variables.
3. Define the text in custom fields. If you do, provide a good fallback or lookup so the text is not copied onto every new page and updating it in one place applies across the site. For example, define the word for "Event" on the calendar page rather than on every calendar entry.