Control how visitors are redirected based on language preferences.
Browser Language Detection Redirect
Lang Forge ships a built-in, SEO-safe Accept-Language redirect. Enable it with update_option('lf_auto_detect_language', true) (or the Settings checkbox). On the visitor’s first page load the plugin:
- Skips if
lf_languageorlf_autodetect_donecookies exist, if the request is notGET, or ifX-Requested-With: XMLHttpRequestis set — so AJAX, POST, and logged-in admin flows are never redirected. - Parses the browser’s
Accept-Languageheader against the site’s active languages. - If a non-default language matches, issues
wp_safe_redirect('/' . $detected . '/', 302)and setslf_autodetect_done=1(1-year cookie,is_ssl()-aware,Securewhen serving HTTPS) so the browser never gets redirected again. - If the detected language matches the default (or nothing matches), simply writes the
lf_autodetect_donemarker and continues — subsequent visits stay on/.
This replaces the earlier behaviour of silently serving translated content at the canonical URL, which broke hreflang and confused crawlers.
#### Overriding or extending the built-in redirect
If you need custom logic (geo-IP, user-agent allowlists, subdomain-specific opt-outs, etc.), disable the built-in flag and hook template_redirect yourself. The recipe below mirrors the plugin’s own implementation and is a good starting point:
/**
* Custom first-visit language redirect. Run only when the built-in
* `lf_auto_detect_language` option is OFF — otherwise you'll double-redirect.
*/
add_action('template_redirect', function () {
if (get_option('lf_auto_detect_language', false)) return; // plugin already handles it
if (!empty($_COOKIE['lf_language'])) return; // visitor has chosen
if (!empty($_COOKIE['lf_autodetect_done'])) return; // already redirected
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'GET') return; // POST/PUT never redirect
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])) return; // AJAX
$current = lf_get_current_language();
$default = lf_get_default_language();
if ($current !== $default) return; // already on a language URL
$accept = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
$preferred = [];
foreach (explode(',', $accept) as $part) {
$part = trim($part);
[$lang, $q] = array_pad(explode(';', $part, 2), 2, 'q=1');
$preferred[substr(trim($lang), 0, 2)] = floatval(str_replace('q=', '', $q));
}
arsort($preferred);
$languages = lf_get_languages();
foreach ($preferred as $code => $q) {
if (!isset($languages[$code]) || $code === $default) continue;
// Match the plugin's cookie name so the two paths share state.
setcookie(
'lf_autodetect_done', '1',
time() + YEAR_IN_SECONDS,
COOKIEPATH, COOKIE_DOMAIN, is_ssl()
);
wp_safe_redirect(home_url('/' . $code . '/'), 302);
exit;
}
}, 5);Stick to the lf_autodetect_done cookie name — when the built-in redirect is later flipped on, it’ll honour the cookie your custom code already set and won’t re-redirect the same visitor.
Country-Based Redirects
/**
* Redirect based on IP geolocation.
* Requires a geolocation service or database.
*/
add_action('template_redirect', function () {
if (isset($_COOKIE['lf_geo_redirect'])) return;
if (!is_front_page()) return;
$country_map = [
'DE' => 'de', 'AT' => 'de', 'CH' => 'de',
'FR' => 'fr', 'BE' => 'fr',
'US' => 'en', 'GB' => 'en', 'AU' => 'en',
];
// Use your preferred geolocation method
$country = apply_filters('theme_detect_country', '');
if ($country && isset($country_map[$country])) {
$target_lang = $country_map[$country];
$current = lf_get_current_language();
if ($target_lang !== $current && isset(lf_get_languages()[$target_lang])) {
$core = LF_Core::instance();
setcookie('lf_geo_redirect', '1', time() + 86400 * 7, '/');
wp_redirect($core->get_language_url($target_lang), 302);
exit;
}
}
}, 4);—