923 lines
26 KiB
PHP
923 lines
26 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Mutiple Domain WordPress plugin.
|
|
*
|
|
* Core features.
|
|
*
|
|
* Contributors:
|
|
*
|
|
* - Clay Allsopp <https://github.com/clayallsopp>
|
|
* - Alexander Nosov <https://github.com/cyberaleks>
|
|
* - João Faria <https://github.com/jffaria>
|
|
* - Raphael Stäbler <https://github.com/blazer82>
|
|
* - Tobias Keller <https://github.com/Tobias-Keller>
|
|
* - Maxime Granier <https://github.com/maxgranier>
|
|
*
|
|
* @author Gustavo Straube <https://github.com/straube>
|
|
* @version 1.0.6
|
|
* @package multiple-domain
|
|
*/
|
|
class MultipleDomain
|
|
{
|
|
|
|
/**
|
|
* The plugin version.
|
|
*
|
|
* @var string
|
|
* @since 0.3
|
|
*/
|
|
const VERSION = '1.0.6';
|
|
|
|
/**
|
|
* The number of the default HTTP port.
|
|
*
|
|
* @var integer
|
|
*/
|
|
const PORT_HTTP = 80;
|
|
|
|
/**
|
|
* The number of the default HTTPS port.
|
|
*
|
|
* @var integer
|
|
*/
|
|
const PORT_HTTPS = 443;
|
|
|
|
/**
|
|
* The plugin instance.
|
|
*
|
|
* @var \MultipleDomain
|
|
* @since 0.8.4
|
|
*/
|
|
private static $instance;
|
|
|
|
/**
|
|
* The current domain.
|
|
*
|
|
* This property's value also may include the host port when it's
|
|
* different than `80` (the default HTTP port) and `443` (the default HTTPS
|
|
* port).
|
|
*
|
|
* @var string
|
|
* @since 0.2
|
|
*/
|
|
private $domain = null;
|
|
|
|
/**
|
|
* The original domain set in WordPress installation.
|
|
*
|
|
* This property's value also may include the host port when it's
|
|
* different than `80` (the default HTTP port) and `443` (the default HTTPS
|
|
* port).
|
|
*
|
|
* @var string
|
|
* @since 0.3
|
|
*/
|
|
private $originalDomain = null;
|
|
|
|
/**
|
|
* The list of available domains.
|
|
*
|
|
* This array holds all available domains as its keys. Each item in the
|
|
* array is also an array containing the following keys:
|
|
*
|
|
* - `base`
|
|
* - `lang`
|
|
* - `protocol`
|
|
*
|
|
* @var string
|
|
*/
|
|
private $domains = [];
|
|
|
|
/**
|
|
* Indicate whether the default ports should be ingored.
|
|
*
|
|
* This check is used when redirecting from a domain to another, for
|
|
* example.
|
|
*
|
|
* @var bool
|
|
* @since 0.11.0
|
|
*/
|
|
private $ignoreDefaultPorts = false;
|
|
|
|
/**
|
|
* Indicate whether canonical link should be added to pages.
|
|
*
|
|
* @var bool
|
|
* @since 0.11.0
|
|
*/
|
|
private $addCanonical = false;
|
|
|
|
/**
|
|
* Plugin activation tasks.
|
|
*
|
|
* The required plugin options are added to WordPress. We also make sure
|
|
* this plugin is the first loaded here.
|
|
*
|
|
* @return void
|
|
* @since 0.7
|
|
*/
|
|
public static function activate()
|
|
{
|
|
add_option('multiple-domain-domains', []);
|
|
add_option('multiple-domain-ignore-default-ports', true);
|
|
add_option('multiple-domain-add-canonical', false);
|
|
|
|
self::loadFirst();
|
|
}
|
|
|
|
/**
|
|
* Update plugin loading order to load this plugin before any other plugin
|
|
* and make sure all plugins use the right domain replacements.
|
|
*
|
|
* @return void
|
|
* @since 0.8.7
|
|
*/
|
|
public static function loadFirst()
|
|
{
|
|
/*
|
|
* Relative path to this plugin. The array of active plugins has the
|
|
* plugin path as its keys. We'll use this path to move Multiple Domain
|
|
* to the first position in that array.
|
|
*/
|
|
$path = str_replace(WP_PLUGIN_DIR . '/', '', MULTIPLE_DOMAIN_PLUGIN);
|
|
$plugins = get_option('active_plugins');
|
|
|
|
if (empty($plugins)) {
|
|
return;
|
|
}
|
|
|
|
if (($key = array_search($path, $plugins))) {
|
|
array_splice($plugins, $key, 1);
|
|
array_unshift($plugins, $path);
|
|
update_option('active_plugins', $plugins);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the single plugin instance.
|
|
*
|
|
* @return \MultipleDomain The plugin instance.
|
|
* @since 0.8.4
|
|
*/
|
|
public static function instance()
|
|
{
|
|
if (!isset(self::$instance)) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Create a new instance.
|
|
*
|
|
* Adds actions and filters required by the plugin.
|
|
*/
|
|
private function __construct()
|
|
{
|
|
$this->initAttributes();
|
|
$this->hookActions();
|
|
$this->hookFilters();
|
|
$this->hookShortcodes();
|
|
|
|
new MultipleDomainSettings($this);
|
|
}
|
|
|
|
//
|
|
// WordPress API integration
|
|
//
|
|
|
|
/**
|
|
* Initialize the class attributes.
|
|
*
|
|
* @return void
|
|
* @since 0.8
|
|
*/
|
|
private function initAttributes()
|
|
{
|
|
$this->ignoreDefaultPorts = (bool) get_option('multiple-domain-ignore-default-ports');
|
|
$this->originalDomain = $this->getDomainFromUrl(get_option('home'), $this->ignoreDefaultPorts);
|
|
|
|
$this->domain = $this->getDomainFromRequest();
|
|
|
|
$domains = (array) get_option('multiple-domain-domains');
|
|
$this->resetDomains();
|
|
foreach ($domains as $domain => $options) {
|
|
$options = wp_parse_args($options, [
|
|
'base' => null,
|
|
'lang' => null,
|
|
'protocol' => null,
|
|
]);
|
|
$this->addDomain($domain, $options['base'], $options['lang'], $options['protocol']);
|
|
}
|
|
|
|
if (!array_key_exists($this->domain, $this->domains)) {
|
|
$this->domain = $this->originalDomain;
|
|
}
|
|
|
|
$this->addCanonical = (bool) get_option('multiple-domain-add-canonical');
|
|
}
|
|
|
|
/**
|
|
* Hook plugin actions to WordPress.
|
|
*
|
|
* @return void
|
|
* @since 0.8
|
|
*/
|
|
private function hookActions()
|
|
{
|
|
add_action('init', [ $this, 'redirect' ]);
|
|
add_action('wp_head', [ $this, 'addHrefLangTags' ]);
|
|
add_action('wp_head', [ $this, 'addCanonicalTag' ]);
|
|
add_action('plugins_loaded', [ $this, 'loaded' ]);
|
|
add_action('activated_plugin', [ self::class, 'loadFirst' ]);
|
|
add_action('wpseo_register_extra_replacements', [ $this, 'registerYoastVars' ]);
|
|
}
|
|
|
|
/**
|
|
* Hook plugin filters to WordPress.
|
|
*
|
|
* @return void
|
|
* @since 0.8
|
|
*/
|
|
private function hookFilters()
|
|
{
|
|
|
|
// Generic domain replacement
|
|
add_filter('content_url', [ $this, 'fixUrl' ]);
|
|
add_filter('option_siteurl', [ $this, 'fixUrl' ]);
|
|
add_filter('option_home', [ $this, 'fixUrl' ]);
|
|
add_filter('plugins_url', [ $this, 'fixUrl' ]);
|
|
add_filter('wp_get_attachment_url', [ $this, 'fixUrl' ]);
|
|
add_filter('get_the_guid', [ $this, 'fixUrl' ]);
|
|
|
|
// Specific domain replacement filters
|
|
add_filter('upload_dir', [ $this, 'fixUploadDir' ]);
|
|
add_filter('the_content', [ $this, 'fixContentUrls' ], 20);
|
|
add_filter('allowed_http_origins', [ $this, 'addAllowedOrigins' ]);
|
|
|
|
// Add body class based on domain
|
|
add_filter('body_class', [ $this, 'addDomainBodyClass' ]);
|
|
|
|
// Stop WP built in Canonical URL if this plugin has 'Add canonical links' enabled
|
|
add_filter('get_canonical_url', [ $this, 'getCanonicalUrl' ]);
|
|
}
|
|
|
|
/**
|
|
* Hook plugin shortcodes to WordPress.
|
|
*
|
|
* @return void
|
|
* @since 0.8.5
|
|
*/
|
|
private function hookShortcodes()
|
|
{
|
|
add_shortcode('multiple_domain', [ $this, 'shortcode' ]);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
/**
|
|
* Return the current domain.
|
|
*
|
|
* Since this value is checked against plugin settings, it may not reflect
|
|
* the actual current domain in `HTTP_HOST` key from global `$_SERVER` var.
|
|
*
|
|
* Depending on the plugin settings, the domain also may include the host
|
|
* port when it's different than `80` (the default HTTP port) and `443` (the
|
|
* default HTTPS port).
|
|
*
|
|
* @return string|null The domain.
|
|
* @since 0.2
|
|
*/
|
|
public function getDomain()
|
|
{
|
|
return $this->domain;
|
|
}
|
|
|
|
/**
|
|
* Return original domain set in WordPress installation.
|
|
*
|
|
* Notice this method may return an unexpected value when running the site
|
|
* using the `server` command from wp-cli. That's because wp-cli changes the
|
|
* value of `site_url` and `home_url` options through a filter.
|
|
* Unfortunately, it's not possible to change this behaviour.
|
|
*
|
|
* The domain also may include the host port when it's different than `80`
|
|
* (the default HTTP port) and `443` (the default HTTPS port).
|
|
*
|
|
* @return string The domain.
|
|
* @since 0.3
|
|
*/
|
|
public function getOriginalDomain()
|
|
{
|
|
return $this->originalDomain;
|
|
}
|
|
|
|
/**
|
|
* Return all domains available.
|
|
*
|
|
* The keys in the returned array are the domain name. Each item in the
|
|
* array is also an array containing the following keys:
|
|
*
|
|
* - `base`
|
|
* - `lang`
|
|
* - `protocol`
|
|
*
|
|
* @return array The list of domains.
|
|
* @since 0.11.0
|
|
*/
|
|
public function getDomains()
|
|
{
|
|
return $this->domains;
|
|
}
|
|
|
|
/**
|
|
* Indicate whether the default ports (`80` or `443`) should be ingored.
|
|
*
|
|
* This check is used when redirecting from a domain to another, for
|
|
* example.
|
|
*
|
|
* @return bool A boolean indicating if the default port should be ignored.
|
|
* @since 0.8.2
|
|
*/
|
|
public function shouldIgnoreDefaultPorts()
|
|
{
|
|
return $this->ignoreDefaultPorts;
|
|
}
|
|
|
|
/**
|
|
* Indicate whether the canonical tags should be added to page.
|
|
*
|
|
* @return bool A boolean indicating if the default port should be ignored.
|
|
* @since 0.11.0
|
|
*/
|
|
public function shouldAddCanonical()
|
|
{
|
|
return $this->addCanonical;
|
|
}
|
|
|
|
/**
|
|
* Get the base path associated to the given domain.
|
|
*
|
|
* If no domain is passed to the function, it'll return the base path for
|
|
* the current domain.
|
|
*
|
|
* Notice this function may return `null` when no base path is set for a
|
|
* given domain in the plugin config.
|
|
*
|
|
* @param string|null $domain The domain.
|
|
* @return string|null The base path.
|
|
* @since 0.10.3
|
|
*/
|
|
public function getDomainBase($domain = null)
|
|
{
|
|
return $this->getDomainAttribute('base', $domain);
|
|
}
|
|
|
|
/**
|
|
* Get the language associated to the given domain.
|
|
*
|
|
* If no domain is passed to the function, it'll return the language for
|
|
* the current domain.
|
|
*
|
|
* Notice this function may return `null` when no language is set for a
|
|
* given domain in the plugin config.
|
|
*
|
|
* @param string|null $domain The domain.
|
|
* @return string|null The language code.
|
|
* @since 0.8
|
|
*/
|
|
public function getDomainLang($domain = null)
|
|
{
|
|
return $this->getDomainAttribute('lang', $domain);
|
|
}
|
|
|
|
/**
|
|
* Get the protocol option for the given domain.
|
|
*
|
|
* If no domain is passed to the function, it'll return the option for the
|
|
* current domain.
|
|
*
|
|
* The possible returned values are `http`, `https`, or `auto` (default). If
|
|
* no protocol is defined for a given domain, the default value will be
|
|
* returned.
|
|
*
|
|
* @param string|null $domain The domain.
|
|
* @return string The protocol option.
|
|
* @since 0.10.0
|
|
*/
|
|
public function getDomainProtocol($domain = null)
|
|
{
|
|
$protocol = $this->getDomainAttribute('protocol', $domain);
|
|
return in_array($protocol, [ 'http', 'https' ]) ? $protocol : 'auto';
|
|
}
|
|
|
|
/**
|
|
* Reset the list of domains.
|
|
*
|
|
* In case the `$keepOriginal` param is `true`, which is the default, the
|
|
* list of domains will have only the original domain where WordPress was
|
|
* installed.
|
|
*
|
|
* @param bool $keepOriginal Indicates whether the original domain should
|
|
* be kept.
|
|
* @return void
|
|
* @since 1.0.0
|
|
*/
|
|
public function resetDomains($keepOriginal = true)
|
|
{
|
|
if (!$keepOriginal || empty($this->originalDomain)) {
|
|
$this->domains = [];
|
|
return;
|
|
}
|
|
|
|
$this->domains = [
|
|
$this->originalDomain => [
|
|
'base' => null,
|
|
'lang' => null,
|
|
'protocol' => 'auto',
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Add a new domain to the list of domains.
|
|
*
|
|
* Besides the `$domain` param, all other are optional.
|
|
*
|
|
* @param string $domain The domain.
|
|
* @param string $base The base path.
|
|
* @param string $lang The language.
|
|
* @param string $protocol The protocol option. It can be `http`, `https`
|
|
* or `auto`.
|
|
* @return void
|
|
* @since 1.0.0
|
|
*/
|
|
public function addDomain($domain, $base = null, $lang = null, $protocol = 'auto')
|
|
{
|
|
$this->domains[$domain] = [
|
|
'base' => $base,
|
|
'lang' => $lang,
|
|
'protocol' => $protocol,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Store the current list of domains in the WordPress options.
|
|
*
|
|
* This is can be used to persist changes made to the list of domains with
|
|
* `resetDomains` and `addDomain` methods.
|
|
*
|
|
* @return void
|
|
* @since 1.0.0
|
|
*/
|
|
public function storeDomains()
|
|
{
|
|
update_option('multiple-domain-domains', $this->domains);
|
|
}
|
|
|
|
/**
|
|
* When the current domain has a base URL restriction and the current
|
|
* request URI doesn't match it, redirects the user.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function redirect()
|
|
{
|
|
/*
|
|
* Allow developers to create their own logic for redirection.
|
|
*/
|
|
do_action('multiple_domain_redirect', $this->domain);
|
|
|
|
$base = $this->getDomainBase();
|
|
$uri = !empty($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : null;
|
|
|
|
$base = ltrim($base, '/');
|
|
$uri = ltrim($uri, '/');
|
|
|
|
if (empty($base) || preg_match('/^wp-[a-z]+(\.php|\/|$)/i', $uri)) {
|
|
return;
|
|
}
|
|
|
|
if (strpos($uri, $base) !== 0) {
|
|
wp_redirect(home_url('/' . $base));
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Replaces the domain in the given URL.
|
|
*
|
|
* The domain in the given URL is replaced with the current domain. If the
|
|
* URL contains `/wp-admin/` it'll be ignored when replacing the domain and
|
|
* returned as is.
|
|
*
|
|
* @param string $url The URL to fix.
|
|
* @return string The domain replaced URL.
|
|
* @since 0.10.0
|
|
*/
|
|
public function fixUrl($url)
|
|
{
|
|
if (!preg_match('/\/wp-admin\/?/', $url)) {
|
|
$domain = $this->getDomainFromUrl($url);
|
|
$url = $this->replaceDomain($domain, $url);
|
|
}
|
|
return $url;
|
|
}
|
|
|
|
/**
|
|
* Replaces the domain in `upload_dir` filter used by `wp_upload_dir()`.
|
|
*
|
|
* The domain in the given `url` and `baseurl` is replaced by the current
|
|
* domain.
|
|
*
|
|
* @param array $uploads The array of `url`, `baseurl` and other
|
|
* properties.
|
|
* @return array The domain-replaced values.
|
|
* @since 0.4
|
|
*/
|
|
public function fixUploadDir($uploads)
|
|
{
|
|
$uploads['url'] = $this->fixUrl($uploads['url']);
|
|
$uploads['baseurl'] = $this->fixUrl($uploads['baseurl']);
|
|
return $uploads;
|
|
}
|
|
|
|
/**
|
|
* Replaces the domain in post content.
|
|
*
|
|
* All occurrences of any of the available domains (i.e. all domains set in
|
|
* the plugin config) will be replaced with the current domain.
|
|
*
|
|
* @param string $content The content to fix.
|
|
* @return string The domain replaced content.
|
|
* @since 0.8
|
|
*/
|
|
public function fixContentUrls($content)
|
|
{
|
|
foreach (array_keys($this->domains) as $domain) {
|
|
$content = $this->replaceDomain($domain, $content);
|
|
}
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Add all available domains to allowed origins.
|
|
*
|
|
* This filter is used to prevent CORS issues.
|
|
*
|
|
* @param array $origins The default list of allowed origins.
|
|
* @return array The updated list of allowed origins.
|
|
* @since 0.8
|
|
*/
|
|
public function addAllowedOrigins($origins)
|
|
{
|
|
foreach (array_keys($this->domains) as $domain) {
|
|
$origins[] = 'https://' . $domain;
|
|
$origins[] = 'http://' . $domain;
|
|
}
|
|
return array_values(array_unique($origins));
|
|
}
|
|
|
|
/**
|
|
* Add the current domain to the body class in a sanitized version.
|
|
*
|
|
* If the current domain is `example.com`, the class added to the page body
|
|
* will be `multiple-domain-example-com`. Notice this filter only has effect
|
|
* when the `body_class()` function is added to the page's `<body> tag`.
|
|
*
|
|
* @param array $classes The initial list of body class names.
|
|
* @return array Updated list of body class names.
|
|
* @since 0.9.0
|
|
*/
|
|
public function addDomainBodyClass($classes)
|
|
{
|
|
$classes[] = 'multiple-domain-' . preg_replace('/[^a-z0-9]+/i', '-', $this->domain);
|
|
return $classes;
|
|
}
|
|
|
|
/**
|
|
* Add `hreflang` links to head for SEO purpose.
|
|
*
|
|
* @return void
|
|
* @author Alexander Nosov <https://github.com/cyberaleks>
|
|
* @since 0.4
|
|
*/
|
|
public function addHrefLangTags()
|
|
{
|
|
/**
|
|
* The WP class instance.
|
|
*
|
|
* @var WP
|
|
*/
|
|
global $wp;
|
|
|
|
$uri = trailingslashit('/' . ltrim(add_query_arg([], $wp->request), '/'));
|
|
$currentProtocol = $this->getCurrentProtocol();
|
|
|
|
foreach (array_keys($this->domains) as $domain) {
|
|
$protocol = $this->getDomainProtocol($domain);
|
|
if ($protocol === 'auto') {
|
|
$protocol = $currentProtocol;
|
|
}
|
|
$protocol .= '://';
|
|
|
|
$lang = $this->getDomainLang($domain);
|
|
|
|
if (!empty($lang)) {
|
|
$this->outputHrefLangTag($protocol . $domain . $uri, $lang);
|
|
}
|
|
|
|
if ($domain === $this->originalDomain) {
|
|
$this->outputHrefLangTag($protocol . $domain . $uri);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add `canonical` links to head for SEO purpose.
|
|
*
|
|
* @return void
|
|
* @since 0.11.0
|
|
*/
|
|
public function addCanonicalTag()
|
|
{
|
|
if (!$this->shouldAddCanonical()) {
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* The WP class instance.
|
|
*
|
|
* @var WP
|
|
*/
|
|
global $wp;
|
|
|
|
$uri = home_url(add_query_arg([], $wp->request), 'relative') . '/';
|
|
$currentProtocol = $this->getCurrentProtocol();
|
|
|
|
$protocol = $this->getDomainProtocol($this->originalDomain);
|
|
if ($protocol === 'auto') {
|
|
$protocol = $currentProtocol;
|
|
}
|
|
$protocol .= '://';
|
|
|
|
$this->outputCanonicalTag($protocol . $this->originalDomain . $uri);
|
|
}
|
|
|
|
/**
|
|
* This shortcode simply returns the current domain.
|
|
*
|
|
* @return string The current domain.
|
|
* @since 0.8.5
|
|
*/
|
|
public function shortcode()
|
|
{
|
|
return $this->domain;
|
|
}
|
|
|
|
/**
|
|
* Load text domain when plugin is loaded.
|
|
*
|
|
* @return void
|
|
* @since 0.8.6
|
|
*/
|
|
public function loaded()
|
|
{
|
|
$path = dirname(plugin_basename(MULTIPLE_DOMAIN_PLUGIN)) . '/languages/';
|
|
load_plugin_textdomain('multiple-domain', false, $path);
|
|
}
|
|
|
|
/**
|
|
* Register vars to be used as text replacements in Yoast tags.
|
|
*
|
|
* @return void
|
|
* @since 0.11.0
|
|
*/
|
|
public function registerYoastVars()
|
|
{
|
|
wpseo_register_var_replacement(
|
|
'%%multiple_domain%%',
|
|
[ $this, 'getDomain' ],
|
|
'advanced',
|
|
__('The current domain from Multiple Domain', 'multiple-domain')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get the current domain via request headers parsing.
|
|
*
|
|
* @return string|null The current domain.
|
|
* @since 0.8.7
|
|
*/
|
|
private function getDomainFromRequest()
|
|
{
|
|
$domain = $this->getHostHeader();
|
|
|
|
if (empty($domain)) {
|
|
return null;
|
|
}
|
|
|
|
$matches = [];
|
|
if (preg_match('/^(.*):(\d+)$/', $domain, $matches) && $this->isDefaultPort($matches[2])) {
|
|
$domain = $matches[1];
|
|
}
|
|
return $domain;
|
|
}
|
|
|
|
/**
|
|
* Get the `Host` HTTP header value.
|
|
*
|
|
* To make it compatible with proxies, this function first tries to get the
|
|
* value from `X-Host` header and, then, falls back to the regular `Host`
|
|
* header.
|
|
*
|
|
* It returns `null` in case both headers are empty.
|
|
*
|
|
* @return string|null The HTTP `Host` header value.
|
|
* @since 0.8.7
|
|
*/
|
|
private function getHostHeader()
|
|
{
|
|
if (!empty($_SERVER['HTTP_X_HOST'])) {
|
|
return $_SERVER['HTTP_X_HOST'];
|
|
}
|
|
|
|
if (!empty($_SERVER['HTTP_HOST'])) {
|
|
return $_SERVER['HTTP_HOST'];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get the current URL protocol based on server settings.
|
|
*
|
|
* The possible returned values are `http` and `https`.
|
|
*
|
|
* @return string The protocol.
|
|
*/
|
|
private function getCurrentProtocol()
|
|
{
|
|
return empty($_SERVER['HTTPS']) || $_SERVER['HTTPS'] === 'off' ? 'http' : 'https';
|
|
}
|
|
|
|
/**
|
|
* Get an attribute by its name for the given domain.
|
|
*
|
|
* If no domain is passed to the function, it'll return the attribute value
|
|
* for the current domain.
|
|
*
|
|
* Notice this function may return `null` when the attribute is not set in
|
|
* the plugin config or doesn't exist.
|
|
*
|
|
* @param string $name The attribute name.
|
|
* @param string|null $domain The domain.
|
|
* @return string The attribute value.
|
|
* @since 0.10.0
|
|
*/
|
|
private function getDomainAttribute($name, $domain = null)
|
|
{
|
|
if (empty($domain)) {
|
|
$domain = $this->domain;
|
|
}
|
|
$attribute = null;
|
|
if (!empty($this->domains[$domain][$name])) {
|
|
$attribute = $this->domains[$domain][$name];
|
|
}
|
|
return $attribute;
|
|
}
|
|
|
|
/**
|
|
* Replaces the domain.
|
|
*
|
|
* All occurrences of the given domain will be replaced with the current
|
|
* domain in the content.
|
|
*
|
|
* The protocol may also be replaced following the protocol settings defined
|
|
* in the plugin config for the current domain.
|
|
*
|
|
* @param string $domain The domain to replace.
|
|
* @param string $content The content that will have the domain replaced.
|
|
* @return string The domain-replaced content.
|
|
*/
|
|
private function replaceDomain($domain, $content)
|
|
{
|
|
if (MULTIPLE_DOMAIN_LOW_MEMORY) {
|
|
return $this->replaceDomainUsingLessMemory($domain, $content);
|
|
}
|
|
if (array_key_exists($domain, $this->domains)) {
|
|
$regex = '/(https?):\/\/' . preg_quote($domain, '/') . '(?![a-z0-9.\-:])/i';
|
|
$protocol = $this->getDomainProtocol($this->domain);
|
|
$replace = ($protocol === 'auto' ? '${1}' : $protocol) . '://' . $this->domain;
|
|
$content = preg_replace($regex, $replace, $content);
|
|
}
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Replaces the domain using less memory.
|
|
*
|
|
* This function does the same as `replaceDoamin`, however it uses
|
|
* `mb_eregi_replace` instead of `preg_replace` for less memory consumption.
|
|
* On the other hand, it takes more time to execute.
|
|
*
|
|
* @param string $domain The domain to replace.
|
|
* @param string $content The content that will have the domain replaced.
|
|
* @return string The domain-replaced content.
|
|
* @since 1.0.2
|
|
*/
|
|
private function replaceDomainUsingLessMemory($domain, $content)
|
|
{
|
|
if (array_key_exists($domain, $this->domains)) {
|
|
$regex = '(https?):\/\/' . preg_quote($domain, '/') . '(?![a-z0-9.\-:])';
|
|
$protocol = $this->getDomainProtocol($this->domain);
|
|
$replace = ($protocol === 'auto' ? '\\1' : $protocol) . '://' . $this->domain;
|
|
$content = mb_eregi_replace($regex, $replace, $content);
|
|
}
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Parses the given URL to return only its domain.
|
|
*
|
|
* The server port may be included in the returning value depending on its
|
|
* number and plugin settings.
|
|
*
|
|
* @param string $url The URL to parse.
|
|
* @param bool $ignoreDefaultPorts If `true` is passed to this value, a
|
|
* default HTTP or HTTPS port will be ignored even if it's present
|
|
* in the URL.
|
|
* @return string The domain.
|
|
* @since 0.2
|
|
*/
|
|
private function getDomainFromUrl($url, $ignoreDefaultPorts = false)
|
|
{
|
|
$parts = parse_url($url);
|
|
$domain = $parts['host'];
|
|
if (!empty($parts['port']) && !($ignoreDefaultPorts && $this->isDefaultPort($parts['port']))) {
|
|
$domain .= ':' . $parts['port'];
|
|
}
|
|
return $domain;
|
|
}
|
|
|
|
/**
|
|
* Checks if the given port is a default HTTP (`80`) or HTTPS (`443`) port.
|
|
*
|
|
* @param int $port The port to check.
|
|
* @return bool Indicates if the port is a default one.
|
|
* @since 0.2
|
|
*/
|
|
private function isDefaultPort($port)
|
|
{
|
|
$port = (int) $port;
|
|
return $port === self::PORT_HTTP || $port === self::PORT_HTTPS;
|
|
}
|
|
|
|
/**
|
|
* Prints a `hreflang` link tag.
|
|
*
|
|
* @param string $url The URL to be set into `href` attribute.
|
|
* @param string $lang The language code to be set into `hreflang`
|
|
* attribute. Defaults to `x-default`.
|
|
* @return void
|
|
* @since 0.5
|
|
*/
|
|
private function outputHrefLangTag($url, $lang = 'x-default')
|
|
{
|
|
$url = htmlentities($url);
|
|
$lang = str_replace('_', '-', $lang);
|
|
printf('<link rel="alternate" href="%s" hreflang="%s" />', $url, $lang);
|
|
}
|
|
|
|
/**
|
|
* Prints a `canonical` link tag.
|
|
*
|
|
* @param string $url The canonical URL to be set into `href` attribute.
|
|
* @return void
|
|
* @since 0.11.0
|
|
*/
|
|
private function outputCanonicalTag($url)
|
|
{
|
|
$url = htmlentities($url);
|
|
printf('<link rel="canonical" href="%s" />', $url);
|
|
}
|
|
|
|
/**
|
|
* Filter override WordPress built-in canonical tag generation if using the this plugin's canonical tag feature
|
|
*
|
|
* @param $url
|
|
* @return string
|
|
*/
|
|
public function getCanonicalUrl($url)
|
|
{
|
|
// If *not* using the plugin's canonical tags, then return this URL. Otherwise, don't
|
|
if (!$this->shouldAddCanonical()) {
|
|
return $url;
|
|
}
|
|
return '';
|
|
}
|
|
}
|