November 29, 2023 —John Koster
I've recently been working on consolidating a number of websites. A common task when doing so is ensuring that all existing paths on separate domains are correctly redirecting to their new home.
There are dedicated services that can handle these types of redirects, but I was looking for something quick and simple to handle these redirects; in this post I'll walk you through the quick method I came up with for generating a routes file from an existing Statamic site.
The sites I am consolidating are fairly simple, and I only need to point to similar URLs on the new domain.
To get started, I needed to fetch the relative URLs for all of my existing Statamic entries and build up a list of all the relative URLs. Luckily, Statamic makes this painless and provides a simple way to retrieve them using the Statamic\Facades\Entry
facade:
1<?php 2 3use Statamic\Facades\Entry; 4 5function generateRedirectRoutes(string $homeRedirect, string $basePath, string $notFoundRedirect): string 6{ 7 $pathParts = []; 8 9 foreach (Entry::all() as $entry) {10 $url = $entry->url();11 12 // Skip the home page.13 if ($url == '/') {14 continue;15 }16 17 $pathParts[] = " '{$url}',";18 }19 20 $paths = implode("\n", $pathParts);21 22 // We'll finish this later.23}
at this point, our $paths
variable would contain a value similar to the following:
12 '/home',3 '/about',4 '/contact',
the leading whitespace is just there to make things look a little bit better in the final output.
At this point I have my relative URLs in a nicely formatted string, and all that is left to do is generate the routes file. I will be doing this by constructing a string with interpolated values and returning it:
1<?php 2 3function generateRedirectRoutes(string $homeRedirect, string $basePath, string $notFoundRedirect): string 4{ 5 $pathParts = []; 6 7 foreach (Entry::all() as $entry) { 8 $url = $entry->url(); 9 10 // Skip the home page.11 if ($url == '/') {12 continue;13 }14 15 $pathParts[] = " '{$url}',";16 }17 18 $paths = implode("\n", $pathParts);19 20 return <<<EOT21<?php22 23use Illuminate\Support\Facades\Route;24 25Route::get('/', function () {26 return redirect()->to('{$homeRedirect}', 301);27});28 29Route::get('/{any}', function (\$any) {30 31 \$paths = [32{$paths}33 ];34 35 if (! in_array(\$any, \$paths)) {36 return redirect()->to('{$notFoundRedirect}', 301);37 }38 39 return redirect()->to('{$basePath}'.\$any, 301);40})->where('any', '.*');41EOT;42}
Our function now looks pretty complicated, but its really just creating a fairly typical Laravel routes file with the information we provided it. Using the same three sample URLs from earlier, if we were to call our new function like so:
1<?php2 3generateRedirectRoutes('https://example.org', 'https://example.org/my-prefix', 'https://example.org/404');
it would generate the following routes file for us:
1<?php 2 3use Illuminate\Support\Facades\Route; 4 5Route::get('/', function () { 6 return redirect()->to('https://example.org', 301); 7}); 8 9Route::get('/{any}', function ($any) {10 11 $paths = [12 '/home',13 '/about',14 '/contact',15 ];16 17 if (! in_array($any, $paths)) {18 return redirect()->to('https://example.org/404', 301);19 }20 21 return redirect()->to('https://example.org/my-prefix'.$any, 301);22})->where('any', '.*');
It's a rather quick and simple way to generate a routes file, but it works for my use case. If you are looking to do something similar, you could expand on the logic to handle more complicated redirects as needed.
∎
The following amazing people help support this site and my open source projects ♥️
If you're interesting in supporting my work and want to show up on this list, check out my GitHub Sponsors Profile.