The issue:
I have many celebrities and for each I want to publish a few pages.
- foo.com/celebrities/
- foo.com/celebrities/brad-pitt/
- foo.com/celebrities/angelina-julie/ (Angelina’s hub page)
- foo.com/celebrities/angelina-julie/profile/
- foo.com/celebrities/angelina-julie/contact/
- foo.com/celebrities/angelina-julie/gallery/
The pages (index, profile, contact, gallery) are common to all the celebrities, but their content is generated on the fly by database queries and PHP scripting.
(3,700 celebrities and some of the content are published today
here. These pages are all static, generated by a backoffice application that I developed, and uploaded (with a one-way synchronization utility via FTP). The static pages are well optimized and the new solution must use best SEO practices as well, friendly URLs included.)
The solution:
Two issues need to be approached:
- Dynamic rendering of friendly URLs, that will work with MODx core navigation libraries and related MODs such as WayFinder, Breadcrumbs, etc.
- Enabling browser accessibility to these pages.
Note 1: The tactic behind the solution uses MODx 404 document extensively. This document is being called each time the system cannot interpret the URL. The 404 document calls a snippet that includes the business logic on how to forward the call (server-side) to a valid document.
Note 2: The ability to browse friendly URLs can be easily achieved via .htaccess rules, but I chose to keep the business logic within the framework repository, and to maintain cross-platform compatibility with IIS servers without ISAPI_Rewrite installed.
Note 3: The page URL mapping could have been easier had I set the following structure:
foo.com/celebrities/profile/angelina-julie/
but it doesn’t adhere to this particular site’s UI logic and SEO principles.
Site Settings
Under Tools -> Configuration -> Friendly URLs:
Prefix for friendly URLs:
[+URLPrefix+]/
Suffix for friendly URLs:
/
[+URLPrefix+] is a PlaceHolder that is initialized in the snippet
getCelebParams
Template Settings
I’m using one template only for all the celebrities documents.
In this template I placed a call to
getCelebParams: [[getCelebParams]]
Snippets
There are two snippets:
getCelebParams and
404Router. The first has a role in setting up friendly urls, and the latter - in routing a URL call to the appropriate document. I will detail the snippets last in order to maintain fluidity here.
404 Document
Just set up a 404 document, and define its docID in site settings.
Make sure NOT to cache the document.
Include this call to
404Router snipped in the document content:
[[404Router]] or [!404Router!].
Celebrity Documents
- Each of the celebrity pages has its own document (index, about, contact, profile, etc.)
- Make sure to include the document pathname in the Document’s alias.
- Make sure to assign a template that calls getCelebParams snippet.
- Don’t cache the document.
getCelebParams Snippet
This snipped is called by the template that is shared by each of the celebrity documents.
<?php
$celebFileName = $modx->celebFileName;
$sql = $modx->db->query("SELECT * FROM `cg_celebs` WHERE (FileName = '$celebFileName')");
$result = $modx->db->getRow($sql);
// Setting Placeholders:
// =================
$modx->setPlaceholder('URLPrefix', "celebrities/".$result['FileName']);
// There is much more written here that is not related to the topic at hand.
?>
404Router Snippet
This snippet is called from the 404 document above.
<?php
// Getting the requested URL:
$RequestURL = $_SERVER['REQUEST_URI'];
// Testing if the requested URL points to the celebrities "folder":
if (strpos($RequestURL, "celebrities/") <> 0)
{
// Isolating the FileName portion of the URL from the Document one:
$celebURL = str_replace("http://", "", $RequestURL);
$split_url = explode('/', $celebURL);
$celebFileName = $split_url[2];
$celebDocument = $split_url[3];
$celebDocument = str_replace(".html", "", $celebDocument);
// Casing Document for DocID:
switch ($celebDocument) {
case "index":
$celebDocID = 89; // Celebrity's Homepage (Hub Page)
break;
case "birth-data":
$celebDocID = 114;
break;
default:
$celebDocID = 89; // Celebrity's Homepage (Hub Page)
}
// Rerouting request to index.php without changing requested URL:
$modx->celebFileName = $celebFileName;
$modx->sendForward($celebDocID);
}
?>
Last but not least - I’m a total newbie to MODx, and a rather poor PHP coder. Please feel free to suggest improvements to this solution.