Magento 2 Frontend Developer Guide
Magento 2 Frontend Developer Guide
FRONTEND
DEVELOPER'S
STUDY GUIDE
JOSEPH MAXWELL
SWIFTOTTER SOLUTIONS
INTRODUCTION
You downloaded the most comprehensive study guide for Magento 2 Frontend
Development. The material covered provides excellent methodology for training
developers who are new to these concepts.
This study guide answers the questions presented in Magento’s study guide for
this test. Reading this study guide is part of solid preparation for passing the test
but does not guarantee a passing grade. What should yield a passing grade is
extensive experience with Magento’s frontend combined with rigorous and careful
review of this study guide.
Most people who spend $260 on a test want confidence that they are likely to pass
it. Therefore the next step of taking our practice test is critical. The practice test
validates that you are ready for the test. Following completion of the practice test,
you see questions you answered correctly and the ones you didn’t.
Additionally, for a small fee, you can see your scores on the practice test by
objective (showing your weak areas) and get the objective scores emailed to you.
Think about it. After you take the real test, didn’t you want to know where you were
weak? Now, by taking SwiftOtter’s practice test and choosing the $10 upgrade, you
can know before you take the test how you are doing and where to study more.
This study guide demonstrates our commitment to excellence and our love
for continuous learning and improvement. Enhancing the Magento developer
community is good for everyone: developers, agencies, site owners and customers.
I want to especially thank Jesse Maxwell, my brother, for his technical and
grammatical review of this book. His deep frontend experience was invaluable.
CONTENTS
Introduction.......................................................................................2
We Are SWIFTotter..........................................................................3
Acknowledgements........................................................................4
1 Create Themes.................................................................................8
1.1 Describe folder structure for local
and Composer-based themes.......................................................9
1.2 Describe the different folders of a theme...................................10
1.3 Describe the different files of a theme........................................12
1.4 Understand the usage of Magento areas:
adminhtml/base/frontend...............................................................1314
2 Magento Design Configuration System......................................14
2.1 Describe the relationship between themes...............................15
2.2 Configure the design system using the
options found in the Admin UI under
Content > Design > Configuration................................................16
2.3 Apply a temporary theme configuration to a store
view using the options found in the Admin UI
under Content > Design > Schedule............................................18
2.4 Understand the differences and similarities between
Content > Design > Configuration and > Schedule
to configure the design fallback...................................................20
3 Layout XML in Themes...................................................................21
3.1 Demonstrate knowledge of all layout XML directives
and their arguments........................................................................22
3.2 Describe page layouts and their inheritance ............................27
3.3 Demonstrate understanding of layout handles
and corresponding files..................................................................30
3.4 Understand the differences between containers
and blocks.........................................................................................35
3.5 Describe layout XML override technique...................................36
3.6 Understand layout merging...........................................................38
1.
CREATE
THEMES
(4 QUESTIONS - 7%)
Create Themes
Themes in Magento 2 control much of the look and feel for the frontend and the
backend. They use a combination of PHP, XML, HTML, CSS and JavaScript to
achieve the desired look. Themes override or extend existing PHP, HTML, CSS and
JavaScript while providing extra functionality.
Themes should only be for applying changes to existing code. New functionality
should go into modules specific to the use case.
When compared with Magento 1, themes have many similarities: they are found in
the app/design folder, they are structured in a package/theme path, and they use
resemblant layout XML syntax.
Local themes are stored in the app/design directory. If a theme is loaded through
Composer, that theme can be located anywhere on the file system, but in most
cases will use the default vendor/ directory within Magento.
Magento uses the Composer autoloader. If you look at the Luma theme’s composer.
json, you will see the [Link] node, whose value is [Link].
As the Magento application starts up, Composer executes each file as specified
in the [Link] section. [Link] then registers itself as a
theme. The theme is now available.
media/: this folder usually has one file: [Link]. The preview image
provides a sample of what the theme will look like when activated.
web/: the files and directories here will be eventually downloaded by website
visitors. In one form or another, they will ultimately be accessible from pub/
static. LESS files will first be placed in var/view_preprocessed before being
compiled and found in pub/static.
As a rule of thumb, Magento recommends not to use this directory but rather place
customizations of the theme into the appropriate directory within the module
directory where the functionality originates (for example, checkout customizations
should be placed under the Magento_Checkout/web directory).
css/: location of base Magento stylesheets. These will be exported to the pub/
static/[area]/[package]/[theme]/[locale]/css directory.
css/source/: LESS files that implement styles for basic UI elements. Most of
these styles are mixins for global elements from the Magento UI library. theme.
less is also located here, which overrides values for the default variables.
images/: images that are included in the theme. These are images that will not
frequently change. For example, you would include an icon here, but not a free
shipping banner.
Module overrides:
When developing a theme, you will likely need to override another module’s
assets. These overrides reside in the theme folder, then the module’s name. For
example, in our SwiftOtter_Flex theme, we need to override [Link] in
Magento_Catalog.
HELPFUL LINKS:
• [Link]
themes/[Link]
• adminhtml or frontend
• /
• /
• Theme name
Examples:
• frontend/SwiftOtter/Flex
• frontend/Magento/luma
• adminhtml/Magento/backend
[Link] (required): this file describes the theme to Magento. You will see a title
node, a parent node (optional), and a media/preview_image (optional) node.
HELPFUL LINKS:
• [Link]
themes/[Link]
However, a module’s assets can either be made available to both the adminhtml
and frontend areas or just one of the two areas individually. Files in the view/
base directory are available to both the frontend and adminhtml areas.
Placing a file in the frontend or adminhtml directory, will override that file in the
base theme, if it exists there.
The current area is determined in the App\State class, however this knowledge
is not expected from a frontend developer.
HELPFUL LINKS:
• [Link]
themes/[Link]
2.
MAGENTO DESIGN
CONFIGURATION
SYSTEM
(4 QUESTIONS - 7%)
Magento Design Configuration System
Parent/child.
In the theme’s [Link] file, you can specify the <parent/> node, like:
<parent>Magento/blank</parent>. As such, a theme can be a part of (or the
end of) many layers of other themes.
This hierarchy is what is used to determine the fallback sequence for theme
inheritance (see here and here).
The only difference is that the child theme is the theme that is currently selected for
display in the specified area. Any theme can be chosen for display (whether or not it
specifies a parent in [Link]).
HELPFUL LINKS:
• [Link]
themes/[Link]
15
Copyright © 2018, SwiftOtter, Inc.
Magento Design Configuration System
Configuration settings provide an easy-to-use interface for detailing options for the
theme that is applied to a store. They are not theme configuration, but rather store
design configuration.
TIP: These settings are stored in the core_config_data table but are not found in
Store > Configuration.
16
Copyright © 2018, SwiftOtter, Inc.
Magento Design Configuration System
The configuration values are displayed in a grid format showing the website > store
> store view hierarchy with an option to adjust configuration at each point.
These values are retrieved like any other store configuration value (see here,
getDefault).
The theme is automatically added to the theme table in the database. Themes
are available in the admin panel’s Content > Design > Configuration and can be
selected in the site’s Applied Theme dropdown list.
If a theme is removed, the default theme will automatically be used, but the theme’s
database record is not automatically removed.
HELPFUL LINKS:
• [Link]
themes/[Link]
17
Copyright © 2018, SwiftOtter, Inc.
Magento Design Configuration System
• Assuming that these store design configuration values are stored in another
table.
• Assuming that these store design configuration values are associated with a
theme and NOT a store.
HELPFUL LINKS:
• [Link]
[Link]
The purpose of this feature is to automate site design changes for specific
occasions. For example, a merchant may configure a custom theme to display for
the duration of the Christmas season.
On the day the change is scheduled to start, the selected theme is configured
as the primary theme for that store. Note that only one design change can be
18
Copyright © 2018, SwiftOtter, Inc.
Magento Design Configuration System
scheduled at a time. If the start and end dates overlap another design change’s
start and end dates, Magento will throw an error and prevent you from saving.
[Link]
Theme/Model/[Link] controls the design that is applied onto the website.
Specifically, the loadChange() method responds with the currently active design
change. This triggers the theme_save_after which clears the cache.
When the design change is scheduled, unless Varnish is enabled, the design
change will be applied and removed automatically (see this page).
It is our understanding that full-page caching overrides the design changes, until
the cache is purged or expires.
19
Copyright © 2018, SwiftOtter, Inc.
Magento Design Configuration System
What is the effect if both options are used at the same time?
20
Copyright © 2018, SwiftOtter, Inc.
Magento 2 Certified Professional
Frontend Exam Preparation eBook
3.
LAYOUT XML
IN THEMES
The basic building blocks of layout XML elements are <block/> and <container/>.
Most other layout instructions make modifications to blocks and containers.
Containers
Containers contain or group blocks and other containers. If you look in the root
layout XML file, you will see the top-most element is a container.
M1 MAGENTO 1
If you are coming from Magento 1, a great example of how
containers are now leveraged is found in the difference of how
the product page is rendered. While the output is quite similar, the
layout XML behind it is very different:
• Magento 1
• Magento 2
22
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
However, the ListText block has the advantage that data values can be set via layout
XML <arguments> node. Containers don’t allow for <arguments>.
name: required. This defines how you will reference this container from other areas
in the system.
htmlTag: a tag to wrap the child block output. Required if htmlClass is specified.
ReferenceContainer
<referenceContainer name="[Link]">
<block name="[Link]"
template="SwiftOtter::[Link]">
<arguments>
<argument name="viewModel"
type="xsi:object">SwiftOtter\Flex\Block\ProductDetails</
argument>
</arguments>
</block>
</referenceContainer>
23
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
The above example will include a new logic class (using the recommended
Template Block + ViewModel approach) to render additional product details.
The template from this example is automatically rendered to the page within the
container [Link].
Blocks
Blocks are a foundational building unit for layout in Magento. They are the link
between a PHP block class, which contains logic and a template which renders
content. Blocks can have children and grandchildren (and so on). Information can
be passed from layout XML into the block via the <arguments/> child node. For
those of a hybrid discipline (backend developers) this could include view models or
some static values to be utilized in the template.
• name: used to interact with the block from other locations in the frontend.
• template: the path to the template. You should always use Magento
module path notation. Example: SwiftOtter_Hero::[Link]. If the
24
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
• cacheable (default true): if specified as false, the entire page will not be
cached with Full Page Cache. Because this negatively impacts performance,
it is best to never add to blocks that are on pages where the caching is
applied. Instead, follow the directions in this Magento Stack Exchange post
on how to utilize Magento’s ESI system if the block content is public, that
is, the identical for all visitors, or use customer-data sections in case the
content is private (that is, specific for each visitor). More information on
including private data on cached pages can be found at this link.
HELPFUL LINKS:
• [Link]
layouts/[Link]
ReferenceBlock
Like containers, referencing another block allows you to affect the output of another
block.
25
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
<referenceBlock name="[Link]">
<arguments>
<argument name="template"
xsi:type="string">SwiftOtter_Flex::[Link]</argument>
</arguments>
</referenceBlock>
The above example shows how to change the template of an existing block. Note
that changing the template here will break fallback patterns that depend on the
original file chosen. As such, this might be problematic for module developers.
For example, let’s say you are developing a module and want to redirect the SKU’s
template to a custom one in your module. A merchant, who uses your module,
installs a custom theme. When they browse to the product page, the SKU might not
look correct because the theme they installed did not take into account the updated
SKU template.
The idea is to place configuration into one location (alongside the other
configuration that is controlling the look of the page). Layout XML configures
containers and blocks. It would be easier to maintain extra details for containers
and blocks when they are not buried in a mass of HTML. In addition, this opens
26
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
up the possibility for module developers to easily adjust these parameters without
having to override many templates.
• <move element="[Link]"
destination="[Link]"/>: this moves an element (block or
container) into another element (block or container).
• The move element also contains before and after attributes so you
can change the element’s placement within a parent if so desired.
The page layout is specified in a layout XML file, in the root <page/> node, like:
<page layout="2columns-left" ...></page>
27
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
To create a custom layout you must first define the layout, define the common
layout instructions, and then utilize that layout (as seen in the first answer to this
section). In our example below, we will create a text layout. This is similar to the two
column layout example except the text area is narrower.
Page layouts only contain containers. This is different than the page configuration
(XML files with a layout handle as their file name, and stored in view/[area]/
layout) which can contain blocks and containers.
The definition of the layouts are stored in your module’s [Link] file, like
app/code/SwiftOtter/Test/view/[Link]. See the following example.
<page_layouts xmlns:xsi="http://
[Link]/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/
PageLayout/etc/[Link]">
<layout id="text">
28
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
</layout>
</page_layouts>
<!-- app/code/SwiftOtter/Module/view/page_layout/[Link]
-->
<?xml version="1.0"?>
<layout xmlns:xsi="[Link]
[Link]/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/
Layout/etc/page_layout.xsd">
<update handle="2columns-right"/>
<referenceContainer name="[Link]"
htmlClass="page-wrapper page-layout-2columns-right layout--
text"/>
</layout>
29
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
Page layouts can be customized in the admin panel on products, categories, CMS
pages.
How can the root page layout be specified for all pages and for
specific pages?
Set the layout parameter on the <page /> node to the ID of a layout specified
in one of the page_layout XML files. The node can otherwise be blank if desired.
Specific pages can be targeted using the layout XML’s filename.
HELPFUL LINKS:
• [Link]
layouts/[Link]
30
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
For the example below, we will look at the following URL: [Link]
customer/account. When browsing here, the <body/> tag contains the following
classes: account customer-account-index page-layout-2columns-left.
• customer: the route ID, see here. Please note that the route ID can be
different than the front name. When browsing to a page, the front name is
used to match the URL with the controller. When building layout handles, the
route’s ID is used.
• index: the controller’s action, as it was not specified in the URL above: see
this link.
So how does this map to a layout XML file? Layout XML files are stored in a
module’s view/[area]/layout directory.
We can then take the layout handle and look for a file in the layout directory with
that name. If you are using PHPStorm, a fast way to do this is by tapping the `Shift`
key twice and entering the filename you wish to locate.
Any of the layout handles listed above can affect the output of a page. The
customer_account_index.xml file will be specific to the customer dashboard.
31
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
To determine what controller based layout handle applies to the current page, the
quickest method is to look at the body class. One of the classes contains the path.
Exchange the dashes for underscores to get the layout handle. For instance, the
product page has a class of catalog-product-view. The layout handle would
then be catalog_product_view.
To get the full list of handles that are available, briefly add the following
to a template that is rendered on the page: <?php var_dump($block-
>getLayout()->getUpdate()->getHandles()) ?>. We are including
another way to get the layout handles, below in the “What are the most commonly
used layout handles?” section.
To add a new layout handle, simple use the update layout instruction:
<update handle="new_handle_name"/>
See above. The purpose is to connect layout XML instructions with a controller. This
also decouples the rendering of HTML on the frontend, making it easy to control
what is shown, where.
32
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
If you are on a development machine and wish to see every layout handle that is
utilized for a page, do the following:
• Open vendor/magento/framework/View/Model/Layout/[Link]
Home Page:
• default
• cms_index_index
• cms_page_view
• cms_index_index
• cms_index_index_id_home
• 1column
• catalog_product_prices
Product Page:
• default
• catalog_product_view
33
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
• catalog_product_view_type_simple
• catalog_product_view_id_16
• catalog_product_view_sku_24-UG07
• 1column
• catalog_product_prices
In reviewing the above layout handle lists, you will see that there are some common
entries. default is a layout handle that is available everywhere. If you add
view/[area]/layout/[Link] to your module, every page in that area
(frontend or adminhtml) will be affected.
Layout handles are a fantastic way to group updates together. For example, you
can create a new layout handle to display specific information on a product page.
Unless you instruct the Magento Layout model to include that handle, no changes
appear. But, say, in a plugin, you tell the Layout model to include the handle, all
changes associated with that layout handle will take effect on the website.
34
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
A block represents the end of the chain in rendering HTML for Magento. Containers
contain blocks and can wrap them in an HTML tag. Also, containers will not render
any output if there are no children assigned to them.
\Magento\Framework\View\Element\Template
35
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
The order is influenced through the use of the before and after attributes. You
can specify a block or container’s name or you can use the - (dash) symbol to
denote at the beginning or the end.
HELPFUL LINKS:
• [Link]
layouts/[Link]
It is not ideal to override layout. However, as described by this article, there are
some situations where overriding XML layout is inevitable.
For example, to completely erase the existing Magento product page layout in
our SwiftOtter Flex theme, you would create a new XML file in: app/design/
SwiftOtter/Flex/Magento_Catalog/layout/override/frontend/
catalog_product_view.xml.
Note that these files are placed into the override folder instead of directly
inside the layout folder. XML files that are directly placed in the layout directory
are merged, while XML files that are placed in the appropriate subdirectory of
override replace the original file.
36
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
New blocks or containers could be added to the core layout file with a new version.
If that file was overridden, other modules that depend on specific elements would
not have access to them (and their functionality would be halted) unless you
manually added them to your theme’s override.
Overriding layout files circumvent any changes in core files and increase chances of
trouble during upgrades. As such, it must be viewed as the ultimate last result.
37
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
Layout merging is the process of assembling all of the layout XML files into
one large XML document ([Link]
develop/lib/internal/Magento/Framework/View/Model/Layout/Merge.
php _loadFileLayoutUpdatesXml method). When rendering the page,
Magento locates the layout instructions for the particular handles (see _
fetchPackageLayoutUpdates) and merges them together. Magento then
traverses this document instantiating PHP classes for each block and then
rendering the output.
Layout is merged in order that the modules are loaded. To quickly see the
loading order of modules, check the app/etc/[Link] file. If two conflicting
instructions are given, the module that loads last wins.
When you are building a new theme, you will need to make adjustments to the
layout XML. While you can override layout XML files (see discussion above), this is
less than ideal for upgradeability purposes as any updates that Magento ships will
not be present in the overridden files.
Instead, utilize the layout XML merging directories. For example: app/design/
SwiftOtter/Flex/Magento_Catalog/layout. We can create layout XML
files that will be merged with layout XML files in the Magento_Catalog module.
As such, we can use instructions like <move element="[Link]"
destination="[Link]" after="[Link].
after"/>
38
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
If you want to see the results of the layout merging on your developer machine, do
the following:
• Navigate to \Magento\Framework\View\Result\Page
• $output .= $this->getLayout()->getXmlString();
Go to a page on the website and view source. The XML will be appended after the
HTML tag.
Layout XML instructions are first merged in the base area and then by the area that
applies to the current request (frontend or adminhtml).
39
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
Source: vendor/magento/framework/View/File/Collector/[Link]
The only way to remove elements added earlier is through the remove attribute on
the referenceBlock or referenceContainer tags:
Additive changes are when you create new XML elements that are in addition to
what has already been written. These changes will likely affect existing elements
(setting new arguments, for example).
<block class="Magento\Catalog\Block\Product\View\
Attributes" name="[Link]" as="additional"
template="Magento_Catalog::product/view/[Link]"
group="detailed_info">
<arguments>
40
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
</arguments>
</block>
<?xml version="1.0"?>
<page xmlns:xsi="[Link]
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/
Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="[Link]">
<arguments>
</arguments>
</referenceBlock>
</body>
</page>
41
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
You can change the argument name to title and notice the difference in the
$block->_data variable. As such, you are overriding the existing value for title
and are specifying your own. This is considered an overriding change.
They are processed in the order in which the handles were added to the Merge
class. The default handle is loaded first. Then, in order of when they were added
through the request lifecycle.
In the above class, see the load() method. In this method, the layout is merged as
it loops through the associated layout handles.
As a side note: this can cause some trouble if you are relying on a custom-injected
layout handle to adjust the design on a page. As such, there may be instances
where you need to go to extra lengths to inject a layout handle earlier in the
application’s lifecycle.
42
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
This would then be according to the order in which the layout files are loaded. See
the in-depth topic on section 3.6.
The processing order and merging of layout XML is determined by the module
load order. Adjusting the <sequence/> setting for modules will influence the
processing order of layout XML.
For backend developers, you can use plugins to inject your layout handles earlier in
the process. For example, if you want to add a layout handle before the catalog_
product_view one, you need to create a before plugin for \Magento\
Catalog\Helper\Product\View::initProductLayout.
• Wishful overrides: where you want to override another block, but you specify
a different name and the block is injected twice.
43
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
• boolean
• object
• number
• null
• array
HELPFUL LINKS:
• [Link]
layouts/[Link]#argument
44
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
module_name: sets the module for the block. Usually this is automatically
determined.
The etc/[Link] file is used to specify custom and updatable properties for the
theme in Magento. The majority of the values apply to image sizes and the product
gallery settings.
<view xmlns:xsi="[Link]
xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/
etc/[Link]">
<media>
<images module="Magento_Catalog">
<image id="bundled_product_customization_page"
type="thumbnail">
<width>140</width>
<height>140</height>
45
Copyright © 2018, SwiftOtter, Inc.
Layout XML in Themes
</image>
</images>
</media>
</view>
HELPFUL LINKS:
• [Link]
themes/[Link]
In a custom theme, you can create a new etc/[Link] file and specify the elements
that you wish to change. Sorry if that seems obvious.
The closest value to the end of the rope wins. Any values declared in a child theme
will override the parent. Also, values declared in a specific area (frontend, for
instance), will take precedence over a base theme.
46
Copyright © 2018, SwiftOtter, Inc.
Magento 2 Certified Professional
Frontend Exam Preparation eBook
4.
CREATE AND
CUSTOMIZE
TEMPLATE
FILES
(5 QUESTIONS - 8%)
Create and Customize Template Files
The provided template path can be broken down into two arguments, which are
located either side of the scope separator ::.
The first states the area to look in, in this case SwiftOtter_Module, which looks
in the corresponding module:
app/code/SwiftOtter/Module
The second part [Link] is the path within this module's template folder
(view/[area]/template). In this case, that completes the path:
app/code/SwiftOtter/Module/view/frontend/template/[Link]
If you would like to change the template and use another one:
48
Copyright © 2018, SwiftOtter, Inc.
Create and Customize Template Files
When overriding a template file by assigning a new template via layout XML,
you effectively break the fallback path for a template. This prevents themes from
modifying the template.
You can customize a template by adding it to your custom theme. For example, to
modify vendor/magento/module-catalog/view/frontend/templates/product/[Link],
use the following path:
app/design/frontend/SwiftOtter/Flow/Magento_Catalog/view/
frontend/templates/product/[Link]
49
Copyright © 2018, SwiftOtter, Inc.
Create and Customize Template Files
HELPFUL LINKS:
• [Link]
templates/[Link]
While the chances are usually slim, there can be broken functionality that occurs
when upgrading. The reason is that the template that was overridden may have
been enhanced along with other aspects of the system that depended on the
template. If the overridden template is not upgraded, things can break.
The most notorious example was from Magento 1 days. SUPEE-9767 enabled form
key checking on the checkout. With the patch, Magento added the form key to the
templates. But many checkouts had at least some customized template files which
then did not include the form key. While this was easy to catch with testing, it added
to the overall implementation time for this upgrade.
The easiest way is to enable template hints, which can be activated using the
command-line: bin/magento dev:template-hints:enable or in the admin
area, in the follow location:
Frontend:
Stores > Settings > Configuration > Advanced > Developer > Debug > Enabled
Template Path Hints for Storefront > Yes
50
Copyright © 2018, SwiftOtter, Inc.
Create and Customize Template Files
Admin:
Stores > Settings > Configuration > Advanced > Developer > Debug > Enabled
Template Path Hints for Admin > Yes
The next step is to look through the Magento code. The template is often set in
layout XML, so this is the best place to start. Locate the block that renders the
template in XML and see if the template is set. If so, it will contain the reference to
the template. In some places, though, the template is defined in the PHP class itself.
If this is the case, open the block class and look for the $_template property or
some place where it is set.
HELPFUL LINKS:
• [Link]
• Never use squiggly braces: this is a code smell that indicates your block or
view model should be doing more work.
51
Copyright © 2018, SwiftOtter, Inc.
Create and Customize Template Files
• If you need to use a loop, use the foreach > endforeach constructs.
• Keep templates to a reasonable minimum. Massive 500 line files are a code
smell.
Why aren’t the common PHP loop and block constructs used?
HELPFUL LINKS:
• [Link]
between-if-and-if-endif
• getMediaDirectory()
• getUrl()
• getBaseUrl()
• getChildBlock($alias)
52
Copyright © 2018, SwiftOtter, Inc.
Create and Customize Template Files
• getModuleName()
• escapeJs($string)
• escapeCss($string)
• escapeUrl($string)
$block->getChildHtml('child-name');
53
Copyright © 2018, SwiftOtter, Inc.
Create and Customize Template Files
$block->getChildHtml();
Groups are a little-known part of the Magento layout system. These methods are found
in vendor/magento/framework/View/[Link]. The primary
example of groups in the Magento core is on the product detail page’s tabs and can
be seen rendered at this link. Rendering them involves obtaining all of their names
using getGroupChildNames and then rendering each block by name in a loop.
<referenceBlock name="[Link]">
<arguments>
<argument name="test_value"
xsi:type="string">11111</argument>
</arguments>
54
Copyright © 2018, SwiftOtter, Inc.
Create and Customize Template Files
</referenceBlock>
The value for test_value will be available in the template like: $block-
>getData('test_value') or $block->getTestValue().
HELPFUL LINKS:
• [Link]
• JavaScript: $block->escapeJs('value');
• URLs: $block->escapeUrl($url);
55
Copyright © 2018, SwiftOtter, Inc.
Magento 2 Certified Professional
Frontend Exam Preparation eBook
5.
STATIC ASSET
DEPLOYMENT
(3 QUESTIONS - 5%)
Static Asset Deployment
HELPFUL LINKS:
• [Link]
[Link]
• [Link]
process/[Link]
• Not using the static file signing for cache busting. Users would see old
content at this point.
57
Copyright © 2018, SwiftOtter, Inc.
Static Asset Deployment
According to DevDocs, production mode will not generate any missing static files
whereas development and default will attempt to symlink any necessary assets
into the corresponding folder in pub/static.
Server-side and client-side are the two available options. This is configured in Store
> Configuration > Advanced > Developer > Frontend Development Workflow.
Server-side: LESS files are compiled with a PHP LESS library. In developer mode,
PHP will generate the CSS files on the fly provided there is not one already. Running
php bin/magento setup:static-content:deploy will also compile the
stylesheets.
58
Copyright © 2018, SwiftOtter, Inc.
Static Asset Deployment
Client-side: LESS files are compiled every page load on the client-side. This results
in exceptionally slow response times and horrible flash-of-unstyled-text.
59
Copyright © 2018, SwiftOtter, Inc.
Magento 2 Certified Professional
Frontend Exam Preparation eBook
6.
CUSTOMIZE
AND CREATE
JAVASCRIPT
You can also include JS files into the <head/> tag of the rendered page. This is
helpful to include external libraries.
61
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
// app/code/SwiftOtter/Module/view/frontend/web/js/modal.
js
define([], function() {
};
});
<script type="script/x-magento-init">
".element-selector": {
"SwiftOtter_Module/js/modal": {
"configuration-value": true
62
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
</script>
Imperative notation:
While this is not usually the best way, it can be the easiest way to execute
Javascript on a page that depends on other libraries (i.e. jQuery) or modules:
<script type="text/javascript">
require([
"SwiftOtter_Module/js/modal"
], function(loader) {
/* … */
});
</script>
63
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
RequireJS Config:
You can include Javascript on every page in an area using the requirejs-
[Link] file with a declaration like as shown below. As a side benefit, it usually
runs sooner than the special Magento attribute or script tag because there is less
Javascript that has to initialize before your module is loaded.
var config = {
deps: ['SwiftOtter_Module/js/modal']
};
HELPFUL LINKS:
• [Link]
layouts/[Link]#layout_markup_css
• [Link]
javascript/js_init.html
• [Link]
magento-2-knockout-frontend
• [Link]
• [Link]
fundamentals/
64
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
The advantage is that inline JavaScript is easy to include, and it does not send an
additional request. The downside, though, is that the code becomes difficult to
reuse. Additionally, depending on what type of Javascript is rendered, this code is
not deferred and can block page loading.
If other places in the application need the same functionality, the script must be
included there as well. This inhibits caching because the JavaScript cannot be
cached separately from the main document and must be sent again every time.
Also, as the complexity of the logic increases, it begins to be difficult to manage. At
that point (or if you begin development knowing that it will soon get to this point),
splitting your JavaScript into multiple files will ease development.
HELPFUL LINKS:
• [Link]
This occurs through placing functionality into require or define methods. What
is the difference between these two methods? require executes immediately.
When RequireJS is loading modules, and it comes across one that has this method,
the contents are executed. define wraps a module that can be requested and
used by other modules. As a result, it is only executed when called, such as
65
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
require(['SwiftOtter_Module/js/loader'], function(loader) {
/* … */ });
In the <script/> tag in layout XML, you can also apply common attributes that will
be rendered on the <script/> tag in HTML, such as defer and async.
• checkout_cart_index.xml
• \Magento\Checkout\Block\Cart\Shipping
• [Link]
HELPFUL LINKS:
• [Link]
fundamentals/loading-javascript-in-a-page-with-layout-xml/
66
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
jQuery UI widgets are an extension of jQuery that provides pre-built components for
displaying common functionality. Here are a list of core widgets.
67
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
HELPFUL LINKS:
• [Link]
the-widget-factory/
Magento includes a number of jQuery widgets that are available to customize the
look of the frontend. The goal is to save development time by offering pre-built
solutions to solve business requirements.
• [Link]
widget_confirm.html
• [Link]
widget_accordion.html
HELPFUL LINKS:
• [Link]
widgets/[Link]
• [Link]
68
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
• Specify the path of the module. For the confirmation widget, it would look
like:
require(['Magento_Ui/js/modal/confirm'],
function(confirmWidget) { /* … */ });
• If the widget affects an HTML element, you need to use the widget
name as it was originally defined: $('.element-selector').
accordion({ /* … */ });
define([
"jquery"
], function($) {
$.widget("[Link]", {});
return $.[Link];
});
69
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
In the above code, we are exporting the newly-created widget from a RequireJS
module. Here is where an important distinction is made. When creating the widget,
you assign its name to the jQuery object. As such, that widget is callable from the
jQuery selector.
However, the widget is also exported from the module. If you do not need to use
the jQuery selector, you can import the widget and just use the name as imported.
define([
"jquery",
"SwiftOtter_Flex/js/mywidget"
], function($, importedMyWidget) {
$(".element-selector").mywidget(/* … */);
/**
*/
70
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
importedMyWidget(/* … */);
/**
*/
$('.element-selector').accordion("activate");
The syntax is to execute the widget’s name and pass, as a method argument, the
name of the function you want to execute.
71
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
How can you add new methods to a jQuery UI Widget? How can a
jQuery UI Widget method be wrapped with custom logic?
There are two ways to implement this. If the business requirements dictate
modifying something already in use (like the product page tabs), a different
approach must be used than if you are creating something new (and have the
capacity to specify a new component).
//app/code/SwiftOtter/Test/view/frontend/requirejs-config.
js
var config = {
"config": {
"mixins": {
"mage/tabs": {
'SwiftOtter_Test/js/tabs-mixin': true
72
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
};
// app/code/SwiftOtter/Test/view/frontend/web/js/tabs-
[Link]
define(['jquery'], function(jQuery) {
return function(original) {
[Link](
'[Link]',
jQuery['mage']['tabs'],
activate: function() {
return this._super();
73
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
);
return jQuery['mage']['tabs'];
});
Many thanks to Alan Storm’s article on this subject which makes it very clear on how
to do this.
// app/code/SwiftOtter/Test/view/frontend/web/js/custom-
[Link]
define([
'jquery',
'jquery/ui',
'mage/tabs'
], function($) {
$.widget('[Link]', $.[Link], {
doSomething: function(input) {
74
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
});
});
// app/code/SwiftOtter/Test/view/frontend/templates/test.
phtml
<div class="element-selector"></div>
<script>
require([
'jquery',
$(".element-selector").customTabs();
$(".element-selector").customTabs("doSomething",
"hello");
75
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
});
</script>
HELPFUL LINKS:
• [Link]
• [Link]
javascript/custom_js.html
• [Link]
customizing-javascript-jquery-ui-widgets-with-requirejs-mixins/
RequireJS gives the capacity to split JS functionality into separate files or modules.
This makes each file easy to read and easier to test. JS is capable of being an
Object-Oriented Language, although, similar to PHP, JS can be written either way.
76
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
For the most part, RequireJS follows a similar principle to Magento 2 backend
development: a module never instantiates itself, and it does not directly instantiate
another class. The dependencies that a module requests are provided to the
requesting module.
There are already many examples above, but we will look at the specifics of
directory paths and loading modules.
<script type="text/x-magento-init">
"*": {
"SwiftOtter_Test/js/test": {
"details": "test"
77
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
</script>
POINTS TO REMEMBER
• Do not add the .js to the module file path. The extension is
assumed.
Note that you can find these module names in [Link] (example).
HELPFUL LINKS:
• [Link]
• [Link]
fundamentals/loading-javascript-in-a-phtml-template-with-
requirejs-via-x-magento-init/
define([], function() {
78
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
});
HELPFUL LINKS:
• [Link]
fundamentals/defining-a-javascript-requirejs-amd-module/
• [Link]
fundamentals/passing-arguments-from-php-to-simple-requirejs-
javascript-modules/
They are an array specified in the first parameter of the define or require
methods.
An alias provides flexibility in directing requireJS to the correct (or new) URL for a
module. This is set up in your module’s view/[area]/[Link].
79
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
HELPFUL LINKS:
• [Link]
javascript/custom_js.html#js_replace
• [Link]
fundamentals/aliasing-requirejs-module-files-with-requirejs-
config/
See vendor/magento/module-require-js/Model/[Link]
ensureSourceFile($relPath).
HELPFUL LINKS:
• vendor/magento/framework/RequireJs/[Link]
80
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
Let’s look at an example of how to create a mixin and override an existing module’s
functionality.
// app/code/SwiftOtter/Flex/view/[Link]
var config = {
"config": {
"mixins": {
"Magento_Catalog/js/price-utils": {
81
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
"SwiftOtter_Test/js/price-utils-
override": true
};
// app/code/SwiftOtter/Flex/view/frontend/js/price-utils-
[Link]
define([], function() {
var updates = {
return '00000';
};
82
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
return function(target) {
});
HELPFUL LINKS:
• [Link]
javascript/js_mixins.html
• [Link]
with-requirejs/
• [Link]
customizing-javascript-jquery-ui-widgets-with-requirejs-mixins/
• [Link]
fundamentals/customizing-javascript-objects-with-requirejs-
mixins/
• [Link]
components/customizing-javascript-uicomponents-with-
requirejs-mixins/
83
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
The following settings are found in Store > Configuration > Advanced > Developer.
• Bundle JavaScript files: groups the JS files into bundles. This is a similar
idea to merging but supposed to be more flexible and downloads several
files. The Inchoo article below has some interesting performance statistics
and turning this on could negatively impact performance.
• Minify JavaScript files: reduces the JS file’s size by doing things like
stripping whitespace and shortening variable names.
The most important is to ensure that the server is properly configured with HTTP/2
and Gzip compression enabled.
HELPFUL LINKS:
• [Link]
84
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
Magento tells requireJS to download minified files through the minified resolver:
vendor/magento/module-require-js/Model/[Link],
ensureMinResolverFile() method.
The minified files are saved with a .min suffix. As a result, all the file names are
different in production. This poses a potential problem during deployment if
those assets are built outside of the primary Magento database, or if the setting is
changed at some point after the assets are built. If the static content is deployed
with a different setting, none of the Javascript on the site will work.
To reduce download time and make the frontend more useful and faster.
85
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
does not represent an exhaustive study, hopefully this will shed some light and
point you in the right direction for learning these.
Since this is a complex topic, and we can’t cover everything, we suggest you to
check out additional resources that can help guide you for further study:
UI Components are available in the frontend and the backend. The way Magento
uses these UI Components differs by the area. While it is generally better to follow
precedent, both ways work in either place. The core UI component Javascript
module is: Magento_Ui/js/core/app
In the frontend area, UI Components are configured through layout XML (vendor/
magento/module-checkout/view/frontend/layout/checkout_index_
[Link]). The jsLayout argument is used to specify information.
<?xml version="1.0"?>
<page xmlns:xsi="[Link]
[Link]/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/
Layout/etc/page_configuration.xsd">
<body>
86
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
<referenceContainer name="content">
<uiComponent name="cms_block_listing"/>
</referenceContainer>
</body>
</page>
(example from)
HELPFUL LINKS:
• [Link]
ui_comps.html
• [Link]
concepts/ui_comp_config_flow_concept.html
• [Link]
components/
UI Components are initialized with JSON. This is seen when viewing the source of a
Magento page that utilizes UI Components.
87
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
// app/code/SwiftOtter_Test/web/js/
<!-- … -->
<arguments>
<!-- -->
</argument>
</arguments>
This layout XML is merged together, converted into JSON, and is available on the
frontend.
A common system on the frontend is to use layout processors. In the checkout one
page block, in the getJsLayout method, you will see that these layout processors
have the opportunity to modify the UI component details before they are rendered.
This is especially helpful for the checkout as customer details are likely to change
should they refresh the page after filling in their information. In the case of the
checkout layout processor, you can find their contract here.
HELPFUL LINKS:
• [Link]
components/configuring-uicomponents-with-layout-xml/
• [Link]
regions/
88
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
Any values that are defined in the defaults property of the UI Component’s
Javascript module can be overridden with configuration loaded onto the page.
When looking to update a UI Component, a good place to start is with the
defaults property and checking if there is an item for the applicable value that
should be changed. The module’s parents likely also have defaults objects and
all of those values can be overridden as well. When the modules are initialized,
all of the defaults from a module and its ancestors are merged and then
configuration from the page is applied over that. Magento DevDocs provides a list
of common admin UI components and their available configuration options.
HELPFUL LINKS:
• [Link]
concepts/ui_comp_config_flow_concept.html
• [Link]
ui_comps.html
The template is specified as the module name, a slash, followed by the file path
within the module's view/<area>/web/template directory, but without the .html
file name suffix.
89
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
Tracks are specified in the UI Component’s JS files. These convert the specified
properties on the UI Component into a knockout-es5 observable.
HELPFUL LINKS:
• Implementation: initObservable
HELPFUL LINKS:
• [Link]
developers/
• [Link]
90
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
Bindings are a way to link reactive data with HTML. They are connected with the
data-bind attribute like:
There are many bindings available; here are some of the most common:
• if: similar to visible but removes or adds the child nodes based on the
evaluation of the property.
• click: calls the specified function when the element is clicked. It’s a one-
way binding (HTML to Javascript) which differs slightly from other bindings
that are bi-directional.
Magento also provides some custom bindings. All of them can be set as regular
bindings in a data-bind="" attribute, but some also may be specified as virtual
knockout elements, custom attributes or custom elements.
All of the following are more or less equivalent if used within a knockout .html
template:
91
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
Note that not all bindings are supported in all variations, and for some, the binding
name is different (for example data-bind="i18n: '…'" and
translate="'… '").
HELPFUL LINKS:
• [Link]
concepts/[Link]
• [Link]
92
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
</div>
In this example, the div tag will be bound directly to the UI component that is
registered in the uiRegistry with the identifier estimation.
Due to the complexity of this, I highly recommend doing some experimenting and
watching [Link]’s excellent series on Knockout and data binding.
HELPFUL LINKS:
• [Link]
• [Link]
concepts/[Link]
The UI Components on the checkout page provide a good example regarding how
to specify the template used to be rendered.
vendor/magento/module-checkout/view/frontend/web/js/view/
[Link]
// app/code/SwiftOtter/Flex/view/web/js/example-
[Link]
define([
93
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
'uiComponent'
], function (
Component
) {
return [Link]({
defaults: {
template: SwiftOtter_Flex/example-component',
});
});
// app/code/SwiftOtter/Flex/view/web/template/example-
component
<div class="sample-component">
94
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
</div>
HELPFUL LINKS:
• [Link]
Any update to the value triggers any dom elements that knockout rendered with
that observable to be re-rendered.
95
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
This works well for any data type except arrays. If the observable contains an array
or an object, a regular knockout observable does not trigger updates when values
within the array change.
Magento also includes the knockout plugkn ko-es5. The benefit of ko-es5 is that it
allows the creation of observables that can be read and set like regular properties,
while knockout still tracks the changes under the hood.
You can use the observable’s subscribe method to listen to changes. The
real value of the observable comes out when you bind that to an element in the
template like:
Virtual elements are a way to bind a child element without having to insert a node
into the DOM just to specify the binding.
96
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
<ul>
<li>Please choose</li>
</ul>
Supplying the default first list item can not be easily done when the foreach
binding is specified on the ul element:
</ul>
HELPFUL LINKS:
• [Link]
[Link]
97
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
Links, imports, exports, and listens are how UI components share data between
themselves. Having an understanding of each of these pieces will simplify your
development responsibilities.
Some of the examples in this section have been adapted from [Link]’s discourse
on the matter. These videos have greatly augmented my knowledge in this area.
HELPFUL LINKS:
• [Link]
concepts/ui_comp_linking_concept.html
tracks:
In order for a property to be updateable by the following methods, you must add
this property to the [Link] object. This converts each property
specified in the object or array into an observable property.
imports:
98
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
requesting object. Whenever that data is updated, it flows through the properties as
specified in the imports node.
define([
'uiComponent'
], function(Component) {
return [Link]({
defaults: {
price: 11,
tracks: {
price: true
},
imports: {
price: '${$.provider}:price'
})
});
99
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
HELPFUL LINKS:
• [Link]
components/javascript-uicomponent-imports/
exports
links
This is a two-way binding system. If the value is updated on either component (the
host or the linked component), both components’ value will likewise be updated.
HELPFUL LINKS:
• [Link]
components/javascript-uicomponent-links/
${} evaluates the expression inside the curly braces. In ES5, this would typically be
within backticks. However, because Magento has a system in place to process them
100
Copyright © 2018, SwiftOtter, Inc.
Customize and Create JavaScript
differently if browsers do not natively support template literals, quotes are used instead.
If the browser does support template literals, they are processed with backticks.
Inside the ${}, using $. resolves to this. As such, $.provider resolves to this.
provider.
HELPFUL LINKS:
• [Link]
components/javascript-uicomponent-es5-pseudo-template-
strings/
• [Link]
concepts/ui_comp_template_literals.html
101
Copyright © 2018, SwiftOtter, Inc.
Magento 2 Certified Professional
Frontend Exam Preparation eBook
7.
USE LESS/
CSS TO
CUSTOMIZE
THE MAGENTO
LOOK AND
FEEL
(5 QUESTIONS - 8%)
Use LESS/CSS to Customize the Magento Look and Feel
Magento utilizes the LESS preprocessor to simplify theming. Its goal is to keep
styles more concise by providing variables, handling nested selectors, and allowing
common functions (mixins). Browsers cannot interpret LESS so it must be compiled
into CSS.
The most common LESS files, that are compiled into CSS are: [Link],
[Link], [Link]. These files are included in the default_head_blocks.
xml file. According to a convention, all LESS files that are directly included and
compiled to CSS do not start with an underscore.
[Link]: additions for desktop styles. This contains the additional styles
for displaying on a screen that is 768px or wider.
There are other files that do not begin with an underscore and are individually
output: see this link.
To insert an external stylesheet into the <head/> tag, you can use the <css/>, or
the <link/> tag in layout XML:
<page xmlns:xsi="[Link]
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/
Layout/etc/page_configuration.xsd">
<head>
<css src="css/[Link]"/>
103
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
<css src="[Link]
[Link]" src_type="url" />
</head>
</page>
The <link/> can also be used to add JavaScript resources. To make sure your code
is clear, we would recommend adding CSS resources using the <css/> element.
HELPFUL LINKS:
• [Link]
layouts/[Link]#layout_markup_css
• [Link]
magento-2
104
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
@import directive:
While Magento contains hundreds of .less files, it compiles those files back into
a number of .css files. LESS provides an @import construct to import a file. All
files can import other files. Eventually an entire tree is built of imported files. A LESS
convention is that all files that are included by the @import construct starts with an
underscore in its filename.
@import '_styles.less';
HELPFUL LINKS:
• [Link]
css-topics/[Link]#fedg_css-import
• [Link]
Mixins
The way it works is you write some LESS instructions (which, in this case, are
verbatim CSS):
105
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
.element-selector {
background-color: #ff0000;
.another-element-selector {
.element-selector();
.another-element-selector {
background-color: #ff0000;
Mixins can also contain parameters. Using our above fictitious example:
.element-selector(@color) {
background-color: @color;
106
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
This is called:
.another-element-selector {
.element-selector(#0000ff);
Mixin parameters can be supplied in a format similar to a Javascript object and many
in Magento are setup this way. When this is the case, one can pass in a subset of
arguments by including the parameter’s name along with the argument value.
HELPFUL LINKS:
• [Link]
Variables:
Variables allow you to specify a value in one place and then use it in other
locations (just like with programming). Magento makes heavy use of LESS variables
(hopefully, someday we will see them simplified).
HELPFUL LINKS:
• [Link]
107
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
@arguments:
@arguments takes the arguments that were passed into a mixin and renders them
in that order.
HELPFUL LINKS:
• [Link]
variable
In writing vanilla CSS, you can have a maximum of three levels of nested code:
• Media query
• @supports wrapper
• Selector
LESS gives you the power to nest CSS as deep as you wish. This LESS is then
compiled back into the above two levels of nested code.
Here is an example:
// app/code/SwiftOtter/Test/view/web/css/source/_module.
less
.element-selector {
color: #000000;
108
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
.child-selector {
background-color: #ff0000;
.element-selector {
background-color: #ff0000;
background-color: #0000dd;
109
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
.element-selector {
background-color: #ff0000;
.element-selector {
background-color: #0000dd;
While nesting can appear very helpful, it can introduce tremendous bloat into
styling. It seems to fix specificity problems but adds many extra bytes. The question
that we ask is: “are the additional selectors necessary?” In many cases they are not.
Small changes to deeply nested selectors can have significant impact on output.
For instance, adding a comma and second class name to a selector five levels deep
doubles the entire chain. Deep nesting also leads to hard to manage selectors that
are more specific than required and difficult to override. Instead, using a quality
naming convention, such as BEM will eliminate many levels of nesting and simplify
code reuse.
110
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
Describe how the & (Ampersand) works and its function. Describe
how calculations are possible as well.
The & is a concatenation character and is particularly useful with writing BEM styles.
Here is an example:
.element-selector {
color: #000000;
&__text {
font-size: 1rem;
&__call-to-action {
background-color: #ff0000;
111
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
.element-selector__call-to-action { background-color:
#ff0000; }
.element-selector {
It is generally better to limit its use, though, because it can make finding the initial
declaration of the style more tedious because searching is essentially useless.
HELPFUL LINKS:
• [Link]
112
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
When loading the page, Magento looks for any css insertions into the <head/>
tag in layout XML. Any .css file references are changed to .less and a search is
made for a LESS file with that name. From there, Magento parses the @imports
and //@magento_import instructions and assembles file paths based on the
fallback directories.
Magento’s Luma and blank themes load in two CSS files: [Link] (desktop)
and [Link] (mobile and greater). These are the entry points into the LESS
file structure. These are also the output files (except that they will have a .css
extension). All LESS files that have been imported by another LESS file are included
into one of these two files.
HELPFUL LINKS:
• [Link]
css-topics/[Link]#server-side
113
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
When you create a new LESS file, you first need to run bin/magento
dev:source-theme:deploy. Then (or if you just make a change to a new LESS
file) you need to delete the pub/static/[area] directory. Refresh your browser to
regenerate files (and get something to drink while you wait). Better yet, use the
Grunt compiler.
TIP: Or for even faster response, use Snowdog’s SASS port and Frontools.
If you use client-side compilation, most changes are seen immediately when
refreshing the browser.
LESS does not have the ability to dynamically find and include partials. As a result,
every path must be included individually in the primary stylesheet. To work around
this limitation, Magento provides a //@magento_import directive. This will search
for files through many locations and include each version that it finds. Note the use
114
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
of the // as a comment to prevent any errors with LESS. Using the //@magento_
import directive allows the inclusion of a specific file from each module with just
one line.
HELPFUL LINKS:
• [Link]
design/frontend/Magento/blank/web/css/[Link]
_extends.less: this file contains a massive list of abstract selectors that can be
“extended” from and mixins.
We need to modify the availability notice on the product page. The merchant
has requested that this text is very large and prominent on the page. You have
115
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
already created the SwiftOtter/Flex theme. How do you update the font size for this
element?
However, if this is the first of a litany of changes, override the LESS file.
The goal of merging is to reduce the number of HTTP requests. The goal of
minification is to reduce the number of bytes being transferred. Minification is
valuable as it strips out whitespace which adds extra weight to the download
request. Both of these provide performance boosts.
116
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
To enable / disable these settings, go into Store > Configuration > Advanced >
Developer > CSS Settings.
If you have built a custom theme, these components will need to be imported with a
path like:
As an example, let’s add a new font onto our website design (don’t take the font
names seriously):
Another example:
.footer-breadcrumbs {
.breadcrumbs();
117
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
Caution: some of the mixins are extraordinarily large. Instead of including a large
mixin to accommodate your interface, we recommend exploring the option of
matching Magento’s selector structure in order to leverage their styles. This
prevents introducing a large amount of nearly duplicate code.
HELPFUL LINKS:
• [Link]
css-topics/[Link]
• [Link]
css-topics/[Link]
New variables should be placed in local theme lib/ or local theme files. Overrides
of existing variables should be declared in this file: <theme_dir>/web/css/
source/_theme.less.
Source: [Link]
frontend/Magento/blank/web/css/source/_theme.less
There are multiple ways to extend a lib file, you can extend it by copying the .less
file into your theme. For example, if you need to customize _dropdowns.less:
118
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
cp lib/web/css/source/lib/_dropdowns.less app/design/
frontend/SwiftOtter/Flex/css/source/lib
The caveat here is that the less you copy core files, the more upgradeable the
application will be.
Another approach is to implement your own custom version of the file, containing
only your overrides. You can do this by adding the following file:
app/design/frontend/SwiftOtter/Flex/css/source/custom/lib/_
[Link]
This will not be imported by default as it is an additional file, so you will need to add
the import yourself. You can copy the core import file (web/css/_styles.less)
to your theme at the following location:
app/design/frontend/SwiftOtter/Flex/css/_styles.less
Then add the additional import. The best method to use will be dependent on the
level of extension required. For example, in a situation where you want to override a
single mixin within a lib file that contains multiple, it may be beneficial to just add
your own custom file containing the single override. This method also helps to
clearly identify where edits have been made.
HELPFUL LINKS:
• [Link]
magento-2
119
Copyright © 2018, SwiftOtter, Inc.
Use LESS/CSS to Customize the Magento Look and Feel
The mixins usually have default parameters that are variables declared in the ./
variables folder. As a result, many things can be changed by setting your own
values on those variable names in the _theme.less file. You can also override the
files and make further changes. Finally, when including a Magento UI library mixin
in your own code, you can specify custom values for the many parameters that
are available. The breadcrumbs UI widget has almost sixty variables that can be
customized.
120
Copyright © 2018, SwiftOtter, Inc.
Magento 2 Certified Professional
Frontend Exam Preparation eBook
8.
CUSTOMIZE
THE LOOK
AND FEEL
OF SPECIFIC
MAGENTO
PAGES
• Header block
• Header links
• Logo
• Menu bar
• Header styles
• Footer container
• Footer block
• Copyright
122
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
Quick search
• Mini-search form
• Search styles
• Styles
Mini-cart
• Minicart form
• Styles
• Layout XML
• UI Component
Breadcrumbs
• Template
• Block
• UI Widget
• Styles
Sidebar menu
• [Link] is the name of the container that represents the sidebar.
• Styles
123
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
The Design tab on a product edit page provides the ability to affect how a product
is rendered on the frontend.
• Display Product Options in: determines where to place the product’s options
• Layout Update XML: the capability to inject Layout XML updates into a
product’s page. Here you can create / remove blocks, change templates, etc.
One thing to reiterate is that layout XML changes are possible within the Layout
Update XML field. Here is an example of adding a customer block:
<referenceContainer name="[Link]">
<block template="SwiftOtter_Test::[Link]"/>
</referenceContainer>
Using layout handles. When a product is rendered, multiple layout handles are
assigned:
• catalog_product_view
124
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
• catalog_product_view_type_[product type]:
• catalog_product_view_type_simple
• catalog_product_view_type_configurable
• catalog_product_view_type_bundle
• catalog_product_prices
How can you use custom layout updates for specific product
pages?
You can use either the layout handle for the particular SKU or product ID or the
Layout Update XML field in the admin panel for that product.
Magento provides many containers on the product page, making it much easier
than Magento 1 to modify the output on a product page. All you need to do is
reference the container and add blocks to it.
Here is a list of all the containers available (as of Magento 2.2, reference):
• content
• [Link]
125
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• [Link]
• skip_gallery_before.wrapper
• skip_gallery_after.wrapper
There are two sections within a category page that affect how the page displays:
Design and Display Settings.
Design
Use Parent Category Settings: if checked, the rest of the settings in this tab are
loaded from the parent category.
126
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
Apply Design to Products: if this is selected the theme, layout settings, and layout
XML updates are merged with the product (in the event of a conflict, the product
will win). Reference, getDesignSettings method.
Display Settings
Display mode: available options are: product, static block only, or products and
static block.
• [Link]
Catalog/view/frontend/templates/navigation/[Link]
• [Link]
LayeredNavigation/view/frontend/templates/layer/[Link]
• [Link]
LayeredNavigation/view/frontend/templates/layer/[Link]
• [Link]
LayeredNavigation/view/frontend/templates/layer/[Link]
127
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
This is configured in a category’s design tab, “Use Parent Category Settings” option.
These updates are found on the CMS page’s design tab. You can adjust the layout,
theme, and the page’s layout XML.
A content manager can utilize static variables to store small pieces of information
and make them easily updatable. There are two type of variables: contact
information and custom variables. The list of contact information variables comes
from these files ([Link]
code/Magento/Email/Model/Template/[Link] and [Link]
128
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
magento2/blob/2.2-develop/app/code/Magento/Email/Model/Source/[Link]).
The list of custom variables are set up in System > Custom Variables.
Template directives can be found in this file. Search for the following: Directive(
var: loads a variable that is present in the current scope. This is found in the
$this->templateVars array, which is set when setVariables is called. As
such, it is not available for use in CMS pages.
store: formulates a URL. See the storeDirective method for all available
options:
{{store url="about-us"}}
// renders: [Link]
block: renders a block. Specifying the class attribute allows you to instantiate a
block of a particular type. All of the attributes specified in this directive are passed
to the block with magic setters. If no class attribute is specified and an integer id
attribute is, a CMS block is rendered for the ID specified.
{{block id="id_from_block_id_column"}}
<!-- OR -->
{{block id="id_from_identifier_column"}}
129
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
{{if customer_name}}
{{else}}
Hello no name,
{{/if}}
HELPFUL LINKS:
• [Link]
• [Link]
directives/
• [Link]
directives/
Widgets are a tool for placing complex components into CMS output. They provide
a centralized mechanism for rendering and retrieving information.
130
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
<widgets xmlns:xsi="[Link]
instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_
Widget:etc/[Link]">
placeholder_image="SwiftOtter_Test::images/
test_widget.jpg">
<parameters>
</parameter>
131
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
</parameters>
</widget>
</widgets>
Widgets can be used anywhere that the content is filtered by a template filter. This
includes:
• CMS pages
• Email templates
Widgets allow you to inject a CMS block into a location in layout XML configuration.
This is a great option for content managers adding promotional material to the
website. You can select from a number of different layout handles and then choose
a container in which to inject the CMS block.
New targets can be created to facilitate widgets being injected into. Do this with the
<containers/> tag found inside the <widget/> configuration:
132
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
<widgets>
<!-- … -->
<containers>
<container name="content">
</container>
</containers>
</widget>
</widgets>
133
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
<template/>s and the content manager will be able to select from a list of
templates.
HELPFUL LINKS:
• [Link]
• [Link]
CMS blocks are managed in Content > Blocks. CMS blocks can be inserted into
other parsed variables with the {{block id=""}} directive. Note that the id
parameter can either be the block’s numeric ID (from the block_id column) or
identifier (source).
<arguments>
134
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
block_identifier</argument>
</arguments>
</block>
<!-- app/code/SwiftOtter/Test/view/frontend/layout/
customer_account.xml -->
<?xml version="1.0"?>
<page xmlns:xsi="[Link]
[Link]/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/
Layout/etc/page_configuration.xsd">
135
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
<body>
<referenceBlock name="customer-account-navigation-
wish-list-link" remove="true"/>
<referenceBlock name="customer-account-navigation-
billing-agreements-link" remove="true"/>
</body>
</page>
Source: [Link]
Customer addresses are configured in Stores > Configuration > Customers >
Customer Configuration > Address templates. These templates use the directives
discussed above in 8.4 Customizing CMS pages.
Container blocks provide easy places to add elements to the checkout. The primary
file for the checkout is this.
136
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
<!-- … -->
</item>
</item>
</item>
<!-- … -->
• before-form
• before-fields
• address-list-additional-addresses
• before-shipping-method-form
137
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
• summary
HELPFUL LINKS:
• [Link]
138
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
Once you have created a new transactional email template, you need to instruct
Magento which email template to use. This is done in Store > Configuration. For
order emails, go to Sales > Sales Emails. For customer emails, go to Customer >
Customer Configuration.
Transactional email templates use the same directives as was discussed in 8.4.
You can utilize the {{var …}} attribute in these email templates for any variable that
was specified when initializing the email. For example, for the order notification
template, the following variables are available (source):
139
Copyright © 2018, SwiftOtter, Inc.
Customize the Look and Feel of Specific Magento Pages
There is not a WYSIWYG image uploader for transactional email templates. To add
an image, you need to place the image in a module or a theme’s web/images
directory. You can load the image like (see, viewDirective method):
To create links to store pages, use the {{store url="..."}} directive. The
value in the url parameter is relative to the store’s URL. If your store URL is
[Link] and you want to link to [Link]
com/test-url, you would add the following directive:
HELPFUL LINKS:
• [Link]
templates/[Link]
• [Link]
Configuration/transactional-emails-where-do-images-go/
m-p/91304/highlight/true#M2388
140
Copyright © 2018, SwiftOtter, Inc.
Magento 2 Certified Professional
Frontend Exam Preparation eBook
9.
IMPLEMENT
INTERNATIONALIZATION
OF FRONTEND PAGES
(3 QUESTIONS - 5%)
Implement Internationalization of Frontend Pages
Internationalization has been a core Magento feature since its early days. Magento
2 maintains strong support across the entire platform.
Magento includes a feature to locate all translatable strings within a particular path.
You can utilize this for an entire Magento installation or just for a module or a theme.
To assist in building a language package, you need to locate all strings within the
Magento application. You can run this command to obtain this information:
bin/magento i18n:collect-phrases -m
When run with the -m flag, two additional columns are added: type and module.
type is either theme or module. The module column represents the module that
utilizes this translation.
142
Copyright © 2018, SwiftOtter, Inc.
Implement Internationalization of Frontend Pages
A theme translation dictionary allows you to specify translations for words used in
a theme or a module. These phrases are placed in a .csv inside your module or
theme’s i18n directory (app/code/SwiftOtter/Test/i18n/de_DE.csv).
Translations specified for the theme or module are the first two sources of
translation data. These translations can be overridden by a language package or in
the database.
HELPFUL LINKS:
• [Link]
[Link]#config-cli-subcommands-
xlate-dict
• [Link]
translations/theme_dictionary.html
Language packs
A language pack allows you to translate words used anywhere in Magento. The
source for this is bin/magento i18n:collect-phrases command with the -m
flag. This searches the entire Magento application (including modules and themes)
for all translatable strings.
The output from this command is the fundamental ingredient to a language pack.
Once you have translated the strings, you then execute this command (substituting
the path to the CSV file and specifying the target language):
143
Copyright © 2018, SwiftOtter, Inc.
Implement Internationalization of Frontend Pages
You must then create a new language module within the app/i18n/
SwiftOtter_FR/ (or something similar). This contains the usual module
files ([Link] uses the \Magento\Framework\Component\
ComponentRegistrar::LANGUAGE component type). It also includes a
[Link] file:
<?xml version="1.0"?>
<language xmlns:xsi="[Link]
[Link]/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:App/
Language/[Link]">
<code>fr_FR</code>
<vendor>SwiftOtter</vendor>
<package>fr_fr</package>
</language>
You can include multiple <use/> nodes in the [Link] file. If Magento
does not find a string in the included language package, it will search through each
<use/> (and subsequently those language package’s <use/> nodes) until it finds
an applicable translation.
144
Copyright © 2018, SwiftOtter, Inc.
Implement Internationalization of Frontend Pages
Inside the language package, include the CSV generated above named as the
contents of the <code/> node with a .csv suffix.
HELPFUL LINKS:
• [Link]
[Link]#config-cli-subcommands-
xlate-pack
• [Link]
LocalePack_de_DE
• [Link]
Magento/fr_FR
Database translations
Database translations are the easiest to implement, but the most difficult to transfer
from installation to installation. They are found in the translation table.
To create a new translation, the easiest is to turn on Inline Translation (Store >
Configuration > Developer > Translate Inline). You could also insert new rows in the
the translation table manually with the limitation being the need to determine
the module to associate the translation to.
While translating with Inline Translation, disable the Translations, Block HTML
and Full Page caches.
145
Copyright © 2018, SwiftOtter, Inc.
Implement Internationalization of Frontend Pages
1. Module translations
2. Theme translations
3. Translation package
4. Database translations
PHTML:
146
Copyright © 2018, SwiftOtter, Inc.
Implement Internationalization of Frontend Pages
Email templates:
The first example under each heading below shows rendering a plain string. The
second example shows how to use substitutions.
UI Component templates:
JS files:
147
Copyright © 2018, SwiftOtter, Inc.
Implement Internationalization of Frontend Pages
$.mage.__('Shopping Cart')
$t('Shopping Cart')
HELPFUL LINKS:
• [Link]
translations/translate_theory.html
• [Link]
javascript/
148
Copyright © 2018, SwiftOtter, Inc.
Magento 2 Certified Professional
Frontend Exam Preparation eBook
10.
MAGENTO
DEVELOPMENT
PROCESS
(2 QUESTIONS - 3%)
Magento Development Process
Note that you cannot disable caches in the Magento admin when in production
mode.
bin/magento cache:enable
# OR
bin/magento cache:disable
# OR
bin/magento cache:flush
# OR
150
Copyright © 2018, SwiftOtter, Inc.
Magento Development Process
You can see which caches are enabled and disabled, in the admin area, or with the
command
bin/magento cache:status
You can abbreviate any of these commands within each namespace so long as that
namespace is still unique.
One thing to note is that you cannot disable caches in the admin panel while in
production mode.
HELPFUL LINKS:
• [Link]
[Link]
OR
151
Copyright © 2018, SwiftOtter, Inc.
Magento Development Process
bin/magento deploy:mode:show
bin/magento cache:flush
To disable a cache:
bin/magento cache:status
To symlink the JS, LESS, and image files into the pub/static folder during
development:
bin/magento dev:source-theme:deploy
When pushing code to production, to compile the frontend assets (note that this
does not work in developer mode):
bin/magento setup:static-content:deploy
152
Copyright © 2018, SwiftOtter, Inc.