'elementor_library', 'posts_per_page' => -1, 'post_status' => 'publish', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key, WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Elementor itself stores the template type in postmeta; no taxonomy alternative exists. 'meta_key' => '_elementor_template_type', 'meta_value' => 'REPEFOEL_repeater', 'fields' => 'ids', 'no_found_rows' => true, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ] ); if ( empty( $templates ) ) { return [ '' => esc_html__( 'No templates found. Create templates in Elementor Templates section.', 'addoncraft-repeater-for-elementor-acf' ) ]; } $options = [ '' => esc_html__( 'Select Template', 'addoncraft-repeater-for-elementor-acf' ) ]; foreach ( $templates as $template_id ) { $options[ $template_id ] = esc_html( get_the_title( $template_id ) ); } return $options; } /** * Return all ACF repeater field names (cached for one hour). */ public function get_only_repeater_name() { if ( ! function_exists( 'acf_get_field_groups' ) || ! function_exists( 'acf_get_fields' ) ) { return []; } $cached = wp_cache_get( 'repefoel_acf_repeater_fields' ); if ( $cached !== false ) { return $cached; } $all_repeater_fields = []; $field_groups = acf_get_field_groups(); if ( ! empty( $field_groups ) ) { foreach ( $field_groups as $group ) { $fields = acf_get_fields( $group['ID'] ); if ( ! empty( $fields ) ) { foreach ( $fields as $field ) { if ( $field['type'] === 'repeater' ) { $all_repeater_fields[ $field['name'] ] = esc_html( $field['label'] ); } } } } } wp_cache_set( 'repefoel_acf_repeater_fields', $all_repeater_fields, '', 3600 ); return $all_repeater_fields; } /** * Return all published posts/pages as an ID => title map. */ protected function get_all_posts() { $post_ids = get_posts( [ 'post_type' => 'any', 'posts_per_page' => -1, 'post_status' => 'publish', 'fields' => 'ids', 'no_found_rows' => true, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, ] ); $options = []; foreach ( $post_ids as $id ) { $options[ $id ] = get_the_title( $id ); } return $options; } /** * Map each ACF repeater field name to the post IDs that currently have * data in it, so the editor can grey out fields that don't apply to the * selected source post — no AJAX needed, computed once and cached. */ public function get_repeater_field_post_map() { $cached = wp_cache_get( 'repefoel_field_post_map' ); if ( $cached !== false ) { return $cached; } $fields = array_keys( $this->get_only_repeater_name() ); $map = array_fill_keys( $fields, [] ); if ( ! empty( $fields ) ) { foreach ( $this->get_all_posts() as $post_id => $title ) { foreach ( $fields as $field_name ) { $value = get_field( $field_name, $post_id ); if ( ! empty( $value ) && is_array( $value ) ) { $map[ $field_name ][] = $post_id; } } } } wp_cache_set( 'repefoel_field_post_map', $map, '', 3600 ); return $map; } /* ------------------------------------------------------------------ */ /* Render helpers */ /* ------------------------------------------------------------------ */ /** * Return Elementor template HTML for the given template ID. */ protected function render_template( $template_id ) { if ( ! $template_id || ! class_exists( '\Elementor\Plugin' ) ) { return ''; } return \Elementor\Plugin::instance()->frontend->get_builder_content_for_display( $template_id, true ); } /** * Extended wp_kses allowlist that covers SVG,