139

I want to add custom PHP code to ensure that whenever a page on my site loads in my browser, the URL of that page is echoed to the screen. I can use echo get_permalink(), but that does not work on all pages. Some pages (e.g. my homepage) display several posts, and if I use get_permalink() on these pages, the URL of the displayed page is not returned (I believe it returns the URL of the last post in the loop). For these pages, how can I return the URL?

Can I attach get_permalink() to a particular hook that fires before the loop is executed? Or can I somehow break out of the loop, or reset it once it is complete?

Thanks.

5
  • Can you provide some context as to what you would want to do with this URL? Are you trying to create sharable URLs? Assemble custom URLs for links/actions?
    – Tom J Nowell
    Commented Jul 25, 2017 at 12:19
  • @TomJNowell I would like to enqueue a particular JS script, but only on certain pages (in this case, those pages are the homepage of my site in various languages: example.com, example.com/fr, example.com/es, etc). The JS file will server to add hyperlinks to several titles that appear only on the homepage.
    – cag8f
    Commented Jul 25, 2017 at 16:03
  • why not just use is_home() or is_page( 'fr' ) etc and only enqueue the script if it's true?
    – Tom J Nowell
    Commented Jul 25, 2017 at 16:15
  • @TomJNowell Well now my code is if ( home_url( $wp->request ) == home_url() ) { wp_enqueue_script();} This appears to fire on every home page, regardless of language. Is that what you were suggesting?
    – cag8f
    Commented Jul 26, 2017 at 5:32
  • 3
    Why not use $_SERVER['REQUEST_URI'] and company? See this question: stackoverflow.com/q/6768793/247696
    – Flimm
    Commented May 29, 2019 at 13:07

15 Answers 15

232

get_permalink() is only really useful for single pages and posts, and only works inside the loop.

The simplest way I've seen is this:

global $wp;
echo home_url( $wp->request )

$wp->request includes the path part of the URL, eg. /path/to/page and home_url() outputs the URL in Settings > General, but you can append a path to it, so we're appending the request path to the home URL in this code.

Note that this probably won't work with Permalinks set to Plain, and will leave off query strings (the ?foo=bar part of the URL).

To get the URL when permalinks are set to plain you can use $wp->query_vars instead, by passing it to add_query_arg():

global $wp;
echo add_query_arg( $wp->query_vars, home_url() );

And you could combine these two methods to get the current URL, including the query string, regardless of permalink settings:

global $wp;
echo add_query_arg( $wp->query_vars, home_url( $wp->request ) );
11
  • 15
    If permalinks set to plain: echo '//' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];.
    – Max Yudin
    Commented Jul 25, 2017 at 12:18
  • 3
    @Jacob I tried that, but it seems to be returning the URL of my homepage only. As you can see in the top left on this page (dev.horizonhomes-samui.com/properties/hs0540), where I have inserted code to echo home_url( $wp->request ). I have ensured to include global $wp as well. Permalinks are not 'Plain,' but set to 'Post Name.' I don't see any relevant PHP errors in the log either. This particular page is part of my dev site, which is otherwise blocked off to visitors. I'm not sure if that matters or not. edit: Actually, hold that thought--could be user error. Stand by...
    – cag8f
    Commented Jul 25, 2017 at 16:14
  • 2
    @Jacob edit 2: OK your code does indeed work. My issue was that I was including the code in functions.php 'naked,' i.e. not in any function that is attached to a hook. So your code was returning the URL of the homepage, regardless of the page that was displayed in my browser. Once I moved the code inside a function--a function attached to a WP hook (wp_enqueue_scripts), it did indeed return the URL of the displayed page. Do you know the reason for that behavior? Maybe I need to create a new question for that.
    – cag8f
    Commented Jul 25, 2017 at 16:20
  • 5
    @cag8f If the code sits "naked" in functions.php then you are running it before all the properties of the $wp object have been set up. When you wrap it in a function attached to an appropriate hook then you are delaying its execution until a suitable point in the Wordpress code run. Commented Apr 5, 2018 at 11:28
  • 1
    These methods are all awesome, and great ideas for working with WordPress. You might add trailingslashit() to them though, depending on your needs.
    – Jake
    Commented Oct 17, 2019 at 22:56
31

You may use the below code to get the whole current URL in WordPress:

global $wp;
$current_url = home_url(add_query_arg(array(), $wp->request));

This will show the full path, including query parameters.

5
  • Hi - if you have a look at developer.wordpress.org/reference/functions/add_query_arg you'll see that your code doesn't actually preserve existing query parameters. Commented Apr 5, 2018 at 10:55
  • 15
    To preserve query parameters you'd need to replace the empty array() with $_GET. ie: home_url(add_query_arg($_GET,$wp->request));
    – Brad Adams
    Commented Jun 14, 2018 at 12:48
  • It won’t work if WordPress is installed in subdirectory Commented Nov 26, 2018 at 12:01
  • 1
    @BradAdams the answer wasnt working for me until I saw your comment about the empty array. Thanks!
    – 730wavy
    Commented Dec 9, 2022 at 1:08
  • the Brad Adams comment code unfortuntaely doesn't add a trailing slash to the request so your perma would end like /foo instead of /foo/
    – DrLightman
    Commented Mar 20 at 13:49
21

Why not just use?

get_permalink( get_the_ID() );

That is for single pages.

For category pages, use this:

get_category_link( get_query_var( 'cat' ) );

Simple script to get the current URL of any page:

// get current URL 
$current_url = get_permalink( get_the_ID() );
if( is_category() ) $current_url = get_category_link( get_query_var( 'cat' ) );
echo $current_url;
      
5
  • 3
    +1 all other answers are much to complicated, this is just the simplest solution
    – Mark
    Commented Apr 16, 2020 at 13:37
  • 1
    This is the easiest way. +1 Commented May 23, 2020 at 18:30
  • doesn't work with blog categories on my site
    – Iggy
    Commented Jun 21, 2020 at 14:04
  • 3
    Only works for single posts and pages though. Commented Mar 12, 2021 at 14:17
  • This does not include URL parameters.
    – GeorgeP
    Commented Apr 19, 2022 at 12:14
20

In my case, this code worked fine:

$current_url = home_url($_SERVER['REQUEST_URI'])

I hope it will help someone, I tried all answers but this one was helpful.

1
  • This solution doesn't work for subdirectory installs. When the home_url is s.b/hm and REQUEST_URI is /hm/current_url/ then the value becomes https://s.b/hm/hm/current_url. The install directory is repeated. Commented Feb 2 at 17:05
12

The following code will give the current URL:

global $wp;
echo home_url($wp->request)

You can use the below code to get the full URL along with query parameters.

global $wp;  
$current_url = home_url(add_query_arg(array($_GET), $wp->request));

This will show the full path, including query parameters. This will preserve query parameters if already in the URL.

3
  • This snippet skips wp-admin/plugins.php in my current URL, it's only the root path and query strings. Commented Aug 3, 2019 at 1:25
  • Close! The trailing slash was missing, and thus causes a quick redirect to add it when WP parses it out, which gets a small SEO ding, so I added it below. So far this creates the exact URL global $wp; $current_url = home_url(add_query_arg(array($_GET), $wp->request . '/')); Commented Mar 19, 2021 at 2:32
  • @ShaneMcCurdy I guess you could also use trailingslashit() (see Jake's comment above) Commented May 26, 2021 at 15:19
5

The solutions here are all good but were not consistent with both local and remote server environments. So I came up with a simpler neat solution that works better regardless of the WordPress permalink settings.

function getCurrentUrl() {
    $protocol = is_ssl() ? 'https://' : 'http://';
    return ($protocol) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
$currentUrl = getCurrentUrl();
echo $currentUrl;

The output will include URL query parameters and slugs.

3
function current_location()
{
    if (isset($_SERVER['HTTPS']) &&
        ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
        isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
        $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
        $protocol = 'https://';
    } else {
        $protocol = 'http://';
    }
    return $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}

echo current_location();
2
  • Can you explain how and why this code solves the question?
    – kero
    Commented Nov 29, 2018 at 11:29
  • In my opinion the most flexible solution. It works on any WP page (even on wp-admin, wp-login.php, archive pages, etc). Just notice, that it does not include any URL params
    – Philipp
    Commented Apr 1, 2019 at 16:09
3
global $wp;
$wp->parse_request();
$current_url = home_url($wp->request);
3
  • 1
    Always try and include a bit of an explanation with your answer so the OP gets a better understanding of what's happening. That way we all end up learning and the community grows. :-) Commented Jan 13, 2021 at 2:13
  • Aye, eight years later I'm still baffled how this works, and where you should use it (naked? inside a hook? a filter? the loop?... we have no idea). Commented May 26, 2021 at 15:17
  • I like that firing wp::parse_request() works for catching endpoints in the URL. That's just neat.
    – Howdy_McGee
    Commented Sep 28, 2021 at 20:40
2

This is what worked for me (short and clean solution that includes the query strings in the URL too):

$current_url = add_query_arg( $_SERVER['QUERY_STRING'], '', home_url( $wp->request ) );

The output URL will look like below

http://sometesturl.test/slug1/slug2?queryParam1=testing&queryParam2=123

The solution was taken from here

1

This is an improved way of example that mentioned previously. It works when pretty URLs are enabled however it discards if there is any query parameter like /page-slug/?param=1 or URL is ugly at all.

Following example will work on both cases.

    $query_args = array();

    $query = wp_parse_url( $YOUR_URL );

    $permalink = get_option( 'permalink_structure' );

    if ( empty( $permalink ) ) {

        $query_args = $query['query'];

    }

    echo home_url( add_query_arg( $query_args , $wp->request ) )
1

Maybe wp_guess_url() is what you need. Available since version 2.6.0.

1
  • This just guesses the base URL. On the frontend, you end up with a similar effect to home_url().
    – Jake
    Commented Oct 17, 2019 at 22:54
1

After so much research of a simple task, a mix of all answers above works for us:

function get_wp_current_url(){
    global $wp;
    if('' === get_option('permalink_structure')) return home_url(add_query_arg(array($_GET), $wp->request));
        else return home_url(trailingslashit(add_query_arg(array($_GET), $wp->request)));
}

No missing slash at the end and so on. As the question id about output the current url, this doesnt care about security and stuff. However, hash like #comment at the end cant be found in PHP.

1

I realize this is an old question, however one thing I've noticed is no-one mentioned using get_queried_object().

It's a global wp function that grabs whatever relates to the current url you're on. So for instance if you're on a page or post, it'll return a post object. If you're on an archive it will return a post type object.

WP also has a bunch of helper functions, like get_post_type_archive_link that you can give the objects post type field to and get back its link like so

get_post_type_archive_link(get_queried_object()->name);

The point is, you don't need to rely on some of the hackier answers above, and instead use the queried object to always get the correct url.

This will also work for multisite installs with no extra work, as by using wp's functions, you're always getting the correct url.

2
  • Hm. Possibly there might just be the issue of not having a universal way of specifying all kinds of possible objects. In other words, things like get_post_type_archive_link() work great if you know, in advance, that you have an archive link. Thus, you'll still need to figure out what kind of object you have before using a specific helper function on it. As WP gets more and more object types, you need to have more code to deal with each individual case separately... Commented May 26, 2021 at 15:16
  • get_queried_object ALWAYS contains information that can be leveraged to ascertain what type of Wordpress object it is. This includes post archives. This is easy enough to test. Simply try viewing the results of the method call in each template type, and you will gain a better understanding of what I mean. Commented May 27, 2021 at 21:28
1

WP updated something and now the property request of the global $wp is empty by default. You must call the special method parse_request before to get data of this property.

So it was this way:

global $wp;
echo home_url( $wp->request );

Now it should be the next way:

global $wp;
$wp->parse_request();
echo home_url( $wp->request );

P.S. I'd like to leave in comments under the most popular response, but I don't permissions to leave comments.

2
  • But parse_request should already be called by $wp->main() at the bottom of that file.
    – Rup
    Commented Nov 1, 2021 at 10:34
  • Yeap, maybe, but probably some plugin broke it and my class stopped to work correct, because $wp->request just returned an empty string. So safely to use $wp->parse_request() to asure that $wp->request is correct.
    – Ivan Ivan
    Commented Dec 3, 2021 at 22:48
0

Might be late but for whoever it might help, get_page_link() should do the trick. If you want only the uri of the page get_page_uri() is the perfect helper.

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.