the situation :

my settings > permalinks are sets on post name, but sometimes anyway a post url is using the query post id :

https://my_website.com/?p=4348 instead of https://my_website.com/my_post

I identified in which situation it happens : when the post status is draft instead of publish. I let the connected users see their page in draft, but in this case the url does not uses the post_name anymore, but a query with the post_id.

the problem :

I want to be safe from this when I'm in production, here is the problem it causes :

On posts i have links like <a href="?action=my_action"></a>, they are supposed to produce this kind of url :


but instead, if the page url was using the query and not the post_name, i get this url :


because the new query replace the previous one. So i loose the information of the page on which I want to execute the action.

solutions ?

I cannot dynamically create the link to add the information in the query for example (I'm not the one creating the front, and the links are created with a front builder, divi)

I've tried to get the current url, check if it uses the wrong pattern, and in that case redirect to the right pattern, but I could not. First I created the right url with home_url('path/'.$post->post_name), then i wanted to compare it to the current url, but I could not reliably find it ? I've tried with get_permalink();, global $wp; $wp->request;, and get_query_vars(), but it failed.

I also tried to check from which page the url comes, but i use the request referer for that and I think I cannot rely on it ? Anyway this option is not optimal since sometime i cannot differentiate the action by the page i come from, in case there is action on both pages.

1 Answer 1


I found two possible solutions to my problem :

1. the link to the post should not use permalink

the problem is actually that a draft post has a permalink with its post_id instead of post_name, as explained here : How to make draft posts or posts in review accessible via full url / slug?

so, in my case i could find where the link is generated, and it was getting the link with get_permalink() which will return the url with post_id if the post is a draft. So instead i now use home_url($post->post_name) to redirect to the post with an url with post_name : https://my_website.com/my_page

2. redirect the page to it's version without post_id

additionally, on the post i use the template_redirect hook to check if the current uri match the post_name (after a bunch of tests to check if I'm on the right post), if not I redirect the page to the url with post_name :

function check_url_for_post_id() {
  if (!is_my_post()) {

  $post_id = get_the_ID();
  $current_post = get_post($post_id);
  if (is_null($current_post)) {
  $current_slug = trim($_SERVER['REQUEST_URI'], '/');
  $slug = trim($current_post->post_name, '/');

  if ($slug !== $current_slug) {
add_action('template_redirect', 'check_url_for_post_id');

So i'm using $_SERVER and I don't know if it's safe ? on this question, some people said we should not use $_GET and $_POST, and I suppose also not $_REQUEST or $_SERVER because they are vulnerable to attacks : https://stackoverflow.com/questions/13652605/extracting-a-parameter-from-a-url-in-wordpress

anyway, I suppose that in my case it's ok, since I only use it for comparison, I don't use it's content otherwise

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.