WordPress.org

Make WordPress Core

Opened 13 months ago

Last modified 13 months ago

#50100 new defect (bug)

Native domain mapping does not handle both WWW and non-WWW versions of a domain - both should work

Reported by: jodamo5 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 5.4.1
Component: Networks and Sites Keywords: needs-testing
Focuses: multisite Cc:

Description

The native domain mapping only works for the exact domain entered, and does not automatically redirect www to non-www (if a non-www was entered) or non-www to www (if a www domain was entered).

Examples

Example – “WWW” Mapped Domain:

  • Multisite core domain: xyz.com
  • Subsite original address: abc.xyz.com
  • Subsite once mapped: www.abc.com

What happens:

  • Visiting www.abc.com shows the site (as expected)
  • Visiting abc.com does not show the site – it instead shows the multisite registration page – xyz.com/wp-signup.php?new=abc.com

What I expected to happen:

Visiting abc.com should automatically redirect to www.abc.com because that is the mapped domain

Alternative Example – non-WWW Mapped Domain:

  • Multisite core domain: xyz.com
  • Subsite original address: abc.xyz.com
  • Subsite once mapped: abc.com

What happens:

  • Visiting abc.com shows the site (as expected)
  • Visiting www.abc.com does not show the site – it instead shows the multisite registration page – xyz.com/wp-signup.php?new=www.abc.com

What I expected to happen:

Visiting www.abc.com should automatically redirect to abc.com because that is the mapped domain.

Possible Arguments

Technical Arguments vs Human Experience

One technical argument presented for this is that abc.com and www.abc.com are two distinct domain entities. Just like images.google.com and fonts.google.com are two distinct domain entities. While this argument is technically correct it is not correct practically as it ignores best practice and the human-user element of how websites have worked for 20 years.

While "www.google.com" and "google.com" are two technically different domains, in reality no website owner should ever point these to two different sites! It would be ridiculous to do so.

So while other subdomain entries do not need to be allowed for, there should be an automatic allowance for "www" and the root domain to automatically redirect between each other based on whether the mapped domain was entered with www or not.

Should This Be Core?

A key question with every enhancement request is whether or not something should actually be part of WordPress core, or be left to a plugin.

The official domain mapping documentation states:

Before WordPress 4.5, domain mapping requires a domain mapping plugin like WordPress MU Domain Mapping.
In WordPress 4.5+, domain mapping is a native feature.

So the official recommendation is that core can take care of the domain mapping on multisite installations.

However, there is no mention anywhere on the page that this native domain mapping will not work for the standard behaviour of automatically handling both the www and root versions of the domain. Since this is the way all websites normally work, if it was the intentional behaviour it seems to be a glaring omission from the documentation.

I reason that WordPress multisite users would not expect to map abc.com and have www.abc.com fail to load the site, and instead get redirected to the multisite registration page.

Possible Solutions

Could it be solved through htaccess rules?

When setting up a multisite the steps include changing the contents in the htaccess file.

Redirecting between www and root for domains can be done at an htaccess level, so could a clever htaccess rule be written to handle this for all mapped domains that get added to the site?

If this approach was to be used, it would need to handle a wide variety of scenarios:

  • It would need to exclude the core multisite domain and all its sub-domains from being affected. (Only mapped domains should be affected)
  • Having a blanket "redirect root to www" for all subdomains, or vice versa is not ideal. Some mapped domains might specifically want to be shown with www or without www. A blanket htaccess rule wouldn't know whether the user mapped a www or root domain.

So I don't think setting a blanket rule from .htaccess is a good solution.

PHP Redirect

I believe the solution needs to be PHP specific. The redirection should apply to mapped domains only, and should assess whether the mapped domain begins with "www." or not. If not, then WordPress should redirect www traffic for that domain to the root version of that domain. If it does begin with "www." then traffic seeking the root domain should be automatically redirected to the www domain.

Related Tickets

#48197 Add support for assigning multiple domains to a single site in multisite

Ticket 48197 is asking for much more than this ticket of mine is suggesting. While it could be used to solve this problem, it is functionality that extends beyond where core WordPress needs to serve. It is more of a nice-to-have that can be served by plugins. Therefore, although it is related, I see ticket 48197 as having less valid arguments for being included in core, which is why this posted as a separate ticket.

Summary

The current domain mapping that is built into core has this enormous problem in usability. Site owners would not expect their site to work for "www.abc.com" but send visitors who entered "abc.com" to a registration page for the multisite. This is a bad user experience.

When using multisite native domain mapping, WordPress should automatically account for www and non-www and redirect between the two, depending on whether the domain entered started with www or not.

Change History (7)

#1 follow-up: @jonoaldersonwp
13 months ago

From an SEO perspective, redirecting to the mapped domain (via a 301 HTTP header) is definitely the preferred behaviour. We can't really claim to be "SEO friendly" with such a rudimentary omission as URL/domain consolidation.

However, I suggest that we wrap this into https://developer.wordpress.org/reference/functions/redirect_canonical/ to avoid being greedy in (edge) cases where not redirecting is the preferred behaviour.

#2 in reply to: ↑ 1 @jodamo5
13 months ago

Thanks @jonoaldersonwp.

I'm new to logging issues here, so when you say...

However, I suggest that we wrap this into https://developer.wordpress.org/reference/functions/redirect_canonical/ to avoid being greedy in (edge) cases where not redirecting is the preferred behaviour.

...how specifically do we do that?

Are you saying that this issue should be assigned to to the developers who deal with that section of core? Keen for your guidance about how to proceed.

#3 @jonoaldersonwp
13 months ago

https://developer.wordpress.org/reference/functions/redirect_canonical/ describes functionality which already exists, which attempts to redirect requests to URLs to the 'correct' version of that URL. That prevents some duplication issue, catches some 404s, etc.

I'm suggesting that we integrate a 'check that this is the correct mapped domain' check into those existing processes, so that it can be turned on/off or modified using behaviours and hooks which already exist (and that, for sites which have disabled redirect_canonical, nothing will change).

Note that redirect_canonical is turned on by default, and remains enabled unless specifically disabled by plugin/theme authors.

#4 @jeremyfelt
13 months ago

  • Keywords needs-testing added
  • Type changed from enhancement to defect (bug)

Hi @jodamo5, thanks for opening a ticket.

Some of my memories around this are a little fuzzy, but treating www.domain.com and domain.com as the same is effectively what WordPress does when it can and I think has helped avoid confusion overall.

From wp-includes/ms-load.php (code on GitHub):

// Either www or non-www is supported, not both. If a www domain is requested,
// query for both to provide the proper redirect.
$domains = array( $domain );
if ( 'www.' === substr( $domain, 0, 4 ) ) {
	$domains[] = substr( $domain, 4 );
}

I'm not sure why the WP support documentation mentions native domain mapping. I think that article needs to be updated with a bit more context as WordPress does not have native ability to map multiple domains to a single domain. The preferred term for what WordPress does provide support for is arbitrary domains.

It used to be more difficult to use arbitrary domains in WordPress, which is one of the reasons that people would install a domain mapping plugin. Not to map multiple domains to one, but to support different full domains in general. In WordPress 4.5 (or earlier?), we improved support for arbitrary domains. This means that example.com and unrelatedexample.com will have an easier time on the same network. Telling WordPress to load example.com when unrelatedexample.com is requested is still something a plugin must handle.

That all said.

Based on the logic from ms-load.php above, I would expect your second example to work. If abc.com exists in wp_blogs as a site's domain and a request to www.abc.com is received and get_site_by_path() is fired, then it should find abc.com and redirect accordingly. If this is not working, there may be a bug to track down.

I would not expect the first example to work as that would involve always adding www to queries for bare domains. (I think our recommendation in the past has been to try and avoid www on sites, but that could definitely be wrong?)

In general, while the first example should work, and we should look at fixing any related bug, I would always encourage anyone to handle these redirects at the web server level rather than in WordPress as it removes the need for WordPress to handle the unnecessary query and redirect.

#5 @jodamo5
13 months ago

Thanks @jeremyfelt

To clarify, the WP domain mapping documentation does not state that multiple domains can be mapped. So the documentation is correct, however it fails to mention the enormous problem of not handling both www and non-www within the native domain mapping setup.

However, to update the ticket, I have investigated further, and found that the code you mentioned does indeed work. So my second example was incorrect.

To confirm, if the domain is mapped without www e.g. abc.com then if a visitor types www.abc.com the domain mapping automatically finds and swaps them to abc.com. So that is good.

However, the other half of the problem still exists. It is a huge usability issue that when a domain is mapped as www. the bare domain does not redirect to the site, but instead shows a multisite registration page.

Redirecting a bare domain to www, if the www version is mapped, is standard practise across all other domain mapping plugins - and the documentation says we no longer need to use these other plugins since domain mapping is now native.

I strongly expect WordPress multisite users who map www.abc.com as their domain would be shocked and frustrated when abc.com does not redirect to their site and instead takes users to the registration page. I know that was my experience.

Thanks very much for pointing to the right place in the code. It was exactly the right section for handling this problem.

I would like to propose that, to solve this usability problem, we simply add "www." to queries for bare domains, so that both www and non-www domains are checked. The code in ms-load.php already handles building the array of two domains and checking if either matches an existing site, so it would only be a small change that would greatly improve the usability. It would mean that every domain array has two domains - a www and non-www version.

Proposed Change

Existing Code

        // Either www or non-www is supported, not both. If a www domain is requested,
	// query for both to provide the proper redirect.
	$domains = array( $domain );
	if ( 'www.' === substr( $domain, 0, 4 ) ) {
		$domains[] = substr( $domain, 4 );
	}

	$args = array(
		'number'                 => 1,
		'update_site_meta_cache' => false,
	);

	if ( count( $domains ) > 1 ) {
		$args['domain__in']               = $domains;
		$args['orderby']['domain_length'] = 'DESC';
	} else {
		$args['domain'] = array_shift( $domains );
	}

Proposed New Code

	// Whether a www or non-www domain is requested,
	// query for both to provide the proper redirect.
	$domains = array( $domain );
	if ( 'www.' === substr( $domain, 0, 4 ) ) {
		$domains[] = substr( $domain, 4 );
	} else {
		$domains[] = 'www.'. $domain;
	}

	$args = array(
		'number'                 	   => 1,
		'update_site_meta_cache' 	   => false,
		'domain__in'             	   => $domains,
		'orderby' => array('domain_length' => 'DESC')
	);

I have tested this within a multisite environment, and it produces the exact same array that was previously produced when a www. domain was requested. It now produces that array whether a www or non-www domain is requested. So the code works well. (It will of course need thorough testing.)

I can set this up as a pull request, but first wanted to get feedback about it.

I expect this would a barely measurable performance impact, while greatly improving the usability of domain mapping. What are your thoughts on this enhancement?

#6 @jonoaldersonwp
13 months ago

I strongly expect WordPress multisite users who map www.abc.com as their domain would be shocked and frustrated when abc.com does not redirect to their site and instead takes users to the registration page. I know that was my experience.

Yep, not to mention the massive SEO, usability, security and performance implications.

#7 @jodamo5
13 months ago

Thanks @jonoaldersonwp.

@jeremyfelt will you also support this change if I create the pull request? Keen for your feedback.

Note: See TracTickets for help on using tickets.