Make WordPress Core

Opened 12 years ago

Closed 5 weeks ago

#23221 closed defect (bug) (worksforme)

Multisite in subdirectory with root site address

Reported by: grapplerulrich's profile grapplerulrich Owned by:
Milestone: Priority: normal
Severity: normal Version: 3.5
Component: Bootstrap/Load Keywords: dev-feedback close
Focuses: multisite Cc:

Description

I have seem to have found a url bug in the multisite.

How to replicate

  1. Install WordPress in a subdirectory
  2. Change the the url from the subdirectory to the root by adding index.php to the the root and changing the following code.
    /** Loads the WordPress Environment and Template */
    require('./subdirectory/wp-blog-header.php');
    
  3. Change the site url in the settings to the root.
  4. Start the process to convert the site to a multisite.

Affect

Then it should cause the network dashboard url to be incorrect. You will get http://example.com/wp-admin/network/ instead of
http://example.com/subdirectory/wp-admin/network/.

Attachments (2)

23221.diff (609 bytes) - added by markoheijnen 12 years ago.
Replace build url with site_url()
23221.2.diff (637 bytes) - added by markoheijnen 12 years ago.
Should not have used site_url for this

Download all attachments as: .zip

Change History (44)

#1 @alexvorn2
12 years ago

  • Cc alexvornoffice@… added

#3 @odisant
12 years ago

Problem seems to be in network_site_url() in link-template.php. Changing line 2112 from:

$url = set_url_scheme( 'http://' . $current_site->domain . $current_site->path, $scheme );

to:

$url = set_url_scheme( trailingslashit(site_url()), $scheme );

Seems to resolve the problem.

@markoheijnen
12 years ago

Replace build url with site_url()

#4 @markoheijnen
12 years ago

  • Milestone changed from Awaiting Review to 3.6

Added a patch to solve the problem with the help of site_url what odisant mentioned. Would love to see this in 3.6.

#5 @markoheijnen
12 years ago

  • Keywords has-patch added; needs-patch removed

@markoheijnen
12 years ago

Should not have used site_url for this

#6 @markoheijnen
12 years ago

Added a patch that does work. I don't think get_site_option() will cost a performance penalty since it does get cached.

#7 @markoheijnen
12 years ago

  • Keywords has-patch removed
  • Milestone 3.6 deleted
  • Resolution set to invalid
  • Status changed from new to closed

Closing as invalid. Reason is that the path isn't correctly set.

So check the following

  • PATH_CURRENT_SITE is something like /wp/
  • All rows of wp_blogs don't have the path like /wp/
  • Path of the site in wp_site
  • siteurl in wp_sitemeta
  • siteurl of the single site in wp_options of wp_x_options

#8 @nacin
11 years ago

  • Resolution invalid deleted
  • Status changed from closed to reopened

The path is set correctly. This isn't invalid, rather, this is by design. The root site uses /wordpress for siteurl, but a network requires URL rewriting, and in that context we are able to simply rewrite the subdirectory out of all subsequent sites (and the network admin).

#9 @SergeyBiryukov
11 years ago

  • Milestone set to Awaiting Review

#10 @SergeyBiryukov
11 years ago

#24382 was marked as a duplicate.

#11 @creativeinfusion
11 years ago

Sorry about the duplicate, I thought this ticket was just a misconfiguration of a straight MS subdirectory install where the home directory was the subdirectory.

There's definately a good case for tidy URLs, but we're left with no function that can be relied on to tell us the actual URL to the site install. Even using site_url(BLOG_ID_CURRENT_SITE) may not work - see Nacin's point in comment:78:ticket:19796

Having network_site_url() & network_home_url() return the same value when the underlying subdir network install isn't actually like that is certainly odd. Until it was possible to install a sub directory MS in its own directory it delivered expected results all the time. Expressing that install difference is what I thought the different functions were for (mirroring site_url and home_url on single site).

#12 @markoheijnen
11 years ago

I was sure that was the case since I tested it out and with setting all table fields correctly I could solve this issue. But it was strange that I had to do that manually if it was needed at all.

#13 @creativeinfusion
11 years ago

For a sub directory install PATH_CURRENT_SITE will be set as you noted, but for a sub directory install where WordPress is given its own directory and the site operates from document root, PATH_CURRENT_SITE is not set.

PATH_CURRENT_SITE is equivilent to the path component of home_url on a single site install.

#14 @andre.langer
11 years ago

sorry, I am a little bit confused now.
Is there already a working, proper solution or patch for the mentioned issue in WordPress 3.5.1?

I have just done a clean install of Wordpress in an own directory different from the root directory and enabled Multisite (subdirectory) behavior. I can also not access the network administrator dashboard because the generated admin URL does not contain the mainsite subdirectory before wp_admin, which redirects me back to the frontend site of the original Wordpress installation giving a 404 for wp_admin/network.
It is not only related to the wp-admin rewrite process, I also cannot access the frontend of a created multisite, the generated URL regularly points to http://domain.com/multisitesubdirectory. Do I maybe have to declare the wordpress subdir also when creating a new multisite (in comparison to the administration of wordpress url vs site url).

The network wizard generated a config template with PATH_CURRENT_SITE set to "/".
Some people suggested to edit wp-includes/link-template.php func network_admin_url(),
but this is said to be an inappropriate solution in this thread. Currently, I am still not entirely sure if it is a user configuration error, or if the combination of wordpress subdirectory installation and multisite subdirectory configuration is cleanly supported in Wordpress 3.5.

Last edited 11 years ago by andre.langer (previous) (diff)

#15 @creativeinfusion
11 years ago

I have several installations using WordPress Multisite 3.5.1 (subdirectory) with WordPress in it's own directory and it does work fine. There's no need to edit any core code.

You do have to make the advised changes to your .htaccess (or web.config if on IIS) as per your sites the network install page instructions, or it can't work. See also http://codex.wordpress.org/Multisite_Network_Administration#.htaccess_and_Mod_Rewrite

The only issue is if you use custom content/plugin directories, then you'll need to make custom rewrite rules.

Last edited 11 years ago by creativeinfusion (previous) (diff)

#16 @jeremyfelt
11 years ago

  • Component changed from Multisite to Bootstrap/Load
  • Focuses multisite added

#17 @Denis-de-Bernardy
11 years ago

  • Keywords dev-feedback added

@Nacin or other core dev: Any traction to fix this in 3.9? I'm working on a BuddyPress site which I'd like to install using this setup. A cursory look into what's wrong atm suggests me that I can get most or all of the problems fixed using a plugin, but we might as well check this into Core if there's some traction from code devs.

#18 @Denis-de-Bernardy
11 years ago

For reference, besides the installer (which creates incorrect URIs on the initial site that then need fixing in the database), the fix seems to be the following with a site installed in /wp and wp content residing in /content:

wp-config:

define('WP_CONTENT_DIR', __DIR__ . '/content');
define('WP_CONTENT_URL', 'http://www.example.com/content');

define('WP_ALLOW_MULTISITE',    true);

define('MULTISITE',             true);
define('SUBDOMAIN_INSTALL',     false);
define('DOMAIN_CURRENT_SITE',   'www.example.com');
define('PATH_CURRENT_SITE',     '/');
define('SITE_ID_CURRENT_SITE',  1);
define('BLOG_ID_CURRENT_SITE',  1);

.htaccess:

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]

# add a trailing slash to /wp-admin
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(content/.*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) wp/$2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ wp/$2 [L]
RewriteRule . index.php [L]

content/mu-plugins/ms-fixes.php:

<?php
register_theme_directory(ABSPATH . 'wp-content/themes/');

add_filter('network_site_url', function($url, $path, $scheme) {
    return str_replace(
        '//www.example.com/wp-admin/network/',
        '//www.example.com/wp/wp-admin/network/',
        $url);
}, 10, 3);

WP insists on making the original site's admin area live in /wp/ and I'm actually fine with that. I'll post updates and patches in here if I find more issues/fixes if the ticket gets blessed by a core dev.

Last edited 11 years ago by Denis-de-Bernardy (previous) (diff)

#19 follow-ups: @nacin
11 years ago

We added WP-in-subdirectory support to multisite in 3.5. It doesn't actually put /wp/ in URLs, though. Rather, since we require URL rewriting for multisite, we simply rewrite the /wp/ out of those URLs. Thus, nothing changes and it's still /wp-admin/network/ etc. If we have to rewrite the heck out of those URLs anyway, we might as well also rewrite out the subdirectory.

If you have a single site with home != siteurl and try to promote it to a multisite, this should 'just work.' You should be given the right .htaccess rules and everything should be good.

If you wish to keep /wp/, you'll need a filter and changes to your .htaccess. I don't think we need to support that out of the box.

#20 in reply to: ↑ 19 @Denis-de-Bernardy
11 years ago

Replying to nacin:

Thus, nothing changes and it's still /wp-admin/network/ etc.

That one returned an internal server error, though I admittedly didn't check if it still did after editing the rewrite rules.

If you have a single site with home != siteurl and try to promote it to a multisite, this should 'just work.'

It doesn't. It sets some entries in wp_site and wp_blogs or wp_options to the /wp/ url; I had to edit the database to make it work. Or it might be that it hadn't, and I edited them before changing the rewrite rules, and then it eventually did.

Uploads didn't work out of the box for the same reason (they do now, admittedly)

If you wish to keep /wp/, you'll need a filter and changes to your .htaccess. I don't think we need to support that out of the box.

Your call.

Last edited 11 years ago by Denis-de-Bernardy (previous) (diff)

#21 @Denis-de-Bernardy
11 years ago

Upon investigating this further:

The rewrite rules that WP generates, and the entries in wp_site and wp_blogs, are all correct provided that #26969 gets fixed.

Using a custom content folder works fine provided #24143 gets fixed. It then worked with WP_CONTENT_DIR set to wp-content and content.

There *is* potential for a very minor and mildly related issue when a theme with an identical slug lives in /wp-content/themes/foo and /wp/wp-content/themes/foo, with the latter active (it'll then load files from the former). This is assuming WP allows either to be active (I haven't tested for this).

There's potential for a last tweak related to the main site's wp-admin area: before the network setup, the siteurl is set to http://example.com/wp. It should ideally get changed to http://example.com during the network setup. Needs dev feedback here.

Version 0, edited 11 years ago by Denis-de-Bernardy (next)

#22 @Denis-de-Bernardy
11 years ago

Another related plugin is: #17376.

This ticket was mentioned in IRC in #wordpress-dev by ddebernardy. View the logs.


11 years ago

#24 @Denis-de-Bernardy
11 years ago

There actually also are issues with uploads. See #25650 for instance. And trying to place the uploads folder anywhere but in WP_CONTENT_DIR . '/uploads' borders on the impossible.

#25 @Denis-de-Bernardy
11 years ago

For the uploads folder, a mu-plugin and a rewrite rule actually do the trick, e.g. for /media that would be:

RewriteRule ^([_0-9a-zA-Z-]+/)?(media/.*) $2 [L]
add_filter('pre_option_upload_path', function($val) {
	return '../media';
});
add_filter('pre_option_upload_url_path', function($val) {
	$media_url = home_url('/media');
	$media_url = preg_replace("#^.*?//[^/]+#", '', $media_url);
	return $media_url;
});

Can anyone picture how this could get fixed properly in WP?

#26 @CreativeInfusion
11 years ago

Related: #23483 (for UPLOADS)

#27 @danielbachhuber
11 years ago

This caused me some amount of hell the last few days — it would be great to get fixed up.

Here's the intermediate solution I used for my situation: https://gist.github.com/danielbachhuber/9379135

Our setup is:

  • One subdomain network
  • WordPress is installed in /wp/

I also ran into #27287

#28 in reply to: ↑ 19 @FolioVision
10 years ago

Replying to nacin:

If you wish to keep /wp/, you'll need a filter and changes to your .htaccess. I don't think we need to support that out of the box.

Nacin, this seems to me an arrogant and short-sighted approach. You could just fix the network_admin_url() function out of the box. It's one line in wp-config.php.

I know it's more exciting to code really complex features which bloat Wordpress than to make core URL structure both flexible and bulletproof. I'd say the second is more important.

Enjoy the hoops you make people jump through. Could you just fix network_admin_url(). We've done the hard work for you.

Last edited 10 years ago by FolioVision (previous) (diff)

#29 @alexander.rohmann
10 years ago

Just spent several hours trying to sort this out before coming across this. I don't see how "site URL" should ever depend on "path"

I think it's fair to expect network_site_url to return the actual site url, just like site_url would. Meaning the URL to the WordPress files themselves. Would be really great if this and #27287 could be addressed. Some workarounds are ok, but would be so much simpler if this was just done right in core.

I propose adding a new constant that specifies the WordPress files location. Something like:

define('WP_INSTALL_PATH','/wp/');

The path can still be used as a safe fallback, but this way we can have a Multisite and separate the install files without needing to bother with extra code.

Thoughts?

#30 @FolioVision
10 years ago

Hi Alexander,

Thanks for taking a close look at this issue.

On the other hand, adding a clear cut path to the Wordpress PHP files would really simplify matters in multisite. My vote is for adding this simple universal variable which would be accessed in all multisite, just like you suggested:

define('WP_INSTALL_PATH','/wp/');

Alec Kinnear

PS. I had thought network_admin_url() would get the job done using the existing path variables.

Last edited 10 years ago by FolioVision (previous) (diff)

#31 @nacin
10 years ago

#31057 was marked as a duplicate.

#32 @SergeyBiryukov
10 years ago

#31057 was marked as a duplicate.

#33 follow-up: @nacin
10 years ago

Essentially, we made a decision in #19796 that having /wp/ in the URL was ugly. But everything still works. Let me explain:

Single site has no requirement for rewrite rule support in Apache, IIS, nginx, etc. Multisite, however, does. So for single site, you have home URL being example.com and site URL being example.com/wp/, where the files are. But in multisite, we can keep the files in example.com/wp/wp-admin/ (for example), set the URLs to example.com/wp-admin/, then use rewrite rules to rewrite /wp-admin/ to /wp/wp-admin/. This keeps URLs clean and the filesystem clean.

We use this setup on wordpress.org. It works fine. Something like https://gist.github.com/danielbachhuber/9379135 is only necessary if you want /wp/ in the URL. If you do not, then when you set up a network with /wp/ being your site URL, everything will be handled for you in the rewrite rules that are generated.

This ticket was mentioned in Slack in #core-multisite by sergeybiryukov. View the logs.


10 years ago

#35 @loboyle
9 years ago

In general this is working well for me, but I've come across a problem with this and W3 Total Cache. If you want to upload the wp-includes files to a CDN, W3TC (unaware of the rewrite rule) uploads the files to the CDN with the subdirectory in the path, but rewrites them on the site without the subdirectory (as there is no path in the siteurl, WP enqueues them without the subdirectory, and W3TC just rewrites what's requested).

Has anybody else encountered this and found a solution? I've also asked in the support forums, but thought here might be more productive.

https://wordpress.org/support/topic/w3tc-subdirectory-wp-install-and-cdn-wp-includes-uploads

#36 in reply to: ↑ 33 @renatofrota
8 years ago

Replying to nacin:

Essentially, we made a decision in #19796 that having /wp/ in the URL was ugly. But everything still works. Let me explain:

Single site has no requirement for rewrite rule support in Apache, IIS, nginx, etc. Multisite, however, does. So for single site, you have home URL being example.com and site URL being example.com/wp/, where the files are. But in multisite, we can keep the files in example.com/wp/wp-admin/ (for example), set the URLs to example.com/wp-admin/, then use rewrite rules to rewrite /wp-admin/ to /wp/wp-admin/. This keeps URLs clean and the filesystem clean.

We use this setup on wordpress.org. It works fine. Something like https://gist.github.com/danielbachhuber/9379135 is only necessary if you want /wp/ in the URL. If you do not, then when you set up a network with /wp/ being your site URL, everything will be handled for you in the rewrite rules that are generated.

This may be working on wordpress.org but is still not working on the WordPress we download and run ourselves.

I just tried a setup, steps:

  1. install WP on /wp/
  2. copy index.php and .htaccess to / and modify /index.php to require wp-blog-header.php from /wp/ subdirectory
  3. activate WPMS (subdirectory based network)
  4. modified .htaccess and wp-config.php as suggested by instructions on WP Dashboard and re-login

Now domain.com/wp-admin redirects to domain.com/wp/wp-admin (OK here, I don't mind if the "ugly" /wp is displayed or not, since the redirection works) but all links related to network admin are being displayed as domain.com/wp-admin/network and this is not working as expected (redirect loop).

I am seeing this is open for years. Is it still planned to be fixed by any form (with/without directory being displayed on URL, I don't mind) or should I give up and install WP on / ?

#37 @FolioVision
8 years ago

Thanks for your comment Renato. We feel the same way.

I still don't understand Andrew @nacin why this rather standard configuration (safely tucking the WordPress PHP files and directories away out of root) can't be fully supported.

Last edited 8 years ago by FolioVision (previous) (diff)

#38 @FolioVision
8 years ago

Quick question. Is our issue here somehow solved in these changes https://make.wordpress.org/core/2016/11/04/multisite-focused-changes-in-4-7/? @jeremyfelt

I see the multisite team has done amazing work in 4.7. It would be great if this installation directory path could be wiped out once and for all.

#14730
ms-files.php required ob_clean() and flush()
#26855
get_blogaddress_by_id used in wp-activate.php limits functionality in MU Domain Mapped Sites
#34450
get_id_from_blogname returns false if the main domain starts with www.
#36918
Multisite: Can't set en_US for language, when creating a new site
#37053
Ensure `get_site_by_path()` returns a `WP_Site`
#37061
Use `get_sites()` in `get_blogs_of_user()`
#37102
Replace get_blog_details with get_site
#37218
get_main_network_id should use WP_Network_Query
#37309
Show always domain and path when deleting a site
#37414
Use `get_network()` instead of global `$current_site`
#37447
Remove redundant `is_multisite()` checks in network admin templates
#37553
Deprecate `wp_get_network()`
#37612
Use blog_id field while selecting blogs for networks upgrade
#37621
Incorrect docs for `$number` argument in `WP_Site_Query`
#37764
Network Admin - sites screen notice: the id for the message div is not unique
#37823
Use get_sites in Network upgrade
#37896
Remove old "My Sites" help text
#37901
Multisite admin has duplicate HTML id's for ab-awaiting-mod
#37922
WP_Site_Query does not have a $join query clause to compact
#37932
Add annotations for extended `WP_Site` properties
#37943
Invalid link to the "Run importer" action while installing importer plugin from a multisite sub-site
#38039
Invalid PHPDOC for get_sites
#38151
die() instead of wp_die() ?
#38152
Clarify in the DocBlock that get_site_by_path() does not return exact matches
#38175
Use `get_sites()` instead of a database lookup in `get_id_from_blogname()`
#38253
Site icon functions using `ms_is_switched()` incorrectly
#38319
Add $network_id parameter to filters in `get_network_option()`
#38320
Add $network_id parameter to hooks in `add_network_option()`
#38321
Add $network_id parameter to hooks in `update_network_option()`
#38322
Add $network_id parameter to hooks in `delete_network_option()`
#38344
"Site Language" label for per-user language selection isn't accurate on Multisite
#38345
Replace get_blog_details() usage in WP_Importer::set_blog() with get_site()
#38346
Replace get_blog_details() usage in wpmu_delete_blog() with get_site( $blog_id )
#38347
Replace get_blog_details() usage in /wp-admin/ms-delete-site.php with get_site()
#38348
Replace get_blog_details() usage in wp-admin/my-sites.php with get_site()
#38349
Replace get_blog_details() with get_site() in all of the wp-admin/network/ screens
#38350
Replace get_blog_details() usage in wp_xmlrpc_server::_multisite_getUsersBlogs() with get_site()
#38351
Replace get_blog_details() usage in wp-includes/ms-blogs.php with get_site()
#38353
Replace get_blog_details() usage in get_dashboard_blog() with get_site()
#38355
Replace get_blog_details() usage in get_active_blog_for_user() with get_site()
#38356
Replace get_blog_details() usage in add_user_to_blog() with get_site()
#38357
Replace get_blog_details() usage in ms_site_check() with get_site()
#38358
Replace get_blog_details() usage in get_blogs_of_user() with get_site()
#38370
Customizer: Theme install and preview is still available on a single site in a MS setup and throws JS error when attempting to install
#38451
WordPress Profile email change is flawed but has an easy fix
#38459
Checkbox have double label on single input field
#38491
Deprecate the `blog_details` filter
#38497
Replace get_blog_details() in unit tests with get_site()
#38526
REST Multisite new user is not assigned to any site
#38602
WP_UnitTest_Factory_For_Network::get_object_by_id() calling deprecated wp_get_network()
#38763
Multisite sign-up notifications missing user login
#38962
REST API: Don't delete posts/links when deleting/removing a user from a site in a multisite install
#38990
REST API: admin_email setting description is inaccurate
#39005
REST API: Site URL setting should not be present on multisite installations


Last edited 8 years ago by FolioVision (previous) (diff)

#39 @protohominid
8 years ago

I'm still having this exact same issue with my local install with WP 4.7, but the live site works fine. Seems like the htaccess rewrite rules are working on the live site, but not on my local installation (exact same rules in both places). What might cause that? Was there any solution to this planned for WP core?

#40 @miklb
7 years ago

I get the decision, but it is a breaking one if it's not documented anywhere or there's no warning (site url/. I've not found any good documentation for nginx rewrite for the WordPress files in a subdirectory.

That said, what worked for me with nginx and WordPress files in /wp

rewrite ^/(wp-.*.php)$ /wp/$1 last;
rewrite ^/(wp-(admin|includes).*) /wp/$1 last;

Just leaving this here in case someone else stumbles onto this issue as I did.

Edit spoke too soon. While my subdomain installs work with these rules, my primary site is still using the /wp/ path, causing some issues, so back to drawing board.

Edit Edit updated second rewrite to remove wp-content, seems to be working better, but still some ghosts in machine.

Last edited 7 years ago by miklb (previous) (diff)

#41 @jorbin
3 months ago

  • Keywords close added

As pointed out by @nacin, this is functioning as designed. It's also been many years now with little advocacy or work towards a solution which makes me think that at this point it is absolutely a feature worth keeping and this should be closed as worksforme. Before closing, I'll give some time to anyone who wants to advocate a different direction.

#42 @JeffPaul
5 weeks ago

  • Milestone Awaiting Review deleted
  • Resolution set to worksforme
  • Status changed from reopened to closed

I concur, close.

Note: See TracTickets for help on using tickets.