Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to exclude domain from link generation in wordpress

Tags:

php

wordpress

I have a website that responds on *.domain.com.

Going to x.domain.com or y.domain.com should produce the same web page.

What * is I do not know, but it is and important piece of info since we track things based on it.

When moving to wordpress we ran into a pretty severe problem. It seems to generate links (using get_page_link) with the domain which is set in the admin.

This will not work for us because we can't find a way to tell wordpress to generate links without the domain (why does it do this anyway?!) and every time a link is clicked the browser goes from: x.domain.com to domain.com (since domain.com is what we have in the admin).

like image 886
Xealot Avatar asked Jan 21 '23 14:01

Xealot


1 Answers

Unfortunately WordPress is architected such that it is really hard to get rid of the domain component of URLs. But all is not lost! Read on as the answer to your question requires a bit of background.

The WordPress team made the decision to require the user of a site to hardcode the site domain either in the database via an admin console, which you can see in the following screen shot, of via PHP which we'll discuss below:

WP_HOME and WP_SITEURL in WordPress Admin Console

You might ask what the difference is between the the two URLs? Even I find it confusing because I almost never need anything other them to have them both set to the root URL and as it's not important for your question I'll just gloss over that detail. If you are interested though you can learn more here:

  • Changing The Site URL
  • Editing wp-config.php: WordPress Address (URL)
  • Giving WordPress Its Own Directory

Moving along, the other option is to hardcode the two PHP constants WP_SITEURL and WP_HOME in the /wp-config.php file which can be found in the root of a WordPress installation. Those two lines might look like this in your /wp-config.php file:

define('WP_HOST','http://domain.com');
define('WP_SITEURL','http://domain.com');

The good news is that you can define both of them dynamically based on the current domain your site is serving from (I'm going to assume you have both your DNS server and your Apache web server configured for wildcard DNS.) You can use the following code to match any subdomain name consisting of letters and numbers:

$root_domain = 'domain.com';  // Be sure to set this to your 2nd level domain!!!
$this_domain = $_SERVER['SERVER_NAME'];
if (!preg_match("#^([a-zA-Z0-9]+\.)?{$root_domain}$#",$this_domain)) {
    echo "ERROR: The domain [$this_domain] is not a valid domain for this website.";
    die();
} else {
    define('WP_HOME',"http://{$this_domain}");
    define('WP_SITEURL',"http://{$this_domain}");
}

The bad news is you may have some "artifacts" to deal with after you get it working such as how URLs are handled for image URLs stored in the database content (which may or may not end up being a problem) or for Google Maps API keys, etc. If you have trouble with them let me suggest you post another question here or even better at the new WordPress Answers Exchange also run by the same people as StackOverflow.

As for telling WordPress how to generate links, there are filters you can "hook" but in my quick testing I don't think you need it because WordPress will generate the links for whatever domain happens to be your current domain. Still if you do find you need them you can do it although be prepared to be overwhelmed by all the add_filter() statements required! Each one controls one of the different ways links can be generated in WordPress.

Here is the hook filter function and the 40+ add_filter() calls; you might not need them all but if you do here they are:

function multi_subdomain_permalink($permalink){
    $root_domain = 'domain.com';
    $this_domain = $_SERVER['SERVER_NAME'];
    if (preg_match("#^([a-zA-Z0-9]+)\.?{$root_domain}$#",$this_domain,$match)) {
        $permalink = str_replace("http://{$match[1]}.",'http://',$permalink);
    }
    return $permalink;
}
add_filter('page_link','multi_subdomain_permalink');
add_filter('post_link','multi_subdomain_permalink');
add_filter('term_link','multi_subdomain_permalink');
add_filter('tag_link','multi_subdomain_permalink');
add_filter('category_link','multi_subdomain_permalink');
add_filter('post_type_link','multi_subdomain_permalink');
add_filter('attachment_link','multi_subdomain_permalink');
add_filter('year_link','multi_subdomain_permalink');
add_filter('month_link','multi_subdomain_permalink');
add_filter('day_link','multi_subdomain_permalink');
add_filter('search_link','multi_subdomain_permalink');

add_filter('feed_link','multi_subdomain_permalink');
add_filter('post_comments_feed_link','multi_subdomain_permalink');
add_filter('author_feed_link','multi_subdomain_permalink');
add_filter('category_feed_link','multi_subdomain_permalink');
add_filter('taxonomy_feed_link','multi_subdomain_permalink');
add_filter('search_feed_link','multi_subdomain_permalink');

add_filter('get_edit_tag_link','multi_subdomain_permalink');
add_filter('get_edit_post_link','multi_subdomain_permalink');
add_filter('get_delete_post_link','multi_subdomain_permalink');
add_filter('get_edit_comment_link','multi_subdomain_permalink');
add_filter('get_edit_bookmark_link','multi_subdomain_permalink');

add_filter('index_rel_link','multi_subdomain_permalink');
add_filter('parent_post_rel_link','multi_subdomain_permalink');
add_filter('previous_post_rel_link','multi_subdomain_permalink');
add_filter('next_post_rel_link','multi_subdomain_permalink');
add_filter('start_post_rel_link','multi_subdomain_permalink');
add_filter('end_post_rel_link','multi_subdomain_permalink');

add_filter('previous_post_link','multi_subdomain_permalink');
add_filter('next_post_link','multi_subdomain_permalink');

add_filter('get_pagenum_link','multi_subdomain_permalink');
add_filter('get_comments_pagenum_link','multi_subdomain_permalink');
add_filter('shortcut_link','multi_subdomain_permalink');
add_filter('get_shortlink','multi_subdomain_permalink');

add_filter('home_url','multi_subdomain_permalink');
add_filter('site_url','multi_subdomain_permalink');
add_filter('admin_url','multi_subdomain_permalink');
add_filter('includes_url','multi_subdomain_permalink');
add_filter('content_url','multi_subdomain_permalink');
add_filter('plugins_url','multi_subdomain_permalink');

add_filter('network_site_url','multi_subdomain_permalink');
add_filter('network_home_url','multi_subdomain_permalink');
add_filter('network_admin_url','multi_subdomain_permalink');

While brings us to the final point. There is functionality in WordPress that attempts to ensure every URL that is loaded is served via its canonical URL which in general is a web best practice, especially if you are concerned with optimizing search engine results on Google and other search engines. In your case, however, if you really do not want WordPress to redirect to your canonical URL then you need to add a redirect_canonical filter hook and tell WordPress not to do it.

What follows is the code to make sure any page that serves as "x.domain.com" stays on "x.domain.com" even if all the URLs are filtered to be "domain.com". That may not be the exact logic you need but I'm just showing you the building blocks of WordPress so you'll be able to figure out the logic that you require.

A few final details about this function call; parameters #3 and #4 refer respectively to the priority (10 is standard priority so this hook will not be handled special) and the number of function arguments (the 2 arguments are $redirect_url and $requested_url.) The other thing to note is that returning false instead of a valid URL cancels the canonical redirect:

add_filter('redirect_canonical','multi_subdomain_redirect_canonical',10,2);
function multi_subdomain_redirect_canonical($redirect_url,$requested_url){
    $redirect = parse_url($redirect_url);
    $requested = parse_url($requested_url);
    // If the path+query is the same for both URLs, Requested and Redirect, and
    if ($redirect['path']+$redirect['query']==$requested['path']+$requested['query']) {
            // If Requested URL is a subdomain of the Redirect URL
        if (preg_match("#^([a-zA-Z0-9]+).{$redirect['host']}$#",$requested['host'])) {
            $redirect_url = false;  // Then cancel the redirect
        }
    }
    return $redirect_url;
}

That's about it. Hope this helps.

-Mike

like image 145
MikeSchinkel Avatar answered Jan 31 '23 10:01

MikeSchinkel