To get the current page slug in WordPress with PHP, use get_post_field( 'post_name', get_the_ID() ). WordPress stores the slug as post_name in the database, and this single function returns it for any post, page, or custom post type:
// Slug of the current post or page
$slug = get_post_field( 'post_name', get_the_ID() );
// Slug of a specific post by ID
$slug = get_post_field( 'post_name', 42 );
echo esc_html( $slug );
Below I’ll cover every common variation: getting a slug from the global $post object, getting the slug from an archive/term page, finding a post by its slug (a different and very common need), getting category or taxonomy slugs, generating slugs programmatically, and ensuring a slug is unique. A WordPress slug is just the URL-friendly version of a title (Hello World → hello-world), but it shows up in more places than people realize.
Method 1: Get the slug with get_post_field()
This is the cleanest approach. get_post_field() reads straight from the database and works anywhere: inside the loop, inside a custom WP_Query, in an AJAX handler, or in a REST API callback.
// Current post/page
$slug = get_post_field( 'post_name', get_the_ID() );
// Specific post by ID
$slug = get_post_field( 'post_name', 42 );
// Inside a custom loop with WP_Query
while ( $query->have_posts() ) {
$query->the_post();
$slug = get_post_field( 'post_name', get_the_ID() );
echo esc_html( $slug );
}
wp_reset_postdata();
Always esc_html() the output when rendering it on the page. Even though WordPress normalizes slugs to lowercase ASCII, it’s a habit worth keeping for all database-sourced strings.
Method 2: Use the global $post object
Inside the main loop or any template file where the global $post is already set up, you can read the slug off the object directly:
global $post;
$slug = $post->post_name;
echo esc_html( $slug );
It’s fast and readable, but it has one catch: the global $post isn’t always set (AJAX calls, admin pages, custom WP_Query loops without wp_reset_postdata). When in doubt, fall back to Method 1.
Method 3: Get the slug from the queried object
get_queried_object() returns whatever WordPress is currently rendering (a post, a term, a user, a post type archive). It’s the most universal way to get the current slug because it works on both single posts and archive pages:
$queried = get_queried_object();
if ( is_singular() ) {
// Single post/page/CPT
$slug = $queried->post_name;
} elseif ( is_category() || is_tag() || is_tax() ) {
// Taxonomy term archive
$slug = $queried->slug;
} elseif ( is_post_type_archive() ) {
// Custom post type archive
$slug = $queried->rewrite['slug'] ?? $queried->name;
}
Reach for this when you need one snippet that handles every page type your theme renders.
Method 4: Get the slug of the parent page
For hierarchical content (pages with a parent, or custom post types with hierarchical => true), you often want the parent’s slug, not the current page’s:
$parent_id = wp_get_post_parent_id( get_the_ID() );
if ( $parent_id ) {
$parent_slug = get_post_field( 'post_name', $parent_id );
} else {
$parent_slug = null; // this is a top-level page
}
Useful for conditional sidebars, breadcrumb templates, or adding a CSS class that reflects the section a page belongs to.
Method 5: Get a post BY its slug
This is the reverse direction: you have a slug string and need the actual post object (or ID, title, content). Use get_page_by_path(). Despite the name, it works for posts, pages, and any custom post type.
// Get a page by slug (default post type is 'page')
$page = get_page_by_path( 'about-us' );
// Get a post by slug
$post = get_page_by_path( 'my-post-slug', OBJECT, 'post' );
// Get a custom post type by slug
$product = get_page_by_path( 'blue-widget', OBJECT, 'product' );
// Just the ID
$post = get_page_by_path( 'my-post-slug', OBJECT, 'post' );
$post_id = $post ? $post->ID : 0;
The third argument can also be an array of post types (array( 'post', 'page' )) if you want to search across multiple at once. Always check the return value for null before using it, since an invalid slug returns null rather than an error.
Method 6: Get a category, tag, or taxonomy slug
Term objects (categories, tags, custom taxonomies) store their slug in the slug property:
// Get a category slug by ID
$category = get_term( 5, 'category' );
$slug = $category->slug;
// Current category slug on an archive page
$queried = get_queried_object();
$slug = $queried->slug;
// All categories a post belongs to
$categories = get_the_category();
foreach ( $categories as $cat ) {
echo esc_html( $cat->slug );
}
// All tags a post belongs to
$tags = get_the_tags();
foreach ( $tags as $tag ) {
echo esc_html( $tag->slug );
}
For custom taxonomies, swap get_the_category() / get_the_tags() for get_the_terms( $post_id, 'your_taxonomy' ).
Method 7: Generate a slug from a string
Building custom URLs, inserting posts programmatically, or creating unique IDs from user input? sanitize_title() is the same function WordPress uses internally when it generates a slug from a post title:
$slug = sanitize_title( 'My Blog Post Title!' );
// Returns: my-blog-post-title
$slug = sanitize_title( 'Déjà vu & other words' );
// Returns: deja-vu-other-words
It lowercases, transliterates accented characters, replaces whitespace with hyphens, and strips characters that aren’t URL-safe.
If the slug is going into a database query (for example, matching against post_name), use sanitize_title_for_query() instead. It’s slightly more aggressive about character handling to guarantee the result matches what WordPress stores.
Method 8: Make sure a generated slug is unique
If you’re programmatically inserting posts (via wp_insert_post() or a custom import), WordPress handles slug uniqueness automatically. If you need the unique slug in advance (for example, to display a preview URL before saving), use wp_unique_post_slug():
$desired_slug = sanitize_title( $user_input_title );
$unique_slug = wp_unique_post_slug(
$desired_slug,
0, // post ID (0 for new posts)
'publish', // post status
'post', // post type
0 // parent ID
);
// Returns 'my-title' or 'my-title-2' if 'my-title' is already taken
Frequently asked questions
How do I get the current page slug in WordPress?
Use get_post_field( 'post_name', get_the_ID() ). WordPress stores the slug in the post_name database column, and this one line works for posts, pages, and custom post types. Inside the loop, you can also read it from the global $post object as $post->post_name.
How do I get a post by its slug in WordPress?
Use get_page_by_path( 'your-slug', OBJECT, 'post' ). Despite the name, it works for posts, pages, and custom post types. The third argument is the post type (or an array of post types). Check the return value for null before using it, since an invalid slug returns null.
What is the difference between post_name and post_title?
post_title is the human-readable title you see in the admin (“My Blog Post”). post_name is the URL-friendly slug WordPress generates from it (“my-blog-post”). Both live in the wp_posts table. Use get_the_title() for the title and get_post_field( 'post_name', $id ) for the slug.
How do I get the current category slug in WordPress?
On a category archive page, use get_queried_object()->slug. For a specific category by ID, use get_term( $id, 'category' )->slug. For all categories attached to a post, loop through get_the_category() and read each term’s slug property.
How do I generate a WordPress slug from a string?
Use sanitize_title( 'Your String Here' ). It’s the same function WordPress uses internally: it lowercases, transliterates accented characters, replaces spaces with hyphens, and strips characters that aren’t URL-safe. For query matching, use sanitize_title_for_query() to guarantee the result matches what’s stored in the database.
How do I get the slug of the parent page in WordPress?
Combine wp_get_post_parent_id() with get_post_field(): $parent_id = wp_get_post_parent_id( get_the_ID() ); $parent_slug = get_post_field( 'post_name', $parent_id );. If the page is top-level, wp_get_post_parent_id() returns 0, so check that before using the slug.
Why is $post->post_name empty in my code?
Usually because the global $post isn’t set in the context you’re running. This happens in AJAX callbacks, REST API routes, and custom WP_Query loops without wp_reset_postdata(). Fall back to get_post_field( 'post_name', $id ), which doesn’t depend on the global state.
Bottom line
For the current page’s slug, get_post_field( 'post_name', get_the_ID() ) is the one-liner to memorize. For anything that isn’t a singular post (archives, term pages, CPT archives), use get_queried_object() and read the appropriate property. To go the other direction (slug → post), get_page_by_path() handles all post types. And to generate a slug from a string, sanitize_title() matches WordPress’s own behavior.
Related: how to get a post ID, get the post title, get the current URL, or browse the full WordPress code snippets library.



6 Responses
I found this very useful. Thanks for this.
Thaaaaaank you man
I do what I can ¯\_(ツ)_/¯ 😂
Thank you very much
Worked perfect
Great post! I appreciate how clearly you explained the difference between get_post_field() and using the global $post object to get the slug. The examples were super helpful especially the one showing how to get the slug by post ID. This will definitely come in handy for some custom functionality I'm building in a theme. Looking forward to more WordPress development tips!
Very helpful
I spent hours searching the official WP docs but I found the answer here immediately.
Thank you