You could used a so called “virtual page”.
A virtual page is a page which is not managed in the WordPress admin area. That means this page is not represents by a post, page or a custom post type.
There are different ways to create a virtual page, one way is to use a custom rewrite rule.
Example:
domain.com/download/123
// inform wordpress about the new url
add_filter( 'generate_rewrite_rules', function ( $wp_rewrite ) {
$wp_rewrite->rules = array_merge(
['download/(\d+)/?$' => 'index.php?dl_id=$matches[1]'],
$wp_rewrite->rules
);
} );
// add dl_id to the list of WordPress query vars
// so wordpress knows that variable
add_filter( 'query_vars', function( $query_vars ) {
$query_vars[] = 'dl_id';
return $public_query_vars;
} );
add_action( 'template_redirect', function() {
$dl_id = intval( get_query_var( 'dl_id' ) );
if ( $dl_id ) {
// load the filename from the database and send the file to the browser
die;
}
} );
A detailed explanation can be found in the article “How to Create a Virtual Page in WordPress” by Anh Tran on medium.