2

Whenever you enter an URL with two path segments that doesn't exists, WordPress will automatically parse the query as an attachment.

How to reproduce

  1. Change you permalink structure to /%postname%/.
  2. Enter the following path behind your WordPress root URL: /foo/bar make sure "foo" isn't a existing taxonomy or post type.
  3. Hook into pre_get_posts and dump the global $wp_query.
  4. As you can see from the debugged information, the system is trying to parse the URL as an attachment since it adds post_type = 'attachment' to the query and some other attachment related information.
  5. If there is not a post or page with the slug name from the first segment and an attachment with a slug from the second segment than WordPress will return a 404.

NOTE: I'm not sure about the statements I make in step 2 and 5.

Why care?

I found it very annoying to deal with this default behavior and really would like to disable it somehow, if you know how please let me know. It make it impossible to achieve certain permalink structures. Where you probably want to know about as well. I'm trying to achieve a permalink structure where the current post slug is prefix by it's term slug. For example the post type 'example' has post 'bar' which has a relation with a term with the slug 'foo'. Instead of defining the permalink 'example/bar' it should be defined as 'foo/bar'.

0

After getting to know a bit more about the default perma structure and how to modify it I stumbled upon the hook rewrite_rules_array. This hook allows you to filter the array of rewrite rules, an array of URL rewrite rules in WordPress what will help determine what type of content to load.

This is a great place to disable the default behavior for recognizing the path as attachment. This is how you get rid of all rewrite rules for attachments, thus all the behavior for recognizing a path as attachment.

add_filter('rewrite_rules_array', function($rules) {
    foreach ($rules as $rule => $url) {
        if (strpos($url, 'attachment') !== false) {
            unset($rules[$rule]);
        }
    }
    return $rules;
});

I'm not sure about all other rules and I definitely want to check them all out. These for example:

"(.?.+?)(?:/([0-9]+))?/?$" => "index.php?pagename=$matches[1]&page=$matches[2]"
"([^/]+)(?:/([0-9]+))?/?$" => "index.php?name=$matches[1]&page=$matches[2]"

Will help you recognize pages, very useful to know if you only want to use pages. But remember if you rewrite the array with only these keys/values then new rules for example rules for your custom post type will also be rewritten (removed).

NOTE: Debugging this filter is only possible on the Settings > Permalinks page in the WordPress back-end.

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.