The attached patch comes about from the hacking that I have to do with every new release to allow site-specific themes that are not available system-wide, and from a conversation this morning with Adrian R. regarding configuration updates (that he has discussed with Dries). The basic idea is to allow multiple sites running from a single Drupal installation to share some themes and modules while also having site-specific versions. For example, say I have site1.com and site2.com running from the same Drupal installation. site1 has a custom theme or module that it does not want site2 to be able to use. Or, say site2 wants to use a cvs version of a module whereas site1 wants to use the released version. Currently this is not possible.

The attached patch makes this possible by moving site configuration (including the default 'conf.php' config) into a new conf directory structure, making the includes directory more off-limits to end users (as it should be). The structure looks like this:

conf/
conf/default/
conf/default/config.php
conf/site1.com/
conf/site1.com/config.php
conf/site1.com/modules/...
conf/site1.com/themes/...
conf/www.site2.com.subdir/
conf/www.site2.com.subdir/config.php
conf/www.site2.com.subdir/themes/...

The site configurations require the config.php file, but the modules and themes directories are optional. If they exist, they will be searched. This allows different sites to use different modules and themes, different versions of modules and themes, modified versions of modules or themes, and/or custom modules or themes that are unavailable to other sites. The master directories (modules/ and themes/) will still be used, and their files will be available to all sites. Items installed in the site's configuration directories will shadow the master versions if installed both places.

Details:

includes/bootstrap.inc:

* Changed conf_init() to return the configuration directory for the current site with 'conf/default' as the default. It uses a static variable so that the search only needs to happen once. Note that I also cleaned up the matching code a bit so that it will search for a file as follows: www.site.com.subdir, site.com.subdir, www.site.com, site.com, --default--. Previously the search order would be: www.site.com.subdir, site.com.subdir, com.subdir, subdir, ubdir, --default--. The new way seems to be closer to what we want.

* Changed include_once to include the new, correct configuration file.

includes/file.inc:

* Changed file_scan_directory() to use $name (the basename) as the array key rather than the filename. This prevents problems when a "master" version of an item was installed/enabled and a new site-specific version is now installed/enabled. Questions: Will this cause problems elsewhere? Are contribs using this? What if a file with a specific name exists in two subdirectories? One will overwrite the other now...

modules/system.module:

* Changed system_listing() to scan the master modules and themes directories followed by the site-specific directories (if they exist).

* Changed system_listing() to handle basename-keyed array now returned from file_scan_directory (including within the required and throttle_required arrays).

* Changed system_listing() DELETE db_query to use name and type as key rather than filename and type.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

adrian’s picture

Dries has mentioned that he thinks conf_init() should work the other way around.
Ie : get a list of directories in /conf/ , and then try to match the url against that.

But that's a small point..

+1

jhriggs’s picture

That would be faster...and easier (getting the list in conf/ and then matching the URL against the list). I'll look into a new patch that works that way.

jhriggs’s picture

So as I have looked into this, I have found that it may not be more efficient and may cause other problems. Say there is an installation with 15 sites. Currently we do a structured search based on the URL in a specific order. As soon as a match is found, we drop out of the loop with just a few file_exists() checks (no more than 4 for some.site.com/subdir). In the proposed manner, we have to build a list of all 15 configuration directories with a file_exists() check for each. Then we have to search through that list for an entry that somehow matches the current URL. This matching may not be a simple task.

I am open to suggestions, but I think what is currently in the patch may be the way to go. Talking with Adrian about this, he agrees.

Dries’s picture

Can't you load a list of all diretories into an array, and perform a regex on them?

jhriggs’s picture

You can, but lets look at some of the code:

$confdir = "conf";
$dirs = array();
$dh = opendir($confdir);

while ($dir = readdir($dh)) {
  if (($dir != "default") && file_exists("$confdir/$dir/config.php")) {
    $dirs[] = $dir;
  }
}

closedir($dh);

You have already done (potentially) a lot of file_exists() checks. Now you have an array something like this:

drupal.org.test
drupal.org
another.drupal.org.site

If the current URL is http://www.drupal.org/test, how exactly do you do the preg_grep? You would look for www.drupal.org.test first? No dice. Then what, drupal.org.test? Each time through you are doing a preg_grep against the entire array. Alternately, you could try a preg_match() of each item in the array against the URL, but how can you be sure you get the right one? drupal.org and drupal.org.test would match, but there is no guarantee as to what order they appear in the array, and sorting doesn't help a whole lot.

This method would use a file_exists() for every directory in conf/ and lots of RE matches which seems like a lot more overhead than at most 4 file_exists() and a few implodes. At first glance the RE method seems more straightforward and easier, but looking into it deeper, there are some slow-downs and hurdles. Is there something I'm missing?

Dries’s picture

Thanks for researching this some more. Given this feature will be of interest for hosting companies, scalability is key. Add to that that this look-up function will be invoked for every page request, we should strive to optimize it as much as possible. Pick whatever is most efficient.

Tarlbot’s picture

When thinking about multisite configuration can you think about how to have different favicon.ico files for different sites?

One way to deal with this is to explicity specify the favicon.ico file in the theme, and delete the one at the root of the Drupal directory - this works okay for many browsers:
<link rel="shortcut icon" href="/themes/site_marvin/images/favicon.ico">
Sadly this doesn't work with all.

Any thoughts on how to get this working better?

jhriggs’s picture

Dries -

I completely agree about scalability and efficiency. That's why I have taken plenty of time to look into both methods. Out of the two, I think what is in my original patch is more efficient, though there may be still better ways that we could investigate. Ideas are welcomed!

Tarlbot -

I have attached an updated patch that _attempts_ to address favicon.ico. (See below.) Let me know if/how it works...

All -

Here is an updated version of the configdir patch. This version doesn't really change much from the original other than to make possible a site-specific misc/ directory in addition to themes/ and modules/. Although this might be slightly controversial, it is more common than not that someone may want to tweak one of the CSS files for a particular site or use a different XML image, etc. Below is a summary of changes (in addition to those already listed for the original patch):

includes/file.inc:

* Added file_miscfile() that returns the path to the site-specific version of a misc file in conf/site/misc/ if it exists or in misc/ otherwise. So, if a certain site has a different xml.gif image the path returned will be conf/site/misc/xml.gif. Other sites will get misc/xml.gif.

favicon.ico:

* Moved to misc/. Redirection will occur in index.php. This will only work with Clean URLs. Maybe a problem. Is there a better way to handle this? Should we ignore the problem and just wait for browsers to support link rel="shortcut icon"?

index.php:

* Checks for q=favicon.ico and redirects to either misc/favicon.ico or the site-specific conf/site/misc/favicon.ico.

update.php, includes/common.inc, includes/theme.inc, modules/book.module:

* Changed hard-coded misc/* paths to call file_miscfile().

Dries’s picture

Looks good, however, here is another thought: what if I have 100 sites of which 95 want to use foo.module. I'd have to duplicate foo.module 95 times, not?

jhriggs’s picture

Well, it depends. If you want it to _only_ be available for those 95 sites and not the other 5, yes. Otherwise, you would just install foo.module in the standard modules/ directory. All modules there are available for all sites. 95 sites would enable it, and the other 5 would not.

Both the site-specific (conf/site/modules/|conf/site/themes/) and site-wide (modules/|themes/) directories, respectively, will be searched. Site-specific versions will shadow site-wide versions. For example:

conf/
-site1.com/
--config.php
--themes/
---site1custom/
----site1custom.theme
-site2.com/
--config.php
--modules/
---image.module {HEAD}
modules/
-image.module {4.4.0}
-foo.module
-...

In this situation, we have the following:

site1 themes: site1custom, {chameleon, example, xtemplate, others in themes/}
site1 modules: whatever is in modules/

site2 themes: whatever is in themes/
site2 modules: image {HEAD}, {foo, blog, book, others in modules/}

Make sense?

jhriggs’s picture

One more revision. I got a little concerned about just changing the key used in the array returned by file_scan_directory(). It worked fine for the changes I proposed, but if contribs used it, they would get different -- and likely unexpected -- results. In this patch, I changed file_scan_directory() to take another argument, $key, which is the key to be used for the returned array. The possible values are "filename" (default), the old behavior, "basename", to use each file's basename as the key, and "name", the extension-less name of each file. Here's the difference (assume we're looking for "\.theme$"):

adir/file1.theme
adir/dir1/file2.theme
adir/dir2/file1.theme
adir/dir2/file2.theme

"filename" -> keys: adir/file1.theme, adir/dir1/file2.theme, adir/dir2/file1.theme, adir/dir2/file2.theme

"basename" -> keys: file1.theme, file2.theme

"name" -> keys: file1, file2

For the purposes of this request, we want either of the latter two; however, this is drastically different than the results that any contribs may be used to getting. I feel that this change is simply safer and won't have negative side-effects on any code that may use file_scan_directory().

Anonymous’s picture

Great work jhriggs !!!

This seems to be exactly what I need.

Any chance that this will make it to the official release 'by default' ???

moshe weitzman’s picture

AdrianR has promised to enhance this patch a bit and resubmit aling with his njew install system.

jhriggs’s picture

Per discussions that I have had with Adrian (and based on the fact that it was ancillary to this issue anyways), this latest version of the patch is pretty much the same as before except that it removes all of the file_miscfile changes.

My only concern is that individual configurations should have some means (in the admin. config?) of overriding anything in misc/. drupal.css can be handled in themes, etc., so that's OK. Forum icons can be changed, so they're OK. We just need to make sure that things like xml.gif, print.css, the arrows, and the other images can be overridden if desired.

Dublin Drupaller’s picture

hiya jhriggs...

I am a newbie and I have gone through the handbook, downloaded "compare it" and tried to apply the patch to the three files you mentioned. No joy.

Is there a simple way of applying a patch that is understandable to newbies?

Any help or guidance appreciated. Is it possible that you can upload the patched files ?
i.e. as i understand it the following files have to be modified for your patch.

file.inc
bootstrap.inc
and
system.module

Would be very grateful and I'm not being lazy, I have tried a few times now to apply the patch using the compare it programme for windows and it won't work for me.

thanks in advance if you get a chance to help.

Jason

jhriggs’s picture

FileSize
15.8 KB

Much to Adrian's delight I am sure ;), attached is version 5 of this patch. This version includes the following:

* Modules no longer have a separate name (admin/system/modules#name). The base file name is used instead, as is the case for themes. No modules in core or contrib were using this functionality, and it causes some nasty headaches with this patch if modules get moved or installed in the site-specific modules directory.

* Adds system_path($name, $type) to system.module. This gives modules and themes a way to find their path (as they will no longer necessarily be located in themes/ or modules/ which will break their current hardcoded paths).

* Xtemplate has been updated to use system_path().

jhriggs’s picture

FileSize
15.76 KB

Oops. Ignore version 5. It has an erroneous preg_match(). This version reverts that line.

Steve Dondley’s picture

It would be great if core modules could be made site specific. Unless I'm doing something wrong, it doesn't appear to work for me. For instance, if I place 'user.module' into the site's 'module' directory and make modifications to it, nothing happens. It doesn't override the original user.module.

jhriggs’s picture

After you place a version of an already installed module (like user.module) into the site-specific modules directory, you have to go to the admin/system/modules page to get it to refresh its list of modules. The path to the old version (in modules/) is stored in the database until this refresh occurs when it is updated to the new one (in conf/somesite/modules/). I don't know of a way around this, so I guess it needs to be documented...consider this the documentation. ;)

Anonymous’s picture

jhriggs,

When I follow your directions I get the following error when I visit the system/modules configuration page:

Fatal error: Cannot redeclare user_module_invoke() (previously declared in modules/user.module:7) conf/xxxxxx/modules/user.module on line 7

I am using the confdir4 version of the patch and not the latest patch. Perhaps this is the problem?

Great patch by the way. Thanks for your work and contributions.

Steve Dondley’s picture

Well, I removed the version 4 multisite patch updated my software with version 5 of and I receive the same error as posted above. I'm using v. 4.4.1 of Drupal.

Steve Dondley’s picture

I found the source of the problem with trying to use a site-specific user.module mentioned above. The problem is that the includes/module.inc file loads the user.module in a couple of different places. First, near the top of the file, it loaded in a 'require_once' statement. The second place it could be loaded is in the while loop of the module_list() function, there is an 'include_once' statement that loads it.

Then, when the system_listing() function includes the site-specific user.module, PHP sends a warning that the user_module_invoke() has already been declared.

It would be a pretty big hack to get this working, I think. The obstacle is that some user.module funcitons are called before they get included by the system_listing() function. And unfortunately, I'm not familiar enough with Drupal's inner working to attempt a fix.

moshe weitzman’s picture

it would seem a good approach to move those functions which are called very early in the request to bootstrap.inc or other include file.

jhriggs’s picture

Voici version 7. This is just updated for HEAD (after tabs and some other things hit core) and changes all double quotes to single quotes in the patch.

Dries’s picture

1. What do people think of this patch?

2. Do the other themes need to be updated?

3. How does one use/test this? The functionality nor its usage does not appear to be documented.

Dries’s picture

1. What do people think of this patch?

2. Do the other themes need to be updated?

3. How does one use/test this? The functionality nor its usage appears to be documented.

jseng’s picture

first of all, i believe multi-site feature is important. many people has asked for it for a variety of reasons, either they ran multiple sites for friends, or they are webhosting company looking for a solution etc.

This patch seem to be an feature expansion on http://drupal.org/book/view/274

However, I believe it is time we relook at how to do multi-site properly, rather then doing hacks on hacks. What we need is a proper architecture (in DB) in how multisite is handled...not just for theme and modules but also taxonomy, user roles, permissions, etc etc. It should also be easily configured via admin page without shell access to be consistent with all other admin function.

moshe weitzman’s picture

when disparaging a patch that is in CVS review as a 'hack upon hacks', please say why it is a hack and how it should be done better. "use a proper architecture (in DB)" is too vague to be helpful.

+1 for this patch

jseng’s picture

admin functions should technically be configurable via the webpage (except the unavoidable ones like setting up the initial db). multisite function is one of such features to be consistent.

doing alt. site-conf.php right now is a hack, albeit one clever one. (strictly speaking, it is no different from dup. the drupal and put them in another directory - we save perhaps a few hundred k of diskspace thats all). this patch allows individual themes & modules is an extension of a hack.

inclusion of a new field, e.g. site_id to relevant table would be a cleaner solution in the long run. it allows more flexibility.

ps: nope, i am not objecting to this patch. multisite is a useful feature and i am not going to stand in its way, not unless i have another alt. patch. i only make this comment at the urging of a discussion on D4B users list on multisite in drupal.

jhriggs’s picture

The DB approach sounds elegant and desirable in theory, but how does one accomplish this in practice? First, one must be able to connect to the DB. We can't look things up in the database if we cannot first connect to the DB, so we must still have the login information in a configuration file somewhere.

Second, with your site_id field, are you suggesting that all sites use the same DB? That would lead to some major administrative and security issues. I don't want the several diverse and distinct sites I host to be using the same DB, but I do want them all to run from the same Drupal install.

Third, like I just mentioned, we are often talking about distinct sites, not just subsites. Say I am hosting distinct sites siteA and siteB, how would an administrator log in and configure these sites in your senario? Does the siteA administrator have control over siteB's configuration? What if siteA and siteB are competitors? That won't work. Are you proposing a completely separate server configuration admin interface just for the server admin set up site configurations? That seems to be getting a bit too complex.

Finally, Adrian R's new installation system is designed to work with the framework in this patch. I'm most interested in hearing his thoughts.

jhriggs’s picture

In response to Dries's questions:

2. Any themes/modules that expect, include, or look for files using hard-coded paths in modules/ or themes/ need to be updated to use system_path().

3. The functionality and usage are pretty well documented in the tracks for this issue. We will need to come up with handbook docs, of course, but for testing, all relevant information should be documented. Basically, one does this:

* Apply patch

* Move includes/conf.php to conf/default/config.php

* Move any site configurations (i.e. includes/site.a.php to conf/site.a/config.php

In its most basic sense, that's all there is to it. Behavior should be the same as today except that admins are able to use links and/or permissions for the site configuration directories as they see fit (i.e. to give the site's owner permission to change the config file without admin intervention).

To get more complex:

* Create themes and/or modules subdirectories for sites (conf/default/themes, conf/default/modules, conf/site.a/themes, conf/site.a/modules)

* Install themes/modules that are specific for sites. That is, a theme "siteAtheme" installed in conf/site.a/themes/ is only available for siteA. If image.module is only installed in conf/default/modules, it will only be available for sites using the default configuration, but not siteA.

* The main themes/ and modules/ directories are still used. Themes and modules in these directories are available for all sites; however, if siteA wants to use a modified version of a theme/module installed in the default directory, this is possible. The version installed in the site's conf directory overrides (or shadows) the one installed in the modules/ or themes/ directory.

Anonymous’s picture

The install system uses the multisite patch as a foundation, to create the installation and upgrade interface for sites on the same install. This information doesnt get stored in a database, but in a config file for each site. This allows you to move sites without needing a master database for all sites (which you surely wont be moving).

I don't see why you would want to get rid of the configuration file, as it is the most flexible solution. And you can already achieve multiple site
hosting in the same database using database prefixes. The installation system is also fully capable of doing db_prefix installs. This patch is about allowing different sites access to different available modules / themes. Not to allow all sites access to the same set of installed files (like a big d4b install would probably work)

The problem with this patch is not that it uses the config file, the problem with this patch is that the way that drupal initializes itself conflicts with override theme/module files.

Drupal uses include_once() to handle the file loading, but if you try to add an overriding file .. the path is different , and the admin screen tries to load all modules just for the help text.. hence crashes. We need to break out the way module loading currently works, so that you can keep a more secure module registry, via a module_load function or something.

Chris Johnson’s picture

When considering how to support multiple sites with one Drupal install, I believe it's a good idea to look at use cases, and pick those which are most important and will most frequently be used.

My take on 2 such use cases and how often they are used:

1. As "jhriggs" points out, there are problems with sharing the same database or same administration interface between sites if they are distcintly unrelated (perhaps even competitor) sites. It seems to me that this will be the most frequent case for people who want to provide Drupal hosting services. That is, just as a hosting service might host 100 web sites using 100 Apache VirtualHost clauses, likewise a hosting service might want to host 100 Drupal sites.

2. The instancess where someone wants to host multiple related sites (subsites) or multiple sites administered by one administrator seems like it would be less common.

Even if the number of people who currently want #2 out number the people who want #1, coding Drupal to use a site key in all the appropriate database tables as a technique to solve #2 per jseng would tend to cut off the ability to do #1 cleanly. It will cause all installations to pay the much larger database overhead of #2, even though #2 will remain a small fraction of all Drupal installations.

adrian’s picture

sorry , i hadn't logged on yet.

Steve Dondley’s picture

I like the patch and I am using it. See post #32 above for a problem I ran into when trying to use customized core modules (specifically user.module). There's about 5 or 6 modules like this.

I like jseng's idea of integrating permissions, roles, etc. I have one site (Site B) whose user base is a subset of another site's (Site A) user base. Site B is set up as a "private" area and the content is restricted to authorized users. Site B uses Site A's roles, permissions and users tables.

To get this done, I made a very quick and dirty hack, and modified the user_access() function that handles the "Name Rules" operation and added a new table the database in a way so that only authorized users from Site A could log into Site B. However, this is less than ideal. For instance, it's currently impossible for a user to have one role for Site A and another for Site B. At some point, I'm going to throw together a hack to fix that problem. ;)

Sorry for all my hacks. I'd contribute to the CVS but I'm afraid my programming skills and knowledge of Drupal just ain't there yet.

Chris Johnson’s picture

It appears nysus's hack/patch to create a private subsite B of site A is a result of Drupal's like of an appropriately fine-grained access control scheme. That is, the need for subsite B is only because there is no way to block the non-B members from a private area of A. This ability is something that was been widely needed for a long time.

Creating database architecture changes to support multiple sites from one Drupal installation and one Drupal database to allow private subsites is not the right way to solve that problem. Instead we need the much talked about permission system (something I intend to get to Real Soon Now).

Dries’s picture

I'm playing the devil's advocate here but if I want to host multiple Drupal sites, can't I use soft links instead? The misc- and include-directories could be soft-linked entirely, where the modules and themes could be soft-linked individually. The default modules or module profiles could be created by grouping them in directories, and can be enabled using a single soft-link to avoid having to create a link for each module.

moshe weitzman’s picture

I was about to point out that Windows doesn't have soft links, but apparently it does.

I have no insight into whether the proposed soft link configuration is equivalent to this patch.

adrian’s picture

I don't see softlinks being able to replicate this functionality, although they would aid in managing a site configured with it. An example...

This tree hosts three different sites..

  1. mydomain.com
  2. hisdomain.com
  3. herdomain.com

Themes

Each of the top sites have their own themes , implemented as .theme files, that are not shipped with core. i am making this part simple for now, as the new template system is already multisite ready, the more common usage of this would be that each had their own unique set of templates for phptemplate/xtemplate.. both of which need to be hacked to work, as is.

Additional modules

  • jabber.module - mydomain
  • textile.module - herdomain
  • title.module - hisdomain
  • ecommerce framework - mydomain, herdomain

Customized modules

  • user.module - herdomain
  • blog.module - hisdomain

Using multisite patch

Say the site is installed in /home/drupal/webroot/htdocs. Create the following conf.php files conf/mydomain.com/conf.php. conf/herdomain.com/conf.php, conf/hisdomain.com/conf.php. These files contain the database settings for the sites. mydomain and herdomain's config files also contain :
$module_directories[] = "/home/drupal/modules/ecommerce/';
Each config directory has another modules directory, where you could either copy .. or link to the other modules required. In this case you would need to install conf/mydomain.com/modules/jabber.module, conf/hisdomain.com/modules/title.module, conf/herdomain/modules/textile.module This is the part of the patch that can be managed with soft links.. but an important distinction that should be noted , is that you can not put softlinks into cvs or subversion. This is incredibly hard to swallow for people, like me, who keep their sites in version control systems.

Themes for each of the sites would be installed into their conf directories .. ie: conf/mydomain.com/themes/mytheme/, conf/hisdomain.com/themes/histheme/ and conf/herdomain.com/themes/hertheme/. These might not be able to be linked.. I recall that I have had trouble with links and themes in the past, although i have no hard evidence. I will continue assuming you can.

Copies of modules/user.module to conf/herdomain.com/modules/user.module and modules/system.module to conf/hisdomain.com/modules/system.module can be made. Although this is where the patch currently fails ... the reason being that all modules are being loaded quite early, and there isn't decent protection to stop 2 modules with the same name being loaded .. and hence it crashes with namespace collisions.. (ie: function module_help() already defined).

The use can now be given ftp / ssh access, with a chrooted environment to their conf directory. Where they would be able to modify the files they have direct access to. Including their own themes and modules.

Using softlinks

To accomplish this, you would need to use seperate trees for each of the sites, as without the patch .. each of the sites is only aware of the modules/ and themes/ directories. You could accomplish this via either using a drupal core instance installed for each site , or via a simulated core instance achieved via selectively linking directories and/or files to their places in the new tree. You would not be able to easily override modules, as you would need to link each of the modules in modules/ seperately , and then would need a new place to store the modules that have been modified, unlink the default provided module , and then relink to the new location.

None of this could be stored in cvs/svn , and the maintanence on something like this would be exponential. It would be safer / easier to just give a standard install with write access to each of the sites.

Summary

While it is technically possible to accomplish this using softlinks, it is a hack of giant proportians, and a maintenance nightmare. Currently, the only problem with this patch is in the case of overriding modules , and this is directly related to how drupal loads modules.. so the patch isn't unneccesary.. it just has some issues.

adrian’s picture

The changes to module loading have been made and the patch is available on the Safe(r) module loading issue. I am waiting for it to hit HEAD, then I will make a new version of this patch with the last issue (overriding modules) fixed.

moshe weitzman’s picture

with module loading in core, i think this patch just needs a refresh and resubmit. we just have a few days before the freeze ...

jhriggs’s picture

FileSize
19.88 KB

As requested and in time for the freeze, here is version 8.

  • Updated for changes in HEAD.
  • Updates and/or reverts some of the changes done with the recent Safe(r) Module Loading patch. That patch mentions that it is required for this one; however, it duplicates some code in and conflicts with this patch.
  • Moves system_path() in system.module to drupal_path() in common.inc and also adds drupal_filename() to common.inc. The new module_load() function requires these functions, but of course they were not available until system.module was loaded. Thus, they were moved to common.inc.
  • drupal_path() and drupal_filename() only return a file/path if the file exists.
  • drupal_filename() takes an optional third argument, $filename, that sets the path to be used for the specified file rather than retrieving it from the database.
  • An error is printed via drupal_set_message() if a module cannot be loaded in system_listing(). The Safe(r) Module Loading patch ignored a failed module_load().
jhriggs’s picture

Version 9 (attached) is updated for HEAD after the major theme changes. Much of the theme listing code in system.module had to be rewritten. I have not tested this exhaustively yet, but Adrian is hounding me for an update, so I am uploading in its current state and setting the status to active.

jhriggs’s picture

Note that the patch won't work properly on a fresh install without this patch.

jhriggs’s picture

FileSize
28.71 KB

Another sync with HEAD. The only real change is that drupal_filename() now uses a "best-effort" search for the item:

  • If a filename is passed in, and the file exists, it is used.
  • If the filename stored in the database exists, it is used.
  • The site-specific directory for the item is checked.
  • The default directory for the item is checked.
killes@www.drop.org’s picture

FileSize
29.13 KB

Updated to CVS. Hope I didn't break anything.

Dries’s picture

The patch looks good to me, although some of the function names are not very explanatory. I had to read the Doxygen documentation to understand what some of the functions might be doing. That said, the patch seems to simplify quite a bit of code.

Some documentation is required as how to use this new functionality. Should this be added as a new section to the INSTALL.txt?

adrian’s picture

FileSize
64.33 KB

The biggest change, is that the config file is now located at conf/$url/config.php , instead of at includes/$url.php. Furthermore, we can ship with a conf/default/config.php.

Using the functionality is pretty simple. If you only want to install a module or theme for a single site, instead of them all, create a conf/$url/modules (or conf/$url/themes) directory, and place the code in there instead. You can also use symlinks to install modules / themes for specific sites simply and easily.

You can even give your clients/users chrooted ftp access to their conf/$url directory and allow them to upload their custom (or additional) modules and themes into an area only they can access.

I have attached a pic showing what I did for the bryght hosting platform (which is built on this patch). However, we search additional directories than just the site-specific and core distribution directories. The image is slightly out of date, but we build the final module list using :

1) site specific modules.
2) reseller specific modules.
3) install profile specific modules.
4) core modules.

The system_listing() function in this patch alone is reason enough to include this in core, as it centralizes these directories, so you can just edit a single function to add more locations to search.

Something additionally we still need to look at, is automatically creating files/ in the client config directory. As this is required for true multisite hosting. With the new file_api friendly image module, drupal is a lot better behaved for multiple sites.

jhriggs’s picture

OK. One last version -- hopefully -- before commit (!!!). This again syncs with HEAD. Per conversations with Dries, drupal_filename() and drupal_path() have been renamed to drupal_get_filename() and drupal_get_path(), respectively. Additionally, the configuration directory is now 'sites' rather than 'conf'. Also at Dries's request, I have included an update to INSTALL.txt. This is probably more detailed than what needs to be in that file. Chunks of it can be moved to the handbook, but at least it's written down somewhere. ;)

Once this gets committed, I will also make a final 4.5 version of the patch for those interested in using it on 4.5.

Dries’s picture

Committed to HEAD! Thanks for the hard work and persistence!

I made two small changes: renamed config.php to settings.php and modified conf_init() to work with 'localhost'.

Dries’s picture

jhriggs’s picture

Looks like you left a debugging print() call in conf_init()...

TDobes’s picture

This patch broke the ability to modify theme settings for styles. I am investigating currently, but if anyone else has a solution, feel free to make a patch.

jhriggs’s picture

This patch broke the ability to modify theme settings for styles. I am investigating currently, but if anyone else has a solution, feel free to make a patch.

Hrm...it used to work. It's been tough trying to hit a moving target with this patch. I'll investigate it too...

jhriggs’s picture

Also, as Dries had suspected, this patch broke Moshe's bootstrap fix. Should drupal_get_filename(), drupal_get_path(), and drupal_load() move from common.inc to bootstrap.inc?

moshe weitzman’s picture

yes they should. i will be submitting a new bootstrap patch shortly.

jhriggs’s picture

FileSize
5.91 KB

OK. This patch moves drupal_get_filename(), drupal_get_path(), and drupal_load() from common.inc to bootstrap.inc. It also removes that rogue print that snuck in.

moshe weitzman’s picture

the bootstrap patch that i just uploaded supercedes the most recent one here by jhriggs. please ignore the patch here. setting this issue to 'fixed.'

TDobes’s picture

NOT fixed.

This should remain active until the broken theme settings for styles is fixed. I've been distracted by other issues for the past few hours, but hope to get a patch together to fix it later tonight.

TDobes’s picture

The attached patch fixes a number of issues that cropped up with the theme settings as a result of the multi-site patch:
1. no longer able to modify settings for styles of templates
2. .theme files could no longer co-exist with templates for use in supplementing engine-based theme functions
3. for themes/engines that implement the _settings hook, the headers of "theme-specific settings" and "engine-specific settings" were inverted in some instances

jhriggs: The changes are fairly minor, but I'd appreciate it if you could glance at this code and make sure it doesn't break anything.

TDobes’s picture

attaching the patch would help, I suppose

Dries’s picture

Committed TDobes' patch to HEAD. Great work and collaboration guys!

jhriggs’s picture

As promised, here is a patch for 4.5 for those who may be interested (Adrian). :)

jhriggs’s picture

Note that with the 4.5 patch, you may need to check out TDobes's theme patch also...

Anonymous’s picture

inteja’s picture

Category: feature » support

I just want to make sure I understand this.

When I'm setting up domains, directories and speaking to my hosting company, what exactly do I need to do?

On reading the above, I assume I can just point all domains to the same IP address and Drupal with multi-site patch will automatically determine which config and site to display based on the url. I don't need to set-up any subfolders in the www/public_html/ folder - they now get created in www/public_html/conf/

So for example:

www.mysite1.com -> www/public_html/conf/www.mysite1.com/config.php
www.mysite2.com -> www/public_html/conf/www.mysite2.com/config.php
www.mysite3.com -> www/public_html/conf/www.mysite3.com/config.php

Is this correct?

Brian.

jhriggs’s picture

Yes, that is correct, but note that the 'conf' directory got renamed 'sites' and the config file was renamed 'settings.php' when the patch was committed. So the path would be 'www/public_html/sites/www.mysite1.com/settings.php' for example. Read the '4. CONNECTING DRUPAL' section in INSTALL.txt. It explains exactly how to do this...

inteja’s picture

Thanks.

What if I have multiple top level domains for the one site e.g.

mysite.com
mysite.org
mysite.net

How does this work? Will Drupal still match on 'www/public_html/sites/mysite/settings.php' i.e. removing the TLD?

Brian.

jhriggs’s picture

No, you need the TLD. You would need 'sites/mysite.com', 'sites/mysite.org', and 'sites/mysite.net', but you can make two of them symlinks to the other.

adrian’s picture

This is in core, and has been for a while.

green monkey’s picture

jhriggs
Does this patch work wiht 4.6.x. I understand and have used multi themes in 4.6.2, but it is the site-specific modules I'm working towards now and would like use a single code based or better defined - share user database across both.

So will this patch work with 4.6.x or is there a different way to do site-specific modules in 4.6.x

thanks

moshe weitzman’s picture

this patch was committed and is party of 4.6. create a directory sites//modules and put your site specific packages there.

green monkey’s picture

thank you sir,
this makes me very happy as I generally muddle big patches up.

and to have it built into core, makes my head spin with possible appliactions

green monkey’s picture

Drupal 4.6.2 - multi-site - single code base - "site-specific modules"

I understand the folllowing:
- /sites/ understand set up and have one example running

but I need to take this one step further.

I also get the /sites//modules concept

but this is where I get lost (prefix and/or base)

site A - straight up install
Site B - using Site A's code base

then I need to setup a /sites//modules .. and load the module I want to run as a "site-specific module" into this area so it has content than the info in Site A

? Now what do I do to mySQL side of this

If I do nothing, they share a table - not good

If I do a prefix (prior to creating Site B's table) to avoid Site B's module's table from sitting on top of Site A's module, then I lose the commonality of the other modules that I would like Site A and Site B to share.

did i miss a step .. somewhere?