Adding a Trailing Slash to CMS Pages in Magento 2

Published by John on October 9, 2019 Under Magento

While working on a migration from Magento 1 to Magento 2 for one of my clients, one of the issues I ran into was adding a trailing slash to the end of the URL for CMS Pages.

For both categories and products, there is an option for adding a Suffix to the URL, which can be found Under Admin -> Stores -> Configuration -> Catalog -> Search Engine Optimization.

Then, adjust the Product URL Suffix or Category URL Suffix as needed.

However, I do not believe there is a similar option for CMS Pages. Instead, when you save a page, it uses the identifier of the page to create a URL Rewrite, then on the front end of the website, it first checks for a redirect with the trailing slash, then if it doesn’t find it, searches for one without the trailing slash, adding a redirect.

So, for example, if you had a page with a title of ‘About Us’, when the page is saved, it will automatically set the identifier as ‘about-us’, unless you manually change it.

When someone visits your website and goes to ‘about-us/’, they will get automatically redirected to the ‘about-us’.

As a result of this process, which I believe is the default Magento 2 behavior, if you were to add a trailing slash using your .htaccess file or nginx conf, you will get a ‘too many redirects’ warning.

I believe there are probably a few different ways to address this, but I think the easiest and least obtrusive in terms to code changes is to simply add a trailing slash to the identifier of each page.

Of course, you can’t really expect your end client to remember to add a trailing slash each time they create a new CMS Page, so I created a simple event observer that ties into the cms_page_prepare_save event, checks the identifier for a trailing slash, and if it is not present, adds it.

Disclaimer / Prerequisites

You should make a backup of your site and database, see below.

You should do this on a development site first and test for bugs, before using on a live website. I make no guarantees that this is the best solution to this problem.

This assumes you already have a working Magento module setup already.

Make Note of default pages under Stores -> Configuration -> Web -> Default Pages (You may need to set these back up)

Backup Your Site

Before continuing, please make a backup of your website files and database. For the database, I would recommend backing up both your full database, then additionally the url_rewrites and cms_page tables, like so:


mysqldump -u root -p magento_2_database | gzip > ~/magento_2_database_2019-10-09.sql.gz

mysqldump -u root -p magento_2_database url_rewrite cms_page | gzip > ~/magento_2_database_small_2019-10-09.sql.gz

Update your Module to add Observer

First, we will create a new observer: app/code/Your_Company/Module/Observer/CmsPrepareSave.php

<?php

namespace Your_Company\Module\Observer;

class CmsPrepareSave implements \Magento\Framework\Event\ObserverInterface
{
	public function execute(\Magento\Framework\Event\Observer $observer)
	{
		
		$skip_routes = array('no-route');
		
		$page_data = $observer->getData('page');
		
		if(!is_object($page_data)){
			return $this;
		}
		
		$page_identifier = $page_data->getIdentifier();
		
		if(empty($page_identifier) || in_array($page_identifier, $skip_routes)){
			return $this;
		}
		
		if(substr($page_identifier, (strlen($page_identifier) - 1)) != '/'){
			$page_data->setIdentifier("{$page_identifier}/");
		}

		return $this;
	}
}


Make sure to change ‘Your_Company\Module’ to the correct values for your custom magento 2 module.

The execute function checks that it is not the ‘no-route’ page, using the skip_routes variable, then checks to see the identifier has a trailing slash and if not, adds it.

Next, we will add(or update) your modules events.xml file for the adminhtml section: app/code/Your_Company/Module//etc/adminhtml/events.xml


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="cms_page_prepare_save">
        <observer name="kcr_cms_page_prepare_save" instance="Your_Company\Module\Observer\CmsPrepareSave" />
    </event>
</config>

This adds a hook into the cms_page_prepare_save event using our newly created Observer.

Again, make sure to update Your_Company\Module to the correct values for your plugin.

Finally, make sure your website is in development mode and then clear your Magento 2 cache:


php bin/magento deploy:mode:set developer

php bin/magento cache:clean

Now, save a page and it should automatically add the trailing slash.

Fixing Existing Pages

Going forward, any time you save a page, the trailing slash should be automatically added to the URL, prior to the product saving. However, to keep from having to manually change the pages, you can use the below queries.

As noted above, after making these changes, you may need to adjust your default pages again.

Check for existing cms_pages without a trailing slash


select page_id, title, identifier from cms_page where identifier not like '%/' and identifier != 'no-route';

Update existing CMS Pages to add a trailing slash


update cms_page set cms_page.identifier = concat(identifier, '/') where identifier not like '%/' and identifier != 'no-route';

Find existing Rewrites that need to be changed


select request_path from url_rewrite where url_rewrite.request_path not like '%/' and entity_type = 'cms-page' and url_rewrite.request_path != 'no-route';

Update existing Rewrites to add a trailing slash.


update url_rewrite set request_path = concat(request_path, '/') where url_rewrite.request_path not like '%/' and entity_type = 'cms-page' and request_path != 'no-route';

If you get a duplicate entry warmning, uuse the below and then re-run the select query to find ones that did not change. For this site, there were several pages that had the same URL as a category.


update IGNORE url_rewrite set request_path = concat(request_path, '/') where url_rewrite.request_path not like '%/' and entity_type = 'cms-page' and request_path != 'no-route';

If you took your site out of production mode, you should probably clear cache, update, then set back to production:


php bin/magento cache:clean
php bin/magento setup:upgrade
php bin/magento deploy:mode:set production

Fixing Layout Handles

If you have overridden any of these pages using layout handles, they will need to be updated.

By default, magento 2 replaces a forward slash / with an underscore _

So, if your page identifier is: about-us/

Your Handle would be: about-us_

And so in your view/frontend/layout folder, your handle might look like: cms_page_view_id_about-us_.xml

Fixing 404 Errors After Forcing Slashes Via Htacess

If you decide you want to force adding the trailing slash via your .htaccess file, you should be aware that this may break some pages on the front end and backend.

Specifically on the front end during checkout, you may see the following error: Request does not match any route.

And, if you look at the network log, you will see several 404 errors related to the rest url, which helps draw some of the sections of the checkout box. This is because your htacess file is forcing a trailing slash onto the rest api urls, but they are not setup to support this.

Similarly, several pages in the backend will also stop working and also show 404 errors. To fix, update your .htaccess to exclude these. Something like the below will probably work.

	RewriteCond %{REQUEST_URI} !^/rest.*
	RewriteCond %{REQUEST_URI} !^/admin_backend.*
	RewriteCond %{REQUEST_URI} !^/customer.*
	RewriteCond %{REQUEST_URI} !^/account.*
	RewriteCond %{REQUEST_URI} !^/checkout.*
	RewriteCond %{REQUEST_URI} !^/contact.*
	RewriteCond %{REQUEST_URI} !^/cart.*
	RewriteCond %{REQUEST_URI} !^/api.*
	RewriteCond %{REQUEST_URI} /+[^\.]+$
	RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]

In the above, ‘admin_backend’ should be changed to whatever you have as your admin backend front name.

I think several of those, like account, contact, and cart, may not be necessary, but figured that it would be better to play it safe.

If you are using custom plugins, you may need to update this to add support for them as well.

Wrapping Up

If all went well, whenever you save a page, the trailing slash should get added to the page.

Not a Developer? If you are not a developer or otherwise need help getting this setup on your Magento 2 site, please contact me and I can quickly get you setup with my base Magento 2 plugin, which includes this feature.


No Comments |

Add a Comment