I'm working on rewrite rules for a plugin that uses a URL endpoint, /modifier, to create a query_var &modifier=1 to signify it should do something else.

The rewrite deals with URLs where /modifier is appended to the end of a URL for a post, page, or custom post type.

It seems like adding a rewrite endpoint would be ideal, but according to the Wordpress rewrite endpoints API the incoming URL would need to end with a value, like /modifier/1 in order to rewrite automatically to &modifier=1 via the endpoint API. If there's no value after the endpoint, it resolves to &modifier= and has no value when checking if it isset.

So I'm still doing it the long way, via generate_rewrite_rules. The rewrite for posts and pages works fine - I could include it but maybe it's not relevant.

The rewrite for custom post types, added at the top, also works when a post type is explicitly hardcoded.

add_filter('generate_rewrite_rules', 'my_rewrite');
function my_rewrite($wp_rewrite) {
    // rewrite rules for custom post type "specific-type"
    $cpt_rules = array(
        'specific-type-slug/([^/]+)/modifier' => 'index.php?specific-type='. $wp_rewrite->preg_index(1) .'&modifier=1'
    );
    $wp_rewrite->rules = $cpt_rules + $wp_rewrite->rules;
}

The problem is making a loop for all custom post types. get_post_types() is only available after init. This rewrite is filtering generate_rewrite_rules, several steps earlier.

So here's the loop I've tried. It obviously doesn't work, the post types aren't set up yet.

add_filter('generate_rewrite_rules', 'my_rewrite');
function my_rewrite($wp_rewrite) {
  global $wp_post_types;
  $types = get_post_types( array( '_builtin' => false ) );
  // get the registered data about each post type with get_post_type_object
  foreach( $types as $type ) {
    $cpt_rules = '';
    $typeobj = get_post_type_object( $type );

    if( isset( $typeobj->rewrite->slug ) ) {
        $slug = $typeobj->rewrite->slug;
        $cpt_rules = array(
            $slug.'/([^/]+)/modifier' => 'index.php?'.$type.'='. $wp_rewrite->preg_index(1) .'&modifier=1'
        );
        $wp_rewrite->rules = $cpt_rules + $wp_rewrite->rules;
    }
  }
}

Something tells me using a plugin class might be the way to solve this, but I don't understand how.

  • Update: it is certainly a heck of a lot easier to just change the URL to modifier/1 and use the endpoint API, I can confirm this works. Still I'm curious if there's a way to use the query_var modifier even if it is not followed by a value in the URL. – nimmolo Jun 30 '14 at 10:40

Apologies if this seemed too obvious to answer, i'm just getting my head around htaccess rewrites in wordpress.

The most elegant way to parse the modifier through the URL like this seems to be to add a rewrite endpoint and just check for it in the URL later, if you don't want to pass a value.

The beauty is there's no need for any other rewrite rules, as long as you're just checking for this endpoint.

add_action( 'init', 'wp_modifier_endpoint' );
function wp_modifier_endpoint() {
    add_rewrite_endpoint( 'modifier', EP_PERMALINK | EP_PAGES );
}

In the function creating the /modifier links, there's also no need to add a value after /modifier/value either, unless you need a value. My previous technique checked if the endpoint (as query_var) isset, but you can just check for the endpoint string within the URL with the php strrpos function.

$url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
$endpoint = substr( $url, 9 ); /* number of chars in string "/modifier" */
if( false !== strpos( $endpoint, '/modifier' ) ) {
    /* do something; */
}

Update: per Milo's comment below, it is preferable to check if modifier is an array_key of query_vars - this seems more foolproof and easily extensible, in case you want to check for multiple keys.

global $wp_query;
if( array_key_exists( 'modifier' , $wp_query->query_vars ) ) {
    /* do your thing; */
}
  • 1
    see this answer for another way of detecting the presence of an endpoint in a request. – Milo Jul 1 '14 at 1:14
  • Thanks Milo. Unfortunately if array_key_exists( 'modifier', $wp_query->query_vars ) didn't work for me when I just tried it in the checking function. I was getting hopeful! For sure, "modifier" has been added to public_query_vars within the plugin earlier. – nimmolo Jul 1 '14 at 1:42
  • 1
    if it's within a function you need to globalize $wp_query before you can access it: global $wp_query; – Milo Jul 1 '14 at 1:45
  • hahaa!!! indeed you do. oh, man. thanks. it works now, and i think this is preferable to looking in the string – nimmolo Jul 1 '14 at 2:57

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.