---
title: "Conditional Content - PerfLocale"
description: "Show or hide content based on the visitor's language. Gutenberg block, shortcode, and PHP helper - one shared predicate across all three."
canonical: "https://perflocale.com/docs/conditional-content/"
source: "https://perflocale.com/docs/conditional-content/"
format: "markdown"
---
# 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](https://perflocale.com/docs/cache-tags/)).

## 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, and both the block and the shortcode then escape the result: the rendered content is passed through `wp_kses()` with the `post` allowlist extended to cover everything WordPress core’s own block renderers emit (`<iframe>` embeds, inline `<svg>`, responsive-image `srcset`/`sizes`). Inline `<script>`/`<style>` tags and event-handler attributes are stripped — widgets that enqueue their JavaScript through `wp_enqueue_script()` are unaffected, but raw script embeds are not kept. To allow extra markup per-site, extend the allowlist with the `perflocale/conditional_content/allowed_html` filter. 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 — script-based embeds need their markup allowed via the `allowed_html` filter, or their JS enqueued rather than inlined)
-   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.

[← Shortcodes reference](https://perflocale.com/docs/shortcodes/#perflocale-if)
