function getDomainName(string $url): string|bool {
if (empty($url) || !filter_var($url, FILTER_VALIDATE_URL)) {
return false;
}
$host = parse_url($url, PHP_URL_HOST);
$parts = explode('.', $host);
$count = count($parts);
if ($count > 2) {
$tld = $parts[$count - 1]; // eg: "uk" or "com"
$sld = $parts[$count - 2]; // eg: "co" or "example"
// top-level domain is 2 letters (eg: uk, au, br, za) AND second-level domain is 2-3 letters (eg: co, com, org, net, edu)
if (strlen($tld) === 2 && (strlen($sld) === 2 || strlen($sld) === 3)) {
// Multi-part extension: Grab 3 parts (eg: domain.co.uk)
$domain = ($count >= 3) ? $parts[$count - 3] . '.' . $sld . '.' . $tld : $host;
} else {
// Standard extension: Grab 2 parts (eg: domain.com)
$domain = $sld . '.' . $tld;
}
} else {
// Host already 2 parts (eg: domain.com or domain.co)
$domain = $host;
}
return $domain;
}
OpenCart: Pass template directory for Twig includes
Build the path in a controller…
$dir_opencart = str_replace('\\', '/', DIR_OPENCART);
$dir_template = str_replace('\\', '/', realpath(__DIR__ . '/../../view/template'));
$data['dir_twig_include'] = str_replace($dir_opencart, '', $dir_template) . '/';
$this->load->view('folder/name', $data);
Then use it in a template…
{% include dir_twig_include ~ 'folder/filename.twig';
🍻
Coerce browsers that ignore autocomplete=”off” to stop auto-filling credential fields
The Chromium Project intentionally ignores standard W3C specifications by not honoring the autocomplete="off" attribute of forms and inputs when their heuristics discover credential fields.
Some credentials have nothing to do with the current domain, are not auto-fillable by browser password managers, and should not require developers to deploy workarounds like the auto-fill trap below.
Continue readingGoogle Chrome: Prevent default search engine from loading in new tabs (Caveat: Disables address bar search).
I’m conflicted on whether I prefer this, or the default search engine loading in every new tab. That being said, here’s how to prevent your default search engine from loading every time you open new tabs in Google Chrome.
Continue readingFix Google reCaptcha’s “Missing form label” Accessibility Error
Chances are screen readers overlook Google’s faux pas when it comes to not providing labels for thier hidden g-recaptcha-response TEXTAREA, but we would prefer not seeing such errors during accessibility evaluations.
Here is a simple script to handle the problem gracefully.
Continue readingAdding pause/play button to Bootstrap carousel for better accessibility.
Starting with the example code for a carousel with indicators we add another button to the beginning of .carousel-indicators.
<button type="button" class="btn btn-sm" id="carouselExamplePause" aria-label="Pause">⏸︎</button>
Then we add JavaScript to make it functional.
Continue readingAutomatically adjust scroll-padding-top for “Skip to main content” links (useful for .sticky-top headers)
window.addEventListener('resize', () => {
document.documentElement.style.scrollPaddingTop = document.getElementById('content').getBoundingClientRect().top
})
Tip: Set default using CSS in case JavaScript is disabled.
html {
scroll-padding-top: 50px;
}
Toggle Bootstrap collapsible state by device screen size
How to turn on/off Bootstrap’s collapse function based on window.innerWidth
function toggleCollapsibility(container) {
// Default to disabled
let find = 'collapse', replace = 'collapse-disabled'
// We only want collapse on smaller devices
if (window.innerWidth < 992) {
// Flip to enabled
[find, replace] = [replace, find]
}
document.querySelectorAll(`${container} [data-bs-toggle="${find}"]`).forEach((element) => {
element.dataset.bsToggle = replace
})
}
Continue reading Helpful CSS Classes for Flipping and Rotating Elements
Useful CSS transformation classes for use with Content Security Policy (CSP).
/* Flip Horizontal */
.flip-h {
transform: scaleX(-1);
}
/* Flip Vertical */
.flip-v {
transform: scaleY(-1);
}
/* Rotation */
.rotate-0, .rotate-360 {
transform: rotate(0deg);
}
.rotate-45 {
transform: rotate(45deg);
}
.rotate-90 {
transform: rotate(90deg);
}
.rotate-135 {
transform: rotate(135deg);
}
.rotate-180 {
transform: rotate(180deg);
}
.rotate-225 {
transform: rotate(225deg);
}
.rotate-270 {
transform: rotate(270deg);
}
.rotate-315 {
transform: rotate(315deg);
}
Combining flip and rotate classes can achieve most desired display transformations.
Disable CodeIgniter 4 Cache Handler During Development
We recently ran into an issue where CodeIgniter’s cache() produced unexpected results during development. Our problem was forgetting to change the cache handler from ‘file’ to ‘dummy’ outside of the production environment. So we do not have to remember to change the handler, we modified our App’s Config\Cache::handler as follows…
public string $handler = (ENVIRONMENT === 'production') ? 'file' : 'dummy';
That one simple “set it and forget it” change could have saved wasted time spent debugging the problem.
Update: While discussing this with other developers, one alternative would be updating the .env file.
Hide Bootstrap 5 Tooltips When Clicked
Here’s an easy way to hide Bootstrap tooltips onclick. Useful for focusable elements that do not change the current document’s location.
document.querySelectorAll('[data-bs-toggle="tooltip"], .add-bs-tooltip').forEach(element => {
new bootstrap.Tooltip(element)
element.addEventListener('click', event => {
bootstrap.Tooltip.getInstance(event.currentTarget).hide()
})
})
Bonus: Our .add-bs-tooltip selector is for eliminating the need to wrap other Bootstrap elements that already have the data-bs-toggle attribute (modals, dropdowns, etc). 😉
Block Top-Level Domains (TLDs) Using cPanel Email Filters
Initially we had a long list of “From ends with” filters like below trying cut down on our most common spam sources.
From ends with .ru
From ends with .pk
From ends with .in
From ends with .de
From ends with .jp
From ends with .kr
Recently I noticed those rules were effectively blocking those TLDs. It did not take long to figure out why. Here are example FROM headers email systems might encounter.
From: "John Doe" <john@example.com>
From: Jane <jane@example.com>
From: bob@example.com
The problem with using “From ends with” is the header frequently ends with a greater-than symbol. So we decided to use “From matches regex” instead.
Continue reading