Get URL of any PHP file in WordPress

Getting URL of the current page or current PHP file is a very common task. And that is not exceptional in WordPress. For example: when you include a plugin in a theme or using LESS PHP compiler. There're some available techniques, but I found that all of them are not good enough to work in all situation, so I hope what I write in this post is a better approach.

Let's look at these methods before getting to the final solution:

1. Get current URL via $wp->request This technique is introduced by Konstantin Kovshenin. It uses $wp->request and $wp->query_string to get current URL of a page in the front end global$wp;
$url = add_query_arg($wp->query_string, '', home_url( $wp->request ) ); It's good enough if you only want URL for the current page and on the front end. It doesn't help if you want to have URL to a plugin file. An updated version of this technique by Stephen Harris: global$wp;
$url = home_url( add_query_arg( [],$wp->request ) );

2. Get URL of current PHP file, common approach

$url = @$_SERVER['HTTPS'] == 'on' ? 'https://' : 'http://';
if ( $_SERVER['SERVER_PORT'] != '80' ) {$url .= $_SERVER['HTTP_HOST'] . ':' .$_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI']; } else {$url .= $_SERVER['HTTP_HOST'] .$_SERVER['REQUEST_URI'];
}

Or in WordPress way:

$current_url = set_url_scheme( 'http://' .$_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); This also works quite well. The logic is similar to 1st method, it based on request URI, server name. But it has only one disadvantage: this method work only with current requested PHP file. And that totally fails if you want to get URL to a plugin of WordPress (you probably never access to plugin PHP file directly, right?) 3. Replace WP_CONTENT_DIR by WP_CONTENT_URL The logic is simple: all our PHP files are located in wp-content dir, thus replacing WP_CONTENT_DIR by WP_CONTENT_URL is a good hope to get correct URL: $file = __FILE__; // Current PHP file, but can be anyone
$url = str_replace( WP_CONTENT_DIR, WP_CONTENT_URL,$file );

Of course, this is very simple and works in most cases. These 2 variables are initialized when WordPress is loaded. We don't need to consider about server path, server request, query string list 1st and 2nd methods. Safe enough.

But there're 2 problems with this method:

• In Windows environment, due to inconsistent of using backward slash (/) and forward slash (\) in the path by WordPress (see how it defines these constants without considering this problem), the function doesn't return correct URL.

Test code:

add_action( 'init', function () {
$file = __FILE__;$url = str_replace( WP_CONTENT_DIR, WP_CONTENT_URL, $file ); echo '<pre>', '__FILE__ : ' .$file . '<br>',
'WP_CONTENT_DIR: ' . WP_CONTENT_DIR . '<br>',
'WP_CONTENT_URL: ' . WP_CONTENT_URL . '<br>',
'URL           : ' . $url . '<br>', '</pre>' ; die; } ); Result: __FILE__ : D:\Dropbox\UniServer\www\wp\wp-content\mu-plugins\test.php WP_CONTENT_DIR: D:\Dropbox\UniServer\www\wp/wp-content WP_CONTENT_URL: http://localhost:8080/wp/wp-content URL : D:\Dropbox\UniServer\www\wp\wp-content\mu-plugins\test.php • Second problem comes from Multisite environment with Domain Mapping plugin installed. Because the constant WP_CONTENT_URL is defined via function get_option( 'siteurl' ), it doesn't give you the correct URL to wp-content folder in sub-site. Assume we have a multisite with main domain test.com, and a sub-site with domain exam.com. If we run the same test code as above, we'll see this results: On the main site (correct): __FILE__ : /var/home/testuser/www/test.com/wp-content/mu-plugins/test.php WP_CONTENT_DIR: /var/home/testuser/www/test.com/wp-content WP_CONTENT_URL: http://test.com/wp-content URL : http://test.com/wp-content/mu-plugins/test.php On a sub-site (incorrect): __FILE__ : /var/home/testuser/www/test.com/wp-content/mu-plugins/test.php WP_CONTENT_DIR: /var/home/testuser/www/test.com/wp-content WP_CONTENT_URL: http://test.com/exam/wp-content URL : http://test.com/exam/wp-content/mu-plugins/test.php 4. Final (working) solution: If you run your site in Linux environment and not in Multisite mode, you can use the 3rd method above. It's short and works like a charm! But if you want a solution that works in all situation, try this: $file = __FILE__;

// Get correct URL and path to wp-content
$content_url = untrailingslashit( dirname( dirname( get_stylesheet_directory_uri() ) ) );$content_dir = untrailingslashit( WP_CONTENT_DIR );

// Fix path on Windows
$file = wp_normalize_path($file );
$content_dir = wp_normalize_path($content_dir );

$url = str_replace($content_dir, $content_url,$file );

Basically, this solution is an additional version of 3rd method above with 2 fixes mentioned. Please try this, and if you have any suggestion or idea, please let me know via comments!