5

Is there any way to make all requests to any subdomain load the same Wordpress website e.g. user1.example.com, user2.example.com and user3.example.com all load the same website, but with the links pointing to the current subdomain?

I'd like to keep mostly the same content across the different websites. The only difference is that by reading the subdomain I can offer customized content (website title, etc) specifically to that user, or add a hook to display an error message if the user doesn't exist. At the moment the network install requires me to manually define every website, with different contents across them.

2 Answers 2

2

In WordPress you can easily do this with sub-directories like example.com/user1

Sub-domain & URL Strategy Having username.domain.com will prevent you in the future from having your own sub-domains like shop.example.com and will plague you if you wanted to use www.example.com or just http://example.com

Finally ... what if some user wants to use expletives or special characters in their username <-- not very good.

Traffic Load Sub-domains are analysed (sic) by DNS servers around the world to figure out how to route traffic. If you want to use many sub-domains, this will also increase the load on your Apache web server as it tries to figure out what to do with someusername123456789.example.com

But to do this ... you'd need to look at scripts, htaccess and rewrite rules and then, this question is probably better suited for a different forum.

Sub-directories are easy along with URL parameters
Its safe to say that sub-direcotries are easy (WordPress Author pages as example) and then WordPress can analyse this and determine what to do.

You can even use URL parameters like www.example.com/category/?user=username123456789

In summary -- don't do subdomains for usernames it can cause multiple headaches that you don't want.

3
  • A few things. First, it's not as if DNS servers get skipped when you use a single domain with sub directories. That's a cost of things on the web. Use a highly available, fast DNS server if you want to improve things. Second, the processing power for apache (or nginx) to match wildcard subdomains is minimal. The point where it is likely to be of concern is when your application is running on more than on server. WordPress multisite does multiple subdomains and can work on a massive scale (see WordPress.com). Commented Oct 3, 2012 at 23:20
  • @chrisguitarguy yeh that's true but the OP doesn't want WordPress multisite
    – Damien
    Commented Oct 4, 2012 at 5:12
  • Useless answer, it doesn't answer the question. Please add a disclaimer that it doesn't answer the question in the beginning, wasted an entire minute reading this useless answer. Commented Nov 8, 2023 at 6:03
2

To me it sounds like this might be something better suited to a single site install vs. multi site. But it really depends on how customized things need to be for a single user.

NOTE: this answer will not include information about server setup, etc.

First off, I would define WP_HOME and WP_SITEURL in wp-config.php and make them unchanging. You can probably set these dynamically, but the results needs to be that they point to the main, root domain. My local WP install is wordpress.dev, so I'll use that throughout this answer.

Example:

<?php
// in wp-config.php
define('WP_HOME', 'http://wordpress.dev');
define('WP_SITEURL', WP_HOME . '/wp'); // wp in sub directory

// custom content directory
define('WP_CONTENT_DIR', dirname(__FILE__) . '/content');
define('WP_CONTENT_URL', WP_HOME . '/content');

Next we need to set the user based on the current subdomain. This should be relatively easy: parse the HTTP host, look for a user by that username, set that user as the user for later. I'd suggest wrapping everything in a class (a singleton here).

<?php
class WPSE66456
{
    // container for an instance of this class
    private static $ins;

    // The current user, based on subdomain.
    private $user = null;

    /***** Singleton Pattern *****/

    public static function init()
    {
        add_action('plugins_loaded', array(__CLASS__, 'instance'), 0);
    }

    public static function instance()
    {
        is_null(self::$ins) && self::$ins = new self;
        return self::$ins;
    }

    /**
     * Constructor.  Actions really get added here.
     *
     */
    protected function __construct()
    {
        // empty for now...
    }
} // end class

Then we need to write something to parse $_SERVER['HTTP_HOST'] and see if we get a valid username from it.

<?php
class WPSE66456
{
    // snip snip

    protected function __construct()
    {
        $this->set_current_user($_SERVER['HTTP_HOST']);
    }

    protected function set_current_user($host)
    {
        if(!is_null($this->user))
            return;

        list($user, $host) = explode('.', $host, 2);

        // gets tricky here.  Where is the real site? Is it at the root domain?
        // For the purposes of this tutorial, let's assume that we're using a
        // nacked root domain for the main, no user site.

        // Make sure the $host is still a valid domain, if not we're on the root
        if(strpos($host, '.') === false)
        {
            $this->user = false;
        }
        else
        {
            if($u = get_user_by('slug', $user))
            {
                // we have a user!
                $this->user = $u;
            }
            else
            {
                // invalid user name.  Send them back to the root.
                wp_redirect("http://{$host}", 302);
                exit;

                // Or you could die here and show an error...
                // wp_die(__('Invalid User'), __('Invalid User'));
            }
        }
    }
}

Now that you have a username you can do all sorts of things. As an example, let's change the blog tagline to a greeting for that user.

<?php
class WPSE66456
{
    // snip snip

    protected function __construct()
    {
        $this->set_current_user($_SERVER['HTTP_HOST']);
        add_filter('bloginfo', array($this, 'set_tagline'), 10, 2);
    }

    // snip snip

    public function set_tagline($c, $show)
    {
        if('description' != $show || !$this->user)
            return $c;

        return 'Hello, ' . esc_html($this->user->display_name) . '!';
    }
}

Assuming you use the root, naked (no www) url for your install, WordPress will send cookies to all the sudomains. So you, can check to see if a user is viewing their own subdomain and throw them back to the root, otherwise.

<?php
class WPSE66456
{
    // snip snip

    protected function __construct()
    {
        $this->set_current_user($_SERVER['HTTP_HOST']);
        add_filter('bloginfo', array($this, 'set_tagline'), 10, 2);
        add_action('init', array($this, 'check_user'), 1);
    }

    // snip snip

    public function check_user()
    {
        if($this->user === false || current_user_can('manage_options'));
            return; // on the root domain or the user is an admin

        $user = wp_get_current_user();

        if(!$user || $user != $this->user)
        {
            wp_redirect(home_url());
            exit;
        }
    }
}

Finally, the last thing to consider would be that WordPress allows things in user names that won't work with the domain name system. Like user.one is a valid user name. But user.one.yoursite.com is two subdomains deep and not going to work.

So you'll need to hook into pre_user_login and sanitize things.

<?php
class WPSE66456
{
    // snip snip

    protected function __construct()
    {
        $this->set_current_user($_SERVER['HTTP_HOST']);
        add_filter('bloginfo', array($this, 'set_tagline'), 10, 2);
        add_filter('pre_user_login', array($this, 'filter_login'));
        add_action('init', array($this, 'check_user'), 1);
    }

    // snip snip

    public function filter_login($login)
    {
        // replace anything that isn't a-z and 0-9 and a dash
        $login = preg_replace('/[^a-z0-9-]/u', '', strtolower($login));

        // domains can't begin with a dash
        $login = preg_replace('/^-/u', '', $login);

        // domains can't end with a dash
        $login = preg_replace('/-$/u', '', $login);

        // probably don't want users registering the `www` user name...
        if('www' == $login)
            $login = 'www2';

        return $login;
    }
}

all of the above as plugin.

There a lot of concerns that aren't addressed in this answer. Does this scale to where you need it to scale? How will having multiple subdomains of very similar content impact search optimization? How much content gets customized? If it's a lot, would multi-site be better suited for this task?

4
  • Actually I didn't need any access to admin or the current user -- just the frontend of the website. I added filters on site_url, home_url, theme_root_uri and content_url. Sorry I wasn't being very clear, but the users aren't built-in Wordpress users -- just users from an external service. We were basically displaying the same content on each user's home page, but changing a few things based on data retrieved over the api.
    – Zahymaka
    Commented Oct 10, 2012 at 7:06
  • This will still work, you just need to modify the "set user" a bit and remove the check_user filter from init. Then it's all just adding filters. I would strongly encourage you to do some sort of whitelisting of usernames before just hitting whatever API you're using. Without doing that, it's going to be very easy to do something like a DoS attack on your site or cause your API key to get banned. Commented Oct 10, 2012 at 13:37
  • This is great. But for me the content directory does not work when I set it either set to /content or /wp-conent
    – Zen
    Commented Dec 14, 2019 at 3:22
  • I am very new, please advise how I install this plugin. Can I just copy to the Child theme functions.php? or where I should insert this class.
    – Zen
    Commented Dec 14, 2019 at 4:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.