WP Residence Help WP Residence Help

  • WPRESIDENCE
  • Video Tutorials
  • Client Support
  • API
Home / WPResidence Translate Plugin / Language Switcher Widget — Developer Reference

Language Switcher Widget — Developer Reference

35 views 0

This article documents the frontend language switcher widget shipped with wpresidence-translate. It covers registration, option storage, render pipeline, translation-target resolution, and the inline script that handles cookie persistence and navigation. The user-facing sibling explains the site-owner workflow; for the product overview see the multi-language real estate website guide.

Source Files

File Role
includes/widgets/language-switcher.php Widget bootstrap – registers the sidebar widget and control via wp_register_sidebar_widget() / wp_register_widget_control().
includes/widgets/language-switcher-options.php Instance storage helpers (wpr_translate_language_switcher_get_options(), _save_options(), _next_number()).
includes/widgets/language-switcher-display.php Frontend render – wpr_translate_language_switcher_widget_display() and wpr_translate_render_language_switcher_dropdown().
includes/widgets/language-switcher-control.php Admin form renderer at Appearance > Widgets – single Title field.

Registration

The widget uses the legacy wp_register_sidebar_widget() API rather than WP_Widget because the plugin intentionally keeps multiple instances behind a single option. wpr_translate_register_language_switcher_widget() loops saved instances and registers each, plus a catch-all id for the widgets screen.

$widget_ops = array(
    'classname'   => 'wpr-language-switcher-widget',
    'description' => __( '...', 'wpr-translate' ),
);
$control_ops = array( 'id_base' => 'wpr_translate_language_switcher' );

Instance numbers start at 1 and increment via wpr_translate_language_switcher_next_number(). Registered IDs follow the pattern wpr_translate_language_switcher-{N}.

Option Storage

All instances live under a single option:

Option key Shape
wpr_translate_language_switcher (constant WPR_TRANSLATE_LANGUAGE_SWITCHER_OPTION) array( int $number => array( ‘title’ => string ) )

Helpers sort the array by numeric key, sanitize titles through sanitize_text_field(), and delete the option when no instances remain.

Screenshot: wp_options row for wpr_translate_language_switcher with serialized instance map

Render Pipeline

wpr_translate_language_switcher_widget_display( $args, $widget_args ) is the display callback. In order it:

  1. Loads saved options and resolves the instance title by $widget_args[‘number’].
  2. Calls wpr_translate_get_active_languages() and bails when fewer than 2 languages exist.
  3. Detects the current context – is_singular(), get_queried_object() for WP_Term, global $post fallback.
  4. Resolves the current language via wpr_translate_get_context_language( $current_post_id ); for term archives it overrides with wpr_translate_get_element_language( $term_id, ‘tax_{taxonomy}’ ).
  5. Builds a $translation_map – language code to target post/term ID – using wpr_translation_get_translation_group() for posts and wpr_translate_lookup_translated_term_id_strict() for terms.
  6. Computes a fallback post URL via wpr_translation_get_post_language_permalink(), falling back to get_permalink().
  7. Iterates languages, builds per-language payload (code, label, flag URL, target URL, router URL, fallback URL, cookie flag), and emits <li> items.
  8. Delegates to wpr_translate_render_language_switcher_dropdown() for the Bootstrap dropdown shell.
  9. Emits a small inline script that wires clicks, updates the button label/flag, stores the cookie preference, and navigates.

Output Shape

<div id="wpr-language-switcher-{widget_id}" class="dropdown wpr-language-switcher"
     data-current-post-id="…" data-current-language-code="…"
     data-flag-alt-template="%s flag">
  <button class="btn dropdown-toggle wpr-language-switcher-toggle"
          data-bs-toggle="dropdown" aria-expanded="false">…</button>
  <ul class="dropdown-menu wpr-language-switcher-menu">
    <li role="presentation">
      <button class="dropdown-item wpr-language-switcher-item"
              data-language-code="fr" data-translation-id="123"
              data-target-url="…" data-router-url="…"
              data-fallback-url="…" data-can-set-cookie="1"
              data-flag-url="…" data-label="Français">…</button>
    </li>
  </ul>
</div>

When the widget is injected into a WPRentals header menu, the helper wpr_translate_is_wprentals_theme_active() adds sub-menu, menu-item, and menu-item-link classes plus Bootstrap-3 data-toggle=”dropdown” for compatibility.

Target URL Resolution

For each language the widget picks the best URL in this priority:

  1. Direct translation – wpr_translation_get_post_language_permalink() for posts or get_term_link() for terms.
  2. Front-page root – when the current post is the front page (or one of its translations), the language root URL from wpr_translate_language_router_get_switch_url().
  3. Fallback post/term URL – the default-language permalink of the current post or term, if any.
  4. Router URL – wpr_translate_language_router_get_switch_url( $language ) for archives, search, 404s.

The data-can-set-cookie attribute is 0 when the URL is a fallback (no real translation) so the cookie is not stuck on a language the visitor did not intentionally pick.

Cookie Persistence

On click, the inline script POSTs to admin-ajax.php with action=wpr_translate_set_language_cookie, the selected language code, a wp_create_nonce(‘wpr_translate_language_cookie’), and current_post_id. The transport preference order is navigator.sendBeacon, fetch with keepalive: true, and finally XMLHttpRequest so navigation is not delayed.

The server stores the choice under the cookie wpestate_translation_lang_pref, which wpr_translate_resolve_preferred_language() reads on subsequent requests.

Screenshot: Browser DevTools Application tab showing the wpestate_translation_lang_pref cookie

Flags

Flag URLs are constructed with WPR_TRANSLATE_URL . ‘assets/img/flags/4×3/{code}.svg’. The widget uses the language’s explicit flag field first and falls back to the language code if no flag is set. Missing flags render an <img> with no src and the hidden-state class wpr-language-switcher-flag–hidden so the layout stays intact.

Menu Injection

$args[‘wpr_translate_menu_injected’] tells the display callback it is rendering inside a WordPress nav menu rather than a standalone widget area. Combined with wpr_translate_is_wprentals_theme_active(), this toggles WPRentals-compatible markup. Menu injection itself is handled by nav-menu-locations-frontend.php – outside the scope of this article.

Elementor Widget

There is no dedicated Elementor language switcher widget in either the plugin or residence-elementor at this time. For Elementor layouts, drop a standard WordPress widget area or use a shortcode/widget via the Sidebar widget. The legacy WPResidence theme widget WP_Estate_Translation continues to work for older sites, but new integrations should use the widget documented here.

Extension Tips

  • Do not guard on $_SERVER[‘HTTP_ACCEPT_LANGUAGE’]. The widget never renders different markup per visitor – language detection happens via cookie on click, not at render time.
  • Multiple instances: each instance is keyed by its number, and the wrapper ID is derived from $args[‘widget_id’]. Two instances on the same page each get their own handlers.
  • Styling: hook your theme CSS on .wpr-language-switcher, .wpr-language-switcher-toggle, and .wpr-language-switcher-item. Avoid overriding the inline script.
  • Translation-group helpers: if you are building a custom switcher, reuse wpr_translation_get_translation_group() and wpr_translation_get_post_language_permalink() rather than reading the trid tables directly.

Related Articles

  • Managing Languages – upstream option the widget reads from.
  • Language Detection & Redirects – how the cookie is consumed on subsequent requests.
  • Admin Bar Language Switcher & Editor Header Selector – admin-side companion.

See the multi-language real estate website page for product context.

WPResidence Translate Plugin

Related Articles

  • String Scanner — Developer Guide
  • The String Scanner
  • Gettext Pipeline & MO Files — Developer Guide
  • Gettext & MO Files — Making Translations Appear on the Front End

Help Categories

  • 18Agent, Agency & Developers
  • 5Blog Posts & Blog Lists
  • 38Elementor Shortcodes Built-In
  • 56FAQ
  • 15Footer
  • 5Getting Started
  • 37Header
  • 2IDX & MLSImport
  • 6Installation & Setup
  • 22Installation FAQ
  • 23Maps & Location Settings
  • 21Multi-Language Third Party Plugins
  • 6Other Third party Plugins
  • 19Pages
  • 4Payments & Monetization
  • 20Property Lists, Categories & Archive
  • 36Property Pages & Layouts
  • 31Search & Filtering
  • 163Technical how to | Custom Code Required
  • 8Technical: Actions and filters
  • 6Technical: Child Theme
  • 86Theme Options & Global Settings
  • 6Translations & Languages
  • 16WPBakery Shortcodes
  • 51WPResidence / WPEstate CRM
  • 50WPResidence 5.0 Documentation
  • 8WPResidence Elementor Studio
  • 50WPResidence Translate Plugin

Join Us On

Powered by WP Estate - All Rights Reserved
  • WPRESIDENCE
  • Video Tutorials
  • Client Support
  • API