Problem
In same cases you may want to set up a specific domain just for editing your Concrete site. This may be beacuse you have set up redundant servers for high availability or you want to increase security by limiting the IP addresses that can access the edit interface. Another reason for setting up an edit domain is to avoid issues with aggressive caching.
Whatever the use case, one of the challenges that can arrise is generating a sitemap.xml
file. By default, the links to all of the content in a site contained in the sitemap.xml
file will be created using the domain where the command is issued from. If someone is manually generating the it from edit domain using the Dashboard, then the links will point to the edit domain rather than the public domain.
Solution
Fortunately, Concrete supports many application event hooks which can be used to modify it's behavior. One useful event in this scenario is on_sitemap_xml_element
. This event is fired each time an element is added to the sitemap.xml
file as it's generated. We can hook into this event and change the URL's host before it's written to disk.
In the example below, the public and edit domains are specified in a .env
file and are accessed in the $_ENV
global variable with by using the vlucas/phpdotenv
package to load the values by adding something like this to application/bootstrap/autoload.php
:
$env = Dotenv\Dotenv::createImmutable(__DIR__ . '/../../../' /* path to .env outside of public directory */);
These values can be used in the application/config/site.php
to set the canonical URL as well. Below, they are used to ensure that the URLs in the sitemap.xml
nodes reference the public domain.
$app['director']->addListener('on_sitemap_xml_element', function ($event) {
// Don't make changes if edit and public URLs not detected
if (empty($_ENV['CANONICAL_URL_EDIT']) || empty($_ENV['CANONICAL_URL_PUBLIC'])) {
return $event;
}
/** @var \Concrete\Core\Page\Sitemap\Event\ElementReadyEvent $event */
$element = $event->getElement();
// Don't try to modify a header or footer element.
if (!$element instanceof \Concrete\Core\Page\Sitemap\Element\SitemapPage) {
return $event;
}
/** @var \Concrete\Core\Url\UrlImmutable $url */
$url = $element->getUrl();
// Don't modify if no URL is set
if (!$url instanceof \Concrete\Core\Url\UrlImmutable) {
return $event;
}
if ((string) $url->getHost() !== $_ENV['CANONICAL_URL_PUBLIC']) {
/** @var \Concrete\Core\Page\Sitemap\Element\SitemapPage $element */
$element->setUrl($url->setHost($_ENV['CANONICAL_URL_PUBLIC']));
}
return $event;
});