WordPress и домены-синонимы (алиасы)
Задача: сделать так, чтобы один сайт на WordPress с одной БД открывался по множеству разных доменов и не сойти с ума.
Ситуация такая: есть сайт. Внутри — WordPress и свой мир. У сайта есть команда разработки. Для каждого разработчика придумано своё окружение и работы ведутся на dev-домене. dev0.*.tld
, dev2.*.tld
, ну и пока не закончатся разработчики или цифры.
Ещё есть обычные зеркала сайта — маркетинг придумал домен в другой доменной зоне, глобальные, региональные и какие угодно. И при этом всё это живёт на одной БД, ну, да. Не спрашивайте. Так бывает. Реальность достаточна сурова и объясняется контекстом (который до конца никому не понятен) или фразой типа: «так устроена жизнь».
И вот я совсем не понимаю, зачем в WordPress в базе данных в пугающе многих местах, захардкожен домен сайта. При варианте разработки «сделал локально → перенёс на удалённый сервер», человечество изобрело для этого костыля другие костыли или просто в лоб заменяют SQL-запросом все совпадения домена. Потрясающе.
Константы WP_SITEURL
и WP_HOME
¶
Решение (трюк?) с переопределением констант WP_SITEURL
и WP_HOME
работают не так, как нужно: они переопределяются, но не изменяются. И чаще всего вы получите при обращении к dev0.*.tld
запрос ресурсов, статики и всего, с абсолютным урлом основного домена. На dev-окружениях такое и бесит и недопустимо.
// wp-config.phpdefine( 'WP_HOME', 'https://' . $_SERVER['HTTP_HOST'] );define( 'WP_SITEURL', 'https://' . $_SERVER['HTTP_HOST'] );
// wp-config.php define( 'WP_HOME', 'https://' . $_SERVER['HTTP_HOST'] ); define( 'WP_SITEURL', 'https://' . $_SERVER['HTTP_HOST'] );
«Умная переопределялка» для хоста через $_SERVER['HTTP_HOST']
будет вести себя точно также из-за абсолютных ссылок в БД.
/** * Вторая попытка определения хоста для дев- и прод-доменов */switch ( strtolower( $_SERVER['HTTP_HOST'] ) ){ case 'dev.7site.tld': define('WP_SITEURL', 'https://dev.7site.tld'); define('WP_HOME', 'https://dev.7site.tld'); break; case '7site.tld': define('WP_SITEURL', 'https://7site.tld'); define('WP_HOME', 'https://7site.tld'); break; default: define('WP_SITEURL', 'https://site.tld'); define('WP_HOME', 'https://site.tld'); break;}
/** * Вторая попытка определения хоста для дев- и прод-доменов */ switch ( strtolower( $_SERVER['HTTP_HOST'] ) ) { case 'dev.7site.tld': define('WP_SITEURL', 'https://dev.7site.tld'); define('WP_HOME', 'https://dev.7site.tld'); break; case '7site.tld': define('WP_SITEURL', 'https://7site.tld'); define('WP_HOME', 'https://7site.tld'); break; default: define('WP_SITEURL', 'https://site.tld'); define('WP_HOME', 'https://site.tld'); break; }
Разумеется, при этом менять что-то в самой БД — нельзя. При этом хочется. А нельзя.
Кажется, логичным: заменять то, что нужно и там, где надо (дорогостоящая операция по производительности). Так уже работает, например, для медиафайлов на dev-доменах: медиа загружены на основной домен, менеджер при тестировании смотрит окружение разработчика, но урл для картинки будет заменён на урл боевого домена:
<img class="gallery__img" alt="<?= $item['alt']; ?>" draggable="false" src="<?= str_replace( 'dev1.', '', $item['src'] ); ?>">
<img class="gallery__img" alt="<?= $item['alt']; ?>" draggable="false" src="<?= str_replace( 'dev1.', '', $item['src'] ); ?>">
Что же делать ¶
Выкинуть из кода все переопределения констант.
Создать файл wp-domains.php
в корне. Внутри описать магию с ob_start
+ str_replace
.
<?php/** * https://github.com/MihanEntalpo/WordpressGitTools/blob/master/wp-domains.php *///Проверим, не запускался ли данный скрипт ранее:if (defined("WP_DOMAINS_INITIALIZED")) return;const WP_DOMAINS_INITIALIZED = 1;//Домены на котором может работать сайт, локальные и удалённые,$domains_enabled = array( "site.tld", "7site.tld", "dev.7site.tld");//Добавим в массив $_SERVER все необходимые для проверки ключи,//которых там может не быть$_SERVER = array_replace( array( "HTTPS" => "", "HTTP_HTTPS" => "", "REQUEST_SCHEME" => "", "SERVER_PORT" => "" ), $_SERVER);//Проверим, используется ли https?$https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || (!empty($_SERVER['HTTP_HTTPS']) && $_SERVER['HTTP_HTTPS'] != 'off') || $_SERVER['REQUEST_SCHEME'] == 'https' || $_SERVER['SERVER_PORT'] == 443;//Составим адрес хоста$site_addr = ($https ? "https://" : "http://") . $_SERVER['HTTP_HOST'] . "/";//Заменим адрес хоста на тот, что мы вычислилиif (!defined("WP_HOME")) define("WP_HOME", $site_addr);if (!defined("WP_SITEURL")) define("WP_SITEURL", $site_addr);//Добавим обработчик выдачи сайта, который будет заменять во всех ссылках//домены на текущий доменob_start(function ($data) use ($domains_enabled, $https){ $current_host = $_SERVER['HTTP_HOST']; $replace = array(); $scheme = $https ? "https" : "http"; foreach ($domains_enabled as $domain) { if ($current_host == $domain) continue; $replace["http://$domain/"] = "$scheme://$current_host/"; $replace["https://$domain"] = "$scheme://$current_host"; $replace["//$domain/"] = "//$current_host/"; $replace["//$domain"] = "//$current_host"; } return str_replace(array_keys($replace), array_values($replace), $data);});
<?php /** * https://github.com/MihanEntalpo/WordpressGitTools/blob/master/wp-domains.php */ //Проверим, не запускался ли данный скрипт ранее: if (defined("WP_DOMAINS_INITIALIZED")) return; const WP_DOMAINS_INITIALIZED = 1; //Домены на котором может работать сайт, локальные и удалённые, $domains_enabled = array( "site.tld", "7site.tld", "dev.7site.tld" ); //Добавим в массив $_SERVER все необходимые для проверки ключи, //которых там может не быть $_SERVER = array_replace( array( "HTTPS" => "", "HTTP_HTTPS" => "", "REQUEST_SCHEME" => "", "SERVER_PORT" => "" ), $_SERVER ); //Проверим, используется ли https? $https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || (!empty($_SERVER['HTTP_HTTPS']) && $_SERVER['HTTP_HTTPS'] != 'off') || $_SERVER['REQUEST_SCHEME'] == 'https' || $_SERVER['SERVER_PORT'] == 443; //Составим адрес хоста $site_addr = ($https ? "https://" : "http://") . $_SERVER['HTTP_HOST'] . "/"; //Заменим адрес хоста на тот, что мы вычислили if (!defined("WP_HOME")) define("WP_HOME", $site_addr); if (!defined("WP_SITEURL")) define("WP_SITEURL", $site_addr); //Добавим обработчик выдачи сайта, который будет заменять во всех ссылках //домены на текущий домен ob_start(function ($data) use ($domains_enabled, $https) { $current_host = $_SERVER['HTTP_HOST']; $replace = array(); $scheme = $https ? "https" : "http"; foreach ($domains_enabled as $domain) { if ($current_host == $domain) continue; $replace["http://$domain/"] = "$scheme://$current_host/"; $replace["https://$domain"] = "$scheme://$current_host"; $replace["//$domain/"] = "//$current_host/"; $replace["//$domain"] = "//$current_host"; } return str_replace(array_keys($replace), array_values($replace), $data); });
Подключить файл wp-domains.php
в файлы wp-config.php
и wp-load.php
.
require_once __DIR__ . '/wp-domains.php';
require_once __DIR__ . '/wp-domains.php';
Проверено на хостинге reg.ru, четырёх доменах-синонимов и трёх поддоменах.