I have a custom post type Portfolio and each portfolio is a questionnaire. If I email the link of a portfolio to a client via email.

How can I expire link after 10 minutes, So if client has came after 10 minutes to visit the link Then there should be message that link has expired Please try again.

How can I do that?


Ok I came up with this

add_action( 'wp_loaded', 'my_create_questionnaire_link');
function my_create_questionnaire_link(){

  // this check is for demo, if you go to http://yoursite.demo/?create-my-link, you will get your unique url added to your content
  if( isset( $_GET['create-my-link'] ) ){

    // This filter is for demo purpose
    // You might want to create a button or a special page to generate your
    // unique URL
    add_filter( 'the_content', function( $content ){

      // This is the relevant part
      // This code will create a unique link containing valid period and a nonce

      $valid_period = 60 * 10; // 10 minutes
      $expiry = current_time( 'timestamp', 1 ) + $valid_period; // current_time( 'timestamp' ) for your blog local timestamp
      $url = site_url( '/path/to/your/portfolio/page' );
      $url = add_query_arg( 'valid', $expiry, $url ); // Adding the timestamp to the url with the "valid" arg
      $nonce_url = wp_nonce_url( $url, 'questionnaire_link_uid_' . $expiry, 'questionnaire' );  // Adding our nonce to the url with a unique id made from the expiry timestamp

      // End of relevant part
      // now here I return my nounce to the content of the post for demo purposed
      // You would use this code when a button is pressed or when a special page is visited

      $content .= $nonce_url;

      return $content;
    } );


This is where you would check for the validity of the unique URL

add_action( 'template_redirect', 'my_url_check' );
function my_url_check(){

  if( isset( $_GET['questionnaire'] )){

    // if the nonce fails, redirect to homepage
    if( ! wp_verify_nonce( $_GET['questionnaire'], 'questionnaire_link_uid_' . $_GET['valid'] ) ){
      wp_safe_redirect( site_url() );

    // if timestamp is not valid, redirect to homepage
    if( $_GET['valid'] < current_time( 'timestamp', 1) ){
      wp_safe_redirect( site_url() );

    // Show your content as normal if all verification passes.
| improve this answer | |
  • In the last code there should be additional } at the end. $url = site_url - can it be a regular url like example.com/my-page The creation of the link is working fine, but when I try to use it, it always redirects me to home page. – File_Submit Aug 29 '16 at 20:15
  • 1
    Thanks for noticing the missing }, typo is fixed. For the url, sure it can be whatever url you want, within your site, I've put site_url as an example because it will generate the mysite.com part automatically and is portable to other installs (it takes the url in your WP config) as for the home page redirect, this means one of the 2 checks are failing. I'm checking for the $_GET variable and if you change any of those variable keys, then you need to update the variable names in the check too – bynicolas Aug 29 '16 at 20:22
  • Thanks, I found out that the nonce fails. I haven't change the keys. – File_Submit Aug 30 '16 at 7:34
  • 1
    Well I just tested again by pasting the code in my answer and it works perfectly for me... to pass nonce verification, the parameters have to be identical as when the nonce was created. so make sure you don't have a typo in your functions and in variable names. match corresponding parameters in wp_verify_nonce to wp_nonce_url – bynicolas Aug 30 '16 at 7:49
  • 1
    Your issue doesn't make sense and I don't think you found the error. The checks we perform are based on a unique number generated from A the url, B the timestamp and C a unique identifier for that particular action (which is created from the timestamp). The nonce check will fail if the wp_verify_nonce function is not able to recreate the same nonce given the parameters we supply to that function, so then you will get redirected (here is where I assumed you had the issue). The other reason you will get redirected is if the timestamp is over the validity period. – bynicolas Aug 30 '16 at 14:29

You could add an custom query var with the timestamp.

eg. example.com/portfolio?exp=12345678

Then, when a user lands on that url, you could check the current time against the timestamp. If 10 mins have passed / or not, will allow you to output different things on the page.

You could even store a certain timestamp, to know what client got which form/timestamp.


As bynicolas has noted, technically the client could generate a current time timestamp and access the link again.

So you might want to consider saving that timestamp as a transient, for 10 min.

Now, when the client visits the url, you need to check if that transient with the timestamp has expired.

Just an idea.

| improve this answer | |
  • This would work, but then anyone could change the timestamp and gain access to the link again... So the expiration wont be really effective – bynicolas Aug 29 '16 at 15:09
  • You think a client would know how to generate a timestamp? :) But yes that's a possibility. So maybe he could use a 10 min transient with the timestamp. If transient has expired, no access. – The J Aug 29 '16 at 15:24
  • That would make it a nice upgrade, a more robust solution. I was thinking to integrate a nonce into this. – bynicolas Aug 29 '16 at 15:27
  • That is also a great way to go about it, that's pretty much what they are there for. Just wondering if he's ok with a long url? If yes, then it would be a great solution too. I don't think the transient is necessary at that point, so url "prettiness" and lenght is probably the only thing that matters at this point. – The J Aug 29 '16 at 15:30
  • No, it doesn't matter if the link is long and ugly :) – File_Submit Aug 29 '16 at 19:41

Here's one idea: Hook to the template_redirect action:


At this point, you can examine the $post object to make sure it has the type of your CPT ($post->post_type), and get the timestamp ($post->post_date). If the current system time is > 10 minutes beyond the post time, then redirect the user to your desired URL.

You'll probably want to do some sort of "garbage collection" on expired CPTs as well - delete those expired posts so your database doesn't fill up with unneeded content.

| improve this answer | |
  • hmm, but then I will need to create new post each time I want to send the link of the post to a client. – File_Submit Aug 29 '16 at 14:58
  • 1
    ah. I read your original question as meaning there was a distinct CPT post for each client. If that's not the case then the answer from The J is better -- and if you are worried about the client deciphering the timestamp being passed in as part of query string - just munge it. With either symmetric encryption or something quick/easy like convert to base_64. – C C Aug 29 '16 at 15:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.