Package Naming

Packages should have descriptive and unique names. For the purpose of asset organization it is helpful for packages with a long name to also have a unique shortened version of that name (eg: “Personal Portfolio Site” by Marketpath -> “mp-pps1”) for use as an identifier. For the sake of consistency we recommend using kebab-case for all paths.

Standardization

Where applicable, packages should conform to a predefined set of standards, which should be identified using the “standard” label (eg: “standard:mpss1-bootstrap5”). This is useful for guaranteeing interoperability to the greatest extent reasonably possible between packages utilizing the same standard (see our MPSS1 documentation for an example of what that standard might look like).

Package Composition

Wherever possible, large packages should be broken down into smaller component packages. This centralizes the creation and maintenance of components used in multiple other packages - which should improve both the quality and buildout time of new sites and packages. Of course, each package used should be high-quality and must also follow the Marketpath package development guidelines or this will not work. Only assets specific to the current package should be unique.

Package Types

Full site

  • Should ONLY be used for packages that can and should be installed when a site is first created, and must follow the “Full Site Guidelines” below in addition to these Package Guidelines.
  • Will generally include numerous other packages of all types (but no other Full Site packages) along with all other assets on the site that are not included as part of another package.

Page

  • Should be used for packages that include a small number of page templates (ideally only one, although in some cases it may make sense to bundle multiple page templates into a single package) and any related assets (javascript, stylesheets, etc…). These packages should be as lightweight as possible while still being complete.
  • To improve reusability (in particular inside full site packages) you should NOT include sample pages in the page package - instead include information about it on the demo and/or documentation page for the package.
  • Will generally include multiple “widget” packages, and possibly some others.

Widget

  • Should be used for packages that contain a visible “widget” on the site (eg: pagination, banner, CTA, blogroll, tag cloud, etc…). Widgets will not typically do anything special by themselves but must be included by another template - likely with some configuration involved - to output to the live site.
  • Will typically include one or more “component” packages, and possibly a “data” package.

Form

  • Should be used for packages that include a small number of form templates (ideally only one, although in some cases it may make sense to bundle multiple form templates into a single package) and any related assets (javascript, stylesheets, etc…). These packages should be as lightweight as possible while still being complete.
  • You should NOT include a sample form in form packages - instead include information about it on the demo and/or documentation page for the package.
  • Will generally include one or more “component” packages.
  • Test form templates using all of the field types, conditionals, and validation options to ensure completeness.
  • Form packages should generally be set to auto-update by default - making form maintenance easier for everyone. However, this also means that form packages in particular should NOT be updated until the updates are thoroughly tested.

Gallery

  • Should be used for packages that include a small number of gallery templates (ideally only one, although in some cases it may make sense to bundle multiple gallery templates into a single package) and any related assets (javascript, stylesheets, etc…). These packages should be as lightweight as possible while still being complete.
  • You should NOT include a sample gallery in gallery packages - instead include information about it on the demo and/or documentation page for the package.
  • Will generally include one or more “component” packages.

Data

  • Should be used for packages that contain reusable data or configuration objects. Some examples might be a package for a reusable datastore definition, a reusable list of objects (eg: US States), or a specific snippet to be included in the header or footer of multiple sites.
  • Will not typically include any other packages, and will only include the smallest number of assets necessary for its stated purpose.

Component

  • Should be used for packages that contain reusable “components” (ie: partials, javascript libraries, etc…) that make up the building blocks of larger packages and of sites. These packages will not typically do anything special by themselves but must be used according to the instructions to achieve their intended purpose. Ideally each component package should be designed to accomplish a single purpose.
  • May include other component and/or data packages but will often be the “smallest unit”. It should only contain those assets and packages required to accomplish a single purpose.

Organization

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

The names for all sample content should start with “SAMPLE: “ (Name, not Title) unless they must be named differently for a specific reason.

Place all sample content under a folder called “samples” unless they must be in a different folder for a specific reason. Place all sample images in “samples/images” unless they must be in a different folder for a specific reason.

Content that is not central to the functionality of the package should be included in the package as “Install Only” in order to make it as easy as possible for content editors to make changes without fearing that their changes will be overwritten or make package updates more complicated than necessary. This applies doubly for folders.

Wherever possible, restrict folders and templates to specific entity types. This makes it easier for users to find the desired folder/template while creating and managing content. Also include and enforce default root paths for folders, blogs, and datastores; and set the default template for blog posts etc…

Asset Paths and Naming

Templates, javascript, and stylesheets should be organized according to the company, package name, and asset type.

  • The Path should always start with your lowercase company name (eg: “marketpath”) followed by the package identifier (eg: “mp-pps1”)
  • In the event that you want or need to include multiple versions in the same package, the package identifier should be followed by the version number. For many packages it may even be a good idea to include a version number in your initial version in order to make future updates to the package easier.
  • Javascript and stylesheets should be under their respective “js” and “css” paths.
  • You may optionally organize assets under other sub-paths but should only do so either if your package will include a large number of assets or if you are copying assets from another source and are using their file organization schema.
  • Assets intended to be consumed by other assets (eg: partial templates, SCSS included files, non-compiled javascript files, etc…) should have names that start with an underscore (eg: _partial.liquid)
  • Asset names should end in an appropriate extension (eg: .liquid, .txt, .js, .css, .scss, .less)
  • Examples:
    • /marketpath/superbanner/v1/_banner.liquid
    • /marketpath/superbanner/v1/js/mpbanner.js
    • /marketpath/superbanner/v1/js/_mpbanner.js
    • /marketpath/logisticall/home.liquid
    • /marketpath/logisticall/contact.liquid
    • /marketpath/logisticall/_sidebar.liquid
    • /marketpath/logisticall/_menu.liquid
    • /marketpath/logisticall/css/main.scss
    • /marketpath/logisticall/js/main.js

Consider keeping overrides under a different root path (eg: /overrides/marketpath/superbanner/v1).

If one or more javascript and/or stylesheet assets are taken from another source (eg: git, a third party website, etc…) then the original file structure and naming conventions should be used under the relevant root path.

Template, Javascript, and Stylesheet names and paths should not be changed once the package has been activated. This is so that other developers may re-use your assets without fear of a package update breaking their code.

Code Standards

Code standards only apply when working with original code - it is impractical, improper, and unhelpful to backport new code standards over existing third-party code.

Try not to get too fancy with your code unless it is clearly called for - fancy code takes more time, has more bugs, and requires more maintenance than simple code. If you find yourself wanting or needing fancy code, put it into its own package with clear documentation.

Try to use full and descriptive names for functions, mixins, filenames, variables, etc… They make the code easier to read and maintain. Use proper indentation to make logical and visually-distinct groupings of code.

Inside a package - or a group of packages - follow a consistent coding methodology. This means, for example, that if you use BEM-style classnames in one component then you should attempt to apply it everywhere. It also means that you should not mix variable naming schemas if you can avoid it (eg: $primary-color, $orange, $color-theme-background, etc…).

Javascript

Where possible when writing small quantities of javascript, write vanilla javascript instead of relying on other frameworks. This will make your code more portable and reusable.

  • Good: document.getElementById(“menubtn”).addEventListener(“click”, doSomething);
  • Bad: jQuery(“#menubtn”).click(doSomething);

Of course, if you are writing a lot of javascript where another framework would be helpful and makes sense then go ahead and use it - but the javascript framework should generally be included in its own separate package and referenced by your package rather than included directly in your package javascript files.

All third-party javascript libraries should include a version number - either in the path or in the filename, while first-party javascript (code that YOU write) may optionally include a version number. The version number typically only needs to include major versions so long as there are no breaking updates (not backwards-compatible) in minor version updates.

Functions and variables should be scoped to a single global object (or a small number of global objects if necessary) with a sufficiently unique name to prevent naming conflicts. It often helps to write code inside an IIFE to prevent global scope pollution.

  • Good: marketpath_maps.init()
  • Bad: init_maps()

All javascript assets should end in .js

Stylesheets

When copying stylesheets from third-party libraries, use the same type of stylesheet that they originally used (so if they wrote vanilla CSS then you should write CSS too, or if they wrote SCSS your code should be SCSS).

When creating your own stylesheets, use scss or less since those are easier to customize. Furthermore, when you do so, consider breaking up your stylesheets into smaller (partial) stylesheets which may be imported into your main stylesheet.

Mark partial stylesheets as not compiled.

Stylesheets should be careful not to hide visual indicators (such as bullets) in editable content areas. This makes it difficult to edit the actual content. Additionally, changing text to white makes it difficult to see the text in a content area. When it is necessary or desirable to make text white (or light-colored), consider adding a CSS override for body.cke_editable to make the text visible inside the HTML editor.

All stylesheet assets should end in either .css, .less, .scss, or .sass

Templates

Templates should be clean, well organized, and labeled in an intuitive manner.

Limit the total number of page templates, each restricted to the specific entity types they should be used with. Ideally each page template should be restricted to a single entity type, since that will make for a better user experience when creating new pages.

Where possible add images to your page templates, which should be representative of what a page created using that template might look like when your package is installed on another site.

Break up your partial templates into individual logically-organized templates for each section of your site. Use “DRY” templates (“Don’t Repeat Yourself”) wherever possible and reasonable.

By creating templates for common “functionality”, you can use them almost like custom reusable functions. Just be sure to document how to use them in a comment at the top of each partial template - including the purpose, “Inputs”, “Outputs” (if applicable), and override/customization options (if applicable).

Template variables should take advantage of {% var %} and {% set %} functionality as much as possible - {% assign %} should only be used where it is strictly necessary, and when used the variable name must be sufficiently unique to avoid naming collisions. Additionally any variables saved on the global scope using the {% assign %} method should be described in the package documentation.

Partial templates that rely on a particular CSS or javascript framework (eg: “bootstrap”) should note it by a comment at the top of the template or some other equally clear method.

All template assets should end in either .html, .liquid, .txt, or another extension that makes sense intuitively for that asset.

For full compatibility with these development guidelines all templates should start with a comment that includes:

  • A description of the purpose of the template
  • Any CSS or javascript assets that the template requires
  • A list of all of the “inputs” (variables that change how this template works)
  • A list of all of the “outputs” (variables that are set on the parent scope in this template)

Includes

All CSS and javascript should be added to the document using the {% add_javascript %} and {% add_stylesheet %} methods. Note that adding the same javascript or stylesheet multiple times is OK since liquid will only output it once in the compiled page. Be sure to clearly document how to customize or disable your javascript and stylesheet files.

When including javascript and stylesheets from templates, you should make every reasonable effort to ensure the following:

  1. You only include the minimum code necessary to make your package look and behave correctly (do not include unneccessary code, placeholders, etc...). For example: you should not compile an entire CSS or JS framework for access to a few small members.
  2. Your code will work when included multiple times on a page (eg: you do not rely on unique ids unless you can guarantee within reason that the id will only appear once in the DOM)
  3. It would be simple for a consumer of your package to include your scripts and/or styles in their main site javascript and/or stylesheet and rather than from within your component.
  • Good: % unless exclude_component_css %}{% add_stylesheet "/path/to/component.scss" %}{% endunless %}
  • Bad: {% add_stylesheet "/path/to/component.scss" %}

Documentation

Each package should have:

  • A publicly-accessible documentation page for developers
  • Site Instructions for editors if applicable
  • A publicly-accessible demo page if possible

Particularly note any functionality that uses custom (or core) site settings since those values will need to be intentionally reviewed and set after the theme is installed.

Customization

Each package needs to be customizable without having to override core package assets (assets set to "install and update"). The documentation should clearly state the ways that the theme may be customized without overriding core assets.

In some cases this may be accomplished by passing in configuration variables to components. In other cases you should use install-only assets, such as template and variable override files. Note that wherever possible default values should be included even if they are not explicitly passed in or overridden. This will make your components more robust in general and will make package updates smoother.

Multi-Lingual Friendly

It is not necessary at this time for all packages to be multi-lingual. However, if you desire for a package to be usable on a multi-lingual website then all text should be customizable by language. Some ways to do this:

  1. Define separate templates for each language. However, this will result in a lot of extra templates when only a few pieces of text need to be customized.
  2. Define the language as a dictionary or as individual variables in a template. Switching language would simply require including a (configurable) language-specific template to load the alternate text into the dictionary and/or variables.
  3. Define the text in custom fields. However, if you do this make sure that you provide a good fallback and/or lookup mechanism so that the text does not have to be copied every time a new page is created (and so that updating the text only requires updating it in one place to apply across the site). Example: Define the word for "Event" on the calendar page rather than separately on every calendar entry.

Accessibility Standards

All packages should make a good-faith effort at outputting "accessible" markup. Before activing a package, consider how screen readers and different users/browsers may interpret the output. There are a number of relatively simple ways to improve the accessibility of your code, including but not limited to:

  • Proper heading order (eg: no skipping from H1 to H3 etc...), and headings utilize the proper heading tags - not styled paragraphs, divs, or spans
  • All images have alt text. If the image acts as decoration and does not provide any useful content, it should have an empty alt="" attribute. Alternatively, images may use aria-label or aria-labelledby attributes, although this is less common.
  • ARIA roles and attributes, as well as alt, title, and other HTML accessibility attributes
  • semantic markup
  • Screen reader utilities (eg: .sr-only and .sr-only-focusable classes in bootstrap)
  • proper color contrast and clearly visible controls
  • Avoiding hover for any significant navigation or functionality
  • Keyboard navigation support - by way of HTML tabindex attributes, javascript, and other methods
  • Visual distinct and identifiable styles for focused elements - often accomplished using an outline
  • Respect browser preferences
  • Respect browser zoom

Intellectual Property

Packages must not include any assets which you do not have the rights to distribute to anyone with access to your package. This means that public packages cannot include assets that are not free for commercial use. If you have the right to distribute that content (scripts, images, etc…) it must be documented in the code and must follow any other requirements stated by the owner of the intellectual property.

If your package includes content that requires agreement to the terms and conditions, those terms and conditions must be included in the package agreement. However, you should NOT include agreements for child packages in the parent package since users will be required to agree to the child packages at the time that they are installed.

You should not have to include more than one agreement per package - if your package requires agreement to multiple terms and conditions then it should probably be broken down into separate packages with their own agreements.

In particular, you must double-check that you have permission to distribute all images and documents in each package.

External Resources

Avoid referencing outside JS or other resources where possible. Instead these assets should be served from the Marketpath CMS site.

Examples of files that are ok to use from their original source:

  • Fonts (eg: Google Fonts, Adobe Fonts, Font Awesome, etc...)
  • Google tag manager/analytics/etc…
  • Other proprietary third-party services that instruct you to use their provided URL (eg: AppCues, LogRocket)

Examples of files that should be copied to the Marketpath CMS site:

  • Bootstrap
  • jQuery
  • Angular
  • Vue
  • Images and documents from other sites/services (ie: no hot-linking)

Any third-party APIs that require a “key” (or “token”, etc…) should use a custom site setting for that key - with no default value. Otherwise you will end up exposing your key to other developers and bad things will happen!

Consider the Editor Experience

When building templates, consider how easy it is for a user to create and edit new pages. Field names should be obvious and most fields should have descriptions. Use field conditions and validation where possible. Field values should be easily edited and flow in the same order as their position on the page if possible.

Repeated Content

While the main content on each page should be unique, much of the supplemental content on a website may be repeated on multiple pages. Where possible, repeated content (eg: testimonials, projects, featured content, etc...) should be managed in a single location and referenced across the site.

It may be valuable for repeated content to be able to be customized on individual pages while remaining the same on all other pages. In that case, the default option should be to use the "standard/default" values and only provide custom values when the user explicitly overrides the default values.

Examples:

  • A template that displays testimonials may randomly pull testimonials from a datastore, but the developer may provide an option for the user to manually select the testimonials to display on any given page instead.
  • A template that displays a "Core Values" article list may have an option to use the values from another page (eg: the home page by default) or set custom values.
  • A template that displays "Our Story" may reference a snippet, with a default snippet selected. Changing the value displayed would be as simple as selecting a different snippet, and updating any snippet would update it on every page which it is displayed on.

Default Values

Only set default values on custom fields where the default value would make sense on most websites, since there is a strong probability that the default values will find their way onto live sites. In particular this means that default values should contain no dummy text (Lorem Ipsum or similar) or proprietary intellectual property.

Don’t Over Engineer, Larry!

While it may be helpful to a small number of users, you shouldn’t add every conceivable option for every possible scenario. KISS - keep it simple stupid. Too many options add confusion.

 

Changelog

 

The following changes have been made to the Package Development Guidelines:

Date Change
01/12/2023
  • Added information about Repeated Content and Default Values under Consider the Editor Experience.
  • Added Multi-Lingual Friendly information under Customization.
03/14/2023
  • Added new recommendation to limit page templates to a single object type and include a represntative image