How to create download links based on Custom Fields with Rewrite API

The first step in making this work is to register your custom query var for the file via the query_vars filter. I’ve named it wpa82328_file, but you can change this to something more meaningful to you. file is a bit generic though, so you’ll want to prefix it with something guaranteed to be unique:

function wpa82328_query_vars( $query_vars ){
    $query_vars[] = 'wpa82328_file';
    return $query_vars;
}
add_filter( 'query_vars', 'wpa82328_query_vars' );

Next, the rewrite rule which will convert incoming requests to /download/resource/file/ from the pretty URL to query vars:

function wpa82328_rewrite_rule(){
    add_rewrite_rule(
        '^download/([^/]+)/([^/]+)/?$',
        'index.php?resource=$matches[1]&wpa82328_file=$matches[2]',
        'top'
    );
}
add_action( 'init', 'wpa82328_rewrite_rule' );

This will point everything to the main index.php file with the resource and filename query vars set.

Next, we have to capture these requests early, before the main query is run and headers are sent. If we try to do this later, headers will already be sent and downloads won’t work.

I’ve hooked the parse_request action, where a ref array of query vars is passed as an argument to the hooked function. We can then easily check for the presence of the wpa82328_file query var, which will tell us that a download is being requested. Read the comments within the code to understand what is happening in each step:

function wpa82328_parse_request( &$wp ){

    // if the wpa82328_file query var is set
    if ( array_key_exists( 'wpa82328_file', $wp->query_vars ) ){

        // query for the requested resource
        $args = array(
            'name' => $wp->query_vars['resource'],
            'post_type' => 'resource'
        );
        $resource = new WP_Query( $args );

        // get all of the custom fields for this resource
        $custom_fields = get_post_custom( $resource->post->ID );

        // check each custom field for a value that matches the file query var
        foreach( $custom_fields as $key => $value ):

            // if a custom field value matches, we have the correct key
            if( in_array( $wp->query_vars['wpa82328_file'], $value ) ){

                echo 'file key is: ' . $key;

                // increment count
                // set proper headers
                // initiate file download

                exit(); 
            }

        endforeach;
    }
    return;
}
add_action( 'parse_request', 'wpa82328_parse_request' );

The last part you’ll have to sort out is extracting the number from the key so you can get the correct count and asset keys. I would personally change it to have the number last, making it easier to just do a substr on the key to get the number. Or better, I would store them all as an array of arrays under a single key, so once you find the index that contains the requested name, you just have to go to the next index to find the count, and the next to find the asset url.

Leave a Comment