Conditional Content
Mark up any chunk of content so it only renders for visitors in specific languages - or everywhere except specific languages. Three surfaces, one shared core predicate: they can’t drift apart.
- Gutenberg block:
perflocale/if-language- pick from the block inserter ("Show If Language"), multi-select languages in the sidebar, add any inner blocks - Shortcode:
[perflocale_if langs="..."]or[perflocale_if not_langs="..."] - PHP helper:
perflocale_if_language( $slugs, $invert = false )
Gutenberg block
Insert the Show If Language block, add whatever inner blocks you want to conditionalise, then pick the target languages in the block’s inspector sidebar. Toggle Invert to flip the condition (show everywhere except the selected languages).
Because it’s server-rendered, the condition is evaluated on the actual request - no client-side flashing and no effect on cached HTML served by a CDN when the cache key includes language context (see Cache-Tag headers).
Shortcode
[perflocale_if langs="fr,de"]
Shown only to French and German visitors.
[/perflocale_if]
[perflocale_if not_langs="en"]
Shown to every visitor except those browsing the English version.
[/perflocale_if]
[perflocale_if langs="fr"]
<a href="/fr/promo/">Voir la promo</a>
[/perflocale_if]
Nested shortcodes and blocks inside the enclosed content render normally. Use langs for positive match or not_langs for the inversion - if both are set, not_langs wins.
PHP helper
if ( perflocale_if_language( [ 'fr', 'de' ] ) ) {
echo 'Shown only to French or German visitors.';
}
// Invert: show for every language EXCEPT these.
if ( perflocale_if_language( [ 'en' ], true ) ) {
// ...
}
// All three of these call the same function:
perflocale_if_language( 'fr' );
perflocale_if_language( 'fr,de' );
perflocale_if_language( [ 'fr', 'de' ] );
The helper accepts a single slug, a comma-separated string, or an array. Second argument $invert flips semantics to "NOT in the list".
Edge-case semantics
| Situation | Behaviour |
|---|---|
| Empty language list, not inverted | Block hides (nothing matches) |
| Empty language list, inverted | Block shows (“show except none” = show everywhere) |
| Language router not available yet | Block hides (fail-closed to avoid leaking content in the wrong locale) |
| Language slug not in active languages | Never matches - block hides |
Both langs and not_langs set | not_langs wins (inverted match) |
Performance
Each evaluation is one in_array() against a short normalised array plus a single per-request cached current-language lookup. No database I/O. The block renders server-side so there’s no client-JS cost either.
Common use cases
- Localised promotions: show a discount banner only in specific regional languages
- Legal disclaimers that apply only in certain jurisdictions (tie to language as a proxy)
- Third-party widgets that only make sense in one locale (local payment methods, local social buttons)
- Calls-to-action in the visitor’s own language pointing to localised content
- Hiding untranslated sections while a translation is pending
Shared core
All three surfaces delegate to the same static method - PerfLocale\Frontend\ConditionalContent::should_show( array $languages, bool $invert = false ). If you’re building an addon that needs the same predicate (e.g. a custom query filter or a mail template guard), call it directly from PHP.