This blog article & associated module are meant to help you access a specific container or block in your Magento 2 theme from an external system. For example, you may be integrating your Magento 2 installation with WordPress, Drupal, Expression Engine, or another CMS in which you want to load part of the page from your Magento 2 store. Or, you may just want to render a specific element’s HTML outside the context of a Magento 2 controller action.
TO DOWNLOAD THE SOURCE CODE FOR THIS MODULE, SEE THE GITHUB HERE:
https://github.com/cadencelabs/m2external
To do this, you need to accomplish a few things:
- Provide a new application entry point to start up Magento 2 but not trigger the controller routing process.
- Bootstrap your new entry point to use the store of your choosing
- Add an empty layout handle and assign it to the View singleton in your application
- Use a wrapper class to expose different parts of the layout (head assets, blocks, or containers)
Included in the attached module are functions to handle all of that. The below snippet of code shows how to utilize the module’s built in Integration class to to expose parts of your Magento 2 theme.
First, download the module source code from Github. After you’ve installed the module in your codebase:
* Make sure you’ve added the module to app/etc/config.php
* Make sure you run the upgrade script:
bin/magento setup:upgrade
How To Use Cadence_External
1) Boot The External Application
// Set a config array of information related to your Magento 2 installation
$config = [
'bootstrap_path' => '../../app/bootstrap.php',
'store' => 'en',
'theme' => "Cadence/Exampletheme"
]
require_once($config['bootstrap_path']);
$params = $_SERVER;
$params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS] = [
DirectoryList::PUB => [DirectoryList::URL_PATH => ''],
DirectoryList::MEDIA => [DirectoryList::URL_PATH => 'media'],
DirectoryList::STATIC_VIEW => [DirectoryList::URL_PATH => 'static'],
DirectoryList::UPLOAD => [DirectoryList::URL_PATH => 'media/upload'],
];
$params[\Magento\Store\Model\StoreManager::PARAM_RUN_CODE] = $config['store'] ?? 'default'; // Website code as same in admin panel
$params[\Magento\Store\Model\StoreManager::PARAM_RUN_TYPE] = 'store';
$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params);
/** @var \Cadence\External\Framework\App\External $app */
$app = $bootstrap->createApplication('\Cadence\External\Framework\App\External');
$integration = $app->launch([
'theme' => $config['theme']
]);
Using the above code, we’re doing a few things:
- Define a config array of information we want to pass to the Magento 2 install: the theme we want, the store we want, and where the bootstrap.php file lives
- bootstrap_path – The absolute path to our Magento 2 installation
- store – The store code for the store whose layout we want to bootup
- theme – The theme we want to boot
- Bootstrap the external application
- Launch the application
- The launch call returns the special Cadence\External\Model\Integration class
2) Access and Display Page View Components
The Integration class provides exposure for a number of methods:
Load/Render Special Assets
$specialAssets = $integration->getPageComponents();
This call loads an array of special assets from the layout. Magento 2 manages the <head> components and the body/html attributes outside of blocks, so we need to load this information separately. The data in this array is:
- requireJs – The requireJs script loader
- headContent – The native head content (including styles) from Magento 2
- headAdditional – Extra head content from plugins
- htmlAttributes – Attributes for the <html> tag
- bodyAttributes – Attributes for the <body> tag
- loaderIcon – The default loader icon
These are fully rendered pieces of html, so you can simply echo them out to the page.
Load/Render Blocks or Containers
// Output a container
echo $integration->getContainerHtml('after.body.start');
// Output a block
echo $integration->getBlockHtml('header');
// Get a block to manipulate
$headerBlock = $integration->getBlock('header');
These 3 calls allow you to access specific components of the Magento 2 layout. You can output the container html, block html, or directly access a block’s methods.
3) Customize External Blocks
This module adds a new layout file external.xml.
You can copy the template file into app/design/frontned/YOUR_THEME/layout/external.xml
Once it’s there, you can customize the file to add any extra blocks not included in the default layout:
<?xml version="1.0"?>
<!--
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<!-- Your customizations -->
<referenceContainer name="header-wrapper">
<!-- ... -->
</referenceContainer>
<!-- End custom -->
</body>
</page>
4) Putting it All Together
You should use the external application module to output Magento 2 assets into another system (or custom codebase) you have on the same server. Magento 2 must be accessible on the same file system, but the databases can be separate.
To review, here is how the module allows you access to Magento 2’s layout:
- Bootup a special External type of Magento 2 Application
- Launch the application, and configure a special Integration model
- The Integration model handles loading a boilerplate layout for the given theme and store view
- The integration model exposes methods to allow access to the special components (head assets) and general containers / blocks
Need Help Integrating Magento 2?
Here at Cadence Labs, we’ve got years of experience with Magento, and can help you with a variety of issues that come up when integrating Magento 2 with an external system.
If you would like help integrating your Magento site, call (719)-286-0751 or visit our contact page to have a real person contact you today!
Thanks for sharing your knowledge, this article was extremely helpful. It’s still very hard to find decent tutorials for Magento 2!
Thanks Alan! Very helpful indeed.
I’m rendering the top.links block in an external application, including authorization-link, register-link, and my-account-link. The output always reflects a logged-out user, even when a user is logged in on the Magento side. In Magento\Customer\Block\Account/AuthorizationLink, for example, isLoggedIn() returns null, even though Context::CONTEXT_AUTH is “customer_logged_in”. Since $this->httpContext->getValue(Context::CONTEXT_AUTH) generates that null value given the correct input from Context:CONTEXT_AUTH, it seems to be a problem with the \Magento\Framework\App\Http\Context configuration.
Do you have any suggestions about next steps to resolve this problem?
Magento 2 handles this through the “Private Content Sections” configuration (you’ll find the top links in a section.xml file in the customer module)
Essentially, an Ajax request should hole-punch this logged-in/logged-out status after the page renders via javascript. You’ll want to make sure you’re applying the Magento 2 javascript and knockout bindings.
If you don’t have access to that, I recommend you use the ObjectManager to grab the customer session instead of relying on the HTTP context
Thanks again Alan. I was already outputting the customer jsLayout config in the external app, so I did just end up switching the top links to be rendered on the client side using Knockout bindings in the “customer” scope. Worked like a charm.
Hi Alan Barber thanks for the great solution and sharing, i have run your code and i got this error
Magento\Framework\Exception\LocalizedException: Invalid XML in file /var/www/html/xxx/app/code/Cadence/External/etc/events.xml: Element ‘config’: Missing child element(s). Expected is ( event ). Line: 2 in
Could you pleases help me solve this problem it should help me a lot if it work
Thank you very much