some of you might prefer to have clean URLs with CMSimple. There is a recipe in the CMSimple Wiki, but this is somewhat outdated and has some drawbacks. Inspired by kweku's request, I had a look at this issue a while ago, but stopped halfway. Now another user asked for having clean URLs, so I had a further look at it, and it seems it's quite possible to have them without any particular problems or restrictions. However, it is possible that some plugins are not compatible.
Requirements
You need an Apache server with mod_rewrite enabled, and need to be confident editing source code files (see http://www.cmsimple-xh.org/wiki/doku.ph ... es_offline). You must not use subsites -- the following recipe will not work with those.
This recipe handles CMSimple_XH 1.5.x, but it should work for other versions and variants of CMSimple also.[1]
Prepare your site to have almost clean URLs
At first change the configuration setting of Uri -> Seperator to "/". Then have a look at your page URLs. If the page headings contain special characters, you have to get rid of them; see http://www.cmsimple-xh.org/wiki/doku.ph ... n_headings.
I recommend this step anyway, even if you're not interested in clean URLs, as it makes the URLs better readable and exchangeable, and is necessary to make deep links from some platform (such as Facebook) working.
Add the necessary rewrite rules for the webserver
Add a file .htaccess in the root folder of the CMSimple installation (right beside the main index.php). Insert the following:
Code: Select all
RewriteEngine on
# Do not rewrite requests to existing directories and files:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Everything else is a CMSimple_XH page request,
# so shift the subfolders to the beginning of the query string
RewriteRule ^([A-z]{2}/)?(.*)$ $1?$2 [QSA]
- Change $sn and $sl
Somewhat at the beginning of cmsimple/cms.php you'll find the following line:Replace it with:Code: Select all
$subsite_folder_array = explode('/',str_replace($_SERVER['QUERY_STRING'],'',$_SERVER['REQUEST_URI'])); // creates array
Then find:Code: Select all
$subsite_folder_array = explode('/', $_SERVER['SCRIPT_NAME']); // creates array
and replace it with:Code: Select all
$sn = preg_replace('/([^\?]*)\?.*/', '\1', sv(($iis ? 'SCRIPT_NAME' : 'REQUEST_URI')));
Code: Select all
$sn = preg_replace('/index\.php$/', '', $_SERVER['SCRIPT_NAME']);
- Change the links that CMSimple produces
Find function a() in cmsimple/cms.php. Replace it with the following:Code: Select all
function a($i, $x) { global $sn, $u, $cf, $adm; if ($i == 0 && !$adm) { if ($x == '' && $cf['locator']['show_homepage'] == 'true') { return '<a href="' . $sn . $u[0] . '">'; } } return isset($u[$i]) ? '<a href="' . $sn . $u[$i] . (!empty($x) ? '?' . $x : '') . '">' : '<a href="' . $sn . (!empty($x) ? '?' . $x : '') . '">'; }
- Add a "base" element
Find function head() in cmsimple/cms.php. Add the following lines before the return statement:Code: Select all
global $sn; $t .= tag('base href="http' . (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 's' : '') . '://' . $_SERVER['SERVER_NAME'] . ($_SERVER['SERVER_PORT'] < 1024 ? '' : ':' . $_SERVER['SERVER_PORT']) . $sn . '"') . "\n";
Duplicate Content
You might have already noticed, that the old URLs (those after switching to almost clean URLs) still work. That's basically no problem, but search engines don't like this duplicate content (i.e. the same page accessible via more than one URL). The solution is to insert a canonical link element. Please note, that ge_canonical doesn't cater for clean URLs.
So put the following to userfuncs.php:
Code: Select all
<?php
/**
* Returns the canonical link tag. Works only for clean URLs.
*
* @global string The absolute path to the directory of the folder which contains index.php.
* @global string The GET parameter of the current page.
* @global array The GET parameters of all pages.
* @param array $ignoreParams The paramaters to ignore in the canonical URL (e.g. print).
* @return string The (X)HTML.
*/
function canonical($ignoreParams = array())
{
global $sn, $su, $u;
$params = array();
$allParams = explode('&', $_SERVER['QUERY_STRING']);
foreach ($allParams as $param) {
$param = explode('=', $param);
$key = $param[0];
if ($key != $su && !in_array($key, $ignoreParams)) {
$params[$key] = isset($param[1]) ? $param[1] : null;
}
}
ksort($params);
$newParams = array();
foreach ($params as $key => $value) {
$newParams[] = $key . (isset($value) ? "=$value" : '');
}
$baseURL = 'http'
. (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 's' : '')
. '://' . $_SERVER['SERVER_NAME']
. ($_SERVER['SERVER_PORT'] < 1024 ? '' : ':' . $_SERVER['SERVER_PORT'])
. $sn;
$canonicalSU = $su == $u[0] ? '' : $su;
$url = $baseURL . $canonicalSU;
if (!empty($newParams)) {
$url .= '?' . (empty($canonicalSU) ? '&' : '')
. implode('&', $newParams);
}
$link = tag('link rel="canonical" href="'
. htmlspecialchars($url, ENT_COMPAT, 'UTF-8') . '"') . "\n";
return $link;
}
/*
* Insert the canonical link to the "head" element, when not in admin mode.
*/
if (!$adm) {
$hjs .= canonical(array('logout', 'print'));
}
?>
Code: Select all
$hjs .= canonical(array('logout', 'month', 'print', 'year'));
When you log in to the back-end, you'll notice, that the template's stylesheet isn't used by the editor any more (tinyMCE and CKeditor). To change that for tinyMCE you have to extend your init file with the following:
Code: Select all
document_base_url: "%BASE_URL%",
Switching to view mode in the back-end will change to the "non clean" URLs. That's no problem, but you can change this behavior easily. Find function admin_menu() in cmsimple/cms.php and replace the following line:
Code: Select all
$t .= '<li><a href="' . $sn . '?' . $su . '&' . $changeMode . '">' . $changeText . '</a></li>' . "\n";
Code: Select all
$t .= '<li>' . a($s, $changeMode) . $changeText . '</a></li>' . "\n";
Christoph
PS: I've noticed some problems in IE. The solution is to use an absolute URL instead of an absolute path reference for the `base' element. Fixed in the description above.
PPS: Due to the use of SERVER_NAME and SCRIPT_NAME the solution will not work for some kinds of redirected domains (server internal redirects relying on symlinks).
PPPS: [1] There's an own recipe for CMSimple_XH 1.6.