=')) {
add_action('admin_notices', [$this, 'repefoel_admin_notice_minimum_elementor_version']);
return;
}
if (class_exists('ACF')) {
// Detect Pro
if (function_exists('acf_add_options_page')) {
define('REPEFOEL_USING_ACF_PRO', true);
$this->repefoel_acf_pro_include();
$this->repefoel_acf_free_include();
} else {
define('REPEFOEL_USING_ACF_PRO', false);
$this->repefoel_acf_free_include();
}
}
}
public function repefoel_acf_pro_include()
{
add_action('elementor/widgets/widgets_registered', [$this, 'repefoel_register_new_widgets']);
add_action('elementor/elements/categories_registered', [$this, 'REPEFOEL_cat_register']);
add_action('elementor/controls/register', [$this, 'REPEFOEL_custom_controls']);
add_action('wp_enqueue_scripts', [$this, 'repefoel_frontend_enqueue_script']);
// Register Elementor Template
add_action('elementor/documents/register', [$this, 'REPEFOEL_elementor_document_register']);
// Add to template library
add_filter('elementor/template-library/sources/local/template_types', [$this, 'REPEFOEL_add_template_type']);
// Add template type to admin
add_action('elementor/admin/after_create_settings', [$this, 'REPEFOEL_register_admin_fields'], 15);
add_action('elementor/editor/after_enqueue_scripts', [$this, 'repefoel_enqueue_editor_scripts']);
add_action('wp_ajax_repefoel_create_elementor_repeater_template', [$this, 'repefoel_create_elementor_repeater_template']);
add_action('wp_ajax_repefoel_update_template_preview_settings', [$this, 'repefoel_update_template_preview_settings']);
// Enqueue REPEFOEL template CSS inside the editor preview so widget styles appear correctly.
// Elementor only loads CSS for the document being edited; embedded templates need explicit loading.
add_action('wp_enqueue_scripts', [$this, 'repefoel_enqueue_preview_template_styles']);
// Check if Dynamic Tags module exists (Pro feature)
if (!class_exists('\Elementor\Modules\DynamicTags\Module')) {
add_action('admin_notices', [$this, 'repefoel_admin_notice_pro_required']);
return;
}
add_action('elementor/dynamic_tags/register', [$this, 'repefoel_register_dynamic_tags']);
}
/**
* In the Elementor editor preview, enqueue CSS for every REPEFOEL repeater
* template used on the current page so widget styles render correctly.
*/
public function repefoel_enqueue_preview_template_styles()
{
if (!class_exists('\Elementor\Plugin')) {
return;
}
if (!\Elementor\Plugin::instance()->preview->is_preview_mode()) {
return;
}
$post_id = get_the_ID();
if (!$post_id) {
return;
}
$raw = get_post_meta($post_id, '_elementor_data', true);
if (empty($raw)) {
return;
}
$data = json_decode($raw, true);
if (!is_array($data)) {
return;
}
$template_ids = array_unique(array_filter($this->repefoel_extract_template_ids($data)));
foreach ($template_ids as $template_id) {
if (class_exists('\Elementor\Core\Files\CSS\Post')) {
try {
\Elementor\Core\Files\CSS\Post::create((int) $template_id)->enqueue();
} catch (\Throwable $e) {
// Skip templates with missing or corrupted Elementor settings meta.
}
}
}
}
/**
* Recursively walk Elementor element data and collect every
* repefoel_template_select value from REPEFOEL widgets.
*/
private function repefoel_extract_template_ids(array $elements)
{
$widget_types = [
'REPEFOEL_widget_repeater',
'REPEFOEL_widget_repeater_carousel',
'REPEFOEL_widget_post_repeater',
];
$ids = [];
foreach ($elements as $element) {
if (!is_array($element)) {
continue;
}
$widget_type = $element['widgetType'] ?? '';
if (in_array($widget_type, $widget_types, true)) {
$tid = (int) ($element['settings']['repefoel_template_select'] ?? 0);
if ($tid > 0) {
$ids[] = $tid;
}
}
if (!empty($element['elements']) && is_array($element['elements'])) {
$ids = array_merge($ids, $this->repefoel_extract_template_ids($element['elements']));
}
}
return $ids;
}
public function repefoel_acf_free_include()
{
add_action('elementor/dynamic_tags/register', [$this, 'repefoel_free_register_dynamic_tags']);
}
/**
* Enqueue custom scripts for the editor
*/
public function repefoel_enqueue_editor_scripts()
{
wp_enqueue_script(
'REPEFOEL-repeater-template',
plugin_dir_url(__FILE__) . 'assets/js/repeaters_template.js',
['jquery', 'elementor-editor'],
REPEFOEL__PLUGIN_VERSION,
true
);
// Field name => [post IDs with data] map, used to grey out Repeater
// Field options that don't apply to the selected source post.
$repeater_widget = \Elementor\Plugin::instance()->widgets_manager->get_widget_types('REPEFOEL_widget_repeater');
$field_post_map = $repeater_widget ? $repeater_widget->get_repeater_field_post_map() : [];
// Localized strings for i18n
wp_localize_script(
'REPEFOEL-repeater-template',
'REPEFOELTemplateData',
[
'ajax_url' => admin_url('admin-ajax.php'),
'editUrl' => admin_url('post.php'),
'nonce' => wp_create_nonce('repefoel_nonce'),
'customTemplate' => esc_html__('Custom Template', 'addoncraft-repeater-for-elementor-acf'),
'customTemplates' => esc_html__('Custom Templates', 'addoncraft-repeater-for-elementor-acf'),
'successMessage' => esc_html__('Custom template saved successfully!', 'addoncraft-repeater-for-elementor-acf'),
'backLabel' => esc_html__('Back', 'addoncraft-repeater-for-elementor-acf'),
'editingTemplate' => esc_html__('Loop Item', 'addoncraft-repeater-for-elementor-acf'),
'publishLabel' => esc_html__('Save', 'addoncraft-repeater-for-elementor-acf'),
'fieldPostMap' => $field_post_map,
]
);
wp_enqueue_style(
'REPEFOEL-repeater-template',
plugin_dir_url(__FILE__) . 'assets/css/custom-template.css',
[],
REPEFOEL__PLUGIN_VERSION
);
}
public function repefoel_admin_notice_missing_main_plugin()
{
if (!current_user_can('activate_plugins')) {
return;
}
$message = sprintf(
__('Addoncraft Repeater For Elementor ACF requires Elementor to be installed and activated.', 'addoncraft-repeater-for-elementor-acf')
);
printf('
', wp_kses_data($message));
}
public function repefoel_admin_notice_missing_acf_pro_plugin()
{
if (!current_user_can('activate_plugins')) {
return;
}
$message = sprintf(
__('Addoncraft Repeater For Elementor ACF requires Advanced Custom Fields (Free or Pro) to work properly.< to be installed and activated.', 'addoncraft-repeater-for-elementor-acf')
);
printf('', wp_kses_data($message));
}
public function repefoel_admin_notice_minimum_elementor_version()
{
deactivate_plugins(plugin_basename(__FILE__));
if (isset($_GET['activate'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- value is only unset, never read or processed.
unset($_GET['activate']);
}
$message = sprintf(
__('Addoncraft Repeater For Elementor ACF requires Elementor version 3.0.0 or greater.', 'addoncraft-repeater-for-elementor-acf')
);
printf('', wp_kses_data($message));
}
public function repefoel_admin_notice_pro_required()
{
?>
Elementor Pro to work because Dynamic Tags are a Pro-only feature.', 'addoncraft-repeater-for-elementor-acf'); ?>
register_free_group($tags_manager);
/**
* Dynamic Tag for simple text field dynamic tag like heading
*/
require_once(__DIR__ . '/dynamic-tags/normal/acf_text_tag.php');
$tags_manager->register(new \REPEFOEL_ACF_Text());
require_once(__DIR__ . '/dynamic-tags/normal/acf_image_tag.php');
$tags_manager->register(new \REPEFOEL_ACF_Image());
require_once(__DIR__ . '/dynamic-tags/normal/acf_url_tag.php');
$tags_manager->register(new \REPEFOEL_ACF_URL());
require_once(__DIR__ . '/dynamic-tags/normal/site_title.php');
$tags_manager->register(new \REPEFOEL_SITE_TITLE());
require_once(__DIR__ . '/dynamic-tags/normal/author-info.php');
$tags_manager->register(new \REPEFOEL_Author_Info());
require_once(__DIR__ . '/dynamic-tags/normal/author-profile.php');
$tags_manager->register(new \REPEFOEL_Author_Profile());
}
public function register_free_group($tags_manager)
{
$tags_manager->register_group(
'REPEFOEL-free_dynamic-tag',
[
'title' => esc_html__('Addoncraft ACF', 'addoncraft-repeater-for-elementor-acf')
]
);
}
public function repefoel_register_dynamic_tags($tags_manager)
{
$this->register_group($tags_manager);
/**
* Dynamic Tag for simple text field dynamic tag like heading
*/
require_once(__DIR__ . '/dynamic-tags/repeater/acf_text_repeater_tag.php');
$tags_manager->register(new \REPEFOEL_ACF_Repeater_Text());
/**
* Dynamic Tag for Image field dynamic tag like Image
*/
require_once(__DIR__ . '/dynamic-tags/repeater/acf_image_repeater_tag.php');
$tags_manager->register(new \REPEFOEL_ACF_Repeater_Image());
/**
* Dynamic Tag for URL field dynamic tag like Hyperlink
*/
require_once(__DIR__ . '/dynamic-tags/repeater/acf_url_repeater_tag.php');
$tags_manager->register(new \REPEFOEL_ACF_Repeater_URL());
}
public function REPEFOEL_custom_controls($controls_manager)
{
/**
* Dynamic Tag for URL field dynamic tag like Hyperlink
*/
require_once REPEFOEL__PLUGIN_PATH . 'controls/repeater-control.php';
$controls_manager->register(new \REPEFOEL_repeater_control());
}
public function REPEFOEL_elementor_document_register($documents_manager)
{
require_once REPEFOEL__PLUGIN_PATH . 'templates/repeater-document.php';
$documents_manager->register_document_type('REPEFOEL_repeater', 'REPEFOEL_Repeater_Document');
}
/**
* Add custom template type to Elementor's template types
*/
public function REPEFOEL_add_template_type($template_types)
{
$template_types[self::TEMPLATE_TYPE] = [
'title' => __('Addoncraft Repeater', 'addoncraft-repeater-for-elementor-acf'),
'plural_title' => __('Addoncraft Repeaters', 'addoncraft-repeater-for-elementor-acf'),
];
return $template_types;
}
/**
* Register admin fields
*/
public function REPEFOEL_register_admin_fields($settings)
{
// Add template type to new template dialog
add_filter('elementor/template-library/create_new_dialog_types', [$this, 'REPEFOEL_template_dialog_types']);
}
public function REPEFOEL_template_dialog_types($types)
{
$types['REPEFOEL_repeater'] = [
'title' => __('Addoncraft Repeater', 'addoncraft-repeater-for-elementor-acf'),
'icon' => 'eicon-document-file',
];
return $types;
}
public function register_group($tags_manager)
{
$tags_manager->register_group(
'REPEFOEL-dynamic-tag',
[
'title' => esc_html__('Addoncraft Repeater', 'addoncraft-repeater-for-elementor-acf')
]
);
}
/**
* Register Enqueue Scripts
*
* @since v1.0.0
*/
public function repefoel_frontend_enqueue_script()
{
$css_deps = ['elementor-frontend'];
wp_register_style('REPEFOEL_custom_style', plugins_url('/assets/css/style.css', __FILE__), $css_deps, REPEFOEL__PLUGIN_VERSION, 'all');
wp_enqueue_style('REPEFOEL_custom_style');
wp_register_style('repefoel-rp-style', plugins_url('/assets/css/rp-widget.css', __FILE__), $css_deps, REPEFOEL__PLUGIN_VERSION, 'all');
wp_enqueue_style('repefoel-rp-style');
wp_register_script('repefoel-swiper-init', plugins_url('/assets/js/swiper-init.js', __FILE__), ['swiper'], REPEFOEL__PLUGIN_VERSION, true);
wp_enqueue_script('repefoel-swiper-init');
}
/**
* Register Categories
*
* @since v1.0.0
*/
public function REPEFOEL_cat_register($elements_manager)
{
$categories = [];
$categories['REPEFOEL_category_advanced'] =
[
'title' => 'Addoncraft Repeater',
'icon' => 'fa fa-plug',
// 'promotion' => [
// 'url' => 'https://go.elementor.com/go-pro-section-woocommerce-widget-panel/'
// ]
];
$old_categories = $elements_manager->get_categories();
$categories = array_merge(
array_slice($old_categories, 0, 4),
$categories,
array_slice($old_categories, 4, null),
);
$set_categories = function ($categories) {
$this->categories = $categories;
};
$set_categories->call($elements_manager, $categories);
}
/**
* Register widgets
*
* @since v1.0.0
*/
public function repefoel_register_new_widgets()
{
require_once REPEFOEL__PLUGIN_PATH . 'elementor/element/abstract-repefoel-widget.php';
require_once REPEFOEL__PLUGIN_PATH . 'elementor/element/acf/acf_repeater.php';
\Elementor\Plugin::instance()->widgets_manager->register_widget_type(new REPEFOEL_ACF_Repeater);
require_once REPEFOEL__PLUGIN_PATH . 'elementor/element/acf/acf_repeater_carousel.php';
\Elementor\Plugin::instance()->widgets_manager->register_widget_type(new REPEFOEL_ACF_Repeater_Carousel);
require_once REPEFOEL__PLUGIN_PATH . 'elementor/element/post/post-repeater.php';
\Elementor\Plugin::instance()->widgets_manager->register_widget_type(new REPEFOEL_post_Repeater);
}
// public function REPEFOEL_elementor_init()
// {
// $args = [
// 'labels' => 'Addoncraft Repeater',
// 'public' => true,
// 'show_ui' => true,
// 'show_in_menu' => true,
// 'show_in_nav_menus' => true,
// 'exclude_from_search' => false,
// 'capability_type' => 'post',
// 'hierarchical' => false,
// 'supports' => ['title', 'editor', 'thumbnail'],
// ];
// register_post_type('repeRepeaterTypes', $args);
// }
public function repefoel_create_elementor_repeater_template()
{
check_ajax_referer('repefoel_nonce', 'nonce');
if (!current_user_can('edit_posts')) {
wp_die('Insufficient permissions');
}
$template_title = 'REPEFOEL Repater #' . uniqid();
$post_data = array(
'post_title' => $template_title,
'post_status' => 'publish',
'post_type' => 'elementor_library',
'meta_input' => array(
'_elementor_edit_mode' => 'builder',
'_elementor_template_type' => 'REPEFOEL_repeater',
'_elementor_version' => ELEMENTOR_VERSION,
'_elementor_pro_version' => defined('ELEMENTOR_PRO_VERSION') ? ELEMENTOR_PRO_VERSION : '',
'_wp_page_template' => 'elementor_canvas'
)
);
$template_id = wp_insert_post($post_data);
if (is_wp_error($template_id)) {
wp_send_json_error('Failed to create template');
}
// Set initial Elementor data with a default container widget
$container_id = substr( md5( uniqid( '', true ) ), 0, 8 );
$elementor_data = wp_json_encode( [
[
'id' => $container_id,
'elType' => 'container',
'settings' => [
'content_width' => 'full',
],
'elements' => [],
'isInner' => false,
],
] );
update_post_meta( $template_id, '_elementor_data', $elementor_data );
$initial_post_id = absint( $_POST['post_id'] ?? 0 );
$initial_repeater_field = isset( $_POST['repeater_field'] ) ? sanitize_text_field( wp_unslash( $_POST['repeater_field'] ) ) : '';
update_post_meta( $template_id, '_elementor_page_settings', [
'REPEFOEL_preview_post' => $initial_post_id,
'REPEFOEL_repeater_field' => $initial_repeater_field,
] );
$edit_url = add_query_arg(array(
'post' => $template_id,
'action' => 'elementor'
), admin_url('post.php'));
// Return success with edit URL
wp_send_json_success(array(
'template_id' => $template_id,
'template_title' => $template_title,
'edit_url' => $edit_url
));
}
public function repefoel_update_template_preview_settings()
{
check_ajax_referer('repefoel_nonce', 'nonce');
if ( ! current_user_can( 'edit_posts' ) ) {
wp_die( 'Insufficient permissions' );
}
$template_id = absint( $_POST['template_id'] ?? 0 );
$post_id = absint( $_POST['post_id'] ?? 0 );
$repeater_field = isset( $_POST['repeater_field'] ) ? sanitize_text_field( wp_unslash( $_POST['repeater_field'] ) ) : '';
if ( ! $template_id ) {
wp_send_json_error( 'Invalid template ID' );
}
$settings = get_post_meta( $template_id, '_elementor_page_settings', true );
if ( ! is_array( $settings ) ) {
$settings = [];
}
if ( $post_id ) {
$settings['REPEFOEL_preview_post'] = $post_id;
}
if ( $repeater_field ) {
$settings['REPEFOEL_repeater_field'] = $repeater_field;
}
update_post_meta( $template_id, '_elementor_page_settings', $settings );
wp_send_json_success();
}
}
REPEFOEL_ELEMENTOR_ADDON::get_instance();