File "index.php"

Full Path: /home/vantageo/public_html/cache/cache/cache/.wp-cli/wp-content/plugins/woocommerce-products-filter/index.php
File size: 150.97 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/*
  Plugin Name: Products Filter for WooCommerce
  Plugin URI: https://products-filter.com/
  Description: WOOF - WooCommerce Products Filter. Flexible, easy and robust products filter for WooCommerce store site!
  Requires at least: WP 4.9.0
  Tested up to: WP 6.0
  Author: realmag777
  Author URI: https://pluginus.net/
  Version: 2.2.9.4
  Requires PHP: 7.0
  Tags: filter,search,woocommerce,woocommerce filter,woocommerce product filter,woocommerce products filter,products filter,product filter,filter of products,filter for products,filter for woocommerce
  Text Domain: woocommerce-products-filter
  Domain Path: /languages
  Forum URI: https://pluginus.net/support/forum/woof-woocommerce-products-filter/
  WC requires at least: 3.6.0
  WC tested up to: 6.9
 */

//update_option('woof_settings', '');//dev: nearly absolute reset of the plugin settings
if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly
}

//***

if (defined('DOING_AJAX')) {
    if (isset($_REQUEST['action'])) {
        //for wp plugin WP Live Chat Support http://wp-livechat.com/
        if ($_REQUEST['action'] === 'wplc_call_to_server_visitor') {
            return;
        }
    }
}

//***

define('WOOF_PATH', plugin_dir_path(__FILE__));
define('WOOF_LINK', plugin_dir_url(__FILE__));
define('WOOF_PLUGIN_NAME', plugin_basename(__FILE__));
define('WOOF_EXT_PATH', WOOF_PATH . 'ext/');
define('WOOF_VERSION', '2.2.9.4');
//define('WOOF_VERSION', uniqid('woof-')); //for dev only
define('WOOF_MIN_WOOCOMMERCE_VERSION', '3.6');
//classes
include WOOF_PATH . 'classes/request.php';
include WOOF_PATH . 'classes/storage.php';
include WOOF_PATH . 'classes/helper.php';
include WOOF_PATH . 'classes/cron.php';
include WOOF_PATH . 'classes/hooks.php';
include WOOF_PATH . 'classes/ext.php';
//***
include WOOF_PATH . 'classes/counter.php';
include WOOF_PATH . 'classes/widgets.php';
//***
include WOOF_PATH . 'lib/alert/index.php';
//***
include WOOF_PATH . 'installer/first_settings.php';

//***
//13-09-2022
final class WOOF {

    public $settings = array();
    public $html_types = array(
        'radio' => 'Radio',
        'checkbox' => 'Checkbox',
        'select' => 'Drop-down',
        'mselect' => 'Multi drop-down'
    );
    public $items_keys = array(
        'by_price'
    );
    public static $query_cache_table = 'woof_query_cache';
    public $is_activated = true;
    private $session_rct_key = 'woof_really_current_term';
    public $storage = null;
    public $storage_type = 'transient'; //session, transient
    public $show_notes = false;

    public function __construct() {
        global $wpdb;
        self::$query_cache_table = $wpdb->prefix . self::$query_cache_table;
        //new  feature
        add_action('woocommerce_init', array($this, 'replacing_template_loop_product_thumbnail'));
        //***
        add_action('wp_ajax_woof_upload_ext', array($this, 'woof_upload_ext'));
        add_action('wp_ajax_nopriv_woof_upload_ext', array($this, 'woof_upload_ext'));

        $this->init_settings();
        if (!$this->is_should_init()) {
            $this->is_activated = false;
            return NULL;
        }
        //extensions initializating
        $this->init_extensions();

        $this->storage = new WOOF_STORAGE($this->storage_type);

        //+++

        if (!defined('DOING_AJAX')) {
            global $wp_query;
            if (isset($wp_query->query_vars['taxonomy']) AND in_array($wp_query->query_vars['taxonomy'], get_object_taxonomies('product'))) {
                $this->set_really_current_term();
            }
        }

        //+++

        add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts_styles'));
        add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
        add_action('admin_init', array($this, 'admin_init'));
        add_action('widgets_init', array($this, 'widgets_init'));
    }

    public function init() {

        if (!class_exists('WooCommerce')) {
            return;
        }

        //***
        $first_init = (int) get_option('woof_first_init', 0);
        if ($first_init != 1) {
            update_option('woof_first_init', 1);
            update_option('woof_set_automatically', 1);
            update_option('woof_autosubmit', 1);
            update_option('woof_show_count', 1);
            update_option('woof_show_count_dynamic', 0);
            update_option('woof_hide_dynamic_empty_pos', 0);
            update_option('woof_try_ajax', 0);
            update_option('woof_checkboxes_slide', 1);
            update_option('woof_hide_red_top_panel', 0);
            update_option('woof_sort_terms_checked', 0);
            update_option('woof_filter_btn_txt', '');
            update_option('woof_reset_btn_txt', '');

            //***

            $first_options = array(
                //'use_chosen' => 1,
                'select_design' => 'chosen', //!!
                'icheck_skin' => 'square_blue',
                'use_beauty_scroll' => 1,
                'woof_auto_hide_button' => 1,
                'woof_auto_filter_skins' => 'flat_white woof_auto_1_columns'
            );

            update_option('woof_settings', $first_options);
            $this->settings = $first_options;

            $first_settings = new WoofFirstSettings($this);
            $first_settings->init_first_settings();

            //***
            update_option('image_default_link_type', 'file'); //http://wordpress.stackexchange.com/questions/9727/link-to-file-url-by-default
        }

        //***

        $this->settings['delete_image'] = apply_filters('woof_delete_img_url', WOOF_LINK . "img/delete.png");

        load_plugin_textdomain('woocommerce-products-filter', false, dirname(plugin_basename(__FILE__)) . '/languages');
        add_filter('plugin_action_links_' . WOOF_PLUGIN_NAME, array($this, 'plugin_action_links'), 50);
        add_action('woocommerce_settings_tabs_array', array($this, 'woocommerce_settings_tabs_array'), 50);
        add_action('woocommerce_settings_tabs_woof', array($this, 'print_plugin_options'), 50);

        //+++
        //Optimize
        if (isset($this->settings['optimize_js_files']) AND $this->settings['optimize_js_files']) {
            add_action('wp_head', array($this, 'wp_head'), 999);
            add_action('wp_footer', array($this, 'wp_load_js'), 11);
        } else {
            add_action('wp_head', array($this, 'wp_head'), 999);
            add_action('wp_head', array($this, 'wp_load_js'), 999);
        }
        add_action('wp_footer', array($this, 'wp_footer'), 999);
        //+++
        if (!isset($_REQUEST['legacy-widget-preview'])) {
            add_shortcode('woof', array($this, 'woof_shortcode'));
            add_shortcode('woof_btn', array($this, 'show_btn'));
            add_shortcode('woof_mobile', array($this, 'show_mobile_btn'));
        }

        //+++
        add_action('wp_ajax_woof_save_options', array($this, 'woof_save_options'), 1);
        add_action('wp_ajax_woof_draw_products', array($this, 'woof_draw_products'));
        add_action('wp_ajax_nopriv_woof_draw_products', array($this, 'woof_draw_products'));
        add_action('wp_ajax_woof_redraw_woof', array($this, 'woof_redraw_woof'));
        add_action('wp_ajax_nopriv_woof_redraw_woof', array($this, 'woof_redraw_woof'));
        //+++
        add_filter('widget_text', 'do_shortcode');
        add_action('parse_query', array($this, "parse_query"), 9999);
        add_filter('woocommerce_product_query', array($this, "woocommerce_product_query"), 9999);
        add_action('body_class', array($this, 'body_class'), 9999);
        //+++
        add_action('woocommerce_before_shop_loop', array($this, 'woocommerce_before_shop_loop'), 2);
        add_action('woocommerce_after_shop_loop', array($this, 'woocommerce_after_shop_loop'), 10);

        add_shortcode('woof_products', array($this, 'woof_products'));
        //special shortcode to get all products ids. Really it is cutted [woof_products]. USE BEFORE [woof]
        add_shortcode('woof_products_ids_prediction', array($this, 'woof_products_ids_prediction'));
        add_shortcode('woof_price_filter', array($this, 'woof_price_filter'));

        add_shortcode('woof_search_options', array($this, 'woof_search_options'));
        add_shortcode('woof_found_count', array($this, 'woof_found_count'));

        //add_filter('woocommerce_pagination_args', array($this, 'woocommerce_pagination_args'));
        add_action('wp_ajax_woof_cache_count_data_clear', array($this, 'cache_count_data_clear'));
        add_action('wp_ajax_woof_cache_terms_clear', array($this, 'woof_cache_terms_clear'));
        add_action('wp_ajax_woof_price_transient_clear', array($this, 'woof_price_transient_clear'));

        //***
        add_action('wp_ajax_woof_remove_ext', array($this, 'woof_remove_ext'));

        add_filter('sidebars_widgets', array($this, 'sidebars_widgets'));
        //own filters of WOOF
        add_filter('woof_modify_query_args', array($this, 'woof_modify_query_args'), 1);
        //sheduling
        if ($this->get_option('cache_count_data_auto_clean')) {
            add_action('woof_cache_count_data_auto_clean', array($this, 'cache_count_data_clear'));
            if (!wp_next_scheduled('woof_cache_count_data_auto_clean')) {
                wp_schedule_event(time(), $this->get_option('cache_count_data_auto_clean'), 'woof_cache_count_data_auto_clean');
            }
        }


        //for pagination while searching is going only
        //http://docs.woothemes.com/document/change-number-of-products-displayed-per-page/
        if ($this->get_option('per_page') > 0 AND $this->is_isset_in_request_data($this->get_swoof_search_slug())) {
            if (version_compare(PHP_VERSION, '5.3.0', '<=')) {
                add_filter('loop_shop_per_page', create_function('$cols', "return {$this->get_option('per_page')};"), 9999);
            } else {
                add_filter('loop_shop_per_page', function ($cols) {
                    return $this->get_option('per_page');
                }, 9999);
            }
        }

        //cron
        add_filter('cron_schedules', array($this, 'cron_schedules'), 10, 1);
        //custom filters
        //***
        if ($this->is_isset_in_request_data($this->get_swoof_search_slug())) {
            $this->storage->set_val('woof_last_search_request', $this->get_request_data());
        }
        //sort terms. First if is checked
        if (get_option('woof_sort_terms_checked', 0)) {
            add_filter('woof_sort_terms_before_out', array($this, 'woof_sort_terms_is_checked'), 10, 2);
        }

        //compatibility with woo catalog
        add_filter('woocommerce_is_filtered', array($this, 'woocommerce_is_filtered'), 20);
        //meta filter
        add_action('woocommerce_product_query', array($this, 'woocommerce_parse_query'));
        //no found  template
        add_filter('woocommerce_locate_template', array($this, 'woof_overide_template'), 99, 3);
        add_filter('wc_get_template_part', array($this, 'woof_overide_template'), 99, 3);

        //compatibility with woo shortcode
        add_filter('woocommerce_shortcode_products_query', array($this, 'woocommerce_shortcode_products_query'), 99, 3);
        //ajax native shortcode shortcode
        $this->activate_woo_shortcodes();
        //sort options
        add_filter('woof_sort_terms_before_out', array($this, "sort_terms_before_out"), 5, 2);
        // AND OR logic
        add_filter('woof_main_query_tax_relations', array($this, 'change_query_tax_relations'), 5, 1);
        //woopd compatibility
        add_filter('woopt_get_query_args', array($this, 'woopt_set_query_args'), 5, 1);
    }

    public function admin_init() {
        include_once WOOF_PATH . 'classes/alert.php';
        (new WOOF_ADV())->init();
    }

    public function admin_enqueue_scripts() {
        if (isset($_GET['tab']) AND $_GET['tab'] == 'woof') {

            WOOF_HELPER::hide_admin_notices();

            wp_enqueue_style('open_sans_font', 'https://fonts.googleapis.com/css?family=Open+Sans');
            wp_enqueue_style('woof', WOOF_LINK . 'css/plugin_options.css', array(), WOOF_VERSION);

            wp_enqueue_style('woof_fontello', WOOF_LINK . 'css/fontello.css', array(), WOOF_VERSION);
        }
    }

    public function woof_save_options() {

        //save options can admin only <notifications@pluginvulnerabilities.com>
        if (!current_user_can('manage_woocommerce')) {
            return;
        }

        //***

        $data = WOOF_HELPER::safe_parse_str(WOOF_REQUEST::get('formdata'));

        if (isset($data['woof_settings'])) {
            if (!isset($data['_wpnonce_woof']) || !wp_verify_nonce($data['_wpnonce_woof'], 'woof_save_option')) {
                return;
            }

            $_POST = WOOF_HELPER::sanitize_array($data); //for WC_Admin_Settings
            WC_Admin_Settings::save_fields($this->get_options());
            //+++
            if (class_exists('SitePress') OR class_exists("Polylang")) {
                if (class_exists('SitePress')) {
                    //$lang = ICL_LANGUAGE_CODE;
                    $lang = apply_filters('wpml_current_language', NULL);
                }
                if (class_exists('Polylang')) {
                    $lang = get_locale();
                }
                if (isset($data['woof_settings']['wpml_tax_labels']) AND!empty($data['woof_settings']['wpml_tax_labels'])) {
                    $translations_string = $data['woof_settings']['wpml_tax_labels'];
                    $translations_string = explode(PHP_EOL, $translations_string);
                    $translations = array();
                    if (!empty($translations_string) AND is_array($translations_string)) {
                        foreach ($translations_string as $line) {
                            if (empty($line)) {
                                continue;
                            }

                            $line = explode(':', $line);
                            if (!isset($translations[$line[0]])) {
                                $translations[$line[0]] = array();
                            }
                            $tmp = explode('^', $line[1]);
                            $translations[$line[0]][$tmp[0]] = $tmp[1];
                        }
                    }

                    $data['woof_settings']['wpml_tax_labels'] = $translations;
                }
            }

            $data['woof_settings'] = WOOF_HELPER::sanitize_array($data['woof_settings']);

            //+++
            if (is_array($data['woof_settings'])) {
                $data['woof_settings']['default_overlay_skin_word'] = WOOF_HELPER::escape($data['woof_settings']['default_overlay_skin_word']);
                update_option('woof_settings', $data['woof_settings']);
            }
            wp_cache_flush();
        }


        die('done');
    }

    public function print_plugin_options() {

        wp_enqueue_script('media-upload');
        wp_enqueue_style('thickbox');
        wp_enqueue_script('thickbox');

        wp_enqueue_style('wp-color-picker');
        wp_enqueue_script('wp-color-picker');
        wp_enqueue_media();
        wp_enqueue_script('woof', WOOF_LINK . 'js/plugin_options.js', array('jquery', 'jquery-ui-core', 'jquery-ui-sortable'), WOOF_VERSION);

        $is_custom_extensions = false;
        if (is_dir($this->get_custom_ext_path())) {
            $dir_writable = is_writable($this->get_custom_ext_path());
            if ($dir_writable) {
                $is_custom_extensions = true;
            }
        }

        ob_start();
        ?>
        var woof_save_link = "<?php echo admin_url('admin.php?page=wc-settings&tab=woof&settings_saved=1') ?>";
        var woof_lang_saving = "<?php esc_html_e('WOOF settings saving ...', 'woocommerce-products-filter') ?>";
        var woof_abspath = "<?php echo realpath(ABSPATH) ?>";
        var woof_ext_path = "<?php echo realpath($this->get_custom_ext_path()) . '/' ?>";
        var woof_ext_url = "<?php echo sprintf("%s?action=woof_upload_ext&extnonce=%s", admin_url('admin-ajax.php'), wp_create_nonce('add-ext-nonce')) ?>";
        var woof_ext_custom = "<?php echo intval($is_custom_extensions) ?>";
        var woof_show_notes = <?php echo intval($this->show_notes ? 1 : 0) ?>;
        <?php
        $stxt = ob_get_clean();
        wp_add_inline_script('woof', $stxt, 'before');

        //*** for woocommerce >= v.2.6.0
        //to avoid https://products-filter.com/filtering-by-product-attribute-doesn-work/
        if (apply_filters('woof_init_archive_by_default', true)) {
            global $wpdb;
            $data_sql = array(
                array(
                    'type' => 'int',
                    'val' => 1,
                )
            );
            $wpdb->query(WOOF_HELPER::woof_prepare("UPDATE {$wpdb->prefix}woocommerce_attribute_taxonomies SET attribute_public=%d", $data_sql));
            flush_rewrite_rules();
            delete_transient('wc_attribute_taxonomies');
        }
        //***

        $args = array(
            "woof_settings" => $this->settings,
            "extensions" => $this->get_ext_directories()
        );

        $this->render_html_e(WOOF_PATH . 'views/plugin_options.php', $args);
    }

    public function enqueue_scripts_styles() {
        //enqueue styles
        if (isset($this->settings['custom_front_css']) AND!empty($this->settings['custom_front_css'])) {
            wp_enqueue_style('woof', $this->settings['custom_front_css']);
        } else {
            wp_enqueue_style('woof', WOOF_LINK . 'css/front.css', array(), WOOF_VERSION);
        }

        $css_data = "";

        $btn_url = '';
        if (isset($this->settings['woof_auto_hide_button_img']) AND!empty($this->settings['woof_auto_hide_button_img'])) {
            $btn_url = $this->settings['woof_auto_hide_button_img'];
        }
        //assemble dynamic css
        if (isset($this->settings['delete_image'])) {
            $css_data .= PHP_EOL . ".woof_products_top_panel li span, .woof_products_top_panel2 li span{"
                    . "background: url(" . $this->settings['delete_image'] . ");"
                    . "background-size: 14px 14px;"
                    . "background-repeat: no-repeat;"
                    . "background-position: right;"
                    . "}";
        }

        if ($btn_url != 'none' && $btn_url) {

            $css_data .= PHP_EOL . ".woof_show_auto_form,.woof_hide_auto_form{ background-image: url('$btn_url'); }";
        } elseif ($btn_url == 'none') {
            $css_data .= PHP_EOL . ".woof_show_auto_form,.woof_hide_auto_form{ background-image: none ;}";
        }

        if (isset($this->settings['overlay_skin_bg_img'])) {
            if (!empty($this->settings['overlay_skin_bg_img'])) {
                $css_data .= PHP_EOL . ".plainoverlay {
                        background-image: url('" . $this->settings['overlay_skin_bg_img'] . "');
                    }";
            }
        }

        if (isset($this->settings['plainoverlay_color'])) {
            if (!empty($this->settings['plainoverlay_color'])) {
                $css_data .= PHP_EOL . ".jQuery-plainOverlay-progress {
                        border-top: 12px solid " . $this->settings['plainoverlay_color'] . " !important;
                    }";
            }
        }

        if (isset($this->settings['woof_auto_subcats_plus_img'])) {
            if (!empty($this->settings['woof_auto_subcats_plus_img'])) {
                $css_data .= PHP_EOL . ".woof_childs_list_opener span.woof_is_closed{
                        background: url(" . $this->settings['woof_auto_subcats_plus_img'] . ");
                    }";
            }
        }

        if (isset($this->settings['woof_auto_subcats_minus_img'])) {
            if (!empty($this->settings['woof_auto_subcats_minus_img'])) {
                $css_data .= PHP_EOL . ".woof_childs_list_opener span.woof_is_opened{
                        background: url(" . $this->settings['woof_auto_subcats_minus_img'] . ");
                    }";
            }
        }
        if (!current_user_can('create_users')) {
            $css_data .= PHP_EOL . ".woof_edit_view{
                    display: none;
                }";
        }

        $show_price_search_button = 0;
        if (isset($this->settings['by_price']['show_button'])) {
            $show_price_search_button = (int) $this->settings['by_price']['show_button'];
        }
        if (isset($this->settings['by_price']['show']) AND (int) $this->settings['by_price']['show'] == 1) {
            if (!$show_price_search_button == 1) {
                $css_data .= PHP_EOL . ".woof_price_search_container .price_slider_amount button.button{
                        display: none;
                    }

                    /***** END: hiding submit button of the price slider ******/";
            }
        }


        if (isset($this->settings['custom_css_code'])) {
            $css_data .= PHP_EOL . stripcslashes($this->settings['custom_css_code']);
        }

        if (!empty(WOOF_EXT::$includes['css_code_custom'])) {
            foreach (WOOF_EXT::$includes['css_code_custom'] as $css_key_code => $css_code) {
                $css_data .= PHP_EOL . $css_code;
            }
        }
        if ($css_data) {
            wp_add_inline_style('woof', $css_data);
        }
        //***
        //select type
        $select_type = $this->get_select_type();
        switch ($select_type) {
            case "selectwoo":
                wp_enqueue_style('select2');
                break;
            case "chosen":
                wp_enqueue_style('chosen-drop-down', WOOF_LINK . 'js/chosen/chosen.min.css', array(), WOOF_VERSION);
                break;
            default :
        }


        if (isset($this->settings['overlay_skin']) AND $this->settings['overlay_skin'] != 'default') {
            wp_enqueue_style('plainoverlay', WOOF_LINK . 'css/plainoverlay.css', array(), WOOF_VERSION);
        }

        if ($this->get_option('use_beauty_scroll', 0)) {
            //removed
        }

        $icheck_skin = 'none';
        if (isset($this->settings['icheck_skin'])) {
            $icheck_skin = $this->settings['icheck_skin'];
        }
        if ($icheck_skin != 'none') {
            if (!$icheck_skin) {
                $icheck_skin = 'square_green';
            }

            if ($icheck_skin != 'none') {
                $icheck_skin = explode('_', $icheck_skin);
                wp_enqueue_style('icheck-jquery-color', WOOF_LINK . 'js/icheck/skins/' . $icheck_skin[0] . '/' . $icheck_skin[1] . '.css', array(), WOOF_VERSION);
            }
        }

        //***
        //for extensions
        if (!empty(WOOF_EXT::$includes['css'])) {
            foreach (WOOF_EXT::$includes['css'] as $css_key => $css_link) {
                wp_enqueue_style($css_key, $css_link, array(), WOOF_VERSION);
            }
        }
    }

    public function body_class($classes) {
        if ($this->is_isset_in_request_data($this->get_swoof_search_slug())) {
            $classes[] = 'woof_search_is_going';
        }

        return $classes;
    }

    //compatibility  with woo catalog
    public function woocommerce_is_filtered($is_filtered) {
        if ($this->is_isset_in_request_data($this->get_swoof_search_slug())) {
            $is_filtered = true;
        }

        return $is_filtered;
    }

    public function widgets_init() {
        if ($this->is_should_init()) {
            register_widget('WOOF_Widget');
        } else {
            $this->is_activated = false;
        }
    }

    //fix for woo 2.3.2 and higher with attributes filtering
    public function change_woo_att_data($taxonomy_data) {
        $taxonomy_data['query_var'] = true;
        return $taxonomy_data;
    }

    public function sidebars_widgets($sidebars_widgets) {
        $price_filter = 0;
        if (isset($this->settings['by_price']['show'])) {
            $price_filter = (int) $this->settings['by_price']['show'];
        }

        if ($price_filter) {
            $sidebars_widgets['sidebar-woof'] = array('woocommerce_price_filter');
        }

        return $sidebars_widgets;
    }

    public function cron_schedules($schedules) {
        //$schedules stores all recurrence schedules within WordPress
        for ($i = 2; $i <= 7; $i++) {
            $schedules['days' . $i] = array(
                'interval' => $i * DAY_IN_SECONDS,
                'display' => sprintf(esc_html__("each %s days", 'woocommerce-products-filter'), $i)
            );
        }

        return (array) $schedules;
    }

    /**
     * Show action links on the plugin screen
     */
    public function plugin_action_links($links) {
        $buttons = array(
            '<a href="' . admin_url('admin.php?page=wc-settings&tab=woof') . '">' . esc_html__('Settings', 'woocommerce-products-filter') . '</a>',
            '<a target="_blank" href="' . esc_url('https://products-filter.com/') . '">' . esc_html__('Documentation', 'woocommerce-products-filter') . '</a>'
        );

        if ($this->show_notes) {
            $buttons[] = '<a target="_blank" style="color: red; font-weight: bold;" href="' . esc_url('https://codecanyon.pluginus.net/item/woof-woocommerce-products-filter/11498469') . '">' . esc_html__('Go Pro!', 'woocommerce-products-filter') . '</a>';
        }

        return array_merge($buttons, $links);
    }

    public function get_swoof_search_slug() {
        $slug = 'swoof';

        if (!$this->show_notes) {
            if (isset($this->settings['swoof_search_slug']) AND!empty($this->settings['swoof_search_slug'])) {
                $slug = $this->settings['swoof_search_slug'];
            }
        }

        return $slug;
    }

    public function woocommerce_product_query($q) {
        //http://docs.woothemes.com/wc-apidocs/class-WC_Query.html
        //wp-content\plugins\woocommerce\includes\class-wc-query.php -> public function product_query( $q )
        $meta_query = $q->get('meta_query');

        //for extensions
        if (!empty(WOOF_EXT::$includes['html_type_objects'])) {
            foreach (WOOF_EXT::$includes['html_type_objects'] as $obj) {
                if (method_exists($obj, 'assemble_query_params')) {
                    $q->set('meta_query', $obj->assemble_query_params($meta_query, $q));
                }
            }
        }


        return $q;
    }

    function woocommerce_parse_query($q) {
        $meta_query = $q->get('meta_query');
        $meta_query = apply_filters('woof_get_meta_query', $meta_query);

        $q->set('meta_query', $meta_query);

        $tax_query = $q->get('tax_query');
        $tax_query = $this->parse_tax_query($tax_query);

        $q->set('tax_query', $tax_query); //wc_get_loop_prop( 'total' ),
    }

    public function parse_query($wp_query) {
        //on single page works [woof_products] shortcode, so we doesn need parse query there!!!
        //***
        WOOF_REQUEST::set('woof_parse_query', 1);

        if (!defined('DOING_AJAX')) {
            if (WOOF_REQUEST::isset('woof_products_doing')) {
                return $wp_query;
            }
        }



        $request = $this->get_request_data();

        //+++
        if ($wp_query->is_main_query()) {
            if ($this->is_isset_in_request_data($this->get_swoof_search_slug())) {

                if (!isset($wp_query->query['post_type']) OR $wp_query->query['post_type'] != 'product') {
                    global $wp;
                    if (home_url($wp->request) != home_url()) {
                        // return $wp_query;
                    }
                }

                if (!empty($wp_query->tax_query) AND isset($wp_query->tax_query->queries)) {

                    $tax_relations = apply_filters('woof_main_query_tax_relations', array());

                    if (!empty($tax_relations)) {

                        $tax_query = $wp_query->tax_query->queries;
                        foreach ($tax_query as $key => $value) {
                            if (in_array($value['taxonomy'], array_keys($tax_relations))) {
                                if (count($tax_query[$key]['terms'])) {
                                    $tax_query[$key]['operator'] = $tax_relations[$value['taxonomy']];
                                    $tax_query[$key]['include_children'] = 0;
                                }
                            }
                        }


                        // fix visibility
                        if (version_compare(WOOCOMMERCE_VERSION, '3.0', '>=')) {
                            $this->product_visibility_for_parse_query();
                        }
                        // end fix
                        $wp_query->set('tax_query', $tax_query);
                    }
                }

                //***
                $disable_swoof_influence = false;
                if (isset($this->settings['disable_swoof_influence'])) {
                    $disable_swoof_influence = (bool) $this->settings['disable_swoof_influence'];
                }
                $is_divi = false;

                if (!$disable_swoof_influence) {
                    if (!is_page()) {
                        $wp_query->set('post_type', 'product');
                        if (!$is_divi) {
                            $wp_query->is_post_type_archive = true;
                        }
                    }
                    if ($is_divi) {
                        if (!isset($_GET['really_curr_tax'])) {
                            $wp_query->is_tax = false;
                            $wp_query->is_tag = false;
                        }
                    } else {
                        $wp_query->is_tax = false;
                        $wp_query->is_tag = false;
                    }

                    $wp_query->is_home = false;
                    $wp_query->is_single = false;
                    $wp_query->is_posts_page = false;
                    $wp_query->is_search = false; //!!!
                }

                //+++
                $meta_query = array();

                if (isset($wp_query->query_vars['meta_query'])) {
                    $meta_query = $wp_query->query_vars['meta_query'];
                }

                //+++
                //for extensions
                if (!empty(WOOF_EXT::$includes['html_type_objects'])) {
                    foreach (WOOF_EXT::$includes['html_type_objects'] as $obj) {
                        if (method_exists($obj, 'assemble_query_params')) {
                            //lock adding meta params for single page while shortcode start to work when searching is going
                            if (is_page()) {
                                if (!WOOF_REQUEST::isset('woof_products_doing')) {
                                    $wp_query->set('meta_query', $meta_query);
                                    return $wp_query;
                                }
                            }
                            $obj->assemble_query_params($meta_query, $wp_query);
                        }
                    }
                }

                //***
                //fix visibility
                if (version_compare(WOOCOMMERCE_VERSION, '3.0', '<')) {
                    $meta_query = $this->listen_catalog_visibility($meta_query, true);
                }
                //***
                $wp_query->set('meta_query', $meta_query);
                //compatibility for woocommerce-products-per-page
                if (class_exists('Woocommerce_Products_Per_Page')) {
                    $wp_query->set('posts_per_page', $this->get_wppp_per_page());
                }
            }
        }

        return $wp_query;
    }

    private function assemble_price_params(&$meta_query) {
        $request = $this->get_request_data();
        if (isset($request['min_price']) AND isset($request['max_price'])) {

            if (class_exists('WCML_Multi_Currency') AND!class_exists('WOOCS')) {
                global $woocommerce_wpml;
                if (isset($woocommerce_wpml->multi_currency)) {
                    $current_currency = $woocommerce_wpml->multi_currency->get_client_currency();
                    if ($current_currency != get_option('woocommerce_currency')) {
                        $request['min_price'] = $woocommerce_wpml->multi_currency->prices->unconvert_price_amount($request['min_price'], $current_currency);
                        $request['max_price'] = $woocommerce_wpml->multi_currency->prices->unconvert_price_amount($request['max_price'], $current_currency);
                    }
                }
            }

            if (wc_tax_enabled() && 'incl' === get_option('woocommerce_tax_display_shop') && !wc_prices_include_tax()) {
                $class_min = isset($request['min_price']) ? floatval(wp_unslash($request['min_price'])) : 0;
                $class_max = isset($request['max_price']) ? floatval(wp_unslash($request['max_price'])) : PHP_INT_MAX;
                $tax_class = apply_filters('woocommerce_price_filter_widget_tax_class', ''); // Uses standard tax class.
                $tax_rates = WC_Tax::get_rates($tax_class);

                if ($tax_rates) {
                    $class_min -= WC_Tax::get_tax_total(WC_Tax::calc_inclusive_tax($class_min, $tax_rates));
                    $class_max -= WC_Tax::get_tax_total(WC_Tax::calc_inclusive_tax($class_max, $tax_rates));
                }
                $request['min_price'] = $class_min;
                $request['max_price'] = $class_max;
            }

            if ($request['min_price'] <= $request['max_price']) {
//                $meta_query[] = array(
//                    'key' => '_price',
//                    'value' => array(floatval($request['min_price']), floatval($request['max_price'])),
//                    'type' => 'DECIMAL(5,2)',
//                    'compare' => 'BETWEEN'
//                );
//

                $meta_query[] = [
                    'relation' => 'AND',
                    [
                        'key' => '_price',
                        'value' => floatval($request['min_price']),
                        'compare' => '>=',
                        'type' => 'NUMERIC'
                    ],
                    [
                        'key' => '_price',
                        'value' => floatval($request['max_price']),
                        'compare' => '<',
                        'type' => 'NUMERIC'
                    ]
                ];
            }
        }

        return $meta_query;
    }

    public function woocommerce_settings_tabs_array($tabs) {
        $tabs['woof'] = esc_html__('Products Filter', 'woocommerce-products-filter');
        return $tabs;
    }

    public function wp_head() {
        if (!defined('DOING_AJAX') && !is_page()) {
            global $wp_query;
            $queried_obj = get_queried_object();
            if (isset($wp_query->query_vars['taxonomy']) AND is_object($queried_obj) AND get_class(get_queried_object()) == 'WP_Term' AND!isset($request_data['really_curr_tax'])) {
                if (is_object($queried_obj)) {
                    $this->set_really_current_term($queried_obj);
                }
            } elseif (isset($request_data['really_curr_tax'])) {
                $tmp = explode('-', $request_data['really_curr_tax'], 2);
                $res = get_term($tmp[0], $tmp[1]);
                $this->set_really_current_term($res);
            } else {
                $this->set_really_current_term();
            }
        } else {
            if ($this->is_really_current_term_exists()) {
                $this->set_really_current_term();
            }
        }
    }

    public function wp_load_js() {
        global $is_edge, $is_gecko;

        global $wp_query;
        //***
        ob_start();
        /* dynamic js assemble vars */
        ?>
        var woof_is_permalink =<?php echo intval((bool) $this->is_permalink_activated()) ?>;
        var woof_shop_page = "";
        <?php if (!$this->is_permalink_activated()): ?>
            woof_shop_page = "<?php echo esc_url(home_url('/?post_type=product')) ?>";
        <?php endif; ?>
        var woof_m_b_container ="<?php esc_html_e(apply_filters('woof_mobile_btn_place_container', '.woocommerce-products-header')); ?>";
        var woof_really_curr_tax = {};
        var woof_current_page_link = location.protocol + '//' + location.host + location.pathname;
        /*lets remove pagination from woof_current_page_link*/
        woof_current_page_link = woof_current_page_link.replace(/\page\/[0-9]+/, "");
        <?php
        if (!isset($wp_query->query_vars['taxonomy'])) {
            $page_id = get_option('woocommerce_shop_page_id');
            if ($page_id > 0) {
                if (!$this->is_permalink_activated()) {
                    $link = home_url('/?post_type=product');
                } else {
                    $link = get_permalink($page_id);
                }
            }

            if (isset($link) AND!empty($link) AND is_string($link)) {
                ?>
                woof_current_page_link = "<?php echo esc_url($link) ?>";
                <?php
            }
        }


        /* code bone when filter child categories on the category page of parent
          like here: http://demo.pluginus.net/product-category/clothing/?swoof=1&product_cat=hoo1 */
        ?>
        var woof_link = '<?php echo esc_url(WOOF_LINK) ?>';
        <?php
        $curr_tax = $this->get_really_current_term();
        if ($curr_tax && is_object($curr_tax)) {
            ?>
            woof_really_curr_tax = {term_id:<?php echo intval($curr_tax->term_id) ?>, taxonomy: "<?php esc_html_e($curr_tax->taxonomy) ?>"};
            <?php
        }
        ?>

        var woof_ajaxurl = "<?php echo admin_url('admin-ajax.php') ?>";

        var woof_lang = {
        'orderby': "<?php esc_html_e('orderby', 'woocommerce-products-filter') ?>",
        'date': "<?php esc_html_e('date', 'woocommerce-products-filter') ?>",
        'perpage': "<?php esc_html_e('per page', 'woocommerce-products-filter') ?>",
        'pricerange': "<?php esc_html_e('price range', 'woocommerce-products-filter') ?>",
        'menu_order': "<?php esc_html_e('menu order', 'woocommerce-products-filter') ?>",
        'popularity': "<?php esc_html_e('popularity', 'woocommerce-products-filter') ?>",
        'rating': "<?php esc_html_e('rating', 'woocommerce-products-filter') ?>",
        'price': "<?php esc_html_e('price low to high', 'woocommerce-products-filter') ?>",
        'price-desc': "<?php esc_html_e('price high to low', 'woocommerce-products-filter') ?>",
        'clear_all': "<?php esc_html_e(apply_filters('woof_clear_all_text', esc_html__('Clear All', 'woocommerce-products-filter'))) ?>"
        };

        if (typeof woof_lang_custom == 'undefined') {
        var woof_lang_custom = {};/*!!important*/
        }

        var woof_is_mobile = 0;
        <?php if (WOOF_HELPER::is_mobile_device()): ?>
            woof_is_mobile = 1;
        <?php endif; ?>



        var woof_show_price_search_button = 0;
        var woof_show_price_search_type = 0;
        <?php
        $show_price_search_button = 0;
        $show_price_search_type = 0;
        if (isset($this->settings['by_price']['show_button'])) {
            $show_price_search_button = (int) $this->settings['by_price']['show_button'];
        }

        if (isset($this->settings['by_price']['show'])) {
            $show_price_search_type = (int) $this->settings['by_price']['show'];
        }

        if ($show_price_search_button == 1):
            ?>
            woof_show_price_search_button = 1;
        <?php endif; ?>

        var woof_show_price_search_type = <?php echo intval($show_price_search_type) ?>;

        var swoof_search_slug = "<?php esc_attr_e($this->get_swoof_search_slug()); ?>";

        <?php
        $icheck_skin = 'none';
        if (isset($this->settings['icheck_skin'])) {
            $icheck_skin = $this->settings['icheck_skin'];
        }
        ?>

        var icheck_skin = {};
        <?php if ($icheck_skin != 'none'): ?>
            <?php $icheck_skin = explode('_', $icheck_skin); ?>
            icheck_skin.skin = "<?php esc_html_e($icheck_skin[0]) ?>";
            icheck_skin.color = "<?php esc_html_e($icheck_skin[1]) ?>";
            if (window.navigator.msPointerEnabled && navigator.msMaxTouchPoints > 0) {
            /*icheck_skin = 'none';*/
            }
        <?php else: ?>
            icheck_skin = 'none';
        <?php endif; ?>

        var woof_select_type = '<?php esc_html_e($this->get_select_type()); ?>';


        <?php $woof_use_beauty_scroll = $this->get_option('use_beauty_scroll', 0); ?>
        var woof_current_values = '[]';
        <?php if ($this->get_request_data()) { ?>
            woof_current_values = '<?php echo json_encode($this->get_request_data()); ?>';
        <?php } ?>
        var woof_lang_loading = "<?php esc_html_e('Loading ...', 'woocommerce-products-filter') ?>";

        <?php if (isset($this->settings['default_overlay_skin_word']) AND!empty($this->settings['default_overlay_skin_word'])): ?>
            woof_lang_loading = "<?php esc_html_e($this->settings['default_overlay_skin_word'], 'woocommerce-products-filter') ?>";
        <?php endif; ?>

        var woof_lang_show_products_filter = "<?php esc_html_e('show products filter', 'woocommerce-products-filter') ?>";
        var woof_lang_hide_products_filter = "<?php esc_html_e('hide products filter', 'woocommerce-products-filter') ?>";
        var woof_lang_pricerange = "<?php esc_html_e('price range', 'woocommerce-products-filter') ?>";

        var woof_use_beauty_scroll =<?php echo intval($woof_use_beauty_scroll) ?>;

        var woof_autosubmit =<?php echo intval(get_option('woof_autosubmit', 0)) ?>;
        var woof_ajaxurl = "<?php echo admin_url('admin-ajax.php') ?>";
        /*var woof_submit_link = "";*/
        var woof_is_ajax = 0;
        var woof_ajax_redraw = 0;
        var woof_ajax_page_num =<?php echo intval(get_query_var('page') ? get_query_var('page') : 1) ?>;
        var woof_ajax_first_done = false;
        var woof_checkboxes_slide_flag = <?php esc_attr_e((int) get_option('woof_checkboxes_slide') === 1 ? 1 : 0); ?>;


        /*toggles*/
        var woof_toggle_type = "<?php esc_html_e((isset($this->settings['toggle_type']) AND!empty($this->settings['toggle_type'])) ? $this->settings['toggle_type'] : 'text') ?>";

        var woof_toggle_closed_text = "<?php esc_html_e((isset($this->settings['toggle_closed_text']) AND!empty($this->settings['toggle_closed_text'])) ? trim(WOOF_HELPER::wpml_translate(null, $this->settings['toggle_closed_text'])) : '+') ?>";
        var woof_toggle_opened_text = "<?php esc_html_e((isset($this->settings['toggle_opened_text']) AND!empty($this->settings['toggle_opened_text'])) ? trim(WOOF_HELPER::wpml_translate(null, $this->settings['toggle_opened_text'])) : '-') ?>";

        var woof_toggle_closed_image = "<?php esc_html_e((isset($this->settings['toggle_closed_image']) AND!empty($this->settings['toggle_closed_image'])) ? $this->settings['toggle_closed_image'] : WOOF_LINK . 'img/plus.svg') ?>";
        var woof_toggle_opened_image = "<?php esc_html_e((isset($this->settings['toggle_opened_image']) AND!empty($this->settings['toggle_opened_image'])) ? $this->settings['toggle_opened_image'] : WOOF_LINK . 'img/minus.svg') ?>";


        /*indexes which can be displayed in red buttons panel*/
        <?php
        $taxonomies = $this->get_taxonomies();
        $taxonomies_keys = array_keys($taxonomies);
        if (version_compare(PHP_VERSION, '5.3.0', '<=')) {
            array_walk($taxonomies_keys, create_function('&$str', '$str = "\"$str\"";'));
        } else {
            array_walk($taxonomies_keys, function (&$str) {
                $str = "\"" . $str . "\"";
            });
        }
        $taxonomies_keys = implode(',', $taxonomies_keys);
        $extensions_html_type_indexes = array();

        if (!empty(WOOF_EXT::$includes['html_type_objects'])) {
            foreach (WOOF_EXT::$includes['html_type_objects'] as $obj) {
                if ($obj->index !== NULL) {
                    $extensions_html_type_indexes[] = $obj->index;
                }
            }
        }
        $extensions_html_type_indexes[] = "min_rating";
        if (version_compare(PHP_VERSION, '5.3.0', '<=')) {
            array_walk($extensions_html_type_indexes, create_function('&$str', '$str = "\"$str\"";'));
        } else {
            array_walk($extensions_html_type_indexes, function (&$str) {
                $str = "\"$str\"";
            });
        }


        $extensions_html_type_indexes = implode(',', apply_filters('woof_extensions_type_index', $extensions_html_type_indexes));

        $extensions_html_type_indexes = str_replace('&quot;', "\"", esc_js($extensions_html_type_indexes));
        ?>
        var woof_accept_array = ["min_price", "orderby", "perpage", <?php echo wp_kses_post(wp_unslash($extensions_html_type_indexes)) ?>,<?php echo wp_kses_post(wp_unslash($taxonomies_keys)) ?>];

        <?php if (isset($request_data['really_curr_tax'])): ?>
            <?php
            $tmp = explode('-', $request_data['really_curr_tax']);
            ?>
            woof_really_curr_tax = {term_id:<?php echo intval($tmp[0]) ?>, taxonomy: "<?php WOOF_HELPER::escape($tmp[1], true) ?>"};
        <?php endif; ?>

        /*for extensions*/

        var woof_ext_init_functions = null;
        <?php if (!empty(WOOF_EXT::$includes['js_init_functions'])) : ?>
            woof_ext_init_functions = '<?php echo json_encode(wc_clean(WOOF_EXT::$includes['js_init_functions'])); ?>';
        <?php endif; ?>


        <?php
        if ($is_gecko AND (int) get_option('woof_try_ajax', 0) === 0 AND isset($this->settings['overlay_skin']) AND $this->settings['overlay_skin'] != 'default') {
            $this->settings['overlay_skin'] = 'plainoverlay';  //Compatibility SVG with firefox
        }
        ?>

        var woof_overlay_skin = "<?php esc_html_e(isset($this->settings['overlay_skin']) ? $this->settings['overlay_skin'] : 'default') ?>";


        function woof_js_after_ajax_done() {
        jQuery(document).trigger('woof_ajax_done');
        <?php echo(isset($this->settings['js_after_ajax_done']) ? stripcslashes(esc_js(str_replace('"', "'", $this->settings['js_after_ajax_done']))) : ''); ?>
        }

        <?php
        $stxt = ob_get_clean();

        if (!isset($this->settings['use_tooltip'])) {
            $show_tooltip = 1;
        } else {
            $show_tooltip = $this->settings['use_tooltip'];
        }
        if ($show_tooltip) {
            wp_enqueue_style('woof_tooltip-css', WOOF_LINK . 'js/tooltip/css/tooltipster.bundle.min.css', array(), WOOF_VERSION);
            wp_enqueue_style('woof_tooltip-css-noir', WOOF_LINK . 'js/tooltip/css/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-noir.min.css', array(), WOOF_VERSION);
            wp_enqueue_script('woof_tooltip-js', WOOF_LINK . 'js/tooltip/js/tooltipster.bundle.min.js', array('jquery'), WOOF_VERSION);
        }
        if ($icheck_skin != 'none') {
            wp_enqueue_script('icheck-jquery', WOOF_LINK . 'js/icheck/icheck.min.js', array('jquery'), WOOF_VERSION);
        }
        if (isset($this->settings['optimize_js_files']) AND $this->settings['optimize_js_files']) {
            wp_enqueue_script('woof_front', WOOF_LINK . 'js/front_comprssd.js', array('jquery'), WOOF_VERSION);
        } else {
            wp_enqueue_script('woof_front', WOOF_LINK . 'js/front.js', array('jquery'), WOOF_VERSION);
            wp_enqueue_script('woof_radio_html_items', WOOF_LINK . 'js/html_types/radio.js', array('jquery'), WOOF_VERSION);
            wp_enqueue_script('woof_checkbox_html_items', WOOF_LINK . 'js/html_types/checkbox.js', array('jquery'), WOOF_VERSION);
            wp_enqueue_script('woof_select_html_items', WOOF_LINK . 'js/html_types/select.js', array('jquery'), WOOF_VERSION);
            wp_enqueue_script('woof_mselect_html_items', WOOF_LINK . 'js/html_types/mselect.js', array('jquery'), WOOF_VERSION);
        }
        wp_add_inline_script('woof_front', $stxt, 'before');
        wp_localize_script('woof_front', 'woof_filter_titles', $this->get_all_filter_titles());
        $text_data = array();
        if (!empty(WOOF_EXT::$includes['js_lang_custom'])) {
            foreach (WOOF_EXT::$includes['js_lang_custom'] as $js_key_lang => $js_text) {
                $text_data[$js_key_lang] = $js_text;
            }
            wp_localize_script('woof_front', 'woof_ext_filter_titles', $text_data);
        }
        $js_data = "";
        if (!empty(WOOF_EXT::$includes['js_code_custom'])) {
            foreach (WOOF_EXT::$includes['js_code_custom'] as $js_key_code => $js_code) {
                $js_data .= PHP_EOL . $js_code;
            }
            wp_add_inline_script('woof_front', $js_data, 'before');
        }

        if (!empty(WOOF_EXT::$includes['js'])) {
            foreach (WOOF_EXT::$includes['js'] as $js_key => $js_link) {
                wp_enqueue_script($js_key, $js_link, array('jquery'), WOOF_VERSION);
            }
        }

        //select type
        $select_type = $this->get_select_type();
        switch ($select_type) {
            case "selectwoo":
                wp_enqueue_script('selectWoo');
                wp_enqueue_script('select2');
                break;
            case "chosen":
                wp_enqueue_script('chosen-drop-down', WOOF_LINK . 'js/chosen/chosen.jquery.js', array('jquery'), WOOF_VERSION);
                break;
            default :
        }


        if (isset($this->settings['overlay_skin']) AND $this->settings['overlay_skin'] != 'default') {
            wp_enqueue_script('plainoverlay', WOOF_LINK . 'js/plainoverlay/jquery.plainoverlay.min.js', array('jquery'), WOOF_VERSION);
        }

        if ($woof_use_beauty_scroll) {
            /* removed */
        }

        $price_filter = 0;
        if (isset($this->settings['by_price']['show'])) {
            $price_filter = (int) $this->settings['by_price']['show'];
        }

        if ($price_filter == 1) {
            wp_enqueue_script('jquery-ui-core', array('jquery'));
            wp_enqueue_script('jquery-ui-slider', array('jquery-ui-core'));
            wp_enqueue_script('wc-jquery-ui-touchpunch', array('jquery-ui-core', 'jquery-ui-slider'));
            wp_enqueue_script('wc-price-slider', array('jquery-ui-slider', 'wc-jquery-ui-touchpunch'));
        }
    }

    public function get_all_filter_titles() {
        $options = array();
        $items_order = array();
        $taxonomies = $this->get_taxonomies();
        $taxonomies_keys = array_keys($taxonomies);
        if (isset($this->settings['items_order']) AND!empty($this->settings['items_order'])) {
            $items_order = explode(',', $this->settings['items_order']);
        } else {
            $items_order = array_merge($this->items_keys, $taxonomies_keys);
        }

        //*** lets check if we have new taxonomies added in woocommerce or new item
        foreach (array_merge($this->items_keys, $taxonomies_keys) as $key) {
            if (!in_array($key, $items_order)) {
                $items_order[] = $key;
            }
        }

        //lets print our items and taxonomies
        foreach ($items_order as $key) {
            if (in_array($key, $this->items_keys)) {
                if (isset($this->settings['meta_filter']) AND isset($this->settings['meta_filter'][$key])) {
                    if (isset($this->settings[$key]['show']) && $this->settings[$key]['show'] != 0) {
                        $options[$key] = $this->settings['meta_filter'][$key]['title'];

                        if (in_array($this->settings['meta_filter'][$key]["search_view"], array('select', 'mselect'))) {
                            $options[$this->settings['meta_filter'][$key]["search_view"] . "_" . $key] = $this->settings['meta_filter'][$key]['title'];
                        }
                    }
                } else {
                    if (isset($this->settings[$key]['show']) && $this->settings[$key]['show'] != 0) {
                        $options[$key] = $key;
                    }
                }
            } else {
                if (isset($taxonomies[$key])) {
                    if (isset($this->settings['tax'][$key]) && $this->settings['tax'][$key] != 0) {

                        if (isset($this->settings["custom_tax_label"][$key]) AND $this->settings["custom_tax_label"][$key]) {
                            $title = $this->settings["custom_tax_label"][$key];

                            if (isset($this->settings["tax_type"]) && $this->settings["tax_type"][$key] == 'select_hierarchy') {
                                $tmp_title = explode("^", $title);
                                if (isset($tmp_title[1]) && $tmp_title[1]) {
                                    $title = $tmp_title[1];
                                } elseif (strrpos($title, "+") !== false) {
                                    $title = $taxonomies[$key]->labels->name;
                                }
                            }

                            $options[$key] = WOOF_HELPER::wpml_translate(null, $title);
                        } else {
                            $options[$key] = WOOF_HELPER::wpml_translate($taxonomies[$key]);
                        }
                        if (isset($this->settings['comparison_logic'][$key]) AND $this->settings['comparison_logic'][$key] == "NOT IN") {
                            $options["rev_" . $key] = $options[$key];
                        }
                    }
                }
            }
        }

        return $options;
    }

    public function wp_footer() {
        if (isset($this->settings['overlay_skin']) AND ( $this->settings['overlay_skin'] != 'default' AND $this->settings['overlay_skin'] != 'plainoverlay')) {
            ?>

            <img  style="display: none;" src="<?php echo esc_url(WOOF_LINK) ?>img/loading-master/<?php esc_attr_e($this->settings['overlay_skin']) ?>.svg" alt="preloader" />

            <?php
        }

        if (isset($this->settings['autoform_toggle_closed_image']) AND!empty($this->settings['autoform_toggle_closed_image'])) {
            ?>
            <style>
                .woof_show_auto_form,
                .woof_hide_auto_form{
                    background: url("<?php echo esc_url($this->settings['autoform_toggle_closed_image']) ?>") !important;
                }
            </style>
            <?php
        }
    }

    private function init_settings() {
        $this->settings = get_option('woof_settings', array());
    }

    public function get_taxonomies() {
        static $taxonomies = array();
        if (empty($taxonomies)) {
            $taxonomies = get_object_taxonomies('product', 'objects');
            unset($taxonomies['product_shipping_class']);
            unset($taxonomies['product_type']);
            //unset($taxonomies['product_visibility']);
        }
        return $taxonomies;
    }

    public function get_options() {
        $options = array
            (array(
                'name' => '',
                'type' => 'title',
                'desc' => '',
                'id' => 'woof_general_settings'
            ),
            array(
                'name' => esc_html__('Set filter automatically', 'woocommerce-products-filter'),
                'desc' => esc_html__('Set filter automatically on the shop page', 'woocommerce-products-filter'),
                'id' => 'woof_set_automatically',
                'type' => 'select',
                'class' => 'chosen_select',
                'css' => 'min-width:300px;',
                'options' => array(
                    1 => esc_html__('Yes', 'woocommerce-products-filter'),
                    2 => esc_html__('Yes, but only for mobile devices', 'woocommerce-products-filter'),
                    3 => esc_html__('Yes, but only for desktop', 'woocommerce-products-filter'),
                    0 => esc_html__('No', 'woocommerce-products-filter'),
                ),
                'desc_tip' => true
            ),
            array(
                'name' => esc_html__('Autosubmit', 'woocommerce-products-filter'),
                'desc' => esc_html__('Start searching just after changing any of the elements on the search form', 'woocommerce-products-filter'),
                'id' => 'woof_autosubmit',
                'type' => 'select',
                'class' => 'chosen_select',
                'css' => 'min-width:300px;',
                'options' => array(
                    0 => esc_html__('No', 'woocommerce-products-filter'),
                    1 => esc_html__('Yes', 'woocommerce-products-filter')
                ),
                'desc_tip' => true
            ),
            array(
                'name' => esc_html__('Show count', 'woocommerce-products-filter'),
                'desc' => esc_html__('Show count of items near taxonomies terms on the front', 'woocommerce-products-filter'),
                'id' => 'woof_show_count',
                'type' => 'select',
                'class' => 'chosen_select',
                'css' => 'min-width:300px;',
                'options' => array(
                    0 => esc_html__('No', 'woocommerce-products-filter'),
                    1 => esc_html__('Yes', 'woocommerce-products-filter')
                ),
                'desc_tip' => true
            ),
            array(
                'name' => esc_html__('Dynamic recount', 'woocommerce-products-filter'),
                'desc' => esc_html__('Show count of items near taxonomies terms on the front dynamically. Must be switched on "Show count". In turbo mode if filter is very big better select "Yes, only for PC"', 'woocommerce-products-filter'),
                'id' => 'woof_show_count_dynamic',
                'type' => 'select',
                'class' => 'chosen_select',
                'css' => 'min-width:300px;',
                'options' => array(
                    0 => esc_html__('No', 'woocommerce-products-filter'),
                    1 => esc_html__('Yes', 'woocommerce-products-filter')
                ),
                'desc_tip' => true
            ),
            array(
                'name' => esc_html__('Hide empty terms', 'woocommerce-products-filter'),
                'desc' => esc_html__('Hide empty terms in "Dynamic recount" mode', 'woocommerce-products-filter'),
                'id' => 'woof_hide_dynamic_empty_pos',
                'type' => 'select',
                'class' => 'chosen_select',
                'css' => 'min-width:300px;',
                'options' => array(
                    0 => esc_html__('No', 'woocommerce-products-filter'),
                    1 => esc_html__('Yes', 'woocommerce-products-filter')
                ),
                'desc_tip' => true
            ),
            array(
                'name' => esc_html__('Try to ajaxify the shop', 'woocommerce-products-filter'),
                'desc' => esc_html__('Select "Yes" if you want to TRY make filtering in your shop by AJAX. Not compatible for 100% of all wp themes, so test it well if you are going to buy premium version of the plugin because incompatibility is not fixable!', 'woocommerce-products-filter'),
                'id' => 'woof_try_ajax',
                'type' => 'select',
                'class' => 'chosen_select',
                'css' => 'min-width:300px;',
                'options' => array(
                    0 => esc_html__('No', 'woocommerce-products-filter'),
                    1 => esc_html__('Yes', 'woocommerce-products-filter')
                ),
                'desc_tip' => true
            ),
            array(
                'name' => esc_html__('Hide childs in checkboxes and radio', 'woocommerce-products-filter'),
                'desc' => esc_html__('Hide childs in checkboxes and radio. Near checkbox/radio which has childs will be plus icon to show childs.', 'woocommerce-products-filter'),
                'id' => 'woof_checkboxes_slide',
                'type' => 'select',
                'class' => 'chosen_select',
                'css' => 'min-width:300px;',
                'options' => array(
                    0 => esc_html__('No', 'woocommerce-products-filter'),
                    1 => esc_html__('Yes', 'woocommerce-products-filter')
                ),
                'desc_tip' => true
            ),
            array(
                'name' => esc_html__('Hide woof top panel buttons', 'woocommerce-products-filter'),
                'desc' => esc_html__('Red buttons on the top of the shop page when searching done', 'woocommerce-products-filter'),
                'id' => 'woof_hide_red_top_panel',
                'type' => 'select',
                'class' => 'chosen_select',
                'css' => 'min-width:300px;',
                'options' => array(
                    0 => esc_html__('No', 'woocommerce-products-filter'),
                    1 => esc_html__('Yes', 'woocommerce-products-filter')
                ),
                'desc_tip' => true
            ),
            array(
                'name' => esc_html__('Lets checked terms will be on the top', 'woocommerce-products-filter'),
                'desc' => esc_html__('Selected terms will always be displayed on the top (for parent-terms only, child will be on the top but under parent-term as it was)', 'woocommerce-products-filter'),
                'id' => 'woof_sort_terms_checked',
                'type' => 'select',
                'class' => 'chosen_select',
                'css' => 'min-width:300px;',
                'options' => array(
                    0 => esc_html__('No', 'woocommerce-products-filter'),
                    1 => esc_html__('Yes', 'woocommerce-products-filter')
                ),
                'desc_tip' => true
            ),
            array(
                'name' => esc_html__('Filter button text', 'woocommerce-products-filter'),
                'desc' => esc_html__('Filter button text in the search form', 'woocommerce-products-filter'),
                'id' => 'woof_filter_btn_txt',
                'type' => 'text',
                'class' => 'text',
                'css' => 'min-width:300px;',
                'desc_tip' => true
            ),
            array(
                'name' => esc_html__('Reset button text', 'woocommerce-products-filter'),
                'desc' => esc_html__('Reset button text in the search form. Write "none" to hide this button on front.', 'woocommerce-products-filter'),
                'id' => 'woof_reset_btn_txt',
                'type' => 'text',
                'class' => 'text',
                'css' => 'min-width:300px;',
                'desc_tip' => true
            ),
            array('type' => 'sectionend', 'id' => 'woof_general_settings')
        );

        return apply_filters('wc_settings_tab_woof_settings', $options);
    }

    //for dynamic count
    //$type - none,single,multi
    public function dynamic_count($curr_term, $type, $additional_taxes = '', $meta_term = array(), $custom_type = "") {
        //global $wp_query;
        $request = $this->get_request_data();
        WOOF_REQUEST::set('woof_current_recount', $curr_term);
        $opposition_terms = array();
        global $wp_query;
        //+++
        if (!is_array($curr_term)) {
            $curr_term = array();
        }
        if (!isset($curr_term['taxonomy'])) {
            $curr_term['taxonomy'] = "";
        }
        //+++
        if (!empty($additional_taxes)) {
            $opposition_terms = $this->_expand_additional_taxes_string($additional_taxes);
        }
        if (!empty($opposition_terms)) {
            $tmp = array();
            foreach ($opposition_terms as $t) {
                $tmp[$t['taxonomy']] = $t['terms'];
            }
            $opposition_terms = $tmp;
            unset($tmp);
        }

        //***
        if ($this->is_really_current_term_exists()) {
            //we need this when for dynamic recount on taxonomy page
            $o = $this->get_really_current_term();
            $opposition_terms[$o->taxonomy] = array($o->slug);
        }
        //$opposition_terms - all terms from $additional_taxes or/and from really_current_term
        //it is always in opposition
        $in_query_terms = array(); //terms from request
        static $product_taxonomies = null;
        if (!$product_taxonomies) {
            $product_taxonomies = $this->get_taxonomies();
            $product_taxonomies = array_keys($product_taxonomies);
        }
        if (!empty($request) AND is_array($request)) {
            foreach ($request as $tax_slug => $terms_string) {
                $tax_slug_t = $this->uncheck_slug($tax_slug);
                if ($tax_slug_t != $tax_slug) {
                    $request[$tax_slug_t] = $terms_string;
                    unset($request[$tax_slug]);
                    $tax_slug = $tax_slug_t;
                }

                if (in_array($tax_slug, $product_taxonomies)) {
                    $in_query_terms[$tax_slug] = explode(',', $terms_string);
                }
            }
        }


        //$in_query_terms - terms we have in search query!!
        //***

        $term_is_in_query = false;
        if (empty($meta_term)) {
            if ($curr_term AND isset($in_query_terms[$curr_term['taxonomy']]) AND isset($curr_term['slug'])) {
                if (in_array($curr_term['slug'], $in_query_terms[$curr_term['taxonomy']])) {
                    $term_is_in_query = true;
                }
            }
        }

        //any way we not display count for the selected terms
        if ($term_is_in_query) {
            return 0;
        }

        //***

        $term_is_in_opposition = false;
        if (empty($meta_term)) {
            if ($curr_term AND isset($opposition_terms[$curr_term['taxonomy']])) {
                if (in_array($curr_term['slug'], $opposition_terms[$curr_term['taxonomy']])) {
                    $term_is_in_opposition = true;
                }
            }
        }
        //***

        $terms_to_query = array();
        if (empty($meta_term) AND empty($custom_type)) {
            $default_types = array('radio', 'select', 'price2', 'checkbox', 'mselect');
            //for extensions
            if (!in_array($type, $default_types)) {
                if (isset(WOOF_EXT::$includes['taxonomy_type_objects'][$type])) {
                    $obj = WOOF_EXT::$includes['taxonomy_type_objects'][$type];
                    $type = $obj->html_type_dynamic_recount_behavior;
                }
            }
            //***
            //price2 -> 'none' (default)
            //radio, select -> 'single'
            //checkbox, mselect -> 'multi'
            switch ($type) {
                case 'single':

                    if (isset($in_query_terms[$curr_term['taxonomy']])) {
                        $in_query_terms[$curr_term['taxonomy']] = array($curr_term['slug']);
                    } else {
                        $terms_to_query[$curr_term['taxonomy']] = array($curr_term['slug']);
                    }


                    break;

                case 'multi':

                    if (isset($in_query_terms[$curr_term['taxonomy']])) {
                        $in_query_terms[$curr_term['taxonomy']] = array($curr_term['slug']);
                    } else {
                        $terms_to_query[$curr_term['taxonomy']][] = $curr_term['slug'];
                    }


                    break;

                default:
                    //leave it empty
                    break;
            }
        }
        //***

        $taxonomies = array();
        if (!empty($opposition_terms)) {
            foreach ($opposition_terms as $tax_slug => $terms) {
                if (!empty($terms)) {
                    $taxonomies[] = array(
                        'taxonomy' => $tax_slug,
                        'terms' => $terms,
                        'field' => 'slug',
                        'operator' => 'IN',
                        'include_children' => true
                    );
                }
            }
        }


        if (!empty($in_query_terms)) {
            foreach ($in_query_terms as $tax_slug => $terms) {
                if (!empty($terms)) {
                    $logic_arr = array();
                    if (isset($this->settings['comparison_logic'])) {
                        $logic_arr = $this->settings['comparison_logic'];
                    }
                    if (isset($logic_arr[$tax_slug]) AND $logic_arr[$tax_slug] == "AND") {
                        $request = $this->get_request_data();
                        $terms_t = array();
                        if (isset($request[$tax_slug])) {
                            $terms_t = explode(",", $request[$tax_slug]);
                        }
                        $terms = array_merge($terms, $terms_t);
                        $taxonomies[] = array(
                            'taxonomy' => $tax_slug,
                            'terms' => $terms,
                            'field' => 'slug',
                            "operator" => "AND",
                            "include_children" => false
                        );
                    } elseif (isset($logic_arr[$tax_slug]) AND $logic_arr[$tax_slug] == "NOT IN" AND (!$curr_term OR $curr_term['taxonomy'] != $tax_slug)) {

                        $taxonomies[] = array(
                            'taxonomy' => $tax_slug,
                            'terms' => $terms,
                            'field' => 'slug',
                            "operator" => "NOT IN",
                            "include_children" => false
                        );
                    } else {
                        $taxonomies[] = array(
                            'taxonomy' => $tax_slug,
                            'terms' => $terms,
                            'field' => 'slug',
                            'operator' => 'IN',
                            'include_children' => 1
                        );
                    }
                }
            }
        }

        if (!empty($terms_to_query)) {
            foreach ($terms_to_query as $tax_slug => $terms) {
                if (!empty($terms)) {
                    $taxonomies[] = array(
                        'taxonomy' => $tax_slug,
                        'terms' => $terms,
                        'field' => 'slug',
                        'operator' => 'IN',
                        'include_children' => 1
                    );
                }
            }
        }

        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        if (!empty($taxonomies)) {
            $taxonomies['relation'] = 'AND';
        }
        //***
        $args = array(
            'nopaging' => true,
            'fields' => 'ids',
            'post_type' => 'product',
            'post_status' => 'publish'
        );

        $args['tax_query'] = $taxonomies;
        $args['meta_query'] = array();

        //check for price
        if ($this->is_isset_in_request_data('min_price') AND $this->is_isset_in_request_data('max_price')) {
            $this->assemble_price_params($args['meta_query']);
            $args['meta_query']['relation'] = 'AND';
        }

        //check for rating
        if ($this->is_isset_in_request_data('min_rating')) {
            $min = $request['min_rating'];
            if ($min == 4) {
                $max = 10;
            } else {
                $max = $min + 1 - 0.001;
            }
            $args['meta_query'][] = array(
                'key' => '_wc_average_rating',
                'value' => array($min, $max),
                'type' => 'DECIMAL',
                'compare' => 'BETWEEN'
            );
            $args['meta_query']['relation'] = 'AND';
        }
        //meta filter
        $args['meta_query'] = apply_filters('woof_get_meta_query', $args['meta_query']);
        if (!empty($meta_term) AND empty($custom_type)) {
            switch ($type) {
                case 'select':
                case 'mselect':
                    if (!isset($meta_term['relation'])) {
                        $meta_term['relation'] = "OR";
                    }

                    if ($meta_term['relation'] == "OR") {

                        WOOF_HELPER::recursiveRemoval($args['meta_query'], $meta_term['key']); //this is a more elegant solution
                    }

                    $args['meta_query'][] = array(
                        'key' => $meta_term['key'],
                        'value' => $meta_term['value'],
                        'compare' => '='
                    );
                    break;
                case 'checkbox_ex':
                    $args['meta_query'][] = $meta = array(
                        'key' => $meta_term['key'],
                        'compare' => 'EXISTS'
                    );
                    break;
                case 'checkbox':
                    $args['meta_query'][] = $meta = array(
                        'key' => $meta_term['key'],
                        'compare' => 'EXISTS'
                    );
                    break;
                case 'slider':
                    $args['meta_query'][] = $meta = array(
                        'key' => $meta_term['key'],
                        'value' => $meta_term['value'],
                        'type' => 'numeric',
                        'compare' => 'BETWEEN',
                    );
                    break;
                default:
                    //leave it empty
                    break;
            }
        }
        //WPML compatibility
        if (class_exists('SitePress')) {
            //$args['lang'] = ICL_LANGUAGE_CODE;
            $args['lang'] = apply_filters('wpml_current_language', NULL);
        }
        //***
        $atts = array();
        if (!isset($args['meta_query'])) {
            $args['meta_query'] = array();
        }
        //for extensions
        if (!empty(WOOF_EXT::$includes['html_type_objects'])) {
            foreach (WOOF_EXT::$includes['html_type_objects'] as $obj) {
                if (method_exists($obj, 'assemble_query_params')) {
                    $obj->assemble_query_params($args['meta_query'], $args);
                }
            }
        }

        //***
        WOOF_REQUEST::set('woof_dyn_recount_going', 1);
        remove_filter('posts_clauses', array(WC()->query, 'order_by_popularity_post_clauses'));
        remove_filter('posts_clauses', array(WC()->query, 'order_by_rating_post_clauses'));

        // fix visibility
        if (version_compare(WOOCOMMERCE_VERSION, '3.0', '>=')) {
            if ($this->get_option('listen_catalog_visibility')) {
                $args['tax_query'] = $this->product_visibility_not_in($args['tax_query'], $this->generate_visibility_keys(true));
            }
        } elseif (version_compare(WOOCOMMERCE_VERSION, '3.0', '<')) {
            if ($this->get_option('listen_catalog_visibility')) {
                $args['meta_query'][] = array(
                    'key' => '_visibility',
                    'value' => array('search', 'visible'),
                    'compare' => 'IN'
                );
            }
        }
        //***
        $args['wc_query'] = 'product_query'; //key to find this  query
        $args = apply_filters('woof_dynamic_count_attr', $args, $custom_type);
        $query = new WP_QueryWoofCounter($args);
        WOOF_REQUEST::del('woof_current_recount');
        WOOF_REQUEST::del('woof_dyn_recount_going');
        return $query->found_posts;
    }

    public function woocommerce_shortcode_products_query($query_args, $attr, $type = "") {
        if (WOOF_REQUEST::get('override_no_products')) {
            return $query_args;
        }
        if ($this->is_isset_in_request_data($this->get_swoof_search_slug())) {
            WOOF_REQUEST::set('woof_products_doing', 1);
            $query_args['tax_query'] = array_merge($query_args['tax_query'], $this->get_tax_query(''));
            $query_args['meta_query'] = array_merge($query_args['meta_query'], $this->get_meta_query());

            $tax_relations = apply_filters('woof_main_query_tax_relations', array());
            if (!empty($tax_relations)) {
                $tax_query = $query_args['tax_query'];
                foreach ($tax_query as $key => $value) {
                    if (isset($value['taxonomy'])) {
                        if (in_array($value['taxonomy'], array_keys($tax_relations))) {
                            if (count($tax_query[$key]['terms'])) {
                                $tax_query[$key]['operator'] = $tax_relations[$value['taxonomy']];
                                $tax_query[$key]['include_children'] = 0;
                            }
                        }
                    }
                }
                $query_args['tax_query'] = $tax_query;
            }

            $query_args = apply_filters('woof_products_query', $query_args);

            if (isset($_GET['paged'])) {
                $query_args['paged'] = intval($_GET['paged']);
            }
            // @codingStandardsIgnoreStart
            if (isset($_GET['orderby'])) {
                $ordering_args = WC()->query->get_catalog_ordering_args();
            } else {
                $ordering_args = WC()->query->get_catalog_ordering_args($query_args['orderby'], $query_args['order']);
            }
            $query_args['orderby'] = $ordering_args['orderby'];
            $query_args['order'] = $ordering_args['order'];
            if ($ordering_args['meta_key']) {
                $query_args['meta_key'] = $ordering_args['meta_key'];
            }
        }


        return $query_args;
    }

    //delete deprecated
    public function is_woof_use_chosen() {
        // $is = $this->get_option('use_chosen', 0);
        $is = false;
        $select_type = $this->get_option('select_design', false);
        $select_type_old = $this->get_option('use_chosen', 0);

        if (($select_type_old == 1 && !$select_type) || 'chosen' == $select_type) {
            $is = true;
        }

        $is = apply_filters('woof_use_chosen', $is);
        return $is;
    }

    public function get_select_type() {
        $select_type = $this->get_option('select_design', false);
        $select_type_old = $this->get_option('use_chosen', 0);
        if ($select_type_old == 1 && !$select_type) {
            $select_type = 'chosen';
        } elseif ($select_type_old == 0 && !$select_type) {
            $select_type = 'selectwoo';
        }
        return $select_type;
    }

    public function woocommerce_before_shop_loop() {

        $woof_set_automatically = 0;
        //for mobile devices
        $mobile_behavior = intval(get_option('woof_set_automatically', 0));
        if (($mobile_behavior == 1) OR ( $mobile_behavior == 2 AND wp_is_mobile()) OR ( $mobile_behavior == 3 AND!wp_is_mobile())) {
            $woof_set_automatically = 1;
        }

        if ($woof_set_automatically === 1 && !WOOF_REQUEST::isset('woof_before_shop_loop_done')) {
            //lock
            WOOF_REQUEST::set('woof_before_shop_loop_done', true);
            $shortcode_hide = false;
            if (isset($this->settings['woof_auto_hide_button'])) {
                $shortcode_hide = intval($this->settings['woof_auto_hide_button']);
            }

            $price_filter = 0;
            if (isset($this->settings['by_price']['show'])) {
                $price_filter = (int) $this->settings['by_price']['show'];
            }
            $shortcode_id = "auto_shortcode";
            if (isset($this->settings['woof_auto_filter_skins']) AND $this->settings['woof_auto_filter_skins']) {
                $shortcode_id = $this->settings['woof_auto_filter_skins'];
            }

            echo do_shortcode('[woof sid="' . esc_attr($shortcode_id) . '" autohide=' . esc_attr($shortcode_hide) . ' price_filter=' . esc_attr($price_filter) . ']');
        }
        ?>



        <?php
        // woo3.3
        $is_wc_shortcode = false;
        if (version_compare(WOOCOMMERCE_VERSION, '3.3', '>=')) {
            $is_wc_shortcode = wc_get_loop_prop('is_shortcode');
        }
        //++++
        //for ajax output
        if (get_option('woof_try_ajax', 0) && !WOOF_REQUEST::isset('woof_products_doing') && !$is_wc_shortcode) {
            echo '<div class="woocommerce woocommerce-page woof_shortcode_output">';
            $shortcode_txt = "woof_products is_ajax=1";
            if ($this->is_really_current_term_exists()) {
                $o = $this->get_really_current_term();
                $shortcode_txt = "woof_products taxonomies=" . $o->taxonomy . ":" . $o->term_id . " is_ajax=1 predict_ids_and_continue=1";
                WOOF_REQUEST::set('WOOF_IS_TAX_PAGE', $o->taxonomy);
            }
            echo '<div id="woof_results_by_ajax" data-shortcode="', wp_kses_post(wp_unslash($shortcode_txt)), '">';
        }

        if (get_option('woof_hide_red_top_panel', 0) == 0) {
            echo do_shortcode('[woof_search_options]');
        }
    }

    public function woocommerce_after_shop_loop() {
        // woo3.3
        $is_wc_shortcode = false;
        if (version_compare(WOOCOMMERCE_VERSION, '3.3', '>=')) {
            $is_wc_shortcode = wc_get_loop_prop('is_shortcode');
        }
        //for ajax output
        if (get_option('woof_try_ajax', 0) && !WOOF_REQUEST::isset('woof_products_doing') && !$is_wc_shortcode) {// woo3.3
            echo '</div>';
            echo '</div>';
        }
    }

    public function get_request_data($apply_filters = true) {

        $data = WOOF_HELPER::sanitize_array($_GET);
        // fix for special simbols
        $woof_text_urlencode = apply_filters('woof_text_urlencode', 0);
        if (isset($data['gclid'])) {
            //google tracking id removing from search link
            unset($data['gclid']);
        }

        //secure data filtrating
        if (!empty($data) AND is_array($data)) {
            $tmp = array();
            foreach ($data as $key => $value) {
                if (!is_string($key) OR!is_string($value)) {
                    continue;
                }
                if ($woof_text_urlencode) {
                    $tmp[WOOF_HELPER::escape($key)] = urlencode(WOOF_HELPER::escape($value));
                } else {
                    $tmp[WOOF_HELPER::escape($key)] = WOOF_HELPER::escape($value);
                }
            }
            $data = $tmp;
        }


        if ($apply_filters) {
            $data = apply_filters('woof_get_request_data', $data);
        }

        return $data;
    }

    public function is_isset_in_request_data($key, $apply_filters = true) {
        $request = $this->get_request_data($apply_filters);
        return isset($request[$key]);
    }

    public function get_catalog_orderby($orderby = '', $order = 'ASC') {
        if (empty($orderby) OR $orderby == 'no') {
            $orderby = get_option('woocommerce_default_catalog_orderby');
        }

        //wp-content\plugins\woocommerce\includes\class-wc-query.php#588
        //$orderby_array = array('menu_order', 'popularity', 'rating',
        //'date', 'price', 'price-desc','rand');
        $meta_key = '';
        global $wpdb;
        switch ($orderby) {
            case 'price-desc':
                $orderby = "meta_value_num {$wpdb->posts}.ID";
                $order = 'DESC';
                $meta_key = '_price';
                break;
            case 'price':
                $orderby = "meta_value_num {$wpdb->posts}.ID";
                $order = 'ASC';
                $meta_key = '_price';
                break;
            case 'popularity' :
                // Sorting handled later though a hook
                add_filter('posts_clauses', array(WC()->query, 'order_by_popularity_post_clauses'));
                $meta_key = 'total_sales';
                break;
            case 'rating' :
                $orderby = "meta_value_num {$wpdb->posts}.ID";
                $order = 'DESC';
                $meta_key = '_wc_average_rating';
                break;
            case 'title' :
                $orderby = 'title';
                break;
            case 'title-desc':
                $orderby = "title";
                $order = 'DESC';
                break;
            case 'title-asc':
                $orderby = "title";
                $order = 'ASC';
                break;
            case 'rand' :
                $orderby = 'rand';
                break;
            case 'date' :
                $order = 'DESC';
                $orderby = 'date';
                break;
            default:
                $orderby = 'menu_order title';
                break;
        }

        return apply_filters('woof_order_catalog', compact('order', 'orderby', 'meta_key'));
    }

    public function get_tax_query($additional_taxes = '') {
        $data = $this->get_request_data();
        $res = array();

        $woo_taxonomies = NULL; {
            $woo_taxonomies = get_object_taxonomies('product');
        }

        //+++

        if (!empty($data) AND is_array($data)) {
            foreach ($data as $tax_slug => $value) {
                if (in_array($tax_slug, $woo_taxonomies)) {
                    $value = explode(',', $value);
                    $res[] = array(
                        'taxonomy' => $tax_slug,
                        'field' => 'slug',
                        'terms' => $value,
                    );
                }
            }
        }
        //+++
        //for shortcode
        //[woof_products is_ajax=1 per_page=8 taxonomies=product_cat:9,12+locations:30,31]
        $res = $this->_expand_additional_taxes_string($additional_taxes, $res);
        //+++
        if (!empty($res)) {
            $res = array_merge(array('relation' => 'AND'), $res);
        }

        $res = $this->parse_tax_query($res);

        //woof_get_tax_query works in ajax mode if describe in themes functions.php
        return apply_filters('woof_get_tax_query', $res);
    }

    private function _expand_additional_taxes_string($additional_taxes, $res = array()) {
        if (!empty($additional_taxes)) {
            $t = explode('+', $additional_taxes);
            if (!empty($t) AND is_array($t)) {
                foreach ($t as $string) {
                    $tmp = explode(':', $string);
                    $tax_slug = $tmp[0];
                    $tax_terms = explode(',', $tmp[1]);
                    $slugs = array();
                    foreach ($tax_terms as $term_id) {
                        $term = get_term(intval($term_id), $tax_slug);
                        if (is_object($term) AND!is_wp_error($term)) {
                            $slugs[] = $term->slug;
                        }
                    }

                    //***
                    if (!empty($slugs)) {
                        $res[] = array(
                            'taxonomy' => $tax_slug,
                            'field' => 'slug', //id
                            'terms' => $slugs
                        );
                    }
                }
            }
        }

        return $res;
    }

    private function listen_catalog_visibility($meta_query, $is_search = false) {
        if ($this->get_option('listen_catalog_visibility')) {
            //if search is going
            if ($this->is_isset_in_request_data($this->get_swoof_search_slug())) {
                if (!empty($meta_query)) {
                    foreach ($meta_query as $key => $value) {
                        if (isset($value['key'])) {
                            if ($value['key'] == '_visibility') {
                                unset($meta_query[$key]);
                                $meta_query = array_values($meta_query);
                                break;
                            }
                        }
                        if (version_compare(WOOCOMMERCE_VERSION, '3.0', '>=')) {
                            if (isset($value['taxonomy'])) {
                                if ($value['taxonomy'] == 'product_visibility') {
                                    unset($meta_query[$key]);
                                    $meta_query = array_values($meta_query);
                                    break;
                                }
                            }
                        }
                    }
                }

                if ($is_search) {
                    global $wp_query;
                    $wp_query->is_search = true;
                }
                if (version_compare(WOOCOMMERCE_VERSION, '3.0', '>=')) {
                    
                } elseif (version_compare(WOOCOMMERCE_VERSION, '3.0', '<')) {
                    $meta_query[] = array(
                        'key' => '_visibility',
                        'value' => array('search', 'visible'),
                        'compare' => 'IN'
                    );
                }
            }
        }

        return $meta_query;
    }

    //works only in shortcode [woof_products]
    public function get_meta_query($args = array()) {
        //print_r(WC()->query); - will think about it
        $meta_query = WC()->query->get_meta_query();
        $meta_query = array_merge(array('relation' => 'AND'), $meta_query);
        //+++
        $this->assemble_price_params($meta_query);
        //for extensions
        if (!empty(WOOF_EXT::$includes['html_type_objects'])) {
            foreach (WOOF_EXT::$includes['html_type_objects'] as $obj) {
                if (method_exists($obj, 'assemble_query_params')) {
                    $obj->assemble_query_params($meta_query);
                }
            }
        }
        // fix visibility
        if (version_compare(WOOCOMMERCE_VERSION, '3.0', '<')) {
            $meta_query = $this->listen_catalog_visibility($meta_query);
        }
        // end fix
        // For meta filter
        $meta_query = apply_filters('woof_get_meta_query', $meta_query);
        return $meta_query;
    }

    public function woof_products_ids_prediction($atts) {
        return $this->woof_products($atts, true);
    }

    //plugins\woocommerce\includes\class-wc-shortcodes.php#295
    //[woof_products is_ajax=1 per_page=8 taxonomies=product_cat:9,12+locations:30,31]
    public function woof_products($atts, $is_prediction = false) {
        WOOF_REQUEST::set('woof_products_doing', 1);
        $shortcode_txt = 'woof_products';
        if (!empty($atts) AND is_array($atts)) {
            foreach ($atts as $key => $value) {
                $shortcode_txt .= ' ' . $key . '=' . $value;
            }
        }
        //***
        $data = $this->get_request_data();
        $catalog_orderby = $this->get_catalog_orderby(isset($data['orderby']) ? $data['orderby'] : '');

        //https://gist.github.com/mikejolley/1622323
        extract(shortcode_atts(array(
            'columns' => apply_filters('loop_shop_columns', 4),
            'orderby' => 'no',
            'order' => 'no',
            'page' => 1,
            'per_page' => 0,
            'is_ajax' => 0,
            'taxonomies' => '',
            'sid' => '',
            'behavior' => '', //recent
            'custom_tpl' => '', //path like: wp-content/themes/my_theme/woo_tpl_1.php
            'tpl_index' => '', //index of any template extension
            'predict_ids_and_continue' => false,
            'get_args_only' => false,
            'shortcode' => '',
            'product_ids' => "",
            'post__in' => "",
            'display_on_search' => 0,
                        ), $atts));

        $order_by_defined_in_atts = false;
        if ($orderby == 'no') {
            $orderby = $catalog_orderby['orderby'];
            $order = $catalog_orderby['order'];
        } elseif ($orderby == 'price' OR $orderby == 'price-desc') {
            $catalog_orderby = $this->get_catalog_orderby(isset($orderby) ? $orderby : '');
        } else {
            $order_by_defined_in_atts = true;
        }

        //***
        //this needs just for AJAX mode for shortcode [woof] in woof_draw_products()
        WOOF_REQUEST::set('woof_additional_taxonomies_string', $taxonomies);

        // fix visibility
        $tax_query = array();
        if (empty($product_ids)) {
            $tax_query = $this->get_tax_query($taxonomies);
        }

        if (version_compare(WOOCOMMERCE_VERSION, '3.0', '>=') AND version_compare(WOOCOMMERCE_VERSION, '3.3', '<')) {
            $tax_query = $this->listen_catalog_visibility($tax_query);
        } elseif (version_compare(WOOCOMMERCE_VERSION, '3.3', '>=')) {         // woo3.3
            $search = false;
            if ($this->is_isset_in_request_data($this->get_swoof_search_slug()) && count($data) > 1) {
                $search = true;
            }

            $tax_query = $this->product_visibility_not_in($tax_query, $this->generate_visibility_keys($search));
        }
        //+++
        //+++

        $args = array(
            'post_type' => array('product'/* ,'product_variation' */),
            'post_status' => 'publish',
            'orderby' => $orderby,
            'order' => $order,
            'tax_query' => $tax_query,
            'wc_query' => 'product_query'//key to find this  query
        );
        if (empty($product_ids)) {
            $args['meta_query'] = $this->get_meta_query();
            if ($post__in) {
                $args['post__in'] = explode(",", $post__in);
            }
        } else {
            $args['post__in'] = explode(",", $product_ids);
        }

        if ($per_page > 0) {
            $args['posts_per_page'] = $per_page;
        } else {
            if (intval($this->settings['per_page']) > 0) {
                $args['posts_per_page'] = intval($this->settings['per_page']);
            }

            //compatibility for woocommerce-products-per-page
            if (class_exists('Woocommerce_Products_Per_Page')) {
                $args['posts_per_page'] = $this->get_wppp_per_page();
            }
        }

        //Display Product for WooCommerce compatibility
        if (WOOF_REQUEST::isset('perpage')) {
            $args['posts_per_page'] = intval(WOOF_REQUEST::get('perpage'));
        }

        //if smth wrong, set default per page option
        if (!isset($args['posts_per_page']) OR empty($args['posts_per_page'])) {
            if ($this->get_option('per_page') > 0) {
                $args['posts_per_page'] = $this->get_option('per_page');
            } else {
                $args['posts_per_page'] = get_option('posts_per_page');
            }
        }

        //***
        if (!$order_by_defined_in_atts) {
            if (!empty($catalog_orderby['meta_key'])) {
                $args['meta_key'] = $catalog_orderby['meta_key'];
                $args['orderby'] = $catalog_orderby['orderby'];
                if (!empty($catalog_orderby['order'])) {
                    $args['order'] = $catalog_orderby['order'];
                }
            } else {
                $args['orderby'] = $catalog_orderby['orderby'];
                if (!empty($catalog_orderby['order'])) {
                    $args['order'] = $catalog_orderby['order'];
                }
            }
        }
        //print_r($args);
        //+++
        $pp = $page;
        if (get_query_var('page')) {
            $pp = get_query_var('page');
        }
        if (get_query_var('paged')) {
            $pp = get_query_var('paged');
        }

        if ($pp > 1) {
            $args['paged'] = $pp;
        } else {
            $args['paged'] = ((get_query_var('page')) ? get_query_var('page') : $page);
        }
        //+++

        if (!empty($behavior)) {
            switch ($behavior) {
                case 'recent':
                    $args['orderby'] = 'date';
                    $args['order'] = 'desc';
                    break;

                default:
                    break;
            }
        }
        //***
        $wr = $args;

        global $products, $wp_query;
        //***
        $tax_relations = apply_filters('woof_main_query_tax_relations', array());
        if (!empty($tax_relations)) {
            $tax_query = $wr['tax_query'];
            foreach ($tax_query as $key => $value) {
                if (isset($value['taxonomy'])) {
                    if (in_array($value['taxonomy'], array_keys($tax_relations))) {
                        if (count($tax_query[$key]['terms'])) {
                            $tax_query[$key]['operator'] = $tax_relations[$value['taxonomy']];
                            $tax_query[$key]['include_children'] = 0;
                        }
                    }
                }
            }

            $wr['tax_query'] = $tax_query;
        }
        //***

        $wr = apply_filters('woof_products_query', $wr);

        //***

        if ($get_args_only) {
            WOOF_REQUEST::set('woof_query_args', $wr);
            return $wr;
        }
        $hide_products = false;
        if ($display_on_search) {
            $hide_products = true;
            $get_array = $this->get_request_data();
            //var_dump($real_query);
            if (isset($this->settings['items_order'])) {
                $key_array = explode(',', $this->settings['items_order']);
                $by_only_array = array('woof_text', 'stock', 'onsales', 'woof_sku', 'product_visibility', 'min_price', 'max_price');
                $tax_array = array_keys($this->settings['excluded_terms']);
                $key_array = array_merge($by_only_array, $key_array, $tax_array);
                $real_query = array_intersect(array_keys($get_array), $key_array);
                if (count($real_query)) {
                    $hide_products = false;
                }
                //var_dump($key_array);
                if (isset($this->settings['meta_filter'])) {
                    if (!is_array($this->settings['meta_filter'])) {
                        $this->settings['meta_filter'] = array();
                    }
                    foreach ($this->settings['meta_filter'] as $item) {
                        $key = $item['search_view'] . "_" . $item['meta_key'];
                        if (in_array($key, array_keys($get_array))) {
                            $hide_products = false;
                        }
                    }
                }
            }
        }

        if (!$is_prediction) {
            $wp_query = $products = new WP_Query($wr);
            WOOF_REQUEST::set('woof_wp_query', $wp_query);
            WOOF_REQUEST::set('woof_wp_query_found_posts', $wp_query->found_posts);

            if ($predict_ids_and_continue) {
                WOOF_REQUEST::set('predict_ids_and_continue', 1);
                WOOF_REQUEST::set('woof_wp_query_ids', new WP_Query(array_merge($wr, array('fields' => 'ids'))));
                WOOF_REQUEST::set('woof_wp_query_ids', WOOF_REQUEST::get('woof_wp_query_ids')->posts);
            }
        } else {
            WOOF_REQUEST::set('woof_wp_query_ids', new WP_Query(array_merge($wr, array('fields' => 'ids'))));
            WOOF_REQUEST::set('woof_wp_query_ids', WOOF_REQUEST::get('woof_wp_query_ids')->posts);
            return;
        }


        if ($this->get_option('listen_catalog_visibility')
                AND $this->is_isset_in_request_data($this->get_swoof_search_slug())) {
            //for wp-content\plugins\woocommerce\includes\class-wc-query.php -> $in = array( 'visible', 'search' )
            $wp_query->is_search = true;
        }

        $wp_query->is_post_type_archive = true; //we need it to display top panel with counter and order drop-down
        WOOF_REQUEST::set('woof_wp_query_args', $wr);
        //***
        ob_start();
        global $woocommerce_loop;
        $woocommerce_loop['columns'] = $columns;
        $woocommerce_loop['loop'] = 0;
        // woo3.3
        if (version_compare(WOOCOMMERCE_VERSION, '3.3', '>=')) {
            $this->set_loop_properties($products, $columns);
        }
        ?>

        <?php if ($is_ajax == 1): ?>
            <?php ?>
            <div id="woof_results_by_ajax" data-count="<?php echo intval($products->found_posts) ?>"  class="woof_results_by_ajax_shortcode" data-shortcode="<?php esc_attr_e($shortcode_txt) ?>">
                <?php
                //endif;
                //ajax compatibility
                WOOF_REQUEST::set('woof_redraw_elements', []);
                if (isset($this->settings['result_count_redraw']) AND $this->settings['result_count_redraw']) {
                    ob_start();
                    woocommerce_result_count();
                    WOOF_REQUEST::push('woof_redraw_elements', ob_get_contents(), $this->settings['result_count_redraw']);
                    ob_end_clean();
                }
                if (isset($this->settings['order_dropdown_redraw']) AND $this->settings['order_dropdown_redraw']) {
                    ob_start();
                    woocommerce_catalog_ordering();

                    WOOF_REQUEST::push('woof_redraw_elements', ob_get_contents(), $this->settings['order_dropdown_redraw']);

                    ob_end_clean();
                }
                if (isset($this->settings['per_page_redraw']) AND $this->settings['per_page_redraw']) {
                    ob_start();
                    woocommerce_pagination();

                    WOOF_REQUEST::push('woof_redraw_elements', ob_get_contents(), $this->settings['per_page_redraw']);

                    ob_end_clean();
                }
                WOOF_REQUEST::set('woof_redraw_elements', apply_filters('woof_redraw_elements_after_ajax', WOOF_REQUEST::get('woof_redraw_elements'), $products));
                //+++
                ?>
            <?php endif; ?>
            <?php
            if ($products->have_posts()) :
                add_filter('post_class', array($this, 'woo_post_class'));
                WOOF_REQUEST::set('woof_before_shop_loop_done', true);
                ?>

                <div class="woocommerce columns-<?php esc_attr_e($columns) ?> woocommerce-page woof_shortcode_output">

                    <?php
                    $show_loop_filters = true; //for attribute behavior of the shortcode
                    if (!empty($behavior)) {
                        if ($behavior == 'recent') {
                            $show_loop_filters = false;
                        }
                    }
                    // elementor  compatybility
                    if (isset($_GET['action']) AND $_GET['action'] == 'elementor') {
                        $show_loop_filters = false;
                    }
                    if (!$hide_products) {
                        if ($show_loop_filters) {
                            do_action('woocommerce_before_shop_loop');
                        }

                        //***



                        if (function_exists('woocommerce_product_loop_start')) {
                            woocommerce_product_loop_start();
                        }
                        ?>

                        <?php
                        global $woocommerce_loop;
                        $woocommerce_loop['columns'] = $columns;
                        $woocommerce_loop['loop'] = 0;

                        //+++
                        //wc_get_template('loop/loop-start.php');
                        ?>

                        <?php
                        $template_part = apply_filters('woof_template_part', 'product');
                        //products output
                        if (empty($custom_tpl) AND empty($tpl_index)) {
                            while ($products->have_posts()) : $products->the_post();
                                wc_get_template_part('content', $template_part);
                            endwhile; // end of the loop.
                        } else {
                            if (!empty($tpl_index)) {
                                //template extension drawing
                                if (isset(WOOF_EXT::$includes['applications'][$tpl_index])) {
                                    WOOF_EXT::$includes['applications'][$tpl_index]->draw($products);
                                }
                            } else {
                                $custom_tpl = str_replace('.' . pathinfo($custom_tpl, PATHINFO_EXTENSION), '', str_replace("..", "", $custom_tpl));
                                $this->render_html_e(get_theme_file_path($custom_tpl . ".php"), array(
                                    'the_products' => $products
                                ));
                            }
                        }
                        ?>

                        <?php //wc_get_template('loop/loop-end.php');                                                                          ?>

                        <?php
                        //woo_pagenav(); - for wp theme canvas
                        if (function_exists('woocommerce_product_loop_end')) {
                            woocommerce_product_loop_end();
                        }
                        ?>

                        <?php
                        if ($show_loop_filters) {
                            do_action('woocommerce_after_shop_loop');
                        }
                    }
                    ?>
                </div>


                <?php
            else:
                if ($is_ajax == 1) { {
                        ?>
                        <div id="woof_results_by_ajax" class="woof_results_by_ajax_shortcode" data-shortcode="<?php esc_attr_e($shortcode_txt) ?>">
                            <?php
                        }
                    }
                    ?>
                    <div class="woocommerce woocommerce-page woof_shortcode_output">

                        <?php
                        if (!$is_ajax) {
                            wc_get_template('loop/no-products-found.php');
                        } else {
                            ?>
                            <div id="woof_results_by_ajax" class="woof_results_by_ajax_shortcode" data-shortcode="<?php esc_attr_e($shortcode_txt) ?>">
                                <?php
                                wc_get_template('loop/no-products-found.php');
                                ?>
                            </div>
                            <?php
                        }
                        ?>

                    </div>
                    <?php
                    if ($is_ajax == 1) {
                        if (!get_option('woof_try_ajax', 0)) {
                            echo '</div>';
                        }
                    }

                endif;
                ?>

                <?php if ($is_ajax == 1): ?>
                    <?php if (!get_option('woof_try_ajax', 0)): ?>
                    </div>

                <?php endif; ?>
            <?php endif; ?>
            <?php
            wp_reset_postdata();
            wp_reset_query();
            // woo3.3
            if (version_compare(WOOCOMMERCE_VERSION, '3.3', '>=')) {
                wc_reset_loop();
            }
            //+++

            WOOF_REQUEST::del('woof_products_doing');

            return ob_get_clean();
        }

        //for shortcode woof_products
        public function woo_post_class($classes) {
            global $post;
            $classes[] = 'product';
            $classes[] = 'type-product';
            $classes[] = 'status-publish';
            $classes[] = 'has-post-thumbnail';
            $classes[] = 'post-' . $post->ID;
            return $classes;
        }

        //shortcode, works when ajax mode only for shop/category page
        public function woof_draw_products() {
            if (WOOF_REQUEST::isset('link')) {
                $link = parse_url(WOOF_REQUEST::get('link'), PHP_URL_QUERY);
                $query_array = WOOF_HELPER::safe_parse_str($link);
                $_GET = apply_filters('woof_draw_products_get_args', wc_clean(array_merge($query_array, wc_clean($_GET))), WOOF_REQUEST::get('link'));
            }

            $product_ids = "";
            if (WOOF_REQUEST::isset('turbo_mode_ids')) {
                $product_ids = " product_ids='" . sanitize_text_field(WOOF_REQUEST::get('turbo_mode_ids')) . "' ";
            }

            $shortcode_str = $this->check_shortcode("woof_products", "[" . WOOF_REQUEST::get('shortcode') . " page=" . WOOF_REQUEST::get('page') . $product_ids . "]");
            $products = do_shortcode($shortcode_str);
            $additional_fields = array();

            if (WOOF_REQUEST::get('woof_redraw_elements')) {
                $additional_fields = WOOF_HELPER::sanitize_html_fields_array(WOOF_REQUEST::get('woof_redraw_elements'));
            }

            if (isset($_GET["woof_redraw_elements"]) AND $_GET["woof_redraw_elements"]) {
                $additional_fields = array_merge($additional_fields, WOOF_HELPER::sanitize_html_fields_array($_GET['woof_redraw_elements']));
            }

            //+++
            $form = '';
            if (WOOF_REQUEST::isset('woof_shortcode')) {//if search form on the page exists
                $text = "";
                $shortcode_str = "";
                $woof_shortcode_str = wp_kses_post(wp_unslash(WOOF_REQUEST::get('woof_shortcode')));

                if (empty(WOOF_REQUEST::get('woof_additional_taxonomies_string'))) {
                    $text = "[" . stripslashes($woof_shortcode_str) . "]";
                } else {
                    $taxonomies_str = sanitize_text_field(WOOF_REQUEST::get('woof_additional_taxonomies_string'));
                    $text = "[" . stripslashes($woof_shortcode_str . " taxonomies={$taxonomies_str}]");
                }
                $shortcode_str = $this->check_shortcode("woof", $text);
                //for data-shortcode in woof.php in ajax mode
                if (!empty($shortcode_str)) {
                    WOOF_REQUEST::set('woof_shortcode_txt', $woof_shortcode_str);
                }
                //***
                $form = trim(do_shortcode($shortcode_str));
            }


            wp_die(json_encode(compact('products', 'form', 'additional_fields')));
        }

        public function show_btn($atts) {
            $args = $atts;

            return $this->render_html(WOOF_PATH . 'views/shortcodes/woof_show_btn.php', $args);
        }

        public function show_mobile_btn($atts) {
            $args = $atts;
            if (wp_is_mobile()) {
                return $this->render_html(WOOF_PATH . 'views/shortcodes/woof_mobile_btn.php', $args);
            }


            return "";
        }

        public function woof_shortcode($atts) {
            $args = array();
            //this for synhronizating shortcode woof_products if its has attribute taxonomies

            if (isset($atts['taxonomies'])) {
                $args['additional_taxes'] = apply_filters('woof_set_shortcode_taxonomyattr_behaviour', $atts['taxonomies']);
            } else {
                $args['additional_taxes'] = '';
            }

            //by hands excluded terms directly in [woof] shortcode
            WOOF_REQUEST::del('woof_shortcode_excluded_terms');
            if (isset($atts['excluded_terms'])) {
                WOOF_REQUEST::set('woof_shortcode_excluded_terms', $atts['excluded_terms']);
            }

            if (isset($atts['mobile_mode'])) {
                $args['mobile_mode'] = $atts['mobile_mode'];
            }

            //+++
            $taxonomies = $this->get_taxonomies();
            $allow_taxonomies = (array) (isset($this->settings['tax']) ? $this->settings['tax'] : array());
            $args['taxonomies'] = array();
            $hide_empty = (bool) get_option('woof_hide_dynamic_empty_pos', 0);
            if (!empty($taxonomies)) {
                foreach ($taxonomies as $tax_key => $tax) {
                    if (!in_array($tax_key, array_keys($allow_taxonomies))) {
                        continue;
                    }
                    //+++

                    $args['taxonomies_info'][$tax_key] = $tax;
                    $args['taxonomies'][$tax_key] = WOOF_HELPER::get_terms($tax_key, $hide_empty);
                    //show only subcategories if is_really_current_term_exists
                    if ($this->is_really_current_term_exists()) {
                        $t = $this->get_really_current_term();
                        if ($tax_key == $t->taxonomy) {
                            if (isset($args['taxonomies'][$tax_key][$t->term_id])) {
                                $args['taxonomies'][$tax_key] = $args['taxonomies'][$tax_key][$t->term_id]['childs'];
                            } else {
                                if ($t->parent != 0) {
                                    $parent = get_term($t->parent, $tax_key);
                                    $parents_ids = array();
                                    $parents_ids[] = $parent->term_id;
                                    while ($parent->parent != 0) {
                                        $parent = get_term_by('id', $parent->parent, $tax_key);
                                        $parents_ids[] = $parent->term_id;
                                    }
                                    $parents_ids = array_reverse($parents_ids);
                                    //***
                                    $tmp = $args['taxonomies'][$tax_key];
                                    foreach ($parents_ids as $id) {
                                        $tmp = $tmp[$id]['childs'];
                                    }
                                    if (isset($tmp[$t->term_id])) {
                                        $args['taxonomies'][$tax_key] = $tmp[$t->term_id]['childs'];
                                    }
                                }
                            }
                        }
                    }
                }
            } else {
                $args['taxonomies'] = array();
            }
            //***
            if (isset($atts['skin'])) {
                wp_enqueue_style('woof_skin_' . $atts['skin'], WOOF_LINK . 'css/shortcode_skins/' . $atts['skin'] . '.css', array(), WOOF_VERSION);
            }
            //***

            if (isset($atts['sid'])) {
                $args['sid'] = $atts['sid'];
                wp_enqueue_script('woof_sid', WOOF_LINK . 'js/woof_sid.js', array('jquery'), WOOF_VERSION);
            }


            if (isset($atts['autohide'])) {
                $args['autohide'] = $atts['autohide'];
            } else {
                $args['autohide'] = 0;
            }

            if (isset($atts['redirect'])) {
                $args['redirect'] = $atts['redirect'];
            } else {
                $args['redirect'] = '';
            }

            if (isset($atts['start_filtering_btn'])) {
                $args['start_filtering_btn'] = $atts['start_filtering_btn'];
            } else {
                $args['start_filtering_btn'] = 0;
            }

            if (isset($atts['start_filtering_btn_txt'])) {
                $args['woof_start_filtering_btn_txt'] = $atts['start_filtering_btn_txt'];
            } else {
                $args['woof_start_filtering_btn_txt'] = apply_filters('woof_start_filtering_btn_txt', esc_html__('Show products filter form', 'woocommerce-products-filter'));
            }


            if (isset($atts['tax_only'])) {
                $args['tax_only'] = explode(',', $atts['tax_only']);
                $args['tax_only'] = array_map('trim', $args['tax_only']);
            } else {
                $args['tax_only'] = array();
            }

            if (isset($atts['tax_exclude'])) {
                $args['tax_exclude'] = explode(',', $atts['tax_exclude']);
                $args['tax_exclude'] = array_map('trim', $args['tax_exclude']);
            } else {
                $args['tax_exclude'] = array();
            }

            if (isset($atts['by_only'])) {
                $args['by_only'] = explode(',', $atts['by_only']);
                $args['by_only'] = array_map('trim', $args['by_only']);
            } else {
                $args['by_only'] = array();
            }


            if (isset($atts['autosubmit']) AND $atts['autosubmit'] != -1) {
                $args['autosubmit'] = $atts['autosubmit'];
            } else {
                $args['autosubmit'] = get_option('woof_autosubmit', 0);
            }


            WOOF_REQUEST::set('hide_terms_count_txt_short', -1);
            if (isset($atts['hide_terms_count'])) {
                WOOF_REQUEST::set('hide_terms_count_txt_short', intval($atts['hide_terms_count']));
            }

            if (isset($atts['ajax_redraw'])) {
                $args['ajax_redraw'] = $atts['ajax_redraw'];
            } else {
                $args['ajax_redraw'] = 0;
            }
            if (isset($atts['btn_position'])) {
                $args['btn_position'] = $atts['btn_position'];
            } else {
                $args['btn_position'] = 'b';
            }
            if (isset($atts['dynamic_recount'])) {
                $args['dynamic_recount'] = $atts['dynamic_recount'];
            } else {
                $args['dynamic_recount'] = -1;
            }

            $args['price_filter'] = 0;
            if (isset($this->settings['by_price']['show'])) {
                $args['price_filter'] = (int) $this->settings['by_price']['show'];
            }

            if (isset($atts['by_step'])) {
                $args['by_step'] = $atts['by_step'];
            }

            //***
            $args['show_woof_edit_view'] = 0;
            if (current_user_can('create_users')) {
                $args['show_woof_edit_view'] = isset($this->settings['show_woof_edit_view']) ? (int) $this->settings['show_woof_edit_view'] : 0;
            }




            //lets assemble shortcode txt for ajax mode for data-shortcode in woof.php
            WOOF_REQUEST::set('woof_shortcode_txt', 'woof ');
            if (!empty($atts)) {
                foreach ($atts as $key => $value) {
                    if (($key == 'tax_only' OR $key == 'by_only' OR $key == 'tax_exclude') AND empty($value)) {
                        continue;
                    }

                    WOOF_REQUEST::set('woof_shortcode_txt', WOOF_REQUEST::get('woof_shortcode_txt') . $key . "='" . (is_array($value) ? explode(',', $value) : $value) . "' ");
                }
            }
            $args['woof_settings'] = get_option('woof_settings', array());

            $args['shortcode_atts'] = $atts;
            return $this->render_html(WOOF_PATH . 'views/woof.php', apply_filters('woof_filter_shortcode_args', $args));
        }

        //shortcode
        public function woof_price_filter($args = array()) {
            $type = 'slider';
            if (isset($args['type']) AND $args['type'] == 'select') {
                $type = 'select';
            }
            if (isset($args['type']) AND $args['type'] == 'text') {
                $type = 'text';
            }
            if (isset($args['type']) AND $args['type'] == 'radio') {
                $type = 'radio';
            }
            if (!isset($args['range_min'])) {
                $args['range_min'] = null;
            }
            if (!isset($args['range_max'])) {
                $args['range_max'] = null;
            }
            return $this->render_html(WOOF_PATH . 'views/shortcodes/woof_price_filter_' . $type . '.php', $args);
        }

        //shortcode
        public function woof_search_options($args = array()) {
            return $this->render_html(WOOF_PATH . 'views/shortcodes/woof_search_options.php', array());
        }

        //shortcode
        public function woof_found_count($args = array()) {
            return $this->render_html(WOOF_PATH . 'views/shortcodes/woof_found_count.php', array());
        }

        //redraw search form
        public function woof_redraw_woof() {
            $shortcode = sanitize_text_field(WOOF_REQUEST::get('shortcode'));
            WOOF_REQUEST::set('woof_shortcode_txt', $shortcode);
            $shortcode_str = $this->check_shortcode("woof", "[" . $shortcode . "]");
            wp_die(do_shortcode($shortcode_str));
        }

        public function woocommerce_pagination_args($args) {
            return $args;
        }

        //if we are on the category products page, or any another product taxonomy page
        public function get_really_current_term() {
            $res = NULL;
            $key = $this->session_rct_key;
            $request = $this->get_request_data(FALSE);

            if ($this->storage->is_isset($key)) {
                $res = $this->storage->get_val($key);
            }

            if (!$res) {
                if (isset($request['really_curr_tax'])) {
                    $tmp = explode('-', $request['really_curr_tax']);
                    if (isset($tmp[1])) {
                        $res = get_term($tmp[0], $tmp[1]);
                    }
                }
            }


            return $res;
        }

        public function is_really_current_term_exists() {
            return (bool) $this->get_really_current_term();
        }

        //we need it when making search on the category page == any taxonomy term page
        private function set_really_current_term($queried_obj = NULL) {
            if (defined('DOING_AJAX')) {
                return false;
            }


            $request = $this->get_request_data();
            if (!$queried_obj) {
                if (isset($request['really_curr_tax'])) {
                    return false;
                }
            }

            $key = $this->session_rct_key;

            if ($queried_obj === NULL) {
                $this->storage->unset_val($key);
            } else {
                $this->storage->set_val($key, $queried_obj);
            }

            return $queried_obj;
        }

        //ajax + wp_cron
        public function cache_count_data_clear() {
            global $wpdb;
            $wpdb->query("TRUNCATE TABLE " . self::$query_cache_table);
        }

        //ajax only
        public function woof_cache_terms_clear() {
            global $wpdb;
            $res = $wpdb->get_results("SELECT * FROM {$wpdb->options} WHERE option_name LIKE '_transient_woof_terms_cache_%'");

            if (!empty($res)) {
                foreach ($res as $transient) {
                    delete_transient(str_replace('_transient_', '', $transient->option_name));
                }
            }

            //wp_die('done');
        }

        public function woof_price_transient_clear() {
            delete_transient('woof_min_max_prices');
        }

        //Display Product for WooCommerce compatibility
        public function woof_modify_query_args($query_args) {

            if (WOOF_REQUEST::isset($this->get_swoof_search_slug())) {
                if (WOOF_REQUEST::isset('woof_wp_query_args')) {

                    $WP_Meta_Query = new WP_Meta_Query();
                    $query_args['meta_query'] = $WP_Meta_Query->sanitize_query(WOOF_REQUEST::get('woof_wp_query_args', 'meta_query'));

                    $WP_Tax_Query = new WP_Tax_Query();
                    $query_args['tax_query'] = $WP_Tax_Query->sanitize_query(WOOF_REQUEST::get('woof_wp_query_args', 'tax_query'));

                    $query_args['paged'] = intval(WOOF_REQUEST::get('woof_wp_query_args', 'paged'));
                }
            }

            return $query_args;
        }

        public function get_custom_ext_path($relative = '') {
            if (!isset($this->settings['custom_extensions_path'])) {
                return null;
            }

            //***

            if (!empty($relative)) {
                $relative = trim($relative, DIRECTORY_SEPARATOR);
                $relative .= DIRECTORY_SEPARATOR;
            }
            return WP_CONTENT_DIR . DIRECTORY_SEPARATOR . $this->settings['custom_extensions_path'] . DIRECTORY_SEPARATOR . $relative;
        }

        public function get_custom_ext_link($relative = '') {
            if (!empty($relative)) {
                $relative = trim($relative, DIRECTORY_SEPARATOR);
                $relative .= DIRECTORY_SEPARATOR;
            }
            return WP_CONTENT_URL . DIRECTORY_SEPARATOR . $this->settings['custom_extensions_path'] . DIRECTORY_SEPARATOR . $relative;
        }

        public function get_ext_directories() {
            $directories = array();
            $directories['default'] = glob(WOOF_EXT_PATH . '*', GLOB_ONLYDIR);
            $directories['custom'] = array();
            if (isset($this->settings['custom_extensions_path']) AND!empty($this->settings['custom_extensions_path'])) {
                if ($this->get_custom_ext_path()) {
                    $directories['custom'] = glob($this->get_custom_ext_path() . '*', GLOB_ONLYDIR);
                }
            }

            return $directories;
        }

        public function control_extension_by_key($key, $activate) {
            $directories = $this->get_ext_directories();
            if (isset($this->settings['activated_extensions'])) {
                $activated = $this->settings['activated_extensions'];
            } else {
                $activated = array();
            }
            //*** default exts

            if (!empty($directories['default']) AND is_array($directories['default'])) {

                foreach ($directories['default'] as $path) {

                    if (strrpos($path . DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR . $key . DIRECTORY_SEPARATOR) !== false) {
                        $idx = WOOF_EXT::get_ext_idx_new($path);
                        $key = array_search($idx, $activated);

                        if ($activate && $key === false) {
                            //add
                            $activated[] = $idx;
                            $this->settings['activated_extensions'] = $activated;
                            update_option('woof_settings', $this->settings);
                        }
                        if (!$activate && $key !== false) {
                            //delete
                            unset($activated[$key]);
                            $this->settings['activated_extensions'] = $activated;
                            update_option('woof_settings', $this->settings);
                        }
                    }
                }
            }
        }

        //initialization of extensions
        public function init_extensions() {

            $directories = $this->get_ext_directories();
            if (isset($this->settings['activated_extensions'])) {
                $activated = $this->settings['activated_extensions'];
            } else {
                $activated = array();
            }


            //for extensions defined by user (custom ext)
            if (!empty($directories['custom']) AND is_array($directories['custom'])) {
                if (!is_array($activated)) {
                    $activated = array();
                }

                foreach ($directories['custom'] as $path) {
                    //if (in_array(md5($path), $activated))
                    if (WOOF_EXT::is_ext_activated($path)) {
                        include_once $path . DIRECTORY_SEPARATOR . 'index.php';
                    }
                }
            }


            //*** default exts
            if (!empty($directories['default']) AND is_array($directories['default'])) {
                if (!is_array($activated)) {
                    $activated = array();
                }

                foreach ($directories['default'] as $path) {
                    //if (in_array(md5($path), $activated))
                    if (WOOF_EXT::is_ext_activated($path)) {
                        include_once $path . DIRECTORY_SEPARATOR . 'index.php';
                    }
                }
            }



            //hooked feature for extensions
            $this->html_types = apply_filters('woof_add_html_types', $this->html_types);
            //hooked feature for extensions
            $this->items_keys = apply_filters('woof_add_items_keys', $this->items_keys);
        }

        //ajax
        public function woof_remove_ext() {
            if (!current_user_can('manage_woocommerce') OR!current_user_can('activate_plugins')) {
                return;
            }

            check_ajax_referer('rm-ext-nonce', 'rm_ext_nonce');

            if (!wp_verify_nonce(WOOF_REQUEST::get('rm_ext_nonce'), 'rm-ext-nonce')) {
                die('Stop!');
            }
            //***

            $idx = WOOF_REQUEST::get('idx');

            $directories = array();
            if ($this->get_custom_ext_path()) {
                $directories = glob($this->get_custom_ext_path() . '*', GLOB_ONLYDIR);
            }
            if (!empty($directories)) {
                foreach ($directories as $dir) {

                    if (WOOF_EXT::get_ext_idx_new($dir) == $idx) {

                        $it = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
                        $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
                        foreach ($files as $file) {
                            if ($file->isDir()) {
                                rmdir($file->getRealPath());
                            } else {
                                unlink($file->getRealPath());
                            }
                        }
                        rmdir($dir);
                    }
                }
                die('done');
            }
            die('fail');
        }

        function woof_upload_ext() {
            if (!current_user_can('manage_woocommerce') OR!current_user_can('activate_plugins')) {
                return;
            }

            check_ajax_referer('add-ext-nonce', 'extnonce');

            if (!wp_verify_nonce(WOOF_REQUEST::get('extnonce'), 'add-ext-nonce')) {
                die('Stop!');
            }

            $upload_dir = WOOF_HELPER::get_server_var('HTTP_LOCATION');
            $valid_extensions = array('zip');

            $Upload = new FileUpload('uploadfile');
            $result = $Upload->handleUpload($upload_dir, $valid_extensions);

            //***

            $zipArchive = new ZipArchive();
            $zip_result = $zipArchive->open($Upload->getSavedFile());
            $ext_info = array();
            if ($zip_result === TRUE) {
                $zipArchive->extractTo($upload_dir);
                $zipArchive->close();
                $dir = $upload_dir . str_replace('.zip', '', $Upload->getFileName());
                $ext_info = WOOF_HELPER::parse_ext_data($dir . '/info.dat');
                $ext_info['idx'] = md5($dir);
                unlink($Upload->getSavedFile());
            }

            if (!$result) {
                die(json_encode(array('success' => false, 'msg' => $Upload->getErrorMsg())));
            } else {
                die(json_encode(array('success' => true, 'ext_info' => $ext_info)));
            }
        }

        public function is_permalink_activated() {
            return get_option('permalink_structure', '');
        }

        public function get_option($key, $default = 0) {
            $res = $default;
            if (isset($this->settings[$key])) {
                $res = $this->settings[$key];
            }

            return $res;
        }

        private function is_should_init() {

            if (is_admin()) {
                return true;
            }
            //do not exclude in widget page
            if (isset($_SERVER['SCRIPT_URI'])) {
                $uri = parse_url(trim(WOOF_HELPER::get_server_var('SCRIPT_URI')));

                $uri = explode('/', trim($uri['path'], ' /'));
                if ($uri[0] === 'wp-json') {
                    $show_legacy = array('widget-types', 'sidebars', 'widgets', 'batch');
                    $match = array_intersect($show_legacy, $uri);
                    if (count($match) != 0) {
                        $this->is_activated = true;
                        return true;
                    }
                }
            }

            //stop loading the plugins filters and its another functionality on all pages of the site
            if (isset($this->settings['init_only_on']) AND!empty($this->settings['init_only_on'])) {
                $links = explode(PHP_EOL, trim($this->settings['init_only_on']));
                $server_link = '';
                if (isset($_SERVER['SCRIPT_URI'])) {
                    $server_link = WOOF_HELPER::get_server_var('SCRIPT_URI');
                } else {
                    if (isset($_SERVER['REQUEST_URI'])) {
                        $server_link = site_url() . WOOF_HELPER::get_server_var('REQUEST_URI');
                    }
                }

                //***
                $removeChar = ["https://", "http://", "/"];
                $init = true;
                if (!empty($server_link)) {

                    if (stripos($server_link, '/' . $this->get_swoof_search_slug() . '/') !== false) {
                        $this->is_activated = true;
                        return true;
                    }
                    $server_link_mask = str_replace($removeChar, '', trim(stripcslashes($server_link), " /"));
                    if (isset($this->settings['init_only_on_reverse']) AND $this->settings['init_only_on_reverse']) {
                        $init = true;
                    } else {
                        $init = false;
                    }
                    foreach ($links as $key => $pattern_url) {

                        $pattern_url = str_replace($removeChar, '', trim(stripcslashes($pattern_url), " /"));
                        $use_mask = true;
                        if (stripos($pattern_url, '#') === 0) {
                            $pattern_url = trim(ltrim($pattern_url, "#"));
                            $use_mask = false;
                        }

                        if ($use_mask) {
                            preg_match('/(.+)?' . trim($pattern_url) . '(.+)?/', $server_link_mask, $matches);
                            $init_tmp = !empty($matches);
                        } else {
                            $init_tmp = ($pattern_url == $server_link_mask);
                        }

                        if (isset($this->settings['init_only_on_reverse']) AND $this->settings['init_only_on_reverse']) {

                            if ($init_tmp) {
                                $init = false;
                                break;
                            }
                        } else {

                            if ($init_tmp) {
                                $init = true;
                                break;
                            }
                        }
                    }
                    if ($init) {
                        $this->is_activated = true;
                        return true;
                    }
                }
            } else {
                return true;
            }


            return false;
        }

        public function render_html_e($pagepath, $data = array()) {
            if (isset($data['pagepath'])) {
                unset($data['pagepath']);
            }
            if (is_array($data) AND!empty($data)) {
                extract($data);
            }

            $pagepath = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $pagepath);
            $pagepath = realpath($pagepath);
            if (!$pagepath) {
                return;
            }
            include($pagepath);
        }

        public function render_html($pagepath, $data = array()) {
            if (isset($data['pagepath'])) {
                unset($data['pagepath']);
            }
            if (is_array($data) AND!empty($data)) {
                extract($data);
            }

            $pagepath = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $pagepath);
            $pagepath = realpath($pagepath);
            if (!$pagepath) {
                return '';
            }

            ob_start();
            include($pagepath);
            return ob_get_clean();
        }

        //******************************************* FEATURES SUGGESTIONS ***************************************************

        public function woof_sort_terms_is_checked($terms = array(), $type = "checkbox") {
            if (!is_array($terms)) {
                $terms = array();
            }
            $not_sort_terms = apply_filters('woof_not_sort_checked_terms', array('slider'));

            if (in_array($type, $not_sort_terms)) {
                return $terms;
            }

            $request = $this->get_request_data();
            $temp_term = current($terms);
            if (!is_array($temp_term))
                return $terms;
            if ($this->is_isset_in_request_data($temp_term['taxonomy'])) {
                $current_request = $request[$temp_term['taxonomy']];
                $current_request = explode(',', urldecode($current_request));
            } else {
                return $terms;
            }
            $temp_array = array();
            foreach ($terms as $key => $val) {

                if (in_array($val['slug'], $current_request)) {
                    $temp_array[$key] = $val;
                }
            }
            foreach ($temp_array as $key => $val) {
                unset($terms[$key]);
            }
            return array_merge($temp_array, $terms);
        }

        //***
        // woo3.3
        public function set_loop_properties($query, $columns) {
            wc_set_loop_prop('is_paginated', true);
            wc_set_loop_prop('total_pages', $query->max_num_pages);
            wc_set_loop_prop('current_page', (int) max(1, $query->get('paged', 1)));
            wc_set_loop_prop('per_page', (int) $query->get('posts_per_page'));
            wc_set_loop_prop('total', (int) $query->found_posts);
            wc_set_loop_prop('columns', $columns);
            wc_set_loop_prop('is_filtered', true);
        }

        public function product_visibility_not_in($tax_query, $keys) {
            $arr_ads = wc_get_product_visibility_term_ids();
            $product_not_in = array();
            if (!is_array($keys)) {
                $keys = array($keys);
            }
            foreach ($keys as $key) {
                if (isset($arr_ads[$key]) OR!empty($arr_ads[$key])) {
                    $product_not_in[] = $arr_ads[$key];
                }
            }
            if (!empty($product_not_in)) {
                $tax_query[] = array(
                    'taxonomy' => 'product_visibility',
                    'field' => 'term_taxonomy_id',
                    'terms' => $product_not_in,
                    'operator' => 'NOT IN',
                );
            }

            return $tax_query;
        }

        public function woof_overide_template($template, $template_name, $template_path) {
            if ($template_name == 'loop/no-products-found.php') {
                if (isset($this->settings['override_no_products']) AND!empty($this->settings['override_no_products'])) {
                    WOOF_REQUEST::set('override_no_products', 1);
                    $template = WOOF_PATH . 'views/no-products-found.php';
                }
            }
            return $template;
        }

        public function generate_visibility_keys($search = false) {
            $keys = array();
            if ('yes' === get_option('woocommerce_hide_out_of_stock_items')) {
                $keys[] = 'outofstock';
            }
            if ($this->get_option('listen_catalog_visibility')) {
                $keys[] = 'exclude-from-search';
                if (!$search) {
                    $keys[] = 'exclude-from-catalog';
                }
            }
            return $keys;
        }

        public function product_visibility_for_parse_query() {
            add_filter('woocommerce_product_query_tax_query', function ($tax_query, $_this) {
                foreach ($tax_query as $key => $tax) {
                    if (isset($tax['taxonomy']) AND $tax['taxonomy'] == 'product_visibility') {
                        unset($tax_query[$key]);
                    }
                }
                $tax_query = $this->product_visibility_not_in($tax_query, $this->generate_visibility_keys(true));
                return $tax_query;
            }, 10, 2);
            add_filter('woocommerce_product_is_visible', function ($visible, $id) {
                return true;
            }, 10, 2);
        }

        //+++

        public function check_shortcode($tag = "", $text = "") {
            $tags = array(
                'products_woof',
                'recent_products_woof',
                'sale_products_woof',
                'best_selling_products_woof',
                'top_rated_products_woof',
                'featured_products_woof',
                $tag
            );

            $pattern = get_shortcode_regex($tags);
            preg_match_all("/$pattern/", $text, $matches);
            if (isset($matches[0][0]) AND!empty($matches[0][0])) {
                return $matches[0][0];
            } else {
                return "";
            }
        }

        public function get_wppp_per_page() {
            $per_page = 12;
            if (WOOF_REQUEST::isset('wppp_ppp')) {
                $per_page = intval(WOOF_REQUEST::get('wppp_ppp'));
            } elseif (WOOF_REQUEST::isset('ppp')) {
                $per_page = intval(WOOF_REQUEST::get('ppp'));
            } elseif (isset($_COOKIE['woocommerce_products_per_page'])) {
                $per_page = intval($_COOKIE['woocommerce_products_per_page']);
            } else {
                $per_page = intval(get_option('wppp_default_ppp', '12'));
            }
            return $per_page;
        }

        public function activate_woo_shortcodes() {
            $shortcodes = array(
                'products',
                'recent_products',
                'sale_products',
                'best_selling_products',
                'top_rated_products',
                'featured_products',
            );
            foreach ($shortcodes as $tag) {
                add_shortcode(esc_attr($tag) . "_woof", array($this, 'woof_ajax_shortcode'));
                add_action('woocommerce_shortcode_' . $tag . '_loop_no_results', function () {
                    do_action('woocommerce_no_products_found');
                }, 10, 1);
            }
        }

        public function woof_ajax_shortcode($atts, $content, $tag) {
            $attr_str = "";
            if (is_array($atts)) {
                foreach ($atts as $key => $val) {
                    if (is_int($key)) {
                        $attr_str .= " " . $val;
                    } else {
                        $attr_str .= sprintf(" %s='%s'", $key, $val);
                    }
                }
            }
            $shortcode = str_replace("_woof", "", $tag);
            ob_start();
            ?>

            <div id="woof_results_by_ajax" class="woof_results_by_ajax_shortcode" data-shortcode="<?php esc_attr_e($tag . $attr_str) ?>" >
                <?php
                echo do_shortcode("[" . esc_html($shortcode . $attr_str) . " ]");
                ?>
            </div>
            <?php
            return ob_get_clean();
        }

        public function sort_terms_before_out($terms, $type) {
            if (!is_array($terms)) {
                $terms = array();
            }
            $term = reset($terms);
            if (!$term) {
                return $terms;
            }
            $tax = $term["taxonomy"];
            $orberby = -1;
            $order = "ASC";
            if (isset($this->settings['orderby'][$tax])) {
                $orberby = $this->settings['orderby'][$tax];
            }
            if (isset($this->settings['order'][$tax])) {
                $orber = $this->settings['order'][$tax];
            }
            if ($orberby != -1) {
                switch ($orberby) {
                    case'id':
                        if ($orber == 'ASC') {
                            uasort($terms, function ($a, $b) {
                                if ((int) $a['term_id'] == (int) $b['term_id']) {
                                    return 0;
                                }
                                return ((int) $a['term_id'] < (int) $b['term_id']) ? -1 : 1;
                            });
                        } else {
                            uasort($terms, function ($a, $b) {
                                if ((int) $a['term_id'] == (int) $b['term_id']) {
                                    return 0;
                                }
                                return ((int) $a['term_id'] > (int) $b['term_id']) ? -1 : 1;
                            });
                        }
                        break;
                    case'name':
                        if ($orber == 'ASC') {
                            uasort($terms, function ($a, $b) {
                                return strnatcasecmp($a['name'], $b['name']);
                            });
                        } else {
                            uasort($terms, function ($a, $b) {

                                return strnatcasecmp($b['name'], $a['name']);
                            });
                        }

                        break;
                    case'numeric':
                        if ($orber == 'ASC') {
                            uasort($terms, function ($a, $b) {
                                if ((int) $a['slug'] == (int) $b['slug']) {
                                    return 0;
                                }
                                return ((int) $a['slug'] < (int) $b['slug']) ? -1 : 1;
                            });
                        } else {
                            uasort($terms, function ($a, $b) {
                                if ((int) $a['slug'] == (int) $b['slug']) {
                                    return 0;
                                }
                                return ((int) $a['slug'] > (int) $b['slug']) ? -1 : 1;
                            });
                        }

                        break;
                }
            }

            return $terms;
        }

        public function change_query_tax_relations($logic_array) {
            $logic_arr = array();
            if (isset($this->settings['comparison_logic'])) {
                $logic_arr = $this->settings['comparison_logic'];
            }
            foreach ($logic_arr as $cat => $logic) {
                if ($logic == 'AND' OR $logic == 'NOT IN') {
                    $logic_array[$cat] = $logic;
                }
            }
            return $logic_array;
        }

        public function replacing_template_loop_product_thumbnail() {
            $show = 0;
            if (isset($this->settings['show_images_by_attr_show'])) {
                $show = $this->settings['show_images_by_attr_show'];
            }
            if ($show) {
                //for another wp themes add compatibility in the current function
                if (class_exists('Flatsome_Default')) {
                    //flatsome theme compatibility
                    remove_action('flatsome_woocommerce_shop_loop_images', 'woocommerce_template_loop_product_thumbnail', 10);
                    add_action('flatsome_woocommerce_shop_loop_images', array($this, 'wc_template_loop_product_replaced_thumb'), 10);
                } else {
                    // Remove product images from the shop loop
                    remove_action('woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10);
                    // Adding something instead
                    add_action('woocommerce_before_shop_loop_item_title', array($this, 'wc_template_loop_product_replaced_thumb'), 10);
                }
            }
        }

        public function wc_template_loop_product_replaced_thumb() {
            global $product;
            $needed = array();
            if (isset($this->settings['show_images_by_attr'])) {
                $needed = $this->settings['show_images_by_attr'];
            }

            if (is_array($needed) AND count($needed)) {
                if ($this->is_isset_in_request_data($this->get_swoof_search_slug()) AND $product->is_type("variable")) {

                    $need_array = array();
                    $request = $this->get_request_data();

                    $need_array = array_intersect_key($request, array_flip($needed));
                    $rate = array();
                    if (count($need_array)) {
                        $variations = $product->get_available_variations();

                        foreach ($variations as $key => $variant) {
                            if (isset($variant['attributes'])) {
                                $rate[$key] = 0;
                                foreach ($need_array as $attr_name => $values) {
                                    if (isset($variant['attributes']["attribute_" . $attr_name]) AND in_array($variant['attributes']["attribute_" . $attr_name], explode(",", $values))) {
                                        $rate[$key]++;
                                    }
                                }
                            }
                        }

                        arsort($rate);

                        $attr_key = array_key_first($rate);
                        if (array_shift($rate)) {
                            if (isset($variations[$attr_key]["image_id"]) AND $variations[$attr_key]["image_id"]) {
                                $image_size = apply_filters('single_product_archive_thumbnail_size', 'woocommerce_thumbnail');
                                $image = wp_get_attachment_image($variations[$attr_key]["image_id"], $image_size, false, array());
                                if ($image) {
                                    echo wp_kses_post(wp_unslash($image));
                                    return;
                                }
                            }
                        }
                    }
                }
            }
            echo woocommerce_get_product_thumbnail();
        }

        public function woopt_set_query_args($query_args) {
            if ($this->is_isset_in_request_data($this->get_swoof_search_slug())) {
                WOOF_REQUEST::set('woof_products_doing', 1);
                $query_args['tax_query'] = array_merge($query_args['tax_query'], $this->get_tax_query(''));
                $query_args['meta_query'] = array_merge($query_args['meta_query'], $this->get_meta_query());
                $query_args = apply_filters('woof_products_query', $query_args);

                if (isset($_GET['paged'])) {
                    $query_args['paged'] = intval($_GET['paged']);
                }
            }
            return $query_args;
        }

        function sync_on_product_save($product_id, $prod) {
            if (isset($this->settings['price_transient']) AND $this->settings['price_transient']) {
                woof_price_transient_clear();
            }
        }

        public function parse_tax_query($tax_query) {
            $request = $this->get_request_data();
            $array_logic = $this->change_query_tax_relations(array());
            foreach ($array_logic as $key => $logic) {
                if ($logic == "NOT IN" AND isset($request[$this->check_slug($key)])) {
                    $terms = explode(",", $request[$this->check_slug($key)]);
                    $tax_query[] = array(
                        "taxonomy" => $key,
                        "terms" => $terms,
                        "field" => "slug",
                        "operator" => "NOT IN"
                    );
                }
            }
            return $tax_query;
        }

        public function check_slug($slug) {
            $array_logic = $this->change_query_tax_relations(array());
            if (isset($array_logic[$slug]) AND $array_logic[$slug] == 'NOT IN') {
                $slug = 'rev_' . $slug;
            }
            return $slug;
        }

        public function uncheck_slug($slug) {
            $slug = preg_replace("@^rev_@", '', $slug);
            return $slug;
        }

    }

//***

    if (isset($_GET['P3_NOCACHE'])) {
        //stupid trick for that who believes in P3
        return;
    }

//***

    $init_the_plugin = true;

//there is no reason to activate the plugin in wp-admin area, exept of the plugin settings page
    if (is_admin()) {
        $init_the_plugin = false;
    }

//    //compatybility  with elementor
    if (isset($_GET['action']) AND $_GET['action'] == 'elementor') {
        $init_the_plugin = true;
    }

    if (defined('DOING_AJAX')) {
        $init_the_plugin = true;
    }

    if (isset($_GET['page']) AND $_GET['page'] == 'wc-settings') {
        $init_the_plugin = true;
    }

//***
    if (isset($_SERVER['SCRIPT_URI']) AND function_exists('basename')) {
        $init_pages = array('plugins.php', 'widgets.php', 'term.php', 'edit-tags.php');
        //http://stackoverflow.com/questions/7395049/get-last-part-of-url-php
        $lastSegment = basename(parse_url(WOOF_HELPER::get_server_var('SCRIPT_URI'), PHP_URL_PATH));
        if (in_array($lastSegment, $init_pages)) {
            $init_the_plugin = true;
        }
    } else {
        $init_the_plugin = true;
    }
//***

    if ($init_the_plugin OR isset($_GET['woof_cron_key'])) {
        $WOOF = new WOOF();
        if ($WOOF->is_activated) {
            $GLOBALS['WOOF'] = $WOOF;
            add_action('init', array($WOOF, 'init'), 1);
        }
    }
    //clear price transient
    add_action('woocommerce_update_product', function ($prod_id, $product = null) {
        delete_transient('woof_min_max_prices');
    }, 10, 2);

    function woof() {
        global $WOOF;
        return $WOOF;
    }