Retrieving the current page URL in WordPress might seem like a straightforward task, but it often leads to unexpected results. Many developers reach for get_permalink(), only to realize it behaves inconsistently depending on where it is called.
If you are inside the WordPress Loop, get_permalink() returns the URL of the current post being processed. However, if you are on a homepage displaying multiple posts, a category archive, or a search results page, this function may return the URL of the last post in the list rather than the actual page URL shown in the browser address bar.
In this guide, we will explore the most reliable ways to get the current URL in WordPress, handling query strings, permalink structures, and edge cases.
1. Using the Global $wp Object (Recommended)
The most robust way to get the current path in WordPress is by using the global $wp object. This object contains the request information that WordPress processed to load the current page.
By combining $wp->request with the home_url() function, you can reconstruct the full URL accurately. This method is generally preferred because it stays within the WordPress ecosystem and respects your site settings.
global $wp;
// Ensure the request is parsed
$wp->parse_request();
// Get the home URL and append the request path
$current_url = home_url( $wp->request );
echo $current_url;
Note: In some recent versions of WordPress or specific server configurations, the $wp->request property might be empty if called too early in the execution cycle. Calling $wp->parse_request() ensures the property is populated before you use it.
2. Handling Query Parameters and URL Arguments
The standard $wp->request method typically returns the "clean" URL (e.g., example.com/my-page/). If your site uses query strings for filtering, tracking, or pagination (e.g., example.com/my-page/?color=blue), those parameters will be lost.
To preserve these query variables, you should use the add_query_arg() function. This is particularly useful for search pages or custom product filters.
global $wp;
// Get the current URL including query strings
$current_url = add_query_arg( $wp->query_vars, home_url( $wp->request ) );
echo $current_url;
If you want a more manual approach to include the standard PHP $_GET variables, you can use this snippet:
global $wp;
$current_url = home_url( add_query_arg( array( $_GET ), $wp->request ) );
echo $current_url;
3. The "Queried Object" Approach
WordPress provides a powerful function called get_queried_object(). This function returns the object currently being queried—whether it is a single post, a category, an author, or a post type archive.
This is often the "cleanest" way to get a URL because it uses WordPress's built-in logic to determine exactly what the user is looking at.
$queried_object = get_queried_object();
if ( is_singular() ) {
$current_url = get_permalink( $queried_object->ID );
} elseif ( is_category() || is_tag() || is_tax() ) {
$current_url = get_term_link( $queried_object );
} elseif ( is_post_type_archive() ) {
$current_url = get_post_type_archive_link( $queried_object->name );
}
echo $current_url;
This method is highly reliable for SEO purposes because it returns the "canonical" version of the URL, avoiding issues with duplicate content caused by tracking parameters.
4. The Native PHP Fallback
Sometimes, you might need the URL exactly as the server sees it, regardless of WordPress logic. In these cases, you can use the standard PHP $_SERVER global. This is useful if you are working in a hybrid environment or a script that loads before WordPress is fully initialized.
function get_wp_current_url_raw() {
$protocol = is_ssl() ? 'https://' : 'http://';
return $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
echo get_wp_current_url_raw();
While effective, use this with caution. It doesn't sanitize the output automatically, and it may behave differently across various hosting environments (like those using reverse proxies or load balancers).
5. Accounting for Permalink Settings
Your WordPress permalink settings (found under Settings > Permalinks) change how URLs are structured. If you are using "Plain" permalinks (e.g., ?p=123), the $wp->request property might behave differently than with "Post name" settings.
To create a function that handles both scenarios and ensures trailing slashes are handled correctly, you can use this logic:
function get_smart_current_url() {
global $wp;
$permalink_structure = get_option('permalink_structure');
if ( empty( $permalink_structure ) ) {
// Handle Plain Permalinks
return home_url( add_query_arg( array(), $wp->request ) );
} else {
// Handle Pretty Permalinks and ensure trailing slash
return home_url( trailingslashit( $wp->request ) );
}
}
Frequently Asked Questions
Why does get_permalink() return the wrong URL on my blog page?
get_permalink() is designed to work within "The Loop." If you are on a page that lists multiple posts, the function will return the link for the specific post currently being processed by the loop. To get the URL of the main archive page itself, use home_url( $wp->request ) instead.
How do I get the current URL in a Multisite environment?
All the methods mentioned above using home_url() or $wp->request are multisite-compatible. WordPress will automatically use the base URL of the specific sub-site you are currently viewing.
Is it safe to echo $_SERVER['REQUEST_URI'] directly?
No. You should always wrap URLs in esc_url() before outputting them to the screen to prevent Cross-Site Scripting (XSS) attacks. For example: echo esc_url( home_url( $wp->request ) );.
Wrapping Up
Choosing the right method to get the current URL depends entirely on your specific needs:
- For standard theme development, using global $wp is the most reliable.
- For SEO and canonical links, get_queried_object() is the superior choice.
- For raw server requests, use the $_SERVER global with proper escaping.
By understanding how WordPress handles requests, you can ensure your navigation, social sharing buttons, and custom redirects always point to the correct location.