Watch YouTube Video
The goal
It could be that you only want to show certain elementor popups in a certain language. This is not possible with the current tools. That is why I have developed my own extension which makes this possible.
To make it as seamless as possible I wanted to add an extra rule to Elementor’s “advanced rules”. Unfortunately the elementor documentation regarding this part is not that extensive.
In fact, this piece only talks about injecting controls to the standard widgets. But I want to show my control at the bottom of the “Advanced rules” section of the popup Publish Settings, as shown on the screenshot below.
The revelation
So I started digging, and what I figured out was that we can actually hook into way more stuff then documented with the elementor/element/{$stack_name}/{$section_id}/after_section_end
hook.
The actual popup timing controls are specifiek in timing.php
, if you’re interested, here is the full code of that file.
There are two interesting bits that we should take a closer look at.
public function get_name() {
return 'popup_timing';
}
$this->start_controls_section( 'timing' );
The above pieces of code are the missing pieces we need to complete our action hook. This would now become: elementor/element/popup_timing/timing/after_section_end
.
Where {$stack_name}
was replaced with the return value of get_name()
namely popup_timing'
. And {$section_id}
was replaced with the value passed to $this->start_controls_section
namely timing
The build – Back-end
I’m not interested in the build, show me the code.
With this information in mind we can start building. The first thing I did was run some checks to make sure that elementor edit mode is active, that elementor itself is running and that polylang is running.
$edit_mode = ElementorPlugin::$instance->editor->is_edit_mode();
if (
!$edit_mode ||
!is_plugin_active("elementor/elementor.php") ||
!function_exists("pll_languages_list")
) {
return;
}
Afterwards we need to start injecting our controls. Also we add the first control which functions as a header.
$element->start_injection([
"at" => "after",
"of" => "browsers",
]);
$element->add_control("polylang_heading", [
"type" => ElementorControls_Manager::HEADING,
"label" => esc_html__("Show in languages", "elementor-pro"),
]);
After that I’ve performed some hocus pocus on the given languages to popuplate the most important control. I’m not going in details what this bit of code does. If it’s unclear, feel free to let me know via the comments down below.
$default_languages = pll_languages_list();
$popup_display_settings = end(
get_post_meta(get_the_ID(), "_elementor_popup_display_settings")
);
$chosen_languages = [];
if ($popup_display_settings["timing"] !== null) {
!array_key_exists("active_languages", $popup_display_settings["timing"])
? ($chosen_languages =
$popup_display_settings["timing"]["active_languages"])
: null;
}
empty($chosenLanguages) ? ($chosen_languages = $default_languages) : null;
$languageOptions = [];
foreach ($default_languages as $key => $lang) {
$languageOptions[$lang] = $lang;
}
Then we add the last two controls. First one is the languages select, second one is the switcher.
$element->add_control("active_languages", [
"type" => ElementorControls_Manager::SELECT2,
"multiple" => true,
"default" => array_values($chosen_languages),
"options" => $languageOptions,
]);
$element->add_control("polylang", [
"type" => ElementorControls_Manager::SWITCHER,
"classes" => "elementor-popup__display-settings__group-toggle",
"frontend_available" => true,
]);
All that’s left is the end the injection.
$element->end_injection();
If we wrap all that code in an action hooks which calls the action we spoke about previously you will end up with this bit of code:
add_action(
"elementor/element/popup_timing/timing/after_section_end",
function ($element, $args) {
$edit_mode = ElementorPlugin::$instance->editor->is_edit_mode();
if (
!$edit_mode ||
!is_plugin_active("elementor/elementor.php") ||
!function_exists("pll_languages_list")
) {
return;
}
$element->start_injection([
"at" => "after",
"of" => "browsers",
]);
$element->add_control("polylang_heading", [
"type" => ElementorControls_Manager::HEADING,
"label" => esc_html__("Show in languages", "elementor-pro"),
]);
$default_languages = pll_languages_list();
$popup_display_settings = end(
get_post_meta(get_the_ID(), "_elementor_popup_display_settings")
);
$chosen_languages = [];
if ($popup_display_settings["timing"] !== null) {
!array_key_exists(
"active_languages",
$popup_display_settings["timing"]
)
? ($chosen_languages =
$popup_display_settings["timing"]["active_languages"])
: null;
}
empty($chosenLanguages)
? ($chosen_languages = $default_languages)
: null;
$languageOptions = [];
foreach ($default_languages as $key => $lang) {
$languageOptions[$lang] = $lang;
}
$element->add_control("active_languages", [
"type" => ElementorControls_Manager::SELECT2,
"multiple" => true,
"default" => array_values($chosen_languages),
"options" => $languageOptions,
]);
$element->add_control("polylang", [
"type" => ElementorControls_Manager::SWITCHER,
"classes" => "elementor-popup__display-settings__group-toggle",
"frontend_available" => true,
]);
$element->end_injection();
},
10,
2
);
The build – Last steps
Once we got all that work done I had to figure out a way to conditionally show the popup based on the defined languages. For that we need one more thing: A script that listens for elementor popup events which we can hijack to perform our conditional checks
Below is the script which we will put in the footer. This script listens for elementor/popup/show
events. If such an event is triggered we temporarily hide the popup, untill we receive response from an AJAX request to the back-end.
add_action("wp_footer", function () {
// Make sure we don't hide the popup in editor mode
if (ElementorPlugin::$instance->preview->is_preview_mode()) {
return;
} ?>
});
All that’s left is to add the following action which will run when an ajax request is sent. This will get all the required data from the databank and return it so that the appropriate check can be completed.
function fetch_popup_timing_triggers()
{
$meta = get_post_meta(
$_POST["postid"],
"_elementor_popup_display_settings",
false
);
wp_send_json([
"current_lang" => pll_current_language(),
"meta" => end($meta),
]);
wp_die();
}
add_action("wp_ajax_nopriv_fetch_popup_timing_triggers", "fetch_popup_timing_triggers");
add_action("wp_ajax_fetch_popup_timing_triggers", "fetch_popup_timing_triggers");
When done correctly, you should now be able to conditionally show elementor popup based on a language setting, dictated by Polylang. If you are stuck, feel free to leave a comment and I’ll try to help you out.