11 KiB
name, description
| name | description |
|---|---|
| oro-frontend-dev | OroCommerce frontend development reference covering storefront themes, back-office themes, layouts, SCSS, JavaScript architecture (Chaplin/Backbone), page components, templates, and asset management. Use when customizing the storefront UI, modifying admin templates, writing JS components, or styling OroCommerce pages. |
OroCommerce Frontend Developer
Reference for frontend/UI development on OroCommerce. Full docs: https://doc.oroinc.com/frontend/
Two Theme Systems
OroCommerce has two separate theme architectures:
| Area | Framework | Templates | JS | Docs |
|---|---|---|---|---|
| Storefront | OroLayouts (SEO-friendly, no SPA) | Layout YAML + Twig blocks | Chaplin/Backbone | https://doc.oroinc.com/frontend/storefront/ |
| Back-office | Placeholders (SPA-like, Twig+Underscore) | Twig extends @OroUI | Chaplin/Backbone | https://doc.oroinc.com/frontend/back-office/ |
Themes are NOT interchangeable between storefront and back-office.
Storefront Theming
Theme Structure
Resources/views/layouts/{theme_name}/
theme.yml # theme definition (label, parent, icon)
config/
assets.yml # SCSS entry points
jsmodules.yml # JS module registration
datagrids.yml # frontend datagrid configs
templates/ # Twig block templates
page/ # per-page layout overrides
theme.yml
Basic:
label: 'My Custom Theme'
parent: default
icon: bundles/mybundle/images/theme-icon.png
groups: [commerce]
rtl_support: true
Full configuration with admin-selectable options:
label: 'Acme Theme'
parent: default
groups: [commerce]
rtl_support: true
configuration:
sections:
header:
label: Header
options:
promotional_content:
label: oro_frontend.theme.default.configuration.header.promotional_content.label
type: content_block_selector
options:
required: false
standalone_main_menu:
label: oro_frontend.theme.default.configuration.header.standalone_main_menu.label
type: checkbox
default: checked
previews:
checked: 'bundles/orofrontend/images/previews/menu-standalone.png'
unchecked: 'bundles/orofrontend/images/previews/menu-hamburger.png'
product_listing:
label: 'oro.product.theme.default.configuration.product_listing.label'
options:
filters_position:
label: 'oro.product.theme.default.configuration.product_listing.filters_position.label'
type: radio
default: sidebar
values:
top: 'oro.product.theme.default.configuration.product_listing.filters_position.values.top'
sidebar: 'oro.product.theme.default.configuration.product_listing.filters_position.values.sidebar'
Configuration option types: content_block_selector, menu_selector, checkbox, radio, select.
Layout Updates
Layout updates are YAML files that modify page structure:
layout:
actions:
- '@setBlockTheme':
id: page_container
themes: '@MyBundle/layouts/my_theme/page/layout.html.twig'
- '@add':
id: my_custom_block
parentId: page_content
blockType: text
options:
text: '=data["locale"].getLanguage()'
- '@remove':
id: unwanted_block
- '@move':
id: existing_block
parentId: new_parent
Place layout updates in route-specific directories to target individual pages:
Resources/views/layouts/{theme}/
layout.yml # global layout (all pages)
oro_frontend_root/frontend_root.yml # homepage
oro_product_frontend_product_index/product_index.yml # PLP
oro_product_frontend_product_view/product_view.yml # PDP
oro_checkout_frontend_checkout/checkout.yml # checkout
Block Types
| blockType | Purpose |
|---|---|
container |
Wraps child blocks with a div |
text |
Static text or expression |
block |
Custom Twig-rendered block |
content_block |
References admin-managed content block by alias |
menu |
Renders a navigation menu |
Layout Data Expressions
Access data providers and context variables in YAML options:
options:
vars:
# Data provider methods (registered via layout_data_provider tag)
topCategories: '=data["category_provider"].getRootCategoriesWithSlugs()'
featuredCount: '=data["product_provider"].getFeaturedProductCount()'
ctaLinks: '=data["cta_link_provider"].getLinks(data["menu"].getMenu("commerce_main_menu"))'
# Context variables (route params, request attributes)
category: '=data["category_provider"].getCategoryById(context["category_id"])'
@addTree Action
Add multiple blocks at once:
- '@addTree':
items:
footer_menu:
blockType: menu
options:
item: '=data["menu"].getMenu("commerce_footer_links")'
depth: 2
tree:
page_footer_base:
footer_menu: ~
@setBlockTheme with Multiple Files
- '@setBlockTheme':
themes:
- 'templates/layout.html.twig'
- 'templates/page-footer/footer_branding.html.twig'
- 'templates/navigation/sidebar_menu.html.twig'
Twig Block Naming Convention
Block names in layout Twig templates follow: _{blockId}_widget
{% block _my_custom_block_widget %}
<div {{ block('block_attributes') }}>
{{ block_widget(block) }}
</div>
{% endblock %}
SCSS / Stylesheets
Register SCSS in config/assets.yml:
styles:
inputs:
- 'bundles/acmetheme/scss/styles.scss'
output: 'css/styles.css'
Recommended SCSS directory organization:
scss/
styles.scss # main entry point (@import all)
variables/
_colors.scss # color palette as Sass maps
_typography.scss
_mixins.scss
components/
_product-cards.scss
_buttons.scss
layout/
_page-header.scss
_page-footer.scss
_product-view.scss
_product-index.scss
_checkout.scss
navigation/
_sidebar.scss
_topbar.scss
Color palette using Sass maps (Oro pattern):
@use 'sass:map';
$theme-color-palette: (
'brand': (
'primary': #424242,
'secondary': #A89571,
),
'semantic': (
'success': #005E1F,
'error': #D32F2F,
)
) !default;
$color-palette: map.deep-merge($color-palette, $theme-color-palette);
Access via get-var-color('brand', 'primary'). Build: php bin/console oro:assets:build.
SVG Icons
Custom icons go in the theme's icons directory. Register via theme config.
Back-Office Theming
Twig Template Overrides
Override admin templates by mirroring directory structure under Resources/views/.
Common base templates to extend:
@OroUI/actions/index.html.twig-- list/grid pages@OroUI/actions/view.html.twig-- detail/view pages@OroUI/actions/update.html.twig-- create/edit form pages
Use Oro UI macros for consistent rendering:
{% import '@OroUI/macros.html.twig' as UI %}
{{ UI.renderProperty('Label', value) }}
{{ UI.renderHtmlProperty('HTML Label', htmlValue) }}
Placeholders
Inject content into predefined back-office page regions.
# Resources/config/oro/placeholders.yml
placeholders:
oro_view_additional_data:
items:
my_custom_section:
order: 50
template: '@AcmeExample/Placeholder/section.html.twig'
applicable: '@acme.placeholder_filter->isApplicable'
Common placeholder targets:
oro_view_additional_data-- entity view page extra sectionsoro_widget_side_bar-- sidebar widgetsoro_title_before/oro_title_after-- title area
Conditional rendering via applicable filter (service method returning bool).
Placeholders are back-office only; use Layout Updates for storefront.
SCSS
Override admin SCSS variables or add new stylesheets via theme settings.
JavaScript Architecture
Built on Chaplin.js (extends Backbone.js). Key concepts:
Page Components
The primary extension mechanism. Define in HTML via data attributes:
<div data-page-component-module="mybundle/js/app/components/my-component"
data-page-component-options="{{ options|json_encode }}">
</div>
Component lifecycle: created on page:update, disposed on page change.
JS Module Registration
Register modules in Resources/config/jsmodules.yml:
dynamic-imports:
mybundle:
- mybundle/js/app/components/my-component
aliases:
jquery$: oroui/js/extend/jquery
# Override an existing module with custom implementation
map:
'*':
'orofrontend/js/app/datafilter/frontend-multiselect-decorator': 'acmetheme/js/custom-multiselect-decorator'
App Modules
Execute code at application startup (auto-initialized on every page):
app-modules:
- acmetheme/js/app/modules/inventory-checker
- acmetheme/js/app/modules/checkout-shipping-options
AMD Module Pattern
Oro's JS uses AMD define() with the oroui/js/mediator for cross-component communication:
define(function(require) {
'use strict';
const mediator = require('oroui/js/mediator');
const $ = require('jquery');
class MyComponent {
constructor() {
$(document).ready(() => {
mediator.on('checkout:shipping-method:rendered', this.onShippingRendered);
});
}
onShippingRendered() {
// DOM manipulation after Oro renders shipping methods
}
}
new MyComponent();
return MyComponent;
});
Key mediator events: checkout:shipping-method:rendered, filters-manager:after-applying-state, page:update, page:afterChange.
Page Events
System events during page lifecycle:
page:beforeChangepage:requestpage:update-- content is updated, init componentspage:afterChange-- all components initialized
File Naming Convention
js/app/
components/ # PageComponent implementations
controllers/ # Chaplin controllers (rare -- PageController handles all)
models/ # Backbone models and collections
views/ # Backbone views
modules/ # App modules (startup code)
templates/ # Underscore.js templates (*.html)
Asset Build
php bin/console oro:assets:build # build all themes
php bin/console oro:assets:build --watch # watch mode for dev
php bin/console assets:install # symlink public assets
Requires Node.js >= 22 and NPM > 10.
RTL Support
Enable Right-to-Left UI via theme configuration. See: https://doc.oroinc.com/frontend/rtl-support/
Additional Resources
- Storefront how-to guides: https://doc.oroinc.com/frontend/storefront/how-to/
- JS modularity deep-dive: https://doc.oroinc.com/frontend/javascript/javascript-modularity/
- Storefront design/style guide (Figma): https://doc.oroinc.com/frontend/storefront-style-guide/