Login
Neu hier? Registrieren.
Multidomain Lösung mit einer MODx Installation
In diesem Tutorial möchte ich aufzeigen, wie mit einer MODx-Installation (also einer Datenbank und einer Manager-Oberfläche) und vor allem ohne Hacks mehrere Domains verwaltet werden können. Dafür benötigt man lediglich ein paar Plugins, Snippets, Chunks, eine Template Variable sowie Anpassungen der .htaccess. Für Fortgeschrittene bzw. für faule Menschen zeige ich dann noch auf, wie man nur ein Template anlegen muss und trotzdem individuelle Designs für jede Domain verwenden kann.
Voraussetzungen und Einschränkungen
Es gibt prinzipiell keine Einschränkungen, man muss nur ein bisschen sorgsam sein bei der Benennung seiner Dokumente bzw. Template-Ordner. Folgende Voraussetzungen müssen zudem erfüllt sein:
- geladenes mod_rewrite: Ohne mod_rewrite geht nichts. Sollte aber heutzutage auch kein Thema sein.
- Wayfinder 2.5: Möchte man seine Startseite gleichberechtigt als Hauptmenüpunkt anzeigen, muss Wayfinder 2.5 installiert sein (aktuell beta, aber stabil). Grund ist die Möglichkeit, einen Weblink als aktiv zu markieren. Geht aber auch ohne diese Version.
Herangehensweise
Inspiriert von einem Thread im internationalen Forum sowie einer bereits lang im Kopf vorhandenen Gedankenspielerei und natürlich einem konkreten Projekt habe ich ein Set von .htaccess-Anweisungen, Plugins, Snippets und Chunks angelegt die folgendes erlauben:
- Verschiedene Domains mit einer MODx-Installation verwalten
- Keine Hacks des Core (somit 0.9x-kompatibel)
- Pro Domain ein Ordner im Managerbaum
- Pro Domain eine individuelle Fehlerseite mit korrekten 404-Header
- Individuelle Links / Aliase inklusive natürlicher Verzeichnisstruktur (domain1.de/produkte/autos, domain2.de/produkte/autos)
- Möglichkeit, Inhalte domainweit zu nutzen (mit Hilfe des getField-Snippets).
- Kein mehrfaches Anlegen von Menüaufrufen, Auflistungen etc.
- Einsatzmöglichkeiten: Mehrsprachige Websites (.de und .com), mehrere Kunden in einer Installation, redaktionelle Inhalte auf mehreren Domains, SEO-Spaß...
1. Szenario und erste Vorbereitungen
Als erstes nehmen wir unsere SEF-URL-Einstellungen vor:
Werkzeuge->Konfiguration->Benutzerfreundliche URLs:
- Benutzerfreundliche URLs benutzen: ja
- Suffix: .html
- Benutze benutzerfreundliche Aliaspfad-Angaben: ja
- Doppelte Aliase zulassen: ja
- Automatisch generierter Alias: ja
Dann legen wir eine Template Variable "host_url" vom Typ "Text" an und weisen sie unserem Template zu:
Wichtig ist der Name "host_url" sowie die Standardeigenschaft "@inherit".
Als nächstes legen wir ein Snippet an mit dem Namen "http_host" mit folgendem Inhalt:
<?php
return $_SERVER['HTTP_HOST'];
?>
Wir wollen drei verschiedene Domains anlegen:
- www.domain1.de
- www.domain2.de
- www.domain3.de
Wir legen die drei Ordner für die drei Domains im Manager an:
root
+ www.domain1.de
+ www.domain2.de
+ www.domain3.de
+ allgemeine Inhalte
- allgemeine Startseite
- 404
Zusätzlich einen Ordner für domainweite Inhalte (falls gewünscht) sowie eine allgemeine Start- und Fehlerseite, die auch in der Konfiguration als Start- und Fehlerseite angegeben werden. Dies nur als Fallback-Lösung, habe ich bisher nicht gebraucht.
Wichtig: Die Ordner müssen als Titel den Namen der Domain haben, und zwar mit www. Oder alle ohne www, dafür müsste man später die .htaccess anders aufbauen. Ist aber auch möglich, darauf werde ich aber erstmal nicht eingehen.
Wichtig: Als "alias" und als TV "host_url" gibt man für jeden Domain-Ordner ein und denselben eindeutigen Namen für diesen Ordner an. Zum Beispiel "domain1-de". Es ist absolut wichtig, dass dieser Name sonst nirgends mehr als Ordner oder Dokument-Alias vorkommt. Mein Beispiel sollte aber reichen und wird auch so von mir verwendet.
Also:
- Seitentitel: www.domain1.de
- Alias: domain1-de
- TV host_url: domain1-de
Ihr werdet gleich sehen wofür das nötig ist und warum zweimal der selbe Wert.
2. Die .htaccess
Okay, jetzt kommt die Zauberei. Für jede gewünschte Domain legt Ihr folgende Zeilen an, und zwar VOR dem eigentlichen mod_rewrite, aber (natürlich) nach dem RewriteEngine ON. Also:
RewriteEngine On
RewriteBase /
# First be sure to rewrite the request to a unique domain RewriteCond %{HTTP_HOST} .
RewriteCond %{HTTP_HOST} ^domain1\.de [NC] RewriteCond %{HTTP_HOST} !^www\.domain1\.de [NC] RewriteRule (.*) http://www.domain1.de/$1 [R=301,L]# rewrite the homepage of each domain to index.html RewriteRule ^domain1-de\.html$ /index.html
# do the other magic: Rewrite the the requests to for MODx readable folders RewriteCond %{HTTP_HOST} domain1\.de [NC] RewriteCond %{REQUEST_URI} !^/manager RewriteCond %{REQUEST_FILENAME} index\.php [OR] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(index\.(html?|php)|domain1-de)?(.*)$ index.php?q=/domain1-de/$3 [L,QSA]
Schauen wir uns das näher an:
RewriteCond %{HTTP_HOST} . RewriteCond %{HTTP_HOST} ^domain1\.de [NC] RewriteCond %{HTTP_HOST} !^www\.domain1\.de [NC] RewriteRule (.*) http://www.domain1.de/$1 [R=301,L]
Kennt man schon aus der Standard-.htaccess. Dies sorgt lediglich dafür, dass sowohl Anfragen nach http://www.domain1.de als auch http://domain.de einen eindeutig gleichen Namen haben, nämlich www.domain1.de. Ist eigentlich ein absolutes Muss, um nicht die Gefahr des duplicate Content bei Google zu haben.
RewriteRule ^domain1-de\.html$ /index.html
behandelt den Sonderfall des direkten Aufrufs unserer Domainordner. Da diese z.B. den Alias domain1-de haben, wollen wir hier ein sauberes index.html als Link. So klappt auch der Aufruf von www.domain1.de/, da die index.html immer als Ordner-Datei angezeigt wird.
RewriteCond %{HTTP_HOST} domain1\.de [NC]
Jetzt gehts dann richtig los. Sobald nun eine Anfrage nach unser domain1.de kommt...
RewriteCond %{REQUEST_URI} !^/manager
...aber nicht der Manager angefragt wird...
RewriteCond %{REQUEST_FILENAME} index\.php [OR] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(index\.(html?|php)|domain1-de)?(.*)$ index.php?q=/domain1-de/$3 [L,QSA]
schreiben wir unsere Links um, so dass MODx sie intern richtig verarbeitet. Haben wir zum Beispiel ein Dokument im Baum so liegen:
root
- www.domain1.de
- - produkte
- - - autos
- - - - BMW
So wäre der eigentliche Link ja: www.domain1.de/domain1-de/produkte/autos/BMW.html
Diesen ersten Ordner wollen wir aber nicht, denn es soll ja alles sauber aussehen. Also wird eine Anfrage nach www.domain1.de/produkte/autos/BMW.html von MODx intern weiterverarbeitet als www.domain1.de/domain1-de/produkte/autos/BMW.html.
Klingt evtl. kompliziert, aber ist eigentlich recht einfach. Dies machen wir jetzt für alle drei Domains, so dass unsere .htaccess so aussieht:
RewriteEngine On
RewriteBase /
# First be sure to rewrite the request to a unique domain RewriteCond %{HTTP_HOST} . RewriteCond %{HTTP_HOST} ^domain1\.de [NC] RewriteCond %{HTTP_HOST} !^www\.domain1\.de [NC] RewriteRule (.*) http://www.domain1.de/$1 [R=301,L] # rewrite the homepage of each domain to index.html RewriteRule ^domain1-de\.html$ /index.html # do the other magic: Rewrite the the requests to for MODx readable folders RewriteCond %{HTTP_HOST} domain1\.de [NC] RewriteCond %{REQUEST_URI} !^/manager RewriteCond %{REQUEST_FILENAME} index\.php [OR] RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(index\.(html?|php)|domain1-de)?(.*)$ index.php?q=/domain1-de/$3 [L,QSA] # First be sure to rewrite the request to a unique domain RewriteCond %{HTTP_HOST} . RewriteCond %{HTTP_HOST} ^domain2\.de [NC] RewriteCond %{HTTP_HOST} !^www\.domain2\.de [NC] RewriteRule (.*) http://www.domain2.de/$1 [R=301,L] # rewrite the homepage of each domain to index.html RewriteRule ^domain2-de\.html$ /index.html # do the other magic: Rewrite the the requests to for MODx readable folders RewriteCond %{HTTP_HOST} domain2\.de [NC]
RewriteCond %{REQUEST_URI} !^/manager RewriteCond %{REQUEST_FILENAME} index\.php [OR] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(index\.(html?|php)|domain2-de)?(.*)$ index.php?q=/domain2-de/$3 [L,QSA] # First be sure to rewrite the request to a unique domain RewriteCond %{HTTP_HOST} .
RewriteCond %{HTTP_HOST} ^domain3\.de [NC] RewriteCond %{HTTP_HOST} !^www\.domain3\.de [NC] RewriteRule (.*) http://www.domain3.de/$1 [R=301,L] # rewrite the homepage of each domain to index.html RewriteRule ^domain3-de\.html$ /index.html
# do the other magic: Rewrite the the requests to for MODx readable folders RewriteCond %{HTTP_HOST} domain3\.de [NC] RewriteCond %{REQUEST_URI} !^/manager RewriteCond %{REQUEST_FILENAME} index\.php [OR] RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(index\.(html?|php)|domain3-de)?(.*)$ index.php?q=/domain3-de/$3 [L,QSA] # The Friendly URLs part for the rest (or the main domain) RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
Am Ende kommt noch der Standard rein.
3. Plugin für interne Links
Da MODx selbst seine URLs natürlich mit unseren Identifizierungs-Ordnern erzeugt, müssen wir diese entfernen.
Plugin "multisite" anlegen:
global $modx;
$host_url = $modx->getTemplateVarOutput('host_url',$modx->documentIdentifier);
$host_url = $host_url['host_url'];// delete our identification folder from output
$modx->documentOutput=preg_replace("#/?".$host_url."/#i","/", $modx->documentOutput);// Homepage
$modx->documentOutput=preg_replace("#/?".$host_url."\.html#i","index.html", $modx->documentOutput);
und als Event "OnWebPagePrerender" anhaken.
Was passiert? Das Plugin liest unsere TV "host_url" aus, die uns den Namen des Domain-Ordner-Alias liefert. Dieser wird aus allen Pfaden rausgelöscht. Außerdem werden Links auf www.domain1.de/domain1-de.html, also Links auf unseren Domain-Ordner umgeschrieben auf www.domain1.de/index.html.
4. Templates
Im Template-Header (am besten auslagern in einen Chunk) muss folgende Zeile stehen:
<base href="http://[!http_host!]/" />
Damit wird dafür gesorgt, dass die Links in Euren Dokumenten auch die richtige Domain vorangestellt bekommen.
Falls Ihr verschiedene Templates je Domain einbinden wollt, benennt die Template-Ordner einfach nach den Domain-Namen, dann kann das CSS automatisch mit
<link href="/assets/templates/[!http_host!]/default.css" rel="stylesheet" type="text/css" />
eingebunden werden.
5. Eigene Fehlerseiten
Damit sollte unsere Kiste eigentlich schon laufen. Aber da wir natürlich für jede Domain eine eigene 404-Fehlerseite möchten, brauchen wir noch ein weiteres Plugin:
Plugin "404" anlegen mit
/*###### Name: 404 Redirect for multisite
# Version: 0.1 # Author: Marc "MadeMyDay" Hinse (http://www.madeyourweb.com) #####*/ global $modx; $e = &$modx->Event; switch($e->name) { case 'OnPageNotFound': global $modx; $table= $modx->getFullTableName('site_content'); $host_url = $_SERVER['HTTP_HOST']; $host_url = $modx->db->escape($host_url); $where = 'pagetitle = "'.$host_url.'"'; $result = $modx->db->select('id',$table,$where); $row = $modx->db->getRow($result); $redirectParent = $row['id']; if ($redirectParent){ $errorPage= $modx->db->select('id',$table,'alias=404 AND parent='.$redirectParent); $rowerror = $modx->db->getRow($errorPage); $error = $rowerror['id'];$this->sendForward($error, 'HTTP/1.0 404 Not Found');}}
als Event "OnPageNotFound" anhaken.
Das Plugin macht nichts anderes als den MODx Event abzufangen, der bei einer nicht verarbeitbaren Seite "feuert". Es liest aus, was der Besucher angefragt hat (zum Beispiel www.domain1.de/dflefwe), sucht den Domainordner anhand des Seitentitels raus und zeigt dann die Seite mit dem alias "404" an.
Das heißt, unter jedem Domainordner legt man ein Dokument "Seite nicht gefunden" o.ä. an, das den Alias "404" hat. Der Alias ist wichtig und muss immer so lauten wie im Plugin angegeben (eben zum Beispiel "404")!
6. Wayfinder
Möchte man seine Startseite (eben den Domainordner) im Menü gleichwertig den Unterdokumenten anzeigen, also in der Art:
- Startseite
- Unternehmen
- Produkte
- Kontakt
hat aber gezwungenermaßen folgende Struktur:
+ www.domain1.de
- - Unternehmen
- - Produkte
- - Kontakt
legt man einen Weblink an, der auf die Startseite verweist:
- www.domain1.de
- - Startseite (Weblink auf darüberliegenden Ordner)
- - Unternehmen
- - Produkte
- - Kontakt
Problem ist, dass in der aktuellen Wayfinder-Version 2.0 ein Weblink auf ein internes Dokument nicht aktiv markiert wird, wenn das verlinkte Dokument gerade aufgerufen ist. Abhilfe schafft da Wayfinder 2.5, derzeit noch beta. Sinnvoll ist hier das Verwenden der selfClass anstatt bzw. zusätzlich zu der activeClass in den Wayfinder-Parametern. Warum, seht Ihr dann wenn es soweit ist. Kurzum: Da der übergeordnete Ordner ja schon aktiv ist, wenn der Weblink aktiv ist, kriegt der Weblink immer den Status "aktiv". Das trifft bei der selfClass aber nicht zu, da hier nur genau das Dokument aktiv markiert wird, das aufgerufen wird und nicht auch die darüberliegenden.
Das war es erstmal. Fragen und Anregungen gerne im Forum.