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:
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 ) );
Get URL of current PHP file, common approach
There're several tutorials on the Internet about this technique, all of them are similar to this:
$is_https = isset( $_SERVER['HTTPS'] ) && ( $_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1 )
|| isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https';
$url = $is_https ? '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 the 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?)
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 any.
$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
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!
Leave a Reply