<?php

if( ! function_exists('dd') ){

    /**
     * Dumps the given values in a human-readable format.
     * 
     * ***************************
     * FOR DEVELOPMENT AND DEBUG PERPOSE
     * ***************************
     *
     * This function accepts a variable number of arguments and
     * outputs each value using `var_dump()` wrapped in `<pre>` tags
     * for improved readability. It only processes non-empty arrays.
     *
     * @param mixed ...$vals Variable number of arguments to be dumped.
     */
	function dd(...$vals) {
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0];
        $file = $backtrace['file'] ?? 'Unknown file';
        $line = $backtrace['line'] ?? 'Unknown line';
        echo '<div style="background: #e1e1e1;border-left: 3px solid #888;padding: 15px;margin: 15px 0;margin-left: 7px;font-family: monospace;border-radius: 6px;overflow-x: auto;">';
        echo '<div style="margin-bottom: 10px;color: #3F51B5;">';
        echo "🛠️ <strong>File:</strong> <span style='color:#8d8d8d;'>$file</span> on line <span style='color:#4b4b4b;'>$line</span>";
        echo '</div>';
        foreach ($vals as $val) {
            ob_start();
            var_dump($val);
            $output = ob_get_clean();
            // HTML entities
            echo '<pre style="color: #777777;background: #ffffff9c;">' . htmlspecialchars($output) . '</pre>';
        }
        echo '</div>';
    }

}

/**
 * Check is premium version active or not
 * 
 * even old pro version(WC_Min_Max_Quantity) is active then also return true
 *
 * @return boolean
 */
function wpt_is_premium(){
    if( defined( 'WPT_PRO_DEV_VERSION' ) ) return true;
    return false;
}
/**
 * Check is premium version installed or not
 *
 * @return boolean
 */
function wpt_is_premium_installed(){
    if( defined( 'WPT_PRO_DEV_VERSION' ) ) return true;
    return false;
}

/**
 * check pro available or not
 * 
 * @since 3.0.1
 * @by Saiful
 * 
 * @return boolean true|false
 */
if (!function_exists('wpt_is_pro')) {
    function wpt_is_pro()
    {
        return wpt_is_premium();
    }
}


if( !function_exists( 'wpt_column_setting_for_tax_cf' ) ){
    
    /**
     * Using @Hook Filter wpto_column_settings
     * That Filter are situated in two place. In main function and another in shortcode_row_generator function.
     * To identity Old ShortCode system, such: cf_ [prefix] and tax_ [prefix] of custom field and taxonomy column
     * 
     * @param array $column_settings
     * @param int $table_ID
     * @param array $enabled_column_array
     * @return array $column_settings Array, which is most important for Each Column and Items.
     */
    function wpt_column_setting_for_tax_cf( $column_settings, $table_ID, $enabled_column_array ){

        if( is_array( $enabled_column_array ) && count( $enabled_column_array ) > 0 ){
            foreach( $enabled_column_array as $enbl_col => $val ){
                if( substr($enbl_col, 0,3) == 'cf_' ){
                    $column_settings[$enbl_col]['type'] = 'custom_field';
                    $column_settings[$enbl_col]['type_name'] = __( 'Custom Field', 'woo-product-table' );
                    $column_settings[$enbl_col]['older'] = true;
                }
                if( substr($enbl_col, 0,4) == 'tax_' ){
                    $column_settings[$enbl_col]['type'] = 'taxonomy';
                    $column_settings[$enbl_col]['type_name'] = __('Taxonomy', 'woo-product-table');
                    $column_settings[$enbl_col]['older'] = true;
                }
                
            }
        }
        return $column_settings;
    }
}
add_filter( 'wpto_column_settings', 'wpt_column_setting_for_tax_cf', 10, 3 );

if( ! function_exists( 'wpt_detect_current_device' ) ){

    function wpt_detect_current_device() {
        static $device = null;
        
        if ( null !== $device ) {
            return $device;
        }
        
        $detect = new Mobile_Detect();
        if ( $detect->isTablet() ) {
            $device = 'tablet';
        } elseif ( $detect->isMobile() ) {
            $device = 'mobile';
        } else {
            $device = 'desktop';
        }
        
        return $device;
    }
}
if( ! function_exists( 'wpt_extra_variation_title' ) ){

    /**
     * Add Extra Variation Title
     * using Following Filter:
     * apply_filters( 'wpto_variation_title_extra', $variation_title_extra, $product_type, $data );
     * 
     * @since 7.0.25
     * @param string $product_type
     * @param array $data
     * @return string
     */
    function wpt_extra_variation_title($product_type, $data){
        if( $product_type !== 'variation' ) return;

        $attribtues = $data['attributes'] ?? [];
        if( ! is_array( $attribtues ) ) return;
        if( count( $attribtues ) <= 2 ) return;
        $ext = implode(', ', $attribtues);
        return ! empty( $ext ) ? ' - ' . ucwords( $ext ) : '';
    }
}

if( ! function_exists( 'wpt_col_settingwise_device' ) ){
    
    /**
     * This will return column setting wise and founded device wise
     * final device option.
     * 
     * @param int $ID It's table ID. here should be table IT. not post id
     */
    function wpt_col_settingwise_device( $ID ){

        $_device_name = wpt_detect_current_device();
        $_device = $_device_name == 'desktop' ? '' : '_'.$_device_name;
        
        $enabled_column_array = get_post_meta( $ID, 'enabled_column_array' . $_device, true );
            
        if( empty( $enabled_column_array ) && $_device == '_mobile' ){
            $_device = '_tablet'; //Set Device Tablet here and we will use it for getting $column_Setting
            $enabled_column_array = get_post_meta( $ID, 'enabled_column_array' . $_device, true );
        }

        if( empty( $enabled_column_array ) ){
            $_device = ''; //Set Device Desktop, I mean, empty here and we will use it for getting $column_Setting
        }

        return $_device;
    }
}

if( ! function_exists( 'wpt_enabled_column_array' ) ){
    
    /**
     * Actually based on detected device, foudedd column setting and 
     * getting final column settings
     * 
     * @param int $table_ID Description
     * 
     * @return array
     */
    function wpt_enabled_column_array( $table_ID ){

        $_device = wpt_col_settingwise_device( $table_ID );
        $enabled_column_array = get_post_meta( $table_ID, 'enabled_column_array' . $_device, true );

        return is_array( $enabled_column_array ) ? $enabled_column_array : array();
    }
}





if( ! function_exists( 'wpt_device_wise_class' ) ){

    /**
     * Add Device Wise Class
     * using Following Filter:
     * apply_filters( 'wpto_wrapper_tag_class_arr', $wrapper_class_arr, $table_ID, $args, $column_settings, $enabled_column_array, $column_array );
     * 
     * @since 2.7.0.36
     * @param array $wrapper_class_arr
     * @return array
     */
    function wpt_device_wise_class( $wrapper_class_arr ){

       $device = wpt_detect_current_device();
       $wrapper_class_arr[] = 'wpt_device_' . $device;
       
       return $wrapper_class_arr;
   }
}
/**
 * Available Variable in this Filters is:
 * $enabled_column_array, $table_ID, $atts, $column_settings, $column_array
 * Purpose is: Change/Edit/Customize to Enabled Column Array
 */
add_filter( 'wpto_wrapper_tag_class_arr', 'wpt_device_wise_class');
add_filter( 'body_class', 'wpt_device_wise_class' );

if( ! function_exists( 'wpt_table_td_class' ) ){

    /**
     * Add TD Class
     * using Following Filter:
     * apply_filters( 'wpto_td_class_arr', $td_class_arr, $keyword, $table_ID, $args, $column_settings, $table_column_keywords, $product )
     * 
     * @since 2.7.0.36
     * @param array $td_class_arr Array of TD class, which will apply in TD tag of each column
     * @param string $keyword Column Keyword, such as: price, stock, etc. based on keyword, you can add class for specific column. and also you can use $column_settings and $table_ID for getting more information about column and table.
     * @param int $table_ID Table ID
     * @return array
     */
    function wpt_table_td_class( $td_class_arr, $keyword, $table_ID ){

        $not_acpt = array(
            'action',
            'product_title',
            'check'
        );

        if( in_array( $keyword, $not_acpt ) ){
            return $td_class_arr;
        }
        
        $basics = get_post_meta( $table_ID, 'basics', true );
        $responsive = isset( $basics['responsive'] ) ? $basics['responsive'] : 'no_responsive';
        if( $responsive == 'mobile_responsive' ){
            $td_class_arr[] = 'wpt_for_product_desc';
        }

       return $td_class_arr;
   }
}
add_filter( 'wpto_td_class_arr', 'wpt_table_td_class',10,3 );

if( ! function_exists( 'wpt_checkbox_validation' ) ){

    /**
     * Checkbox Enable Disable
     * using Following Filter:
     * $checkbox_validation = apply_filters( 'wpto_checkbox_validation', false, $enabled_column_array,$column_settings, $table_ID, $atts );
     * 
     * @since 2.8.5.3
     * @param bool $bool This is default value, which is false. if you want to enable checkbox column, then you have to return true. otherwise, it will be false and checkbox column will be disable.
     * @param array $enabled_column_array
     * @param array $column_settings
     * @return bool
     */
    function wpt_checkbox_validation( $bool, $enabled_column_array,$column_settings ){

        if( ! is_array( $enabled_column_array ) || !is_array( $column_settings ) ) return false;
        
        if( isset( $enabled_column_array['check'] ) ){
            if( ! is_user_logged_in() && isset( $column_settings['check']['only_login_user'] ) ) return false;
            if( ! is_user_logged_in() && isset( $column_settings['action']['only_login_user'] ) ) return false;
            return true;
        }

        return false;
   }
}
add_filter( 'wpto_checkbox_validation', 'wpt_checkbox_validation', 10, 3);

if( ! function_exists( 'wpt_product_title_column_add' ) ){
    
    /**
     * Add Extra Option in Product Title Column
     * using Following Action:
     * do_action( 'wpto_column_setting_form_product_title', $_device_name, $column_settings );
     * 
     * @since 3.2.0
     * @param string $_device_name Detected Device Name, such as: desktop, mobile, tablet. based on this device name, you can add device wise option for title column.
     * @param array $column_settings Column settings of product title column. you can use this setting for adding condition and also for getting current setting value.
     * @return void
     */
    function wpt_product_title_column_add( $_device_name, $column_settings ){
        
        $title_variation = isset( $column_settings['title_variation']) ? $column_settings['title_variation'] : 'link';

        
        $variation_in_title =  $column_settings['product_title']['variation_in_title'] ?? '';
        $variation_in_title = $variation_in_title == 'on' ? 'checked="checked"' : '';
        $variation_title_hide =  $column_settings['product_title']['variation_title_hide'] ?? '';
        $variation_title_hide = $variation_title_hide == 'on' ? 'checked="checked"' : '';

        $description_off =  isset( $column_settings['description_off'] ) ? $column_settings['description_off'] : 'on';
        $description_off = $description_off == 'off' ? 'checked="checked"' : '';
       ?>
        <div class="description_off_wrapper">
            <label for="description_off<?php echo esc_attr( $_device_name ); ?>"><input id="description_off<?php echo esc_attr( $_device_name ); ?>" title="Disable Deactivate Description from Title Column" name="column_settings<?php echo esc_attr( $_device_name ); ?>[description_off]" id="description_off" class="description_off" type="checkbox" value="off" <?php echo esc_attr( $description_off ); ?>> <?php echo esc_html__( 'Disable Description', 'woo-product-table' ); ?></label>
            <label for="variation_in_title<?php echo esc_attr( $_device_name ); ?>" style="display:none;"><input id="variation_in_title<?php echo esc_attr( $_device_name ); ?>" title="Show variation names with title" name="column_settings<?php echo esc_attr( $_device_name ); ?>[product_title][variation_in_title]" id="variation_in_title" class="variation_in_title" type="checkbox" <?php echo esc_attr( $variation_in_title ); ?>> <?php echo esc_html__( 'Show Variation Name With Title', 'woo-product-table' ); ?></label>
            <label for="variation_title_hide<?php echo esc_attr( $_device_name ); ?>" style="color: #607D8B;font-weight: normal;"><input id="variation_title_hide<?php echo esc_attr( $_device_name ); ?>" title="Hide variation names from title" name="column_settings<?php echo esc_attr( $_device_name ); ?>[product_title][variation_title_hide]" id="variation_title_hide" class="variation_title_hide" type="checkbox" <?php echo esc_attr( $variation_title_hide ); ?>> <?php echo esc_html__( 'Hide Variation Name From Title', 'woo-product-table' ); ?></label>
        </div>
        <div class="title_variation">
            <label for="link<?php echo esc_attr( $_device_name ); ?>"><input type="radio" id="link<?php echo esc_attr( $_device_name ); ?>" name="column_settings<?php echo esc_attr( $_device_name ); ?>[title_variation]" value="link" <?php echo !$title_variation || $title_variation == 'link' ? 'checked' : ''; ?>> <?php echo esc_html__( 'Link Enable', 'woo-product-table' ); ?></label>
            <label for="nolink<?php echo esc_attr( $_device_name ); ?>"><input type="radio" id="nolink<?php echo esc_attr( $_device_name ); ?>" name="column_settings<?php echo esc_attr( $_device_name ); ?>[title_variation]" value="nolink" <?php echo $title_variation == 'nolink' ? 'checked' : ''; ?>> <?php echo esc_html__( 'Link Disable', 'woo-product-table' ); ?></label>
            <label for="ca_quick_view<?php echo esc_attr( $_device_name ); ?>" class="tooltip"><input type="radio" id="ca_quick_view<?php echo esc_attr( $_device_name ); ?>" name="column_settings<?php echo esc_attr( $_device_name ); ?>[title_variation]" value="ca_quick_view" <?php echo $title_variation == 'ca_quick_view' ? 'checked' : ''; ?>> <?php echo esc_html__( 'Quick View - BizzView', 'woo-product-table' ); ?><span class="tooltip-hover down-arrow"><?php echo esc_html__( 'You have to install', 'woo-product-table' ); ?> <a href="https://wordpress.org/plugins/ca-quick-view/" target="_blank"><?php echo esc_html__( 'BizzView - Quick View', 'woo-product-table' ); ?></a></span></label>
            <label for="yith<?php echo esc_attr( $_device_name ); ?>" style="opacity:0.041" class="tooltip"><input type="radio" id="yith<?php echo esc_attr( $_device_name ); ?>" name="column_settings<?php echo esc_attr( $_device_name ); ?>[title_variation]" value="yith" <?php echo $title_variation == 'yith' ? 'checked' : ''; ?>> <?php echo esc_html__( 'Link Disable + Quick View', 'woo-product-table' ); ?><span class="tooltip-hover down-arrow"><?php echo esc_html__( 'You have to install', 'woo-product-table' ); ?> <a href="https://wordpress.org/plugins/yith-woocommerce-quick-view/" target="_blank"><?php echo esc_html__( 'YITH WooCommerce Quick View', 'woo-product-table' ); ?></a></span></label>
        </div>        

       <?php
   }
}
//$keyword, $_device_name, $column_settings, $columns_array, $updated_columns_array, $post, $additional_data
add_action( 'wpto_column_setting_form_product_title', 'wpt_product_title_column_add', 10, 2 );

if( ! function_exists( 'wpt_thumbnails_column_add' ) ){
    
    /**
     * Add Extra Option in Thumbnails Column
     * using Following Action:
     * do_action( 'wpto_column_setting_form_thumbnails', $_device_name, $column_settings );
     * 
     * @since 3.1.2.3
     * @param string $_device_name Detected Device Name, such as: desktop, mobile, tablet. based on this device name, you can add device wise option for thumbnail column.
     * @param array $column_settings Column settings of thumbnail column. you can use this setting for adding condition and also for getting current setting value.
     * @return void
     */
    function wpt_thumbnails_column_add( $_device_name, $column_settings ){

        $thumb_variation = isset( $column_settings['thumb_variation']) ? $column_settings['thumb_variation'] : 'ca_quick_view';
        $img_url = WPT_BASE_URL . 'assets/images/pro-features/';
       ?>
        <?php if( ! wpt_is_pro() ){ ?>
            <div class="thumb_gallery_wrapper wpt-premium-feature-in-free-version">
                <label for="thumb_gallery">
                <input id="thumb_gallery" title="Enable Gallery On Thumbnail Column" class="thumb_gallery" type="checkbox" value="off">
                Enable Gallery
                </label>
            </div>  
            
        <?php }?>
        <div class="thumb_variation">
            <label for="popup<?php echo esc_attr( $_device_name ); ?>"><input type="radio" id="popup<?php echo esc_attr( $_device_name ); ?>" name="column_settings<?php echo esc_attr( $_device_name ); ?>[thumb_variation]" value="popup" <?php echo !$thumb_variation || $thumb_variation == 'popup' ? 'checked' : ''; ?>> <?php echo esc_html__( 'Thumbs Popup', 'woo-product-table' ); ?></label>
            <label for="no_action<?php echo esc_attr( $_device_name ); ?>"><input type="radio" id="no_action<?php echo esc_attr( $_device_name ); ?>" name="column_settings<?php echo esc_attr( $_device_name ); ?>[thumb_variation]" value="no_action" <?php echo $thumb_variation == 'no_action' ? 'checked' : ''; ?>> <?php echo esc_html__( 'No Action', 'woo-product-table' ); ?></label>
            <label for="url<?php echo esc_attr( $_device_name ); ?>"><input type="radio" id="url<?php echo esc_attr( $_device_name ); ?>" name="column_settings<?php echo esc_attr( $_device_name ); ?>[thumb_variation]" value="url" <?php echo $thumb_variation == 'url' ? 'checked' : ''; ?>> <?php echo esc_html__( 'Product Link', 'woo-product-table' ); ?></label>
            
            <label for="ca_quick_view_thumb<?php echo esc_attr( $_device_name ); ?>" class="tooltip"><input type="radio" id="ca_quick_view_thumb<?php echo esc_attr( $_device_name ); ?>" name="column_settings<?php echo esc_attr( $_device_name ); ?>[thumb_variation]" value="ca_quick_view" <?php echo $thumb_variation == 'ca_quick_view' ? 'checked' : ''; ?>> <?php echo esc_html__( 'Quick View - BizzView', 'woo-product-table' ); ?><span class="tooltip-hover down-arrow"><?php echo esc_html__( 'You have to install', 'woo-product-table' ); ?> <a href="https://wordpress.org/plugins/ca-quick-view/" target="_blank"><?php echo esc_html__( 'BizzView - Quick View', 'woo-product-table' ); ?></a></span></label>
            <label for="quick_view<?php echo esc_attr( $_device_name ); ?>" style="opacity:0.041;" class="tooltip"><input type="radio" id="quick_view<?php echo esc_attr( $_device_name ); ?>" name="column_settings<?php echo esc_attr( $_device_name ); ?>[thumb_variation]" value="quick_view" <?php echo $thumb_variation == 'quick_view' ? 'checked' : ''; ?>> <?php echo esc_html__( 'Quick View', 'woo-product-table' ); ?><span class="tooltip-hover down-arrow"><?php echo esc_html__( 'You have to install', 'woo-product-table' ); ?> <a href="https://wordpress.org/plugins/yith-woocommerce-quick-view/" target="_blank"><?php echo esc_html__( 'YITH WooCommerce Quick View', 'woo-product-table' ); ?></a></span></label>
        </div>
        
       <?php
   }
}
add_action( 'wpto_column_setting_form_thumbnails', 'wpt_thumbnails_column_add', 10, 2 );



if( ! function_exists( 'wpt_column_tag_for_all' ) ){

    function wpt_column_tag_for_all( $keyword, $_device_name, $column_settings ){

        switch( $keyword ){
            case 'check':
            case 'tick':
            case 'serial_number':
            case 'total':
            case 'product_id': return;

        }

        $input_one = isset( $column_settings[$keyword]['input_one'] ) ? $column_settings[$keyword]['input_one'] : false;
        $tag_value = isset( $column_settings[$keyword]['tag'] ) ? $column_settings[$keyword]['tag'] : false;

        $tags = array(
            '' => __('No Tag', 'woo-product-table'),
            'section' => __('Section', 'woo-product-table'),
            'h1' => __('Heading 1', 'woo-product-table'),
            'h2' => __('Heading 2', 'woo-product-table'),
            'h3' => __('Heading 3', 'woo-product-table'),
            'h4' => __('Heading 4', 'woo-product-table'),
            'h5' => __('Heading 5', 'woo-product-table'),
            'h6' => __('Heading 6', 'woo-product-table'),
            'p' => __('Paragraph', 'woo-product-table'),
            'b' => __('Bold', 'woo-product-table'),
            'strong' => __('Strong', 'woo-product-table'),
            'span' => __('Span', 'woo-product-table'),
            'div' => __('Div', 'woo-product-table'),
        );

        ?>
        <div class="column_tag_for_all">
            <label><?php echo esc_html__( 'Select wrapper tag', 'woo-product-table' ); ?></label>
            <select class="ua_select" name="column_settings<?php echo esc_attr( $_device_name ); ?>[<?php echo esc_attr( $keyword ); ?>][tag]">    
            <?php
            foreach($tags as $tag => $tag_name){
                $seleced = $tag_value == $tag ? 'selected' : false;
                $output = "<option value='{$tag}' $seleced>$tag_name</option>";

                $allowed_atts = array(
                    'value'      => array(),
                    'selected'      => array(),
                );
    
                echo wp_kses( $output, array(
                    'option' => $allowed_atts
                ) );
            }
            ?>
            </select><?php wpt_doc_link('https://wooproducttable.com/docs/doc/table-design/select-wrapper-tag/'); ?>
        </div>
        <?php
    }
}

add_action( 'wpto_column_setting_form', 'wpt_column_tag_for_all', 10, 3 );

if( ! function_exists( 'wpt_column_add_extra_items' ) ){

    function wpt_column_add_extra_items( $keyword, $_device_name, $column_settings, $columns_array, $updated_columns_array, $post, $additional_data ){
        
        // if( $keyword == 'check' || $keyword == 'product_id' ) return;
        switch( $keyword ){
            case 'check': return;
            case 'tick': return;
            case 'serial_number': return;
            case 'total': return;
            case 'product_id': return;

        }

        unset( $columns_array[$keyword] ); //Unset this column. if in action, here $keyword - action
        
        unset( $columns_array['blank'] );
        unset( $columns_array['freeze'] );
        /**
         * Items actually Checked Items
         */
        $items = isset( $column_settings[$keyword]['items'] ) ? $column_settings[$keyword]['items'] : array();
        $items = is_array( $items ) ? $items : array();
        $items = array_filter( $items );
        
        $_items = $items;

        /**
         * @Hook Filter: wpto_inside_thecked_item_arr
         * Available Args: $items, $keyword, $column_settings, $columns_array, $post
         * To add Any Items for [Select multiple inner items]
         * Remember: It's only for Admin Product Table Edit. and data will debend on Save Only
         */
        $items = apply_filters( 'wpto_inside_checked_item_arr', $items, $keyword, $column_settings, $columns_array );
        if( is_array( $items ) && count( $items ) > 0 ){
            

            $columns_array = array_merge(array_flip($items),$columns_array);
        }
        ?>
        <div class="column_add_extra_items extra-inner-item-wrapper">
            <label for="<?php echo esc_attr( "column_settings{$_device_name}_{$keyword}" ); ?>"><?php echo esc_html__( 'Select multiple inner items:', 'woo-product-table' ); ?><?php wpt_doc_link('https://wooproducttable.com/docs/doc/table-options/select-multiple-inner-items/'); ?></label>
            
            <?php
            $select = "";
            $items_columns = $columns_array;
            $items_columns = apply_filters( 'wpto_inside_item_arr', $items_columns, $keyword, $column_settings, $post );
            $items_columns = apply_filters( 'wpto_inside_item_arr_' . $keyword, $items_columns, $column_settings, $post );
            foreach($items_columns as $key => $key_val){
                $seleced = in_array( $key,$items ) ? 'checked' : false;
                $seleced_option = in_array( $key,$items ) ? 'selected' : false;
                $unique_id = $keyword . '_' . $key . '_' . $_device_name;
                $select .= "<option value='" . esc_attr( $key ) . "' " . esc_attr( $seleced_option ) . "> " . esc_html( $key_val . " - " . $key ) . "</option>";

            }
            ?>

            <select 
                class="internal_select" 
                multiple="multiple" 
                id="<?php echo esc_attr( "column_settings{$_device_name}_{$keyword}" ); ?>"
                name="<?php echo esc_attr( "column_settings{$_device_name}[{$keyword}][items][]" ); ?>"
                >
                <?php 
                $allowed_atts = array(
                    'class'      => array(),
                    'id'         => array(),
                    'xml:lang'   => array(),
                    'value'      => array(),
                    'selected'   => array(),
                );

                echo wp_kses( $select, array(
                    'option' => $allowed_atts
                ) ); ?>
            </select>

        </div>
        <?php
    }
}

add_action( 'wpto_column_setting_form', 'wpt_column_add_extra_items', 10, 7 );

if( ! function_exists( 'wpt_add_extra_inside_items' ) ){

    /**
     * Add Extra Inside Items
     * using Following Filter:
     * apply_filters( 'wpto_inside_item_arr', $columns_array, $keyword, $column_settings, $post );
     * 
     * @since 3.1.5.1
     * @param array $columns_array Array of columns, which is most important for Each Column and Items. based on this array, you can add extra items for select multiple inner items option.
     * @return array    
     */
    function wpt_add_extra_inside_items( $columns_array ){

        $columns_array['menu_order'] = esc_html__( "Menu Order", 'woo-product-table' );

        return $columns_array;
    }
}

add_filter( 'wpto_inside_item_arr', 'wpt_add_extra_inside_items' ); //$items,$keyword, $column_settings, $columns_array, $post

if( ! function_exists( 'wpt_get_config' ) ){

    /**
     * WPML Applied here.
     * Automatically return value will be based on wpml language version.
     * 
     * Get only configuration value
     * from confiiguration page. It will not come from 
     * post ID actually
     * 
     * 
     *
     * @return array|string|null it will return an Array
     */
    function wpt_get_config( $config_key = false ){
        if( ! $config_key ) return wpt_get_config_value();

        $full_config = wpt_get_config_value();
        return $full_config[$config_key] ?? '';

    }
}
if( ! function_exists( 'wpt_get_config_value' ) ){
    /**
     * WPML Applied here.
     * Automatically return value will be based on wpml language version.
     * 
     * getting Config value. If get config value from post, then it will receive from post, Otherwise, will take data from Configuration value.
     * 
     * @param int|false $table_ID Mainly post ID of wpt_product_table. That means: its post id of product table
     * @return array It will return an Array, String, or Null
     */
    function wpt_get_config_value( $table_ID = false ){
        $root_option_key = $option_key = WPT_OPTION_KEY;
        $config_value = $temp_config_value = get_option( $option_key );
        $lang = apply_filters( 'wpml_current_language', NULL );
        
        if( ! empty( $lang ) ){

            $default_lang = apply_filters('wpml_default_language', NULL );
            $lang_ex = $lang == $default_lang ? '': '_' . $lang;
            $option_key =  $root_option_key . $lang_ex;

            $config_l_value = get_option( $option_key );

            $config_value = is_array( $config_value ) && is_array( $config_l_value ) ? array_merge( $config_value, $config_l_value ) : $config_value;
        }

        if( ! $table_ID ) return wpt_config_translate( $config_value, $table_ID );

        $config = get_post_meta( $table_ID, 'config', true );        
        $config = is_array( $config ) ? array_filter( $config ) : array();
        if( ! empty( $config ) && is_array( $config ) && is_array( $config_value ) ){
            $config_value = array_merge( $config_value, $config );
        }
        
        return wpt_config_translate( $config_value, $table_ID );
    }
}

/**
 * Speciall for Config value make as Translateable text
 * We will execute all value inside options, will convet to Translateable text
 * 
 * 
 *
 * @since 3.3.5.2.loco 
 * @author Saiful Islam <codersaiful@gmail.com>
 * 
 * @param array $config_value
 * @param boolean|int|string $table_ID
 * @return array
 */
function wpt_config_translate( $config_value, $table_ID = false ){
    if( ! is_array( $config_value ) ) return [];
//     $config_value = array_map( function( $value ){
        
//         if(is_string( $value )) return __( $value, 'woo-product-table' );
//         return $value;
        
//     }, $config_value );
    //Actually we will change this bellow filter keyword, removed o from wpt
    $config_value = apply_filters( 'wpt_get_config_value', $config_value, $table_ID );

    return $config_value;
}


/**
 * Displays or retrieves the HTML dropdown list of categories.
 *
 * The 'hierarchical' argument, which is disabled by default, will override the
 * depth argument, unless it is true. When the argument is false, it will
 * display all of the categories. When it is enabled it will use the value in
 * the 'depth' argument.
 *
 * @since 2.1.0
 * @since 4.2.0 Introduced the `value_field` argument.
 * @since 4.6.0 Introduced the `required` argument.
 *
 * @param array|string $args {
 *     Optional. Array or string of arguments to generate a categories drop-down element. See WP_Term_Query::__construct()
 *     for information on additional accepted arguments.
 *
 *     @type string       $show_option_all   Text to display for showing all categories. Default empty.
 *     @type string       $show_option_none  Text to display for showing no categories. Default empty.
 *     @type string       $option_none_value Value to use when no category is selected. Default empty.
 *     @type string       $orderby           Which column to use for ordering categories. See get_terms() for a list
 *                                           of accepted values. Default 'id' (term_id).
 *     @type bool         $pad_counts        See get_terms() for an argument description. Default false.
 *     @type bool|int     $show_count        Whether to include post counts. Accepts 0, 1, or their bool equivalents.
 *                                           Default 0.
 *     @type bool|int     $echo              Whether to echo or return the generated markup. Accepts 0, 1, or their
 *                                           bool equivalents. Default 1.
 *     @type bool|int     $hierarchical      Whether to traverse the taxonomy hierarchy. Accepts 0, 1, or their bool
 *                                           equivalents. Default 0.
 *     @type int          $depth             Maximum depth. Default 0.
 *     @type int          $tab_index         Tab index for the select element. Default 0 (no tabindex).
 *     @type string       $name              Value for the 'name' attribute of the select element. Default 'cat'.
 *     @type string       $id                Value for the 'id' attribute of the select element. Defaults to the value
 *                                           of `$name`.
 *     @type string       $class             Value for the 'class' attribute of the select element. Default 'postform'.
 *     @type int|string   $selected          Value of the option that should be selected. Default 0.
 *     @type string       $value_field       Term field that should be used to populate the 'value' attribute
 *                                           of the option elements. Accepts any valid term field: 'term_id', 'name',
 *                                           'slug', 'term_group', 'term_taxonomy_id', 'taxonomy', 'description',
 *                                           'parent', 'count'. Default 'term_id'.
 *     @type string|array $taxonomy          Name of the taxonomy or taxonomies to retrieve. Default 'category'.
 *     @type bool         $hide_if_empty     True to skip generating markup if no categories are found.
 *                                           Default false (create select element even if no categories are found).
 *     @type bool         $multiple          Whether the `<select>` element should have the HTML5 'required' attribute.
 *                                           Default false.
 * }
 * @return string HTML dropdown list of categories.
 */
function wpt_wp_dropdown_categories( $args = '', $get_taxonomy = false ) {

	$defaults = array(
		'show_option_all'   => '',
		'show_option_none'  => '',
		'orderby'           => 'id',
		'order'             => 'ASC',
		'show_count'        => 0,
		'hide_empty'        => 1,
		'child_of'          => 0,
		// 'exclude'           => '',
		'echo'              => 1,
		'selected'          => 0,
		'hierarchical'      => 0,
		'name'              => 'cat',
		'id'                => '',
		'class'             => 'postform',
		'depth'             => 0,
		'tab_index'         => 0,
		'taxonomy'          => 'category',
		'hide_if_empty'     => false,
		'option_none_value' => -1,
		'value_field'       => 'term_id',
		'multiple'          => false,
        'data-key'          => false,
	);
        
	$defaults['selected'] = ( is_category() ) ? get_query_var( 'cat' ) : 0;

	// Back compat.
	if ( isset( $args['type'] ) && 'link' === $args['type'] ) {
		_deprecated_argument(
			__FUNCTION__,
			'3.0.0',
			sprintf(
				/* translators: 1: "type => link", 2: "taxonomy => link_category" */
				__( '%1$s is deprecated. Use %2$s instead.', 'woo-product-table' ),
				'<code>type => link</code>',
				'<code>taxonomy => link_category</code>'
			)
		);
		$args['taxonomy'] = 'link_category';
	}

	// Parse incoming $args into an array and merge it with $defaults.
	$parsed_args = wp_parse_args( $args, $defaults );

	$option_none_value = $parsed_args['option_none_value'];

	if ( ! isset( $parsed_args['pad_counts'] ) && $parsed_args['show_count'] && $parsed_args['hierarchical'] ) {
		$parsed_args['pad_counts'] = true;
	}

	$tab_index = $parsed_args['tab_index'];

	$tab_index_attribute = '';
	if ( (int) $tab_index > 0 ) {
		$tab_index_attribute = " tabindex=\"$tab_index\"";
	}

	// Avoid clashes with the 'name' param of get_terms().
	$get_terms_args = $parsed_args;
	unset( $get_terms_args['name'] );
	$categories = get_terms( $get_terms_args );

        if( is_array( $get_taxonomy ) && ! empty( $get_taxonomy ) ){
            $categories = $get_taxonomy;
        }

	$name     = esc_attr( $parsed_args['name'] );
	$class    = esc_attr( $parsed_args['class'] );
	$id       = $parsed_args['id'] ? esc_attr( $parsed_args['id'] ) : $name;
	$multiple = $parsed_args['multiple'] ? 'multiple' : '';

	$data_key = $parsed_args['data-key'] ? esc_attr( $parsed_args['data-key'] ) : '';

	if ( ! $parsed_args['hide_if_empty'] || ! empty( $categories ) ) {
		$output = "<select  data-key='$data_key' $multiple name='$name' id='$id' class='$class' $tab_index_attribute>\n";
	} else {
		$output = '';
	}
	if ( empty( $categories ) && ! $parsed_args['hide_if_empty'] && ! empty( $parsed_args['show_option_none'] ) ) {

		/**
		 * Filters a taxonomy drop-down display element.
		 *
		 * A variety of taxonomy drop-down display elements can be modified
		 * just prior to display via this filter. Filterable arguments include
		 * 'show_option_none', 'show_option_all', and various forms of the
		 * term name.
		 *
		 * @since 1.2.0
		 *
		 * @see wp_dropdown_categories()
		 *
		 * @param string       $element  Category name.
		 * @param WP_Term|null $category The category object, or null if there's no corresponding category.
		 */
		$show_option_none = apply_filters( 'list_cats', $parsed_args['show_option_none'], null );
		$output          .= "\t<option value='" . esc_attr( $option_none_value ) . "' selected='selected'>$show_option_none</option>\n";
	}

	if ( ! empty( $categories ) ) {

		if ( $parsed_args['show_option_all'] ) {

			/** This filter is documented in wp-includes/category-template.php */
			$show_option_all = apply_filters( 'list_cats', $parsed_args['show_option_all'], null );
			$selected        = ( '0' === (string) $parsed_args['selected'] ) ? " selected='selected'" : '';
			$output         .= "\t<option value=''$selected>$show_option_all</option>\n";
		}

		if ( $parsed_args['show_option_none'] ) {

			/** This filter is documented in wp-includes/category-template.php */
			$show_option_none = apply_filters( 'list_cats', $parsed_args['show_option_none'], null );
			$selected         = selected( $option_none_value, $parsed_args['selected'], false );
			$output          .= "\t<option value='" . esc_attr( $option_none_value ) . "'$selected>$show_option_none</option>\n";
		}

		if ( $parsed_args['hierarchical'] ) {
			$depth = $parsed_args['depth'];  // Walk the full depth.
		} else {
			$depth = -1; // Flat.
		}

		$output .= walk_category_dropdown_tree( $categories, $depth, $parsed_args );
	}

	if ( ! $parsed_args['hide_if_empty'] || ! empty( $categories ) ) {
		$output .= "</select>\n";
	}

	/**
	 * Filters the taxonomy drop-down output.
	 *
	 * @since 2.1.0
	 *
	 * @param string $output      HTML output.
	 * @param array  $parsed_args Arguments used to build the drop-down.
	 */
	$output = apply_filters( 'wp_dropdown_cats', $output, $parsed_args );

	if ( $parsed_args['echo'] ) {
		echo wp_kses_post( $output );
	}

	return $output;
}

/**
 * Generate checkbox-based taxonomy filter HTML.
 *
 * Creates a checkbox list for filtering products by taxonomy terms.
 * Selected items are displayed with a remove (X) button.
 *
 * @since 8.2.0
 * @author Saiful Islam <codersaiful@gmail.com>
 *
 * @param array $args Arguments for generating checkbox filter.
 * @param array|bool $get_taxonomy Optional. Custom taxonomy terms array.
 * @return string HTML output for checkbox filter.
 */
function wpt_checkbox_taxonomy_filter( $args = '', $get_taxonomy = false ) {
    $defaults = array(
        'orderby'           => 'name',
        'order'             => 'ASC',
        'hide_empty'        => 1,
        'child_of'          => 0,
        'hierarchical'      => 1,
        'name'              => 'cat',
        'id'                => '',
        'class'             => 'wpt-checkbox-filter',
        'taxonomy'          => 'category',
        'hide_if_empty'     => false,
        'value_field'       => 'term_id',
        'data-key'          => false,
        'table_id'          => '',
    );

    $parsed_args = wp_parse_args( $args, $defaults );

    // Get terms for the taxonomy
    $get_terms_args = $parsed_args;
    unset( $get_terms_args['name'] );
    unset( $get_terms_args['id'] );
    unset( $get_terms_args['class'] );
    unset( $get_terms_args['data-key'] );
    unset( $get_terms_args['table_id'] );
    
    $categories = get_terms( $get_terms_args );

    if ( is_array( $get_taxonomy ) && ! empty( $get_taxonomy ) ) {
        $categories = $get_taxonomy;
    }

    if ( empty( $categories ) || is_wp_error( $categories ) ) {
        return '';
    }

    $name     = esc_attr( $parsed_args['name'] );
    $class    = esc_attr( $parsed_args['class'] );
    $id       = $parsed_args['id'] ? esc_attr( $parsed_args['id'] ) : $name;
    $data_key = $parsed_args['data-key'] ? esc_attr( $parsed_args['data-key'] ) : '';
    $table_id = esc_attr( $parsed_args['table_id'] );

    $output = "<div class='wpt-checkbox-filter-wrapper {$class}' data-key='{$data_key}' data-table-id='{$table_id}'>";
    $output .= "<div class='wpt-checkbox-list'>";

    foreach ( $categories as $category ) {
        $term_id   = $category->term_id;
        $term_name = esc_html( $category->name );
        $term_slug = $category->slug;
        $count     = $category->count;

        $checkbox_id = "{$id}_{$term_id}";
        
        $output .= "<label class='wpt-checkbox-item' for='{$checkbox_id}'>";
        $output .= "<input type='checkbox' class='wpt-checkbox-input' id='{$checkbox_id}' name='{$name}[]' value='{$term_id}' data-term-name='" . esc_attr( $category->name ) . "' data-term-id='{$term_id}' />";
        $output .= "<span class='wpt-checkbox-label'>{$term_name}</span>";
        if ( $count ) {
            $output .= "<span class='wpt-checkbox-count'>({$count})</span>";
        }
        $output .= "</label>";
    }

    $output .= "</div>"; // .wpt-checkbox-list
    $output .= "</div>"; // .wpt-checkbox-filter-wrapper

    return $output;
}

/**
 * Generate checkbox-based taxonomy search filter for frontend.
 *
 * Creates a complete checkbox filter section with selected items display area.
 *
 * @since 8.2.0
 * @author Saiful Islam <codersaiful@gmail.com>
 *
 * @param string $taxonomy_keyword Taxonomy slug.
 * @param int|string $temp_number Table ID.
 * @param array|bool $search_n_filter Search and filter settings.
 * @return string|bool HTML output or false on failure.
 */
function wpt_checkbox_taxonomy_search_generator( $taxonomy_keyword, $temp_number, $search_n_filter = false ) {
    $selected_taxs = isset( $search_n_filter[$taxonomy_keyword] ) ? $search_n_filter[$taxonomy_keyword] : false;
    $config_value = wpt_get_config_value( $temp_number );
    
    if ( ! $taxonomy_keyword || is_array( $taxonomy_keyword ) ) {
        return false;
    }

    $taxonomy_details = get_taxonomy( $taxonomy_keyword );

    if ( ! $taxonomy_details ) {
        return false;
    }

    $label = apply_filters( 'wpto_searchbox_taxonomy_name', $taxonomy_details->labels->menu_name, $taxonomy_details, $temp_number );
    $tx_order = $config_value['sort_searchbox_filter'] ?? 'ASC';

    $args = array(
        'orderby'      => 'name',
        'order'        => $tx_order,
        'hide_empty'   => 1,
        'hierarchical' => 1,
        'name'         => $taxonomy_keyword,
        'id'           => $taxonomy_keyword . '_' . $temp_number,
        'class'        => "wpt-checkbox-filter wpt-checkbox-filter-{$taxonomy_keyword}",
        'taxonomy'     => $taxonomy_keyword,
        'data-key'     => $taxonomy_keyword,
        'table_id'     => $temp_number,
    );

    // Get custom term selection if available
    $customized_taxonomy_obj = false;
    if ( $selected_taxs && is_array( $selected_taxs ) && count( $selected_taxs ) > 0 ) {
        $customized_taxonomy_obj = array();
        foreach ( $selected_taxs as $termID ) {
            $singleTerm = get_term( $termID );
            if ( $singleTerm && ! is_wp_error( $singleTerm ) ) {
                $customized_taxonomy_obj[] = $singleTerm;
            }
        }

        // Sort terms if order is specified
        if ( ! empty( $tx_order ) && $tx_order !== '0' ) {
            usort( $customized_taxonomy_obj, function( $prev, $next ) use ( $tx_order ) {
                if ( $tx_order === 'ASC' ) return $prev->name > $next->name ? 1 : -1;
                if ( $tx_order === 'DESC' ) return $prev->name > $next->name ? -1 : 1;
                return 0;
            });
        }
    }

    $taxonomy_keyword_escaped = esc_attr( $taxonomy_keyword );
    $label_escaped = esc_html( $label );

    $html = "<div class='search_single search_single_checkbox search_single_{$taxonomy_keyword_escaped}'>";
    $html .= "<label class='search_keyword_label {$taxonomy_keyword_escaped}' for='{$taxonomy_keyword_escaped}_{$temp_number}'>{$label_escaped}</label>";
    
    // Selected items display area
    $html .= "<div class='wpt-selected-items wpt-selected-items-{$taxonomy_keyword_escaped}' data-taxonomy='{$taxonomy_keyword_escaped}'></div>";
    
    // Checkbox filter
    $html .= wpt_checkbox_taxonomy_filter( $args, $customized_taxonomy_obj );
    
    $html .= "</div>"; // .search_single

    return $html;
}

if( ! function_exists( 'wpt_paginate_links' ) ){
    /**
     * Generate paginated links based on Args.
     * 
     * @param array|false $args Args of WP_Query's
     * @return string|null  String of pagination links or false if args are not provided.
     */
    function wpt_paginate_links( $args = false ){

        $html = false;
        if( $args ){
            $product_loop = new WP_Query($args);
            $big = 99999999;
            $paginate = paginate_links( array(
                'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
                'format' => apply_filters( 'wpto_pagination_format', '?paged=%#%', $args ),
                'mid_size'  =>  3,
                'prev_next' =>  false,
                'current' => max( 1, $args['paged'] ),
                'total' => $product_loop->max_num_pages
            ));
            $html .= $paginate; 
        }
        return $html;
    }
}

if( ! function_exists( 'wpt_pagination_by_args' ) ){
    /**
     * Generate full pagination based on Args.
     * 
     * @param array $args Args of WP_Query's
     * @return string String
     */
    function wpt_pagination_by_args( $args = false, $temp_number = false, $whole_data = array() ){
        $whole_data = is_array( $whole_data ) ? $whole_data : array();
        $html = false;
        /**
         * This is confiused filter
         * asole ata add kora thik hobe kina sure na.
         * tobe pore check kore dekha jete pare.
         * amora ei filter ta rakhbo ki na.
         * 
         * @since 3.1.9.3
         */

        if( is_array( $args) ){
            $html .= "<div class='wpt_table_pagination' data-temp_number='{$temp_number}' data-whole_data='". esc_attr( wp_json_encode( $whole_data ) ) ."'>";
            $paginate = wpt_paginate_links( $args );
            $html .= $paginate; 
            $html .= "</div>";
        }
        return $html;
    }
}

if( ! function_exists( 'wpt_additions_data_attribute' ) ){

    /**
     * Generate Product's Attribute
     * 
     * @global object $product Default global product variable, it will only work inside loop
     * @param array|false $attributes Array of attributes
     * @return string 
     */
    function wpt_additions_data_attribute( $attributes = false ){

        global $product;
        $html = false;
        if( $attributes && is_array( $attributes ) && count( $attributes ) > 0 ){
            foreach ( $attributes as $attribute ) :
            $html .= "<div class='wpt_each_attribute_wrapper'>";
                $html .= "<label>" . wc_attribute_label( $attribute->get_name() ) . "</label>";

                $values = array();

                if ( $attribute->is_taxonomy() ) {
                        $attribute_taxonomy = $attribute->get_taxonomy_object();
                        $attribute_values = wc_get_product_terms( $product->get_id(), $attribute->get_name(), array( 'fields' => 'all' ) );

                        foreach ( $attribute_values as $attribute_value ) {
                                $value_name = esc_html( $attribute_value->name );

                                if ( $attribute_taxonomy->attribute_public ) {
                                        $values[] = '<a href="' . esc_url( get_term_link( $attribute_value->term_id, $attribute->get_name() ) ) . '" rel="tag">' . $value_name . '</a>';
                                } else {
                                        $values[] = $value_name;
                                }
                        }
                } else {
                        $values = $attribute->get_options();

                        foreach ( $values as &$value ) {
                                $value = make_clickable( esc_html( $value ) );
                        }
                }

            $html .= apply_filters( 'woocommerce_attribute', wpautop( wptexturize( implode( ', ', $values ) ) ), $attribute, $values );

            $html .= '</div>';
            endforeach;
        }
        return $html;
    }
}

if( ! function_exists( 'wpt_check_sortOrder' ) ){

    /**
     * Checking Value for Select option tag
     * Used in shortcode.php file actually
     * 
     * @param string|false $got_value
     * @param string $this_value
     * @return string
     */
    function wpt_check_sortOrder( $got_value = false, $this_value = 'nothing' ){
        return $got_value == $this_value ? 'selected' : ''; 
    }
}

if( ! function_exists( 'wpt_default_columns_array' ) ){

    /**
     * To get Final Columns List as Array, where will unavailable default disable_column
     * 
     * @return array 
     */
    function wpt_default_columns_array(){

        $column_array = WPT_Product_Table::$columns_array;
        /**
         * To this disable array, Only available keywords of Column Keyword Array
         * 
         */
        $disable_column_keyword = WPT_Product_Table::$colums_disable_array;
        foreach( $disable_column_keyword as $value ){
            unset( $column_array[$value] );
        }
        return $column_array;
    }
}

if( ! function_exists( 'wpt_default_columns_keys_array' ) ){

    /**
     * We used this function to get default keywords array from default columns array
     * 
     * @return array Only Keys of Column Array
     * @since 3.6
     */
    function wpt_default_columns_keys_array(){
        return array_keys( wpt_default_columns_array() );
    }
}

if( ! function_exists( 'wpt_default_columns_values_array' ) ){

    /**
     * We used this function to get default values array from default columns array
     * 
     * @return array Only values of Column Array
     * @since 3.6
     */
    function wpt_default_columns_values_array(){

        return array_values( wpt_default_columns_array() );

    }
}


if( ! function_exists( 'wpt_taxonomy_column_generator' ) ){

    /**
     * Taxonomy column generator
     * clue is: tax_
     * 
     * @param String $item_key
     * @return String
     */
    function wpt_taxonomy_column_generator( $item_key ){

        $key = 'tax_';
        $len = strlen( $key );
        $check_key = substr( $item_key, 0, $len );
        if( $check_key == $key ){
            return $item_key;
        }
    }
}

if( ! function_exists( 'wpt_customfileds_column_generator' ) ){

    /**
     * Custom Fields column generator
     * clue is: cf_
     * 
     * @param String $item_key
     * @return String
     */
    function wpt_customfileds_column_generator( $item_key ){

        $key = 'cf_';
        $len = strlen( $key );
        $check_key = substr( $item_key, 0, $len );
        if( $check_key == $key ){
            return $item_key;
        }
    }
}

if( ! function_exists( 'wpt_limit_words' ) ){

    /**
     * Making new String/description based on word Limit.
     * 
     * @param String $string
     * @param int $word_limit
     * @return String
     */
    function wpt_limit_words( $string = '', $word_limit = 10 ){
        $words = explode( " ",$string );

        $output = implode( " ",array_splice( $words,0,$word_limit ) );
        if( count( $words ) > $word_limit ){
           $output .= $output . '...'; 
        }
        return $output;
    }
}

if( ! function_exists( 'wpt_explode_string_to_array' ) ){

    /**
     * Go generate as Array from 
     * 
     * @param Array $string Obviously should be an Array, Otherwise, it will generate false.
     * @param Array $default_array Actually if not fount a real String, and if we want to return and default value, than we can set here. 
     * @return Array This function will generate comman string to Array
     */
    function wpt_explode_string_to_array( $string,$default_array = [] ) {

        $final_array = [];
        if ( $string && is_string( $string ) ) {
            $string = rtrim( $string, ', ' );
            $final_array = explode( ',', $string );
        } else {
            if( is_array( $default_array ) ){
                $final_array = $default_array;
            }
        }
        return $final_array;
    }
}

if( ! function_exists( 'wpt_generate_each_row_data' ) ){

    /**
     * Generate each row data for product table. This function will only use for once place.
     * I mean: in shortcode.php file normally.
     * But if anybody want to use any others where, you have to know about $table_column_keywords and $wpt_each_row
     * both should be Array, Although I didn't used condition for $wpt_each_row Array to this function. 
     * So used: based on your own risk.
     * 
     * @param array $table_column_keywords
     * @param array $wpt_each_row
     * @return string
     */
    function wpt_generate_each_row_data($table_column_keywords = false, $wpt_each_row = false) {

        $final_row_data = false;
        if ( is_array( $table_column_keywords ) && count( $table_column_keywords ) > 0) {
            foreach ( $table_column_keywords as $each_keyword ) {
                $final_row_data .= ( isset( $wpt_each_row[$each_keyword] ) ? $wpt_each_row[$each_keyword] : false );
            }
        }
        return $final_row_data;
    }
}

if( ! function_exists( 'wpt_define_permitted_td_array' ) ){

    /**Generaed a Array for $wpt_permitted_td 
     * We will use this array to confirm display Table body's TD inside of Table
     * 
     * @since 1.0.4
     * @date 27/04/2018
     * @param array $table_column_keywords
     * @return array|false
     */
    function wpt_define_permitted_td_array( $table_column_keywords = false ){

        $wpt_permitted_td = array();
        if( $table_column_keywords && is_array( $table_column_keywords ) && count( $table_column_keywords ) > 0 ){
            foreach( $table_column_keywords as $each_keyword ){
                $wpt_permitted_td[$each_keyword] = true;
            }
        }
        return $wpt_permitted_td;
    }
}

if( ! function_exists( 'wpt_array_to_option_atrribute' ) ){

    /**
     * Generating <options>VAriation Atribute</option> for Product Variation
     * CAn be removed later.
     * 
     * @param array|false $current_single_attribute Array of attributes
     * @return string
     */
    function wpt_array_to_option_atrribute( $current_single_attribute = false ){

        $html = '<option value>'.esc_html__( 'None', 'woo-product-table' ).'</option>';
        if( is_array( $current_single_attribute ) && count( $current_single_attribute ) ){
            foreach( $current_single_attribute as $wpt_pr_attributes ){
            $html .= "<option value='{$wpt_pr_attributes}'>" . ucwords( $wpt_pr_attributes ) . "</option>";
            }
        }
        return $html;
    }
}

if( ! function_exists( 'wpt_variations_attribute_to_select' ) ){

    /**
     * This is deprecated now. We have used new file for this part
     * new file is: includes/variation_html.php 
     * 
     * For Variable product, Variation's attribute will generate to select tag
     * 
     * @deprecated since 2.7.8 2.7.8.0
     * 
     * @param   array   $attributes Array of attributes
     * @param   int|false|null     $product_id
     * @param   int     $temp_number
     * @return  string  HTML Select tag will generate from Attribute
     */
    function wpt_variations_attribute_to_select( $attributes , $product_id = false, $default_attributes = false, $temp_number = false ){

        $html = false;
        $html .= "<div class='wpt_varition_section' data-product_id='{$product_id}'  data-temp_number='{$temp_number}'>";
        foreach( $attributes as $attribute_key_name=>$options ){

            $label = wc_attribute_label( $attribute_key_name );
            $attribute_name = wc_variation_attribute_name( $attribute_key_name );
            $only_attribute = str_replace( 'attribute_', '', $attribute_name);
            $default_value = !isset( $default_attributes[$only_attribute] ) ? false : $default_attributes[$only_attribute]; //Set in 3.9.0

                    // Get an array of attributes
                    $attr_array = get_the_terms( $product_id, $only_attribute);
            $html .= "<select data-product_id='{$product_id}' data-attribute_name='{$attribute_name}' placeholder='{$label}'>";
            $html .= "<option value='0'>" . $label . "</option>";
            foreach( $options as $option ){
                            // Get the name of the current attribute
                            $attr_name = $option;
                            foreach( $attr_array as $attr ){
                                    if ( isset( $attr->slug ) && $option == $attr->slug) { $attr_name = $attr->name; }
                            }

                $html .= "<option value='" . esc_attr( $option ) . "' " . ( $default_value == $option ? 'selected' : '' ) . ">" . $attr_name . "</option>";
            }
            $html .= "</select>";

        }
        $html .= "<div class='wpt_message wpt_message_{$product_id}'></div>";
        $html .= '</div>';

        return $html;
    }
}


if( ! function_exists( 'wpt_get_value_with_woocommerce_unit' ) ){

    /**
     * Getting unit amount with unint sign. Suppose: Kg, inc, cm etc
     * woocommerce has default wp_options for weight,height etc's unit.
     * Example: for weight, woocommerce_weight_unit
     * 
     * @param string $target_unit Such as: weight, height, lenght, width
     * @param int $value Can be any number. It also can be floating point number. Normally decimal
     * @return string If get unit and value is gater than o, than it will generate string, otheriwse false
     */
    function wpt_get_value_with_woocommerce_unit( $target_unit, $value ){

        $get_unit = get_option( 'woocommerce_' . $target_unit . '_unit' );

        return ( is_numeric( $value ) && $value > 0 ? $value . ' ' . $get_unit : false );
    }
}

if( ! function_exists( 'wpt_args_manipulation_frontend' ) ){

    /**
     * IN FREE
     * Args Manipulation for FrontEnd
     * By Useing following Filter
     * $args = apply_filters( 'wpto_table_query_args', $args, $table_ID, $atts, $column_settings, $enabled_column_array, $column_array );
     * $variables:
     * array $args_product_in 
     * @param array $args
     * @param int $table_ID
     * @param array $atts
     * @return array
     */
    function wpt_args_manipulation_frontend( $args, $table_ID, $atts ){
        
        /**
         * This is an extra and hidden feature
         * which has no any option,
         * only possible by shortcode
         * like: 
         * [Product_Table id='19555'  name='Popular' behavior='normal']
         * 
         * @since 3.1.8.4
         */
        $behavior = $atts['behavior'] ?? '';
        $args['behavior'] = $behavior;

        if( is_page() || is_single() || $behavior == 'normal' ){
            return $args;
        }
        //MainTain for Archives Page
        global $wpdb;
        $query_vars = isset( $GLOBALS['wp_query']->query_vars ) ? $GLOBALS['wp_query']->query_vars : false;

        $page_query = isset( $GLOBALS['wp_query'] ) ? $GLOBALS['wp_query']->query_vars : null;
        $args_product_in = false;
        if( ( isset( $query_vars['post_type'] ) && !empty( $query_vars['post_type'] ) && $query_vars['post_type'] == 'product' ) 
                || ( isset( $page_query['wc_query'] ) && $page_query['wc_query'] == 'product_query' ) 
            ){
            
            if( isset( $args['post__in'] ) && is_array( $args['post__in'] ) && count( $args['post__in'] ) > 0 ){
                return $args;
            }
            
            $gen_args = is_array( $args) && is_array($GLOBALS['wp_query']->query_vars) ? array_merge( $args,$GLOBALS['wp_query']->query_vars ) : $args;
            $gen_args['post_type'] = isset( $args['post_type'] ) && !empty( $args['post_type'] ) ? $args['post_type'] : 'product';
            $args = $gen_args;

            $sql = $GLOBALS['wp_query']->request;
            $_paged = $GLOBALS['wp_query']->query_vars['paged'] ?? 1;

            $cache_key = 'wpt_shop_args_' . $_paged;

            $args_product_in = wp_cache_get( $cache_key );

            if ( false === $args_product_in ) {
                $results = $wpdb->get_results( $sql, ARRAY_A );
                $results = is_array( $results ) ? $results : array();

                foreach( $results as $result ){
                    $args_product_in[] = $result['ID'];
                }

                // Cache the result for future use
                wp_cache_set( $cache_key, $args_product_in, '', 1800 );
            }

            
            $args['post__in'] = $args_product_in;
            $args['paged'] = 0;
            unset( $args['tax_query'] );
            unset( $args['term'] );
            unset( $args['meta_query'] );
        }

        return $args;
    }
}
add_filter( 'wpto_table_query_args', 'wpt_args_manipulation_frontend', 10, 3 );

/**
 * Use folowing filter to get original table
 * remove_filter( 'wpto_table_query_args', 'wpt_args_manipulation_frontend', 10 );
 */

function wpt_url_encode_array(array $data): string {
    $output = '';
    foreach ($data as $groupKey => $groupValues) {
        $inner = '';
        foreach ($groupValues as $key => $value) {
            if (is_array($value)) {
                $value = implode(',', $value);
            }
            $inner .= "({$key}-{$value})";
        }
        $output .= "[{$groupKey}-[{$inner}]]";
    }
    return $output;
}
/**
 * Decode the custom URL-encoded string back into an associative array.
 *
 * @param string $input The encoded string to decode.
 * @return array The decoded associative array.
 */
function wpt_tax_url_decode($input) {
    $result = [];

    // Validate overall format first using regex
    if (!preg_match('/^([a-z_]+_[A-Z]+-\d+(,\d+)*)(__([a-z_]+_[A-Z]+-\d+(,\d+)*))*$/', $input)) {
        return []; // Invalid format
    }

    $filters = explode('__', $input);

    foreach ($filters as $filter) {
        // Split into key and values
        $parts = explode('-', $filter, 2);
        if (count($parts) !== 2) return [];

        [$key, $termString] = $parts;

        // Ensure key is valid: only lowercase letters and underscores + underscore + UPPERCASE operator
        if (!preg_match('/^[a-z_]+_[A-Z]+$/', $key)) return [];

        // Ensure terms are only digits and commas
        if (!preg_match('/^\d+(,\d+)*$/', $termString)) return [];

        // Extract taxonomy and operator
        $keyParts = explode('_', $key);
        $operator = array_pop($keyParts);
        $taxonomy = implode('_', $keyParts);

        // Convert terms to array
        $terms = explode(',', $termString);

        $result[$key] = [
            'taxonomy' => $taxonomy,
            'field'    => 'id',
            'terms'    => $terms,
            'operator' => $operator,
        ];
    }

    return $result;
}


if( ! function_exists( 'wpt_args_manage_by_get_args' ) ){
    
    /**
     * Manage Query Args based on link 
     * using Supper Global $_GET
     * 
     * @since 2.8.9
     * @param array $args Query Args of Product Table, which will generate by default or by shortcode
     * @param int $table_ID Table ID
     * @return array
     */
    function wpt_args_manage_by_get_args( $args, $table_ID ){

        $nonce = wp_create_nonce( "woo-product-table" );
        if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, WPT_PLUGIN_FOLDER_NAME ) ) {
            return $args;
        }
        $founded_table_ID = absint( wp_unslash( $_GET['table_ID'] ?? '' ) );
        if( ! $founded_table_ID ) return $args;
        if( $founded_table_ID != $table_ID ) return $args;
        /**
         * Check WooCommerce Archive Page, such product taxonomy
         * show page, search page. etc
         */
        if( is_shop() || is_product_taxonomy() ){
            return $args;
        }
        
        $MY_GETS = array(
            'table_ID' => absint( wp_unslash( $_GET['table_ID'] ?? false ) ),
            'orderby' => sanitize_text_field( wp_unslash( $_GET['orderby'] ?? false ) ),
            'order' => sanitize_text_field( wp_unslash( $_GET['order'] ?? false ) ),
            's' => sanitize_text_field( wp_unslash( $_GET['search_key'] ?? false ) ),
        );
        $MY_GETS = array_filter( $MY_GETS );
        $tax = sanitize_text_field( wp_unslash( $_GET['tax'] ?? '' ) );
        if( ! empty( $tax ) ){
            $MY_GETS['tax_query'] = wpt_tax_url_decode( $tax );
            if( isset( $args['tax_query'] ) ) unset( $args['tax_query'] );
        }

        $meta = sanitize_text_field( wp_unslash( $_GET['meta'] ?? '' ) );
        if( ! empty( $meta ) ){
            $MY_GETS['meta_query'] = wpt_tax_url_decode( $meta );
            if( isset( $args['meta_query'] ) ) unset( $args['meta_query'] );
        }
        
       $args = array_merge($args,$MY_GETS);
       return $args;
    }
}
add_filter( 'wpto_table_query_args', 'wpt_args_manage_by_get_args', 10, 2 );

if( ! function_exists( 'wpt_add_div_at_top' ) ){

    /**
     * Top Scrollbar
     * To hide, top scrollbar, we can use this action hook
     * 
     * 
     * Add a new div at the top of the table, To add a Wrapper wrapper at the Top
     * 
     * @param Int $table_ID
     * @since 2.7.5.2
     * @date 11 Oct, 2020
     * @return void
     */
    function wpt_add_div_at_top( $table_ID ){
    ?>
<div data-product_id="<?php echo esc_attr( $table_ID ); ?>" class="wpt_second_wrapper wpt_second_wrapper_<?php echo esc_attr( $table_ID ); ?>">
    <div class="wpt_second_content">
    </div>
</div>    
    <?php
    }
}
// add_action( 'wpto_action_before_table', 'wpt_add_div_at_top' );

if( ! function_exists( 'wpt_item_manage_from_theme' ) ){

    /**
     * Managing Final File Location 
     * Actually if a user keep his Item Template file at His theme,
     * That will get First Priority 
     * Then template file will come from user defined template location
     * We have used following Filter
     * apply_filters( 'wpto_item_final_loc', $file, $file_name, $items_directory_2, $keyword, $table_ID, $settings, $items_permanent_dir );
     * 
     * To get Item's Template From Active Theme, Use following Directory
     * [YourTheme]/woo-product-table/items/[YourItemFileName].php
     * 
     * Suppose, Item name is price, than location/directory from theme will be:
     * [YourTheme]/woo-product-table/items/price.php
     * 
     * @param string $file
     * @param string $file_name
     * 
     * @return string $file This Function will return $file Location of Items
     */
    function wpt_item_manage_from_theme( $file, $file_name ){

        $file_frm_theme = get_stylesheet_directory() . '/woo-product-table/items/' . $file_name . '.php';
        if( file_exists( $file_frm_theme ) ){
            return $file_frm_theme;
        }
        return $file;
    }
}
add_filter( 'wpto_item_final_loc', 'wpt_item_manage_from_theme', 1, 2 );

if( ! function_exists( 'wpt_add_td_class' ) ){
    
    /**
     * Add Class on Td for Table
     * 
     * @param array $class_arr
     * @param string $keyword
     * @param int $table_ID
     * @param array $args
     * @param array $column_settings
     * @return array
     */
    function wpt_add_td_class( $class_arr, $keyword, $table_ID, $args, $column_settings ){
        if( isset( $column_settings[$keyword] ) && is_array( $column_settings[$keyword] ) ){
            foreach( $column_settings[$keyword] as $key=>$eachClass ){
                $class_arr[] = is_string( $eachClass ) && $key !== 'content' && $key !== 'tag_class' && $key !== 'style_str' ? str_replace(' ','-', $key . '_' . $eachClass) : false;
            }
        }
        $class_arr = array_filter( (array) $class_arr );
        return $class_arr;
    }
}
add_filter('wpto_td_class_arr', 'wpt_add_td_class', 10, 5);

if( ! function_exists( 'wpt_search_box_validation_on_off' ) ){
    
    /**
     * Primarily I have set Search page off on shop page, wc Arcive page
     * 
     * 
     * 
     * @since 2.7.8.2
     * 
     * @return bool false for shop page and product taxonomy page, true for other pages
     */
    function wpt_search_box_validation_on_off(){
        
        if( is_product_taxonomy() || is_shop() ){
            return false;
        }
        return true;
    }
}
add_filter( 'wpto_searchbox_show', 'wpt_search_box_validation_on_off' );


if( ! function_exists( 'wpt_user_roles_by_id' ) ){
    
    /**
     * Get user roles by user ID.
     * 
     * https://wordpress.stackexchange.com/questions/58916/how-to-get-role-of-user
     * @param  int $id
     * @return array
     */
    function wpt_user_roles_by_id( $id ) {

        $user = new WP_User( $id );

        if ( empty ( $user->roles ) or ! is_array( $user->roles ) )
            return array ();

        return $user->roles;
    }
}

if( ! function_exists( 'wpt_shop_archive_sorting_args' ) ){
    
    /**
     * This function has fixed shop archive default sorting issue.
     * 
     * @param array $args
     * @return array $args
     */
    function wpt_shop_archive_sorting_args( $args ){

        if( is_shop() || is_product_taxonomy() ){
            $get_param = filter_input_array( INPUT_GET);
            $_orderby = sanitize_text_field( wp_unslash( $get_param['orderby'] ?? '' ) );
            $args['paged'] = 1;
            $args['post_type'] = ['product'];
            switch( $_orderby ){
                case 'price':
                        $args['orderby'] = 'meta_value_num';
                        $args['order'] = 'asc';
                        $args['meta_key'] = '_price';
                    break;
                case 'price-desc':
                        $args['orderby'] = 'meta_value_num';
                        $args['order'] = 'desc';
                        $args['meta_key'] = '_price';
                    break;
                case 'rating':
                        $args['orderby'] = 'meta_value_num';
                        $args['order'] = 'desc';
                        $args['meta_key'] = '_wc_average_rating';
                   break;
                case 'popularity':
                        $args['orderby'] = 'meta_value_num';
                        $args['order'] = 'desc';
                        $args['meta_key'] = 'total_sales';
                    break;
                case 'date':
                        $args['order'] = 'desc';
                    break;
            }
        }
        return $args;
    }
}
add_filter( 'wpto_table_query_args_in_row', 'wpt_shop_archive_sorting_args', 10 );
add_filter( 'wpto_table_query_args', 'wpt_shop_archive_sorting_args', 10 );//New added bcz old filter has removed

/**
 * Astra Theme Compatibility
 * 
 * Quantity Plus Minus Button issue solved by removed from Theme
 * Only for Astra Theme
 * 
 * TIPS: At this situation, Need https://wordpress.org/plugins/wc-quantity-plus-minus-button/ Plugin
 * 
 * @since 2.8.3.2
 * 
 * @date 3.2.2021
 * @by Saiful
 * 
 * Priority Added PHP_INT_MAX Version: 2.8.8.0 date 12.5.2021
 */
add_filter( 'astra_add_to_cart_quantity_btn_enabled', '__return_false', PHP_INT_MAX );


if( ! function_exists( 'wpt_ajax_on_first_load' ) ){

    /**
     * Compability Code for WavePlayer
     * 
     * We actually added this code for
     * WavePlayer
     * 
     * Because,
     * If u want to enable this code, u have to use following ACTION HOOK to your theme/plugin
     * Also can use CodeSnipet Plugin.
     * 
     * Hook is: 
     * add_action( 'wp_footer', 'wpt_ajax_on_first_load', 100 );
     * 
     * CodeSnippet Plugin URL: https://wordpress.org/plugins/code-snippets/
     * 
     * @since 2.8.3.5
     * @date 8.2.2021 d.m.y
     * @by Saiful
     * @helped Mukul and Bari
     * @return void
     */
    function wpt_ajax_on_first_load(){

    ?>
    <script id='by-woo-product-table'>
    jQuery(document).ready(function($){
        $("button.wpt_search_button").trigger("click");
    });
    </script>
    <?php
    }
}
//add_action( 'wp_footer', 'wpt_ajax_on_first_load', 100 );

/**
 * Preview template for product table
 * 
 * @param string $template_file
 * @return string
 */
function wpt_product_table_preview_template( $template_file ){

    if( ! is_singular() ){
        return $template_file;
    }
    $type = get_post_type();
    if( $type == 'wpt_product_table' ){
        $template = WPT_DIR_BASE . 'templates/table-preview.php';
        return is_file( $template ) ? $template : $template_file;
    }
   
    return $template_file;
}
add_filter( 'template_include', 'wpt_product_table_preview_template' );


/**
 * **IMPORTANT** FOR OLD AND NEW VERSION
 * USED AT includes/imtems/action.php
 * 
 * WHY THIS FUNCTION:
 * actually some product has indivisual sold enabled
 * and for these product, user will not able to add after added onece.
 * So we checked it if for indivisual product 
 * that product already available or not in cart
 * 
 * for action.php inside items 
 * 
 * comment by saiful
 * kajti koreche mukul 
 * 
 * @param array $search_products Product ID or array of Product IDs to search in the cart
 * @return int Number of matched items in the cart
 */
function wpt_matched_cart_items( $search_products ) {
    $count = 0; // Initializing
    $cart = WC()->cart;
    
    if ( ! is_null( $cart ) && ! $cart->is_empty() ) {
        // Loop though cart items
        foreach(WC()->cart->get_cart() as $cart_item ) {
            // Handling also variable products and their products variations
            $cart_item_ids = array($cart_item['product_id'], $cart_item['variation_id']);

            // Handle a simple product Id (int or string) or an array of product Ids 
            if( ( is_array( $search_products ) && array_intersect( $search_products, $cart_item_ids ) ) 
            || ( !is_array( $search_products ) && in_array( $search_products, $cart_item_ids ) ) ) {

                $count++; // incrementing items count
            }
        }
    }
    return $count; // returning matched items count 
}

//Checking with Dokan's class WeDevs_Dokan
if( class_exists('WeDevs_Dokan') && !function_exists( 'wpt_template_for_dokan' ) ){
   
    /**
     * Compatible with Dokan plugin
     * 
     * @since 3.3.6.2
     *
     * @param string $template_file
     * @return void
     */
    function wpt_template_for_dokan( $template_file ) {
        $page_template_validation = apply_filters( 'wpt_dokan_template', true, $template_file );
       if( $page_template_validation && strpos( $template_file, 'dokan' ) > 0 && strpos( $template_file, 'store' ) > 0 ){
           $my_archive = WPT_BASE_DIR . 'templates/store.php';
           $my_archive = apply_filters( 'wpto_dokan_page_template_loc', $my_archive, $template_file );
           return file_exists( $my_archive ) ? $my_archive : $template_file;
       }
       
       return $template_file;
    }
    add_filter( 'template_include', 'wpt_template_for_dokan', 999 );
}



if( defined('B2BKING_DIR') && ! function_exists( 'wpt_b2bking_plugin_integration' ) ){
    
    /**
     * Integration with B2BKing — Ultimate WooCommerce Wholesale and B2B Solution
     * plugin link: https://wordpress.org/plugins/b2bking-wholesale-for-woocommerce/
     * 
     * @since 3.0.2.0
     * @author Saiful Islam<codersaiful@gmail.com>
     * @author mlstolk https://github.com/mlstolk
     * @link https://github.com/codersaiful/woo-product-table/pull/136
     * 
     * @param array $args
     */
    function wpt_b2bking_plugin_integration( $args ){

        $user_id = get_current_user_id();

        // if b2bking visibility is enabled
        if (intval(get_option( 'b2bking_all_products_visible_all_users_setting', 1 )) !== 1){
            if (intval(get_option('b2bking_disable_visibility_setting', 0)) === 0){

                // set products to visible b2bking products (at group or user level)
                $b2bking_visible_ids = get_transient('b2bking_user_'.$user_id.'_ajax_visibility');
                $b2bking_visible_ids = isset( $args['post__in'] ) && is_array( $args['post__in'] ) ? array_intersect($args['post__in'], $b2bking_visible_ids): $b2bking_visible_ids;
                $args['post__in'] = $b2bking_visible_ids;
            }
        }

        return $args;
    }

    add_filter( 'wpto_table_query_args', 'wpt_b2bking_plugin_integration' );
}

