Retrieves the full permalink for the current post or post ID.
Parameters
$post
int|WP_Postoptional- Post ID or post object. Default is the global
$post
. $leavename
booloptional- Whether to keep post name or page name.
Default:
false
Source
function get_permalink( $post = 0, $leavename = false ) {
$rewritecode = array(
'%year%',
'%monthnum%',
'%day%',
'%hour%',
'%minute%',
'%second%',
$leavename ? '' : '%postname%',
'%post_id%',
'%category%',
'%author%',
$leavename ? '' : '%pagename%',
);
if ( is_object( $post ) && isset( $post->filter ) && 'sample' === $post->filter ) {
$sample = true;
} else {
$post = get_post( $post );
$sample = false;
}
if ( empty( $post->ID ) ) {
return false;
}
if ( 'page' === $post->post_type ) {
return get_page_link( $post, $leavename, $sample );
} elseif ( 'attachment' === $post->post_type ) {
return get_attachment_link( $post, $leavename );
} elseif ( in_array( $post->post_type, get_post_types( array( '_builtin' => false ) ), true ) ) {
return get_post_permalink( $post, $leavename, $sample );
}
$permalink = get_option( 'permalink_structure' );
/**
* Filters the permalink structure for a post before token replacement occurs.
*
* Only applies to posts with post_type of 'post'.
*
* @since 3.0.0
*
* @param string $permalink The site's permalink structure.
* @param WP_Post $post The post in question.
* @param bool $leavename Whether to keep the post name.
*/
$permalink = apply_filters( 'pre_post_link', $permalink, $post, $leavename );
if (
$permalink &&
! wp_force_plain_post_permalink( $post )
) {
$category = '';
if ( str_contains( $permalink, '%category%' ) ) {
$cats = get_the_category( $post->ID );
if ( $cats ) {
$cats = wp_list_sort(
$cats,
array(
'term_id' => 'ASC',
)
);
/**
* Filters the category that gets used in the %category% permalink token.
*
* @since 3.5.0
*
* @param WP_Term $cat The category to use in the permalink.
* @param array $cats Array of all categories (WP_Term objects) associated with the post.
* @param WP_Post $post The post in question.
*/
$category_object = apply_filters( 'post_link_category', $cats[0], $cats, $post );
$category_object = get_term( $category_object, 'category' );
$category = $category_object->slug;
if ( $category_object->parent ) {
$category = get_category_parents( $category_object->parent, false, '/', true ) . $category;
}
}
/*
* Show default category in permalinks,
* without having to assign it explicitly.
*/
if ( empty( $category ) ) {
$default_category = get_term( get_option( 'default_category' ), 'category' );
if ( $default_category && ! is_wp_error( $default_category ) ) {
$category = $default_category->slug;
}
}
}
$author = '';
if ( str_contains( $permalink, '%author%' ) ) {
$authordata = get_userdata( $post->post_author );
$author = $authordata->user_nicename;
}
/*
* This is not an API call because the permalink is based on the stored post_date value,
* which should be parsed as local time regardless of the default PHP timezone.
*/
$date = explode( ' ', str_replace( array( '-', ':' ), ' ', $post->post_date ) );
$rewritereplace = array(
$date[0],
$date[1],
$date[2],
$date[3],
$date[4],
$date[5],
$post->post_name,
$post->ID,
$category,
$author,
$post->post_name,
);
$permalink = home_url( str_replace( $rewritecode, $rewritereplace, $permalink ) );
$permalink = user_trailingslashit( $permalink, 'single' );
} else { // If they're not using the fancy permalink option.
$permalink = home_url( '?p=' . $post->ID );
}
/**
* Filters the permalink for a post.
*
* Only applies to posts with post_type of 'post'.
*
* @since 1.5.0
*
* @param string $permalink The post's permalink.
* @param WP_Post $post The post in question.
* @param bool $leavename Whether to keep the post name.
*/
return apply_filters( 'post_link', $permalink, $post, $leavename );
}
Hooks
- apply_filters( ‘post_link’,
string $permalink ,WP_Post $post ,bool $leavename ) Filters the permalink for a post.
- apply_filters( ‘post_link_category’,
WP_Term $cat ,array $cats ,WP_Post $post ) Filters the category that gets used in the %category% permalink token.
- apply_filters( ‘pre_post_link’,
string $permalink ,WP_Post $post ,bool $leavename ) Filters the permalink structure for a post before token replacement occurs.
Changelog
Version | Description |
---|---|
1.0.0 | Introduced. |
Get post or page (or whatever) permalink by slug:
If you are using polylang (like I usually do), you can get the permalink starting from whichever language slug (I generally start from my language, usually the websites’s default):
Default Usage
The permalink for current post (used within The Loop). As the tag does not display the permalink, the example uses the PHP echo command.
Permalink for this post:
Pass in a post object instead of an ID
This shows how you can you can get the permalink with the page title instead of the ID.
Link to Specific Post
Returns the permalinks of two specific posts (post IDs 1 and 10) as hypertext links within an informational list.
Get current post/page url outside loop. $post is a global variable.
Return the permalink of the post, then search for http://www.mysite.com/ and change it to http://www.yoursite.com/
Example: Woocommerce shop page permalink
Redirect to a page with page ID:
Get permalink for a page parent from current child page (using within the loop):
get_the_ID
: get id of current page.wp_get_post_parent_id
: get the parent page id of the current page.Get page permalink by its template slug:
You can call the function anywhere in your theme like this:
Note: the function only retreives the first page that uses the given template. I wrote it to get the url for my shopping cart, and the like, obviously these are used only once. I have modified my templates dropdown so that it won’t show certain templates if they have been used in any other post. If you want to get all the posts that use the given template, modify the function like this:
Another use of permalink can be
For security measure be sure to use:
Example:
See https://developer.wordpress.org/plugins/security/securing-output/
esc_url()
are incorrect in the example. The second parameter should be the allowed protocols (http
,https
, etc), and the third parameter is the context (ex: ‘display’), not the text domain.