I'm saving some pdfs into a folder with mpdf, the urls of pdfs are like this:


I want that if someone open this url it will show a shorter version like this:


how can I obtain this result using add_rewrite_rule() and apache web server?

UPDATE as suggested I changed the code that generates pdfs in a way that are not stored in a local folder, but are generated everytime when visiting the url with a specified id parameter like this


so now the correct rewrite rule is

 * Rewrite rules
add_action( 'init',  function() {
    add_rewrite_rule( '^example.com/invoice_([0-9]+).pdf$', '/wp-content/themes/mysitetheme/includes/mpdf/invoice.php?id=$1', 'top' );
} );
  • 1
    I would advise against storing uploaded invoices in your theme folder for security reasons. Also, what is mpdf? – Tom J Nowell Nov 10 '20 at 1:03
  • mpdf is a php library that you can use for create a pdf file using html + css. About the storing of invoices, you are right, I updated the code in a way that the pdf will be generated every time without saving to a local folder. – silvered.dragon Nov 10 '20 at 9:45

ok it was easy, the problem was that to match the left side pattern you have to use $1 not $matches[1], this is the solution

 * Rewrite rules
add_action( 'init',  function() {
    add_rewrite_rule( '^invoice_([0-9]+).pdf$', '/wp-content/themes/mysitetheme/invoices/invoice_$1.pdf', 'top' );
} );


From the suggestions received in the comments, it is now clear to me that it is not convenient to use rewrite rules for pages inserted in the wordpress folder without being part of the wordpress core itself, so the suitable solution is to generate virtual pages through the use of add_query_var and include a virtual template to be called when this new query variable is requested through index.php. So the correct code is this:

// Here I define my new query var and the related rewrite rules    
add_action( 'init', 'virtual_pages_rewrite', 99 );
    function virtual_pages_rewrite() {
        global $wp;
        $wp->add_query_var( 'invoice' );
        add_rewrite_rule( '^invoice_([0-9]+).pdf$', 'index.php?invoice=$matches[1]', 'top' );

    // This part is just to prevent slashes at the end of the url
    add_filter( 'redirect_canonical', 'virtual_pages_prevent_slash' );
    function virtual_pages_prevent_slash( $redirect ) {
        if ( get_query_var( 'invoice' ) ) {
            return false;
        } return $redirect;
    // Here I call my content when the new query var is called
    add_action( 'template_include', 'virtual_pages_content');
    function virtual_pages_content( $template ) {
        $fattura = get_query_var( 'fattura' );
        if ( !empty( $fattura) ) {
            include get_template_directory().'/includes/mpdf/invoice.php';
        return $template;
  • Note that this will not work on Nginx based systems, rewrite rules are only meant to be used with index.php?.... type addresses on the right hand side. – Tom J Nowell Nov 10 '20 at 1:03
  • you are right I updated my question and changed the urls – silvered.dragon Nov 10 '20 at 9:53
  • You've misunderstood, I meant index.php, specifically WordPress' index.php in the root WP folder, WP rewrite rules can't be used for arbitrary PHP files, they map pretty permalinks on to query variables, they aren't a generic URL mapping feature, and you can't use it to route URLs to different files and folders. Rewrite rules always map on too "index.php?foo=bar" type URLs, even if index.php is in a different location, because it isn't a path it's a URL – Tom J Nowell Nov 10 '20 at 11:31
  • ok I understand, but considering that it works what is the risk I run if I keep using this approach? – silvered.dragon Nov 10 '20 at 19:12

WP rewrite rules are not for mapping URLs on to arbitrary files and paths.

To do this, you will need either a HTAccess rule, or Nginx config rules. WordPress rewrite rules are not intended for this.

Originally, WP permalinks took the form example.com/index.php?post=123, but then pretty permalinks were added, they took pretty URLs such as /post/123 and matched them to ugly permalinks index.php?post=123. This is the purpose of WP rewrite rules, to turn pretty URLs into ugly URLs with query variables that get passed to WP_Query to create the main post loop and figure out which template to load.

A WP rewrite rule consists of:

  • A regular expression that matches a URL
  • the query variables that expression extracted in the form index.php?var=value

You cannot pass arbitrary files and folders to as the second parameter when adding a rewrite rule. It is not a generic rewrite system. For that you want Apache's mod_rewrite.

Additionally, it is very bad practice to make direct requests to PHP files in WordPress themes, and a big security risk. WP is a CMS let WP handle the request and hook in to handle it in your plugin/theme.

Alternatively, add a new query var named mpdf, look for it on init, then load your MPDF script in PHP rather than doing it directly via a browser request. This would let you use WP rewrite rules.

  • Sorry for the noob question, can you please specify a little in deep the solution to look into init? Actualy I have a php file in my theme folder named invoice.php and in this file there is all the code I wrote for the creations of the pdfs. This page doesn't exist in the wordpress environment, is simply a php page, I think that you are telling me to include the code of this page somewhere else, like in my functions.php, but how can I create then an url for this page?? – silvered.dragon Nov 10 '20 at 19:21
  • Ok I investigate deeper the suggestions in your answer and I updated the code, I think now is perfect – silvered.dragon Nov 11 '20 at 9:28

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.