Recently I had to create an endpoint for users to view a dynamically-generated PDF on a site. I wanted to have a nice-looking URL for users. I found it difficult to wrap my head around the process of adding a rewrite rule in WordPress but I finally figured it out.
WordPress offers a function, add_rewrite_rule
, to register a rewrite rule for your website. In my example, I am going to set up a rule to handle requests to https://plugins.local/scc-pdf. I am also going to accept two parameters – a value for a record ID I am using to generate the PDF and a unique hash for security so that PDFs cannot be viewed by simply changing the record ID in the URL. The final URL will look similar to:
https://plugins.local/scc-pdf/123/3daf10af8c0db478f95b1e89615a6cc3
In the above example, the record ID will be 123 and the hash is 3daf10af8c0db478f95b1e89615a6cc3. We need to set up a pattern with add_rewrite_rule
to look for this type of URL and accept these parameters. I hope you like regular expressions! Luckily, my example will be pretty basic.
I used WordPress’s init
hook to register my rewrite rule.
function scc_pdf_rewrite() {
add_rewrite_rule( '^scc-pdf/([0-9]+)/([A-Z|a-z|0-9]+)/?', 'index.php?recordID=$matches[1]&recordHash=$matches[2]', 'top' );
}
add_action( 'init', 'scc_pdf_rewrite' );
I am starting off my rewrite rule with '^scc-pdf/
. In other words, I am looking for a request that begins with scc-pdf/. Then, I am looking for two parameters separated by a forward-slash. These parameters are collected using regular expression patterns.
In my case, the record ID should be a number. The regular expression pattern ([0-9]+) will grab one or more characters matching the [0-9] pattern which means any number. My recordHash parameter is not limited to numbers, though, and can also include text. In this case, the pattern used will be ([A-Z|a-z|0-9]+). This will grab any number of integers or text (either lowercase or capital). Obviously, regular expressions can become very complicated, very quickly. You can test your rewrite rule using the Debug Bar Rewrite Rules WordPress plugin.

Our URL will be redirected to the index.php
file with parameters for recordPDF
and recordHash
. This is what we want. But if we go to this URL we will not be redirected anywhere. In fact, I just see my test site’s homepage. We need to do two more steps to make this rule active and working.
Note: It is important to mention that you might not always see your changes right away when working with a WordPress rewrite rule. To ensure you are seeing your most recent changes, you might need to flush your permalink rule. Do this by going to Settings > Permalinks and clicking the Save Changes button without changing anything. This will flush the rewrite cache. You may also notice this problem when working with Custom Post Types which also use custom URL structures.
We need to tell WordPress to allow our custom parameters, recordID
and recordHash
. WordPress has a set of query parameters that it will accept. More information about this can be found at WordPress’s documentation for get_query_var. We can add our parameters to WordPress’s $query_vars
by utilizing the query_vars
filter. Here is my code for adding the recordID
and recordHash
parameters to the $query_vars
:
function scc_add_pdf_variables( $query_vars ) {
$query_vars[] = 'recordID';
$query_vars[] = 'recordHash';
return $query_vars;
}
add_filter( 'query_vars', 'scc_add_pdf_variables' );
WordPress now can accept my custom query variables and check for their existence. Reloading the URL still doesn’t show a change, though (and, yes, I flushed the permalink cache!). Our last step is to actually handle the redirect. WordPress’s template_redirect
hook is a place where we can look for our custom parameters and override WordPress’s default behavior. I’m going to check for these parameters being set and, if they are, do something with them. In my recent project I needed to create a PDF and output it to the browser. For the sake of simplicity I will just show how to access the variables and display them.
function scc_display_pdf() {
if ( get_query_var( 'recordID' ) && get_query_var( 'recordHash' ) ) {
echo 'recordID: ' . get_query_var( 'recordID' ) . '<br />';
echo 'recordHash: ' . get_query_var( 'recordHash' );
exit;
}
}
add_action( 'template_redirect', 'scc_display_pdf' );
The get_query_var
function can check for our variables. If both the recordID
and recordHash
are set, I am simply echoing out their values and exiting program execution. Opening my test URL in my browser will echo out the variables:

If these variables are not set WordPress will just keep on running as it normally would and our template_redirect
code will have no effect.