1

I was just surprised when I noticed, that our Craft installation is not case sensitive with routing:

E.g.

https://domain.com/route/to/page-with-content

delivers the same content as

https://domain.com/rOute/TO/page-WITH-content

Is this intended behavior? From my point of view this is simply wrong. I want the upper URL to work (as the slugs are all lowercase) and the second to 404.

Can I disable this behavior? (I did not find anything).

P.S.: Please do not post any redirect solutions. Thanks!

11
  • What database collation are you using? By default, Craft uses case-insensitive collations (utf8mb4_0900_ai_ci for utf8mb4), so URL casing is ignored on the database level. Switching to a case-sensitive collation like utf8mb4_0900_ai_cs might solve this, though it could introduce other problems.
    – MoritzLost
    Sep 16 at 12:31
  • Just curious as to your use case here? Most CMS including WordPress also do this. However, if you're just trying to get a URL to 404 or do something else when someone types it in a different case than what it's supposed to be, you could work around with Twig and compare the URL with the actual request, see if they match, and then take action. Sep 16 at 17:16
  • @MoritzLost Are you sure, that a ci collation is not capable of exactly matching lowercase to lowercase? I thought case-insensitive just means the collation is not capable of bringing the lower/upper-case characters in relation to each other, but an SQL condition WHERE xxx="something" will still never match WHERE xxx="SoMeThInG".. Sep 17 at 7:51
  • @RitterKnight The discussion here in our team actually started with lowercase canonical URLs being in conflict with case-independent routing. You are creating duplicate content. Just think of a normal webserver setup, where assets /img/logo.png will never match Logo.png or LOGO.PNG. Case independence is wrong, even if Wordpress does it :-) Sep 17 at 7:52
  • @MatthiasRedl-Mann No, case-insensitive means the opposite. Using a case-insensitive collation means the database will treat a and A as identical by default – so a search forapple will match APPLE and aPpLe as well. See case sensitivity in string searches for reference. Of course, you can still force a case-sensitive comparison by changing the collation in your query or casting some columns to binary, though I don't think Craft does that by default.
    – MoritzLost
    Sep 17 at 8:11
2

In most cases, case-sensitivity depends on the database collation. By default, Craft uses case insensitive collations (utf8_general_ci or utf8mb4_0900_ai_ci, depending on the charset). You can change that in your database configuration. Keep in mind that if you change the collation for an existing project, it won't update existing tables automatically. You can run this console command to change all tables to the configured collation:

php craft db/convert-charset

Effects of changing the collation

Using a case-sensitive collation will make ALL database queries against that table case-sensitive. This means that upper- and lower-case letters are no longer considered identical for comparison purposes. Consider a search for elements with the title apple. Using a case-insensitive collation, the search will find also find Apple, APPLE, or aPpLe. Using a case-sensitive collation, only apple will match that query. See Case Sensitivity in String Searches for more information.

You can work around this for individual queries in multiple – for example, by performing an individual query with a different collation or casting a specific column to binary (CAST(title as BINARY)). Though Craft's element query interface doesn't provide fine-grained control for that and you can't modify all queries the core uses to find and display content, so that's probably not a feasible solution.

Changing the collation in your database configuration and updating all tables using the command mentioned above should have the desired effect (unless Craft handles this case in a special way, which I don't think it does). That is, if the URL is stored in lower-case, the same URL with upper-case letters won't match that entry, so that URL will go to a 404 page. This might be different for dynamic routes defined in PHP. Those aren't stored in the database as far as I know, so it depends on how Yii2 handles those under the hood.

However, changing the collation will also impact every other query – for example, your search page might work differently if searching for apple doesn't find an entry with the title Apple.

Other considerations

  • People usually don't type URLs manually, and when they do they usually type in lower-case. Instead of preventing upper-case URLs from matching with existing entries, this effort is better spent making sure all the links on your site are in lower-case and nobody in your organization is circulating URLs with upper-case letters in them.
  • This probably won't impact SEO at all, since most services consider URL paths to be case-insensitive. If you're worried about duplicate content, a <link rel="canonical"> tag pointing to the lower-case URL should solve that once and for all.
  • There's a reason _ci collations are the default – in particular, you usually expect case-insensitivity for any features relating to full-text search. Instead of changing the collation and dealing with the issues that arise from that, you could also talk to your SEO people about bike-shedding.
1
  • 1
    Thanks a lot Moritz! btw: Changing the collation of the "uri" column in the table "elements_sites" to e.g. "utf8_bin" changed the behavior immediately, not even Craft's db/convert-charset was needed (though of course I likely oversee other side effects here). Sep 17 at 20:12
1

If you're worried about search engines indexing some page where someone is linking to with a different case, as mentioned by Moritz, that's what you use the canonical tag for:

<link rel="canonical" href="{{ entry.url}}">

You mention the second URL in your example 404s but flipping the argument around for a moment, I'm not sure I'd want the ability for authors to specify the exact same URL but with different case sensitivity—that can get ugly fast, which is what would happen if you allow case sensitive URLs.

However, if you're just trying to get a URL to 404 or do something else when someone types it in a different case than what it's supposed to be, you could work around with Twig and compare the URL with the actual request, see if they match, and the take action.

404 it:


{% if entry.slug != craft.app.request.segments|last %}
    {% exit 404 %}
{%endif%}

Or do a more subtle redirect:

{% if entry.slug != craft.app.request.segments|last %}
   {% redirect entry.url 301 %}
{%endif%}

As an aside if an SEO team is prioritizing this over writing content and acquiring high quality backlinks, you need to give their head a serious shake.

1
  • 1
    After discussion with you guys, I agree that it is probably better to be case insensitive as long as the canonical tag is ok. The opposite would be worse. Sep 20 at 8:42

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.