Rewrite of URL with ‘[‘ ‘]’ or ‘(‘ ‘)’ as literals

Trying to match and URL like this

linktosite/alphaNum/123/321/alphanum[alphanum].jpg

in .htaccess I can match and extract all the groups properly with

linktosite/(.+)/([0-9]+)/([0-9]+)/(.+)\\[(.+)\\]\\.(.+)$

in add_rewrite_rule I can not make it match. I’ve tried escaping the [ with \\[, \\\\[, \\\\\\\\[

and nothing works. I’ve also tried \Q[\E and using it as \x5b \091 and nothing works.
Also tried ([^\\[]+) to match non [ characters up to the [

What’s the proper way to match metacharacters like this?? Does the same for literal \()

1 Answer
1

I’ve found this to be one of the more poorly documented features of WordPress, so hopefully this is on track or will be corrected by someone more fluent in WP_Rewrite.

The basic gist is thus:

  1. During plugin activation and when flushing rules, ensure your custom rule is added to the list.
  2. During init, use add_rewrite_tag() for any custom query string parameters that are in the rule. For a destination of index.php?this_is_custom=$matches[1], you must add the this_is_custom tag.
function wpse_39626_init() {
    // these must be added during init. if you haven't done
    // add_rewrite_tag() for all custom query string vars,
    // wordpress will ignore them.
    add_rewrite_tag( '%wpse_thing%', '(\w+)' );
    add_rewrite_tag( '%wpse_name%', '(\w+)' );
    add_rewrite_tag( '%wpse_index%', '(\w+)' );

    // manually flushing rules so this code is easier to demo.
    // under normal circumstances you would use the plugin
    // activation hook. this will eventually call wpse_39626_rules().
    flush_rewrite_rules();
}
add_action( 'init', 'wpse_39626_init' );

// Normally, this would get called during something like
// your plugin's activation hook. See register_activation_hook().
function wpse_39626_activate() {
    add_rewrite_rule( 'testing/(\w+)\[(\w+)\]', 'index.php?wpse_thing=custom&wpse_name=$matches[1]&wpse_index=$matches[2]', 'top' );
    flush_rewrite_rules();
}
//register_activation_hook( __FILE__, 'wpse_39626_activate' );

// Hook into rewrite_rules_array, in case rewrite rules
// are flushed after the plugin is activated.
function wpse_39626_rules( $rules ) {
    $new_rules = array();

    // Matches: testing/outer[inner]
    //   wpse_name  = outer
    //   wpse_index = inner
    $new_rules['testing/(\w+)\[(\w+)\]'] = 'index.php?wpse_thing=custom&wpse_name=$matches[1]&wpse_index=$matches[2]';

    // prepend and return rules
    return $new_rules + $rules;
}
add_action( 'rewrite_rules_array', 'wpse_39626_rules' );

// Here's some demo code to intercept the page load
// and do custom functionality when our rewrite rule
// matches. (We'll just dump the matched values.)
function wpse_39626_posts( $query ) {
    if( ! is_main_query( $query ) ) {
        return;
    }

    if( $query->get('wpse_thing') != 'custom' ) {
        return;
    }

    var_dump( $query->get('wpse_name') );
    var_dump( $query->get('wpse_index') );

    die;
}
add_action( 'pre_get_posts', 'wpse_39626_posts' );

Your example is a little light on code, particularly in the URL you’re trying to match (what do all those parameters correspond to?), so my answer is somewhat generic.

Leave a Comment