Close [x]

Code demarcation standard

Edit this page on GitHub

Magento core developers must follow the Magento code demarcation standard.

This standard is recommended for third-party extension developers.

Some parts of Magento code might not comply with the standard, but we are working to gradually improve this.

The standard was developed in the scope of our efforts to ensure the following:

  • Decouple visual (CSS) layer from the functional (JavaScript) layer.
  • Decouple functional (JavaScript) layer from the markup (HTML).
  • Reinstate emphasis on using of jQuery templates.
  • Reinstate emphasis on decoupling HTML, CSS and JS from PHP classes.

Use RFC 2119 to interpret the "MUST," "MUST NOT," "REQUIRED," "SHALL," "SHALL NOT," "SHOULD," "SHOULD NOT," "RECOMMENDED," "MAY," and "OPTIONAL" keywords.

Semantics

You must create non-user-oriented string literals from unabbreviated English words concatenated with a hyphen (-)

  • Helps simplify and unify naming conventions that are used to apply visual styles to page elements.

Acceptable PHTML file

<section id="some-id">
   <p> ... </p>
   <p> ... </p>
</section>
<a href="#some-id">Scroll to text</a></a>

Unacceptable PHTML file

<section id="蟹邪谐邪谢芯胁芯泻">
   <p> ... </p>
   <p> ... </p>
</section>
<section id="some_id">
   <p> ... </p>
   <p> ... </p>
</section>
<a href="#some_id">Scroll to text</a>

Semantic representation may rely on ID attribute

  • Forces engineers to think about reusable page components instead of unique singleton components.
  • Reduces long-term maintenance efforts.

Acceptable PHTML file

The following acceptable example is terse and uses an Accessible Rich Internet Applications (ARIA) approach.

<ul>
   <li class="first" type="button" aria-pressed="false" aria-controls="some-id">button 1</li>
   <li type="button" aria-pressed="false" aria-controls="some-id">button 2</li>
   <li type="button" aria-pressed="true" aria-controls="some-id">button 3</li>
</ul>
<div>
   <label for="some-id">Enter text</label>
   <textarea id="some-id"></textarea>
</div>
<a href="#some-id">Scroll to text</a>

Unacceptable combination of PHTML, JavaScript, and CSS files

The following unacceptable example replaces a single PHTML file with a combination of a PHTML, JavaScript, and CSS files.

PHTML file

<ul id="my-special-menu">
   <li id="buttonId1" class="first" type="button">button 1</li>
   <li id="buttonId2" type="button">button 2</li>
   <li id="buttonId3" type="button">button 3</li>
</ul>

JavaScript file

$('#my-special-menu').on('click','li[id^="button"]', function() { ... })

CSS file

#my-special-menu { ... }
#my-special-menu > li { ... }

Code demarcation

Visual representation must rely on only form element type attributes, HTML tags, CSS classes, or pseudo-classes

  • Enforces clean, strict separation between visual and business logic layers.
  • Allows frontend and backend teams to work independently.
  • Allows changing look and feel without affecting business functionality, and vice versa.
  • Enables frontend teams to clean up old styles quickly and easily when refactoring.

Acceptable CSS file

section h1 { ... }
ul > li.first { ... }
.caution { ... }  // Actions such as delete, remove, which remove data from the site.
.caution.link { ... } // if custom styles are needed
.caution.button { ... } // if custom styles are needed
form .field.password { ... }
form input[type="password"] { ... }
section.content { ... }
nav li { ... }
nav li.active { ... }

Unacceptable CSS file

#header { ... }
[data-action="delete"] { ... }
form input[name="password"] { ... }
section[role="main"] { ... }
[role="menu] [role="menuitem"] { ... }
[role="menu] [role="menuitem"].active { ... }

You must not hard-code CSS styles in JavaScript files

Exception: CSS attributes where values must be calculated beyond the css-topics/LESS code.

  • Simplifies change of the default look and feel by adding CSS classes to and removing them from elements.
  • Improves style extensibility.
  • Reduces long-term maintenance efforts by containing CSS styles in a single place.

Acceptable JavaScript widget file

...
   options: {
      hOffset: 0,
      myCustomElement: '[data-container="my-custom-element"]'
   }
...
   this.element.toggleClass('hidden');
...
   this.options.hOffset = /* calculation based on dimensions of some DOM elements within a widget */
   this.element.find(this.options.myCustomElement).css({'margin-top', this.options.hOffset + 'px'})
...

Unacceptable JavaScript file

this.element.on('click', function() {
   if ($(this).is(':visible')) {
      $(this).css({ visibility: 'hidden' });
   } else {
      $(this).css({ visibility: 'visible' });
   }
});

You must not use inline CSS styles inside HTML tags

  • Improves style extensibility allowing engineers to overload styles easier by toggling classes.
  • Enforces clean, strict separation between visual presentation and markup.
  • Enables frontend teams quickly and easily clean up old styles.

Acceptable PHTML file

<div class="no-display"> ... </div>

Unacceptable PHTML file

<div style="display: none;"> ... </div>

Business logic and JavaScript

Business logic must rely on only the form, form element name attributes, or data attributes

  • Enforces clean, strict separation between visual and business logic layers.
  • Allows frontend and backend teams to work independently.
  • Allows changing business logic without affecting styling and vice versa.

Acceptable PHTML file

<div data-mage-init="{myWidget: [option1: 'hi']}"></div>

Acceptable JavaScript file

...
this.element.find('[data-action="delete"]').on( ... );
this.element.on('click', '[data-action="delete"]', function() { ... });
...
// Globally initialized widgets
$('[data-role="tooltip]').tooltip();  // Globally for ALL tooltip elements
...

Unacceptable PHTML file

<div id="my-widget"></div>

Unacceptable JavaScript file

$('#my-widget').doSomething();
$('.parent').on('click', '.button', function() { ... });
$('form').validate();
$('[role="menu"]').navigation();

You must not select DOM elements based on HTML structure

  • Allows frontend teams to modify markup and themes without affecting business logic.

Acceptable JavaScript file

this.element.find('[data-action="edit"]');
this.elements.closest('[data-container]');

Unacceptable JavaScript file

this.element.children().children().html('hello world');
this.element.parent().find('[data-action="edit"]').data('entity_id');

You must use jQuery templates to insert recurring markup into DOM structure

  • Reinstates emphasis on jQuery templates. For more information, see JavaScript Coding Best Practices.
  • Reduces long-term maintenance efforts by having markup code stored in one place.
  • Simplifies frontend debugging efforts.

You must not hard-code inline JavaScript in PHP classes

  • Reduces long term maintenance by having frontend business logic stored in one place.
  • Reduces the number of files to be modified.

Acceptable PHP file

...
public function getSelectorOptions()
{
    return $selectorOptions;
}
...

Acceptable PHTML template

...
<div data-mage-init="{treeSuggest: [<?php echo $this->getSelectorOptions(); ?>]}"></div>
...

Unacceptable PHP file

...
public function getAfterElementHtml()
{
    return <<<HTML
<script>
jQuery('#{$htmlId}-suggest').treeSuggest({$selectorOptions});
</script>
...

Unacceptable PHTML file

<?php echo $this->getAfterElementHtml(); ?>

PHTML templates and PHP files

You must not hard-code inline CSS styles in PHP classes

  • Reduces long-term maintenance efforts by having styles stored in one place.
  • Simplifies debugging and reduces number of files to be modified.
  • Makes styles more extensible and easier to override when needed.

Acceptable PHP file

...
$fieldset->addField('new_category_parent', 'text', array(
    'label'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Parent Category'),
    'title'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Parent Category'),
    'required' => true,
    'class'    => 'parent category',
));
...

Unacceptable PHP file

...
$fieldset->addField('new_category_parent', 'text', array(
    'label'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Parent Category'),
    'title'    => Mage::helper('Mage_Catalog_Helper_Data')->__('Parent Category'),
    'required' => true,
    'style'    => 'border: 1px solid #ccc;',
));
...

You must not hard-code inline JavaScript in PHP classes

  • Reduces long term maintenance by having frontend business logic stored in one place.
  • Reduces the number of files to be modified.

Acceptable PHP file

...
public function getSelectorOptions()
{
    return $selectorOptions;
}
...

Acceptable PHTML template

...
<div data-mage-init="{treeSuggest: [<?php echo $this->getSelectorOptions(); ?>]}"></div>
...

Unacceptable PHP file

...
public function getAfterElementHtml()
{
    return <<<HTML
<script>
jQuery('#{$htmlId}-suggest').treeSuggest({$selectorOptions});
</script>
...

Unacceptable PHTML file

<?php echo $this->getAfterElementHtml(); ?>

You must not hard-code HTML markup (used in the tag) in PHP classes
  • Reduces long-term maintenance efforts by having markup stored in one place.
  • Reduces the number of files to be modified.

Acceptable PHP file

public function getAttributeName($element)
{
    return ($element->getExtType() === 'multiple') ? $element->getId() . '_checkbox' : NULL;
}

public function getAttributeId($element)
{
    return $element->getId();
}

Acceptable PHTML file

<span class="attribute-change-checkbox鈥>
<label>
   <input type="checkbox鈥 
      <?php echo ($this->getAttributeName($element)) ? ' name="' . $this->getAttributeName($element) . '"' : NULL; ?>
      data-mage-init="{customToggleWidget: [elementSelector: "input[name='someCustomName']"]}" />
   <?php echo Mage::helper('Mage_Catalog_Helper_Data')->__('Change'); ?>
</label>
</span>
<!-- jQuery.hide() code can be either located in the widget itself OR can ask PHP Block class whether or not 'weight_and_type_switcher' should be visible. Based on this condition CSS can be applied to hide/show those elements. -->