Last active
March 20, 2024 13:09
-
-
Save bartwttewaall/e00dc6cce8293fc433a7802ab1c786c5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace modules\wirelab; | |
use Craft; | |
use craft\elements\Entry; | |
use Twig\Extension\AbstractExtension; | |
use Twig\TwigFilter; | |
use Twig\TwigFunction; | |
class WirelabTwigExtension extends AbstractExtension | |
{ | |
public function getFilters(): array | |
{ | |
return [ | |
/** | |
* Use regex to replace a string inline | |
* | |
* @example | |
* | |
* ```twig | |
* {{ "some-thing"|pregReplace('/\\-/', '_') }} | |
* ``` | |
*/ | |
new TwigFilter('pregReplace', function (array|string $subject, array|string $pattern, array|string $replacement) { | |
return preg_replace($pattern, $replacement, $subject); | |
}), | |
/** | |
* Convert "(+31) 06 - 123 456 78" to "00310612345678" | |
* | |
* @example | |
* ```twig | |
* <a href="tel:{{ brand.phoneNumber|phone }}">Our number: {{ brand.phoneNumber }}</a> | |
* ``` | |
*/ | |
new TwigFilter('phone', function (string $input) { | |
$input = preg_replace('/\\+/', '00', $input); | |
return preg_replace('/\\D+/', '', $input); | |
}), | |
/** | |
* @return mixed|null The found value or null when not found | |
* | |
* @example | |
* | |
* ```twig | |
* {% set items = [{id:1, name:"one"}, {id:2, name:"two"}, {id:3, name:"three"}] %} | |
* {{ items|find(i => i.name|length > 3)|json_encode }} // output: '{id:3, name:"three"}' | |
* ``` | |
*/ | |
new TwigFilter('find', function (array $array, callable $callback) { | |
foreach ($array as $key => $value) { | |
if (call_user_func($callback, $value, $key, $array) === true) | |
return $value; | |
} | |
return null; | |
}), | |
/** | |
* @return int Returns the found index, or -1 when not found | |
* | |
* @example | |
* | |
* ```twig | |
* {% set items = [{id:1, name:"one"}, {id:2, name:"two"}, {id:3, name:"three"}] %} | |
* {{ items|findIndex(i => i.name|length > 3) }} // output: 2 | |
* ``` | |
*/ | |
new TwigFilter('findIndex', function (array $array, callable $callback) { | |
foreach ($array as $key => $value) { | |
if (call_user_func($callback, $value, $key, $array) === true) | |
return $key; | |
} | |
return -1; | |
}), | |
/** | |
* Format a string or number to a formatted string, using the locale of the current site. | |
* Use case: English & Dutch write a euro sign before the value, most other EU countries write it after the value | |
* See: https://en.wikipedia.org/wiki/Euro_sign#:~:text=The%20European%20Union%27s%20Interinstitutional%20Style,amount%20in%20most%20other%20languages | |
* | |
* @example | |
* | |
* ```twig | |
* {{ "1234,56"|currency('EUR') }} | |
* ``` | |
*/ | |
new TwigFilter('currency', function (string|float $input, string $currency = 'EUR', int $precision = 2) { | |
if (empty($input)) | |
throw new \Exception('Empty input'); | |
if (is_string($input)) $input = floatval(str_replace(',', '.', $input)); | |
$locale = Craft::$app->sites->currentSite->language; | |
$fmt = new \NumberFormatter($locale, \NumberFormatter::CURRENCY); | |
$fmt->setTextAttribute(\NumberFormatter::CURRENCY_CODE, $currency); | |
$fmt->setAttribute(\NumberFormatter::FRACTION_DIGITS, $precision); | |
return $fmt->formatCurrency($input, $currency); | |
}), | |
]; | |
} | |
public function getFunctions(): array | |
{ | |
/** | |
* This function returns unordered groups with unordered child sites, enrichted with properties such as isCurrent and translated language properties | |
* | |
* @example | |
* | |
* ```twig | |
* {% for group in getGroupedSites()|sort((a, b) => b.name <=> a.name) %} | |
* <ul> | |
* <strong>{{ group.name }}</strong> | |
* {% for site in group.sites|sort((a, b) => b.name <=> a.name) %} | |
* <li> | |
* <a href="{{ site.baseUrl }}">{{ site.name }}</a> | |
* </li> | |
* {% endfor %} | |
* </ul> | |
* {% endfor %} | |
* ``` | |
*/ | |
return [ | |
new TwigFunction('getGroupedSites', function () { | |
$entryElement = Craft::$app->getUrlManager()->getMatchedElement(); | |
$groups = Craft::$app->sites->getAllGroups(); | |
$groupsArray = []; | |
foreach ($groups as $group) { | |
$groupObject = new \stdClass(); | |
$groupObject->id = $group->id; | |
$groupObject->uid = $group->uid; | |
$groupObject->name = $group->name; | |
// get group sites | |
$sites = Craft::$app->sites->getSitesByGroupId($group->id); | |
// get current site | |
$currentSite = Craft::$app->sites->currentSite; | |
// add 'sites' property to each group | |
$groupObject->sites = array_map(function ($site) use ($currentSite, $entryElement) { | |
$siteObject = new \stdClass(); | |
foreach (get_object_vars($site) as $key => $value) { | |
$siteObject->$key = $value; | |
} | |
$siteObject->name = $site->name; | |
$siteObject->baseUrl = $site->baseUrl; | |
// find the current entry at a particular site, if it exists | |
$siteEntry = !is_bool($entryElement) ? $entryElement->getLocalized()->siteId($site->id)->one() : $entryElement; | |
$siteObject->entryUrl = $siteEntry ? $siteEntry->url : null; | |
// add 'isCurrent' property to each site | |
$siteObject->isCurrent = $site->id == $currentSite->id; | |
// compose the language code and language name | |
$languageCode = current(explode('-', $site->language)); | |
$locale = Craft::$app->i18n->getLocaleById($languageCode); | |
$siteObject->languageCode = $languageCode; | |
$siteObject->languageName = $locale->displayName; | |
return $siteObject; | |
}, $sites); | |
$groupObject->isCurrent = count(array_filter($groupObject->sites, function($item) { return $item->isCurrent; })) > 0; | |
$groupsArray[] = $groupObject; | |
} | |
return $groupsArray; | |
}), | |
/** | |
* @return Array All related entries with the site's group name as a key and the site url as value | |
* | |
* @example | |
* | |
* ```twig | |
* {% set siteUrls = findRelatedEntries(entry, { includeQueryString: true }) %} | |
* ``` | |
*/ | |
new TwigFunction('findRelatedEntries', function (Entry $entry, bool $includeQueryString = true) { | |
$queryString = ($includeQueryString) ? Craft::$app->getRequest()->getQueryStringWithoutPath() : ''; | |
return collect($entry->getLocalized()->all()) | |
->mapWithKeys(function (Entry $entry) use ($queryString) { | |
$url = $entry->url; | |
if ($queryString !== '') { | |
$url .= '?' . $queryString; | |
} | |
return [$entry->getSite()->getGroup()->name => $url]; | |
}) | |
->toArray(); | |
}), | |
/** | |
* @example | |
* | |
* ```twig | |
* {% set links = getCanonicals() %} | |
* {% set currentLink = links|filter(item => item.isCurrent)|first %} | |
* | |
* <link rel="alternate" href="{{ currentLink.url }}" hreflang="x-default"/> | |
* {% for link in links|filter((item) => not item.isCurrent) %} | |
* <link rel="alternate" href="{{ link.url }}" hreflang="{{ link.languageCode }}" /> | |
* {% endfor %} | |
* ``` | |
*/ | |
new TwigFunction('getCanonicals', function () { | |
// get current site and current element | |
$currentSite = Craft::$app->sites->currentSite; | |
$currentElement = Craft::$app->urlManager->matchedElement; | |
// get all sites by group that have a non-empty baseUrl | |
$sites = array_filter(Craft::$app->sites->getGroupById($currentSite->groupId)->getSites(), function ($site) { | |
return !empty($site->baseUrl); | |
}); | |
$altLinks = []; | |
foreach ($sites as $site) { | |
$url = $site->getBaseUrl(); | |
if ($currentElement) { | |
$otherLocaleElement = Craft::$app->elements->getElementById($currentElement->id, $currentElement->className(), $site->id); | |
// break early | |
if (is_null($otherLocaleElement) || !$otherLocaleElement->enabledForSite) | |
continue; | |
$url = $otherLocaleElement->url; | |
} | |
$link = new \stdClass(); | |
$link->url = $url; | |
$link->languageCode = current(explode('-', $site->language)); | |
$link->countryCode = last(explode('-', $site->language)); | |
$link->language = Craft::$app->i18n->getLocaleById($site->language)->displayName; | |
$locale = Craft::$app->i18n->getLocaleById($link->languageCode); | |
$link->displayName = $locale->displayName; | |
$link->isCurrent = $site->id == $currentSite->id; | |
$altLinks[] = $link; | |
} | |
return $altLinks; | |
}), | |
]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment