Yes, it is perfectly possible to load an Elementor Template via AJAX and still keep (almost) all the benefits of injecting the content in a traditional way. The general approach is:
Create an AJAX endpoint (using admin-ajax.php or the REST API) that returns the HTML of the template.
Render the Template using Elementor’s internal functions (or via shortcode).
Return the rendered content as the AJAX response.
Inject the content into the page with JavaScript at the desired time (for example, on scroll offset for a lazy load).
Below is a sample PHP code (to place in your functions.php or a custom plugin) and a JavaScript snippet that performs the request. The marks___ prefix is used for functions, variables are sanitized, and the nonce is checked for security.
PHP (functions.php or custom plugin)
<?php
namespace Marks\\ElementorAjax; // Example namespace for bigger projects
// Admin-Ajax hooks
add_action('wp_ajax_marks___load_elementor_template', __NAMESPACE__ . '\\\\marks___load_elementor_template_ajax');
add_action('wp_ajax_nopriv_marks___load_elementor_template', __NAMESPACE__ . '\\\\marks___load_elementor_template_ajax');
/**
* Load an Elementor template via AJAX
*/
function marks___load_elementor_template_ajax() {
// Basic security: nonce check
check_ajax_referer('marks___nonce', 'security');
// Sanitize template ID
$template_id = isset($_POST['template_id']) ? sanitize_text_field($_POST['template_id']) : '';
if (empty($template_id)) {
wp_send_json_error(['message' => 'Invalid template ID']);
}
// Check if Elementor is loaded
if (!did_action('elementor/loaded')) {
wp_send_json_error(['message' => 'Elementor was not initialized']);
}
// Render the template using Elementor's API
$html = \\Elementor\\Plugin::instance()->frontend->get_builder_content_for_display($template_id, true);
// Return the rendered HTML
wp_send_json_success(['html' => $html]);
}
JavaScript (front-end injection)
This script can be placed in your theme or enqueued using wp_enqueue_script.
It uses the marks___ prefix and securely passes the wp_create_nonce.
<script>
function marks___ajaxLoadElementorTemplate(templateId, containerSelector) {
const formData = new FormData();
formData.append('action', 'marks___load_elementor_template');
formData.append('template_id', templateId);
formData.append('security', '<?php echo esc_attr( wp_create_nonce("marks___nonce") ); ?>');
fetch('<?php echo esc_url( admin_url("admin-ajax.php") ); ?>', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Insert HTML into the desired container
const container = document.querySelector(containerSelector);
if (container) {
container.innerHTML = data.data.html;
}
} else {
console.error('Error loading the template:', data.data.message);
}
})
.catch(err => {
console.error('AJAX request failed:', err);
});
}
</script>
Lazy Load or Scroll-Triggered Loading
To trigger the template loading when the user scrolls near the container, use the following approach:
<script>
window.addEventListener('scroll', function marks___scrollCheck() {
const lazyElem = document.querySelector('#lazy-elementor-container');
if (!lazyElem) return;
const rect = lazyElem.getBoundingClientRect();
// If it's within 200px of the viewport, load the template
if (rect.top < window.innerHeight + 200) {
// Load the template via AJAX
marks___ajaxLoadElementorTemplate('1234', '#lazy-elementor-container');
// Remove the listener to avoid reloading
window.removeEventListener('scroll', marks___scrollCheck);
}
});
</script>
When the visitor is within 200px of #lazy-elementor-container, this script will trigger the AJAX request for the Elementor template with ID 1234.