Multisites: Cookie Domain vs. Mercator

Nutzung von Mercator Domain Mapping

Hintergrund: Domain Mapping in WordPress Multisites

Will man eine WordPress Multisite betreiben, liefert WordPress seit der Version 4.5 im Core die entsprechenden Domain Mapping Funktionen mit. Man braucht also nicht mehr das alte WordPress MU Domain Mapping Plugin, welches auch nicht mehr compatibel zu neuen WordPress- und PHP-Versionen ist. Leider hat die Core-Funktionalität einen Nachteil: Domain Aliase (beispielsweise den Alias www.xwolf.com für die Domain xwolf.de) sind nicht möglich, bzw. funktionieren nicht richtig. Man könnte zwar den Ansatz „durch den Rücken durch die Brust ins Auge“ führen und für jeden Website Alias einen eigenen Website-Eintrag machen, der dann auf dieselben Doamin Id verweist, aber das ist unschön zu pflegen, unintuitiv und einfach bäh.

Es gibt ein paar wenige Plugins, die versuchen hier etwas zu tun, aber diese sind entweder überteuert oder funktionieren dann doch wieder nur eingeschränkt.

Die beste Lösung ist daher der inoffizielle Nachfolger der MU Domain Mapping Plugins mit Namen Mercator. Mercator gibt es mWn nur über GitHub und nicht in der WP.org Directory. Aber dies würde ich nicht als Makel betrachten, sondern eher als Vorteil.

Mercator bringt mir nach der Installation all die schöne Aliase wieder die vorher MU Domain Mapping hatte. Mehr noch, es ist abwärtscompatibel. Wenn ich es in meiner Network-Setting aktiviere, sehe ich unter den Websites dann auch wieder alle mit dem alten Plugin geachten Aliase.

Screenshot meiner Konfiguration der Domain xwolf.de. Diese hat 5 Aliase: blog.xwolf.de, blog.xwolf.eu, www.xwolf.eu, xwolf.com, xwolf.eu

Soweit so gut.

Problem der Cookie-Domain

Mercator hat leider ein Problem mit der Cookie-Domain. Bzw. mit der bisherige Definition dazu, die ich in der wp-config.php hatte:

define('COOKIE_DOMAIN', $_SERVER['HTTP_HOST']);

Diese Anweisung ist dann notwendig, wenn ich meine Multisite unter einen Domainnamen wie multisiteserver.tld betreibe, die einzelnen Instanzen jedoch eigene Domainnamen haben, wie beispielsweise instanz1.tld, instanz2.tld und so weiter. Und nicht nur Subdomains unterhalb von multisiteserver.tld, wie instanz1.multisiteserver.tld.
Beim Login wird ein Cookie gesetzt. Dieses Cookie muss jedoch muss jedoch im Domain-Teil mit der Domain, auf der man sich befindet übereinstimmen. Ansonsten wird der Browser es ablehnen.
Worauf wiederum der Login fehlschlägt. Standardmäßig wird als Cookie-Domain allerdings die des Servers gesetzt. In diesem Fall also multisiteserver.tld .
Versuche ich mich also dann unter instanz1.tld anzumelden, wird der Browser das Cookie ablehnen. Nach der Eingabe der Zugangsdaten stellt WordPress dann fest, dass das Cookie fehlt und somit lehnt es den Login ab.
Um dies zu verhindern, setzt man obige Definition in der wp-config.php.

Mercator hat im Rahmen ders Mappings und in Bezug auf die Aliase jedoch ein eigenes Verfahren. Wenn es feststellt, dass die obige Definition gesetzt ist, meckert es daher mit folgender Fehlermeldung:

Screenshot der Server-Fehlermeldung: The constant COOKIE_DOMAIN is defined (probably in wp-config.php). Please remove or comment out that define() line.

Dieser Bug ist schon länger bekannt: Siehe Unable to login if single sign-on is disabled.

Lösung

In dem längeren Thread gibt es mehrere Ansätze. Mit hat die folgende Lösung von Rouven Hurling am Besten gefallen: Die sunrise.php von Mercator wird um eine Action erweitert, welche die COOKIE_DOMAIN nochmal prüft und setzt, wenn es notwendig ist.

Meine komplette sunrise.php sieht damit wie folgt aus:

<?php
// Default mu-plugins directory if you haven't set it
defined( 'WPMU_PLUGIN_DIR' ) or define( 'WPMU_PLUGIN_DIR', WP_CONTENT_DIR . '/mu-plugins' );

require WPMU_PLUGIN_DIR . '/mercator/mercator.php';
add_action( 'muplugins_loaded', function () {
        if ( defined( 'COOKIE_DOMAIN' ) ) {
                return;
        }

        $current_site = $GLOBALS['current_blog'];
        $real_domain  = $current_site->domain;
        $domain       = $_SERVER['HTTP_HOST'];

        if ( $domain === $real_domain ) {
                $cookie_domain = $real_domain;
                if ( 'www.' === substr( $cookie_domain, 0, 4 ) ) {
                        $cookie_domain = substr( $cookie_domain, 4 );
                }

                define( 'COOKIE_DOMAIN', $cookie_domain );
        }
} );

Die vorherige Definition der Cookie-Domain in der wp-config.php kann dann gelöscht werden.