How to create custom taxonomy URLs without taxonomy name?

I have a website that lists businesses in different cities (this is a niche site, so all businesses have the same “classification”).

For starters I created a CPT for locations and a taxonomy called “Cities,” which 150 or so cities as terms.

Read More

All 300+ locations have been tagged with a city.

I was able to modify the CPT links so that they appear like so:
example.com/cityname/business-name

What I’d love to have (and not been able to accomplish yet) are urls like
example.com/cityname which would list all businesses from that city.

My understanding is that by default WP attempts to find a page with “cityname” as the name.

What would be the easiest way to reroute this request to use a taxonomy template? Or as an alternative, what would the easiest way be to have the page template detect the city name and pull posts tagged with that taxonomy term?

I suppose I could create rewrite rules in htaccess for all cities, but I’d prefer where the redirects were automatically added when a new city name is added to the taxonomy.

Related posts

Leave a Reply

1 comment

  1. Here is some code that should do the trick:

    //Creates special permastruct that turns all terms of cities into slugs
    add_action( 'init', 'set_rewrite' );
    
    function set_rewrite() {
        //Get terms
        $terms = get_terms( 'cities', array( 'hide_empty' => false ) );
        //return if no terms
        if( count( $terms ) < 1 ) return;
        $slugs = wp_list_pluck( $terms, 'slug' );
        //create term regex
        $termregex = '(' . implode( '|', $slugs) . ')';
        //New query var
        add_rewrite_tag( '%cityname%', $termregex );
        //Add permastruct
        add_permastruct( 'cities_struct', '%cityname%/' );
        //refresh if new term added
        if( get_option( 'update_cities_struct' ) ) {
            global $wp_rewrite;
            $wp_rewrite -> flush_rules();
            update_option( 'update_cities_struct', 0 );
        }
    }
    
    //action to refresh rewrite rules when a new term is saved
    add_action( 'created_cities', 'refresh_cities' );
    add_action( 'edited_cities', 'refresh_cities' );
    add_action( 'delete_cities', 'refresh_cities' );
    
    
    function refresh_cities() {
        update_option( 'update_cities_struct', 1 );
    }
    
    //set city name to the taxonomy cities
    add_filter( 'parse_query', 'parse_cities_query' );
    
    function parse_cities_query( $query ) {
        if( !empty( $query->query_vars['cityname'] ) ) $query->set( 'cities', $query->query_vars['cityname'] )
    }   
    

    Basically this creates a special permastruct that uses the slugs of the taxonomy cities as its base. It creates a query variable called cityname, which only accepts the slugs of the taxonomy and then sends the result to the proper taxonomy query variable.