@diogo Thanks for sharing your code. I just packed it in a Module adding some features.
It extends the Page class, by hooking a new method mlUrl(bool includePageId).
I wanted to generate the localized url too. So instead of using names I use title to generate url.
That function accepts one boolean parameter to specify if to use the page id:
www.mydomain.com/it/my-italian-title/
www.mydomain.com/it/[page id]_my-italian-title
The id is useful if you can't be sure that the localized title is unique, or in case that there are a lot of contents and you don't want to search by title in a long loop, but seeking directly by id.
The generated url always contains the language code, for the default one too, that in this case is manually mapped to 'en';
This is the code (that could be improved, especially in the generation of the url):
<?php
class MultiLanguageURL extends WireData implements Module {
/**
* getModuleInfo is a module required by all modules to tell ProcessWire about them
*
* @return array
*
*/
public static function getModuleInfo() {
return array(
// The module'ss title, typically a little more descriptive than the class name
'title' => 'MultiLanguageURL',
// version: major, minor, revision, i.e. 100 = 1.0.0
'version' => 100,
// summary is brief description of what this module is
'summary' => 'Multi language url',
// Optional URL to more information about the module
'href' => '',
// singular=true: indicates that only one instance of the module is allowed.
// This is usually what you want for modules that attach hooks.
'singular' => true,
// autoload=true: indicates the module should be started with ProcessWire.
// This is necessary for any modules that attach runtime hooks, otherwise those
// hooks won't get attached unless some other code calls the module on it's own.
// Note that autoload modules are almost always also 'singular' (seen above).
'autoload' => true,
);
}
/**
* Initialize the module
*
* ProcessWire calls this when the module is loaded. For 'autoload' modules, this will be called
* when ProcessWire's API is ready. As a result, this is a good place to attach hooks.
*
*/
public function init() {
$this->addHook('Page::mlUrl', $this, 'mlUrl');
}
private function mlPath($page) {
if($page->id === 1) return '/';
$path = '';
$parents = $page->parents();
foreach($parents as $parent) if($parent->id > 1) $path .= "/".$this->toSlug($parent->title);
return $path . '/' . $this->toSlug($page->title) . '/';
}
public function mlUrl($event) {
$page = $event->object;
$includeId = $event->arguments(0);
$url = $this->mlPath($page);
if ($includeId) {
$segments = explode('/', $url);
$index = count($segments)-2;
$segments[$index] = $page->id.'_'.$segments[$index];
$url = implode('/', $segments);
}
$lang = $this->user->language->name;
if (!$lang || $lang=='default') $lang = 'en';
$event->return = '/'.$lang.$url;
}
private function toSlug($str) {
$str = strtolower(trim($str));
$str = preg_replace('/[^a-z0-9-]/', '-', $str);
$str = preg_replace('/-+/', "-", $str);
return $str;
}
public function parseUrl() {
$page = $this->fuel('page');
$user = $this->fuel('user');
$languages = $this->fuel('languages');
$pages = $this->fuel('pages');
$input = $this->fuel('input');
$lang = $page->name;
if ($lang == 'en') $lang='default';
$user->language = $languages->get($lang);
$basePage = $pages->get("/");
$segments = $input->urlSegments;
if($segments){
$page = $basePage;
foreach($segments as $segment){
// search of page id inside the segment
$parts = explode('_', $segment);
$pageid=null;
if (count($parts)>1 && is_numeric($parts[0])) {
$pageid=$parts[0];
$page = $pages->get($pageid);
} else {
$children = $page->children;
foreach ($children as $child){
$found = false;
if($segment==$this->toSlug($child->title)){
$page = $child;
$found = true;
break;
}
}
}
if (!$found) throw new Wire404Exception();
}
} else {
$page = $basePage;
}
$this->fuel->set('page', $page);
return $page;
}
}
This is the code to use the module in your template:
<?php
$page = $modules->get('MultiLanguageURL')->parseUrl();
include("./{$page->template}.php");
?>
and to generate the localized url:
// to include the page id
$page->mlUrl(true);
// to generate without id
$page->mlUrl(false);