Areas

What frontend, adminhtml, webapi_rest, webapi_soap, graphql and crontab change about configuration, routing and design.

Syntax$this->state->emulateAreaCode(\Magento\Framework\App\Area::AREA_FRONTEND, $callback, $params = [])

An area is a named mode of the application. It decides which configuration files load, which routers run, which design and translations apply, and therefore which of your classes exist at all. A module ships one global etc/ folder plus one folder per area it takes part in.

The areas in 2.4.9

CodeFront nameServes
frontendnone; the fallbackthe storefront
adminhtmlbackend/frontName from app/etc/env.php, usually adminthe admin panel
webapi_restrestREST endpoints
webapi_soapsoapSOAP endpoints
graphqlgraphqlthe single GraphQL endpoint; area added in 2.3.0
crontabnonescheduled jobs run by bin/magento cron:run
globalnonenot a request area: configuration with no area folder, applying everywhere

How the area is chosen

For an HTTP request, Http::launch() takes the first URL segment and asks AreaList::getCodeByFrontName(). The admin front name, rest, soap and graphql are claimed; everything else falls through to frontend. The code is then fixed: State::setAreaCode() throws Area code is already set if anything tries to change it.

What an area changes

Configuration merges global first, area second, and the area file wins. etc/di.xml then etc/adminhtml/di.xml; the same for routes.xml and the rest. A class registered only under etc/adminhtml/ does not exist as far as the storefront is concerned, which is the usual explanation for code that works in the admin and silently does nothing on the storefront.

Example

Example · xml
<?xml version="1.0"?>
<!-- app/code/Vendor/Pricing/etc/adminhtml/di.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Vendor\Pricing\Api\LabelSourceInterface"
                type="Vendor\Pricing\Model\Label\AdminSource"/>
</config>

When to use it

  • Use one implementation on the storefront and a different one in the admin.
  • Work out why a configuration file you added has no effect on REST requests.
  • Explain why a cron job cannot render a template that a page renders fine.
  • Track down an "Area code is not set" error from a command that works in the browser.

More examples

The global half of the same preference

Read this file together with the adminhtml one above. Magento loads the global configuration first and then the area's, so a storefront, REST or cron request resolves LabelSourceInterface to StorefrontSource, and an admin request resolves it to AdminSource. Putting the common choice in etc/di.xml and only the difference in the area file keeps the override small and visible. Both files apply after bin/magento cache:flush in developer mode; in production mode run bin/magento setup:di:compile first, because the per-area dependency injection configuration is baked during compilation.

Example · xml
<?xml version="1.0"?>
<!-- app/code/Vendor/Pricing/etc/di.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Vendor\Pricing\Api\LabelSourceInterface"
                type="Vendor\Pricing\Model\Label\StorefrontSource"/>
</config>

One file name, two areas, different meanings

routes.xml is the clearest case of an area changing what a file means: the storefront copy registers into the standard router, the admin copy into the admin router, and a route declared in the wrong folder produces a 404 with no error anywhere. The area folder also decides which controller directory is reachable. There is no etc/webapi_rest/routes.xml or etc/graphql/routes.xml, because those areas do not use routers; REST paths come from webapi.xml and GraphQL from the schema. Apply either file with bin/magento cache:flush.

Example · xml
<?xml version="1.0"?>
<!-- app/code/Vendor/Blog/etc/frontend/routes.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="standard">
        <route id="blog" frontName="blog">
            <module name="Vendor_Blog"/>
        </route>
    </router>
</config>

<!-- app/code/Vendor/Blog/etc/adminhtml/routes.xml declares the same module
     under router id="admin" instead, and those controllers live in
     Vendor/Blog/Controller/Adminhtml/ -->

How a front name becomes an area

This is worth reading rather than copying. Each area contributes one item to AreaList, and the front name is matched before any router runs, which is why a URL beginning with /rest never reaches the standard router and why no module can claim rest, soap, graphql or the admin front name for a route of its own. Magento_Store registers frontend with a null front name and marks it the default, so unclaimed URLs land there. Declaring a new custom area is possible but rarely the right answer: an area brings its own configuration load, design and routing, and almost every real requirement is met by adding files to an existing one.

Example · xml
<!-- vendor/magento/module-webapi/etc/di.xml (core, trimmed) -->
<type name="Magento\Framework\App\AreaList">
    <arguments>
        <argument name="areas" xsi:type="array">
            <item name="webapi_rest" xsi:type="array">
                <item name="frontName" xsi:type="string">rest</item>
            </item>
            <item name="webapi_soap" xsi:type="array">
                <item name="frontName" xsi:type="string">soap</item>
            </item>
        </argument>
    </arguments>
</type>

Discussion

  • Be the first to comment on this lesson.