I'm trying to make some pretty URLs that show content from a category page. An example would be this: https://example.com/resources/white-paper (not a real WP page) would show content from https://example.com/resources/?type=white-paper. /resources is an archive page of a custom post type, and the archive page template pulls the query string and displays posts of the respective taxonomy. Any tips on how to approach this?


Use add_rewrite_rule().

function wpse325663_rewrite_resource_type() {
    add_rewrite_rule('^resources\/(.+)/?', 'resources/?type=$matches[1]', 'top');
add_action('init', 'wpse325663_rewrite_resource_type');

An important note from the codex:

Do not forget to flush and regenerate the rewrite rules database after modifying rules. From WordPress Administration Screens, Select Settings -> Permalinks and just click Save Changes without any changes.


As long as you're only dealing with one CPT, when you register your post type, make sure to set has_archive to true and rewrite to array('slug' => 'resources'). That way you are programmatically creating an archive.

(If you did not set up has_archive when you first registered the CPT, you may need to unregister_post_type() which won't delete your posts but will clear it out, and then re-register it with the new settings. Finally, visit the permalinks settings page to flush permalinks.)

Then, in a child theme or custom theme, create a file called archive-resources.php. This is where you can intercept the query string and respond appropriately. Here's the basic structure:

// if the query string is present
if($_GET['type']) {
    // run your tax query here
    $args = array(
        'post_type' => 'post',
        // tax query is an array of arrays
        'tax_query' => array(
                'taxonomy' => 'type',
                // you can pull various ways; this uses the slug i.e. 'white-paper'
                'field' => 'slug',
                'terms' => $_GET['type']
    $posts = new WP_Query($args);
    if($posts->have_posts()) {
        while($posts->have_posts()): $posts->the_post();
        // your loop here
} else {
    // what to do if no query string is present
    // example: you could redirect elsewhere, or show a default taxonomy query

The downside is your archive will run a default query, so you're basically throwing the results of that query out the window and then running your own. You could just run a regular Loop in the else condition and make use of it since it will run anyway.

  • From here you'd need to work out the rewrite rules to make the query string disappear from the URL, and then if that actually removes the query var you might need to parse the URL rather than rely on $_GET['type']. – WebElaine Jan 15 at 13:50

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.