WordPress Hacks: Nested Paths For WPMU Blogs

Situation: you’ve got WordPress Multi-User setup to host one or more domains in sub-directory mode (as in site.org/blogname), but you want a deeper directory structure than WPMU allows…something like the following examples, perhaps:

  • site.org/blogname1
  • site.org/departments/blogname2
  • site.org/departments/blogname3
  • site.org/services/blogname3

The association between blog IDs and sub-directory paths is determined in wpmu-settings.php, but the code there knows nothing about nested paths. So a person planning to use WordPress MU as a CMS must either flatten his/her information architecture, or do some hacking.

Challenge: hacking WordPress MU to support arbitrary directory paths for each blog

As with my multi-domain hack, the following assumes that you’re using the vhost=no setting, that you have access to and know how to manipulate your MySQL, that you have control over your DNS and know how to use it, and that you know how to configure Apache or similar. You’d also be smart to turn off any object caching you may have running, at least until we’re done doing direct database manipulation. The following also assumes that your wp-config.php sets the DOMAIN_CURRENT_SITE and PATH_CURRENT_SITE constants — if you’ve done a fresh install recently, it probably does, or you can check my domain mapping hack.

Hack The Path Mapping

Right at the top of wpmu-settings.php you can see how it strips all but the base of the URL path, but rather than mod that file, we can take advantage of an obscure MU hack: sunrise.php, which gets executed after some important WordPress components like the database class get loaded and before wpmu-settings.php.

To use sunrise.php, create a PHP file at /wp-content/sunrise.php and set define('SUNRISE', TRUE); in your wp-config.php.

Here’s the sunrise.php code I’m using:

if( defined( 'DOMAIN_CURRENT_SITE' ) && defined( 'PATH_CURRENT_SITE' ) ) {
	$current_site->id = (defined( 'SITE_ID_CURRENT_SITE' ) ? constant('SITE_ID_CURRENT_SITE') : 1);
	$current_site->domain = $domain = DOMAIN_CURRENT_SITE;
	$current_site->path  = $path = PATH_CURRENT_SITE;
	if( defined( 'BLOGID_CURRENT_SITE' ) )
		$current_site->blog_id = BLOGID_CURRENT_SITE;

	$url = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );

	$patharray = (array) explode( '/', trim( $url, '/' ));
	$blogsearch = '';
	if( count( $patharray )){
		foreach( $patharray as $pathpart ){
			$pathsearch .= '/'. $pathpart;
			$blogsearch .= $wpdb->prepare(" OR (domain = %s AND path = %s) ", $domain, $pathsearch .'/' );
		}
	}

	$current_blog = $wpdb->get_row( $wpdb->prepare("SELECT *, LENGTH( path ) as pathlen FROM $wpdb->blogs WHERE domain = %s AND path = '/'", $domain, $path) . $blogsearch .'ORDER BY pathlen DESC LIMIT 1');

	$blog_id = $current_blog->blog_id;
	$public  = $current_blog->public;
	$site_id = $current_blog->site_id;
	$current_site = sl_get_current_site_name( $current_site );
}

function sl_get_current_site_name( $current_site ) {
	global $wpdb;
	$current_site->site_name = wp_cache_get( $current_site->id . ':current_site_name', "site-options" );
	if ( !$current_site->site_name ) {
		$current_site->site_name = $wpdb->get_var( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE site_id = %d AND meta_key = 'site_name'", $current_site->id ) );
		if( $current_site->site_name == null )
			$current_site->site_name = ucfirst( $current_site->domain );
		wp_cache_set( $current_site->id . ':current_site_name', $current_site->site_name, 'site-options');
	}
	return $current_site;
}

The first few lines of the code do pretty much the same as the start of the wpmu_current_site() function in wpmu-settings.php, but starting with line 8 it takes a big departure.

That’s where it splits the requested URL path like /path/to/blog/and/stuff/ into pieces and constructs an SQL query against the wp_blogs table to identify the correct blog to serve the request. The following example shows how:

SELECT *, LENGTH( path ) as pathlen
	 FROM wp_blogs
	 WHERE domain = 'domain.org' AND path = '/'"
	  	 OR (domain = 'domain.org' AND path = '/path/')
	 	 OR (domain = 'domain.org' AND path = '/path/to/')
	 	 OR (domain = 'domain.org' AND path = '/path/to/blog/')
	 	 OR (domain = 'domain.org' AND path = '/path/to/blog/and/')
	 	 OR (domain = 'domain.org' AND path = '/path/to/blog/and/stuff/')
	 ORDER BY pathlen DESC
	 LIMIT 1

Optimization note

Setting a maximum depth (and array_slice( $patharray, 0, $maxdepth )) would allow the query to be cached up to that depth. Otherwise, the query must be executed for every page load. The $maxdepth could either be set arbitrarily, or could be determined automatically based on the maximum path length of registered blogs.

Setting Up New Blogs

Once you’ve hacked the path mapping (and tested that it didn’t break your current site), you can add a new blog at a nested path.

Create a new blog in the MU blog admin.

Create a new blog in the MU blog admin.

Unfortunately, MU strips the slashes from the URL path you just tried to set.

The new blog you just tried to create, but with a very different path.

The new blog you just tried to create, but with a very different path.

Fortunately, you can set the path correctly in the MU blog editor, and it won’t break the path when you save there.

Set the blog path in the MU blog editor, MU won't break it when you save it this time.

Set the blog path in the MU blog editor, MU won't break it when you save it this time.

Once you create the new blog, try to load it in your browser. You’ll quickly notice the stylesheet is missing, though the blog works and functions properly.

Hack The .htaccess

WPMU uses the following .htaccess rewrite rule to properly direct requests for files on the real filesystem:

RewriteRule  ^([_0-9a-zA-Z-]+/)?(wp-.*) $2 [L]

Obviously, that rule won’t work for deep paths, so I’ve replaced it with this rule:

RewriteRule  ^(.+)?/(wp-.*) /$2 [L]

And with that, you should be done.

6 Comments

  1. A multi-site plugin will do the same thing and give you an admin menu to control it.. :) The sunrise.php is an awesome file, which multi-site and domain mapping plugins make great use of.

    It won’t get overwritten on an upgrade.

    • @Andrea_R:
      Please link to a plugin you’d recommend. David Dean’s Multi Site Manager looks good, but doesn’t appear to support nesting blogs at different paths within the same site (it’s also frustrating that I can’t find SVN or Trac access to the plugins at wpmudev.org). It’s critical to my use that I be able to put a blog at any depth in the URL path.

  2. Will this just work with the MU version of Wordpress? I would like to have a nested blog in the normal hosted version. I have a blog that deals with separate groups and wondered if it was possible to have a structure like this:

    http://www.main-blogs/sub-blog/sub-blog-pages

    ?

    • @Steve: you could do that with the .org version of WordPress, but you’d end up doing a lot of work just to avoid installing WPMU. And, if you did go the WPMU route, your proposed page structure is fully supported by the default install.

  3. [...] time we extended the system to host multiple domains and replace our CMS. Soon we’ll consolidate our  public blogging instance into it, and we’re building an [...]

  4. I got stuck trying to get sunrise.php to work correctly until I realized that the sample sunrise.php code is missing the opening and closing php tags.


Comments RSS TrackBack Identifier URI

Leave a comment

 

User contributed tags for this post:

wp mu path url (4) - wordpress mu blog id (3) - ресет hack в MU (3) - wpmu path (3) - wordpressmu create new blogs (2) - nested wpmu installs (2) - wpmu cannot login new blog admin (2) - wordpress mu base path_current_site (2) - sunrise.php (2) - wpmu blog in subdirectory (2) - current site domain path (2) - How to give the same contents in Wordpress MU blogs (2) - wordpress nested pages (2) - directories to url in wordpress (2) - wordpress nesting blogs in MU (2) - wpmu set blog id constant (2) - wordpress sub blogs (2) - wpmu htaccess (2) - editing blog path in mu (2) - routering wordpress mu (2) - mod rewrite subdirectory blogs wpmu (1) - reset wordpress paths (1) - wordpress mu blog path (1) - hack url wordpress (1) - url path wordpress (1) - wordpress mu new blog in sub directory (1) - wordpress mu can't access sub blogs (1) - Entries (RSS) and Comments (RSS)"Create a new Blog (1) - wpmu multisite admin bar (1) - wpmu get blogid via path (1) - multi site blog categories wpmu (1) - wordpress nested post url (1) - wpmu hacks (1) - wordpress get current category by path (1) - query hack wordpress examples (1) - wordpress pages path (1) - how to hack wordpress login (1) - wordpress mu current_blog (1) - wordpressmu change url (1) - wpmu get info blog path (1) - WPMU htaccess sample (1) - wordpress blog ID (1) - wp mu change blogs path (1) - $current_site->domain . $current_site->path subdirectories (1) - apache unique domain wordpressmu RHEL (1) - wpmu sample site (1) - wp-config DOMAIN_CURRENT_SITE (1) - wordpress mu max pages (1) - wordpress nesting pages in url (1) - wpmu orderby (1) - wpmu set post in category (1) - php get path wordpress (1) - wordpress mu blogid (1) - download hack wp-config.php (1) - hack htaccess (1) - hacking wordpress from url (1) - wordpressmu multi domain cannot log in (1) - mod_rewrite path mapping (1) - domain mapping wordpress mu stylesheets (1) - mod_rewrite nested (1) - trim path rewrite rule apache http://www.mydomain.com/path1 http://www.mydomain.com/path2 (1) - wpmu mapping files (1) - wordpress global $current_site (1) - htaccess domain mapping WPMU (1) - hack wordpress mu admin (1) - how to create new blog in wpmu (1) - wordpress theme editor nested files (1) - wordpress multi domain hack (1) - wordpress mu change domain subdirectory cannot login (1) - How to open a new blog on local domain in wordpressmu (1) - wordpress mu Blogs Categories htaccess (1) - wordpress get current url path (1) - base url for wpmu blogs (1) - mu set hacks (1) - wpmu domain mapping plugin with Multi-Site Manager plugin (1) - wpmu rename wp-admin with htaccess (1) - DOMAIN_CURRENT_SITE multi site cannot login (1) - how to change value of path in wp_blogs table in wordpress-mu (1) - wordpress .htaccess sample (1) - wordpress current url (1) - inurl:wpmu inurl:blog (1) - mapping to another domain wordpress subdirectory (1) - how to reset blog id when you create a new blog on wpmu (1) - htaccess rewrite url path (1) - wordpress get current category path (1) - mu hack get id and pasw (1) - domain_current_site wordpress (1) - wordpress mu in subdirectory cant login (1) - wpmu control categories on sub blogs (1) - mod null wordpress blog mu (1) - how get wordprses mu blog path (1) - wordpress mu can't access blogs (1) - wordpress mu directory structure (1) - reset wordpress mu htaccess (1) - wordpress.com nested urls (1) - wordpress DOMAIN_CURRENT_SITE www (1) - change domain structure in wordpressmu (1) - wordpress category nested (1) - WPMU PHP file paths (1) - wordpress wp_blogs options (1) - wpmu .htaccess editing (1) - wpmu on page blog id (1) - cannot login to wordpress mu blogs (1) - wordpress reset current blog (1) - wordpress hack file multiple base urls (1) - wordpress mu .htaccess config (1) - nested blogs wordpress (1) - wordpress reset blog id (1) - wordpress MU DOMAIN _ CURRENT_SITE (1) - wordpress-mu url mapping plugin (1) - change path wordpress mu blog (1) - wordpress mu different blog url wordpress url (1) - maxnested time htaccess (1) - get path info wordpress mu (1) - wordpressmu url blog structure (1) - wordpress mu nested directory (1) - wordpress $current_site (1) - wordpress mu site wont load (1) - wpmu sunrise (1) - wordpressmu directory structure (1) - sunrise.php download (1) - wordpress mu domain structure (1) - wordpress mu htaccess www (1) - nested blog (1) - wordpress path (1) - nested wordpress install htaccess (1) - wordpress mu blogs add (1) - blogs blogs url (1) - wpmu nested paths (1) - how to link blogs using category id in wpmu (1) - wpmu htaccess category to blog (1) - wp_blogs path (1) - wordpress mu blog site path within directory (1) - wordpress mu blog current id (1) - wordpress mu access blog URL via blog ID (1) - wordpress mu database class (1) - cant's access trac wordpress htaccess (1) - nested blogs (1) - wpmu wont load wp-config (1) - wpmu direct files (1) - wordpress mu url structure (1) - popular posts WPMU (1) - paths wordpress (1) - wpmu blog in url path (1) - wpmu blog path (1) - wordpress mu blog path options (1) - $current_site->domain (1) - wpmu-settings url (1) - wpmu and editing htaccess and new blogs (1) - wordpress Nested categories in url (1) -