HEX
Server: Apache/2.4.65 (Debian)
System: Linux kubikelcreative 5.10.0-35-amd64 #1 SMP Debian 5.10.237-1 (2025-05-19) x86_64
User: www-data (33)
PHP: 8.4.13
Disabled: NONE
Upload Files
File: /var/www/gosurya-id/wp-content/plugins/super-forms/includes/class-shortcodes.php
<?php
/**
 * Super Forms Shortcodes Class.
 *
 * @author      feeling4design
 * @category    Class
 * @package     SUPER_Forms/Classes
 * @class       SUPER_Shortcodes
 * @version     1.0.0
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly
}

if( !class_exists( 'SUPER_Shortcodes' ) ) :

/**
 * SUPER_Shortcodes
 */
class SUPER_Shortcodes {
        
    
    /**
     * @var string
     *
     *  @since      3.5.0
    */
    public static $current_form_id = 0;

    public static $shortcodes = false;
    
    public static $form_fields = array();


    // @since 4.7.5 - wrapper function to get the value for this field from entry data
    public static function get_entry_data_value($tag, $value, $name, $entry_data){
        if( isset( $entry_data[$name] ) ) {
            if( $tag=='textarea' ) {
                $value = stripslashes( $entry_data[$name]['value'] );
            }else{
                $value = sanitize_text_field( $entry_data[$name]['value'] );
            }
        }
        return $value;
    }

    /** 
     *  All the fields
     *
     *  Create an array with all the fields
     *
     *  @since      1.0.0
    */
    public static function shortcodes( $shortcode=false, $attributes=false, $content=false ) {
        
        // @since 3.4.0  - custom contact entry status
        $entry_statuses = SUPER_Settings::get_entry_statuses();
        $statuses = array();
        foreach($entry_statuses as $k => $v){
            $statuses[$k] = $v['name'];
        }
        
        $attributes = stripslashes_deep($attributes);

        $attr = array( 
            'shortcode'=>$shortcode, 
            'attributes'=>$attributes, 
            'content'=>$content 
        );
            
        include( 'shortcodes/predefined-arrays.php' );
        
        $array = array();
        
        $array = apply_filters( 'super_shortcodes_start_filter', $array, $attr );
        
        /** 
         *  Layout Elements
         *
         *  @since      1.0.0
        */
        include( 'shortcodes/layout-elements.php' );
        $array = apply_filters( 'super_shortcodes_after_layout_elements_filter', $array, $attr );

        
        /** 
         *  Form Elements
         *
         *  @since      1.0.0
        */
        include( 'shortcodes/form-elements.php' );
        $array = apply_filters( 'super_shortcodes_after_form_elements_filter', $array, $attr );
        

        /** 
         *  HTML Elements
         *
         *  @since      3.5.0
        */
        include( 'shortcodes/html-elements.php' );
        $array = apply_filters( 'super_shortcodes_after_html_elements_filter', $array, $attr );

        $array = apply_filters( 'super_shortcodes_end_filter', $array, $attr );

        self::$shortcodes = $array;

        return $array;
        
    }


    /** 
     *  Merge any possible translations
     *
     *  @since      4.7.0
    */
    public static function merge_i18n($atts, $i18n=null){
        if(!empty($i18n)){
            if( (isset($atts['i18n'])) && (isset($atts['i18n'][$i18n])) ) {
                $atts = array_replace_recursive($atts, $atts['i18n'][$i18n]);
                return $atts;
            }
        }
        if(!empty($_POST['translating'])){
            $i18n = $_POST['i18n'];
            if( (isset($atts['i18n'])) && (isset($atts['i18n'][$i18n])) ) {
                $atts = array_replace_recursive($atts, $atts['i18n'][$i18n]);
                return $atts;
            }
        }
        return $atts;   
    }


    /** 
     *  Get default value
     *
     *  @since      4.9.3
    */
    public static function get_default_value( $tag, $atts, $settings, $entry_data, $default='' ) {
        // Check if we can find parameters
        if( isset( $_GET[$atts['name']] ) ) {
            $atts['value'] = sanitize_text_field( $_GET[$atts['name']] );
        }elseif( isset( $_POST[$atts['name']] ) ) { // Also check for POST key
            $atts['value'] = sanitize_text_field( $_POST[$atts['name']] );
        }
        // Get the value for from entry data
        if( !isset( $atts['value'] ) ) $atts['value'] = $default;
        $entry_data_value = self::get_entry_data_value( $tag, $atts['value'], $atts['name'], $entry_data );
        if( (isset($entry_data_value)) && ($entry_data_value!=='') ){
            $atts['value'] = $entry_data_value;
        }
        if($atts['value']!='') $atts['value'] = SUPER_Common::email_tags( $atts['value'], null, $settings, $user=null, $skip=true, $skipSecrets=true );
        // Add shortcode compatibility for default field value
        $atts['value'] = do_shortcode($atts['value']);

        // Required for dropdown field:
        if( $tag=='dropdown' && !empty($atts['absolute_default']) && empty($atts['value']) ) {
            $atts['value'] = $atts['absolute_default'];
        }
        return $atts['value'];
    }


    /** 
     *  Get all items by post_type
     *
     *  @since      1.0.0
    */
    public static function get_item_html($prefix, $tag, $atts, $data_value, $selected_items, $v, $main_image_url){
        if($atts['retrieve_method']=='post_type') {
            $post_id = absint($v['ID']);
            $label_class = array();
            // Check if we want to display a featured image or not
            if($atts['display_featured_image']=='true'){
                $label_class[] = 'super-has-image';
            }
            // If Checkbox
            if( ($tag=='checkbox') && (in_array($data_value, $selected_items, true )) ) {
                $label_class[] = 'super-active super-default-selected';
            }
            // If Radio
            if( ($tag=='radio') && ($atts[$prefix.'value']==$data_value) ) {
                $label_class[] = 'super-active super-default-selected';
            }
            // Create the item (label)
            $item = '<label class="super-item ' . implode(' ', $label_class) . '">';
                // If checkbox or radio
                if($tag=='checkbox' || $tag=='radio'){
                    $item .= '<span class="super-before"><span class="super-after"></span></span>';
                }
                // If Checkbox
                if($tag=='checkbox'){
                    $item .= '<input' . ( !in_array($data_value, $selected_items, true ) ? '' : ' checked="checked"') . ' type="checkbox" value="' . esc_attr( $data_value ) . '" />';
                }
                // If Radio
                if($tag=='radio'){
                    $item .= '<input type="radio" value="' . esc_attr( $data_value ) . '" />';
                }
                // If we need to display the featured image
                if($atts['display_featured_image']=='true'){
                    $item .= '<div class="super-image" style="background-image:url(\'' . $main_image_url . '\');"><img src="' . esc_url($main_image_url) . '"' . '></div>';
                }
                // If we need to display the title, excerpt or price
                $item .= '<span class="super-item-label">';
                    // Shop title (post title)
                    if($atts['display_title']=='true'){
                        $item .= '<span class="super-title">' . esc_html($v['post_title']) . '</span>';
                    }
                    // Show excerpt (post/product short description)
                    if($atts['display_excerpt']=='true' && !empty($v['post_excerpt']) ){
                        $item .= '<span class="super-excerpt">' . esc_html($v['post_excerpt']) . '</span>';
                    }
                    // Show product price
                    if( function_exists('wc_price') ) {
                        if($atts['display_price']=='true'){
                            $price = get_post_meta( $post_id, '_regular_price', true );
                            // Only if meta exists
                            if(!empty($price)){
                                $sale_price = get_post_meta( $post_id, '_sale_price', true );
                                if(!empty($sale_price)){
                                    $item .= '<span class="super-regular-price super-sale">' . wc_price(get_post_meta( $post_id, '_regular_price', true )) . '</span>';
                                    $item .= '<span class="super-sale-price">' . wc_price(get_post_meta( $post_id, '_sale_price', true )) . '</span>';
                                }else{
                                    $item .= '<span class="super-regular-price">' . wc_price(get_post_meta( $post_id, '_regular_price', true )) . '</span>';
                                }
                            }
                        }
                    }
                $item .= '</span>';
            $item .='</label>';
        }
        return $item;
    }
    public static function get_items($items=array(), $tag, $atts, $prefix='', $settings=array(), $entry_data=array()){

        // When advanced tags is being used get the first value
        if(isset($atts['value']) && $atts['value'] !== '') $real_value = explode(';', $atts['value'])[0];       

        // First retrieve all the values from URL parameter
        $selected_items = array();
        if($tag==='dropdown' || $tag==='checkbox'){
            // When advanced tags is being used get the first value
            if(isset($atts['value']) && $atts['value'] !== '') $selected_items = explode( ",", $atts['value'] );
        }
        if($tag==='radio'){
            if(isset($atts['value']) && $atts['value'] !== '') $selected_items = array($atts['value']);
        }

        // Now get all the actual values (in case user is using dynamic values like: 1;Red)
        $selected_values = array();
        foreach($selected_items as $k => $v){
            // Make sure to trim the values
            $v = trim($v);
            $selected_values[] = explode( ';', $v )[0];
        }

        $items = array();
        
        // dropdown - custom
        // text - autosuggest - custom
        // text - keywords - custom
        // checkbox - custom
        // radio -custom
        if( !isset( $atts[$prefix.'retrieve_method'] ) ) {
            $atts[$prefix.'retrieve_method'] = 'custom';
        } 
        if( $atts[$prefix.'retrieve_method']=='custom' ) {
            // dropdown - custom
            if($tag==='dropdown'){
                $placeholder = array();
                $items = array();
                foreach( $atts['dropdown_items'] as $k => $v ) {
                    // Get advanced tags value
                    $real_value = explode(';', $v['value'])[0];
                    $class = '';
                    // Check if this should be remembered as the default value set via settings
                    if( ($v['checked']==='true' || $v['checked']===true || $v['checked']===1) ) {
                        $class .= 'super-default-selected';
                        $selected_items[] = $v['value'];
                    }
                    if( empty($selected_values) ) {
                        // No URL parameters where set, check if this dropdown has default selected items
                        if( ($v['checked']==='true' || $v['checked']===true || $v['checked']===1) ) {
                            $class .= ' super-active';
                            $placeholder[] = $v['label'];
                        }
                    }else{
                        if(in_array( $real_value, $selected_values, true ) ) {
                            $class .= ' super-active';
                            $placeholder[] = $v['label'];
                        }
                    }
                    $items[] = '<li class="super-item' . ( !empty($class) ? ' ' . $class : '') . '" data-value="' . esc_attr( $v['value'] ) . '" data-search-value="' . esc_attr( $v['label'] ) . '">' . esc_html($v['label']) . '</li>'; 
                    $items_values[] = $v['value'];
                }
            }
            if($tag==='text'){
                // text - autosuggest - custom
                if( !empty($atts['enable_auto_suggest']) ) {
                    if( ( isset( $atts['autosuggest_items'] ) ) && ( count($atts['autosuggest_items'])!=0 ) && ( $atts['autosuggest_items']!='' ) ) {
                        $items = array();
                        foreach( $atts['autosuggest_items'] as $k => $v ) {
                            if( ($v['checked']==='true' || $v['checked']===true || $v['checked']===1) ) {
                                $selected_items[] = $v['value'];
                                $atts['value'] = $v['value'];
                                $items[] = '<li class="super-item super-active super-default-selected" data-value="' . esc_attr( $v['value'] ) . '" data-search-value="' . esc_attr( $v['label'] ) . '">' . stripslashes($v['label']) . '</li>'; 
                            }else{
                                $items[] = '<li class="super-item' . ($atts['value']==$v['value'] ? ' super-active' : '') . '" data-value="' . esc_attr( $v['value'] ) . '" data-search-value="' . esc_attr( $v['label'] ) . '">' . stripslashes($v['label']) . '</li>'; 
                            }
                            $items_values[] = $v['value'];
                        }
                    }
                }
                // text - keywords - custom
                if( !empty($atts['enable_keywords']) ) {
                    if( ( isset( $atts['keywords_items'] ) ) && ( count($atts['keywords_items'])!=0 ) && ( $atts['keywords_items']!='' ) ) {
                        $items = array();
                        foreach( $atts['keywords_items'] as $k => $v ) {
                            if( ($v['checked']==='true' || $v['checked']===true || $v['checked']===1) ) {
                                $selected_items[] = $v['value'];
                                $item = '<li class="super-item super-active" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr($v['value']) . '" data-search-value="' . esc_attr($v['label']) . '">';
                            }else{
                                $item = '<li class="super-item" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr($v['value']) . '" data-search-value="' . esc_attr($v['label']) . '">';
                            }
                            $item .= '<span class="super-wp-tag">' . stripslashes($v['label']) . '</span>'; 
                            $item .= '</li>';
                            $items[] = $item;
                            $items_values[] = $v['value'];
                        }
                    }
                }
            }
            if($tag==='checkbox'){
                // checkbox - custom
                $items = array();
                foreach( $atts['checkbox_items'] as $k => $v ) {
                    // Get advanced tags value
                    $real_value = explode(';', $v['value'])[0];
                    $class = 'super-item';
                    // Check if this should be remembered as the default value set via settings
                    if( ($v['checked']==='true' || $v['checked']===true || $v['checked']===1) ) {
                        $class .= ' super-default-selected';
                    }
                    if( empty($selected_values) ) {
                        if( ($v['checked']==='true' || $v['checked']===true || $v['checked']===1) ) {
                            $selected_items[] = $v['value'];
                            $class .= ' super-active';
                        }
                    }else{
                        if(in_array( $real_value, $selected_values, true ) ) {
                            $class .= ' super-active';
                        }
                    }
                    if(!empty($atts['class'])) $class .= ' ' . $atts['class'];
                    if( !isset( $v['image'] ) ) $v['image'] = '';
                    if( $v['image']!='' ) {
                        $image = wp_get_attachment_image_src( $v['image'], 'original' );
                        $image = !empty( $image[0] ) ? $image[0] : '';
                        if( !isset( $v['max_width'] ) ) $v['max_width'] = 150;
                        if( !isset( $v['max_height'] ) ) $v['max_height'] = 200;
                        $img_styles = '';
                        if( $v['max_width']!='' ) $img_styles .= 'max-width:' . $v['max_width'] . 'px;';
                        if( $v['max_height']!='' ) $img_styles .= 'max-height:' . $v['max_height'] . 'px;';
                        $class .= ' super-has-image';
                        $item = '<label ' . ( !empty($class) ? 'class="'.$class.'" ' : '') . '>';
                        if( !empty( $image ) ) {
                            $item .= '<div class="super-image" style="background-image:url(\'' . $image . '\');"><img src="' . esc_url($image) . '"' . ($img_styles!='' ? ' style="' . $img_styles . '"' : '') . '></div>';
                        }else{
                            $image = SUPER_PLUGIN_FILE . 'assets/images/image-icon.png';
                            $item .= '<div class="super-image" style="background-image:url(\'' . $image . '\');"><img src="' . esc_url($image) . '"' . ($img_styles!='' ? ' style="' . $img_styles . '"' : '') . '></div>';
                        }
                        $item .= '<input type="checkbox" value="' . esc_attr( $v['value'] ) . '" />';
                        if($v['label']!='') $item .= '<span class="super-item-label">' . $v['label'] . '</span>';
                        $item .='</label>';
                    }else{
                        $item = '<label ' . ( !empty($class) ? 'class="'.$class.'" ' : '') . '>';
                        $item .= '<span class="super-before"><span class="super-after"></span></span>';
                        $item .= '<input type="checkbox" value="' . esc_attr( $v['value'] ) . '" /><div>' . $v['label'] . '</div>';
                        $item .= '</label>';
                    }
                    $items[] = $item;
                    $items_values[] = $v['value'];
                }
            }
            if($tag==='radio'){
                // radio -custom
                $items = array();
                $found = false;
                foreach( $atts['radio_items'] as $k => $v ) {

                    // Get advanced tags value
                    $real_value = explode(';', $v['value'])[0];
                    $class = 'super-item';
                    // Check if this should be remembered as the default value set via settings
                    if( ($v['checked']==='true' || $v['checked']===true || $v['checked']===1) ) {
                        $class .= ' super-default-selected';
                    }
                    if( empty($selected_values) ) {
                        if( $found===false && ($v['checked']==='true' || $v['checked']===true || $v['checked']===1) ) {
                            $selected_items[] = $v['value'];
                            $found = true;
                            $class .= ' super-active';
                        }
                    }else{
                        if( $found==false && in_array( $real_value, $selected_values, true ) ) {
                            $found = true;
                            $class .= ' super-active';
                        }
                    }
                    if(!empty($atts['class'])) $class .= ' ' . $atts['class'];
                    if( !isset( $v['image'] ) ) $v['image'] = '';
                    if( $v['image']!='' ) {
                        $image = wp_get_attachment_image_src( $v['image'], 'original' );
                        $image = !empty( $image[0] ) ? $image[0] : '';
                        if( !isset( $v['max_width'] ) ) $v['max_width'] = 150;
                        if( !isset( $v['max_height'] ) ) $v['max_height'] = 200;
                        $img_styles = '';
                        if( $v['max_width']!='' ) $img_styles .= 'max-width:' . $v['max_width'] . 'px;';
                        if( $v['max_height']!='' ) $img_styles .= 'max-height:' . $v['max_height'] . 'px;';
                        $class .= ' super-has-image';
                        $item = '<label ' . ( !empty($class) ? 'class="'.$class.'" ' : '') . '>';
                        if( !empty( $image ) ) {
                            $item .= '<div class="super-image" style="background-image:url(\'' . $image . '\');"><img src="' . esc_url($image) . '"' . ($img_styles!='' ? ' style="' . $img_styles . '"' : '') . '></div>';
                        }else{
                            $image = SUPER_PLUGIN_FILE . 'assets/images/image-icon.png';
                            $item .= '<div class="super-image" style="background-image:url(\'' . $image . '\');"><img src="' . esc_url($image) . '"' . ($img_styles!='' ? ' style="' . $img_styles . '"' : '') . '></div>';
                        }
                        $item .= '<input type="radio" value="' . esc_attr( $v['value'] ) . '" />';
                        if($v['label']!='') $item .= '<span class="super-item-label">' . $v['label'] . '</span>';
                        $item .='</label>';
                    }else{
                        $item = '<label ' . ( !empty($class) ? 'class="'.$class.'" ' : '') . '>';
                        $item .= '<span class="super-before"><span class="super-after"></span></span>';
                        $item .= '<input type="radio" value="' . esc_attr( $v['value'] ) . '" /><div>' . $v['label'] . '</div>';
                        $item .= '</label>';
                    }
                    $items[] = $item;
                    $items_values[] = $v['value'];
                }
            }
        }
        
        // dropdown - taxonomy
        // text - autosuggest - taxonomy
        // text - keywords - taxonomy
        // checkbox - taxonomy
        // radio -taxonomy
        if($atts[$prefix.'retrieve_method']=='taxonomy') {
            // dropdown - taxonomy
            if( !isset( $atts[$prefix.'retrieve_method_taxonomy'] ) ) $atts[$prefix.'retrieve_method_taxonomy'] = 'category';
            if( !isset( $atts[$prefix.'retrieve_method_exclude_taxonomy'] ) ) $atts[$prefix.'retrieve_method_exclude_taxonomy'] = '';
            if( !isset( $atts[$prefix.'retrieve_method_hide_empty'] ) ) $atts[$prefix.'retrieve_method_hide_empty'] = 0;
            if( !isset( $atts[$prefix.'retrieve_method_parent'] ) ) $atts[$prefix.'retrieve_method_parent'] = '';
            $args = array(
                'hide_empty' => $atts[$prefix.'retrieve_method_hide_empty'],
                'exclude' => $atts[$prefix.'retrieve_method_exclude_taxonomy'],
                'taxonomy' => $atts[$prefix.'retrieve_method_taxonomy'],
                'parent' => $atts[$prefix.'retrieve_method_parent'],
            );
            $categories = get_categories( $args );
            $items = array();
            foreach( $categories as $v ) {
                if( !isset( $atts[$prefix.'retrieve_method_value'] ) ) $atts[$prefix.'retrieve_method_value'] = 'slug';
                if($atts[$prefix.'retrieve_method_value']=='slug'){
                    $data_value = $v->slug;
                }elseif($atts[$prefix.'retrieve_method_value']=='id'){
                    $data_value = $v->term_id;
                }else{
                    $data_value = $v->name;
                }
                if($tag=='text') {
                    if($prefix=='keywords_'){
                        // text - keywords - taxonomy
                        $items[] = '<li class="super-item" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr( $data_value ) . '" data-search-value="' . esc_attr($v->name) . '"><span class="super-wp-tag">' . $v->name . '</span></li>';
                    }else{
                        // text - autosuggest - taxonomy
                        $items[] = '<li class="super-item" data-value="' . esc_attr( $data_value ) . '" data-search-value="' . esc_attr( $v->name ) . '">' . $v->name . '</li>'; 
                    }
                }   
                // dropdown - taxonomy
                if($tag=='dropdown')    $items[] = '<li class="super-item" data-value="' . esc_attr( $data_value ) . '" data-search-value="' . esc_attr( $v->name ) . '">' . $v->name . '</li>'; 
                // checkbox - taxonomy
                if($tag=='checkbox')    $items[] = '<label class="super-item' . ( !in_array($data_value, $selected_items, true ) ? '' : ' super-active super-default-selected') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input' . ( !in_array($data_value, $selected_items, true ) ? '' : ' checked="checked"') . ' type="checkbox" value="' . esc_attr( $data_value ) . '" /><div>' . $v->name . '</div></label>';
                // radio - taxonomy
                if($tag=='radio')       $items[] = '<label class="super-item' . ( ($atts['value']!=$data_value) ? '' : ' super-active super-default-selected') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input type="radio" value="' . esc_attr( $data_value ) . '" /><div>' . $v->name . '</div></label>';
                $items_values[] = $data_value;
            }
        }

        // dropdown - post_type
        // checkbox - post_type
        // radio - post_type
        // text - autosuggest - post_type
        // text - keywords - post_type
        if($atts['retrieve_method']=='post_type') {
            if( !isset( $atts[$prefix.'retrieve_method_post'] ) ) $atts[$prefix.'retrieve_method_post'] = 'post';
            if( !isset( $atts[$prefix.'retrieve_method_post_status'] ) ) $atts[$prefix.'retrieve_method_post_status'] = 'publish';
            if( !isset( $atts[$prefix.'retrieve_method_post_limit'] ) ) $atts[$prefix.'retrieve_method_post_limit'] = 30;
            if( !isset( $atts[$prefix.'retrieve_method_exclude_post'] ) ) $atts[$prefix.'retrieve_method_exclude_post'] = '';
            if( !isset( $atts[$prefix.'retrieve_method_parent'] ) ) $atts[$prefix.'retrieve_method_parent'] = '';
            if( !isset( $atts[$prefix.'retrieve_method_orderby'] ) ) $atts[$prefix.'retrieve_method_orderby'] = 'title';
            if( !isset( $atts[$prefix.'retrieve_method_order'] ) ) $atts[$prefix.'retrieve_method_order'] = 'asc';
            $atts[$prefix.'retrieve_method_order'] = strtolower($atts[$prefix.'retrieve_method_order']);
            $args = array(
                'post_type' => $atts[$prefix.'retrieve_method_post'],
                'post_status' => $atts[$prefix.'retrieve_method_post_status'],
                'exclude' => $atts[$prefix.'retrieve_method_exclude_post'],
                'post_parent' => $atts[$prefix.'retrieve_method_parent'],
                'orderby' => $atts[$prefix.'retrieve_method_orderby'],
                'order' => $atts[$prefix.'retrieve_method_order'],
                'numberposts' => (int)$atts[$prefix.'retrieve_method_post_limit']
            );
            if($atts[$prefix.'retrieve_method_orderby']=='price'){
                $args['orderby'] = 'meta_value_num';
                $args['meta_key'] = '_price';
            }

            // Check if we need to do an advanced filter based on taxonomy
            if(!empty($atts[$prefix.'retrieve_method_filters'])){
                // Make sure we grab the tag ID and then add it to the array
                $filters = explode("\n", $atts[$prefix.'retrieve_method_filters']);
                $tax_query = array(
                    'relation' => (!empty($atts[$prefix.'retrieve_method_filter_relation']) ? $atts[$prefix.'retrieve_method_filter_relation'] : 'IN')
                );
                foreach($filters as $fv){
                    $params = explode("|", $fv);
                    if(isset($params[0]) && isset($params[1]) && isset($params[2])) {
                        $field = $params[0];
                        $value = $params[1];
                        $taxonomy = $params[2];
                        $operator = (!empty($params[3]) ? $params[3] : 'IN');
                        $tax_query[] = array(
                            'operator' => $operator,
                            'taxonomy' => $taxonomy,
                            'field' => $field,
                            'terms' => explode(",",$value)
                        );
                    } 
                }
                if(count($tax_query)>1){
                    $args['tax_query'] = $tax_query;
                }
            }
            $posts = get_posts( $args );
            $items = array();
            foreach( $posts as $v ) {
                $v = (array) $v;
                // Try to grab the main featured image
                // In case the variable product does not have any images, we will use this main image as a fallback
                $image = wp_get_attachment_image_src(get_post_thumbnail_id($v['ID']));
                $image_url = !empty( $image[0] ) ? $image[0] : '';
                if( !empty( $image_url ) ) {
                    // If exists
                    $main_featured_image_url = $image_url;
                }else{
                    // If doesn't exists use default placeholder image
                    $main_featured_image_url = SUPER_PLUGIN_FILE . 'assets/images/image-icon.png';
                }
                $final_featured_image_url = $main_featured_image_url;


                // Find out wether this is a WooCommerce product and if it's a variable product
                // If so we must loop through all the variations and display them, because each variation will have it's own price and or meta data
                if( ($atts[$prefix.'retrieve_method_post']==='product') && (class_exists('WooCommerce')) && (wc_get_product( $v['ID'] )->get_type()==='variable') ) {
                    // Seems like we got a variable product here
                    // Get all variations based of this product ID
                    $product = wc_get_product( $v['ID'] );
                    $available_variations = array();
                    foreach ( $product->get_children() as $child_id ) {
                        $variation = wc_get_product( $child_id );
                        // Hide out of stock variations if 'Hide out of stock items from the catalog' is checked.
                        if ( ! $variation || ! $variation->exists() || ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ! $variation->is_in_stock() ) ) {
                            continue;
                        }
                        // Filter 'woocommerce_hide_invisible_variations' to optionally hide invisible variations (disabled variations and variations with empty price).
                        if ( apply_filters( 'woocommerce_hide_invisible_variations', true, $product->get_id(), $variation ) && ! $variation->variation_is_visible() ) {
                            continue;
                        }
                        $array = $product->get_available_variation( $variation );
                        $array['ID'] = $child_id;
                        $array['post_title'] = $variation->get_name();
                        $available_variations[] = $array;
                    }
                    $available_variations = array_values( array_filter( $available_variations ) );
                    foreach($available_variations as $vk => $vv){
                        // Try to get the featured image specifically for this attribute
                        $image = wp_get_attachment_image_src(get_post_thumbnail_id($vv['ID']));
                        $image_url = !empty( $image[0] ) ? $image[0] : '';
                        if( !empty( $image_url ) ) {
                            $final_featured_image_url = $image_url;
                        }else{
                            $final_featured_image_url = $main_featured_image_url;
                        }

                        // @since 1.2.5
                        if( !isset( $atts[$prefix.'retrieve_method_value'] ) ) $atts[$prefix.'retrieve_method_value'] = 'slug';
                        if($atts[$prefix.'retrieve_method_value']=='slug'){
                            $data_value = $v['post_name'];
                        }elseif($atts[$prefix.'retrieve_method_value']=='id'){
                            $data_value = $vv['variation_id'];
                        }elseif($atts[$prefix.'retrieve_method_value']=='custom'){
                            $data_value = '';
                            $retrieve_method_meta_keys = explode("\n", $atts[$prefix.'retrieve_method_meta_keys']);
                            foreach($retrieve_method_meta_keys as $rk => $rv){
                                if($rv=='featured_image'){
                                    $attachment_image = wp_get_attachment_image_src(get_post_thumbnail_id($v['ID']));
                                    if($attachment_image){
                                        $image_url = $attachment_image[0];
                                        if($rk>0){
                                            $data_value .= ';'.$image_url;
                                        }else{
                                            $data_value .= $image_url;
                                        }
                                    }
                                    continue;
                                }
                                if($rk>0){
                                    if(isset($vv[$rv])){
                                        $data_value .= ';'.$vv[$rv];
                                    }else{
                                        // Get post meta data
                                        $meta_value = get_post_meta( $vv['ID'], $rv, true );
                                        if(!is_array($meta_value)){
                                            $data_value .= ';'.$meta_value;
                                        }else{
                                            $data_value .= ';Array()';
                                        }
                                    }
                                }else{
                                    if(isset($vv[$rv])){
                                        $data_value .= $vv[$rv];
                                    }else{
                                        // Get post meta data
                                        $meta_value = get_post_meta( $vv['ID'], $rv, true );
                                        if(!is_array($meta_value)){
                                            $data_value .= $meta_value;
                                        }else{
                                            $data_value .= 'Array()';
                                        }
                                    }
                                }
                            }
                        }else{
                            $data_value = $vv['post_title'];
                        }
                        $sku = '';
                        if(function_exists('wc_get_product')){
                            $product = wc_get_product( $vv['ID'] );
                            $sku = ';'.$product->get_sku();    
                        }
                        if($tag=='text') {
                            if($prefix=='keywords_'){
                                $items[] = '<li class="super-item" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr($data_value) . '" data-search-value="' . esc_attr( $vv['post_title']) . $sku . '"><span class="super-wp-tag">' . $vv['post_title'] . '</span></li>';
                            }else{
                                $items[] = '<li class="super-item" data-value="' . esc_attr($data_value) . '" data-search-value="' . esc_attr( $vv['post_title'] ) . $sku . '">' . $vv['post_title'] . '</li>'; 
                            }
                        }   
                        if($tag=='dropdown')    $items[] = '<li class="super-item"  data-value="' . esc_attr( $data_value ) . '" data-search-value="' . esc_attr( $vv['post_title'] ) . $sku . '">' . $vv['post_title'] . '</li>'; 
                        if($tag=='checkbox'){
                            $items[] = self::get_item_html($prefix, $tag, $atts, $data_value, $selected_items, $vv, $final_featured_image_url);
                        }
                        if($tag=='radio'){
                            $items[] = self::get_item_html($prefix, $tag, $atts, $data_value, null, $vv, $final_featured_image_url);
                        }
                        $items_values[] = $data_value;
                    }
                }else{
                    // @since 1.2.5
                    if( !isset( $atts[$prefix.'retrieve_method_value'] ) ) $atts[$prefix.'retrieve_method_value'] = 'slug';
                    if($atts[$prefix.'retrieve_method_value']=='slug'){
                        $data_value = $v['post_name'];
                    }elseif($atts[$prefix.'retrieve_method_value']=='id'){
                        $data_value = $v['ID'];
                    }elseif($atts[$prefix.'retrieve_method_value']=='custom'){
                        $data_value = '';
                        $retrieve_method_meta_keys = explode("\n", $atts[$prefix.'retrieve_method_meta_keys']);
                        foreach($retrieve_method_meta_keys as $rk => $rv){
                            if($rv=='featured_image'){
                                $attachment_image = wp_get_attachment_image_src(get_post_thumbnail_id($v['ID']));
                                if($attachment_image){
                                    $image_url = $attachment_image[0];
                                    if($rk>0){
                                        $data_value .= ';'.$image_url;
                                    }else{
                                        $data_value .= $image_url;
                                    }
                                }
                                continue;
                            }
                            if($rk>0){
                                if(isset($v[$rv])){
                                    $data_value .= ';'.$v[$rv];
                                }else{
                                    // Get post meta data
                                    $meta_value = get_post_meta( $v['ID'], $rv, true );
                                    if(!is_array($meta_value)){
                                        $data_value .= ';'.$meta_value;
                                    }else{
                                        $data_value .= ';Array()';
                                    }
                                }
                            }else{
                                if(isset($v[$rv])){
                                    $data_value .= $v[$rv];
                                }else{
                                    // Get post meta data
                                    $meta_value = get_post_meta( $v['ID'], $rv, true );
                                    if(!is_array($meta_value)){
                                        $data_value .= $meta_value;
                                    }else{
                                        $data_value .= 'Array()';
                                    }
                                }
                            }
                        }
                    }else{
                        $data_value = $v['post_title'];
                    }
                    $item_value = $data_value;
                    if($tag=='text') {
                        if($prefix=='keywords_'){
                            $items[] = '<li class="super-item" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr($data_value) . '" data-search-value="' . esc_attr( $v['post_title']) . '"><span class="super-wp-tag">' . esc_html($v['post_title']) . '</span></li>';
                        }else{
                            $items[] = '<li class="super-item ' . ( $atts['value']==explode(';', $data_value)[0] ? ' super-active' : '' ) . '" data-value="' . esc_attr($data_value) . '" data-search-value="' . esc_attr( $v['post_title']) . '">' . esc_html($v['post_title']) . '</li>';
                            $item_value = explode(';', $data_value)[0];
                        }
                    }
                    if($tag=='dropdown')    $items[] = '<li class="super-item" data-value="' . esc_attr( $data_value ) . '" data-search-value="' . esc_attr( $v['post_title']) . '">' . esc_html($v['post_title']) . '</li>'; 
                    if($tag=='checkbox'){
                        $items[] = self::get_item_html($prefix, $tag, $atts, $data_value, $selected_items, $v, $main_featured_image_url);
                    }
                    if($tag=='radio'){
                        $items[] = self::get_item_html($prefix, $tag, $atts, $data_value, $selected_items, $v, $main_featured_image_url);
                    }
                    $items_values[] = $item_value;
                }
            }
        }

        // dropdown - product_attribute
        // checkbox - product_attribute
        // radio - product_attribute
        // text - autosuggest - product_attribute
        // text - keywords - product_attribute
        if($atts[$prefix.'retrieve_method']=='product_attribute') {
            if( !isset( $atts[$prefix.'retrieve_method_product_attribute'] ) ) $atts[$prefix.'retrieve_method_product_attribute'] = '';
            if($atts[$prefix.'retrieve_method_product_attribute']!=''){
                // Let's try to retrieve product attributes
                if ( class_exists( 'WooCommerce' ) ) {
                    global $post;
                    if( isset( $post ) ) {
                        global $product;
                        $attributes = $product->get_attribute( $atts[$prefix.'retrieve_method_product_attribute'] );
                        $attributes = explode(', ', $attributes);
                        $items = array();
                        foreach( $attributes as $v ) {
                            if($tag=='text') {
                                if($prefix=='keywords_'){
                                    $items[] = '<li class="super-item" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr( $v ) . '" data-search-value="' . esc_attr( $v ) . '"><span class="super-wp-tag">' . $v . '</span></li>'; 
                                }else{
                                    $items[] = '<li class="super-item" data-value="' . esc_attr( $v ) . '" data-search-value="' . esc_attr( $v ) . '">' . $v . '</li>'; 
                                }
                            }
                            if($tag=='dropdown')    $items[] = '<li class="super-item" data-value="' . esc_attr( $v ) . '" data-search-value="' . esc_attr( $v ) . '">' . $v . '</li>';  
                            if($tag=='checkbox')    $items[] = '<label class="super-item' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input type="checkbox" value="' . esc_attr( $v ) . '" /><div>' . $v . '</div></label>';
                            if($tag=='radio')       $items[] = '<label class="super-item' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input type="radio" value="' . esc_attr( $v ) . '" /><div>' . $v . '</div></label>';
                            $items_values[] = $v;
                        }
                    }
                }          
            }
        }

        // dropdown - tags
        // checkbox - tags
        // radio - tags
        // text - autosuggest - tags
        // text - keywords - tags
        if($atts[$prefix.'retrieve_method']=='tags') {
            $tags = get_tags(
                array(
                    'hide_empty'=>false
                )
            );
            $items = array();
            foreach ( $tags as $v ) {
                if( !isset( $atts[$prefix.'retrieve_method_value'] ) ) $atts[$prefix.'retrieve_method_value'] = 'slug';
                if( $atts[$prefix.'retrieve_method_value']=='slug' ) {
                    $data_value = $v->slug;
                }elseif( $atts[$prefix.'retrieve_method_value']=='id' ) {
                    $data_value = $v->term_id;
                }else{
                    $data_value = $v->name;
                }
                if($tag=='text') {
                    if($prefix=='keywords_'){
                        $item = '<li class="super-item" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr($data_value) . '" data-search-value="' . esc_attr($v->name) . '">';
                        $item .= '<span class="super-wp-tag">' . $v->name . '</span>'; 
                        $item .= '<span class="super-wp-tag-count">×&nbsp;' . $v->count . '</span>'; 
                        if( !empty($v->description) ) {
                            $item .= '<span class="super-flex-clear"></span>';
                            $item .= '<span class="super-wp-tag-desc">' . $v->description . '</span>'; 
                        }
                        $item .= '</li>';
                        $items[] = $item;
                    }else{
                        $items[] = '<li class="super-item" data-value="' . esc_attr($data_value) . '" data-search-value="' . esc_attr( $v->name ) . '">' . $v->name . '</li>';
                    }
                }
                if($tag=='dropdown')    $items[] = '<li class="super-item" data-value="' . esc_attr( $data_value ) . '" data-search-value="' . esc_attr( $v->name ) . '">' . $v->name . '</li>';  
                if($tag=='checkbox')    $items[] = '<label class="super-item' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input type="checkbox" value="' . esc_attr( $data_value ) . '" /><div>' . $v->name . '</div></label>';
                if($tag=='radio')       $items[] = '<label class="super-item' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input type="radio" value="' . esc_attr( $data_value ) . '" /><div>' . $v->name . '</div></label>';
                $items_values[] = $data_value;
            }
        }

        // dropdown - csv
        // checkbox - csv
        // radio - csv
        // text - autosuggest - csv
        // text - keywords - csv
        if($atts[$prefix.'retrieve_method']=='csv') {
            $delimiter = ',';
            $enclosure = '"';
            if( isset( $atts[$prefix.'retrieve_method_delimiter'] ) ) $delimiter = $atts[$prefix.'retrieve_method_delimiter'];
            if( isset( $atts[$prefix.'retrieve_method_enclosure'] ) ) $enclosure = stripslashes($atts[$prefix.'retrieve_method_enclosure']);
            $file = get_attached_file($atts[$prefix.'retrieve_method_csv']);
            if( (!empty($file)) && (($handle = fopen($file, "r")) !== FALSE) ) {
                // Progress file pointer and get first 3 characters to compare to the BOM string.
                $bom = "\xef\xbb\xbf"; // BOM as a string for comparison.
                if (fgets($handle, 4) !== $bom) rewind($handle); // BOM not found - rewind pointer to start of file.
                $placeholder = array();
                $items = array();
                while (($data = fgetcsv($handle, 10000, $delimiter, $enclosure)) !== FALSE) {
                    $num = count($data);
                    $value = 'undefined';
                    $title = 'undefined';
                    for ( $c=0; $c < $num; $c++ ) {
                        if( $c==0) $value = $data[$c];
                        if( $c==1 ) $title = $data[$c];
                    }
                    if( $title=='undefined' ) {
                        $title = $value; 
                    }
                    if($tag=='text') {
                        // text - autosuggest - csv
                        if( !empty($atts['enable_auto_suggest']) ) {
                            $items[] = '<li class="super-item' . ($atts['value']==$value ? ' super-active' : '') . '" data-value="' . esc_attr( $value ) . '" data-search-value="' . esc_attr( $title ) . '">' . $title . '</li>';
                        }else{
                            // text - keywords - csv
                            if($prefix=='keywords_'){
                                $item = '<li class="super-item" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr($value) . '" data-search-value="' . esc_attr($title) . '">';
                                $item .= '<span class="super-wp-tag">' . $title . '</span>'; 
                                $item .= '</li>';
                                $items[] = $item;
                            }else{
                                $items[] = '<li class="super-item" data-value="' . esc_attr( $value ) . '" data-search-value="' . esc_attr( $title ) . '">' . $title . '</li>';
                            }
                        }    
                    }
                    if($tag=='dropdown') {
                        // Get advanced tags value
                        $real_value = explode(';', $value)[0];
                        $class = '';
                        if(in_array( $real_value, $selected_values, true ) ) {
                            $class .= ' super-active';
                            $placeholder[] = $title;
                        }
                        $items[] = '<li class="super-item' . (!empty($class) ? ' ' . $class : '' ) . '" data-value="' . esc_attr( $value ) . '" data-search-value="' . esc_attr( $title ) . '">' . $title . '</li>';
                    }
                    if($tag=='checkbox') {
                        $items[] = '<label class="super-item' . ( !in_array($value, $selected_values, true ) ? '' : 'super-active') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input' . ( !in_array( $value, $selected_items, true ) ? '' : ' checked="checked"') . ' type="checkbox" value="' . esc_attr( $value ) . '" /><div>' . $title . '</div></label>';
                    }
                    if($tag=='radio') {
                        $items[] = '<label class="super-item' . ( ($atts['value']!=$value) ? '' : 'super-active') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input type="radio" value="' . esc_attr( $value ) . '" /><div>' . $title . '</div></label>';
                    }
                    $items_values[] = $value;
                }
                fclose($handle);
            }
        }

        // dropdown - author
        // checkbox - author
        // radio - author
        // text - autosuggest - author
        // text - keywords - author
        if( ($atts[$prefix.'retrieve_method']=='author') || ($atts[$prefix.'retrieve_method']=='post_meta') ) {
            $meta_field_name = '';
            $line_explode = "\n";
            $option_explode = '|';
            if( !empty( $atts[$prefix.'retrieve_method_author_field'] ) ) $meta_field_name = $atts[$prefix.'retrieve_method_author_field'];
            if( !empty( $atts[$prefix.'retrieve_method_author_line_explode'] ) ) $line_explode = $atts[$prefix.'retrieve_method_author_line_explode'];
            if( !empty( $atts[$prefix.'retrieve_method_author_option_explode'] ) ) $option_explode = $atts[$prefix.'retrieve_method_author_option_explode'];

            // Retrieve meta data from author
            if( $atts[$prefix.'retrieve_method']=='author' ) {
                // First check if we are on the author profile page, and see if we can find author based on slug
                $page_url = ( isset($_SERVER['HTTPS']) ? 'https' : 'http' ) . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
                $author_name = basename($page_url);
                $current_author = ( isset($_GET['author']) ? get_user_by('id', absint($_GET['author'])) : get_user_by('slug', $author_name) );
                if( $current_author ) {
                    // This is an author profile page
                    $author_id = $current_author->ID;
                }else{
                    // This is not an author profile page
                    global $post;
                    if( !isset( $post ) ) {
                        $author_id = '';
                    }else{
                        $author_id = $post->post_author;
                    }
                }
                $data = get_user_meta( absint($author_id), $meta_field_name, true ); 
            }
            
            // Retrieve meta data from post
            if( $atts[$prefix.'retrieve_method']=='post_meta' ) {
                global $post;
                $data = get_post_meta( $post->ID, $meta_field_name, true ); 
            }

            // If data exists return in list
            if( $data ) {
                $data = explode( $line_explode, $data );
                if( is_array($data) ) {
                    $items = array();
                    foreach( $data as $v ) {
                        $values = explode( $option_explode , $v );
                        $label = ( isset( $values[0] ) ? $values[0] : '' );
                        $value = ( isset( $values[1] ) ? $values[1] : $label );
                        if( empty($label) ) continue;

                        // @since 4.0.2 - remove line breaks for dropdowns
                        $label = str_replace(array("\r", "\n"), '', $label);
                        $value = str_replace(array("\r", "\n"), '', $value);

                        if($tag=='text') {
                            if($prefix=='keywords_'){
                                $item = '<li class="super-item" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr( $value ) . '" data-search-value="' . esc_attr( $label ) . '">';
                                $item .= '<span class="super-wp-tag">' . $label . '</span>'; 
                                $item .= '</li>';
                                $items[] = $item;
                            }else{
                                $items[] = '<li class="super-item" data-value="' . esc_attr( $value ) . '" data-search-value="' . esc_attr( $label ) . '">' . $label . '</li>';
                            }
                        }
                        if($tag=='dropdown')    $items[] = '<li class="super-item" data-value="' . esc_attr( $value ) . '" data-search-value="' . esc_attr( $label ) . '">' . $label . '</li>';
                        if($tag=='checkbox')    $items[] = '<label class="super-item' . ( !in_array($value, $selected_items, true ) ? '' : ' super-active super-default-selected') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input' . ( !in_array($value, $selected_items, true ) ? '' : ' checked="checked"') . ' type="checkbox" value="' . esc_attr( $value ) . '" /><div>' . $label . '</div></label>';
                        if($tag=='radio')       $items[] = '<label class="super-item' . ( ($atts['value']!=$value) ? '' : ' super-active super-default-selected') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input type="radio" value="' . esc_attr( $value ) . '" /><div>' . $label . '</div></label>';
                        $items_values[] = $value;
                    }
                }
            }
        }
        
        // dropdown - post_terms
        // checkbox - post_terms
        // radio - post_terms
        // text - autosuggest - post_terms
        // text - keywords - post_terms
        if($atts[$prefix.'retrieve_method']=='post_terms') {
            if( empty( $atts[$prefix.'retrieve_method_taxonomy'] ) ) $atts[$prefix.'retrieve_method_taxonomy'] = 'category';
            if( empty( $atts[$prefix.'retrieve_method_post_terms_label'] ) ) $atts[$prefix.'retrieve_method_post_terms_label'] = 'names';
            if( empty( $atts[$prefix.'retrieve_method_post_terms_value'] ) ) $atts[$prefix.'retrieve_method_post_terms_value'] = 'slugs';
            $args = array(
                'taxonomy' => $atts[$prefix.'retrieve_method_taxonomy'],
                'terms_label' => $atts[$prefix.'retrieve_method_post_terms_label'],
                'terms_value' => $atts[$prefix.'retrieve_method_post_terms_value'],
            );
            // We possibly are looking for post terms (taxonomy)
            global $post;
            if( isset( $post ) ) {
                $terms = wp_get_post_terms( $post->ID, $args['taxonomy'], array( 'fields' => 'all' ) );
                $items = array();
                foreach( $terms as $v ) {
                    $data_label = $v->name;
                    $data_value = $v->slug;
                    if($atts[$prefix.'retrieve_method_post_terms_label']=='slugs') $data_label = $v->slug;
                    if($atts[$prefix.'retrieve_method_post_terms_label']=='ids') $data_label = $v->term_id;
                    if($atts[$prefix.'retrieve_method_post_terms_value']=='names') $data_value = $v->name;
                    if($atts[$prefix.'retrieve_method_post_terms_value']=='ids') $data_value = $v->term_id;
                    if($tag=='text') {
                        if($prefix=='keywords_'){
                            // text - keywords - taxonomy
                            $items[] = '<li class="super-item" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr( $data_value ) . '" data-search-value="' . esc_attr($data_label) . '"><span class="super-wp-tag">' . $data_label . '</span></li>';
                        }else{
                            // text - autosuggest - taxonomy
                            $items[] = '<li class="super-item" data-value="' . esc_attr( $data_value ) . '" data-search-value="' . esc_attr( $data_label ) . '">' . $data_label . '</li>'; 
                        }
                    }   
                    // dropdown - taxonomy
                    if($tag=='dropdown')    $items[] = '<li class="super-item" data-value="' . esc_attr( $data_value ) . '" data-search-value="' . esc_attr( $data_label ) . '">' . $data_label . '</li>'; 
                    // checkbox - taxonomy
                    if($tag=='checkbox')    $items[] = '<label class="super-item' . ( !in_array($data_value, $selected_items, true ) ? '' : ' super-active super-default-selected') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input' . ( !in_array($data_value, $selected_items, true ) ? '' : ' checked="checked"') . ' type="checkbox" value="' . esc_attr( $data_value ) . '" /><div>' . $data_label . '</div></label>';
                    // radio - taxonomy
                    if($tag=='radio')       $items[] = '<label class="super-item' . ( ($atts['value']!=$data_value) ? '' : ' super-active super-default-selected') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input type="radio" value="' . esc_attr( $data_value ) . '" /><div>' . $data_label . '</div></label>';
                    $items_values[] = $data_value;
                }
            }
        }

        // dropdown - author
        // checkbox - author
        // radio - author
        // text - autosuggest - author
        // text - keywords - author
        if($atts[$prefix.'retrieve_method']=='users') {
            $exclude_users = array();
            $role_filters = array();
            $default_user_label = '#{ID} - {first_name} {last_name} ({user_email})';
            $meta_keys = 'ID';
            if( !empty( $atts[$prefix.'retrieve_method_exclude_users'] ) ) $exclude_users = explode(",",$atts[$prefix.'retrieve_method_exclude_users']);
            if( !empty( $atts[$prefix.'retrieve_method_role_filters'] ) ) $role_filters = explode("\n",$atts[$prefix.'retrieve_method_role_filters']);
            if( !empty( $atts[$prefix.'retrieve_method_user_label'] ) ) $default_user_label = $atts[$prefix.'retrieve_method_user_label'];
            if( !empty( $atts[$prefix.'retrieve_method_user_meta_keys'] ) ) $meta_keys = $atts[$prefix.'retrieve_method_user_meta_keys'];
            foreach($role_filters as $k => $v){
                $role_filters[$k] = trim($v);    
            }
            $args = array(
                'role__in'     => $role_filters,
                'orderby'      => 'login',
                'order'        => 'ASC',
                'exclude'      => $exclude_users
            ); 
            $users = (array) get_users( $args );
            $regex = '/\{(.*?)\}/';
            $users_array = array();
            foreach($users as $k => $v){
                $v = (array) $v->data;
                // Replace all {tags} and build the user label
                $user_label = $default_user_label;
                preg_match_all($regex, $user_label, $matches, PREG_SET_ORDER, 0);
                foreach($matches as $mk => $mv){
                    if( empty($mv[1]) ) continue;
                    if( isset($mv[1]) && isset($v[$mv[1]]) ) {
                        $user_label = str_replace( '{' . $mv[1] . '}', $v[$mv[1]], $user_label );
                    }else{
                        // Maybe we need to search in user meta data
                        $meta_value = get_user_meta( $v['ID'], $mv[1], true );
                        $user_label = str_replace( '{' . $mv[1] . '}', $meta_value, $user_label );
                    }
                }
                // Replace all meta_keys and build the user value
                $mk = explode("\n", $meta_keys);
                $user_value = array();
                foreach($mk as $mv){
                    if( empty($mv) ) continue;
                    if( isset($v[$mv]) ) {
                        $user_value[] = $v[$mv];
                    }else{
                        // Maybe we need to search in user meta data
                        $meta_value = get_user_meta( $v['ID'], $mv, true );
                        $user_value[] = $meta_value;
                    }   
                }
                $users_array[] = array(
                    'label' => $user_label,
                    'value' => implode(';', $user_value)
                );
            }

            if(isset($entry_data[$atts['name']])) {
                $first_entry_value = explode(";", $entry_data[$atts['name']]['value'])[0];
            }
            $items = array();
            foreach($users_array as $k => $v){
                $value = $v['value'];
                $label = $v['label'];
                $active = false;
                if( (!empty($atts['value'])) && ($atts['value']==explode(";",$value)[0]) ){
                    $active = true;
                }
                $selected = false;
                if(isset($entry_data[$atts['name']])) {
                    $first_item_value = explode(";", $value)[0];
                    if($first_entry_value==$first_item_value){
                        $selected = true;
                        $atts['value'] = $label;
                    }
                }
                if($active){
                    $atts['value'] = esc_attr( $label );
                }
                if($tag=='text') {
                    if($prefix=='keywords_'){
                        $item = '<li class="super-item" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr( $value ) . '" data-search-value="' . esc_attr( $label ) . '">';
                        $item .= '<span class="super-wp-tag">' . $label . '</span>'; 
                        $item .= '</li>';
                        $items[] = $item;
                    }else{
                        $items[] = '<li class="super-item' . ($selected || $active ? ' super-active' : '') . '" data-value="' . esc_attr( $value ) . '" data-search-value="' . esc_attr( $label ) . '">' . $label . '</li>';
                    }
                }
                if($tag=='dropdown'){
                    $items[] = '<li class="super-item' . ($selected || $active ? ' super-active' : '') . '" data-value="' . esc_attr( $value ) . '" data-search-value="' . esc_attr( $label ) . '">' . $label . '</li>';
                }
                if($tag=='checkbox'){
                    $items[] = '<label class="super-item' . ( !in_array($value, $selected_items, true ) || $active ? '' : ' super-active super-default-selected') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input' . ( !in_array($value, $selected_items, true ) || $active ? '' : ' checked="checked"') . ' type="checkbox" value="' . esc_attr( $value ) . '" /><div>' . $label . '</div></label>';
                }
                if($tag=='radio'){
                    $items[] = '<label class="super-item' . ( $selected || $active ? ' super-active super-default-selected' : '') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input type="radio" value="' . esc_attr( $value ) . '" /><div>' . $label . '</div></label>';
                }
                $items_values[] = $value;
            }
        }


        // dropdown - db_table
        // checkbox - db_table
        // radio - db_table
        // text - autosuggest - db_table
        // text - keywords - db_table
        if($atts[$prefix.'retrieve_method']=='db_table') {
            if( !isset( $atts[$prefix.'retrieve_method_db_table'] ) ) $atts[$prefix.'retrieve_method_db_table'] = '';
            if( !isset( $atts[$prefix.'retrieve_method_db_row_value'] ) ) $atts[$prefix.'retrieve_method_db_row_value'] = '';
            if( !isset( $atts[$prefix.'retrieve_method_db_row_label'] ) ) $atts[$prefix.'retrieve_method_db_row_label'] = '';
            $column_value = $atts[$prefix.'retrieve_method_db_row_value'];
            $column_label = $atts[$prefix.'retrieve_method_db_row_label']; // Example: '[{code}] - {last_name} {initials} - [{date}] - {email}';

            // Define the SELECT query
            $select_query = '';
            $regex = '/{\s?[\'|"|\s|]?(.*?)[\'|"|\s|]?}/';
            $match = preg_match_all($regex, $column_value, $matches, PREG_SET_ORDER, 0);
            $tags = array();
            foreach($matches as $k => $v){
                if(isset($v[1])) {
                    $tags[$v[1]] = $v[1];
                    $column_name = $v[1];
                    if(empty($select_query)){
                        $select_query .= $v[1];
                    }else{
                        $select_query .= ', '.$v[1];
                    }
                }
            }
            $match = preg_match_all($regex, $column_label, $matches, PREG_SET_ORDER, 0);
            foreach($matches as $k => $v){
                if(isset($v[1])) {
                    $tags[$v[1]] = $v[1];
                    $column_name = $v[1];
                    if(empty($select_query)){
                        $select_query .= $v[1];
                    }else{
                        $select_query .= ', '.$v[1];
                    }
                }
            }
            if($select_query=='') {
                $select_query = '*';
            }
            global $wpdb;
            $table = $atts[$prefix.'retrieve_method_db_table'];
            $results = $wpdb->get_results("SELECT $select_query FROM $table WHERE 1=1", ARRAY_A);
            $items = array();
            foreach( $results as $k => $v ) {
                $final_value = $column_value;
                $final_label = $column_label;
                foreach( $tags as $tk => $tv ) {
                    $final_value = str_replace('{'.$tv.'}', $v[$tv], $final_value);
                    $final_label = str_replace('{'.$tv.'}', $v[$tv], $final_label);
                }
                if($tag=='text') {
                    if($prefix=='keywords_'){
                        $item = '<li class="super-item" sfevents="' . esc_attr('{"click":"keywords.add"}') . '" data-value="' . esc_attr( $final_value ) . '" data-search-value="' . esc_attr( $final_label ) . '">';
                        $item .= '<span class="super-wp-tag">' . $final_label . '</span>'; 
                        $item .= '</li>';
                        $items[] = $item;
                    }else{
                        $items[] = '<li class="super-item" data-value="' . esc_attr( $final_value ) . '" data-search-value="' . esc_attr( $final_label ) . '">' . $final_label . '</li>';
                    }
                }
                if($tag=='dropdown')    $items[] = '<li class="super-item" data-value="' . esc_attr( $final_value ) . '" data-search-value="' . esc_attr( $final_label ) . '">' . $final_label . '</li>';
                if($tag=='checkbox')    $items[] = '<label class="super-item' . ( !in_array($final_value, $selected_items, true ) ? '' : ' super-active super-default-selected') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input' . ( !in_array($final_value, $selected_items, true ) ? '' : ' checked="checked"') . ' type="checkbox" value="' . esc_attr( $final_value ) . '" /><div>' . $final_label . '</div></label>';
                if($tag=='radio')       $items[] = '<label class="super-item' . ( ($atts['value']!=$final_value) ? '' : ' super-active super-default-selected') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"><span class="super-before"><span class="super-after"></span></span><input type="radio" value="' . esc_attr( $final_value ) . '" /><div>' . $final_label . '</div></label>';
                $items_values[] = $final_value;
            }
        }
        
        // Set correct placeholder for dropdowns
        if($tag=='dropdown'){
            if(!empty($placeholder)){
                $atts['placeholder'] = implode(', ', $placeholder);
            }
        }
        if(empty($atts['value'])){
            $atts['value'] = implode( ',', $selected_items );
        }
        if(empty($items_values)) $items_values = array();
        return apply_filters( 'super_' . $tag . '_' . $atts['name'] . '_items_filter', array('items'=>$items, 'items_values'=>$items_values, 'atts'=>$atts), array( 'tag'=>$tag, 'atts'=>$atts, 'settings'=>$settings, 'entry_data'=>$entry_data ) );
    }

    
    /** 
     *  Output the element HTML on the builder page (create form) inside the preview area
     *
     * @param  string  $tag
     *
     *  @since      1.0.0
    */
    public static function output_builder_html( $tag, $group, $data, $inner, $shortcodes=null, $settings=null, $predefined=false, $builder=false ) {


        // @since 3.5.0 - backwards compatibility with older form codes that have image field and other HTML field in group form_elements instead of html_elements
        if( ($group=='form_elements') && ($tag=='image' || $tag=='heading' || $tag=='html' || $tag=='divider' || $tag=='spacer' || $tag=='google_map' ) ) {
            $group = 'html_elements';
        }

        if( $shortcodes==null ) {
            $shortcodes = self::shortcodes();
        }

        if( !isset( $shortcodes[$group]['shortcodes'][$tag] ) ) {
            return '';
        }

        $name = $shortcodes[$group]['shortcodes'][$tag]['name'];

        $data =  (array) $data;
        if( count($data)==0 ) {
            // We have to add the predefined values for each field setting
            $data = array();
            foreach( $shortcodes[$group]['shortcodes'][$tag]['atts'] as $k => $v ) {
                if(!empty($v['fields'])){
                    foreach( $v['fields'] as $fk => $fv ) {
                        if( $fv['default']!=='' ) {
                            $data[$fk] = $fv['default'];
                        }
                    }
                }
            }
        }else{
            // Skip this if we are adding a predefined element, otherwise it would override it with the element defaults
            if( $predefined==false ) {
                $data = json_decode(json_encode($data), true);
                foreach( $shortcodes[$group]['shortcodes'][$tag]['atts'] as $k => $v ) {
                    if(!isset($v['fields'])) continue; 
                    foreach( $v['fields'] as $fk => $fv ) {
                        if( isset($data[$fk]) ) {
                            $default = SUPER_Common::get_default_element_setting_value($shortcodes, $group, $tag, $k, $fk);
                            if( ( ($data[$fk]==$default) || ($data[$fk]==='') ) && (empty($v['fields'][$fk]['allow_empty'])) ) {
                                unset($data[$fk]);
                            }
                        }
                    }
                }
            }
        }


        $inner = json_decode(json_encode($inner), true);

        $class = '';
        $inner_class = '';

        if( $tag=='column' ) {
            if(empty($data['size'])) $data['size'] = '1/1';
            $sizes = array(
                '1/5'=>array('one_fifth',20),
                '1/4'=>array('one_fourth',25),
                '1/3'=>array('one_third',33.3333334),
                '2/5'=>array('two_fifth',40),
                '1/2'=>array('one_half',50),
                '3/5'=>array('three_fifth',60),
                '2/3'=>array('two_third',66.6666667),
                '3/4'=>array('three_fourth',75),
                '4/5'=>array('four_fifth',80),
                '1/1'=>array('one_full',100),
            ); 
            $class .= ' super_'.$sizes[$data['size']][0] . ' super-' . str_replace( 'column_', 'super_', $tag );
        }
        if($tag=='multipart' || $tag=='tabs' ){
            $class .= ' super-' . $tag;
        }
  
        if( isset( $shortcodes[$group]['shortcodes'][$tag]['drop'] ) ) {
            $class .= ' drop-here';
            // But not if this is a TAB element
            if($tag!='tabs') {
                $inner_class .= ' super-dropable';
            }
        }
        
        if( (!empty($data['minimized'])) && ($data['minimized']=='yes') ) {
            $class .= ' super-minimized';
        }else{
            unset($data['minimized']);
        }
        
        if(!empty($data['align_elements'])){
            $class .= ' super-builder-align-inner-elements-' . $data['align_elements'];
        }

        $result = '';
        
        // If we are updating a TAB element, we will send back a json string with all the content
        // Then on the JS side we will generate the HTML
        // Be aware that this is completely a different method/way then from the other elements
        // This is required because TAB element can have different layouts
        if($builder!==false){
            if( empty($data) ) $data = null;
            if( empty($inner) ) $inner = null;
            $i18n = (isset($_POST['i18n']) ? $_POST['i18n'] : '');
            $result .= self::output_element_html( $tag, $group, $data, $inner, $shortcodes, $settings, $i18n, $builder );
            return $result;
        }

        $result .= '<div class="super-element' . $class . '" data-shortcode-tag="' . $tag . '" data-group="'.$group.'" data-minimized="' . ( !empty($data['minimized']) ? 'yes' : 'no' ) . '" ' . ( $tag=='column' ? 'data-size="' . $data['size'] . '"' : '' ) . '>';
            $result .= '<div class="super-element-header">';
                if( ($tag=='column') || ($tag=='multipart') ){
                    $result .= '<div class="super-element-label">';
                    if(empty($data['label'])){
                        $label = $name;
                    }else{
                        $label = $data['label'];
                    } 
                    $result .= '<span>'.$label.'</span>';
                    $result .= '<input type="text" value="'.esc_attr($label).'" />';
                    $result .= '</div>';
                }
                if($tag=='column'){
                    $result .= '<div class="super-resize super-tooltip" data-content="Change Column Size">';
                        $result .= '<span class="smaller"><i class="fas fa-angle-left"></i></span>';
                        $result .= '<span class="current">' . $data['size'] . '</span><span class="bigger"><i class="fas fa-angle-right"></i></span>';
                    $result .= '</div>';
                }else{
                    $result .= '<div class="super-title">';
                    $result .= $name;
                    if( ($tag!='button') && ($tag!='button') && (isset($data['name'])) ) {
                        $result .= ' <input class="super-tooltip" title="Unique field name" type="text" value="' . esc_attr($data['name']) . '" autocomplete="false" />';
                    }
                    $result .= '</div>';
                }
                $result .= '<div class="super-element-actions">';
                    $result .= '<span class="super-edit super-tooltip" title="' . esc_html__( 'Edit element', 'super-forms' ) . '"><i class="fas fa-pencil-alt"></i></span>';
                    $result .= '<span class="super-duplicate super-tooltip" title="' . esc_html__( 'Duplicate element', 'super-forms' ) . '"><i class="fas fa-copy"></i></span>';
                    $result .= '<span class="super-move super-tooltip" title="' . esc_html__( 'Reposition element', 'super-forms' ) . '"><i class="fas fa-arrows-alt"></i></span>';
                    $result .= '<span class="super-transfer super-tooltip" title="' . esc_html__( 'Transfer this element (also works across forms)', 'super-forms' ) . '"><i class="fas fa-exchange-alt"></i></span>';
                    $result .= '<span class="super-transfer-drop super-tooltip" title="' . esc_html__( 'Transfer after this element', 'super-forms' ) . '"><i class="fas fa-arrow-circle-down"></i></span>';
                    $result .= '<span class="super-minimize super-tooltip" title="' . esc_html__( 'Minimize', 'super-forms' ) . '"><i class="fas fa-minus-square"></i></span>';
                    $result .= '<span class="super-delete super-tooltip" title="' . esc_html__( 'Delete', 'super-forms' ) . '"><i class="fas fa-times"></i></span>';
                $result .= '</div>';
            $result .= '</div>';
            
            // Check if this is a TAB element
            // TAB elements require a special loop because they have multiple "inner" objects
            if($tag=='tabs'){
                $result .= '<div class="super-element-inner">';
                    if( empty($data) ) $data = null;
                    if( empty($inner) ) $inner = null;
                    $i18n = (isset($_POST['i18n']) ? $_POST['i18n'] : '');
                    $result .= self::output_element_html( $tag, $group, $data, $inner, $shortcodes, $settings, $i18n, true );
                $result .= '</div>';
            }else{
                $result .= '<div class="super-element-inner' . $inner_class . '">';
                    if( ( $tag!='column' ) && ( $tag!='multipart' ) ) {
                        if( empty($data) ) $data = null;
                        if( empty($inner) ) $inner = null;
                        $i18n = (isset($_POST['i18n']) ? $_POST['i18n'] : '');
                        $result .= self::output_element_html( $tag, $group, $data, $inner, $shortcodes, $settings, $i18n, false );
                    }
                    if( !empty( $inner ) ) {
                        foreach( $inner as $k => $v ) {
                            if( empty($v['data'] ) ) $v['data'] = null;
                            if( empty($v['inner'] ) ) $v['inner'] = null;
                            $result .= self::output_builder_html( $v['tag'], $v['group'], $v['data'], $v['inner'], $shortcodes, $settings );
                        }
                    }
                $result .= '</div>';
            }
            $result .= '<textarea name="element-data">' . htmlentities( json_encode( $data ), ENT_NOQUOTES | ENT_SUBSTITUTE | ENT_DISALLOWED ) . '</textarea>';
        $result .= '</div>';
        
        return $result;
        
    }


    public static function opening_tag( $tag, $atts, $class='', $styles='') {
        $style = '';
        if($tag=='divider') $atts['width'] = 0;
        if($tag!='image'){
            if( !isset( $atts['width'] ) ) $atts['width'] = 0;
            if( $atts['width']!=0 ) $style .= 'width:' . $atts['width'] . 'px;';
        }
        if( !empty( $atts['tooltip'] ) ) {
            wp_enqueue_style( 'tooltips', SUPER_PLUGIN_FILE.'assets/css/backend/tooltips.css', array(), SUPER_VERSION );    
            wp_enqueue_script( 'tooltips', SUPER_PLUGIN_FILE.'assets/js/backend/tooltips.js', array( 'jquery' ), SUPER_VERSION, false );   
        }
        $result = '<div';
        if( ( $style!='' ) || ( $styles!='' ) ) $result .= ' style="' . $style . $styles . '"';
        $result .= ' class="super-shortcode super-field super-' . $tag;
        if( !empty($atts['label'])  && (!empty($atts['description'])) ) {
            $result .= ' super-has-label-desc';
        }
        $result .= ' ' . (!empty($atts['icon']) ? ' super-icon-' . $atts['icon_position'] . ' super-icon-' . $atts['icon_align'] : '');
        if(!empty($atts['value'])) $result .= ' super-filled';
        $align = '';
        if( isset( $atts['align'] ) ) $align = ' super-align-' . $atts['align'];
        $result .= $align;

        if( !empty( $atts['tooltip'] ) ) $result .= ' super-tooltip';
        if( !isset( $atts['error_position'] ) ) $atts['error_position'] = '';
        $result .= ' ' . $atts['error_position'];
        if( !isset( $atts['grouped'] ) ) $atts['grouped'] = 0;
        if($atts['grouped']==0) $result .= ' super-ungrouped ';
        if($atts['grouped']==1) $result .= ' super-grouped ';
        if($atts['grouped']==2) $result .= ' super-grouped super-grouped-end ';

        // If default value contains {tags} we will replace them on page load via javascript
        if(!empty($atts['value'])){
            $regex = '/\{(.*?)\}/';
            preg_match_all($regex, $atts['value'], $matches, PREG_SET_ORDER, 0);
            if(count($matches)>0){
                $class .= ' super-replace-tags';
            }
        }
        
        if( $tag!='hidden' ) {
            $conditionAttributes = self::conditional_attributes( $atts );
            $class .= $conditionAttributes['class'];
        }

        // @since 1.9 - custom wrapper class
        if($tag=='spacer'){
            if( !isset( $atts['class'] ) ) $atts['class'] = '';     
            $result .= ' ' . $class . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"';
        }else{
            if( !isset( $atts['wrapper_class'] ) ) $atts['wrapper_class'] = '';     
            $result .= ' ' . $class . ($atts['wrapper_class']!='' ? ' ' . $atts['wrapper_class'] : '') . '"';
        }

        if( !empty( $atts['tooltip'] ) ) $result .= ' title="' . esc_attr( stripslashes( $atts['tooltip'] ) ) . '"';
        if( $tag=='text' || $tag=='hidden' ) {
            $result .= self::conditional_variable_attributes( $atts );
        }
        if( $tag!='hidden' ) {
            $result .= $conditionAttributes['dataset']; 
        }

        // @since 3.2.0 - custom TAB index
        if( (isset($atts['custom_tab_index'])) && ($atts['custom_tab_index']>=0) ) {
            $result .= ' data-super-custom-tab-index="' . absint($atts['custom_tab_index']) . '"';   
        }
        $result .= self::pdf_attributes($atts);
        $result .= '>';
        if( !empty($atts['label']) ) {
            $bottom_margin = false;
            if( empty($atts['description']) ) {
                $bottom_margin = true;
            }
            $result .= self::field_label( $atts['label'], $bottom_margin );
        }
        if( !empty($atts['description']) ) {
            $result .= self::field_description( $atts['description'] );
        }

        // Display errors that need to be positioned below the field
        $result .= self::field_error_msg( $tag, $atts, 'top' );
        return $result;
    }

    public static function pdf_attributes( $atts ) {
        $result = '';
        // PDF option
        if( (isset($atts['pdfOption'])) && ($atts['pdfOption']>=0) ) {
            if($atts['pdfOption']!=='none') $result .= ' data-pdfOption="' . esc_attr($atts['pdfOption']) . '"';   
        }
        return $result;
    }
    public static function conditional_attributes( $atts ) {
        if( !isset( $atts['conditional_action'] ) ) $atts['conditional_action'] = 'disabled';
        if( !isset( $atts['conditional_trigger'] ) ) $atts['conditional_trigger'] = 'all';
        if( $atts['conditional_action']!='disabled' ) {
            $class = ' super-conditional-visible';
            if($atts['conditional_action']==='show'){
                $class = ' super-conditional-hidden';
            }
            return array( 'class' => $class, 'dataset' => ' data-conditional-action="' . $atts['conditional_action'] . '" data-conditional-trigger="' . $atts['conditional_trigger'] . '"');
        }
        return array('class'=>'', 'dataset'=>'');
    }
    public static function conditional_variable_attributes( $atts ) {
        if( !isset( $atts['conditional_variable_action'] ) ) $atts['conditional_variable_action'] = 'disabled';
        if( $atts['conditional_variable_action']!='disabled' ) {
            return ' data-conditional-variable-action="' . $atts['conditional_variable_action'] . '"';
        }
    }
    public static function field_label( $label, $bottom_margin ) {
        $class = '';
        if( $bottom_margin==true ) $class = ' super-bottom-margin';
        return '<div class="super-label' . $class . '">' . stripslashes($label) . '</div>';
    }
    public static function field_description( $description ) {
        return '<div class="super-description">' . stripslashes($description) . '</div>';
    }
    public static function field_error_msg( $tag, $atts, $position ) {
        // Do not render error message for non fields (those that do not have a name)
        if(!isset($atts['name'])) return '';
        if($tag=='column' || $tag=='multipart') return '';
        
        if(empty($atts['error'])) {
            $atts['error'] = esc_html__( 'Field is required!', 'super-forms' );
        }
        if(empty($atts['emptyError'])) { // if empty fall back to the validation error message
            $atts['emptyError'] = $atts['error'];
        }
        if( empty( $atts['error_position'] ) ) $atts['error_position'] = 'bottom-right';
        if($position=='top'){
            if($atts['error_position']=='top-left' || $atts['error_position']=='top-right'){
                return '<div class="super-error-msg">' . stripslashes($atts['error']) . '</div><div class="super-empty-error-msg">' . stripslashes($atts['emptyError']) . '</div>';
            }
        }
        if($position=='bottom'){
            if($atts['error_position']=='bottom-left' || $atts['error_position']=='bottom-right'){
                return '<div class="super-error-msg">' . stripslashes($atts['error']) . '</div><div class="super-empty-error-msg">' . stripslashes($atts['emptyError']) . '</div>';
            }
        }
    }   
    public static function opening_wrapper( $atts=array(), $inner=array(), $shortcodes=null, $settings=null, $wrapper_class=null ) {
        if( !isset( $atts['icon'] ) ) $atts['icon'] = '';
        if( !isset( $atts['icon_position'] ) ) $atts['icon_position'] = 'outside';
        if( !isset( $atts['icon_align'] ) ) $atts['icon_align'] = 'left';
        if( !isset( $atts['wrapper_width'] ) ) $atts['wrapper_width'] = '';
        $style = '';
        if( !isset( $atts['wrapper_width'] ) ) $atts['wrapper_width'] = 0;
        if( $atts['wrapper_width']!=0 ) {
            $style = 'width:' . $atts['wrapper_width'] . 'px;';
        }
        if( !empty( $style ) ) {
            $style = ' style="' . $style . '"';
        }
        if( ( isset( $settings['theme_hide_icons'] ) ) && ( $settings['theme_hide_icons']=='yes' ) ) {
            $atts['icon'] = '';
        }

        $result = '<div' . $style . ' class="super-field-wrapper ' . $wrapper_class . '">';
        if($atts['icon']!=''){
            $icon_tag = explode(' ', $atts['icon']);
            if(isset($icon_tag[1])){
                $icon_type = $icon_tag[0];
                $icon_tag = str_replace('fa-', '', $icon_tag[1]);
            }else{
                $default = explode(';', $atts['icon']);
                $icon_tag = $default[0];
                $icon_type = 'fas';
                if(isset($default[1])){
                    $icon_type = $default[1]; // use the existing type
                }
            }
            if( (empty($atts['display'])) || (!empty($atts['display']) && $atts['display']!='slider') ){
                $result .= '<i class="' . $icon_type . ' fa-'.SUPER_Common::fontawesome_bwc($icon_tag).' super-icon"></i>';
            }
        }
        return $result;
    }
    public static function common_attributes( $atts, $tag, $settings = array() ) {
        
        if( !isset( $atts['error'] ) ) $atts['error'] = '';
        if( !isset( $atts['validation'] ) ) $atts['validation'] = '';
        if( !isset( $atts['conditional_validation'] ) ) $atts['conditional_validation'] = '';
        if( !isset( $atts['conditional_validation_value'] ) ) $atts['conditional_validation_value'] = '';
        if( !isset( $atts['conditional_validation_value2'] ) ) $atts['conditional_validation_value2'] = ''; // @since 3.6.0
        if( !isset( $atts['may_be_empty'] ) ) $atts['may_be_empty'] = 'false';
        if( !isset( $atts['email'] ) ) $atts['email'] = '';
        if( !isset( $atts['exclude'] ) ) $atts['exclude'] = 0;
        if( !isset( $atts['replace_commas'] ) ) $atts['replace_commas'] = '';
        if( !isset( $atts['exclude_entry'] ) ) $atts['exclude_entry'] = '';
        if( !isset( $atts['maxlength'] ) ) $atts['maxlength'] = 0;
        if( !isset( $atts['minlength'] ) ) $atts['minlength'] = 0;

        // @since 2.6.0 - IBAN validation
        if( $atts['validation']=='iban' ) {
            wp_enqueue_script( 'iban-check', SUPER_PLUGIN_FILE . 'assets/js/frontend/iban-check.js', array( 'jquery' ), SUPER_VERSION, false );
        }

        $data_attributes = array(
            'message' => $atts['error'],
            'validation' => $atts['validation'],
            'may-be-empty' => $atts['may_be_empty'],
            'conditional-validation' => $atts['conditional_validation'],
            'conditional-validation-value' => $atts['conditional_validation_value'],
            'conditional-validation-value2' => $atts['conditional_validation_value2'], // @since 3.6.0
            'email' => $atts['email'],
            'exclude' => $atts['exclude'],
            'replace-commas' => $atts['replace_commas'],
            'exclude-entry' => $atts['exclude_entry']
        );
        if( $atts['validation']=='none' ) unset($data_attributes['validation']);
        if( $atts['may_be_empty']=='false' ) unset($data_attributes['may-be-empty']);
        if( $atts['conditional_validation']=='none' ) unset($data_attributes['conditional-validation']);

        $result = '';
        foreach($data_attributes as $k => $v){
            if($v!=''){
                $result .= ' data-' . $k . '="' . $v . '"';
            }
        }
        
        // @since 4.7.7 - absolute default value based on settings
        if( isset($atts['absolute_default']) ) {
            $result .= ' data-absolute-default="' . esc_attr(SUPER_Common::email_tags( $atts['absolute_default'], null, $settings )) . '"';
        }

        
        // @since 2.0.0 - default value data attribute needed for Clear button
        if( isset($atts['value']) ) $result .= ' data-default-value="' . esc_attr($atts['value']) . '"';

        // @since 1.2.2
        if( !empty( $atts['disabled'] ) ) $result .= ' disabled="' . esc_attr($atts['disabled']) . '"';

        // @since 3.6.0
        if( !empty( $atts['readonly'] ) ) $result .= ' readonly="true"';

        // @since 3.6.0 - disable field autocompletion
        if( !empty($atts['autocomplete']) ) $result .= ' autocomplete="false"';

        // @since 4.9.3 - Adaptive Placeholders
        // If adaptive placeholders is enabled, we will not want to use the default placeholders
        if(!isset($settings['enable_adaptive_placeholders'])) $settings['enable_adaptive_placeholders'] = '';
        // Do not use Adaptive placeholder for minimal theme
        if(!empty($settings['theme_style']) && $settings['theme_style']=='super-style-one') $settings['enable_adaptive_placeholders'] = '';
        if( (empty($settings['enable_adaptive_placeholders'])) ) {
            if( !empty( $atts['default_placeholder'] ) ) {
                $result .= ' placeholder="' . esc_attr($atts['default_placeholder']) . '"';
            }else{
                if( !empty( $atts['placeholder'] ) ) {
                    $result .= ' placeholder="' . esc_attr($atts['placeholder']) . '"';
                }
            }
        }
        if($tag=='file'){
            if( $atts['minlength']>0 ) {
                $result .= ' data-minfiles="' . esc_attr($atts['minlength']) . '"';
            }
            if( $atts['maxlength']>0 ) {
                $result .= ' data-maxfiles="' . esc_attr($atts['maxlength']) . '"';
            }
        }elseif( $tag=='product' ) {
            if( $atts['maxlength']>0 ) {
                $result .= ' max="' . esc_attr($atts['maxlength']) . '" data-maxlength="' . esc_attr($atts['maxlength']) . '"';
            }
            $result .= ' min="' . esc_attr($atts['minlength']) . '" data-minlength="' . esc_attr($atts['minlength']) . '"';
        }elseif( ($tag=='dropdown') || ($tag=='checkbox') || ($tag=='radio') ) {    
            // @since 1.2.7
            if( !empty($atts['admin_email_value']) && $atts['admin_email_value']!='value' ) {
                $result .= ' data-admin-email-value="' . esc_attr($atts['admin_email_value']) . '"';
            }
            if( !empty($atts['confirm_email_value']) && $atts['confirm_email_value']!='value' ) {
                $result .= ' data-confirm-email-value="' . esc_attr($atts['confirm_email_value']) . '"';
            }

            // @since 1.2.9
            if( !empty($atts['contact_entry_value']) && $atts['contact_entry_value']!='value' ) {
                $result .= ' data-contact-entry-value="' . esc_attr($atts['contact_entry_value']) . '"';
            }

            if( ($tag=='dropdown') || ($tag=='checkbox') ) {
                // @since 2.0.0
                if( $atts['maxlength']>0 ) {
                    $result .= ' data-maxlength="' . esc_attr($atts['maxlength']) . '"';
                }
                if( $atts['minlength']>0 ) {
                    $result .= ' data-minlength="' . esc_attr($atts['minlength']) . '"';
                }
            }

        }else{
            if($tag=='date' || $tag=='time'){
                if( $atts['maxlength']!='' ) {
                    $result .= ' data-maxlength="' . esc_attr($atts['maxlength']) . '"';
                }
                if( $atts['minlength']!='' ) {
                    $result .= ' data-minlength="' . esc_attr($atts['minlength']) . '"';
                }
            }else{
                if( $tag=='text' ) {
                    // @since   1.3   - predefined input mask e.g: (___) ___-____
                    if( !empty($atts['mask']) ) {
                        wp_enqueue_script( 'super-masked-input', SUPER_PLUGIN_FILE . 'assets/js/frontend/masked-input.js', array( 'jquery' ), SUPER_VERSION, false );
                        $result .= ' data-mask="' . esc_attr($atts['mask']) . '"';
                    }
                    if( $atts['maxlength']>0 ) {
                        // For keyword field we do not want to set maxlength
                        if(!empty($atts['enable_keywords']) && $atts['enable_keywords']!='true'){
                            $result .= ' maxlength="' . esc_attr($atts['maxlength']) . '"';
                        }
                    }
                }
                if( $atts['maxlength']>0 ) {
                    $result .= ' data-maxlength="' . esc_attr($atts['maxlength']) . '"';
                }
                if( $atts['minlength']>0 ) {
                    $result .= ' data-minlength="' . esc_attr($atts['minlength']) . '"';
                }
            }

            if( !isset($atts['maxnumber'])) $atts['maxnumber'] = 0;
            if( !isset($atts['minnumber'])) $atts['minnumber'] = 0;
            if($atts['maxnumber']!=0 || $atts['minnumber']!=0){
                if( isset($atts['minnumber']) ) {
                    $result .= ' data-minnumber="' . esc_attr($atts['minnumber']) . '"';
                    if(isset($atts['type']) && $atts['type'] == 'number') {
                        $result .= ' min="' . esc_attr($atts['minnumber']) . '"';
                    }
                }
                if( (isset($atts['maxnumber'])) && ($atts['maxnumber'] > $atts['minnumber']) ) {
                    $result .= ' data-maxnumber="' . esc_attr($atts['maxnumber']) . '"';
                    if(isset($atts['type']) && $atts['type'] == 'number') {
                        $result .= ' max="' . esc_attr($atts['maxnumber']) . '"';
                    }
                }
            }
        }

        // @since 1.2.7     - super_common_attributes_filter
        return apply_filters( 'super_common_attributes_filter', $result, array( 'atts'=>$atts, 'tag'=>$tag ) );

    }

    // @since 4.9.3 - Adaptive Placeholders
    public static function adaptivePlaceholders( $settings, $atts, $tag ) {
        if($settings['theme_style']=='super-style-one') $settings['enable_adaptive_placeholders'] = '';
        if( (!empty($settings['enable_adaptive_placeholders'])) && (!empty($atts['placeholder'])) ) {
            if(empty($atts['placeholderFilled'])) $atts['placeholderFilled'] = $atts['placeholder'];
            $html = '<span class="super-adaptive-placeholder' . (!empty($settings['placeholder_adaptive_positioning']) ? ' super-adaptive-positioning' : '') . '" data-placeholder="' . esc_attr($atts['placeholder']) . '" data-placeholderFilled="' . esc_attr($atts['placeholderFilled']) . '">';
            $html .= '<span>' . $atts['placeholder'] . '</span>';
            $html .= '</span>';
            return $html;
        } 
    }

    // @since 1.2.5     - custom regex validation
    public static function custom_regex( $regex ) {
        if( !empty($regex) ) return '<textarea disabled class="super-custom-regex">' . $regex . '</textarea>';
    }

    public static function loop_conditions( $atts, $tag ) {

        $result = '';

        // @since 4.9.0 - Validate field only if condition is met
        if( (!empty($atts['may_be_empty'])) && ($atts['may_be_empty']=='conditions') ) {
            $field_names = array();
            if(is_array($atts['may_be_empty_conditions'])){
                foreach( $atts['may_be_empty_conditions'] as $k => $v ) {
                    if( !empty($v['field']) ) {
                        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['field'], true);
                        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['value']);
                    }
                    if( !empty($v['and_method']) && !empty($v['field_and']) ) {
                        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['field_and'], true);
                        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['value_and']);
                    }
                }

                $dataFields = '';
                if(!empty($field_names)) $dataFields = ' data-fields="{' . implode('}{', $field_names) . '}"';
                $result .= '<textarea class="super-validate-conditions"' . ($dataFields ? $dataFields : '') . '>' . json_encode($atts['may_be_empty_conditions']) . '</textarea>';
            }
        }

        if( !isset( $atts['conditional_action'] ) ) $atts['conditional_action'] = 'disabled';
        if( !isset( $atts['conditional_items'] ) ) $atts['conditional_items'] = '';
        if( ( $atts['conditional_items']!=null ) && ( $atts['conditional_action']!='disabled' ) ) {
            // @since 4.2.0 - filter hook to change conditional items on the fly for specific element
            if( !empty($atts['name']) ) {
                $atts['conditional_items'] = apply_filters( 'super_conditional_items_' . $atts['name'] . '_filter', $atts['conditional_items'], array( 'atts'=>$atts ) );
            }
            // @since 2.3.0 - speed improvement for conditional logics
            // append the field names ad attribute that the conditions being applied to, so we can filter on it on field change with javascript
            $field_names = array();
            foreach( $atts['conditional_items'] as $k => $v ) {
                // @since 3.5.0 - also check if variable field contains tags and if so, update the correct values
                if( !empty($v['field']) ) {
                    $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['field'], true);
                    $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['value']);
                }
                if( !empty($v['and_method']) && !empty($v['field_and']) ) {
                    $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['field_and'], true);
                    $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['value_and']);
                }
            }
            // @since 1.7 - use json instead of HTML for speed improvements
            $dataFields = '';
            if(!empty($field_names)) $dataFields = ' data-fields="{' . implode('}{', $field_names) . '}"';
            $result .= '<textarea class="super-conditional-logic"' . ($dataFields ? $dataFields : '') . '>' . json_encode($atts['conditional_items']) . '</textarea>';
        }

        // Display errors that need to be positioned below the field
        $result .= self::field_error_msg( $tag, $atts, 'bottom' );

        return $result;
    }
    
    // @since 1.2.7    - variable conditions
    public static function loop_variable_conditions( $atts ) {
        if( !isset( $atts['conditional_variable_action'] ) ) $atts['conditional_variable_action'] = 'disabled';
        if( $atts['conditional_variable_action']!='disabled' ) {
            if( !isset( $atts['conditional_items'] ) ) $atts['conditional_items'] = '';
            // Backwards compatibility to make sure old variable fields will keep working correctly.
            if( !empty( $atts['conditional_variable_items'] ) ) $atts['conditional_items'] = $atts['conditional_variable_items'];

            // @since 4.2.0 - variable conditions based on CSV file
            if( (!empty($atts['conditional_variable_method'])) && ($atts['conditional_variable_method']=='csv') ) {
                $delimiter = ',';
                $enclosure = '"';
                if( !empty( $atts['conditional_variable_delimiter'] ) ) $delimiter = $atts['conditional_variable_delimiter'];
                if( !empty( $atts['conditional_variable_enclosure'] ) ) $enclosure = stripslashes($atts['conditional_variable_enclosure']);
                if(strlen($delimiter)!==1) $delimiter = ',';
                if(strlen($enclosure)!==1) $enclosure = '"';
                $file = get_attached_file($atts['conditional_variable_csv']);
                $rows = array();
                $conditions = array();
                if( $file ) {
                    $row = 0;
                    if( (!empty($file)) && (($handle = fopen($file, "r")) !== FALSE) ) {
                        // Progress file pointer and get first 3 characters to compare to the BOM string.
                        $bom = "\xef\xbb\xbf"; // BOM as a string for comparison.
                        if (fgets($handle, 4) !== $bom) rewind($handle); // BOM not found - rewind pointer to start of file.
                        while (($data = fgetcsv($handle, 10000, $delimiter, $enclosure)) !== FALSE) {
                            $rows[] = $data;
                        }
                        fclose($handle);
                        $columns = $rows[0];
                        foreach( $rows as $k => $v ) {
                            if( $k==0 ) continue;
                            foreach( $v as $kk => $vv ) {
                                if( $kk==0 ) continue;
                                $conditions[] = array(
                                    'field' => $atts['conditional_variable_row'],
                                    'logic' => $atts['conditional_variable_logic'], //'greater_than_or_equal',
                                    'value' => $v[0],
                                    'and_method' => $atts['conditional_variable_and_method'], //'and',
                                    'field_and' => $atts['conditional_variable_col'],
                                    'logic_and' => $atts['conditional_variable_logic_and'], //'greater_than_or_equal',
                                    'value_and' => (isset($columns[$kk]) ? $columns[$kk] : ''),
                                    'new_value' => $vv
                                );
                            }
                        }
                        
                    }
                }
                $atts['conditional_items'] = $conditions;
            }

            if( $atts['conditional_items']!=null ) {
                // @since 4.2.0 - filter hook to change variable conditions on the fly for specific field
                if( !empty($atts['name']) ) {
                    $atts['conditional_items'] = apply_filters( 'super_variable_conditions_' . $atts['name'] . '_filter', $atts['conditional_items'], array( 'atts'=>$atts ) );
                }
                // @since 2.3.0 - speed improvement for variable field
                // append the field names ad attribute that the conditions being applied to, so we can filter on it on field change with javascript
                $field_names = array();
                foreach( $atts['conditional_items'] as $k => $v ) {
                    if( !empty($v['field']) ) {
                        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['field'], true);
                        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['value']);
                    }
                    if( !empty($v['and_method']) && !empty($v['field_and']) ) {
                        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['field_and'], true);
                        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['value_and']);
                    }
                    if( !empty($v['new_value']) ) {
                        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $v['new_value']);
                    }
                }
                // @since 1.7 - use json instead of HTML for speed improvements
                $dataFields = '';
                if(!empty($field_names)) $dataFields = ' data-fields="{' . implode('}{', $field_names) . '}"';
                return '<textarea class="super-variable-conditions"' . ($dataFields ? $dataFields : '') . '>' . json_encode($atts['conditional_items']) . '</textarea>';
            }
        }
    }


    public static function generate_element_stylesheet($group, $tag, $identifier, $atts, $shortcodes){
        $styles = '';
        $id = '#super-id-'.$identifier;
        if($shortcodes==false) $shortcodes = SUPER_Shortcodes::shortcodes();
        // Loop over all settings, and check if it needs to be added as a style
        // Loop over all possible tab settings, e.g: General, Styles etc.
        foreach($shortcodes[$group]['shortcodes'][$tag]['atts'] as $k => $v){
            // First check if 'fields' key exists
            if(isset($v['fields'])){
                // Loop over all fields, and look for 'selector' key
                foreach($v['fields'] as $fk => $fv){
                    if(empty($atts[$fk])) continue; // If value is 0 or empty we do not add the style
                    $styles .= self::loop_over_fields_to_generate_styles($id, $fk, $fv, $atts);
                }
            }else{
                // Dealing with subtabs
                // Loop over all subtabs, then look for 'selector' key
                unset($v['name']); // remove 'name' key
                foreach($v as $stk => $stv){
                    foreach($stv['fields'] as $fk => $fv){
                        if(empty($atts[$fk])) continue; // If value is 0 or empty we do not add the style
                        $styles .= self::loop_over_fields_to_generate_styles($id, $fk, $fv, $atts);
                    }
                }
            }
        }
        if(empty($styles)) return '';
        return '<style id="style-super-id-'.$identifier.'">'.$styles.'</style>';
    }
    public static function loop_over_fields_to_generate_styles($id, $fk, $fv, $atts){
        $styles = '';
        if(isset($fv['_styles'])){
            $value = $atts[$fk];
            foreach($fv['_styles'] as $sk => $sv){
                // Check if property contains a comma, if so we must add this style for all the properties specified
                $properties = explode(',', $sv);
                foreach($properties as $pv){
                    // Convert to proper justify-content
                    if($pv=='justify-content'){
                        if($value=='left') $value = 'flex-start';
                        if($value=='center') $value = 'center';
                        if($value=='right') $value = 'flex-end';
                    }
                    // Append "px" if needed
                    $suffix = '';
                    // In some cases we need to add "px", for instance with font size and line-height
                    if( ($pv=='font-size') || ($pv=='line-height') || (strpos($pv, 'margin-')) || (strpos($pv, '-radius')) || (strpos($pv, '-width')) ) {
                        $suffix = 'px';
                        $value = str_replace('px', '', $value); // Remove px from value if it contains any
                    }
                    $value = $value.$suffix;
                    $styles .= $id.$sk.' {';
                        $styles .= $pv . ': ' . str_replace(';', '', $value) . '!important;';
                    $styles .= '}';
                } 
            }
        }
        return $styles;
    }
    public static function tabs( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null, $dynamic=0, $dynamic_field_names=array(), $inner_field_names=array(), $formProgress=false ) {
        $group = 'layout_elements';
        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, $group, $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation
        $result  = '';
        $layout = $atts['layout']; // possible values: tabs, accordion, list
        $location = (!empty($atts['tab_location']) ? ' super-' . $atts['tab_location'] : ' super-horizontal');
        $prev_next = (!empty($atts['tab_show_prev_next']) ? ' super-prev-next' : '');

        // Add stylesheets specific to this element
        $identifier = str_replace('.', '', microtime(true)).rand(1000000,9999999);
        $result .= self::generate_element_stylesheet($group, $tag, $identifier, $atts, $shortcodes);

        $result .= '<div id="super-id-'.$identifier.'" class="super-shortcode super-' . $tag . ' super-layout-' . $atts['layout'] . $location . $prev_next . (!empty($atts['class']) ? ' ' . $atts['class'] : '') . '"';
        $result .= self::pdf_attributes($atts);
        $result .= '>';
            // For each layout we need to generate a custom set of html
            if($layout=='tabs'){
                // Generate Tab layout
                // First generate the TAB menu (here will users click on to switch to a different TAB)
                $result .= '<div class="super-tabs-menu' . ($atts['tab_class']!='' ? ' ' . $atts['tab_class'] : '') . '">';
                $tab_html = '';
                foreach( $atts['items'] as $k => $v ) {
                    // First check if this TAB item has an image or not
                    $class = '';
                    $image = null;
                    if( !isset( $v['image'] ) ) $v['image'] = '';
                    if( $v['image']!='' ) {
                        $image = wp_get_attachment_image_src( $v['image'], 'original' );
                        $image = !empty( $image[0] ) ? $image[0] : '';
                        $class = ' super-has-image';
                    }
                    // Generate single TAB
                    // Make sure that the first TAB is active by default on page load
                    $tab_html .= '<div class="super-tabs-tab' . ($k==0 ? ' super-active' : '') . ( !empty($class) ? ' ' . $class : '') . '">';
                        if( !empty( $image ) ) {
                            if( empty( $v['max_width'] ) ) $v['max_width'] = 50;
                            if( empty( $v['max_height'] ) ) $v['max_height'] = 50;
                            $img_styles = '';
                            if( $v['max_width']!='' ) $img_styles .= 'max-width:' . $v['max_width'] . 'px;';
                            if( $v['max_height']!='' ) $img_styles .= 'max-height:' . $v['max_height'] . 'px;';
                            $tab_html .= '<div class="super-tab-image"><img src="' . esc_url($image) . '"' . ($img_styles!='' ? ' style="' . $img_styles . '"' : '') . '></div>';
                        }
                        $tab_html .= '<div class="super-tab-title">' . $v['title'] . '</div>';
                        $tab_html .= '<div class="super-tab-desc">' . $v['desc'] . '</div>';
                        $tab_html .= '<span class="super-tab-prev"></span>';
                        $tab_html .= '<span class="super-tab-next"></span>';
                    $tab_html .= '</div>';
                }
                
                // If the only thing that we need to do is update the TABS in the back-end (builder page)
                // Then send a json string back to the JS create-form.js
                // This will then update the TABS html, and also remove or add missing TAB content
                if($builder!==false && is_array($builder)){
                    $from = $builder[0];
                    $to = $builder[1];
                    // From TABS to TABS layout (no change)
                    // We will just want to update the TAB menu here
                    if($from=='tabs' && $to=='tabs'){
                        // Generate the TAB html
                        $json = array(
                            'tag' => $tag,
                            'builder' => $builder,
                            'html' => $tab_html
                        );
                        return json_encode($json);
                    }
                }
                
                $result .= $tab_html;
                $result .= '</div>';
                // End of TAB menu

                // Now generate the actual TAB content (with their inner elements)
                $result .= '<div class="super-tabs-contents' . ($atts['content_class']!='' ? ' ' . $atts['content_class'] : '') . '">';
                foreach( $atts['items'] as $k => $v ) {
                    if(empty($inner)) $inner = null;
                    if(empty($inner[$k])) $inner[$k] = null;
                    $tab_inner = $inner[$k];
                    // Generate single TAB content
                    // Make sure that the first TAB is active by default on page load
                    $result .= '<div class="super-tabs-content' . ($k==0 ? ' super-active' : '') . '">';
                        $result .= '<div class="super-padding">';
                            if($builder) $result .= '<div class="super-element-inner super-dropable">';
                            if( !empty($tab_inner) ) {
                                // Loop through inner elements
                                foreach($tab_inner as $ik => $iv){
                                    if( !empty($iv['data']['name']) ) {
                                        $inner_field_names[$iv['data']['name']] = array(
                                            'name' => (isset($iv['data']['name']) ? $iv['data']['name'] : 'undefined'), // Field name
                                            'email' => (isset($iv['data']['email']) ? $iv['data']['email'] : '') // Email label
                                        );
                                    }
                                }
                                // First check how many columns there are
                                // This way we can correctly close the column system
                                $initialColumnsFound = (empty($GLOBALS['super_column_found']) ? 0 : $GLOBALS['super_column_found']);
                                $GLOBALS['super_column_found'] = 0;
                                foreach( $tab_inner as $iv ) {
                                    if( $iv['tag']=='column' ) $GLOBALS['super_column_found']++;
                                }
                                $re = '/\{(.*?)\}/';
                                $i = $dynamic;
                                foreach( $tab_inner as $iv ) {
                                    if( empty($iv['data']) ) $iv['data'] = null;
                                    if( empty($iv['inner']) ) $iv['inner'] = null;
                                    if($builder){
                                        $result .= self::output_builder_html( $iv['tag'], $iv['group'], $iv['data'], $iv['inner'], $shortcodes, $settings );
                                    }else{
                                        $iv = SUPER_Common::replace_tags_dynamic_columns($iv, $re, $i, $dynamic_field_names, $inner_field_names);
                                        $result .= self::output_element_html( $iv['tag'], $iv['group'], $iv['data'], $iv['inner'], $shortcodes, $settings, $i18n, false, $entry_data, $dynamic, $dynamic_field_names, $inner_field_names, $formProgress );
                                    }
                                }
                                // Restore amount of columns found
                                $GLOBALS['super_column_found'] = $initialColumnsFound;
                            }
                            unset($GLOBALS['super_grid_system']);
                            if($builder) $result .= '</div>';
                        $result .= '</div>';
                    $result .= '</div>';
                }

                    // Prev & Next buttons
                    $result .= '<div class="super-content-prev">';
                        $result .= '<i class="top-line"></i>';
                        $result .= '<i class="bottom-line"></i>';
                    $result .= '</div>';
                    $result .= '<div class="super-content-next">';
                        $result .= '<i class="top-line"></i>';
                        $result .= '<i class="bottom-line"></i>';
                    $result .= '</div>';

                $result .= '</div>';
                // End of TAB contents

            }
            if($layout=='accordion'){
                // If the only thing that we need to do is update the Accordion header in the back-end (builder page)
                // Then send a json string back to the JS create-form.js
                // This will then update the Accordion header items, 
                if($builder!==false && is_array($builder)){
                    $from = $builder[0];
                    $to = $builder[1];
                    $header_items = $atts['items'];
                    // From Accordion to Accordion layout (no change)
                    // We will just want to update the Accordion header items here
                    if($from=='accordion' && $to=='accordion'){
                        // Return the Accordion header items
                        $json = array(
                            'builder' => $builder,
                            'header_items' => $header_items
                        );
                        return json_encode($json);
                    }
                }
                
                // Generate Accordion layout
                foreach( $atts['items'] as $k => $v ) {
                    // First check if this Accordion item has an image or not
                    $class = '';
                    $image = null;
                    if( !isset( $v['image'] ) ) $v['image'] = '';
                    if( $v['image']!='' ) {
                        $image = wp_get_attachment_image_src( $v['image'], 'original' );
                        $image = !empty( $image[0] ) ? $image[0] : '';
                        $class = ' super-has-image';
                    }
                    // Check if item has inner elements
                    if(empty($inner)) $inner = null;
                    if(empty($inner[$k])) $inner[$k] = null;
                    $tab_inner = $inner[$k];
                    // Generate the Accordion item
                    $result .= '<div class="super-accordion-item' . ( !empty($class) ? ' ' . $class : '') . '">';
                        $result .= '<div class="super-accordion-header' . ($atts['tab_class']!='' ? ' ' . $atts['tab_class'] : '') . '">';
                            if( !empty( $image ) ) {
                                if( empty( $v['max_width'] ) ) $v['max_width'] = 50;
                                if( empty( $v['max_height'] ) ) $v['max_height'] = 50;
                                $img_styles = '';
                                if( $v['max_width']!='' ) $img_styles .= 'max-width:' . $v['max_width'] . 'px;';
                                if( $v['max_height']!='' ) $img_styles .= 'max-height:' . $v['max_height'] . 'px;';
                                $result .= '<div class="super-accordion-image"><img src="' . esc_url($image) . '"' . ($img_styles!='' ? ' style="' . $img_styles . '"' : '') . '></div>';
                            }
                            $field_names = SUPER_Common::get_data_fields_attribute(array(), $v['title'], false);
                            $dataFields = '';
                            if(!empty($field_names)) $dataFields = ' data-fields="{' . implode('}{', $field_names) . '}"';
                            $result .= '<div class="super-accordion-title"' . ($dataFields ? $dataFields : '') . ' data-original="' . esc_attr($v['title']) . '">' . esc_html($v['title']) . '</div>';
                            
                            $field_names = SUPER_Common::get_data_fields_attribute(array(), $v['desc'], false);
                            $dataFields = '';
                            if(!empty($field_names)) $dataFields = ' data-fields="{' . implode('}{', $field_names) . '}"';
                            $result .= '<div class="super-accordion-desc"' . ($dataFields ? $dataFields : '') . ' data-original="' . esc_attr($v['desc']) . '">' . esc_html($v['desc']) . '</div>';
                        $result .= '</div>';
                        $result .= '<div class="super-accordion-content' . ($atts['content_class']!='' ? ' ' . $atts['content_class'] : '') . '">';
                            $result .= '<div class="super-padding">';
                                if($builder) $result .= '<div class="super-element-inner super-dropable">';
                                if( !empty($tab_inner) ) {
                                    // Loop through inner elements
                                    foreach($tab_inner as $ik => $iv){
                                        if( !empty($iv['data']['name']) ) {
                                            $inner_field_names[$iv['data']['name']] = array(
                                                'name' => (isset($iv['data']['name']) ? $iv['data']['name'] : 'undefined'), // Field name
                                                'email' => (isset($iv['data']['email']) ? $iv['data']['email'] : '') // Email label
                                            );
                                        }
                                    }
                                    // First check how many columns there are
                                    // This way we can correctly close the column system
                                    $initialColumnsFound = (empty($GLOBALS['super_column_found']) ? 0 : $GLOBALS['super_column_found']);
                                    $GLOBALS['super_column_found'] = 0;
                                    foreach( $tab_inner as $iv ) {
                                        if( $iv['tag']=='column' ) $GLOBALS['super_column_found']++;
                                    }
                                    $re = '/\{(.*?)\}/';
                                    $i = $dynamic;
                                    foreach( $tab_inner as $iv ) {
                                        if( empty($iv['data']) ) $iv['data'] = null;
                                        if( empty($iv['inner']) ) $iv['inner'] = null;
                                        if($builder){
                                            $result .= self::output_builder_html( $iv['tag'], $iv['group'], $iv['data'], $iv['inner'], $shortcodes, $settings );
                                        }else{
                                            $iv = SUPER_Common::replace_tags_dynamic_columns($iv, $re, $i, $dynamic_field_names, $inner_field_names);
                                            $result .= self::output_element_html( $iv['tag'], $iv['group'], $iv['data'], $iv['inner'], $shortcodes, $settings, $i18n, false, $entry_data, $dynamic, $dynamic_field_names, $inner_field_names, $formProgress );
                                        }
                                    }
                                    // Restore amount of columns found
                                    $GLOBALS['super_column_found'] = $initialColumnsFound;
                                }
                                unset($GLOBALS['super_grid_system']);
                                if($builder) $result .= '</div>';
                            $result .= '</div>';
                        $result .= '</div>';
                    $result .= '</div>';
                }
            }
            if($layout=='list'){
                // Generate List layout
                $result .= 'List layout';
            }

        $result .= '</div>';
        return $result;
    }

    /** 
     *  Callback functions for each element to output the HTML
     *
     * @param  string  $tag
     * @param  string  $group
     * @param  array   $data
     *
     *  @since      1.0.0
    */
    public static function multipart( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null, $dynamic=0, $dynamic_field_names=array(), $inner_field_names=array(), $formProgress=false ) {
      
        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'layout_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        // @since 2.6.0 - add active class to the first multipart element
        if( !isset($GLOBALS['super_first_multipart']) ) {
            $GLOBALS['super_first_multipart'] = true;
            $atts['class'] = 'super-active '.$atts['class']; 
        }

        $result  = '';
        $result .= '<div class="super-shortcode super-' . $tag . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '" ' . ($atts['validate']=='true' ? ' data-validate="' . $atts['validate'] . '"' : '') . 'data-step-auto="' . $atts['auto'] .'"';
        
        // @since 4.2.0 - disable scrolling when multi-part contains errors
        if( !empty($atts['disable_scroll']) ) $result .= ' data-disable-scroll="true"';

        // @since 4.3.0 - disable scrolling for multi-part next prev
        if( !empty($atts['disable_scroll_pn']) ) $result .= ' data-disable-scroll-pn="true"';

        // @since 1.2.5
        if( isset( $atts['prev_text'] ) ) $result .= ' data-prev-text="' . $atts['prev_text'] . '"';
        if( isset( $atts['next_text'] ) ) $result .= ' data-next-text="' . $atts['next_text'] . '"';
        
        // @since 3.6.0 - disable autofocus first field
        if( !empty( $atts['autofocus'] ) ) $result .= ' data-disable-autofocus="true"';

        // @since 4.9.0 - display image if set, otherwise the icon if set
        if( !empty($atts['step_image']) ) {
            if( !isset( $atts['step_image'] ) ) $atts['step_image'] = 0;
            $attachment_id = absint($atts['step_image']);
            if( $attachment_id===0 ) {
                $url = SUPER_PLUGIN_FILE . 'assets/images/image-icon.png';
            }else{
                $url = wp_get_attachment_url( $attachment_id );
            } 
            $result .= ' data-image="' . esc_url($url) . '"';
        }else{
            if( !empty($atts['show_icon']) ) {
                $result .= ' data-icon="' . esc_attr($atts['icon']) . '"';
            }
        }
        if( !empty($atts['step_name']) ) {
            $result .= ' data-step-name="' . esc_attr($atts['step_name']) . '"';
        }
        if( !empty($atts['step_description']) ) {
            $result .= ' data-step-description="' . esc_attr($atts['step_description']) . '"';
        }

        $result .= self::pdf_attributes($atts);
        $result .= '>';

        if( !empty( $inner ) ) {
            // Before doing the actuall loop we need to know how many columns this form contains
            // This way we can make sure to correctly close the column system
            $GLOBALS['super_column_found'] = 0;
            foreach( $inner as $k => $v ) {
                if( $v['tag']=='column' ) $GLOBALS['super_column_found']++;
            }
            foreach( $inner as $k => $v ) {
                if( empty($v['data']) ) $v['data'] = null;
                if( empty($v['inner']) ) $v['inner'] = null;
                $result .= self::output_element_html( $v['tag'], $v['group'], $v['data'], $v['inner'], $shortcodes, $settings, $i18n, false, $entry_data, $dynamic=0, $dynamic_field_names=array(), $inner_field_names=array(), $formProgress );
            }
        }
        unset($GLOBALS['super_grid_system']);
        $result .= '</div>';
        return $result;
    }
    public static function column( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null, $dynamic=0, $dynamic_field_names=array(), $inner_field_names=array(), $formProgress ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'layout_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
       
        if($atts['invisible']=='true') $atts['invisible'] = ' super-invisible';
        if(!empty($atts['align_elements'])){
            $atts['align_elements'] = ' super-align-inner-elements-' . $atts['align_elements'];
        }

        // @since   1.3   - background color
        $styles = '';
        if( !isset( $atts['bg_color'] ) ) $atts['bg_color'] = '';
        if( $atts['bg_color']!='' ) {
            
            // @since 1.9    - background opacity
            if( !isset( $atts['bg_opacity'] ) ) $atts['bg_opacity'] = 1;
            
            $styles .= 'background-color:' . SUPER_Common::hex2rgb( $atts['bg_color'], $atts['bg_opacity'] ) . ';';
        }

        // @since   1.9 - custom positioning
        if( !isset( $atts['position'] ) ) $atts['position'] = '';
        if( $atts['position']!='' ) {
            $styles .= 'position:' . $atts['position'] . ';';
            if( !isset( $atts['positioning'] ) ) $atts['positioning'] = '';
            if( !isset( $atts['positioning_top'] ) ) $atts['positioning_top'] = '';
            if( !isset( $atts['positioning_right'] ) ) $atts['positioning_right'] = '';
            if( !isset( $atts['positioning_bottom'] ) ) $atts['positioning_bottom'] = '';
            if( !isset( $atts['positioning_left'] ) ) $atts['positioning_left'] = '';
            if( $atts['positioning']=='top_left' ) {
                $styles .= 'top:' . $atts['positioning_top'] . ';';
                $styles .= 'left:' . $atts['positioning_left'] . ';';
                $styles .= 'right: inherit;';
                $styles .= 'bottom: inherit;';
            }elseif( $atts['positioning']=='top_right' ) {
                $styles .= 'top:' . $atts['positioning_top'] . ';';
                $styles .= 'right:' . $atts['positioning_right'] . ';';
                $styles .= 'left: inherit;';
                $styles .= 'bottom: inherit;';
            }elseif( $atts['positioning']=='bottom_left' ) {
                $styles .= 'bottom:' . $atts['positioning_bottom'] . ';';
                $styles .= 'left:' . $atts['positioning_left'] . ';';
                $styles .= 'right: inherit;';
                $styles .= 'top: inherit;';
            }elseif( $atts['positioning']=='bottom_right' ) {
                $styles .= 'bottom:' . $atts['positioning_bottom'] . ';';
                $styles .= 'right:' . $atts['positioning_right'] . ';';
                $styles .= 'left: inherit;';
                $styles .= 'top: inherit;';
            }
        }

        // @since   1.9 - background image
        if( !isset( $atts['bg_image'] ) ) $atts['bg_image'] = '';
        if( $atts['bg_image']!='' ) {
            $image = wp_get_attachment_image_src( $atts['bg_image'], 'original' );
            $image = !empty( $image[0] ) ? $image[0] : '';
            if( !empty( $image ) ) {
                $styles .= 'background-image: url(\'' . $image . '\');';
            }
        }

        if( $styles!='' ) $styles = ' style="' . $styles . '"';

        // Make sure our global super_grid_system is set
        if( !isset( $GLOBALS['super_grid_system'] ) ) {
            $GLOBALS['super_grid_system'] = array(
                'level' => 0,
                'width' => 0,
                'columns' => array()
            );
        }
        $grid = $GLOBALS['super_grid_system'];

        // Count inner columns of the current column
        $inner_total = 0;
        if( !empty( $inner ) ) {
            foreach( $inner as $k => $v ) {
                if( $v['tag']=='column' ) $inner_total++;
            }
        }
        $GLOBALS['super_grid_system']['columns'][$grid['level']]['inner_total'] = $inner_total;
        if( !isset( $GLOBALS['super_column_found'] ) ) $GLOBALS['super_column_found'] = 0;
        if( !isset( $grid['columns'][$grid['level']]['total'] ) ) $GLOBALS['super_grid_system']['columns'][$grid['level']]['total'] = $GLOBALS['super_column_found'];
        if( !isset( $grid['columns'][$grid['level']]['current'] ) ) $GLOBALS['super_grid_system']['columns'][$grid['level']]['current'] = 0;
        if( !isset( $grid['columns'][$grid['level']]['absolute_current'] ) ) $GLOBALS['super_grid_system']['columns'][$grid['level']]['absolute_current'] = 0;
        if( !isset( $grid[$grid['level']]['width'] ) ) $GLOBALS['super_grid_system'][$grid['level']]['width'] = 0;
        $grid = $GLOBALS['super_grid_system'];

        $result = '';
        $close_grid = false;

        $sizes = array(
            '1/5'=>array('one_fifth',20),
            '1/4'=>array('one_fourth',25),
            '1/3'=>array('one_third',33.3333334),
            '2/5'=>array('two_fifth',40),
            '1/2'=>array('one_half',50),
            '3/5'=>array('three_fifth',60),
            '2/3'=>array('two_third',66.6666667),
            '3/4'=>array('three_fourth',75),
            '4/5'=>array('four_fifth',80),
            '1/1'=>array('one_full',100),
        );

        $grid[$grid['level']]['width'] = floor($grid[$grid['level']]['width']+$sizes[$atts['size']][1]);  
        if( $grid[$grid['level']]['width']>100 ) {
            $grid[$grid['level']]['width'] = $sizes[$atts['size']][1];
            $grid['columns'][$grid['level']]['current'] = 0;
            $result .= '</div>';
        }
        $grid['columns'][$grid['level']]['current']++;
        $grid['columns'][$grid['level']]['absolute_current']++;
        $class = '';
        if($grid['columns'][$grid['level']]['current']==1){
            $class = 'first-column';
            $result .= '<div class="super-grid super-shortcode">';
        }
        if( ( $grid[$grid['level']]['width']>=95 ) || ( $grid['columns'][$grid['level']]['total']==$grid['columns'][$grid['level']]['current'] ) ) {
            $close_grid = true;
        }
        if($grid['columns'][$grid['level']]['absolute_current']==$grid['columns'][$grid['level']]['total']){
            $close_grid = true;
        }

        // @since 1.9 - keep original size on mobile devices
        if( !isset( $atts['hide_on_mobile'] ) ) $atts['hide_on_mobile'] = '';
        if( !isset( $atts['resize_disabled_mobile'] ) ) $atts['resize_disabled_mobile'] = '';
        if( !isset( $atts['hide_on_mobile_window'] ) ) $atts['hide_on_mobile_window'] = '';
        if( !isset( $atts['resize_disabled_mobile_window'] ) ) $atts['resize_disabled_mobile_window'] = '';

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';
        if( !isset( $atts['force_responsiveness_mobile_window'] ) ) $atts['force_responsiveness_mobile_window'] = '';

        if( empty($atts['margin']) ) $atts['margin'] = '';

        $conditionAttributes = self::conditional_attributes( $atts );
        $class .= $conditionAttributes['class'];
        $result .= '<div class="super-shortcode super_' . $sizes[$atts['size']][0] . ' super-column'.$atts['invisible'].$atts['align_elements'].' column-number-'.$grid['columns'][$grid['level']]['current'].' grid-level-'.$grid['level'].' ' . $class . ' ' . $atts['margin'] . ($atts['resize_disabled_mobile']==true ? ' super-not-responsive' : '') . ($atts['resize_disabled_mobile_window']==true ? ' super-not-responsive-window' : '') . ($atts['hide_on_mobile']==true ? ' super-hide-mobile' : '') . ($atts['hide_on_mobile_window']==true ? ' super-hide-mobile-window' : '') . ($atts['force_responsiveness_mobile_window']==true ? ' super-force-responsiveness-window' : '') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"' . $styles; 
        $result .= $conditionAttributes['dataset']; 
        if( $atts['duplicate']=='enabled' ) {
            // @since   1.2.8    - make sure this data is set
            if( !isset( $atts['duplicate_limit'] ) ) $atts['duplicate_limit'] = 0;
            $result .= ' data-duplicate-limit="' . $atts['duplicate_limit'] . '"';

            // @since 1.3
            if( !isset( $atts['duplicate_dynamically'] ) ) $atts['duplicate_dynamically'] = '';
            if($atts['duplicate_dynamically']=='true') {
                $result .= ' data-duplicate-dynamically="' . $atts['duplicate_dynamically'] . '"';
            }
        }
        $result .= self::pdf_attributes($atts);
        $result .= '>';
        
        // @since   1.3   - column custom padding
        $close_custom_padding = false;
        if( !isset( $atts['enable_padding'] ) ) $atts['enable_padding'] = '';
        if( $atts['enable_padding']=='true' ) {
            if( !isset( $atts['padding'] ) ) $atts['padding'] = '';
            if( $atts['padding']!='' ) {
                $close_custom_padding = true;
                $result .= '<div class="super-column-custom-padding" style="padding:' . $atts['padding'] . ';">';
            }
        }

        if( !empty( $inner ) ) {
            if($atts['duplicate']=='enabled' && $entry_data){
                $GLOBALS['super_grid_system'] = $grid;
                $GLOBALS['super_column_found'] = 0;

                // Before we proceed we must fetch all the inner field names
                // This way we can check if a specific field exists inside the dynamic column when replacing {tags}.
                // If no field name exists we will not replace the {tag} and thus not increment from {tag} to {tag_2} to {tag_3} etc.
                $re = '/{"name":"(.*?)"/';
                $str = json_encode($inner);
                preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
                $dynamic_field_names = array();
                foreach($matches as $mk => $mv){
                    $dynamic_field_names[] = $mv[1];
                }

                // Loop through inner elements
                foreach($inner as $ik => $iv){
                    if( !empty($iv['data']['name']) ) {
                        $inner_field_names[$iv['data']['name']] = array(
                            'name' => (isset($iv['data']['name']) ? $iv['data']['name'] : 'undefined'), // Field name
                            'email' => (isset($iv['data']['email']) ? $iv['data']['email'] : '') // Email label
                        );
                    }
                }

                // Grab first field name inside the dynamic column
                // This is always the index on the saved data
                $regex = '/"name":"(.*?)",/';
                preg_match($regex, $str, $matches, PREG_OFFSET_CAPTURE, 0);
                if( isset($matches[1]) && isset($matches[1][0]) ){
                    $field_name = $matches[1][0];
                    $no_data = false;
                    if(isset($entry_data['_super_dynamic_data'])){
                        if(!is_array($entry_data['_super_dynamic_data'])){
                            $_super_dynamic_data = json_decode($entry_data['_super_dynamic_data'], true);
                        }else{
                            $_super_dynamic_data = $entry_data['_super_dynamic_data'];
                        }
                        if( (is_array($_super_dynamic_data)) && (!empty($_super_dynamic_data[$field_name])) ) {
                            $i=1;
                            $re = '/\{(.*?)\}/';
                            foreach($_super_dynamic_data[$field_name] as $dk => $dv){
                                $grid['level']++;
                                $GLOBALS['super_grid_system'] = $grid;
                                $GLOBALS['super_column_found'] = 0;
                                $result .= '<div class="super-shortcode super-duplicate-column-fields">';
                                    foreach( $inner as $k => $v ) {
                                        if( $v['tag']=='column' ) $GLOBALS['super_column_found']++;
                                    }
                                    foreach( $inner as $k => $v ) {
                                        if( empty($v['data']) ) $v['data'] = null;
                                        if( empty($v['inner']) ) $v['inner'] = null;
                                        $v = SUPER_Common::replace_tags_dynamic_columns($v, $re, $i, $dynamic_field_names, $inner_field_names, $dv);
                                        $result .= self::output_element_html( $v['tag'], $v['group'], $v['data'], $v['inner'], $shortcodes, $settings, $i18n, false, $entry_data, $i, $dynamic_field_names, $inner_field_names, $formProgress );
                                    }
                                    $result .= '<div class="super-duplicate-actions">';
                                    $result .= '<span class="super-add-duplicate"></span>';
                                    $result .= '<span class="super-delete-duplicate"></span>';
                                    $result .= '</div>';
                                $result .= '</div>';
                                $grid['level']--;
                                $i++;
                            }
                        }else{
                            $no_data = true;
                        }
                    }else{
                        $no_data = true;
                    }
                    if($no_data){
                        $grid['level']++;
                        $GLOBALS['super_grid_system'] = $grid;
                        $GLOBALS['super_column_found'] = 0;
                        // No data found, let's generate at least 1 column
                        $result .= '<div class="super-shortcode super-duplicate-column-fields">';
                            foreach( $inner as $k => $v ) {
                                if( $v['tag']=='column' ) $GLOBALS['super_column_found']++;
                            }
                            foreach( $inner as $k => $v ) {
                                if( empty($v['data']) ) $v['data'] = null;
                                if( empty($v['inner']) ) $v['inner'] = null;
                                $result .= self::output_element_html( $v['tag'], $v['group'], $v['data'], $v['inner'], $shortcodes, $settings, $i18n, false, $entry_data, $dynamic=0, $dynamic_field_names=array(), $inner_field_names=array(), $formProgress );
                            }
                            $result .= '<div class="super-duplicate-actions">';
                            $result .= '<span class="super-add-duplicate"></span>';
                            $result .= '<span class="super-delete-duplicate"></span>';
                            $result .= '</div>';
                        $result .= '</div>';
                        $grid['level']--;
                    }
                }
            }else{
                // Loop through inner elements
                foreach($inner as $ik => $iv){
                    if( !empty($iv['data']['name']) ) {
                        $inner_field_names[$iv['data']['name']] = array(
                            'name' => (isset($iv['data']['name']) ? $iv['data']['name'] : 'undefined'), // Field name
                            'email' => (isset($iv['data']['email']) ? $iv['data']['email'] : '') // Email label
                        );
                    }
                }
                
                $grid['level']++;
                $GLOBALS['super_grid_system'] = $grid;
                $GLOBALS['super_column_found'] = 0;
                if( $atts['duplicate']=='enabled' ) {
                    $result .= '<div class="super-shortcode super-duplicate-column-fields">';
                }
                foreach( $inner as $k => $v ) {
                    if( $v['tag']=='column' ) $GLOBALS['super_column_found']++;
                }
                $re = '/\{(.*?)\}/';
                $i = $dynamic;
                foreach( $inner as $k => $v ) {
                    if( empty($v['data']) ) $v['data'] = null;
                    if( empty($v['inner']) ) $v['inner'] = null;
                    $v = SUPER_Common::replace_tags_dynamic_columns($v, $re, $i, $dynamic_field_names, $inner_field_names);
                    $result .= self::output_element_html( $v['tag'], $v['group'], $v['data'], $v['inner'], $shortcodes, $settings, $i18n, false, $entry_data, $dynamic, $dynamic_field_names, $inner_field_names, $formProgress );
                }
                if( $atts['duplicate']=='enabled' ) {
                    $result .= '<div class="super-duplicate-actions">';
                    $result .= '<span class="super-add-duplicate"></span>';
                    $result .= '<span class="super-delete-duplicate"></span>';
                    $result .= '</div>';
                    $result .= '</div>';
                }
                $grid['level']--;
            }
            $GLOBALS['super_grid_system'] = $grid;      
        }

        // @since   1.3   - column custom padding
        if( $close_custom_padding==true ) {
            $result .= '</div>';
        }

        $result .= self::loop_conditions( $atts, $tag );

        $result .= '</div>';
        if($close_grid==true){
            $grid[$grid['level']]['width'] = 0;
            $grid['columns'][$grid['level']]['current'] = 0;
            $result .= '</div>';
        }
        $GLOBALS['super_grid_system'] = $grid;
        return $result;
    }


    /** 
     *  Quantity field
     *
     *  @since      1.2.1
    */    
    public static function quantity_field( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        if( empty($atts['wrapper_width']) ) $atts['wrapper_width'] = 50;
        if( empty($settings['theme_field_size']) ) $settings['theme_field_size'] = 'medium';
        if( $settings['theme_field_size']=='large' ) $atts['wrapper_width'] = $atts['wrapper_width']+20;
        if( $settings['theme_field_size']=='huge' ) $atts['wrapper_width'] = $atts['wrapper_width']+30;

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data, '0');
        
        $result = self::opening_tag( $tag, $atts );
        $result .= '<div class="super-quantity-field-wrap">';
            $result .= '<span class="super-minus-button super-noselect"><i>-</i></span>';
            $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );

            // @since 1.9 - custom class
            if( !isset( $atts['class'] ) ) $atts['class'] = '';

            $result .= '<input tabindex="-1" class="super-shortcode-field' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '" type="text"';

            if( empty( $atts['minnumber']) ) $atts['minnumber'] = 0;
            if( empty( $atts['maxnumber']) ) $atts['maxnumber'] = 100;
            if( $atts['value']<$atts['minnumber'] ) {
                $atts['value'] = $atts['minnumber'];
            }
            if( $atts['value']>$atts['maxnumber'] ) {
                $atts['value'] = $atts['maxnumber'];
            }

            $result .= ' name="' . $atts['name'] . '" value="' . esc_attr($atts['value']) . '" data-steps="' . $atts['steps'] . '"';
            $result .= self::common_attributes( $atts, $tag, $settings );
            $result .= ' />';

            // @since 1.2.5     - custom regex validation
            if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

            $result .= '</div>';
            $result .= '<span class="super-plus-button super-noselect"><i>+</i></span>';
        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }


    /** 
     *  Toggle field
     *
     *  @since      2.9.0
    */    
    public static function toggle_field( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        // Based on current value update to final on/off value
        // This way we can correclty check if the toggle should be set to be active or not.
        if($atts['value']=='1'){
            $atts['value'] = $atts['on_value'];
        }else{
            $atts['value'] = $atts['off_value'];
        }

        $atts['validation'] = 'empty';

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data, '0');

        $result = self::opening_tag( $tag, $atts );
        
        if(!isset($atts['prefix_label'])) $atts['prefix_label'] = '';
        if(!isset($atts['prefix_tooltip'])) $atts['prefix_tooltip'] = '';
        if( ($atts['prefix_label']!='') || ($atts['prefix_tooltip']!='') ) {
            $result .= '<div class="super-toggle-prefix-label">';
            if($atts['prefix_label']!='') $result .= '<span>'.$atts['prefix_label'].'</span>';
            if($atts['prefix_tooltip']!='') $result .= '<span class="super-toggle-prefix-question super-tooltip" title="' . esc_attr( stripslashes( $atts['prefix_tooltip'] ) ) . '"></span>';
            $result .= '</div>';
        }

        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );

        $toggle_active = false;
        if($atts['value']==$atts['on_value']){
            $toggle_active = true;
        }

        $result .= '<div class="super-toggle-switch ' . ( $toggle_active ? 'super-active' : '' ) . '">';
            $result .= '<div class="super-toggle-group">';
                $result .= '<label class="super-toggle-on" data-value="' . esc_attr($atts['on_value']) . '"><span>' . $atts['on_label'] . '</span></label>';
                $result .= '<span class="super-toggle-handle"></span>';
                $result .= '<label class="super-toggle-off" data-value="' . esc_attr($atts['off_value']) . '"><span>' . $atts['off_label'] . '</span></label>';
            $result .= '</div>';
        $result .= '</div>';

        if( !isset($atts['class']) ) $atts['class'] = '';
        $result .= '<input class="super-shortcode-field' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '" type="hidden"';
        $result .= ' name="' . $atts['name'] . '" value="' . ( $toggle_active ? esc_attr($atts['on_value']) : esc_attr($atts['off_value']) ) . '"';
        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';

        $result .= '</div>';
        
        if( !isset($atts['suffix_label']) ) $atts['suffix_label'] = '';
        if( !isset($atts['suffix_tooltip']) ) $atts['suffix_tooltip'] = '';
        if( ($atts['suffix_label']!='') || ($atts['suffix_tooltip']!='') ) {
            $result .= '<div class="super-toggle-suffix-label">';
            if($atts['suffix_label']!='') $result .= '<span>'.$atts['suffix_label'].'</span>';
            if($atts['suffix_tooltip']!='') $result .= '<span class="super-toggle-suffix-question super-tooltip" title="' . esc_attr( stripslashes( $atts['suffix_tooltip'] ) ) . '"></span>';
            $result .= '</div>';
        }

        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }


    /** 
     *  Color picker
     *
     *  @since      3.1.0
    */    
    public static function color( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        wp_enqueue_style( 'spectrum', SUPER_PLUGIN_FILE.'assets/css/frontend/spectrum.css', array(), SUPER_VERSION );    
        wp_enqueue_script( 'spectrum', SUPER_PLUGIN_FILE . 'assets/js/frontend/spectrum.js', array( 'jquery' ), SUPER_VERSION, false );

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);

        $result = self::opening_tag( $tag, $atts );

        if( !isset($atts['prefix_label']) ) $atts['prefix_label'] = '';
        if( !isset($atts['prefix_tooltip']) ) $atts['prefix_tooltip'] = '';
        if( ($atts['prefix_label']!='') || ($atts['prefix_tooltip']!='') ) {
            $result .= '<div class="super-toggle-prefix-label">';
            if($atts['prefix_label']!='') $result .= '<span>'.$atts['prefix_label'].'</span>';
            if($atts['prefix_tooltip']!='') $result .= '<span class="super-toggle-prefix-question super-tooltip" title="' . esc_attr( stripslashes( $atts['prefix_tooltip'] ) ) . '"></span>';
            $result .= '</div>';
        }

        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $result .= '<input tabindex="-1" class="super-shortcode-field' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '" type="text"';
        $result .= ' name="' . $atts['name'] . '" value="' . esc_attr($atts['value']) . '"';
        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';
        $result .= '</div>';

        if( !isset( $atts['suffix_label'] ) ) $atts['suffix_label'] = '';
        if( !isset( $atts['suffix_tooltip'] ) ) $atts['suffix_tooltip'] = '';
        if( ($atts['suffix_label']!='') || ($atts['suffix_tooltip']!='') ) {
            $result .= '<div class="super-toggle-suffix-label">';
            if($atts['suffix_label']!='') $result .= '<span>'.$atts['suffix_label'].'</span>';
            if($atts['suffix_tooltip']!='') $result .= '<span class="super-toggle-suffix-question super-tooltip" title="' . esc_attr( stripslashes( $atts['suffix_tooltip'] ) ) . '"></span>';
            $result .= '</div>';
        }

        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }


    /** 
     *  Slider field
     *
     *  @since      1.2.1
    */    
    public static function slider_field( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        wp_enqueue_style( 'simpleslider', SUPER_PLUGIN_FILE.'assets/css/backend/simpleslider.css', array(), SUPER_VERSION );    
        wp_enqueue_script( 'simpleslider', SUPER_PLUGIN_FILE.'assets/js/backend/simpleslider.js', array( 'jquery' ), SUPER_VERSION, false ); 

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data, '0');

        $result = self::opening_tag( $tag, $atts );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );

        $result .= '<input tabindex="-1" class="super-shortcode-field" type="text"';

        $result .= ' name="' . $atts['name'] . '" value="' . esc_attr($atts['value']) . '" data-decimals="' . $atts['decimals'] . '" data-thousand-separator="' . $atts['thousand_separator'] . '" data-decimal-separator="' . $atts['decimal_separator'] . '" data-steps="' . $atts['steps'] . '" data-currency="' . $atts['currency'] . '" data-format="' . $atts['format'] . '"';
        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }

    /** 
     *  Currency field
     *
     *  @since      2.1.0
    */ 
    public static function currency( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {
        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation  
        wp_enqueue_script( 'super-masked-currency', SUPER_PLUGIN_FILE . 'assets/js/frontend/masked-currency.js', array( 'jquery' ), SUPER_VERSION, false ); 
        
        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);

        $result = self::opening_tag( $tag, $atts );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );
        
        if( !isset( $atts['format'] ) ) $atts['format'] = '';
        if( !isset( $atts['currency'] ) ) $atts['currency'] = '$';
        if( !isset( $atts['decimals'] ) ) $atts['decimals'] = 2;
        if( !isset( $atts['thousand_separator'] ) ) $atts['thousand_separator'] = ',';
        if( !isset( $atts['decimal_separator'] ) ) $atts['decimal_separator'] = '.';

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $result .= '<input tabindex="-1" class="super-shortcode-field' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '" type="tel"';
        $result .= ' name="' . $atts['name'] . '" value="' . esc_attr($atts['value']) . '" data-decimals="' . $atts['decimals'] . '" data-thousand-separator="' . $atts['thousand_separator'] . '" data-decimal-separator="' . $atts['decimal_separator'] . '" data-currency="' . $atts['currency'] . '" data-format="' . $atts['format'] . '"';

        // @since 4.2.0 - custom threshold to trigger hooks
        if( !empty($atts['threshold']) ) {
            $result .= ' data-threshold="' . $atts['threshold'] . '"';
        }

        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';

        $result .= '<input type="hidden" value="' . esc_attr(str_replace($atts['thousand_separator'], "", $atts['value'])) . '" />';
        
        // @since 4.9.3 - Adaptive placeholders
        $result .= self::adaptivePlaceholders( $settings, $atts, $tag );

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }

    public static function text( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {
        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        // @since 4.7.0 - field types
        if( !isset( $atts['type'] ) ) $atts['type'] = 'text';
        if( empty($atts['step']) ) $atts['step'] == 'any';

        // Set validation to 'numeric' if field type was set to 'number'
        if($atts['type'] == 'number') $atts['validation'] = 'float';

        // @since 3.1.0 - google distance calculation between 2 addresses
        $data_attributes = '';
        $distance_calculator_class = '';
        if( !isset( $atts['enable_distance_calculator'] ) ) $atts['enable_distance_calculator'] = '';
        if( $atts['enable_distance_calculator']=='true' ) {
            if( !isset( $atts['distance_method'] ) ) $atts['distance_method'] = 'start';
            if( !isset( $atts['distance_value'] ) ) $atts['distance_value'] = 'distance';
            if( !isset( $atts['distance_units'] ) ) $atts['distance_units'] = 'metric';
            if( !isset( $atts['distance_field'] ) ) $atts['distance_field'] = '';
            $data_attributes .= ' data-distance-method="'.$atts['distance_method'].'"';
            $data_attributes .= ' data-distance-value="'.$atts['distance_value'].'"';
            $data_attributes .= ' data-distance-units="'.$atts['distance_units'].'"';
            $data_attributes .= ' data-distance-field="'.$atts['distance_field'].'"';
            if( $atts['distance_method']=='start' ) {
                $data_attributes .= ' data-distance-destination="'.$atts['distance_destination'].'"';
            }else{
                $data_attributes .= ' data-distance-start="'.$atts['distance_start'].'"';
            }
            $distance_calculator_class .= ' super-distance-calculator';
        }

        // @since 3.0.0 - google places autocomplete/fill address based on user input
        $address_auto_complete_attr = '';
        $address_auto_populate_class = '';
        if( !isset( $atts['enable_address_auto_complete'] ) ) $atts['enable_address_auto_complete'] = '';
        if( $atts['enable_address_auto_complete']=='true' ) {
            $address_auto_populate_class = ' super-address-autopopulate';
            // @since 4.9.557 - Check if we need to filter by countrie(s) or  return by specific type
            if( !empty( $atts['address_api_types'] ) ) $address_auto_complete_attr .= ' data-types="' . $atts['address_api_types'] . '"';
            if( !empty( $atts['address_api_countries'] ) ) $address_auto_complete_attr .= ' data-countries="' . $atts['address_api_countries'] . '"';
            // Check if we need to auto populate fields with the retrieved data
            if( !isset( $atts['enable_address_auto_populate'] ) ) $atts['enable_address_auto_populate'] = '';
            if( $atts['enable_address_auto_populate']=='true' ) {
                //onFocus="geolocate()"
                foreach($atts['address_auto_populate_mappings'] as $k => $v){
                    if( $v['field']!='' ) $address_auto_complete_attr .= ' data-map-' . $v['key'] . '="' . $v['field'] . '|' . $v['type'] . '"';
                }
            }
            // If API key is empty, try to grab it from global settings
            if(empty($atts['address_api_key'])){
                $global_settings = SUPER_Common::get_global_settings();
                if( !empty($global_settings['form_google_places_api']) ) {
                    $atts['address_api_key'] = $global_settings['form_google_places_api'];
                }
            }
            if(empty($atts['address_api_language'])){
                $global_settings = SUPER_Common::get_global_settings();
                if( !empty($global_settings['google_maps_api_language']) ) {
                    $atts['address_api_language'] = $global_settings['google_maps_api_language'];
                }
            }
            if(empty($atts['address_api_region'])){
                $global_settings = SUPER_Common::get_global_settings();
                if( !empty($global_settings['google_maps_api_region']) ) {
                    $atts['address_api_region'] = $global_settings['google_maps_api_region'];
                }
            }
            $url = '//maps.googleapis.com/maps/api/js?';
            if( !empty( $atts['address_api_key'] ) ) {
                $address_auto_complete_attr .= ' data-api-key="' . $atts['address_api_key'] . '"';
            }
            if( !empty( $atts['address_api_language'] ) ) {
                $address_auto_complete_attr .= ' data-api-language="' . $atts['address_api_language'] . '"';
                $url .= 'language='.$atts['address_api_language'].'&';
            }
            if( !empty( $atts['address_api_region'] ) ) {
                $address_auto_complete_attr .= ' data-api-region="' . $atts['address_api_region'] . '"';
                $url .= 'region='.$atts['address_api_region'].'&';
            }
            $url .= 'key=' . $atts['address_api_key'] . '&libraries=drawing,geometry,places,visualization&callback=SUPER.google_maps_init';
            wp_enqueue_script( 'google-maps-api', $url, array( 'super-common' ), SUPER_VERSION, false );
        }

        // @since   1.2.4 - auto suggest feature
        if( !isset( $atts['enable_auto_suggest'] ) ) $atts['enable_auto_suggest'] = '';
        $class = ($atts['enable_auto_suggest']=='true' ? ' super-auto-suggest' : '');

        // @since   4.6.0 - wc order search
        if( !isset( $atts['wc_order_search'] ) ) $atts['wc_order_search'] = '';
        $class .= ($atts['wc_order_search']=='true' ? ' super-wc-order-search' : '');

        // @since   3.7.0 - keyword tags
        if( !empty($atts['enable_keywords']) ) {
            $class .= ' super-keyword-tags';
        }

        // @since   3.1.0 - uppercase transformation
        if( !isset( $atts['uppercase'] ) ) $atts['uppercase'] = '';
        $class .= ($atts['uppercase']=='true' ? ' super-uppercase' : '');

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);
        $result = self::opening_tag( $tag, $atts, $class );

        $wrapper_class = '';
        if( ($atts['enable_auto_suggest']=='true') && (!empty($entry_data[$atts['name']])) && (!empty($entry_data[$atts['name']]['value'])) ) {
            // Check if value exist in one of the items
            // If so add overlap class, otherwise don't and check if user is allowed to enter none-existing values (manual input)
            $get_items = self::get_items(array(), $tag, $atts, '', $settings, $entry_data);
            $firstItemValues = array();
            foreach($get_items['items_values'] as $v){
                $firstValue = explode(';', $v)[0];
                $firstItemValues[] = $firstValue;
            }
            if(in_array($entry_data[$atts['name']]['value'], $firstItemValues, true )){
                $wrapper_class = 'super-overlap'; 
            }
        }

        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings, $wrapper_class );
        
        // @since 2.9.0 - keyword enabled
        if( !isset( $atts['enable_keywords'] ) ) $atts['enable_keywords'] = '';
        if( !isset( $atts['keyword_split_method'] ) ) $atts['keyword_split_method'] = 'both';

        $result .= '<input tabindex="-1" class="super-shortcode-field';
        $result .= $distance_calculator_class;
        $result .= $address_auto_populate_class; 
        if( !empty($atts['class']) ) {
            $result .= ' ' . $atts['class'];
        }

        // @since 4.7.0 - field types
        $result .= '" type="' . $atts['type'] . '"';
        if( ($atts['type']=='number') && (!empty($atts['step'])) ) {
            $result .= '" step="' . $atts['step'] . '"';
        }
        if( $atts['enable_distance_calculator']=='true' ) {
            $result .= $data_attributes;
        }

        if( $atts['enable_auto_suggest']=='true' ) {
            $get_items = self::get_items(array(), $tag, $atts, '', $settings, $entry_data);
            $items = $get_items['items'];
            $atts = $get_items['atts'];
        }

        $result .= ' name="' . $atts['name'] . '"';
        if( $atts['value']!=='' ) {
            $result .= ' value="' . esc_attr($atts['value']) . '"';
        }

        // @since 2.2.0   - search / populate with contact entry data
        if( $atts['enable_search']=='true' ) {
            $result .= ' data-search="' . $atts['enable_search'] . '"';
            $result .= ' data-search-method="' . $atts['search_method'] . '"';
            
            // @since 3.2.0 - skip specific fields from being populated
            $skip = '';
            if( !empty($atts['search_skip']) ) {
                $skip = sanitize_text_field( $atts['search_skip'] );
                $result .= ' data-search-skip="' . $skip . '"';
            }

            // @since 3.1.0
            // make sure if the parameter of this field element is set in the POST or GET we 
            // have to set the GET variables to auto fill the form fields based on the contact entry found
            if( $atts['value']!='' ) {
                global $wpdb;
                $value = sanitize_text_field($atts['value']);
                $method = sanitize_text_field($atts['search_method']);
                $table = $wpdb->prefix . 'posts';
                $table_meta = $wpdb->prefix . 'postmeta';
                if($method=='equals') $query = "post_title = BINARY '$value'";
                if($method=='contains') $query = "post_title LIKE BINARY '%$value%'";
                $entry = $wpdb->get_row("SELECT ID FROM $table WHERE $query AND post_status IN ('publish','super_unread','super_read') AND post_type = 'super_contact_entry'");
                if($entry){
                    $data = get_post_meta( $entry->ID, '_super_contact_entry_data', true );
                    unset($data['hidden_form_id']);
                    $skip_fields = explode( "|", $skip );
                    foreach($skip_fields as $field_name){
                        if( isset($data[$field_name]) ) {
                            unset($data[$field_name]);
                        }
                    }
                    $data['hidden_contact_entry_id'] = array(
                        'name' => 'hidden_contact_entry_id',
                        'value' => $entry->ID,
                        'type' => 'entry_id'
                    );
                    if (is_array($data) || is_object($data)) {
                        foreach($data as $k => $v){
                            $_GET[$k] = $v['value'];
                        }
                    }

                }
            }
        }
        if( $atts['wc_order_search']=='true' ) {
            if(!empty($atts['wc_order_search_method'])) $result .= ' data-wcosm="' . esc_attr($atts['wc_order_search_method']) . '"';
            if(!empty($atts['wc_order_search_filterby'])) $result .= ' data-wcosfb="' . implode(';',explode("\n",$atts['wc_order_search_filterby'])) . '"';
            if(!empty($atts['wc_order_search_return_label'])) $result .= ' data-wcosrl="' . esc_attr($atts['wc_order_search_return_label']) . '"';
            if(!empty($atts['wc_order_search_return_value'])) $result .= ' data-wcosrv="' . esc_attr($atts['wc_order_search_return_value']) . '"';
            if(!empty($atts['wc_order_search_populate'])) $result .= ' data-wcosp="' . esc_attr($atts['wc_order_search_populate']) . '"';
            if(!empty($atts['wc_order_search_skip'])) $result .= ' data-wcoss="' . esc_attr($atts['wc_order_search_skip']) . '"';
            if(!empty($atts['wc_order_search_status'])) $result .= ' data-wcosst="' . implode(';',explode("\n",$atts['wc_order_search_status'])) . '"';
            if(!empty($atts['value'])) {
                $value = sanitize_text_field($atts['value']);
                $method = $atts['wc_order_search_method'];
                $query = '';
                if($method=='equals') {
                    $query .= "(wc_order.ID LIKE '$value') OR ";
                }
                if($method=='contains') {
                    $query .= "(wc_order.ID LIKE '%$value%') OR ";
                }
                global $wpdb;
                $filterby = explode(";", $atts['wc_order_search_filterby']);
                foreach($filterby as $k => $v){
                    if(!empty($v)){
                        if($k>0){
                            $query .= " OR ";
                        }
                        if($method=='equals') {
                            $query .= "(meta.meta_key = '".$v."' AND meta.meta_value LIKE '$value')";
                        }
                        if($method=='contains') {
                            $query .= "(meta.meta_key = '".$v."' AND meta.meta_value LIKE '%$value%')";
                        }
                    }
                }

                $order = $wpdb->get_row("SELECT ID
                    FROM $wpdb->posts AS wc_order
                    INNER JOIN $wpdb->postmeta AS meta ON meta.post_id = wc_order.ID
                    WHERE $query
                    AND post_type = 'shop_order'
                    LIMIT 1");
                if($order){
                    if(!empty($atts['wc_order_search_populate'])){
                        $data = SUPER_Common::get_entry_data_by_wc_order_id($order->ID, $atts['wc_order_search_skip']);
                        if(is_array($data)){
                            foreach($data as $k => $v){
                                if(isset($v['value'])){
                                    $_GET[$k] = $v['value'];
                                }
                            }
                        }                        
                    }
                }
            }
        }
        
        // @since 3.0.0 - add data attributes to map google places data to specific fields
        // @since 4.9.557 - Check if we need to display in specific language, filter by countrie(s), return by specific type
        if( !empty($address_auto_complete_attr) ) $result .= $address_auto_complete_attr;
        
        // @since 3.6.0 - disable autocomplete when either auto suggest or keyword functionality is enabled
        if( !empty($atts['enable_auto_suggest']) ) $atts['autocomplete'] = 'true';
        if( !empty($atts['enable_keywords']) ) $atts['autocomplete'] = 'true';

        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';
        
        // @since 4.9.3 - Adaptive placeholders
        $result .= self::adaptivePlaceholders( $settings, $atts, $tag );

        // @since 2.9.0 - entered keywords
        if( !empty($atts['enable_keywords']) ) {
            
            $get_items = self::get_items(array(), $tag, $atts, 'keywords_', $settings, $entry_data);
            $items = $get_items['items'];
            $atts = $get_items['atts'];

            $result .= '<div class="super-autosuggest-tags">';
                $result .= '<div>';
                // Populate form with data
                if(!empty($atts['value'])){
                    $tags = explode(',', $atts['value']);
                    if( empty( $items) ) { // User can input his own tags, no predefined items here
                        foreach( $tags as $tag ) {
                            $result .= '<span class="super-noselect super-keyword-tag" sfevents=\'{"click":"keywords.remove"}\' data-value="' . esc_attr($tag) . '" title="remove this tag">' . esc_html($tag) . '</span>';
                        }
                    }else{
                        foreach( $atts['keywords_items'] as $tag ) {
                            if(in_array($tag['value'], $tags, true )) {
                                $result .= '<span class="super-noselect super-keyword-tag" sfevents=\'{"click":"keywords.remove"}\' data-value="' . esc_attr($tag['value']) . '" title="remove this tag">' . esc_html($tag['label']) . '</span>';
                            }
                        }
                    }
                }
                $result .= '</div>';
                if( empty($atts['keywords_retrieve_method']) ) $atts['keywords_retrieve_method'] = 'free';
                $result .= '<input tabindex="-1" class="super-keyword-filter" type="text"';
                $result .= self::common_attributes( $atts, $tag, $settings );
                $result .= ' data-method="' . esc_attr($atts['keywords_retrieve_method']) . '"';
                $result .= ' data-split-method="' . esc_attr($atts['keyword_split_method']) . '"';
                $result .= ' sfevents="' . esc_attr('{"onblur":"unfocusField","keyup,keydown":"keywords.filter","click,mousedown":"focusField"}') . '"';
                $result .= ' />';
            $result .= '</div>';

            $result .= '<ul class="super-dropdown-list super-autosuggest-tags-list">';
            $result .= '<li data-value="" data-search-value="" class="super-no-results">' . esc_html__( 'No matches found', 'super-forms' ) . '...</li>';
            foreach( $items as $k => $v ) {
                $result .= $v;
            }
            $result .= '</ul>';
        }else{
            // @since 1.2.4
            if( $atts['enable_auto_suggest']=='true' ) {
                $result .= '<ul class="super-dropdown-list">';
                foreach( $items as $v ) {
                    $result .= $v;
                }
                $result .= '</ul>';
            }
        }

        if( ($atts['enable_address_auto_complete']=='true') && (empty($atts['address_api_key'])) ) {
            $result .= '<strong style="color:red;">' . esc_html__( 'Please edit this field and enter your "Google API key" under the "Address auto complete" TAB', 'super-forms' ) . '</strong>';
        }

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= self::loop_variable_conditions( $atts );
        $result .= '</div>';
        return $result;
    }
    public static function textarea( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation
        
        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);

        $result  = self::opening_tag( $tag, $atts );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );

        // @since   1.2.4
        if( !isset( $atts['editor'] ) ) $atts['editor'] = 'false';
        if( !isset( $atts['media_buttons'] ) ) $atts['media_buttons'] = 'true';
        if( !isset( $atts['wpautop'] ) ) $atts['wpautop'] = 'true';
        if( !isset( $atts['force_br'] ) ) $atts['force_br'] = 'false';
        if( !isset( $atts['height'] ) ) $atts['height'] = 0;
        if( !isset( $atts['editor_height'] ) ) $atts['editor_height'] = 100;
        if( !isset( $atts['teeny'] ) ) $atts['teeny'] = 'false';
        if( !isset( $atts['quicktags'] ) ) $atts['quicktags'] = 'true';
        if( !isset( $atts['drag_drop_upload'] ) ) $atts['drag_drop_upload'] = 'true';

        if( $atts['editor']=='true' ) {
            
            if( SUPER_Forms()->is_request('ajax') ) {
                global $wp_scripts, $wp_styles, $wp_version, $tinymce_version, $concatenate_scripts, $compress_scripts;
                $version = 'ver=' . $wp_version;
                $abspath_inc = ABSPATH . WPINC;
                $includes_url = includes_url();
                $admin_url = admin_url();
                $style_content = '';
                $array = array(
                    'buttons' => 'buttons',
                    'editor' => 'editor',
                    'editor-buttons' => 'editor-buttons',
                    'media-views' => 'media-views',
                    'dashicons' => 'dashicons'
                );
                foreach( $array as $k => $v ) {
                    if ( file_exists( "{$abspath_inc}/css/$v.css" ) ) {
                        if(!isset($wp_styles)){
                            $style_content .= wp_remote_fopen("{$includes_url}css/$v.css");
                        }else{
                            if( !in_array( $k, $wp_styles->queue, true ) ) $style_content .= wp_remote_fopen("{$includes_url}css/$v.css");
                        }
                    }
                }
                $result .= '<style type="text/css">' . $style_content . '</style>';

                ob_start();
                ?>
                <script type="text/javascript">
                /* <![CDATA[ */
                var quicktagsL10n = {"closeAllOpenTags":"Close all open tags","closeTags":"close tags","enterURL":"Enter the URL","enterImageURL":"Enter the URL of the image","enterImageDescription":"Enter a description of the image","textdirection":"text direction","toggleTextdirection":"Toggle Editor Text Direction","dfw":"Distraction-free writing mode","strong":"Bold","strongClose":"Close bold tag","em":"Italic","emClose":"Close italic tag","link":"Insert link","blockquote":"Blockquote","blockquoteClose":"Close blockquote tag","del":"Deleted text (strikethrough)","delClose":"Close deleted text tag","ins":"Inserted text","insClose":"Close inserted text tag","image":"Insert image","ul":"Bulleted list","ulClose":"Close bulleted list tag","ol":"Numbered list","olClose":"Close numbered list tag","li":"List item","liClose":"Close list item tag","code":"Code","codeClose":"Close code tag","more":"Insert Read More tag"};
                /* ]]> */
                </script>
                <?php
                $result .= ob_get_clean();

                $array = array(
                    'quicktags' => 'quicktags'
                    //'media-audiovideo' => 'media-audiovideo',
                    //'media-editor' => 'media-editor',
                    //'media-models' => 'media-models',
                    //'media-views' => 'media-views',
                    //'shortcode' => 'shortcode',
                    //'underscore' => 'underscore',
                    //'utils' => 'utils',
                    //'wp-a11y' => 'wp-a11y',
                    //'wp-backbone' => 'wp-backbone',
                    //'wp-util' => 'wp-util',
                    //'wplink' => 'wplink',
                    //'wp-embed' => 'wp-embed',
                    //'wp-emoji-release' => 'wp-emoji-release'
                );
                foreach( $array as $k => $v ) {
                    if ( file_exists( "{$abspath_inc}/js/$v.js" ) ) {
                        if( !in_array( $k, $wp_scripts->queue, true ) ) $result .= "<script type='text/javascript' src='{$includes_url}js/$v.js?$version'></script>";
                    }
                }
                $baseurl = includes_url();
                $baseurl_tinymce = includes_url( 'js/tinymce' );
                $mce_suffix = false !== strpos( $wp_version, '-src' ) ? '' : '.min';
                $compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
                    && false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
                if ( $compressed ) {
                    $result .= "<script type='text/javascript' src='{$baseurl_tinymce}/wp-tinymce.php?c=1&amp;$version'></script>\n";
                    $result .= "<script type='text/javascript' src='{$baseurl}js/utils.js?$version'></script>\n";
                } else {
                    $result .= "<script type='text/javascript' src='{$baseurl_tinymce}/tinymce{$mce_suffix}.js?$version'></script>\n";
                    $result .= "<script type='text/javascript' src='{$baseurl_tinymce}/plugins/compat3x/plugin.js?$version'></script>\n";
                    $result .= "<script type='text/javascript' src='{$baseurl}js/utils.js?$version'></script>\n";
                }
                $abspath_inc = ABSPATH . 'wp-admin';
                $array = array(
                    'editor' => 'editor',
                    'media-upload' => 'media-upload'
                );
                foreach( $array as $k => $v ) {
                    if ( file_exists( "{$abspath_inc}/js/$v.js" ) ) {
                        if( !in_array( $k, $wp_scripts->queue, true ) ) $result .= "<script type='text/javascript' src='{$admin_url}js/$v.js?$version'></script>";
                    }
                }


                $atts['tinymce'] = true;
                if( $atts['force_br']=='true' ) {
                    $atts['tinymce'] = array(
                        'forced_root_block' => false,
                        'force_br_newlines' => true,
                        'force_p_newlines' => false,
                        'convert_newlines_to_brs' => true,
                    );
                }
                $editor_settings = array(
                    'editor_class' => 'super-shortcode-field',
                    'textarea_name' => $atts['name'],
                    'media_buttons' => filter_var( $atts['media_buttons'], FILTER_VALIDATE_BOOLEAN ),
                    'wpautop' => filter_var( $atts['wpautop'], FILTER_VALIDATE_BOOLEAN ),
                    'editor_height' => $atts['editor_height'],
                    'teeny' => filter_var( $atts['teeny'], FILTER_VALIDATE_BOOLEAN ),
                    'tinymce' => $atts['tinymce'],
                    'quicktags' => filter_var( $atts['quicktags'], FILTER_VALIDATE_BOOLEAN ),
                    'drag_drop_upload' => filter_var( $atts['drag_drop_upload'], FILTER_VALIDATE_BOOLEAN )
                );
                ob_start();
                wp_editor( $atts['value'], $atts['name'] . '-' . self::$current_form_id, $editor_settings );
                $editor_html = ob_get_clean();
                $common_attributes = self::common_attributes( $atts, $tag, $settings );
                $editor_html = str_replace( '></textarea>', $common_attributes . ' data-force-br="' . $atts['force_br'] . '" data-teeny="' . $atts['teeny'] . '" data-incl-url="' . $includes_url . '"></textarea>', $editor_html );
                $editor_html = str_replace( '<textarea', '<textarea id="' . $atts['name'] . '-' . self::$current_form_id . '"', $editor_html );
                $result .= str_replace( 'super-shortcode-field', 'super-shortcode-field super-text-editor', $editor_html );
            }else{
                $atts['tinymce'] = true;
                if( $atts['force_br']=='true' ) {
                    $atts['tinymce'] = array(
                        'forced_root_block' => false,
                        'force_br_newlines' => true,
                        'force_p_newlines' => false,
                        'convert_newlines_to_brs' => true,
                    );
                }
                $editor_settings = array(
                    'editor_class' => 'super-shortcode-field',
                    'textarea_name' => $atts['name'],
                    'media_buttons' => filter_var( $atts['media_buttons'], FILTER_VALIDATE_BOOLEAN ),
                    'wpautop' => filter_var( $atts['wpautop'], FILTER_VALIDATE_BOOLEAN ),
                    'editor_height' => $atts['editor_height'],
                    'teeny' => filter_var( $atts['teeny'], FILTER_VALIDATE_BOOLEAN ),
                    'tinymce' => $atts['tinymce'],
                    'quicktags' => filter_var( $atts['quicktags'], FILTER_VALIDATE_BOOLEAN ),
                    'drag_drop_upload' => filter_var( $atts['drag_drop_upload'], FILTER_VALIDATE_BOOLEAN )
                );
                ob_start();
                wp_editor( $atts['value'], $atts['name'] . '-' . self::$current_form_id, $editor_settings );
                $editor_html = ob_get_clean();
                $common_attributes = self::common_attributes( $atts, $tag, $settings );
                $editor_html = str_replace( '<textarea','<textarea '.$common_attributes.' ', $editor_html );
                $editor_html = str_replace( '<textarea', '<textarea id="' . $atts['name'] . '-' . self::$current_form_id . '"', $editor_html );
                $result .= str_replace( 'super-shortcode-field', 'super-shortcode-field super-text-editor super-initialized', $editor_html );
            }
        }else{

            // @since 1.9 - custom class
            if( !isset( $atts['class'] ) ) $atts['class'] = '';

            $result .= '<textarea tabindex="-1" class="super-shortcode-field' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"';
            $result .= ' name="' . $atts['name'] . '"';
            if( $atts['height']>0 ) {
                $result .= ' style="min-height:' . $atts['height'] . 'px;" ';
            }
            $result .= self::common_attributes( $atts, $tag, $settings );

            // @since 3.6.0 - convert <br /> tags to \n
            $value = preg_replace('#<br\s*/?>#i', "\n", $atts['value']);
            $result .= ' >' . $value . '</textarea>';

            // @since 4.9.3 - Adaptive placeholders
            $result .= self::adaptivePlaceholders( $settings, $atts, $tag );

        }

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }
    public static function dropdown( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {
        global $woocommerce;

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation
        $placeholder = (!empty($atts['placeholder']) ? $atts['placeholder'] : '');
        $placeholderFilled = (!empty($atts['placeholderFilled']) ? $atts['placeholderFilled'] : '');

        // @since 3.5.0 - google distance calculation between 2 addresses for dropdown
        $data_attributes = '';
        $distance_calculator_class = '';
        if( !isset( $atts['enable_distance_calculator'] ) ) $atts['enable_distance_calculator'] = '';
        if( $atts['enable_distance_calculator']=='true' ) {
            if( !isset( $atts['distance_method'] ) ) $atts['distance_method'] = 'start';
            if( !isset( $atts['distance_value'] ) ) $atts['distance_value'] = 'distance';
            if( !isset( $atts['distance_units'] ) ) $atts['distance_units'] = 'metric';
            if( !isset( $atts['distance_field'] ) ) $atts['distance_field'] = '';
            $data_attributes .= ' data-distance-method="'.$atts['distance_method'].'"';
            $data_attributes .= ' data-distance-value="'.$atts['distance_value'].'"';
            $data_attributes .= ' data-distance-units="'.$atts['distance_units'].'"';
            $data_attributes .= ' data-distance-field="'.$atts['distance_field'].'"';
            if( $atts['distance_method']=='start' ) {
                $data_attributes .= ' data-distance-destination="'.$atts['distance_destination'].'"';
            }else{
                $data_attributes .= ' data-distance-start="'.$atts['distance_start'].'"';
            }
            $distance_calculator_class .= ' super-distance-calculator';
        }

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);
        
        // @since   4.7.7 - make sure we do not lose the default placeholder
        // This is required for dynamic columns
        $atts['default_placeholder'] = $atts['placeholder'];
        $get_items = self::get_items(array(), $tag, $atts, '', $settings, $entry_data);
        if(empty($atts['language_switch'])){
            $items = $get_items['items'];
        }else{
            $items = $atts['dropdown_items'];
        }
        $atts = $get_items['atts'];

        $result = self::opening_tag( $tag, $atts );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );
        
        $multiple = '';
        if( !isset( $atts['maxlength'] ) ) $atts['maxlength'] = 0;
        if( !isset( $atts['minlength'] ) ) $atts['minlength'] = 0;
        if( ($atts['minlength']>1) || ($atts['maxlength']>1) ) $multiple = ' multiple';

        if(empty($atts['language_switch'])){
            $result .= '<input type="hidden" class="super-shortcode-field';
            $result .= $distance_calculator_class;
            $result .= ($atts['class']!='' ? ' ' . $atts['class'] : '');
            $result .= '"';
            $result .= ($atts['enable_distance_calculator']=='true' ? $data_attributes : '');
            $result .= ' name="' . esc_attr( $atts['name'] ) . '" value="' . esc_attr($atts['value']) . '"';
            $result .= self::common_attributes( $atts, $tag, $settings );
            $result .= ' />';
        }

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        // @since 1.2.8     - auto scroll to value after key press
        if(empty($atts['disable_filter'])){
            $result .= '<input tabindex="-1" type="text" name="super-dropdown-search" value="" data-logic="' . esc_attr($atts['filter_logic']) . '" />';
        }

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $result .= '<ul class="super-dropdown-list' . $multiple . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '">';
        $item_placeholder = $atts['placeholder'];
        if(!empty($get_items['atts']['placeholder'])) {
            $item_placeholder = $get_items['atts']['placeholder'];
        }
        
        if(!empty($atts['language_switch'])){
            $result .= '<li data-value="" class="super-item super-placeholder">';
            $result .= '<img src="'. esc_url(SUPER_PLUGIN_FILE . 'assets/images/blank.gif') . '" class="flag flag-' . $atts['default_language']['flag'] . '" />';
            $result .= '<span>' . $atts['default_language']['language'] . '</span>';
            $result .= '</li>';
        }else{
            $result .= '<li data-value="" class="super-item super-placeholder">' . $item_placeholder . '</li>';
        }
        foreach( $items as $v ) {
            if(!empty($atts['language_switch'])){
                $result .= '<li class="super-item' . ($v['flag']==$atts['default_language']['flag'] ? ' super-active' : '') . '" data-value="' . esc_attr($v['value']) . '">';
                $result .= '<img src="'. esc_url(SUPER_PLUGIN_FILE . 'assets/images/blank.gif') . '" class="flag flag-' . $v['flag'] . '" />';
                $result .= '<span>' . $v['language'] . '</span>';
                $result .= '</li>';
            }else{
                $result .= $v;
            }
        }
        $result .= '</ul>';
        $result .= '<span class="super-dropdown-arrow"><span class="super-after"><i class="fas fa-caret-down"></i></span></span>';
        // @since 4.9.3 - Adaptive placeholders
        $atts['placeholder'] = $placeholder;
        $atts['placeholderFilled'] = $placeholderFilled;
        $result .= self::adaptivePlaceholders( $settings, $atts, $tag );
        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;    
    }
    public static function checkbox( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        // @since 4.7.7 - new radio and checkbox layout options
        $layout = $atts['display'];
        $classes = ' display-' . str_replace('_', '-', $layout);
        if($layout=='grid'){
            $classes .= ' super-c-' . $atts['display_columns'];
        }

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);

        $result = self::opening_tag( $tag, $atts, $classes );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $get_items = self::get_items(array(), $tag, $atts, '', $settings, $entry_data);
        $items = $get_items['items'];
        $atts = $get_items['atts'];
        $selected_items = explode( ",", $atts['value'] );

        if($layout=='grid'){
            $max_columns = (isset($atts['display_columns']) ? absint($atts['display_columns']) : 4);
            $max_rows = (isset($atts['display_rows']) ? absint($atts['display_rows']) : 3);
            $columns = 0;
            $rows = 0;
            if( (empty($atts['display'])) || (!empty($atts['display']) && $atts['display']!='slider') ){
                $result .= '<div class="super-items-list">';
            }
            foreach( $items as $v ) {
                if($rows>=$max_rows && $max_rows!=0){
                    $columns++; // 1
                    if($columns>=$max_columns){
                        $columns = 0;
                        $rows++;
                    }
                }else{
                    $result .= $v;
                    $columns++; // 1
                    if($columns>=$max_columns){
                        $columns = 0;
                        $rows++;
                    }
                }
            }
            if( (empty($atts['display'])) || (!empty($atts['display']) && $atts['display']!='slider') ){
                $result .= '</div>';
            }

        }else{
            // Check if this the "Slider" layout is enabled, if so we will add a wrapper so that the "CarouselJS" can initilize the slider/carousel
            if(!empty($atts['display']) && $atts['display']=='slider'){
                wp_enqueue_style( 'super-carousel', SUPER_PLUGIN_FILE.'assets/css/frontend/carousel.css', array(), SUPER_VERSION );    
                wp_enqueue_script( 'super-carousel', SUPER_PLUGIN_FILE . 'assets/js/frontend/carousel.js', array( 'super-common' ), SUPER_VERSION );
                $result .= '<div class="carouseljs">';
                // Override default configuration for the carousel based on element settings
                $result .= '<textarea>{"columns":"' . absint($atts['display_columns']) . '","minwidth":"' . absint($atts['display_minwidth']) . '","navigation":' . ($atts['display_nav']===true ? 'true' : 'false') . ',"dots":' . ($atts['display_dots_nav']===true ? 'true' : 'false') . '}</textarea>';
            }
            if( (empty($atts['display'])) || (!empty($atts['display']) && $atts['display']!='slider') ){
                $result .= '<div class="super-items-list">';
            }
            foreach( $items as $v ) {
                $result .= $v;
            }
            if( (empty($atts['display'])) || (!empty($atts['display']) && $atts['display']!='slider') ){
                $result .= '</div>';
            }
            if(!empty($atts['display']) && $atts['display']=='slider'){
                $result .= '</div>';
            }
        }

        $result .= '<input class="super-shortcode-field" type="hidden"';
        $result .= ' name="' . esc_attr( $atts['name'] ) . '" value="' . esc_attr(implode(',',$selected_items)) . '"';
        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }
    public static function radio( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation
       
        // @since 4.7.7 - new radio and checkbox layout options
        $layout = $atts['display'];
        $classes = ' display-' . str_replace('_', '-', $layout);
        if($layout=='grid'){
            $classes .= ' super-c-' . $atts['display_columns'];
        }

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);

        $result = self::opening_tag( $tag, $atts, $classes );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';     

        $get_items = self::get_items(array(), $tag, $atts, '', $settings, $entry_data);
        $items = $get_items['items'];
        $atts = $get_items['atts'];

        if($layout=='grid'){
            $max_columns = (isset($atts['display_columns']) ? absint($atts['display_columns']) : 4);
            $max_rows = (isset($atts['display_rows']) ? absint($atts['display_rows']) : 3);
            $columns = 0;
            $rows = 0;
            if( (empty($atts['display'])) || (!empty($atts['display']) && $atts['display']!='slider') ){
                $result .= '<div class="super-items-list">';
            }
            foreach( $items as $v ) {
                if($rows>=$max_rows && $max_rows!=0){
                    $columns++; // 1
                    if($columns>=$max_columns){
                        $columns = 0;
                        $rows++;
                    }
                }else{
                    $result .= $v;
                    $columns++; // 1
                    if($columns>=$max_columns){
                        $columns = 0;
                        //$result .= '<div class="super-line-break"></div>';
                        $rows++;
                    }
                }
            }
            if( (empty($atts['display'])) || (!empty($atts['display']) && $atts['display']!='slider') ){
                $result .= '</div>';
            }

        }else{
            // Check if this the "Slider" layout is enabled, if so we will add a wrapper so that the "CarouselJS" can initilize the slider/carousel
            if(!empty($atts['display']) && $atts['display']=='slider'){
                wp_enqueue_style( 'super-carousel', SUPER_PLUGIN_FILE.'assets/css/frontend/carousel.css', array(), SUPER_VERSION );    
                wp_enqueue_script( 'super-carousel', SUPER_PLUGIN_FILE . 'assets/js/frontend/carousel.js', array( 'super-common' ), SUPER_VERSION );
                $result .= '<div class="carouseljs">';
                // Override default configuration for the carousel based on element settings
                $result .= '<textarea>{"columns":"' . absint($atts['display_columns']) . '","minwidth":"' . absint($atts['display_minwidth']) . '","navigation":' . ($atts['display_nav']===true ? 'true' : 'false') . ',"dots":' . ($atts['display_dots_nav']===true ? 'true' : 'false') . '}</textarea>';
            }
            if( (empty($atts['display'])) || (!empty($atts['display']) && $atts['display']!='slider') ){
                $result .= '<div class="super-items-list">';
            }
            foreach( $items as $v ) {
                $result .= $v;
            }
            if( (empty($atts['display'])) || (!empty($atts['display']) && $atts['display']!='slider') ){
                $result .= '</div>';
            }
            if(!empty($atts['display']) && $atts['display']=='slider'){
                $result .= '</div>';
            }
        }

        $result .= '<input class="super-shortcode-field" type="hidden"';
        $result .= ' name="' . esc_attr( $atts['name'] ) . '" value="' . esc_attr($atts['value']) . '"';
        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }
    public static function file( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        $dir = SUPER_PLUGIN_FILE . 'assets/js/frontend/jquery-file-upload/';
        wp_enqueue_script( 'jquery-ui-widget' );
        wp_enqueue_script( 'jquery-iframe-transport', $dir . 'jquery.iframe-transport.js', array( 'jquery', 'jquery-ui-widget' ), SUPER_VERSION, false );
        wp_enqueue_script( 'jquery-fileupload', $dir . 'jquery.fileupload.js', array( 'jquery', 'jquery-ui-widget' ), SUPER_VERSION, false );
        wp_enqueue_script( 'jquery-fileupload-process', $dir . 'jquery.fileupload-process.js', array( 'jquery', 'jquery-ui-widget' ), SUPER_VERSION, false );
        wp_enqueue_script( 'jquery-fileupload-validate', $dir . 'jquery.fileupload-validate.js', array( 'jquery', 'jquery-ui-widget' ), SUPER_VERSION, false );
        $result = self::opening_tag( $tag, $atts );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );
        
        // @since 1.2.8
        if( !isset( $atts['image'] ) ) $atts['image'] = '';
        if( !isset( $atts['enable_image_button'] ) ) $atts['enable_image_button'] = '';

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $result .= '<div class="super-fileupload-button' . (($atts['enable_image_button']=='true' && $atts['image']!='')  ? ' super-fileupload-image' : '') . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"';
        $style = '';
        if( !isset( $atts['extensions'] ) ) $atts['extensions'] = 'jpg|jpeg|png|gif|pdf';
        $extensions = explode('|', $atts['extensions']);
        foreach($extensions as $k => $v){
            $extensions[$v] = $v;
            unset($extensions[$k]);
        }
        foreach($extensions as $k => $v){
            $upercase = strtoupper($v);
            if( (ctype_lower($v)) && (!isset($extensions[$upercase])) ) {
               $extensions[$upercase] = $upercase;
            }
        }
        $extensions = implode('|', $extensions);

        if( !isset( $atts['width'] ) ) $atts['width'] = 0;
        if( $atts['width']!=0 ) $style .= 'width:' . $atts['width'] . 'px;';
        if( !empty( $styles ) ) $style .= $styles;
        if( !empty( $style ) ) $result .= ' style="'.$style.'"';
        $result .= '>';

        // @since 1.2.8
        if( ($atts['enable_image_button']=='true') && ($atts['image']!='') ) {
            if( !isset( $atts['image'] ) ) $atts['image'] = 0;
            $attachment_id = absint($atts['image']);
            if( $attachment_id===0 ) {
                $url = SUPER_PLUGIN_FILE . 'assets/images/image-icon.png';
            }else{
                $title = get_the_title( $attachment_id );
                $url = wp_get_attachment_url( $attachment_id );
                $alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
            } 
            $img_styles = '';
            if( !isset( $atts['max_img_width'] ) ) $atts['max_img_width'] = 0;
            if( !isset( $atts['max_img_height'] ) ) $atts['max_img_height'] = 0;
            if( $atts['max_img_width']>0 ) {
                $img_styles .= 'max-width:' . $atts['max_img_width'] . 'px;';
            }
            if( $atts['max_img_height']>0 ) {
                $img_styles .= 'max-height:' . $atts['max_img_height'] . 'px;';
            }
            if($img_styles!='') $img_styles = 'style="' . esc_attr($img_styles) . '" ';
            $result .= '<img src="' . esc_url($url) . '" ' . $img_styles . 'alt="' . esc_attr($alt) . '" title="' . esc_attr($title) . '" />';
        }else{
            $result .= '<i class="fas fa-plus"></i><span class="super-fileupload-button-text">' . esc_html($atts['placeholder']) . '</span>';
        }

        $result .= '</div>';
        $atts['placeholder'] = '';

        $files = '';
        // @since   2.9.0 - autopopulate with last entry data
        if( ($entry_data!=null) && (isset($entry_data[$atts['name']])) ) {
            if(isset($entry_data[$atts['name']]['files'])) {
                foreach( $entry_data[$atts['name']]['files'] as $k => $v ) {
                    if( isset($v['url']) ) {
                        // Before adding the file, check if the file still exists.
                        // In some cases this might not be the case due to the file being deleted from the server manually
                        // or when the setting "Delete files from server after form submissions" is enabled
                        // If file has attachment ID, always try to retrieve the url via WP core function
                        if(!empty($v['attachment'])){
                            $v['url'] = wp_get_attachment_url($v['attachment']);
                        }
                        $file = $v['url'];
                        $fileType = (!empty($v['type']) ? $v['type'] : '');
                        $basename = basename($file);
                        $file_headers = @get_headers($file);
                        if($file_headers && (strpos($file_headers[0], '404'))===false) {
                            // File exists, let's add it to the list
                            $files .= '<div class="super-uploaded" data-name="' . esc_attr($basename) . '" title="' . esc_attr($basename) . '" data-type="' . esc_attr($fileType) . '" data-url="' . esc_url($file) . '">';
                                if(!empty($fileType) && (strpos($fileType, 'image/'))===0){
                                    $files .= '<span class="super-fileupload-image super-file-type-' . esc_attr(str_replace('/', '-', $fileType)) . '">';
                                        $files .= '<img src="' . esc_url($file) . '">';
                                    $files .= '</span>';
                                }else{
                                    $files .= '<span class="super-fileupload-document super-file-type-' . esc_attr(str_replace('/', '-', $fileType)) . '"></span>';
                                }
                                $files .= '<span class="super-fileupload-info">';
                                    $split = explode('.', $basename);
                                    $filename = $split[0];
                                    $ext = $split[1];
                                    if (strlen($filename) > 10) $filename = substr($filename, 0, 10).'...';
                                    $files .= '<span class="super-fileupload-name">' . esc_html($filename) . '.' . $ext . '</span>';
                                    $files .= '<span class="super-fileupload-delete"></span>';
                                $files .= '</span>';
                            $files .= '</div>';
                        }
                    }
                }
            }
        }
        if( !isset( $atts['maxlength'] ) ) $atts['maxlength'] = 0;
        if( !isset( $atts['minlength'] ) ) $atts['minlength'] = 0;

        $result .= '<input tabindex="-1" class="super-shortcode-field super-fileupload" type="file" name="files[]" ';
        $result .= ' data-file-size="' . $atts['filesize'] . '"';
        $singleFileSizeMax = absint($atts['filesize']);
        $totalFilesAllowed = absint($atts['maxlength']);
        if($totalFilesAllowed===0){
            $combinedUploadLimit = $singleFileSizeMax;
        }else{
            $combinedUploadLimit = absint($singleFileSizeMax*$totalFilesAllowed);
        } 
        $result .= ' data-upload-limit="' . $combinedUploadLimit . '"';
        $result .= ' data-accept-file-types="' . $extensions . '"';
        if( ($atts['minlength']>1) || ($atts['maxlength']>1) ) $result .= ' multiple';
        $result .= ' />';
        $result .= '<input class="super-active-files" type="hidden" value="" name="' . $atts['name'] . '"';
        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';
        $result .= '<div class="super-progress-bar"></div>';
        $result .= '<div class="super-fileupload-files">';
            $result .= $files;
        $result .= '</div>';
        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }
    public static function date( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation
        
        wp_enqueue_script( 'jquery-ui-datepicker', false, array( 'jquery' ), SUPER_VERSION );
        wp_enqueue_script( 'date-format', SUPER_PLUGIN_FILE . 'assets/js/frontend/date-format.js' );
        // @since 4.9.3 - datepicker localizations
        if(empty($atts['localization'])) $atts['localization'] = '';
        if(!empty($atts['localization'])){
            wp_enqueue_script( 'jquery-ui-datepicker-' . $atts['localization'], SUPER_PLUGIN_FILE . 'assets/js/frontend/datepicker/i18n/datepicker-' . $atts['localization'] . '.js', array(), SUPER_VERSION );
        }
        wp_enqueue_script( 'jquery-ui-multidatespicker', SUPER_PLUGIN_FILE . 'assets/js/frontend/datepicker/jquery-ui.multidatespicker.js', array('jquery-ui-datepicker'), SUPER_VERSION );

        if( !isset( $atts['value'] ) ) $atts['value'] = '';

        // @since 1.3 - Return the current date as default value 
        $format = $atts['format'];
        if( $format=='custom' ) $format = $atts['custom_format'];
        if( !isset( $atts['current_date'] ) ) $atts['current_date'] = '';
        if( $atts['current_date']=='true' ) {
            $new_format = $format;
            if (preg_match("/dd/i", $new_format)) {
                $new_format = str_replace('dd', 'd', $new_format);
            }else{
                $new_format = str_replace('d', 'j', $new_format);
            }
            if (preg_match("/mm/i", $new_format)) {
                $new_format = str_replace('mm', 'm', $new_format);
            }else{
                $new_format = str_replace('m', 'n', $new_format);
            }
            if (preg_match("/oo/i", $new_format)) {
                $new_format = str_replace('oo', 'z', $new_format);
            }else{
                $new_format = str_replace('o', 'z', $new_format);
            }
            if (preg_match("/DD/i", $new_format)) {
                $new_format = str_replace('DD', 'l', $new_format);
            }
            if (preg_match("/MM/i", $new_format)) {
                $new_format = str_replace('MM', 'F', $new_format);
            }
            $new_format = str_replace('yy', 'Y', $new_format);
            $atts['value'] = date_i18n($new_format);
            $atts['absolute_default'] = $atts['value'];
        }

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);

        $result = self::opening_tag( $tag, $atts );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $result .= '<input tabindex="-1" class="super-shortcode-field super-datepicker' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '" type="text" autocomplete="false" ';


        // @since 1.1.8 - added option to select an other datepicker to achieve date range with 2 datepickers (useful for booking forms)
        if( !isset( $atts['connected_min'] ) ) $atts['connected_min'] = '';
        if( !isset( $atts['connected_max'] ) ) $atts['connected_max'] = '';

        // @since 1.2.5 - added option to add or deduct days based on connected datepicker
        if( !isset( $atts['connected_min_days'] ) ) $atts['connected_min_days'] = '1';
        if( !isset( $atts['connected_max_days'] ) ) $atts['connected_max_days'] = '1';

        if( !isset( $atts['range'] ) ) $atts['range'] = '-100:+5';
        if( !isset( $atts['first_day'] ) ) $atts['first_day'] = '1'; // @since 3.1.0 - start day of the week


        // Javascript date format parameters:
        // yy = short year
        // yyyy = long year
        // M = month (1-12)
        // MM = month (01-12)
        // MMM = month abbreviation (Jan, Feb ... Dec)
        // MMMM = long month (January, February ... December)
        // d = day (1 - 31)
        // dd = day (01 - 31)
        // ddd = day of the week in words (Monday, Tuesday ... Sunday)
        // E = short day of the week in words (Mon, Tue ... Sun)
        // D - Ordinal day (1st, 2nd, 3rd, 21st, 22nd, 23rd, 31st, 4th...)
        // h = hour in am/pm (0-12)
        // hh = hour in am/pm (00-12)
        // H = hour in day (0-23)
        // HH = hour in day (00-23)
        // mm = minute
        // ss = second
        // SSS = milliseconds
        // a = AM/PM marker
        // p = a.m./p.m. marker

        $jsformat = $format;
        $jsformat = str_replace('DD', 'dddd', $jsformat);
        if (preg_match("/MM/i", $jsformat)) {
            $jsformat = str_replace('MM', 'MMMM', $jsformat);
        }else{
            if (preg_match("/M/i", $jsformat)) {
                $jsformat = str_replace('M', 'MMM', $jsformat);
            }
        }
        $jsformat = str_replace('mm', 'MM', $jsformat);
        if (preg_match("/yy/i", $jsformat)) {
            $jsformat = str_replace('yy', 'yyyy', $jsformat);
        }else{
            if (preg_match("/y/i", $jsformat)) {
                $jsformat = str_replace('y', 'yy', $jsformat);
            }
        }

        if(!isset($atts['changeMonth'])) $atts['changeMonth'] = 'true';
        if(!isset($atts['changeYear'])) $atts['changeYear'] = 'true';
        if(!isset($atts['showMonthAfterYear'])) $atts['showMonthAfterYear'] = 'false';
        if(!isset($atts['showWeek'])) $atts['showWeek'] = 'true';
        if(!isset($atts['numberOfMonths'])) $atts['numberOfMonths'] = '1';
        if(!isset($atts['showOtherMonths'])) $atts['showOtherMonths'] = 'false';
        if(!isset($atts['selectOtherMonths'])) $atts['selectOtherMonths'] = 'false';
        // Must be set `showOtherMonths` to false if `showOtherMonths` is not enabled
        if($atts['showOtherMonths']!='true') $atts['selectOtherMonths'] = 'false'; 

        $result .= ' value="' . esc_attr($atts['value']) . '" 
        name="' . esc_attr($atts['name']) . '" 
        data-format="' . esc_attr($format) . '" 
        data-jsformat="' . esc_attr($jsformat) . '" 
        data-connected-min="' . esc_attr($atts['connected_min']) . '" 
        data-connected-min-days="' . esc_attr($atts['connected_min_days']) . '" 
        data-connected-max="' . esc_attr($atts['connected_max']) . '" 
        data-connected-max-days="' . esc_attr($atts['connected_max_days']) . '" 
        data-range="' . esc_attr($atts['range']) . '" 
        data-first-day="' . esc_attr($atts['first_day']) . '"
        data-localization="' . esc_attr($atts['localization']) . '"
        data-change-month="' . esc_attr($atts['changeMonth']) . '"
        data-change-year="' . esc_attr($atts['changeYear']) . '"
        data-show-month-after-year="' . esc_attr($atts['showMonthAfterYear']) . '"
        data-show-week="' . esc_attr($atts['showWeek']) . '"
        data-number-of-months="' . esc_attr($atts['numberOfMonths']) . '"
        data-show-other-months="' . esc_attr($atts['showOtherMonths']) . '"
        data-select-other-months="' . esc_attr($atts['selectOtherMonths']) . '" ';

        // @since 1.5.0 - Allow work days selection
        if( !empty($atts['work_days']) ) {
            $result .= 'data-work-days="true"';
        }
        // @since 1.5.0 - Allow weekend selection
        if( !empty($atts['weekends']) ) {
            $result .= 'data-weekends="true"';
        }
        // @since 4.9.5 - Allow user to choose multiple dates
        if( !empty($atts['maxPicks']) ) {
            $result .= 'data-maxPicks="' . esc_attr($atts['maxPicks']) . '"';
        }
        if( !empty($atts['minPicks']) ) {
            $result .= 'data-minPicks="' . esc_attr($atts['minPicks']) . '"';
        }
        // @since 3.6.0 - Exclude specific days
        if( isset($atts['excl_days']) && $atts['excl_days']!='' ) {
            $result .= 'data-excl-days="' . esc_attr($atts['excl_days']) . '"';
        }
        // @since 4.9.46 - Override days exclusion
        if( isset($atts['excl_days_override']) && $atts['excl_days_override']!='' ) {
            $result .= 'data-excl-days-override="' . esc_attr($atts['excl_days_override']) . '"';
        }
        // @since 4.9.3 - Exclude specific dates
        if( isset($atts['excl_dates']) && $atts['excl_dates']!='' ) {
            $result .= 'data-excl-dates="' . esc_attr($atts['excl_dates']) . '"';
        }
        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' readonly="true" />';

        // @since 4.9.3 - Adaptive placeholders
        $result .= self::adaptivePlaceholders( $settings, $atts, $tag );

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }
    public static function time( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {
        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        wp_enqueue_script( 'jquery-timepicker', SUPER_PLUGIN_FILE . 'assets/js/frontend/timepicker.js', array( 'jquery' ), SUPER_VERSION, false );

        // @since 1.3 - Return the current date as default value
        if( !isset( $atts['current_time'] ) ) $atts['current_time'] = '';
        if( $atts['current_time']=='true' ) {
            $atts['value'] = current_time($atts['format']);
        }

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);        
        
        $result = self::opening_tag( $tag, $atts );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $result .= '<input tabindex="-1" class="super-shortcode-field super-timepicker' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '" type="text" autocomplete="false" ';
        if( !isset( $atts['range'] ) ) $atts['range'] = '';
        $result .= ' value="' . esc_attr($atts['value']) . '" name="' . $atts['name'] . '" data-format="' . $atts['format'] . '" data-step="' . $atts['step'] . '" data-range="' . $atts['range'] . '" data-duration="' . $atts['duration'] . '"';
        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';
        
        // @since 4.9.3 - Adaptive placeholders
        $result .= self::adaptivePlaceholders( $settings, $atts, $tag );

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }    
    public static function rating( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation
        
        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);   

        $result = self::opening_tag( $tag, $atts );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );
        $result .= '<div class="super-rating">';

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $i=1;
        while( $i < 6 ) {
            $result .= '<i class="fas fa-star super-rating-star ' . ($i<=(int) $atts['value'] ? 'super-active ' : '') . $atts['class'] . '"></i>';
            $i++;
        }

        $result .= '<input class="super-shortcode-field super-star-rating" type="hidden"';
        $result .= ' value="' . esc_attr($atts['value']) . '" name="' . $atts['name'] . '"';
        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        $result .= '</div>';
        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }

    public static function countries( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {
        $tag = 'dropdown';

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);   

        $result = self::opening_tag( $tag, $atts );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );
        $multiple = '';
        if( !isset( $atts['maxlength'] ) ) $atts['maxlength'] = 0;
        if( !isset( $atts['minlength'] ) ) $atts['minlength'] = 0;
        if( ($atts['minlength']>1) || ($atts['maxlength']>1) ) $multiple = ' multiple';

        $result .= '<input class="super-shortcode-field" type="hidden"';
        $result .= ' value="' . esc_attr($atts['value']) . '" name="' . $atts['name'] . '"';
        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        // @since 1.2.8     - auto scroll to value after key press
        if(empty($atts['disable_filter'])){
            $result .= '<input tabindex="-1" type="text" name="super-dropdown-search" value="" data-logic="' . esc_attr($atts['filter_logic']) . '" />';
        }

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $result .= '<ul class="super-dropdown-list' . $multiple . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '">';
        if( !empty( $atts['placeholder'] ) ) {
            $result .= '<li data-value="" class="super-item super-placeholder">' . $atts['placeholder'] . '</li>';
        }else{
            $result .= '<li data-value="" class="super-item super-placeholder"></li>';
        }
        
        // @since 1.1.4 - use wp_remote_fopen instead of curl
        $countries = array();
        if ( file_exists( SUPER_PLUGIN_DIR . '/countries.txt' ) ) {
            $countries = wp_remote_fopen( SUPER_PLUGIN_FILE . 'countries.txt' );
            $countries = explode( "\n", $countries );
        }

        // @since 2.8.0 - give the possibility to filter countries list (currently used by register & login add-on for woocommerce countries)
        $countries = apply_filters( 'super_countries_list_filter', $countries, array( 'name'=>$atts['name'], 'settings'=>$settings ) );

        foreach( $countries as $k => $v ){
            $v = trim($v);
            $result .= '<li class="super-item" data-value="' . ( is_string($k) ? esc_attr($k) : esc_attr($v) ) . '" data-search-value="' . esc_attr( $v ) . '">' . $v . '</li>'; 
        }
        $result .= '</ul>';
        $result .= '<span class="super-dropdown-arrow"><span class="super-after"><i class="fas fa-caret-down"></i></span></span>';
        // @since 4.9.3 - Adaptive placeholders
        $result .= self::adaptivePlaceholders( $settings, $atts, $tag );
        $result .= '</div>';

        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }
    public static function password( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);

        $result = self::opening_tag( $tag, $atts );
        $result .= self::opening_wrapper( $atts, $inner, $shortcodes, $settings );

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $result .= '<input tabindex="-1" class="super-shortcode-field' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '" type="password"';
        $result .= ' value="' . esc_attr($atts['value']) . '" name="' . $atts['name'] . '"';
        $result .= self::common_attributes( $atts, $tag, $settings );
        $result .= ' />';

        // @since 4.9.3 - Adaptive placeholders
        $result .= self::adaptivePlaceholders( $settings, $atts, $tag );

        // @since 1.2.5     - custom regex validation
        if( !empty($atts['custom_regex']) ) $result .= self::custom_regex( $atts['custom_regex'] );

        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }
    public static function hidden( $tag, $atts, $inner, $shortcodes=null, $settings=null, $entry_data=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );

        if( !isset( $atts['exclude'] ) ) $atts['exclude'] = 0;
        if( !isset( $atts['exclude_entry'] ) ) $atts['exclude_entry'] = '';

        // @since 2.8.0 - invoice numbers
        if( !isset( $atts['code_invoice'] ) ) $atts['code_invoice'] = '';
        if( !isset( $atts['code_invoice_padding'] ) ) $atts['code_invoice_padding'] = '';

        // @since 2.2.0 - random code generation
        if( !isset( $atts['enable_random_code'] ) ) $atts['enable_random_code'] = '';
        $codeSettings = array();
        if($atts['enable_random_code']=='true'){
            if( !isset( $atts['code_length'] ) ) $atts['code_length'] = 7;
            if( !isset( $atts['code_characters'] ) ) $atts['code_characters'] = '1';
            if( !isset( $atts['code_prefix'] ) ) $atts['code_prefix'] = '';
            if( !isset( $atts['code_suffix'] ) ) $atts['code_suffix'] = '';
            if( !isset( $atts['code_uppercase'] ) ) $atts['code_uppercase'] = '';
            if( !isset( $atts['code_lowercase'] ) ) $atts['code_lowercase'] = '';
            $codeSettings = array(
                'len' => $atts['code_length'],
                'char' => $atts['code_characters'],
                'pre' => $atts['code_prefix'],
                'inv' => $atts['code_invoice'],
                'invp' => $atts['code_invoice_padding'],
                'suf' => $atts['code_suffix'],
                'upper' => $atts['code_uppercase'],
                'lower' => $atts['code_lowercase']
            );
        }

        // Get default value
        $atts['value'] = self::get_default_value($tag, $atts, $settings, $entry_data);

        $classes = ' hidden';
        $result = self::opening_tag( $tag, $atts, $classes );

        $result .= '<input class="super-shortcode-field" type="hidden"';
        if( !empty($atts['name']) ) $result .= ' name="' . $atts['name'] . '"';
        $result .= ' value="' . esc_attr($atts['value']) . '" data-default-value="' . esc_attr($atts['value']) . '" data-absolute-default="' . esc_attr($atts['value']) . '"';
        if( !empty($atts['email']) ) $result .= ' data-email="' . $atts['email'] . '"';
        if( !empty($atts['exclude']) ) $result .= ' data-exclude="' . $atts['exclude'] . '"';
        if( !empty($atts['exclude_entry']) ) $result .= ' data-exclude-entry="' . $atts['exclude_entry'] . '"';
        if( $atts['enable_random_code']=='true' ) $result .= ' data-code="' . $atts['enable_random_code'] . '"';
        if( $atts['code_invoice']=='true' ) $result .= ' data-invoice-padding="' . $atts['code_invoice_padding'] . '"';

        if(!empty($codeSettings)) $result .= ' data-codeSettings="' . esc_attr(json_encode($codeSettings)) . '"';
        $result .= ' />';

        $result .= self::loop_variable_conditions( $atts );
        $result .= '</div>';
        return $result;
    }

    public static function recaptcha( $tag, $atts ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        
        $global_settings = SUPER_Common::get_global_settings();
        if(empty($atts['version'])) $atts['version'] = 'v2';
        $class = '';
        if($atts['version']==='v3'){
            $class = 'super-remove-margin';
            if( empty( $global_settings['form_recaptcha_v3'] ) ) $global_settings['form_recaptcha_v3'] = '';
            if( empty( $global_settings['form_recaptcha_v3_secret'] ) ) $global_settings['form_recaptcha_v3_secret'] = '';
            wp_enqueue_script('recaptcha', '//www.google.com/recaptcha/api.js?onload=SUPERreCaptcha&render=' . $global_settings['form_recaptcha_v3']);
        }else{
            wp_enqueue_script('recaptcha', '//www.google.com/recaptcha/api.js?onload=SUPERreCaptcha&render=explicit');
        }
        $result = self::opening_tag( $tag, $atts, $class );

        if( empty( $atts['error'] ) ) $atts['error'] = '';
        if( empty( $atts['align'] ) ) $atts['align'] = '';
        if( !empty( $atts['align'] ) ) $atts['align'] = ' align-' . $atts['align'];

        $api_missing_msg = sprintf( 
            esc_html__( 
                'Please enter your reCAPTCHA API keys in %sSuper Forms > Settings > Form Settings%s',
                'super-forms' 
            ),
            '<a target="_blank" href="' . esc_url(admin_url() . 'admin.php?page=super_settings#form-settings') . '">', 
            '</a>' 
        );
        if($atts['version']==='v3'){
            $result .= '<div class="super-recaptcha g-recaptcha" data-sitekey="' . $global_settings['form_recaptcha_v3'] . '" data-size="invisible"></div>';
            if( ( $global_settings['form_recaptcha_v3']=='' ) || ( $global_settings['form_recaptcha_v3_secret']=='' ) ) {
                $result .= '<strong style="color:red;">' . $api_missing_msg . '</strong>';
            }
        }else{
            if( empty( $global_settings['form_recaptcha'] ) ) $global_settings['form_recaptcha'] = '';
            if( empty( $global_settings['form_recaptcha_secret'] ) ) $global_settings['form_recaptcha_secret'] = '';
            $result .= '<div class="super-recaptcha' . $atts['align'] . '" data-sitekey="' . $global_settings['form_recaptcha'] . '"></div>';
            if( ( $global_settings['form_recaptcha']=='' ) || ( $global_settings['form_recaptcha_secret']=='' ) ) {
                $result .= '<strong style="color:red;">' . $api_missing_msg . '</strong>';
            }
        }

        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }

    public static function image( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'html_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation
        
        $result = self::opening_tag( $tag, $atts, 'align-' . $atts['alignment'] );
        $style = '';
        if( $atts['height']!=0 ) $style .= 'max-height:' . $atts['height'] . 'px;';
        if( $atts['width']!=0 ) $style .= 'max-width:' . $atts['width'] . 'px;';
        $url = '';
        if( !isset( $atts['link'] ) ) $atts['link'] = '';
        if( $atts['link']!='' ) {
            if( $atts['link']=='custom' ) {
                $url = $atts['custom_link'];
            }else{
                $url = get_permalink( $atts['link'] );
            }
            $url = ' href="' . esc_url($url) . '"';
        }
        $result .= '<div class="super-image align-' . esc_attr($atts['alignment']) . '" itemscope="itemscope" itemtype="https://schema.org/ImageObject">';
            $result .= '<div class="super-image-inner">';
                if( !isset( $atts['target'] ) ) $atts['target'] = '';
                if(!empty($url)) $result .= '<a target="' . esc_attr($atts['target']) . '"' . $url . '>';
                    // @since 1.9 - custom class
                    if( !isset( $atts['class'] ) ) $atts['class'] = '';
                    if( !isset( $atts['image'] ) ) $atts['image'] = 0;
                    $attachment_id = absint($atts['image']);
                    if( $attachment_id===0 ) {
                        $url = SUPER_PLUGIN_FILE . 'assets/images/image-icon.png';
                        $result .= '<img src="' . esc_url($url) . '"' . ($atts['class']!='' ? ' class="' . esc_attr($atts['class']) . '"' : '') . ' itemprop="contentURL"';
                    }else{
                        $title = get_the_title( $attachment_id );
                        $url = wp_get_attachment_url( $attachment_id );
                        $alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
                        $result .= '<img src="' . esc_url($url) . '"' . ($atts['class']!='' ? ' class="' . esc_attr($atts['class']) . '"' : '') . ' alt="' . esc_attr($alt) . '" title="' . esc_attr($title) . '" itemprop="contentURL"';
                    } 
                    if( !empty( $style ) ) $result .= ' style="' . esc_attr($style) . '"';
                    $result .= '>';
                if(!empty($url)) $result .= '</a>';
            $result .= '</div>';
        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }

    // @since 1.2.5
    public static function heading( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'html_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        $result = self::opening_tag( $tag, $atts );
        if( !empty($atts['title']) ) {
            $result .= '<div class="super-heading-title">';
            $styles = '';
            if(!empty($atts['heading_size']) && $atts['heading_size']!=='-1') $styles .= 'font-size:'.$atts['heading_size'].'px;'; 
            if(!empty($atts['heading_color'])) $styles .= 'color:'.$atts['heading_color'].';'; 
            if(!empty($atts['heading_weight']) && $atts['heading_weight']!=='none') $styles .= 'font-weight:'.$atts['heading_weight'].';'; 
            if(!empty($atts['heading_align']) && $atts['heading_align']!=='none') $styles .= 'text-align:'.$atts['heading_align'].';'; 
            if(!empty($atts['heading_margin'])) $styles .= 'margin:'.$atts['heading_margin'].';'; 
            if(!empty($atts['heading_line_height'])){
                if($atts['heading_line_height']!=='-1'){
                    if($atts['heading_line_height']==='0'){
                        $styles .= 'line-height:normal;';
                    }else{
                        $styles .= 'line-height:'.$atts['heading_line_height'].'px;';
                    }
                }
            }
            if(!empty($styles)) $styles = ' style="'.$styles.'"';
            $result .= '<'.$atts['size'] . ($atts['class']!='' ? ' class="' . $atts['class'] . '"' : '') . $styles . '>';
            $result .= stripslashes($atts['title']);
            $result .= '</'.$atts['size'].'>';
            $result .= '</div>';
        }
        if( !empty($atts['desc']) ) {
            $styles = '';
            if(!empty($atts['desc_size']) && $atts['desc_size']!=='-1') $styles .= 'font-size:'.$atts['desc_size'].'px;'; 
            if(!empty($atts['desc_color'])) $styles .= 'color:'.$atts['desc_color'].';'; 
            if(!empty($atts['desc_weight']) && $atts['desc_weight']!=='none') $styles .= 'font-weight:'.$atts['desc_weight'].';'; 
            if(!empty($atts['desc_align']) && $atts['desc_align']!=='none') $styles .= 'text-align:'.$atts['desc_align'].';'; 
            if(!empty($atts['desc_margin'])) $styles .= 'margin:'.$atts['desc_margin'].';'; 
            if(!empty($atts['desc_line_height'])){
                if($atts['desc_line_height']!=='-1'){
                    if($atts['desc_line_height']==='0'){
                        $styles .= 'line-height:normal;';
                    }else{
                        $styles .= 'line-height:'.$atts['desc_line_height'].'px;';
                    }
                }
            }
            if(!empty($styles)) $styles = ' style="'.$styles.'"';
            $result .= '<div class="super-heading-description' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"' . $styles . '>';
            $result .= stripslashes($atts['desc']);
            $result .= '</div>';
        }
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }

    public static function html( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'html_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $result = self::opening_tag( $tag, $atts );
        if( !isset( $atts['title'] ) ) $atts['title'] = '';
        if( $atts['title']!='' ) {
            $class = '';
            if( ( $atts['subtitle']=='' ) && ( $atts['html']=='' ) ) {
                $class = ' super-bottom-margin';
            }
            $result .= '<div class="super-html-title' . $class . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '">' . stripslashes($atts['title']) . '</div>';
        }
        if( !isset( $atts['subtitle'] ) ) $atts['subtitle'] = '';
        if( $atts['subtitle']!='' ) {
            $class = '';
            if( $atts['html']!='' ) { 
                $class = ' super-no-bottom-margin'; 
            }
            $result .= '<div class="super-html-subtitle' . $class . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '">' . stripslashes($atts['subtitle']) . '</div>';
        }
        if(!isset($atts['html'])) $atts['html'] = '';
        if( $atts['html']!='' ) { 
            
            // @since 2.3.0 - speed improvements for replacing {tags} in HTML fields
            preg_match_all('/{\K[^}]*(?=})/m', $atts['html'], $matches);
            
            // @since 3.8.0 - strip the advanced tags and only return the field name
            $data_fields = array();
            foreach($matches[0] as $k => $v){
                $v = explode(";", $v);
                $data_fields[$v[0]] = $v[0];
            }

            // @since 4.6.0 - also check for foreach loops, and also add those field tags as attribute
            $match = preg_match_all('/foreach\s?\(\s?[\'|"|\s|]?(.*?)[\'|"|\s|]?\)\s?:([\s\S]*?)(?:endforeach\s?;)/', $atts['html'], $matches, PREG_SET_ORDER, 0);
            foreach($matches as $k => $v){
                $original = $v[0];
                $data_fields[$v[1]] = $v[1];
                if( isset( $v[2] ) ) {
                    preg_match_all('/<%\K[^%>]*(?=%>)/m', $v[2], $matches, PREG_SET_ORDER, 0);
                    foreach($matches as $k => $v){
                        $v = explode(";", $v[0]);
                        if($v[0]!=='counter') $data_fields[$v[0]] = $v[0];
                    }
                }
            }

            // @since 4.6.0 - also check for if statements and also add those field tags as attribute
            $match = preg_match_all('/if\s?\(\s?[\'|"|\s|]?(.*?)[\'|"|\s|]?(==|!=|>=|<=|>|<|\?\?|!\?\?)\s?[\'|"|\s|]?(.*?)[\'|"|\s|]?\)\s?:([\s\S]*?)(?:endif\s?;|(?:elseif\s?:([\s\S]*?))endif\s?;)/', $atts['html'], $matches, PREG_SET_ORDER, 0);
            foreach($matches as $k => $v){
                if( isset( $v[1] ) ) {
                    preg_match_all('/{\K[^}]*(?=})/m', $v[1], $matches, PREG_SET_ORDER, 0);
                    foreach($matches as $k => $v){
                        $v = explode(";", $v[0]);
                        if($v[0]!=='counter') $data_fields[$v[0]] = $v[0];
                    }
                }
                if( isset( $v[3] ) ) {
                    preg_match_all('/{\K[^}]*(?=})/m', $v[3], $matches, PREG_SET_ORDER, 0);
                    foreach($matches as $k => $v){
                        $v = explode(";", $v[0]);
                        if($v[0]!=='counter') $data_fields[$v[0]] = $v[0];
                    }
                }
            }
            $field_names = implode('}{', $data_fields);
            $html = $atts['html'];

            if( (!is_admin()) || ( (isset($_POST['action'])) && ($_POST['action']=='super_listings_edit_entry' || $_POST['action']=='super_language_switcher') ) ) {
                if( !empty($atts['nl2br']) ) $html = nl2br($html);
                $html_code = do_shortcode(stripslashes($html));
            }else{
                if( !empty($_POST['action']) && $_POST['action']=='super_load_preview' && is_admin()){
                    if( !empty($atts['nl2br']) ) $html = nl2br($html);
                }
                $html_code = '<pre>'.htmlspecialchars(stripslashes($html)).'</pre>';
            }

            $dataFields = '';
            if(!empty($field_names)) $dataFields = ' data-fields="{' . $field_names . '}"';
            $result .= '<div class="super-html-content' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '"' . ($dataFields ? $dataFields : '') . '>' . $html_code . '</div>';
            $result .= '<textarea>' . do_shortcode( stripslashes($html) ) . '</textarea>';
        }
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }

    public static function divider( $tag, $atts ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'html_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );

        $classes = ' align-' . $atts['align'] . ' border-' . $atts['border'] . ' style-' . $atts['border_style'] . ' back-' . $atts['back'];
        $styles = 'padding-top:' . $atts['padding_top'] . 'px;padding-bottom:' . $atts['padding_bottom'] . 'px;';
        $result = self::opening_tag( $tag, $atts, $classes, $styles );
        $styles = '';
        $i_styles = '';
        if( $atts['width']!='100' ) {
            $styles .= 'display:inline-block;';
        }
        if( $atts['width']=='custom' ) {
            $styles .= 'width:' . $atts['custom_width'] . ';';
        }else{
            $styles .= 'width:' . $atts['width'].'%;';
        }
        if( $atts['color']!='' ) {
            $styles .= 'border-color:' . $atts['color'] . ';';
            $i_styles .= ' style="color:' . $atts['color'] . ';"';
        }
        if( $atts['thickness']!='' ) {
            $styles .= 'border-top-width:' . $atts['thickness'] . 'px;border-bottom-width:' . $atts['thickness'] . 'px;';
        }
        $styles .= 'height:' . $atts['height'] . 'px;';

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';

        $result .= '<div class="super-divider-inner' . ($atts['class']!='' ? ' ' . $atts['class'] : '') . '" style="' . $styles . '">';
        if( $atts['back']==1 ) {
            $result .= '<span class="super-back-to-top"' . $i_styles . '><i class="fas fa-chevron-up"></i></span>';
        }
        $result .= '</div>';
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }
    public static function spacer( $tag, $atts ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'html_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );

        $styles = '';
        if( $atts['height']!='' ) {
            $styles = 'height:' . $atts['height'] . 'px;';
        }
        $result = self::opening_tag( $tag, $atts, '', $styles );
        $result .= self::loop_conditions( $atts, $tag );
        $result .= '</div>';
        return $result;
    }
    public static function pdf_page_break( $tag, $atts ) {
        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'html_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $class = '';
        if(!empty($atts['orientation'])){
            $class = 'pdf-orientation-'.$atts['orientation'];
        }
        $result = self::opening_tag( $tag, $atts, $class );
        $result .= '</div>';
        return $result;
    }


    /** 
     *  Google Map with API options
     *
     *  @since      3.5.0
    */
    public static function google_map( $tag, $atts ) {
        // In order to print google map load the libraries:
        //wp_enqueue_script( 'super-html-canvas', SUPER_PLUGIN_FILE.'lib/super-html-canvas.min.js', array(), SUPER_VERSION, false );   
        //wp_enqueue_script( 'super-pdf-gen', SUPER_PLUGIN_FILE.'lib/super-pdf-gen.min.js', array( 'super-html-canvas' ), SUPER_VERSION, false );          
        
        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'html_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );

        $map_styles = 'min-height:' . $atts['min_height'] . 'px;';
        if(empty($atts['api_key'])) $atts['api_key'] = '';
        $url = '//maps.googleapis.com/maps/api/js?';
        if( !empty( $atts['api_region'] ) ){
            $url .= 'region='.$atts['api_region'].'&';
        }
        if( !empty( $atts['api_language'] ) ){
            $url .= 'language='.$atts['api_language'].'&';
        }
        $url .= 'key=' . $atts['api_key'] . '&libraries=drawing,geometry,places,visualization&callback=SUPER.google_maps_init';
        wp_enqueue_script( 'google-maps-api', $url, array( 'super-common' ), SUPER_VERSION, false );

        // Add field attributes if {tags} are being used
        $field_names = array();
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['address']);
        // Directions API (route)
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['origin']);
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['destination']);
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['directionsPanel']);
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['travelMode']);
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['unitSystem']);
        // Waypoints
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['waypoints']);
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['optimizeWaypoints']);
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['provideRouteAlternatives']);
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['avoidFerries']);
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['avoidHighways']);
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['avoidTolls']);
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['region']);
        // we will implement this in a later version   // drivingOptions (only when travelMode is DRIVING)
        // we will implement this in a later version   $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['departureTime']);
        // we will implement this in a later version   $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['trafficModel']);
        // we will implement this in a later version   // transitOptions (only when travelMode is TRANSIT)
        // we will implement this in a later version   $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['arrivalTime']);
        // we will implement this in a later version   $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['transitDepartureTime']);
        // we will implement this in a later version   $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['transitModes']);
        // we will implement this in a later version   $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['routingPreference']);
        // UI settings
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['zoom']);
        $field_names = SUPER_Common::get_data_fields_attribute($field_names, $atts['disableDefaultUI']);

        // Polylines
        if( !empty($atts['enable_polyline']) ) {
            $polylines = explode("\n", $atts['polylines']);
            foreach( $polylines as $k => $v ) {
                $coordinates = explode("|", $v);
                if( count($coordinates)<2 ) {
                    $error = esc_html__( 'Incorrect latitude and longitude coordinates for Polylines, please correct and update element!', 'super-forms' );
                }else{
                    $lat = $coordinates[0];
                    $lng = $coordinates[1];
                    if( preg_match("/{(.*?)}/", $lat) ) {
                        $origin_name = str_replace("{", "",$lat);
                        $origin_name = str_replace("}", "", $origin_name);
                        $field_names[$origin_name] = $origin_name;
                    }
                    if( preg_match("/{(.*?)}/", $lng) ) {
                        $origin_name = str_replace("{", "",$lng);
                        $origin_name = str_replace("}", "", $origin_name);
                        $field_names[$origin_name] = $origin_name;
                    }
                }
            }
        }

        $map_id = 'super-google-map-' . self::$current_form_id;

        $dataFields = '';
        if(!empty($field_names)) $dataFields = ' data-fields="{' . implode('}{', $field_names) . '}"';
        $result = '<div class="super-google-map"' . ($dataFields ? $dataFields : '') . '>';
        if( (is_admin()) && (!empty($error)) ) {
            $result .= '<p><strong style="color:red;">' . $error . '</strong></p>';
        }
        $result .= '<div class="' . $map_id . '" id="' . $map_id . '" style="' . $map_styles . '">';
        if( empty($atts['api_key']) ) {
            $result .= '<strong style="color:red;">' . esc_html__( 'Please enter your "Google API key" and make sure you enabled the "Google Maps JavaScript API" library in order to generate a map', 'super-forms' ) . '</strong>';
        }
        $result .= '</div>';
        $result .= '<textarea disabled class="super-hidden">' . json_encode( $atts ) . '</textarea>';
        $result .= '</div>';
        return $result;
    }


    /** 
     *  Add button to allow conditional logic show/hide button
     *
     * @param  string  $tag
     * @param  array   $atts
     *
     *  @since      1.1.6
    */
    public static function button( $tag, $atts, $inner, $shortcodes=null, $settings=null, $i18n=null ) {

        $defaults = SUPER_Common::generate_array_default_element_settings(self::$shortcodes, 'form_elements', $tag);
        $atts = wp_parse_args( $atts, $defaults );
        $atts = self::merge_i18n($atts, $i18n); // @since 4.7.0 - translation

        // Make sure the default form button won't be returned, since we are using a custom button
        if( !isset( $GLOBALS['super_custom_button_used'] ) ) {
            $GLOBALS['super_custom_button_used'] = true;
        }

        $name = $settings['form_button'];

        // @since 2.0.0 - button action (submit/clear/redirect)
        $action = 'submit';

        // @since 2.0.0 - button loading state text
        $loading = '';
        if( !empty($settings['form_button_loading']) ) {
            $loading = $settings['form_button_loading'];
        }

        $radius = $settings['form_button_radius'];
        $type = $settings['form_button_type'];
        $size = $settings['form_button_size'];
        $align = $settings['form_button_align'];
        $width = $settings['form_button_width'];
        $icon_option = (isset($settings['form_button_icon_option']) ? $settings['form_button_icon_option'] : 'none');
        $icon_visibility = (isset($settings['form_button_icon_visibility']) ? $settings['form_button_icon_visibility'] : 'visible');
        $icon_animation = (isset($settings['form_button_icon_animation']) ? $settings['form_button_icon_animation'] : 'horizontal');
        $icon = (isset($settings['form_button_icon']) ? $settings['form_button_icon'] : '');
        $color = $settings['theme_button_color'];
        $color_hover = $settings['theme_button_color_hover'];
        $font = $settings['theme_button_font'];
        $font_hover = $settings['theme_button_font_hover'];

        if( !empty( $atts['action']) ) $action = $atts['action'];
        if( !isset( $GLOBALS['super_submit_button_found'] ) && $action==='submit' ) {
            $GLOBALS['super_submit_button_found'] = true;
        }

        if( !empty( $atts['name'] ) ) $name = $atts['name'];
        $name = stripslashes($name);

        if( !empty( $atts['loading'] ) ) $loading = $atts['loading'];
        
        if( isset( $atts['custom_advanced'] ) ) {
            if( $atts['custom_advanced']=='custom' ) {
                if( isset( $atts['radius'] ) ) $radius = $atts['radius'];
                if( isset( $atts['type'] ) ) $type = $atts['type'];
                if( isset( $atts['size'] ) ) $size = $atts['size'];
                if( isset( $atts['align'] ) ) $align = $atts['align'];
                if( isset( $atts['width'] ) ) $width = $atts['width'];
            }
        }
        if( isset( $atts['custom_icon'] ) ) {
            if( $atts['custom_icon']=='custom' ) {
                if( isset( $atts['icon_option'] ) ) $icon_option = $atts['icon_option'];
                if( isset( $atts['icon_visibility'] ) ) $icon_visibility = $atts['icon_visibility'];
                if( isset( $atts['icon_animation'] ) ) $icon_animation = $atts['icon_animation'];
                if( isset( $atts['icon'] ) ) $icon = $atts['icon'];
            }
        }
        if( isset( $atts['custom_colors'] ) ) {
            if( $atts['custom_colors']=='custom' ) {
                if( isset( $atts['color'] ) ) $color = $atts['color'];
                if( isset( $atts['color_hover'] ) ) $color_hover = $atts['color_hover'];
                if( isset( $atts['font'] ) ) $font = $atts['font'];
                if( isset( $atts['font_hover'] ) ) $font_hover = $atts['font_hover'];
            }
        }
        
        $icon_animation = ' super-button-icon-animation-' . $icon_animation;
        if( $icon_visibility=='visible' ) $icon_animation = '';
        
        $class = 'super-extra-shortcode super-shortcode super-field super-button super-clear-none';
        if($action==='prev' || $action==='next'){
            if($action==='prev'){
                $class .= ' super-prev-multipart';
            }else{
                $class .= ' super-next-multipart';
            }
        }else{
            $class .= ' super-form-button';
        }
        $class .= ' super-radius-' . $radius . ' super-type-' . $type . ' super-button-' . $size . ' super-button-align-' . $align . ' super-button-width-' . $width;
        if( $icon_option!='none' ) {
            $class .= ' super-button-icon-option-' . $icon_option . $icon_animation . ' super-button-icon-visibility-' . $icon_visibility;
        }

        // @since 1.9 - custom class
        if( !isset( $atts['class'] ) ) $atts['class'] = '';
        if( !isset( $atts['wrapper_class'] ) ) $atts['wrapper_class'] = '';
        if( $atts['wrapper_class']!='' ) $class .= ' ' . $atts['wrapper_class'];

        $attributes = '';
        if( $color!='' ) {
            $light = SUPER_Common::adjust_brightness( $color, 20 );
            $dark = SUPER_Common::adjust_brightness( $color, -30 );
            $attributes .= ' data-color="' . esc_attr($color) . '"';
            $attributes .= ' data-light="' . esc_attr($light) . '"';
            $attributes .= ' data-dark="' . esc_attr($dark) . '"';
        }
        if( $color_hover!='' ) {
            $hover_light = SUPER_Common::adjust_brightness( $color_hover, 20 );
            $hover_dark = SUPER_Common::adjust_brightness( $color_hover, -30 );
            $attributes .= ' data-hover-color="' . esc_attr($color_hover) . '"';
            $attributes .= ' data-hover-light="' . esc_attr($hover_light) . '"';
            $attributes .= ' data-hover-dark="' . esc_attr($hover_dark) . '"';
        }
        if( $font!='' ) $attributes .= ' data-font="' . esc_attr($font) .'"';
        if( $font_hover!='' ) $attributes .= ' data-font-hover="' . esc_attr($font_hover) . '"';
        $result = '';

        $result .= '<div' . $attributes . ' data-radius="' . esc_attr($radius) . '" data-type="' . esc_attr($type) . '" class="' . esc_attr($class) . '">';
            if( !isset( $atts['target'] ) ) $atts['target'] = '';
            if( !isset( $atts['action'] ) ) $atts['action'] = 'submit';
            $url = '';
            if($atts['action']!='submit'){
                if( !isset( $atts['link'] ) ) $atts['link'] = '';
                if( $atts['link']!='' ) {
                    if( $atts['link']=='custom' ) {
                        $url = $atts['custom_link'];
                    }else{
                        $url = get_permalink( $atts[$atts['link']] );
                    }
                }
                if( !empty( $atts['target'] ) ) $atts['target'] = 'data-target="' . esc_attr($atts['target']) . '" ';
            }

            $result .= '<div ' . $atts['target'] . 'data-href="' . esc_attr($url) . '" class="super-button-wrap no_link' . ($atts['class']!='' ? ' ' . esc_attr($atts['class']) : '') . '">';
                if( ( $icon!='' ) && ( $icon_option!='none' ) ) {
                    $icon_tag = explode(' ', $icon);
                    if(isset($icon_tag[1])){
                        $icon_type = $icon_tag[0];
                        $icon_tag = str_replace('fa-', '', $icon_tag[1]);
                    }else{
                        $default = explode(';', $icon);
                        $icon_tag = $default[0];
                        $icon_type = 'fas';
                        if(isset($default[1])){
                            $icon_type = $default[1]; // use the existing type
                        }
                    }
                    $result .= '<span class="super-before"><i class="' . $icon_type . ' fa-'.SUPER_Common::fontawesome_bwc($icon_tag).'"></i></span>';
                }
                $result .= '<div class="super-button-name" data-action="' . esc_attr($action) . '" data-normal="' . esc_attr($name) . '" data-loading="' . esc_attr($loading) . '">';
                    $result .= $name;
                    // @since 3.9.0 - option for print action to use custom HTML
                    if( !empty($atts['print_custom']) ) {
                        if( !empty($atts['print_file']) ) {
                            $result .= '<input type="hidden" name="print_file" value="' . absint($atts['print_file']) . '" />';
                        }
                    }
                $result .= '</div>';
                $result .= '<span class="super-after"></span>';
            $result .= '</div>';
        $result .= '</div>';
        return $result;
    }


    /** 
     *  Output the shortcode element on front-end
     *
     * @param  string  $tag
     * @param  string  $group
     * @param  array   $data
     * @param  array   $inner
     * @param  array   $shortcodes
     * @param  array   $settings
     * @param  array   $i18n
     * @param  boolean $builder
     * @param  array   $entry_data
     * @param  int     $dynamic
     * @param  array   $dynamic_field_names
     * @param  array   $inner_field_names
     *
     *  @since      1.0.0
    */
    public static function output_element_html( $tag, $group, $data, $inner, $shortcodes=null, $settings=null, $i18n=null, $builder=false, $entry_data=null, $dynamic=0, $dynamic_field_names=array(), $inner_field_names=array(), $formProgress=false ) {
        // @IMPORTANT: before we proceed we must make sure that the "Default value" of a field will still be available
        // Otherwise when a user would duplicate a column that was populated with Entry data this "Default value" would be replaced with the Entry value
        // This is not what we want, because when duplicating a column we would like to reset each element to it's original state (Default value)
        // The below `absolute_default` will be retrieved on the elements attribute called `data-absolute-default=""`
        // This value is then used when a column is duplicated so we can reset each field to it's initial default value
        if(!empty($data['name'])){
            $element = array('tag' => $tag, 'data' => $data, 'group' => $group);
            $data['absolute_default'] = SUPER_Common::get_absolute_default_value($element, $shortcodes);
        }

        // @since 3.5.0 - backwards compatibility with older form codes that have image field and other HTML field in group form_elements instead of html_elements
        if( ($group=='form_elements') && ($tag=='image' || $tag=='heading' || $tag=='html' || $tag=='divider' || $tag=='spacer' || $tag=='google_map' ) ) {
            $group = 'html_elements';
        }

        if( $shortcodes==null ) {
            $shortcodes = self::shortcodes();
        }
        if( !isset( $shortcodes[$group]['shortcodes'][$tag] ) ) {
            return '';
        }
        if( !isset( $shortcodes[$group]['shortcodes'][$tag]['callback'] ) ) {
            return '';
        }
        $callback = $shortcodes[$group]['shortcodes'][$tag]['callback'];
        $callback = explode( '::', $callback );
        $class = $callback[0];
        $function = $callback[1];
        $data = json_decode(json_encode($data), true);
        $inner = json_decode(json_encode($inner), true);
        if($settings['theme_hide_icons']==='yes'){
            unset($data['icon']);
            unset($data['icon_align']);
            unset($data['icon_position']);
        }
        return call_user_func( array( $class, $function ), $tag, $data, $inner, $shortcodes, $settings, $i18n, $builder, $entry_data, $dynamic, $dynamic_field_names, $inner_field_names, $formProgress );
    }

    
    /** 
     *  Output the shortcode element on backend create form page under Tabs: Layout / Form Elements etc.
     *
     * @param  string $shortcode
     * @param  array $value
     *
     *  @since      1.0.0
    */
    public static function output_element( $shortcode=null, $group='form_elements', $value=array() ) {
        
        $return = '';
        
        // Form Elements
        $return .= '<div class="super-element draggable-element super-shortcode-'.$shortcode.'" data-elementtitle="'.$value['name'].'" data-shortcode="'.$shortcode.'" data-group="'.$group.'" data-droppingallowed="0">';
            if( isset( $value['html'] ) ) {
                $return .= $value['html'];
            }else{
                // Fontawesome 5+ compatibility
                if(isset(explode(';', $value['icon'])[1])){
                    $return .= '<i class="'.explode(';', $value['icon'])[1].' fa-'.explode(';', $value['icon'])[0].'"></i>'.$value['name'];
                }else{
                    $return .= '<i class="fas fa-'.$value['icon'].'"></i>'.$value['name'];
                }
                $return .= '<div class="content" style="display:none;">';
                if( isset( $value['content'] ) ) $return .= $value['content'];
                $return .= '</div>';
            }
            if( isset( $value['predefined'] ) ) {
                $return .= '<textarea class="predefined" style="display:none;">' . json_encode( $value['predefined'] ) . '</textarea>';
            }
        $return .= '</div>';
            
        return apply_filters( 'super_backend_output_element_'.$shortcode.'_filter', $return, array( 'shortcode'=>$shortcode, 'value'=>$value ) );
        
    }

    
    /** 
     *  Common fields for each shortcode (backend dialog)
     *
     *  @since      1.0.0
    */
    public static function name( $attributes=null, $default='' ) {
        $array = array(
            'name' => esc_html__( 'Unique field name', 'super-forms' ) . ' *', 
            'desc' => esc_html__( 'Must be an unique name (required)', 'super-forms' ),
            'default' => ( !isset( $attributes['name'] ) ? $default : $attributes['name'] ),
            'required' => true,
            'filter' => true
        );
        return $array;
    }
    public static function email( $attributes=null, $default='' ) {
        $array = array(
            'name' => esc_html__( 'E-mail & Contact Entry Label', 'super-forms' ) . ' *', 
            'label' => esc_html__( 'When using dynamic columns, you can use %d to determine where the counter should be placed e.g: "Product %d quantity:" would be converted into "Product 3 quantity:"', 'super-forms' ),
            'desc' => esc_html__( 'Indicates the field in emails and contact entries. (required)', 'super-forms' ),
            'default' => ( !isset( $attributes['email'] ) ? $default : $attributes['email'] ),
            'required' => true,
            'i18n' => true
        );
        return $array;
    }
    public static function label( $attributes=null, $default='' ) {
        $array = array(
            'name' => esc_html__( 'Field Label', 'super-forms' ), 
            'desc' => esc_html__( 'Will be visible in front of your field.', 'super-forms' ).' ('.esc_html__( 'leave blank to remove', 'super-forms' ).')',
            'default' => ( !isset( $attributes['label'] ) ? $default : $attributes['label'] ),
            'i18n' => true
        );
        return $array;
    }    
    public static function description( $attributes=null, $default='') {
        $array = array(
            'name' => esc_html__( 'Field description', 'super-forms' ), 
            'desc' => esc_html__( 'Will be visible in front of your field.', 'super-forms' ).' ('.esc_html__( 'leave blank to remove', 'super-forms' ).')',
            'default' => ( !isset( $attributes['description'] ) ? $default : $attributes['description'] ),
            'i18n' => true
        );
        return $array;
    }
    public static function icon( $attributes=null, $default='user' ) {
        $icon = array(
            'default' => ( !isset( $attributes['icon'] ) ? $default : $attributes['icon'] ),
            'name' => esc_html__( 'Select an Icon', 'super-forms' ), 
            'type' => 'icon',
            'desc' => esc_html__( 'Leave blank if you prefer to not use an icon.', 'super-forms' )
        );
        return $icon;
    }
    public static function placeholder( $attributes=null, $default=null ) {
        $array = array(
            'default' => ( !isset( $attributes['placeholder'] ) ? $default : $attributes['placeholder'] ),
            'name' => esc_html__( 'Placeholder', 'super-forms' ), 
            'desc' => esc_html__( 'Indicate what the user needs to enter or select. (leave blank to remove)', 'super-forms' ),
            'i18n' => true
        );
        return $array;
    }
    public static function placeholderFilled( $attributes=null, $default=null ) {
        $array = array(
            'default' => ( !isset( $attributes['placeholder'] ) ? $default : $attributes['placeholder'] ),
            'name' => esc_html__( 'Placeholder when the field is filled out', 'super-forms' ), 
            'label' => '(' . esc_html__( 'only used when Adaptive Placeholders are enabled', 'super-forms' ) . ')',
            'i18n' => true
        );
        return $array;
    }
    public static function width( $attributes=null, $default=0, $min=0, $max=600, $steps=10, $name=null, $desc=null ) {
        if( empty( $name ) ) $name = esc_html__( 'Field width in pixels', 'super-forms' );
        if( empty( $desc ) ) $desc = esc_html__( 'Set to 0 to use default CSS width.', 'super-forms' );
        $array = array(
            'type' => 'slider', 
            'default'=> ( !isset( $attributes['width'] ) ? $default : $attributes['width'] ),
            'min' => $min, 
            'max' => $max, 
            'steps' => $steps, 
            'name' => $name, 
            'desc' => $desc
        );
        return $array;
    }
    public static function slider( $attributes=null, $default=0, $min=0, $max=600, $steps=10, $name=null, $desc=null, $key=null ) {
        if( empty( $name ) ) $name = esc_html__( 'Field width in pixels', 'super-forms' );
        if( empty( $desc ) ) $desc = esc_html__( 'Set to 0 to use default CSS width.', 'super-forms' );
        $array = array(
            'type' => 'slider', 
            'default'=> ( !isset( $attributes[$key] ) ? $default : $attributes[$key] ),
            'min' => $min, 
            'max' => $max, 
            'steps' => $steps, 
            'name' => $name, 
            'desc' => $desc
        );
        return $array;
    }
    public static function minlength( $attributes=null, $default=0, $min=0, $max=100, $steps=1, $name=null, $desc=null) {
        if( empty($name ) ) $name = esc_html__( 'Min characters/selections allowed', 'super-forms' );
        if( empty($desc ) ) $desc = esc_html__( 'Set to 0 to remove limitations.', 'super-forms' );
        $array = array(
            'type' => 'slider', 
            'default'=> ( !isset( $attributes['minlength'] ) ? $default : $attributes['minlength'] ),
            'min' => $min, 
            'max' => $max, 
            'steps' => $steps, 
            'name' => $name, 
            'desc' => $desc
        );
        return $array;
    }
    public static function maxlength( $attributes=null, $default=0, $min=0, $max=100, $steps=1, $name=null, $desc=null ) {
        if( empty( $name ) ) $name = esc_html__( 'Max characters/selections allowed', 'super-forms' );
        if( empty( $desc ) ) $desc = esc_html__( 'Set to 0 to remove limitations.', 'super-forms' );
        $array = array(
            'type' => 'slider', 
            'default'=> ( !isset( $attributes['maxlength'] ) ? $default : $attributes['maxlength'] ),
            'min' => $min, 
            'max' => $max, 
            'steps' => $steps, 
            'name' => $name, 
            'desc' => $desc
        );
        return $array;
    }
    public static function sf_retrieve_method($value, $parent){
        $array = array();
        $values = array();
        $array['default'] = ( !isset( $value ) ? 'custom' : $value );
        if($parent==='enable_keywords'){
            $values['free'] = esc_html__( 'Allow everything (no limitations)', 'super-forms' );
            $array['parent'] = $parent;
            $array['filter_value'] = 'true';
            $array['default'] = ( !isset( $value ) ? 'free' : $value );
        }
        if($parent==='enable_auto_suggest'){
            $array['parent'] = $parent;
            $array['filter_value'] = 'true';
        }
        $values['custom'] = esc_html__( 'Custom items', 'super-forms' ); 
        $values['taxonomy'] = esc_html__( 'Specific taxonomy (categories)', 'super-forms' );
        $values['post_type'] = esc_html__( 'Specific posts (post_type)', 'super-forms' );
        $values['product_attribute'] = esc_html__( 'Product attribute (product_attributes)', 'super-forms' );
        $values['tags'] = esc_html__( 'Tags (post_tag)', 'super-forms' );
        $values['users'] = esc_html__( 'Users (wp_users)', 'super-forms' );
        $values['csv'] = esc_html__( 'CSV file', 'super-forms' );
        $values['author'] = esc_html__( 'Current Author meta data', 'super-forms' ); // @since 4.0.0 - retrieve current author data
        $values['post_meta'] = esc_html__( 'Current Page or Post meta data', 'super-forms' ); // @since 4.0.0 - retrieve current author data
        $values['post_terms'] = esc_html__( 'Current Page or Post terms (based on specified taxonomy slug)', 'super-forms' ); // @since 4.0.0 - retrieve current author data
        $values['db_table'] = esc_html__( 'Specific database table', 'super-forms' ); // @since 4.4.1 - retrieve from a custom database table
        $array['name'] = esc_html__( 'Retrieve method', 'super-forms' );
        $array['desc'] = esc_html__( 'Select a method for retrieving items', 'super-forms' );
        $array['type'] = 'select';
        $array['filter'] = true;
        $array['values'] = $values;
        return $array;
    }

    public static function sf_retrieve_method_exclude_users($value, $parent){
        return array(
            'name' => esc_html__( 'Exclude user(s)', 'super-forms' ), 
            'label' => esc_html__( 'Enter the user ID\'s to exclude seperated by comma\'s', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'users'
        );
    }
    public static function sf_retrieve_method_role_filters($value, $parent){
        return array(
            'type' => 'textarea',
            'name' => esc_html__( 'Filter users by role(s)', 'super-forms' ),
            'label' => esc_html__( 'Define each role on a new line. For instance, if you want to return only WooCommerce customers, you can use: customer', 'super-forms' ),
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'users'
        );
    }
    public static function sf_retrieve_method_user_label($value, $parent){
        return array(
            'name' => esc_html__( 'Label deffinition for each user', 'super-forms' ),
            'label' => esc_html__( 'Define here how you want to list your users e.g: [#{ID} - {first_name} {last_name} ({user_email})] would translate to: [#1845 - John Wilson (john@email)]', 'super-forms' ),
            'placeholder' => "#{ID} - {first_name} {last_name} ({user_email})",
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'users'
        );
    }
    public static function sf_retrieve_method_user_meta_keys($value, $parent){
        return array(
            'type' => 'textarea',
            'name' => esc_html__( 'Define user data or user meta data to return as value', 'super-forms' ), 
            'label' => esc_html__( "Put each key on a new line, for instance if you want to return the user billing address you could enter:\nID\nbilling_first_name\nbilling_last_name\nbilling_company\nbilling_email\nbilling_phone\nbilling_address_1\nbilling_city\nbilling_state\nbilling_postcode\nbilling_country\n\nWhen retrieving the value in the form dynamically you can use tags like so: {fieldname;1} (to retrieve the user ID) and {fieldname;2} (to retrieve the city) and so on...", 'super-forms' ),
            'placeholder' => "ID\nbilling_first_name\nbilling_last_name\nbilling_company\nbilling_email\nbilling_phone\nbilling_address_1\nbilling_city\nbilling_state\nbilling_postcode\nbilling_country",
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'users'
        );
    }
    public static function sf_retrieve_method_db_table($value, $parent){
        return array(
            'required' => true,
            'name' => esc_html__( 'Database table name', 'super-forms' ), 
            'label' => esc_html__( 'Enter the table name including the prefix e.g: wp_mycustomtable', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'db_table'
        );
    }
    public static function sf_retrieve_method_db_row_value($value, $parent){
        return array(
            'name' => esc_html__( 'Use {tags} to define the returned Value per row', 'super-forms' ),
            'label' => esc_html__( 'Example to return the row ID: <strong>{ID}</strong>', 'super-forms' ),
            'desc' => esc_html__( 'Any table column can be returned by using {tags} as long as the columns name exists', 'super-forms' ),
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'db_table'
        );
    }
    public static function sf_retrieve_method_db_row_label($value, $parent){
        return array(
            'name' => esc_html__( 'Use {tags} to define the returned Label per row', 'super-forms' ),
            'label' => esc_html__( 'Example, to return the row First name: <strong>{first_name}</strong>', 'super-forms' ),
            'desc' => esc_html__( 'Any table column can be returned by using {tags} as long as the columns name exists', 'super-forms' ),
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'db_table'
        );
    }
    public static function sf_retrieve_method_post_terms_label($value, $parent){
        return array(
            'required' => true,
            'name' => esc_html__( 'Choose terms label to return', 'super-forms' ), 
            'type' => 'select',
            'values' => array(
                'names' => esc_html__( 'Names (default)', 'super-forms' ),
                'slugs' => esc_html__( 'Slugs', 'super-forms' ),
                'ids' => esc_html__( 'ID\'s', 'super-forms' ),
            ),
            'default'=> ( !isset( $value ) ? 'names' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'post_terms'
        );
    }
    public static function sf_retrieve_method_post_terms_value($value, $parent){
        return array(
            'required' => true,
            'name' => esc_html__( 'Choose terms value to return', 'super-forms' ), 
            'type' => 'select',
            'values' => array(
                'names' => esc_html__( 'Names', 'super-forms' ),
                'slugs' => esc_html__( 'Slugs (default)', 'super-forms' ),
                'ids' => esc_html__( 'ID\'s', 'super-forms' ),
            ),
            'default'=> ( !isset( $value ) ? 'slugs' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'post_terms'
        );
    }
    public static function sf_retrieve_method_author_field($value, $parent){
        return array(
            'required' => true,
            'name' => esc_html__( 'Choose meta field name', 'super-forms' ), 
            'label' => sprintf( esc_html__( 'You would normally be using a textarea field where each option is put on a new line. You can also seperate label and value with pipes. Example textarea value would be:%1$sOption 1|option_1%1$sOption 2|option_2%1$setc...%1$s(ACF fields are also supported)', 'super-forms' ), '<br />' ), 
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'author,post_meta'
        );
    }
    public static function sf_retrieve_method_author_option_explode($value, $parent){
        return array(
            'name' => esc_html__( 'Choose label value break method', 'super-forms' ), 
            'label' => esc_html__( 'This will split up the label and value of each option. By default the label and value will be split by a pipe "|" character.' ), 
            'default'=> ( !isset( $value ) ? '|' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'author,post_meta'
        );
    }
    public static function sf_retrieve_method_author_line_explode($value, $parent){
        return array(
            'name' => esc_html__( 'Choose line break method (optional)', 'super-forms' ), 
            'label' => esc_html__( 'By default each value that is placed on a new line will be converted to an option to choose from. In case you have a text field with comma seperated values, you can change this to be a comma instead.' ), 
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'author,post_meta'
        );
    }
    public static function sf_retrieve_method_custom_items($value, $parent, $type){
        return array(
            'type' => $type,
            'default' => ( !isset( $value ) ? 
                array(
                    array(
                        'checked' => false,
                        'label' => esc_html__( 'First choice', 'super-forms' ),
                        'value' => esc_html__( 'first_choice', 'super-forms' )
                    ),
                    array(
                        'checked' => false,
                        'label' => esc_html__( 'Second choice', 'super-forms' ),
                        'value' => esc_html__( 'second_choice', 'super-forms' )
                    ),
                    array(
                        'checked' => false,
                        'label' => esc_html__( 'Third choice', 'super-forms' ),
                        'value' => esc_html__( 'third_choice', 'super-forms' )
                    )
                ) : $value
            ),
            'filter' => true,
            'parent' => $parent,
            'filter_value' => 'custom',
            'i18n' => true
        );
    }
    public static function sf_retrieve_method_csv($value, $parent){
        return array(
            'name' => esc_html__( 'Upload CSV file', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? '' : $value ),
            'type' => 'file',
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'csv',
            'file_type'=>'text/csv',
            'i18n' => true
        );
    }
    public static function sf_retrieve_method_delimiter($value, $parent){
        return array(
            'name' => esc_html__( 'Custom delimiter', 'super-forms' ), 
            'label' => esc_html__( 'Set a custom delimiter to seperate the values on each row', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? ',' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'csv',
            'i18n' => true
        );
    }
    public static function sf_retrieve_method_enclosure($value, $parent){
        return array(
            'name' => esc_html__( 'Custom enclosure', 'super-forms' ), 
            'label' => esc_html__( 'Set a custom enclosure character for values', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? '"' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'csv',
            'i18n' => true
        );
    }
    public static function sf_retrieve_method_taxonomy($value, $parent){
        return array(
            'name' => esc_html__( 'Taxonomy slug', 'super-forms' ), 
            'label' => esc_html__( 'Enter the taxonomy slug name e.g category or product_cat', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? 'category' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'taxonomy,post_terms'
        );
    }
    public static function sf_retrieve_method_product_attribute($value, $parent){
        return array(
            'name' => esc_html__( 'Product attribute slug', 'super-forms' ), 
            'label' => esc_html__( 'Enter the attribute slug name e.g color or condition', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'product_attribute'
        );
    }                       
    public static function sf_retrieve_method_post($value, $parent){
        return array(
            'name' => esc_html__( 'Post type (e.g page, post or product)', 'super-forms' ), 
            'label' => esc_html__( 'Enter the name of the post type', 'super-forms' ),
            'default'=> ( !isset( $value ) ? 'post' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'post_type'
        );
    }
    public static function sf_retrieve_method_post_status($value, $parent){
        return array(
            'name' => esc_html__( 'Post status (e.g any, publish, inherit, pending, private, future, draft, trash)', 'super-forms' ), 
            'label' => esc_html__( 'Seperated each post status by a comma, enter "any" for all post statuses', 'super-forms' ),
            'default'=> ( !isset( $value ) ? 'publish' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'post_type'
        );
    }
    public static function sf_retrieve_method_post_limit($value, $parent){
        return array(
            'name' => esc_html__( 'Limit (set to -1 for no limit)', 'super-forms' ),
            'label' => esc_html__( 'How many posts should be retrieved at a maximum?', 'super-forms' ),
            'default' => ( !isset( $value ) ? 30 : $value ),
            'type' => 'slider', 
            'min' => -1, 
            'max' => 100, 
            'steps' => 1, 
            'filter' => true,
            'parent' => $parent, // display
            'filter_value' => 'post_type'
        );
    }
    public static function sf_display($value){
        return array(
            'name' => esc_html__( 'Display Layout', 'super-forms' ),
            'label' => esc_html__( 'Select how the items should be displayed', 'super-forms' ),
            'default' => ( !isset( $value ) ? 'vertical' : $value ),
            'type' => 'select', 
            'values' => array(
                'vertical' => esc_html__( 'List (vertical)', 'super-forms' ), 
                'horizontal' => esc_html__( 'List (horizontal)', 'super-forms' ), 
                'grid' => esc_html__( 'Grid', 'super-forms' ), 
                'slider' => esc_html__( 'Slider (Carousel)', 'super-forms' ), 
            ),
            'filter' => true
        );
    }
    public static function sf_display_columns($value, $parent){
        return array(
            'name' => esc_html__( 'Number of columns (1 up to 10)', 'super-forms' ),
            'label' => esc_html__( 'Choose how many columns your Grid or Slider will display.', 'super-forms' ),
            'default' => ( !isset( $value ) ? 4 : $value ),
            'type' => 'slider', 
            'min' => 1, 
            'max' => 10, 
            'steps' => 1, 
            'filter' => true,
            'parent' => $parent, // display
            'filter_value' => 'grid,slider'
        );
    }
    public static function sf_display_minwidth($value, $parent){
        return array(
            'name' => esc_html__( 'Minimum width of each item', 'super-forms' ),
            'label' => esc_html__( 'Choose a minimum width that each item must have', 'super-forms' ),
            'default' => ( !isset( $value ) ? 100 : $value ),
            'type' => 'slider', 
            'min' => 10, 
            'max' => 1000, 
            'steps' => 10, 
            'filter' => true,
            'parent' => $parent, // display
            'filter_value' => 'slider'
        );
    }
    public static function sf_display_nav($value, $parent){
        return array(
            'allow_empty' => true,
            'default' => ( !isset( $value ) ? 'true' : $value ),
            'type' => 'checkbox', 
            'values' => array(
                'true' => esc_html__( 'Display prev/next buttons', 'super-forms' ),
            ),
            'filter' => true,
            'parent' => $parent, // display
            'filter_value' => 'slider'
        );
    }
    public static function sf_display_dots_nav($value, $parent){
        return array(
            'allow_empty' => true,
            'default' => ( !isset( $value ) ? 'true' : $value ),
            'type' => 'checkbox', 
            'values' => array(
                'true' => esc_html__( 'Display dots navigation', 'super-forms' ),
            ),
            'filter' => true,
            'parent' => $parent, // display
            'filter_value' => 'slider'
        );
    }
    public static function sf_display_rows($value, $parent){
        return array(
            'name' => esc_html__( 'Maximum number of rows to display', 'super-forms' ),
            'label' => esc_html__( 'Choose how many rows your Grid will display. (0 = no limit)', 'super-forms' ),
            'default' => ( !isset( $value ) ? 3 : $value ),
            'type' => 'slider', 
            'min' => 0, 
            'max' => 10, 
            'steps' => 1, 
            'filter' => true,
            'parent' => $parent, // display
            'filter_value' => 'grid'
        );
    }
    public static function sf_display_featured_image($value, $parent){
        return array(
            'allow_empty' => true,
            'default' => ( !isset( $value ) ? 'true' : $value ),
            'type' => 'checkbox', 
            'values' => array(
                'true' => esc_html__( 'Show featured image', 'super-forms' ),
            ),
            'filter' => true,
            'parent' => $parent, // retrieve_method
            'filter_value' => 'post_type'
        );
    }
    public static function sf_display_title($value, $parent){
        return array(
            'allow_empty' => true,
            'default' => ( !isset( $value ) ? 'true' : $value ),
            'type' => 'checkbox', 
            'values' => array(
                'true' => esc_html__( 'Show post title', 'super-forms' ),
            ),
            'filter' => true,
            'parent' => $parent, // retrieve_method
            'filter_value' => 'post_type'
        );
    }
    public static function sf_display_excerpt($value, $parent){
        return array(
            'allow_empty' => true,
            'default' => ( !isset( $value ) ? 'true' : $value ),
            'type' => 'checkbox', 
            'values' => array(
                'true' => esc_html__( 'Show post excerpt', 'super-forms' ),
            ),
            'filter' => true,
            'parent' => $parent, // retrieve_method
            'filter_value' => 'post_type'
        );
    }
    public static function sf_display_price($value, $parent){
        return array(
            'allow_empty' => true,
            'default' => ( !isset( $value ) ? 'true' : $value ),
            'type' => 'checkbox', 
            'values' => array(
                'true' => esc_html__( 'Show product price', 'super-forms' ),
            ),
            'filter' => true,
            'parent' => $parent, // retrieve_method_post
            'filter_value' => 'product'
        );
    }
    public static function sf_retrieve_method_orderby($value, $parent){
        return array(
            'name' => esc_html__( 'Order By', 'super-forms' ), 
            'label' => esc_html__( 'Select how you want to order the items', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? 'title' : $value ),
            'type' => 'select', 
            'values' => array(
                'title' => esc_html__( 'Order by title (default)', 'super-forms' ), 
                'date' => esc_html__( 'Order by date', 'super-forms' ), 
                'ID' => esc_html__( 'Order by post id', 'super-forms' ), 
                'author' => esc_html__( 'Order by author', 'super-forms' ), 
                'modified' => esc_html__( 'Order by last modified date', 'super-forms' ), 
                'parent' => esc_html__( 'Order by post/page parent id', 'super-forms' ),
                'menu_order' => esc_html__( 'Order by menu order', 'super-forms' ),
                'price' => esc_html__( 'Order by Product price (WooCommerce only)', 'super-forms' )
            ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'post_type'
        );
    }
    public static function sf_retrieve_method_order($value, $parent){
        return array(
            'name' => esc_html__( 'Order', 'super-forms' ), 
            'label' => esc_html__( 'Select if you want to use Ascending or Descending order', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? 'ASC' : $value ),
            'type' => 'select', 
            'values' => array(
                'ASC' => esc_html__( 'Ascending Order (default)', 'super-forms' ), 
                'DESC' => esc_html__( 'Descending Order', 'super-forms' )
            ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'post_type'
        );
    }
    public static function sf_retrieve_method_exclude_taxonomy($value, $parent){
        return array(
            'name' => esc_html__( 'Exclude a category', 'super-forms' ), 
            'label' => esc_html__( 'Enter the category ID\'s to exclude seperated by comma\'s', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'taxonomy'
        );
    }
    public static function sf_retrieve_method_exclude_post($value, $parent){
        return array(
            'name' => esc_html__( 'Exclude a post', 'super-forms' ), 
            'label' => esc_html__( 'Enter the post ID\'s to exclude seperated by comma\'s', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'post_type'
        );
    }                        
    public static function sf_retrieve_method_filters($value, $parent){
        return array(
            'type' => 'textarea',
            'name' => esc_html__( 'Filter posts by specific taxonomy', 'super-forms' ),
            'label' => sprintf( esc_html__('Define each taxonomy filter on a new line e.g: %1$s%3$sfield|value1,value2,value3|taxonomy|operator%2$s%3$sPossible values for the operator are %1$sIN%2$s, %1$sNOT IN%2$s, %1$sAND%2$s, %1$sEXISTS%2$s and %1$sNOT EXISTS%2$s%3$sExample to create a filter based of ID for Post category:%3$s%1$sid|8429|category|IN%2$s%3$sExample to create a filter based of slug for Post category:%3$s%1$sslug|cars|category|IN%2$s%3$sExample to create a filter based of ID for Post tags:%3$s%1$sid|8429|post_tag|IN%2$s%3$sExample to create a filter based of slug for Post tags:%3$s%1$sslug|red|post_tag|IN%2$s%3$sExample to create a filter based of ID for WC product category:%3$s%1$sid|8429|product_cat|IN%2$s%3$sExample to create a filter based of slug for WC product category:%3$s%1$sslug|cars|product_cat|IN%2$s%3$sExample to create a filter based of ID for WC product tags:%3$s%1$sid|8429|product_tag|IN%2$s%3$sExample to create a filter based of slug for WC product tags:%3$s%1$sslug|red|product_tag|IN%2$s', 'super-forms'), '<strong style="color:red;">', '</strong>', '<br />' ),
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'post_type'
        );
    }
    public static function sf_retrieve_method_filter_relation($value, $parent){
        return array(
            'name' => esc_html__( 'Filters relation', 'super-forms' ), 
            'label' => esc_html__( 'Select a filter relation (OR|AND)', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? 'OR' : $value ),
            'type' => 'select', 
            'values' => array(
                'OR' => 'OR (' . esc_html__( 'default', 'super-forms' ) .')', 
                'AND' => 'AND'
            ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'post_type'
        );
    }
    public static function sf_retrieve_method_hide_empty($value, $parent){
        return array(
            'name' => esc_html__( 'Hide empty categories', 'super-forms' ), 
            'label' => esc_html__( 'Show or hide empty categories', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? 0 : $value ),
            'type' => 'select', 
            'filter'=>true,
            'values' => array(
                0 => esc_html__( 'Disabled', 'super-forms' ), 
                1 => esc_html__( 'Enabled', 'super-forms' ),
            ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'taxonomy'
        );
    }
    public static function sf_retrieve_method_parent($value, $parent){
        return array(
            'name' => esc_html__( 'Based on parent ID', 'super-forms' ), 
            'label' => esc_html__( 'Retrieve categories by it\'s parent ID (integer only)', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'taxonomy,post_type'
        );
    }                          
    public static function sf_retrieve_method_value($value, $parent){
        return array(
            'name' => esc_html__( 'Retrieve Slug, ID, Title or Meta Data as value', 'super-forms' ), 
            'label' => esc_html__( 'Select if you want to retrieve slug, ID or the title as value', 'super-forms' ), 
            'default'=> ( !isset( $value ) ? 'slug' : $value ),
            'type' => 'select', 
            'values' => array(
                'slug' => esc_html__( 'Slug (default)', 'super-forms' ), 
                'id' => esc_html__( 'ID', 'super-forms' ),
                'title' => esc_html__( 'Title', 'super-forms' ),
                'custom' => esc_html__( 'Custom post meta data', 'super-forms' ),
            ),
            'filter'=>true,
            'parent'=>$parent,
            'filter_value'=>'taxonomy,post_type,tags'
        );
    }
    public static function sf_retrieve_method_meta_keys($value){
        return array(
            'type' => 'textarea',
            'name' => esc_html__( 'Define meta data to return as value', 'super-forms' ), 
            'label' => esc_html__( "Put each meta key on a new line, for instance if you want to return the ID, image, price and title of a product, you could enter:\n ID\nfeatured_image\npost_title\n_regular_price\n\nWhen retrieving the value in the form dynamically you can use tags like so: {fieldname;1} (to retrieve the ID), {fieldname;2} (to retrieve the image URL), {fieldname;3} (for title), and {fieldname;4} (to retrieve the price)", 'super-forms' ),
            'placeholder' => "ID\n_regular_price",
            'default'=> ( !isset( $value ) ? '' : $value ),
            'filter'=>true,
            'parent'=>'retrieve_method_value',
            'filter_value'=>'custom'
        );
    }


    /** 
     *  The form shortcode that will generate the form with all it's elements/fields
     *
     * @param  array $atts
     * @param  boolean $elements_only  @since 4.7.0 - used for translation language switcher to reload form with translated elements/fields
     *
     *  @since      1.0.0
    */
    public static function super_form_func( $atts, $elements_only=false ) {
        
        if( class_exists( 'SUPER_WooCommerce' ) ){
            remove_action( 'pre_get_posts', array( SUPER_WooCommerce(), 'exclude_products_from_shop' ) );
        }

        // @since 2.1.0 - make sure we reset the grid system
        unset($GLOBALS['super_grid_system']);

        extract( shortcode_atts( array(
            'id' => '',
            'list_id' => '',
            'entry_id' => '',
            'i18n' => ''
        ), $atts ) );

        $editingContactEntry = false;
        if($id!=='' && $list_id!=='' && $entry_id!==''){
            $editingContactEntry = true;
        }

        // @since 4.6.0 - set GET parameters for parsed shortcode params
        foreach($atts as $k => $v){
            // Skip the default "id" parameter
            if($k!='id'){
                // Only save the value if it doesn't exist yet
                // This way it allows us to override any params through URL parameters
                if(!isset($_GET[$k])){
                    $_GET[$k] = $v;
                }
            }
        }
        // The following is required when user switches between languages on the front-end
        if(isset($atts['parameters']) && is_array($atts['parameters'])){
            foreach($atts['parameters'] as $k => $v){
                if(!isset($_GET[$k])){
                    $_GET[$k] = $v;
                }
            }
        }

        // Sanitize the ID
        $form_id = absint($id);

        self::$current_form_id = $form_id;

        // Check if the post exists
        if ( FALSE === get_post_status( $form_id ) ) {
            // The post does not exist
            $result = '<strong>'.esc_html__('Error', 'super-forms' ).':</strong> '.sprintf(esc_html__('Super Forms could not find a form with ID: %d', 'super-forms' ), $form_id);
            return $result;
        }else{
            // Check if the post is a super_form post type
            $post_type = get_post_type($form_id);
            if( $post_type!='super_form' ) {
                    $result = '<strong>'.esc_html__('Error', 'super-forms' ).':</strong> '.sprintf(esc_html__('Super Forms could not find a form with ID: %d', 'super-forms' ), $form_id);
                    return $result;
            }
        }

        /** 
         *  Make sure that we have all settings even if this form hasn't saved it yet when new settings where added by a add-on
         *
         *  @since      1.0.6
        */
        require_once( SUPER_PLUGIN_DIR . '/includes/class-settings.php' );

        $settings = SUPER_Common::get_form_settings($form_id);
        // Allow users to override any form settings through the shortcode, this way you can have a single form that can be used many times with different settings
        foreach($atts as $k => $v){
            // If the shortcode attribute starts with "_setting_" we use it 
            // e.g.: `_setting_retrieve_last_entry_data="false"` will set the option to "false", even if it was set to "true"
            if(substr( $k, 0, 9 )==='_setting_'){
                // Either override existing setting or set new
                $settingKey = substr($k, 9, strlen($k));
                $settings[substr($k, 9, strlen($k))] = $v;
            }
        }
        // Allow us to manipulate form settings, currently used by Listings Add-on
        $settings = apply_filters( 'super_before_form_render_settings_filter', $settings, array( 'id' => $id, 'list_id' => $list_id, 'entry_id' => $entry_id, 'i18n' => $i18n ) );        

        $translations = SUPER_Common::get_form_translations($form_id);

        // @since 4.7.0 - translation
        if(!empty($i18n)){
            $i18n = sanitize_text_field($i18n);
            if( (!empty($settings['i18n'])) && (!empty($settings['i18n'][$i18n])) ){
                $settings = array_replace_recursive($settings, $settings['i18n'][$i18n]);
                unset($settings['i18n']);
            }
        }

        SUPER_Forms()->enqueue_element_styles();
        SUPER_Forms()->enqueue_element_scripts($settings, false, $form_id);

        $styles = '';

        // @since 1.3
        if( !empty( $settings['theme_form_margin'] ) ) {
            $styles .= 'margin:' . $settings['theme_form_margin'] . ';';
        }

        if($styles!='') $styles = 'style="' . $styles . '" ';

        // Try to load the selected theme style
        // Always load the default styles
        $style_content = require( SUPER_PLUGIN_DIR . '/assets/css/frontend/themes/style-default.php' );
        $style_content .= require( SUPER_PLUGIN_DIR . '/assets/css/frontend/themes/fonts.php' );
        $style_content .= require( SUPER_PLUGIN_DIR . '/assets/css/frontend/themes/colors.php' );
        $class = ' super-default-squared';
        if(!empty($settings['theme_style'])) {
            $class = ' ' . $settings['theme_style'];
        }

        // @since 2.9.0 - theme field size in height
        if( !isset( $settings['theme_field_size'] ) ) $settings['theme_field_size'] = 'medium';
        $class .= ' super-field-size-' . $settings['theme_field_size'];

        // @since 1.2.4     - use transparent field background
        if( !empty( $settings['theme_field_transparent'] ) ) {
            $class .= ' super-transparent-fields';
        }

        // @since 1.2.8     - RTL support
        if( !empty( $settings['theme_rtl'] ) ) {
            $class .= ' super-rtl';
        }else{
            // @since 4.7.0 - translation RTL
            // check if the translation has enable RTL mode
            $translations = SUPER_Common::get_form_translations($form_id);
            if(is_array($translations)){
                if( !empty($translations[$i18n]) && !empty($translations[$i18n]['rtl']) ){
                    if($translations[$i18n]['rtl']=='true'){
                        $class .= ' super-rtl';
                    }
                }
            }
        }

        // @since 3.6.0     - Center form
        if( !empty( $settings['theme_center_form'] ) ) {
            $class .= ' super-center-form';
        }

        // @since 3.2.0     - Save form progress
        if( !empty( $settings['save_form_progress'] ) ) {
            $class .= ' super-save-progress';
        }

        // @since 4.9.3     - Adaptive placeholders
        if($settings['theme_style']=='super-style-one') $settings['enable_adaptive_placeholders'] = '';
        if( !empty($settings['enable_adaptive_placeholders']) ) {
            $class .= ' super-adaptive';
        } 
 
        $entry_data = null;

        $contact_entry_id = 0;
        if( isset( $_GET['contact_entry_id'] ) ) {
            $contact_entry_id = absint($_GET['contact_entry_id']);
        }else{
            if( isset( $_POST['contact_entry_id'] ) ) {
                $contact_entry_id = absint($_POST['contact_entry_id']);
            }
        }
        if($contact_entry_id!=0){
            // If Admin, we are allowed to access this data directly
            if( current_user_can('administrator') ) {
                $entry_data = get_post_meta( $contact_entry_id, '_super_contact_entry_data', true );
                if(!empty($entry_data)){
                    unset($entry_data['hidden_form_id']);
                }
            }else{
                // User must be logged in to access this data
                $current_user_id = get_current_user_id();
                if( $current_user_id!=0 ) {
                    // By default retrieve entry data based on this form ID
                    $form_ids = array($form_id);
                    // Check if we are retrieving entry data based on other form ID
                    if( ( isset( $settings['retrieve_last_entry_form'] ) ) && ( $settings['retrieve_last_entry_form']!='' ) ) {
                        $form_ids = explode( ",", $settings['retrieve_last_entry_form'] );
                    }
                    $form_ids = implode("','", $form_ids);
                    // Lookup contact entries based on this user ID and form ID(s)
                    global $wpdb;
                    $table = $wpdb->prefix . 'posts';
                    $table_meta = $wpdb->prefix . 'postmeta';
                    $entry = $wpdb->get_results("
                    SELECT  ID 
                    FROM    $table 
                    WHERE   post_author = $current_user_id AND
                            post_parent IN ('$form_ids') AND
                            post_status IN ('publish','super_unread','super_read') AND 
                            post_type = 'super_contact_entry'
                    ORDER BY ID DESC
                    LIMIT 1");
                    if( isset($entry[0])) {
                        $entry_data = get_post_meta( $entry[0]->ID, '_super_contact_entry_data', true );
                        if(!empty($entry_data)){
                            unset($entry_data['hidden_form_id']);
                        }
                    }
                }
            }
        }
        // @since 2.9.0 - autopopulate form with user last submitted entry data
        if( ( isset( $settings['retrieve_last_entry_data'] ) ) && ( $settings['retrieve_last_entry_data']=='true' ) ) {

            // @since 3.8.0 - retrieve entry data based on $_GET['contact_entry_id'] or $_POST['contact_entry_id'] 
            if( empty($contact_entry_id) ) {
                $current_user_id = get_current_user_id();
                if( $current_user_id!=0 ) {
                    $form_ids = array($form_id);
                    if( ( isset( $settings['retrieve_last_entry_form'] ) ) && ( $settings['retrieve_last_entry_form']!='' ) ) {
                        $form_ids = explode( ",", $settings['retrieve_last_entry_form'] );
                    }
                    $form_ids = implode("','", $form_ids);

                    // First check if we can find contact entries based on user ID and Form ID
                    global $wpdb;
                    $table = $wpdb->prefix . 'posts';
                    $table_meta = $wpdb->prefix . 'postmeta';
                    $entry = $wpdb->get_results("
                    SELECT  ID 
                    FROM    $table 
                    WHERE   post_author = $current_user_id AND
                            post_parent IN ('$form_ids') AND
                            post_status IN ('publish','super_unread','super_read') AND 
                            post_type = 'super_contact_entry'
                    ORDER BY ID DESC
                    LIMIT 1");
                    if( isset($entry[0])) {
                        // If entry exists, set the ID so we can actually update it based on the ID later
                        if( !empty($settings['update_contact_entry']) ) {
                            $contact_entry_id = absint($entry[0]->ID);
                        }
                        $entry_data = get_post_meta( $entry[0]->ID, '_super_contact_entry_data', true );
                        if(!empty($entry_data)){
                            unset($entry_data['hidden_form_id']);
                        }
                    }
                }
            }
        }

        // @since 3.2.0 - if entry data was not found based on user last entry, proceed and check if we need to get form progress for this form
        $formProgress = false;
        if( ($entry_data==null) && ( (isset($settings['save_form_progress'])) && ($settings['save_form_progress']=='true') ) ) {
            $form_progress = SUPER_Forms()->session->get( 'super_form_progress_' . $form_id );
            if($form_progress!=false){
                $entry_data = $form_progress;
                $formProgress = true;
            }
        }

        $result = '';
        if(!$elements_only){
            $result .= '<style type="text/css">.super-form:not(.super-initialized) *:not(.super-load-icon) { visibility: hidden !important; }</style>';
            $result .= '<div id="super-form-' . $form_id . '" '; 
            $result .= $styles;
            $result .= 'class="super-form ';
            $result .= ( $settings['form_preload'] == 0 ? 'preload-disabled ' : '' );
            $result .= 'super-form-' . $form_id;
            $result .= ' ' . $class;
            $result .= '"';
            $result .= ( (isset($settings['form_hide_after_submitting'])) && ($settings['form_hide_after_submitting']=='true') ? ' data-hide="true"' : '' );
            $result .= ( (isset($settings['form_clear_after_submitting'])) && ($settings['form_clear_after_submitting']=='true') ? ' data-clear="true"' : '' );
            $result .= ( (isset($settings['form_processing_overlay'])) && ($settings['form_processing_overlay']=='true') ? ' data-overlay="true"' : '' );
            
            // @since 3.3.0     - Disable submission on "Enter" 
            $result .= ( (isset($settings['form_disable_enter'])) && ($settings['form_disable_enter']=='true') ? ' data-disable-enter="true"' : '' );

            $result .= ' data-field-size="' . $settings['theme_field_size'] . '"';
            
            // @since 4.7.0 - translation
            if(!empty($i18n)){
                $result .= ' data-i18n="' . $i18n . '"';
            }
            $result .= '>';
            
            // @since 4.7.0 - improved method to center form and to give max width to the form
            if( !empty( $settings['theme_max_width'] ) ) {
                $result .= '<div class="super-max-width-wrapper" style="max-width:' . $settings['theme_max_width'] . 'px;">';
            }

            // @since 3.0.0 - new loading method (gif stops/freezes animating when browser is doing javascript at background)
            $result .= '<span class="super-load-icon"></span>';




            // @since 4.7.0 - translation langauge switcher
            if(empty($settings['i18n_switch'])) $settings['i18n_switch'] = 'false';
            if($settings['i18n_switch']=='true'){
                $translations = SUPER_Common::get_form_translations($form_id);
                if(!empty($translations) && is_array($translations)){
                    wp_enqueue_style( 'super-flags', SUPER_PLUGIN_FILE . 'assets/css/frontend/flags.css', array(), SUPER_VERSION );    
                    $default_language = current($translations);
                    // Set default language to current language if not empty
                    if(!empty($i18n)) $default_language = $translations[$i18n];

                    $result .= '<div class="super-i18n-switcher">';
                    foreach($translations as $tk => $tv){
                        $translations[$tk]['checked'] = 'false';
                        $translations[$tk]['value'] = $tk;
                        $translations[$tk]['label'] = $tv['language'];
                        $translations[$tk]['flag'] = $tv['flag'];
                        if($default_language['flag'] == $tv['flag']){
                            $translations[$tk]['checked'] = 'true';
                        }
                    }
                    $result .= self::dropdown( 
                        $tag = 'dropdown',
                        $atts = array(
                            'language_switch' => true,
                            'default_language' => $default_language,
                            'name' => 'title',
                            'email' => 'Title:',
                            'dropdown_items' => $translations,
                            'placeholder' => '- select your language -',
                            'placeholderFilled' => '- select your language -',
                            'validation' => 'none',
                            'absolute_default' => ''
                        ),
                        $inner=array(), $shortcodes=null, $settings, $i18n, $builder=false, $entry_data=null
                    );
                    $result .= '</div>';
                }
            }

            // @since 1.8 - needed for autocomplete
            $result .= '<form tabindex="0" autocomplete="on"';
            $enctype = apply_filters( 'super_form_enctype_filter', 'multipart/form-data', array( 'id'=>$form_id, 'settings'=>$settings ) );
            if( !empty($enctype) ) {
                $result .= ' enctype="' . esc_attr($enctype) . '"';
            }

            // @since 3.6.0 - custom POST parameters method
            if( empty($settings['form_post_custom']) ) $settings['form_post_custom'] = '';

            // @since 2.2.0 - custom POST method
            if( ( isset( $settings['form_post_option'] ) ) && ( $settings['form_post_option']=='true' ) && ( $settings['form_post_custom']!='true' ) ) {
                $result .= ' method="post" action="' . $settings['form_post_url'] . '" data-actiontags="' . $settings['form_post_url'] . '">';
                $result .= '<textarea class="super-hidden" name="json_data"></textarea>';
            }else{
                $result .= '>';
            }
        }

        // @since 3.4.0 - Lock form after specific amount of submissions (based on total contact entries created)
        if( !empty($settings['form_locker']) ) {
            if( !isset($settings['form_locker_limit']) ) $settings['form_locker_limit'] = 0;
            $limit = $settings['form_locker_limit'];
            $count = get_post_meta( $form_id, '_super_submission_count', true );
            $display_msg = false;
            if( $count>=$limit ) {
                $display_msg = true;
            }
            if( !empty($settings['form_locker_reset']) ) {
                // Check if we need to reset the lock counter based on locker reset
                $last_date = get_post_meta( $form_id, '_super_last_submission_date', true );
                $reset = $settings['form_locker_reset'];
                switch ($reset) {
                    case 'daily':
                        $current_date = (int)date_i18n('Yz');
                        $last_date = (int)date_i18n('Yz', strtotime($last_date));
                        break;
                    case 'weekly':
                        $current_date = (int)date_i18n('YW');
                        $last_date = (int)date_i18n('YW', strtotime($last_date));
                        break;
                    case 'monthly':
                        $current_date = (int)date_i18n('Yn');
                        $last_date = (int)date_i18n('Yn', strtotime($last_date));
                        break;
                    case 'yearly':
                        $current_date = (int)date_i18n('Y');
                        $last_date = (int)date_i18n('Y', strtotime($last_date));
                        break;
                }
                if($current_date>$last_date){
                    // Reset locker
                    update_post_meta( $form_id, '_super_submission_count', 0 );
                    $display_msg = false;
                }
            }
            if( $display_msg ) {
                if(!empty($settings['form_locker_msg'])) {
                    $result .= '<div class="super-msg super-error">';
                    if($settings['form_locker_msg_title']!='') {
                        $result .= '<h1>' . $settings['form_locker_msg_title'] . '</h1>';
                    }
                    $result .= nl2br($settings['form_locker_msg_desc']);
                    $result .= '<span class="super-close"></span>';
                    $result .= '</div>';
                    if($settings['form_locker_hide']=='true') {
                        $result .= '</form>';
                        $result .= '</div>';
                        return $result;
                    }
                }else{
                    // Do not display anything
                    return '';
                }
            }
        }

        // @since 3.8.0 - Lock form after specific amount of submissions for logged in user (based on total contact entries created by user)
        if( !empty($settings['user_form_locker']) ) {

            // Let's check if the user is logged in
            $current_user_id = get_current_user_id();
            if( $current_user_id!=0 ) {
                
                // Let's check the total contact entries this user has created for this specific form
                $user_limits = get_post_meta( $form_id, '_super_user_submission_counter', true );
                $count = 0;
                if( !empty($user_limits[$current_user_id]) ) {
                    $count = $user_limits[$current_user_id];
                }
              
                // Let's check if the total amount of entries reaches the limit set for this form
                $limit = 0;
                if( !empty($settings['user_form_locker_limit']) ) {
                    $limit = $settings['user_form_locker_limit'];
                } 

                $display_msg = false;
                if( $count>=$limit ) {
                    $display_msg = true;
                }
                if( !empty($settings['user_form_locker_reset']) ) {
                    // Check if we need to reset the lock counter based on locker reset
                    $last_date = get_post_meta( $form_id, '_super_last_submission_date', true );
                    $reset = $settings['user_form_locker_reset'];
                    switch ($reset) {
                        case 'daily':
                            $current_date = (int)date_i18n('Yz');
                            $last_date = (int)date_i18n('Yz', strtotime($last_date));
                            break;
                        case 'weekly':
                            $current_date = (int)date_i18n('YW');
                            $last_date = (int)date_i18n('YW', strtotime($last_date));
                            break;
                        case 'monthly':
                            $current_date = (int)date_i18n('Yn');
                            $last_date = (int)date_i18n('Yn', strtotime($last_date));
                            break;
                        case 'yearly':
                            $current_date = (int)date_i18n('Y');
                            $last_date = (int)date_i18n('Y', strtotime($last_date));
                            break;
                    }
                    if( $current_date>$last_date ) {
                        // Reset locker
                        delete_post_meta( $form_id, '_super_user_submission_counter' );
                        $display_msg = false;
                    }
                }
                if( $display_msg ) {
                    if(!empty($settings['user_form_locker_msg'])) {
                        $result .= '<div class="super-msg super-error">';
                        if(!empty($settings['user_form_locker_msg_title'])) {
                            $result .= '<h1>' . $settings['user_form_locker_msg_title'] . '</h1>';
                        }
                        $result .= nl2br($settings['user_form_locker_msg_desc']);
                        $result .= '<span class="super-close"></span>';
                        $result .= '</div>';
                        if(!empty($settings['user_form_locker_hide'])) {
                            $result .= '</form>';
                            $result .= '</div>';
                            return $result;
                        }
                    }else{
                        // Do not display anything
                        return '';
                    }
                }
            }
        }

        // Display message to admin if the form is in debug mode for PDF generator
        if(!empty($settings['_pdf'])) {
            if($settings['_pdf']['generate']==='true' && $settings['_pdf']['debug']==='true') {
                $result .= '<div class="super-msg super-info" data-pdfoption="exclude">';
                    if($settings['form_locker_msg_title']!='') {
                        $result .= '<h1>'.esc_html__( 'PDF Generator debug mode is enabled!', 'super-forms' ).'</h1>';
                    }
                    $result .= esc_html__( 'The form will not be submitted, no email will be send and no Contact Entry will be saved. Only the PDF file will be generated and downloaded for testing purposes.', 'super-forms' );
                    $result .= '<span class="super-close"></span>';
                $result .= '</div>';
            }
        }
        
        // @since 4.6.0 - add nonce field
        $super_ajax_nonce = wp_create_nonce( 'super_submit_' . $form_id );
        $result .= '<input type="hidden" name="super_ajax_nonce" value="' . esc_attr($super_ajax_nonce) . '" />';

        // @since 3.2.0 - add honeypot captcha
        $result .= '<input type="text" name="super_hp" size="25" value="" />';

        // @since 3.1.0 - filter to add any HTML before the first form element
        $result = apply_filters( 'super_form_before_first_form_element_filter', $result, array( 'id'=>$form_id, 'settings'=>$settings ) );

        $result .= '<div class="super-shortcode super-field super-hidden">';
        $result .= '<input class="super-shortcode-field" type="hidden" value="' . absint($form_id) . '" name="hidden_form_id" />';
        $result .= '</div>';

        // When editing a contact entry, we need to pass the below values to handle the ajax request
        if($editingContactEntry===true){
            // Holds list ID
            $result .= '<div class="super-shortcode super-field super-hidden">';
            $result .= '<input class="super-shortcode-field" type="hidden" value="' . absint($list_id) . '" name="hidden_list_id" />';
            $result .= '</div>';
        }

        // Grab all form elements
        $elements = get_post_meta( $form_id, '_super_elements', true );
        if( !is_array($elements) ) {
            $elements = json_decode( $elements, true );
        }

        // @since 2.2.0 - update contact entry by ID
        if( (isset( $settings['update_contact_entry'] )) && ($settings['update_contact_entry']=='true') ) {
            
            // @since 4.7.7 - only add this field if no such field name already exists
            // otherwise we would end up with duplicate fields
            $re = '/{"name":"hidden_contact_entry_id"/';
            $str = json_encode($elements);
            preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);
            if(empty($matches)){
                $result .= '<div class="super-shortcode super-field super-hidden">';
                    $result .= '<input class="super-shortcode-field" type="hidden" value="' . absint($contact_entry_id) . '" name="hidden_contact_entry_id" />';
                $result .= '</div>';
            }
        }

        // Loop through all form elements
        if( !empty( $elements ) ) {
            $shortcodes = self::shortcodes();
            // Before doing the actuall loop we need to know how many columns this form contains
            // This way we can make sure to correctly close the column system
            $GLOBALS['super_column_found'] = 0;
            foreach( $elements as $k => $v ) {
                if( $v['tag']=='column' ) $GLOBALS['super_column_found']++;
            }
            foreach( $elements as $k => $v ) {
                if( empty($v['data']) ) $v['data'] = null;
                if( empty($v['inner']) ) $v['inner'] = null;
                $result .= self::output_element_html( $v['tag'], $v['group'], $v['data'], $v['inner'], $shortcodes, $settings, $i18n, false, $entry_data, $dynamic=0, $dynamic_field_names=array(), $inner_field_names=array(), $formProgress );
            }
        }
        
        // Make sure to only return the default submit button if no custom button was used
        if(!isset($GLOBALS['super_custom_button_used'])){
            $result .= self::button( 'button', array(), '', '', $settings, $i18n );
        }
        // In case of editing an entry via Listings Add-on, make sure we add a submit button
        if( !isset($GLOBALS['super_submit_button_found']) && $editingContactEntry===true ){
            $result .= self::button( 'button', array('name'=>esc_html__( 'Update', 'super-forms' )), '', '', $settings, $i18n );
        }

        // Always unset after all elements have been processed
        unset($GLOBALS['super_custom_button_used']);
        unset($GLOBALS['super_submit_button_found']);
        unset($GLOBALS['super_first_multipart']); // @since 2.6.0

        // @since 3.1.0 - filter to add any HTML after the last form element
        $result = apply_filters( 'super_form_after_last_form_element_filter', $result, array( 'id'=>$form_id, 'settings'=>$settings ) );

        if(!$elements_only){
            $result .= '</form>';
 
            // @since 4.7.0 - improved method to center form and to give max width to the form
            if( !empty( $settings['theme_max_width'] ) ) {
                $result .= '</div>';
            }

            $result .= '</div>';

            // @since 1.3   - put styles in global variable and append it to the footer at the very end
            SUPER_Forms()->form_custom_css .= apply_filters( 'super_form_styles_filter', $style_content, array( 'id'=>$form_id, 'settings'=>$settings ) );

            // @since 1.2.8     - Custom CSS per Form
            if( !isset( $settings['form_custom_css'] ) ) $settings['form_custom_css'] = '';
            $settings['form_custom_css'] = stripslashes($settings['form_custom_css']);
            SUPER_Forms()->form_custom_css .= $settings['form_custom_css'];

            // @since 4.2.0 - custom JS script
            $js = '';
            if( !empty(SUPER_Forms()->theme_custom_js) ) {
                $js .= SUPER_Forms()->theme_custom_js;
            }
            $global_settings = SUPER_Common::get_global_settings();
            if( !empty($global_settings['theme_custom_js']) ) {
                $js .= $global_settings['theme_custom_js'];
            }
            SUPER_Forms()->theme_custom_js = apply_filters( 'super_form_js_filter', $js, array( 'id'=>$form_id, 'settings'=>$settings ) );

            $result = apply_filters( 'super_form_before_do_shortcode_filter', $result, array( 'id'=>$form_id, 'settings'=>$settings ) );

        }

        if( class_exists( 'SUPER_WooCommerce' ) ){
            add_action( 'pre_get_posts', array( SUPER_WooCommerce(), 'exclude_products_from_shop' ) );
        }

        // If on back-end builder page
        if( !empty($_POST['action']) && $_POST['action'] === 'super_load_preview' ){
            $css = SUPER_Forms()->form_custom_css;
            $global_css = '';
            if( isset(SUPER_Forms()->global_settings) ) {
                if( isset(SUPER_Forms()->global_settings['theme_custom_css']) ) {
                    $global_css = stripslashes(SUPER_Forms()->global_settings['theme_custom_css']);
                }
            }
            if( $css!='' ) $result .= '<style type="text/css">' . $global_css . $css . '</style>';
        }

        return do_shortcode( $result );
    }

}

endif;