A Better Title Filter For Twig Using Craft CMS

Quick Summary: The default Twig title filter lacked the necessary flexibility for this site. To address this limitation, I developed a custom Craft CMS Twig Extension, which provided enhanced functionality and greater control over title formatting.

A Twig filter for titles currently exists that converts a string to capitalize it.

{{ entry.title|title }}

The above craft variable and twig filter changes

craft web development in ireland

to

Craft Web Development In Ireland

While the Twig filter for titles works great in 99% of cases, it's important to be aware of its limitations.

But what if your string already contains capitals or other variants that must remain in the current format?

Example

craft CMS web development using AI in ireland

This  becomes

Craft Cms Web Development Using Ai In Ireland

This doesn't achieve what we want. So, a custom Twig extension to the rescue.

Strict Title Twig Extension

The original title filter from Twig uses PHP's mb_convert_case

public static function titleCase(string $charset, $string): string
    {
        return mb_convert_case($string ?? '', \MB_CASE_TITLE, $charset);
    }

Lets create our own function. This is where unicode character properties in regex can save us.

A reproduction of mb_convert_case without the problematic conversion to lowercase becomes:

public function mb_convert_case_utf8_variation($s): string
    {
        $arr = preg_split("//u", $s, -1, PREG_SPLIT_NO_EMPTY);
        $result = "";
        $mode = false;
        foreach ($arr as $char) {
            $res = preg_match(
                    '/\\p{Mn}|\\p{Me}|\\p{P}|\\p{Cf}|\\p{Lm}|\\p{Sk}|\\p{Lu}|\\p{Ll}|' .
                    '\\p{Lt}|\\p{Sk}|\\p{Cs}/u', $char) == 1;
            if ($mode) {
                if (!$res) {
                    $mode = false;
                }
            } elseif ($res) {
                $mode = true;
                $char = mb_convert_case($char, MB_CASE_TITLE, "UTF-8");
            }
            $result .= $char;
        }

        return $result;
    }

Explanation

For each character, a regular expression is used to check if the character belongs to any of several unicode character classes. If the character is from one of these classes, $res will be true.

The rest of the code inside the loop checks the $res value. If $res is true, and $mode is false, that means we're transitioning from a non-matching character to a matching character, so mb_convert_case() is used to convert the character to title case and $mode is set to true. If $res is false and $mode is true, then we're transitioning from a matching character to a non-matching one, so $mode is turned off.

At the end of each loop iteration, whether the character was transformed to title case or not, it's appended to $result.

Props to user Artefacto on this Stack Exchange post

How to Install

I have a custom module on my site where I have integrated this twig extension. I won't review that here, but you can read  Soft Limit Function on a Craft CMS Text Field Using a Module for more info.

You can grab the full code for this Twig Extension