Basically the opposite MultiSite URL question that most people ask

One way to achieve this, is to alter the way WordPress maps the request to a blog in your multisite network by using the sunrise.php drop-in. Sunrise overwrite the default setup in wp-includes/ms-settings.php. There, a bunch of global variables are set up like $current_blog or $current_site.

To activate this dropin you have to define the constant SUNRISE in your wp-config.php:

define( 'SUNRISE', TRUE );

Now, WordPress looks up for a sunrise.php file in your WP_CONTENT_DIR directory. (By default it is /wp-content).

In this sunrise.php you have to do at least the following things:

  • Parse the request to get the domain and the path
  • Setup the the global $current_site using the function get_current_site()
  • Looking for your blog in the wp_blogs database table using your domain and path.
  • With this data, set up the global $current_blog

Here’s an example of how i played with this. It’s not perfect but might get you an idea of how this could look like:

(I use namespaces so be aware of using at least PHP 5.3 or striping the namespace references.)

The shown example does not limit the path segments to two levels like you want but matches the complete path against the database, so that even one or more than two levels are possible as base for a own blog.

namespace dna\Blog_Mapping;

sunrise();

/**
 * init the globals $current_blog and $current_site
 *
 * @global $current_blog
 * @global $current_site
 * @global $wpdb
 * @global $path
 * @global $cookie_domain
 * @return void
 */
function sunrise() {

    if ( defined( 'WP_INSTALLING' ) )
        return; # don't touch the installing process

    if ( ! \is_subdomain_install() )
        return;

    /**
     * strip port numbers in the host
     */
    $domain = addslashes( $_SERVER['HTTP_HOST'] );
    if ( false !== strpos( $domain, ':' ) ) {
        if ( substr( $domain, -3 ) == ':80' ) {
            $domain = substr( $domain, 0, -3 );
            $_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -3 );
        } elseif ( substr( $domain, -4 ) == ':443' ) {
            $domain = substr( $domain, 0, -4 );
            $_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -4 );
        } else {
            \wp_load_translations_early();
            \wp_die( __( 'Multisite only works without the port number in the URL.' ) );
        }
    }
    $current_site = \get_current_site();

    # setup the sitename to the current_site object
    $current_site = $current_site->site_name;

    # find the blog by domain and path
    $uri  = \parse_url( $_SERVER[ 'REQUEST_URI' ] );
    $path = \preg_replace( '|([a-z0-9-]+.php.*)|', '', $uri[ 'path' ] );
    $path = \str_replace ( '/wp-admin/', "https://wordpress.stackexchange.com/", $path );

    $current_blog = get_blog_details( $domain, $path );

    # at this point, we are obviously at the root blog
    # using the core function to get blog by root blog id
    if ( ! $current_blog ) {
        $current_blog = \get_blog_details( $current_site->blog_id );
    }

    if ( empty( $current_blog->site_id ) ) {
        $current_blog->site_id = ( isset( $current_site->id ) )
            ? $current_site->id
            : 1;
    }

    $blogname = substr( $domain, 0, strpos( $domain, '.' ) );
    $blogname .= $current_blog->path;

    # set globals like in wp-includes/ms-settings.php
    $GLOBALS[ 'blog_id' ]      = $current_blog->blog_id;
    $GLOBALS[ 'public' ]       = $current_blog->public;
    $GLOBALS[ 'current_site' ] = $current_site;
    $GLOBALS[ 'current_blog' ] = $current_blog;
    $GLOBALS[ 'path' ]         = $current_blog->path;
    $GLOBALS[ 'blogname' ]     = $blogname;
}

/**
 * get the blog details by domain and
 * matching path segments
 *
 * @global $wpdb
 * @param string $domain
 * @param string $path
 * @return \stdClass|FALSE
 */
function get_blog_details( $domain, $path ) {
    global $wpdb;

    $query = $wpdb->prepare(
    "SELECT
        *
     FROM
        {$wpdb->blogs}
     WHERE
        domain = %s
     AND
            1 = INSTR( %s, path )
     ORDER BY
        CHAR_LENGTH( path ) DESC
     LIMIT 1",
    $domain,
    $path
);

    $current_blog = $wpdb->get_row( $query );

    if ( empty( $current_blog ) )
        return FALSE;

    return $current_blog;
}

Leave a Comment