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, четырёх доменах-синонимов и трёх поддоменах.