Contents

Multilingual (WPML / Polylang) — Plugixa Testimonial

Plugixa Testimonial integrates with WPML and Polylang out of the box. If either is active, the plugin automatically detects it and makes your testimonials, categories, and custom fields translatable. No separate setup or switch is required.

How it works (in 30 seconds)

Plugixa Testimonial uses the Translation Group pattern. Every testimonial, category, and custom field has two extra columns:

  • language_codeen, fr, de, etc.
  • translation_group — a UUID shared by all translations of the same item.

Items with the same translation_group UUID are translations of each other, regardless of language. This is the same model WPML uses internally, so it plays nicely with both WPML and Polylang.

┌─────────────────────────────────────────────┐
│ wp_plugixatestimonial_testimonials          │
├──┬──────────────────┬──────────┬────────────┤
│id│ client_name      │ lang     │ group      │
├──┼──────────────────┼──────────┼────────────┤
│ 1│ Jane Doe         │ en       │ abc-123…   │  ← English
│ 2│ Jane Doe         │ fr       │ abc-123…   │  ← French (same group)
│ 3│ Jane Doe         │ de       │ abc-123…   │  ← German  (same group)
│ 4│ Bob Smith        │ en       │ def-456…   │  ← different item
└──┴──────────────────┴──────────┴────────────┘

Enable / disable

Multilingual is on by default when WPML or Polylang is detected. Turn it off globally from Plugixa Testimonial → Settings → Multilingual:

Setting Values Default Effect
multilingual_enabled auto, off auto auto = enable when WPML/Polylang is present. off = ignore language, show everything.

Which fields are translatable

Entity Translatable Shared across languages
Testimonials client_name, client_role, client_company, testimonial_text, website_url rating, client_photo_id, video_url, status, is_featured, display_order, source, categories
Categories name, slug, description status, display_order
Custom Fields PRO field_label, placeholder field_key, field_type, field_options, is_required, show_in_frontend, menu_order

“Shared” fields are copied automatically when you create a translation, so you don’t have to set the rating or photo again in every language.

Creating translations

Admin UI

Every testimonial, category, and custom field form shows a TranslationStatus panel in the sidebar with flag icons for each site language:

  • Colored flag — translation exists for that language. Click to jump.
  • Grey flag — missing translation. Click to open the Create Translation dialog.

The Create Translation dialog:

  1. Shows a language dropdown with only the remaining untranslated languages.
  2. Clones the source item into the new language.
  3. Shares the translation_group UUID so the items are linked.
  4. Copies shared fields automatically.
  5. Opens the new translation for editing.

Row-level flags in list tables

Each row in the Testimonials, Categories, and Custom Fields lists shows compact flag indicators for all site languages. This gives you a quick visual of translation coverage across the entire dataset.

Filtering by language

Each list page has a Language filter section inside its filter drawer:

[All] [🇺🇸 EN] [🇫🇷 FR] [🇩🇪 DE]
  • All — show every item regardless of language.
  • Specific language — show only items matching that language code.

The selected language is persisted in localStorage (via LanguageContext) and reflected in the filter badge count, active filter chips, and reset actions.

REST API

# Get available languages
GET /wp-json/plugixatestimonial/v1/multilingual/languages

# Multilingual status
GET /wp-json/plugixatestimonial/v1/multilingual/status

# Get translations for a testimonial/category/custom-field
GET /wp-json/plugixatestimonial/v1/multilingual/{entity}/{id}/translations

# Create a translation (clones the source)
POST /wp-json/plugixatestimonial/v1/multilingual/{entity}/{id}/translations
{ "language": "fr" }

# Link two existing items as translations
PUT /wp-json/plugixatestimonial/v1/multilingual/{entity}/link-translations
{ "source_id": 5, "target_id": 12 }

# Unlink a translation
DELETE /wp-json/plugixatestimonial/v1/multilingual/{entity}/{id}/translations/{lang}

Where {entity} is testimonials, categories, or custom-fields.

Frontend behavior

Automatic language detection

On the frontend, the shortcode detects the current language from:

  1. WPML — via WPML API hooks.
  2. Polylangpll_current_language(), with ?lang= query parameter as an override.
  3. Fallback — the site’s default language.

Only testimonials matching the current language are rendered.

Forcing a language in a shortcode

You can force a language regardless of WPML/Polylang state:

[plugixa_testimonials language="fr"]

Useful for:

  • Building a language-specific landing page without setting up full page translation.
  • Embedding testimonials in a single language from a language picker.

Frontend submission passthrough

When a visitor submits a testimonial via [plugixa_testimonial_form]:

  • The form’s JS reads the current site language from the page.
  • Sends it as language_code in the submit payload.
  • The new testimonial is created with that language_code.

No UI change needed — the passthrough is automatic. See Submission Form.

Where language is stored

Database columns

Three tables have these columns:

language_code      VARCHAR(10)    -- e.g., 'en', 'fr'
translation_group  VARCHAR(36)    -- UUID v4

Indexed on both columns for fast filtering.

Backfill for existing installs

When you activate a multilingual-aware version:

  1. The activator adds language_code and translation_group columns if missing.
  2. Activator::maybe_backfill_null_language_codes() backfills every existing row with:
    • language_code = site’s default language (reads Polylang default_lang directly from wp_options for reliable early-load detection).
    • translation_group = a new UUID (unique per item).
  3. The backfill runs once on admin init.

If the backfill fails or you need to re-run it, deactivate and reactivate the plugin.

WPML configuration

The plugin ships with a wpml-config.xml file that registers shortcode attributes as translatable content. WPML String Translation can then translate inline shortcode strings (like custom button_text values) automatically.

Usage in custom code

Check if multilingual is active

if ( \PlugixaTestimonial\Multilingual::instance()->is_multilingual_active() ) {
    // WPML or Polylang is installed AND the feature isn't disabled
}

Get the current language

$lang = \PlugixaTestimonial\Multilingual::instance()->get_current_language();
// → 'en', 'fr', etc.

Build a language-aware WHERE clause

$ml      = \PlugixaTestimonial\Multilingual::instance();
$current = $ml->get_current_language();
$default = $ml->get_default_language();

[ $where_sql, $where_values ] = $ml->build_language_where(
    't',                                  // table alias
    'plugixatestimonial_testimonials',    // logical table
    $current,
    $default
);

$sql = "SELECT * FROM {$wpdb->prefix}plugixatestimonial_testimonials t WHERE 1=1 $where_sql";
$testimonials = $wpdb->get_results( $wpdb->prepare( $sql, ...$where_values ) );
\PlugixaTestimonial\Multilingual::instance()->link_translations(
    'plugixatestimonial_testimonials',
    $source_id,
    $target_id
);

Hooks

Hook Type Description
plugixatestimonial_multilingual_active filter Override auto-detection (return bool).
plugixatestimonial_current_language filter Override the detected current language.
plugixatestimonial_available_languages filter Modify the languages array.
plugixatestimonial_language_where filter Modify the WHERE clause fragment.
plugixatestimonial_before_link_translations action Before linking two items.
plugixatestimonial_after_link_translations action After linking.

Troubleshooting

I see the same testimonial in every language

  • Check that the testimonial has a non-empty language_code. Empty = “belongs to every language” (legacy behavior).

Translation not showing up on the frontend

  1. Confirm the testimonial has status = approved in every language (each translation has its own status).
  2. Confirm the language_code matches the URL language (e.g., fr not fr_FR).
  3. Check whether the testimonial’s categories are also translated — a translated testimonial with only English categories may be filtered out by a translated category filter.

My existing testimonials have no language

Deactivate and reactivate the plugin. The activator re-runs maybe_backfill_null_language_codes() which sets every NULL-language row to the site default language.

Quick Links