Skip to content

Instantly share code, notes, and snippets.

@SRHDesign
Last active November 5, 2025 22:12
Show Gist options
  • Select an option

  • Save SRHDesign/ce8161d4fe13f6a2ea9c1a87af95c591 to your computer and use it in GitHub Desktop.

Select an option

Save SRHDesign/ce8161d4fe13f6a2ea9c1a87af95c591 to your computer and use it in GitHub Desktop.
Elementor + ACF Product Accordions - Complete system with auto-cleanup"

Elementor + ACF Product Accordions System

A complete solution for managing dynamic product accordions in WooCommerce using Elementor and Advanced Custom Fields (ACF).

📦 What's Included

  1. JavaScript Optimizer - Automatically cleans empty accordions and fixes video loading
  2. ACF Field Group - Pre-configured fields for 5 product accordions
  3. Complete Integration - Works seamlessly with Elementor's nested accordion widget

🚀 Quick Start

Step 1: Import ACF Fields

  1. In WordPress admin, go to Custom Fields → Tools
  2. Click Import Field Groups
  3. Copy the contents of acf-product-accordions.json
  4. Paste and import

Step 2: Add JavaScript

Add to your theme's functions.php:

add_action('wp_footer', function() {
    if (is_product()) { // Only on WooCommerce product pages
        ?>
        <script>
        // Paste contents of elementor-accordion-optimizer.js here
        </script>
        <?php
    }
});

Step 3: Configure Elementor

  1. Edit your product template in Elementor
  2. Add a Nested Accordion widget
  3. For each accordion item:
    • Title: Use ACF dynamic tag → accordion_1_title
    • Content: Use ACF dynamic tag → accordion_1_content
  4. Repeat for accordions 2-5
  5. The JavaScript will automatically hide empty accordions

📋 ACF Fields Overview

The field group includes:

  • 5 Accordion Sections (each with enable toggle, title, and WYSIWYG content)
  • Product Video URL field (bonus field for video embeds)
  • Conditional Logic - Fields only show when enabled
  • WooCommerce Integration - Automatically appears on product edit screens

Field Names Reference

enable_accordion_1 → accordion_1_title → accordion_1_content
enable_accordion_2 → accordion_2_title → accordion_2_content
enable_accordion_3 → accordion_3_title → accordion_3_content
enable_accordion_4 → accordion_4_title → accordion_4_content
enable_accordion_5 → accordion_5_title → accordion_5_content
product_video (URL field)

✨ Features

  • ✅ Automatically removes empty accordion items
  • ✅ Fixes YouTube/Vimeo embeds not loading
  • ✅ Fixes iframe content appearing blank
  • ✅ Toggle-based UI for clean admin experience
  • ✅ Conditional fields reduce clutter
  • ✅ Works with WooCommerce products
  • ✅ Performance optimized
  • ✅ Compatible with ACF Free & Pro

🎯 Use Cases

Perfect for:

  • Product specifications
  • Shipping & returns information
  • Size guides
  • Technical details
  • FAQ sections
  • Video demonstrations

🔧 Customization

Change Number of Accordions

Edit the ACF JSON and duplicate/remove accordion field sets. Update your Elementor template accordingly.

Target Different Post Types

In acf-product-accordions.json, change:

"location": [
    [
        {
            "param": "post_type",
            "operator": "==",
            "value": "product"  // Change to "post", "page", etc.
        }
    ]
]

Adjust JavaScript Timing

If accordions load slowly, increase the timeout in the JavaScript:

setTimeout(() => {
    requestAnimationFrame(() => initNestedAccordions(document));
}, 600); // Increased from 400ms

🐛 Troubleshooting

Empty accordions still showing?

  • Check that ACF fields are actually empty (no spaces, line breaks, etc.)
  • Clear Elementor cache
  • Increase JavaScript timeout

Videos not loading?

  • Ensure video URLs are valid
  • Check browser console for errors
  • Verify iframe src attributes are set

Fields not appearing in admin?

  • Ensure ACF is activated
  • Check field group is assigned to correct post type
  • Verify conditional logic settings

📚 Requirements

  • WordPress 5.0+
  • WooCommerce 3.0+
  • Elementor Pro (for nested accordion widget)
  • Advanced Custom Fields (Free or Pro)

📄 License

Free to use and modify for your projects.

[
{
"key": "group_product_accordions",
"title": "Product Accordions",
"fields": [
{
"key": "field_accordion_instructions",
"label": "Instructions",
"name": "",
"aria-label": "",
"type": "message",
"instructions": "",
"required": 0,
"conditional_logic": false,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"message": "<strong>💡 Use these fields to create up to five accordion panels for your product page.</strong><br><br>Enable an accordion to reveal its title and content fields. These can be displayed in Elementor using ACF dynamic tags in the Accordion widget.",
"new_lines": "",
"esc_html": 0
},
{
"key": "field_enable_accordion_1",
"label": "Enable Accordion 1",
"name": "enable_accordion_1",
"aria-label": "",
"type": "true_false",
"instructions": "",
"required": false,
"conditional_logic": false,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"ui": 1,
"message": "Show Accordion 1 fields",
"default_value": 0,
"ui_on_text": "",
"ui_off_text": ""
},
{
"key": "field_accordion_1_title",
"label": "Accordion 1 Title",
"name": "accordion_1_title",
"aria-label": "",
"type": "text",
"instructions": "Enter a title for Accordion 1",
"required": false,
"conditional_logic": [
[
{
"field": "field_enable_accordion_1",
"operator": "==",
"value": "1"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"maxlength": "",
"placeholder": "",
"prepend": "",
"append": ""
},
{
"key": "field_accordion_1_content",
"label": "Accordion 1 Content",
"name": "accordion_1_content",
"aria-label": "",
"type": "wysiwyg",
"instructions": "Enter content for Accordion 1",
"required": false,
"conditional_logic": [
[
{
"field": "field_enable_accordion_1",
"operator": "==",
"value": "1"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"tabs": "all",
"toolbar": "full",
"media_upload": 1,
"default_value": "",
"delay": 0
},
{
"key": "field_enable_accordion_2",
"label": "Enable Accordion 2",
"name": "enable_accordion_2",
"aria-label": "",
"type": "true_false",
"instructions": "",
"required": false,
"conditional_logic": false,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"ui": 1,
"message": "Show Accordion 2 fields",
"default_value": 0,
"ui_on_text": "",
"ui_off_text": ""
},
{
"key": "field_accordion_2_title",
"label": "Accordion 2 Title",
"name": "accordion_2_title",
"aria-label": "",
"type": "text",
"instructions": "Enter a title for Accordion 2",
"required": false,
"conditional_logic": [
[
{
"field": "field_enable_accordion_2",
"operator": "==",
"value": "1"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"maxlength": "",
"placeholder": "",
"prepend": "",
"append": ""
},
{
"key": "field_accordion_2_content",
"label": "Accordion 2 Content",
"name": "accordion_2_content",
"aria-label": "",
"type": "wysiwyg",
"instructions": "Enter content for Accordion 2",
"required": false,
"conditional_logic": [
[
{
"field": "field_enable_accordion_2",
"operator": "==",
"value": "1"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"tabs": "all",
"toolbar": "full",
"media_upload": 1,
"default_value": "",
"delay": 0
},
{
"key": "field_enable_accordion_3",
"label": "Enable Accordion 3",
"name": "enable_accordion_3",
"aria-label": "",
"type": "true_false",
"instructions": "",
"required": false,
"conditional_logic": false,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"ui": 1,
"message": "Show Accordion 3 fields",
"default_value": 0,
"ui_on_text": "",
"ui_off_text": ""
},
{
"key": "field_accordion_3_title",
"label": "Accordion 3 Title",
"name": "accordion_3_title",
"aria-label": "",
"type": "text",
"instructions": "Enter a title for Accordion 3",
"required": false,
"conditional_logic": [
[
{
"field": "field_enable_accordion_3",
"operator": "==",
"value": "1"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"maxlength": "",
"placeholder": "",
"prepend": "",
"append": ""
},
{
"key": "field_accordion_3_content",
"label": "Accordion 3 Content",
"name": "accordion_3_content",
"aria-label": "",
"type": "wysiwyg",
"instructions": "Enter content for Accordion 3",
"required": false,
"conditional_logic": [
[
{
"field": "field_enable_accordion_3",
"operator": "==",
"value": "1"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"tabs": "all",
"toolbar": "full",
"media_upload": 1,
"default_value": "",
"delay": 0
},
{
"key": "field_enable_accordion_4",
"label": "Enable Accordion 4",
"name": "enable_accordion_4",
"aria-label": "",
"type": "true_false",
"instructions": "",
"required": false,
"conditional_logic": false,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"ui": 1,
"message": "Show Accordion 4 fields",
"default_value": 0,
"ui_on_text": "",
"ui_off_text": ""
},
{
"key": "field_accordion_4_title",
"label": "Accordion 4 Title",
"name": "accordion_4_title",
"aria-label": "",
"type": "text",
"instructions": "Enter a title for Accordion 4",
"required": false,
"conditional_logic": [
[
{
"field": "field_enable_accordion_4",
"operator": "==",
"value": "1"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"maxlength": "",
"placeholder": "",
"prepend": "",
"append": ""
},
{
"key": "field_accordion_4_content",
"label": "Accordion 4 Content",
"name": "accordion_4_content",
"aria-label": "",
"type": "wysiwyg",
"instructions": "Enter content for Accordion 4",
"required": false,
"conditional_logic": [
[
{
"field": "field_enable_accordion_4",
"operator": "==",
"value": "1"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"tabs": "all",
"toolbar": "full",
"media_upload": 1,
"default_value": "",
"delay": 0
},
{
"key": "field_enable_accordion_5",
"label": "Enable Accordion 5",
"name": "enable_accordion_5",
"aria-label": "",
"type": "true_false",
"instructions": "",
"required": false,
"conditional_logic": false,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"ui": 1,
"message": "Show Accordion 5 fields",
"default_value": 0,
"ui_on_text": "",
"ui_off_text": ""
},
{
"key": "field_accordion_5_title",
"label": "Accordion 5 Title",
"name": "accordion_5_title",
"aria-label": "",
"type": "text",
"instructions": "Enter a title for Accordion 5",
"required": false,
"conditional_logic": [
[
{
"field": "field_enable_accordion_5",
"operator": "==",
"value": "1"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"maxlength": "",
"placeholder": "",
"prepend": "",
"append": ""
},
{
"key": "field_accordion_5_content",
"label": "Accordion 5 Content",
"name": "accordion_5_content",
"aria-label": "",
"type": "wysiwyg",
"instructions": "Enter content for Accordion 5",
"required": false,
"conditional_logic": [
[
{
"field": "field_enable_accordion_5",
"operator": "==",
"value": "1"
}
]
],
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"tabs": "all",
"toolbar": "full",
"media_upload": 1,
"default_value": "",
"delay": 0
},
{
"key": "field_69035114615d3",
"label": "Product Video",
"name": "product_video",
"aria-label": "",
"type": "url",
"instructions": "",
"required": 0,
"conditional_logic": 0,
"wrapper": {
"width": "",
"class": "",
"id": ""
},
"default_value": "",
"allow_in_bindings": 0,
"placeholder": ""
}
],
"location": [
[
{
"param": "post_type",
"operator": "==",
"value": "product"
}
]
],
"menu_order": 0,
"position": "normal",
"style": "default",
"label_placement": "left",
"instruction_placement": "label",
"hide_on_screen": "",
"active": true,
"description": "Create and manage up to five accordions for WooCommerce products using toggles to enable each section.",
"show_in_rest": 0,
"display_title": ""
}
]
/**
* Elementor Accordion Optimizer
*
* Automatically removes empty accordion items and fixes video/iframe loading issues
* in Elementor's nested accordion widget.
*
* Features:
* - Detects and removes accordion items with no meaningful content
* - Fixes embedded videos/iframes not loading when accordion opens
* - Performance optimized with early returns and event listener management
*
* Usage: Add this script to your WordPress theme or use a code snippet plugin
*/
document.addEventListener('DOMContentLoaded', function () {
// Skip in Elementor editor
if (document.body.classList.contains('elementor-editor-active')) return;
/**
* Utility: detect if accordion content is effectively empty
*/
function isEffectivelyEmpty(contentEl) {
if (!contentEl) return true;
// Quick check for meaningful elements
if (contentEl.querySelector(
'img, iframe, video, audio, svg, canvas, table, ul li, ol li, form, input, textarea, button, blockquote, code, pre, [data-element_type]'
)) return false;
// Check text content
const text = contentEl.textContent.replace(/\u00A0/g, ' ').trim();
if (text.length > 0) return false;
// Only do expensive HTML parsing if text check passed
const stripped = contentEl.innerHTML
.replace(/<!--[\s\S]*?-->/g, '')
.replace(/<br\s*\/?>/gi, '')
.replace(/&(nbsp|thinsp|ensp|emsp);/gi, ' ')
.replace(/<(p|div|span|section|article|h[1-6])[^>]*>\s*<\/\1>/gi, '')
.trim();
return stripped.length === 0;
}
/**
* Core: hide empty accordions and wire up video/iframe refresh
*/
function initNestedAccordions(scope = document) {
const items = scope.querySelectorAll('.elementor-widget-n-accordion .e-n-accordion .e-n-accordion-item');
items.forEach(item => {
const contentEl = item.querySelector(':scope > .e-con');
// Remove empty accordions
if (isEffectivelyEmpty(contentEl)) {
item.remove();
return;
}
// Reload embeds when opened (only add listener once)
if (!item.dataset.accordionInitialized) {
item.dataset.accordionInitialized = 'true';
item.addEventListener('toggle', function () {
if (this.open) {
const embeds = this.querySelectorAll('iframe[src], video[src]');
embeds.forEach(el => {
const currentSrc = el.src;
if (currentSrc) {
el.src = currentSrc; // Force reload
}
});
}
});
}
});
}
// Initialize after Elementor renders
setTimeout(() => {
requestAnimationFrame(() => initNestedAccordions(document));
}, 400);
// Optional: Dynamic content observer (uncomment if needed for AJAX-loaded content)
/*
let debounceTimer;
const mo = new MutationObserver(() => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => initNestedAccordions(document), 300);
});
mo.observe(document.body, { childList: true, subtree: true });
*/
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment